201 lines
13 KiB
Markdown
201 lines
13 KiB
Markdown
# 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.
|