# Sanctification Card Lab Bounded Three.js proof for the card-rendering harness plan. The approved visual baseline is recorded in [`CURRENT-DEFAULTS.md`](CURRENT-DEFAULTS.md). ## Included proof scope - David printed-ink, foil, and holographic presets - Independently selectable paper, linen, plastic, metal, and wood substrates - Timothy as the second-artwork fixture - David color-based coverage and title-panel protection; automatic saturation/value coverage for Timothy - Procedural rounded-card geometry generated from shared physical dimensions - Deterministic linen normal map - Card manipulation, camera inspection, zoom, frame-rate-independent flip/reset, interruption-safe sweep, and movable lighting - Repeatable front, grazing-angle, edge, and back inspection poses - Point, directional, and spot lighting with repeatable studio, gallery, window, dramatic, and flat-review presets - Live light color, position, intensity, environment contribution, and exposure controls - Lab-mode loading of local artwork and finish-mask images without rebuilding - Named browser experiment saves, versioned JSON import/export, and PNG capture - Experimental condition wear with substrate-aware edges, scratches, scuffs, and imperfection seeds; wear and imperfections are deferred product features - Bare Inspect mode and small Lab-mode parameter panel - Pack mode: a touch-responsive foil pouch with a draggable tear strip, reveal-safe ordered stack, and one-at-a-time inspection - Drawing-buffer resolution plus median, p95, and worst frame-time display Transform gizmos and a general timeline are intentionally deferred. The separate Flutter Scene comparison project is unchanged; Three.js remains the authoritative runtime. ## Tear-open foil pack prototype Choose **Pack** in the Mode selector (expand **Controls** first on mobile). Drag the gold top seam **to the right**, or use **Tear open** for the same authored opening without dragging: **Sealed → progressive tear → strip curls away → mouth spreads → staggered card extraction → face-down stack → lifting → lifted → revealing → inspecting → advancing → next stack / complete.** Lifting and flipping are separate actions so the universal back can be reviewed before revealing. The authored order is always David / Printed ink / Linen, Timothy / Foil / Paper, then David / Holographic / Metal. This is not a randomized reward system. - The seam has a mouse/touch hit area at least 44 px tall. Drag distance drives tear progress monotonically: pulling back does not reseal it. A full pull completes the opening on release; a short pull holds its exact tear and **Finish opening** continues from there. The progress bar and percentage also expose the state without relying on the animation. - Cancellation or lost pointer capture holds a partial tear; another seam pull, **Finish opening**, or **Skip** can continue it. A second finger relinquishes the tear gesture to pinch zoom. Restart and mode changes release all captured pointers. - Pressing the pouch makes a small local dent that settles on release. Creases and seam crimps are deterministic, not continuously moving noise. - Drag to rotate and pinch or wheel to zoom during inspection. Pinch/wheel zoom also works before revealing; hidden cards cannot be manually tilted. User zoom may intentionally crop the composition. - Touching or zooming during a scripted transition pauses at the current pose. **Continue** resumes from that elapsed point, without snapping. A tap that interrupts motion does not also advance it. - **Skip** finishes only the current transition, or performs one step immediately from a resting state. It never skips an unseen card's reveal. **Restart** restores the sealed wrapper and first card. - Reduced-motion preference shortens each transition to 70 ms with the same state and reveal/completion ordering. - Switching away pauses Pack and preserves the Inspect/Lab card, camera, materials, local images and experiment settings. Returning to Pack resumes its retained state via Continue. The foil wrapper is two subdivided, joined pouch surfaces and a separate subdivided top ribbon. Controlled vertex deformation creates shallow creases, a travelling tear front, a curled detached strip, and spreading lips. Typography is printed directly on the sheet materials, not on an almost-coplanar label layer. There is no rigid-panel split, transparent cross-fade, cloth engine, or extra asset dependency. The pouch stays above the floor while the three cards slide upward with a small stagger. Only after all cards clear the mouth does the empty pouch move aside; the cards then settle into the existing face-down stack. Opening-only camera framing widens and recenters during extraction, then returns to the established stack framing. Cards use the existing procedural geometry and approved runtime shader. Before revealing, fronts are hidden, backs share the fixed universal material, and edges use a neutral paper recipe. Authored substrate edges are enabled only after the flip finishes. The active card lifts to a dedicated inspection plane before flipping or free rotation. The reserve stack stays visible, offset to the lower right and safely behind the active card's full corner-sweep volume. The exit animation also stays on that safe plane while the reserve stack recenters. Camera framing eases with the lift/exit so the deeper separation does not unexpectedly enlarge the card. The edge mesh draws only extrusion side walls, not end caps beneath the dedicated artwork faces, preventing depth-fighting bands at farther zoom distances. Pack assets are loaded separately on first entry, with retry on failure. Before enabling pack interaction, textures are uploaded and shaders are compiled for the pouch, hidden card fronts, universal backs, and both neutral/revealed edge materials using the scene's lighting and environment. This preparation does not draw or reveal cards. The loading state lasts until it finishes; failures release the new pack resources and keep retry available. Returning to an already prepared pack retains its state without repeating this preparation. Wrapper deformation is coalesced to once per rendered frame, including touch dents and tear input. Fixed crease/crimp calculations are cached; unchanged pouch surfaces and ribbons do not recalculate normals/bounds or upload vertex buffers. Hidden wrappers do not deform. Pack UI updates are also coalesced and only write changed values. These optimizations retain the same mesh resolution, deformation formulas, materials, lighting, pixel ratio, and antialiasing. Mint cards (`condition = 1`) bypass procedural wear calculations whose contribution is zero. Worn cards use the original wear equations, and all finish/substrate shading remains unchanged. There is no sound, haptics, particles, cloth simulation, backend, rewards persistence, pack progress persistence, or timeline/editor. This is a choreography proof, not an final pack-design or mobile performance sign-off. The approved rigid prototype and artifact-free card inspection are the preserved foundation; this foil treatment is the next review iteration. The canvas emits `packreveal` (one-based index and variant) and `packcomplete` (count), once per card/pack per restart. Finish and substrate are separate: - Finish controls printed ink, foil, or holographic coating. - Substrate controls surface roughness/microtexture, underprint response, and edge/core appearance. Paper uses fine, irregular fibers and a broad, weak highlight. Linen uses raised-looking interlaced threads with analytic slope lighting, a bounded two-sample procedural parallax offset, and broad ridge highlights that remain visible in Printed ink at oblique angles. Only the weave shifts with the view: artwork and lettering stay anchored. Surface detail scales the effect; unresolved threads fade to avoid shimmer. This is shader relief with no added geometry or change to the card's silhouette, back, or thickness. This linen look was visually approved September 10, 2026 as `linen-relief-v1-2026-09-10`; its exact defaults are recorded in [`CURRENT-DEFAULTS.md`](CURRENT-DEFAULTS.md#linen). No extra toggle or configuration is required: selecting Linen applies it in Inspect, Lab, and the authored pack. Plastic has a smooth clear-coat highlight even in Printed ink mode. Wood uses raised longitudinal grain with bounded procedural parallax, stronger relief, and a restrained warm tint. The artwork stays anchored while grain shading and tint shift together. Metal retains its reflective underprint and uses luminance-driven recesses: bounded parallax shifts the artwork and finish mask together, with directional groove shading to emphasize depth. The effect fades at the card edges. Metal and wood depth were visually approved September 10, 2026 as `metal-wood-relief-v1-2026-09-10`. Surface detail scales the relief; neither material adds geometry or changes the card silhouette. Procedural detail fades below pixel resolution to limit shimmer. The universal card back uses fixed neutral material properties so front finish and substrate choices do not spoil a pack reveal. The holo spectrum and coverage rules are independent of these substrate changes. Metal combined with Foil preserves the printed colors while adding restrained, slightly raised champagne-metal polishing over the etched steel base. ## Reference `npm run assets` creates `public/reference/manifest.json`, copies the source artwork and approved reference renders, and generates the two masks and normal map. Card geometry is generated directly in Three.js from the dimensions recorded in the manifest; Blender is not required to build or run the harness. The current runtime reference revision is `runtime-look-v4-2026-09-07`, visually informed by: - `blender_prototype/premium_finishes.py` - `blender_prototype/card_finish_material.py` - `blender_prototype/render_premium_review.py` The approved linen, metal, and wood depth follow-ups change runtime shader behavior, not the source artwork, generated normal map, or Blender reference renders. The asset manifest therefore retains its v4 reference revision; the scoped material approvals and parameters are tracked in `CURRENT-DEFAULTS.md`. The runtime shader and geometry are runtime implementations, not a claim of pixel-identical Blender output. David uses color-based coverage and title-panel protection. Holographic color and angle response are preserved; reduced sheen applies only to foil. ## Run ```sh npm install npm run dev ``` Production build: ```sh npm run build ``` Pack regression checks (Node 22.15+): ```sh npm test ``` These check exact pre-optimization wrapper geometry snapshots, surface update counts, per-frame input batching, pause/resume, pinch handoff, restart, reduced motion, ordered reveals, GPU preparation, and failure cleanup. They are CPU/state checks, not a real-device GPU or touch-latency benchmark; mobile performance still needs on-device validation. WebGL pixel parity and pack shader-preparation checks require a local headless Chromium browser with WebGL2 support, installed project dependencies, and generated reference assets (`npm run assets`): ```sh SHADER_BROWSER=/absolute/path/to/chromium \ SHADER_BROWSER_KIND=chromium \ node scripts/shader-pixel-regression.mjs ``` The Chromium runner uses SwiftShader software WebGL. Browsers are not installed automatically; a missing browser, missing WebGL support, timeout, pixel mismatch, or unexpected shader program causes a nonzero exit rather than a skipped check. The pixel check compares 360 combinations of substrate, finish, condition, angle, and lighting against the current shader with unconditional wear evaluation, verifying that the mint fast path remains equivalent. A separately hash-verified v4 reference checks that Paper and Plastic remain unchanged and that the approved Linen, Metal, and Wood iterations produce a visual difference. The pack check exercises opening, all three reveals, and restart under point, directional, and spot lighting, checking for new shader programs after preparation. Software WebGL can validate pixel parity and program reuse, but its timings are not mobile GPU benchmarks. The asset-generation script uses cross-platform Node APIs and works on Windows and Linux. The retained `export:blender` script is an optional reference utility and is not part of the application pipeline. ## Baseline Initial development machine: - Windows - Intel Arc Graphics, driver `32.0.101.6737` - Node `24.14.1` - Three.js version pinned by `package-lock.json` The browser/version, viewport, drawing-buffer resolution, texture settings, and observation duration must be recorded during material approval. The on-screen frame-time display is diagnostic rather than a complete benchmark.