Mike0021/mission-kimik3
hand — GPU shader reconstruction
A real-time WebGL2 fragment-shader reconstruction of reference-hand.jpg (1258×1256): a soft, blurred hand shadow on warm gray paper with a white photo border — rebuilt analytically as SDF capsule chains with per-node shadow density, fitted against measurements of the reference. No image textures are used for the reconstruction itself; the JPEG is only shown by the comparison harness.
Run
npm install
npm start # http://localhost:8000Zero runtime dependencies: the app is vanilla ES modules + raw WebGL2, served by a tiny built-in static server (server.js). No CDN, no build step.
Compare & validate
npm run capture # writes artifacts/{reference,shader-canonical,comparison,diff}.png + metrics.json
npm test # headless smoke tests -> artifacts/test-results.jsonBoth use puppeteer-core with the system Chrome (SwiftShader WebGL2, no GPU needed). Override the browser with CHROME_PATH=/path/to/chrome.
The page
- Shader / Reference / Side-by-side / Split view modes.
- Split mode: draggable divider, pixel-aligned overlay (shader right, reference left), opacity slider, blink toggle for flicker comparison.
- reset: one click back to the canonical comparison view (split 50 %, opacity 100 %, pointer at rest).
- Move the pointer over the image: a small damped parallax / density / light response — the shadow breathes, then settles back to the exact reference pose. At rest the render is deterministic (frozen for canonical captures).
index.html?shot=1renders the shader alone at exactly 1258×1256 with interaction frozen (used by the capture pipeline and tests).
Architecture
index.html app shell / comparison harness
css/style.css chrome + stage layout
js/main.js modes, split/opacity/blink/reset, metrics badge
js/renderer.js raw WebGL2 fullscreen-triangle renderer, pointer smoothing
js/shader.js GLSL (embedded): SDF hand field, density, bg, marks, grain
server.js zero-dependency static server
scripts/capture.js canonical capture + metrics + artifact generation
scripts/analyze.mjs reference-vs-render contour/density comparison (dev)
scripts/fit*.py skeleton fitting tools used during development (dev)
test/smoke.test.js headless smoke testsThe fragment shader works in canonical 1258×1256 pixel space at any canvas size. The hand is a log-sum-exp smooth union of 37 capsule nodes (position, radius, density) with gap-carving channels; coverage is a logistic in the field, density is blended per-node; the background is the measured per-channel polynomial vignette with printed marks and the white border on top; deterministic spatial grain finishes the photograph.
See DESIGN_NOTES.md for the full decomposition, sampled colors, and fitting methodology.
Metrics (current)
From artifacts/metrics.json (regenerated by npm run capture):
- RMSE 10.6 / 255, MAE 5.4 / 255 (dominated by JPEG grain and the palm's stochastic blotch pattern — see DESIGN_NOTES)
- SSIM 0.959
- silhouette IoU 0.941 (hand masks at density > 0.1; contours agree within ±4 px everywhere)
- density-field MAE 0.028 (background-subtracted shadow field)
- regional mean RGB within 2–7 levels in all probe regions
The badge in the top bar shows RMSE · SSIM · IoU live from that file.
