14 KiB
Card harness: accepted library, browsing, and surface defaults
Status: implementation plan, September 14, 2026. This document records the requested changes; it does not apply runtime settings or change approved artwork.
Outcome
Inspect accepted cards directly from artifacts/cards, with a searchable visual picker, independent resolution and printing controls, and editable defaults for individual finishes and materials. Support roughly 500 card identities without loading their full images into browser or GPU memory at startup.
1. Accepted cards are the catalogue
- Discover packages under
artifacts/cards/[folderName]/usingcard.json, the acceptedmanifest.json, and resolution manifests. Include only approved packages; skip migration reports and history. - Key selections by catalogue
cardId, never display title or a reconstructed title slug. Display title, ID, rarity, and accepted revision. - Represent each card once, with variants indexed by resolution (
low,med,high) and printing (normal,borderless,textless,boundless). Each variant identifies artwork, finish mask, optional text mask, dimensions, and recorded hashes. - Use manifest metadata and file-existence checks for normal catalogue refreshes. Full image decoding and hash verification belong in explicit validation, with cached results where appropriate. Opening the picker must not decode every production PNG.
- Report invalid or incomplete packages with useful card/variant errors while keeping valid cards browseable. Show a useful empty-library state. Never silently substitute another printing or resolution.
- Cache catalogue discovery, coalesce refresh requests, and invalidate affected entries when accepted manifests or assets change. Recheck when opening the picker or returning to the page, without repeatedly scanning unchanged image bytes.
Serving and builds
- Replace
public/card-artdiscovery with a Vite catalogue endpoint and a read-only asset endpoint backed directly byartifacts/cards. - Resolve asset requests through known catalogue entries and an allowlist of runtime PNGs. Check resolved paths, including symlinks, remain within the accepted asset root. Source/build/review files are not exposed by this route.
- Use recorded content hashes in URLs/cache validation so replacing an accepted revision cannot leave stale textures on screen.
- Support the same asset contract in development and Vite preview. A local built harness depends on the repository's accepted library being available to its server.
- A standalone static deployment will require a separately served artifact library or an explicit export step. Do not implicitly duplicate the entire 500-card library into tracked
publicfiles. - Retire the old drop-folder catalogue and copies after verifying all consumers use the new catalogue. Keep
public/referencefor the shared back, normal map, and existing renderer regression fixtures.
2. Card selection and inspection
Proposed primary controls:
Card [ David · BP-002 — Browse… ]
Resolution [ High ] Printing [ Normal ]
Finish [ Holographic ] Material [ Paper ]
- Default resolution is High (2000 × 2800); Medium is 1000 × 1400 and Low is 500 × 700. This is texture resolution, distinct from the renderer's drawing-buffer settings.
- Default printing is Normal. Printing and finish remain independent controls.
- Open a right-side drawer on desktop and a full-screen dialog on small screens. Use a native dialog where suitable, with labelled controls, visible focus, Escape, keyboard selection, and focus restoration to the Browse button.
- Include search by title, ID, and rarity, a rarity filter, result count, and stable ID/title sorting.
- Results show a low Normal thumbnail, title, ID, rarity, and accepted revision. Picker thumbnails stay low resolution regardless of the inspection setting.
- Load thumbnails only near the visible area; use a bounded visible grid or incremental loading so scrolling 500 cards does not retain hundreds of decoded images. Preserve search and scroll position when reopening.
- Selecting a card loads it into inspection and closes the picker. Keep resolution, printing, material, finish, lighting, and pose when changing card. Add Previous/Next navigation through the filtered result set for repeated inspection.
- Show loading/error state and keep the prior complete card visible until all new textures are ready. Swap artwork and matching masks together; discard stale results from rapid changes and dispose unused GPU textures.
- Continue supporting local artwork/mask experiments in Lab. Restore selected card reloads the exact selected identity, resolution, and printing.
3. High-resolution packs with bounded texture loading
High is available and is the default in Pack as well. Hidden fronts should produce no draw calls; their high-resolution textures also should not all be decoded/uploaded in advance. The current Pack implementation prepares every selected front, so both loading and GPU preparation need to change.
- Keep the shared back and lightweight card geometry for the face-down stack. Hidden fronts use placeholders until their textures are needed.
- Load the first front before revealing it; prefetch the next card during inspection.
- Keep a small bounded cache for the current card, next card, and any outgoing card still visible during animation. Release texture sets when no visible or imminent card needs them. A duplicate far later in a pack must not pin a texture indefinitely.
- Cache by ID, accepted asset hash/revision, resolution, and printing. Share matching textures safely without disposing them while another card uses them.
- Prepare the required shader/texture resources before allowing a reveal. If assets are still loading, pause at the face-down reveal boundary with a loading indicator and retry on failure.
- Cancel stale loading on pack replacement; preserve reveal order, interruption behavior, shared-back appearance, and material-dependent edges.
- Expose resolution and printing in Pack. Proposed first implementation: a change applies to a new pack, with clear wording before discarding an opening in progress. A later enhancement can preserve contents and position while replacing textures.
- Test memory during rapid New pack, mode switches, and repeated reveals. Invisible fronts alone do not prove that texture memory has been released.
4. Editable defaults per finish and material
Shared settings file
Proposed canonical file: card-harness/config/surface-defaults.json, versioned in Git. A shared validated resolver supplies defaults to Inspect, Lab, Reset, and Pack. It replaces duplicated selection/startup constants, including Pack's current hard-coded finish strength.
Initial requested values for implementation:
| Group | Selection | Setting | Default |
|---|---|---|---|
| Finish | Holographic | Finish strength | 0.33 |
| Finish | Foil | Finish strength | 1.00 |
| Material | Metal | Surface detail | 1.00 |
| Material | Linen | Surface detail | 0.05 |
Interpretation: the user's material strength examples refer to the existing Surface detail control (normalStrength internally). These are proposed harness defaults; recording them here does not alter the shader or claim a new visual approval.
Suggested structure (excerpt; implementation includes every supported selection):
{
"schemaVersion": 1,
"finishes": {
"Holographic": { "finishStrength": 0.33 },
"Foil": { "finishStrength": 1.00 }
},
"materials": {
"Metal": {
"surfaceDetail": 1.00,
"roughness": 0.23,
"metalBrushHorizontal": false
},
"Linen": { "surfaceDetail": 0.05, "roughness": 0.23 }
}
}
- Other finishes/materials start with their existing values until deliberately changed. Preserve support for legacy experiment values through the existing compatibility path.
- Finish presets own finish strength. Material presets own surface detail, roughness, and applicable material-specific controls such as Metal grain orientation.
- Lighting/environment, pose, card selection, condition, and seed remain session/experiment settings; saving a surface default does not capture them.
- Use extensible parameter objects with explicit supported fields and range validation. New exposed shader controls can join the appropriate group without creating another defaults table. Reject unknown/invalid fields with actionable messages instead of silently ignoring them.
- Keep shader formulas and internal relief caps separate from these editable starting values. Setting Surface detail to 1.00 does not remove existing relief limits.
- This is a Three.js harness; the requested renderer-setting workflow does not imply automatic Blender synchronization. If Blender settings are meant literally, map specific equivalents in a separate scoped change.
Lab workflow and persistence
- Add Save finish default and Save material defaults actions near the respective controls. Labels identify the selection being saved, e.g. “Save Holographic default”.
- Moving a slider immediately previews it but does not save it automatically. Show when the current settings differ from the saved preset, and provide Reapply saved defaults for each group.
- The save action writes only the selected group's supported values to the canonical settings file during local development, then updates all controls using that resolver.
- Implement a narrow development-only write endpoint for this one settings file: validate values server-side, require same-origin requests, reject arbitrary paths, write atomically, and detect stale saves to avoid overwriting a newer edit from another tab/editor.
- Direct file edits should refresh the settings catalogue. Preserve currently tweaked values until the user reapplies a preset, changes the relevant selection, or resets.
- For preview/static use, bundle/read the defaults and offer explicit JSON export/import as needed. Show repository saving as unavailable where no development write endpoint exists; never report a browser-only save as a repository update.
Application rules
- Startup and Reset resolve the current default finish and material through the settings file.
- Changing finish applies only the new finish preset; changing material applies only the new material preset. Keep toolbar and Lab controls synchronized.
- Changing card, printing, or resolution preserves current surface tweaks.
- Manual adjustments override presets for the current session until selection change, explicit reapply, or Reset. Saving persists them for future selections and sessions.
- Loading an experiment applies its exact stored surface values after selecting its assets. Updated defaults must not overwrite a saved experiment's values.
- New packs resolve defaults independently for each rolled finish/material. Snapshot those resolved settings for the pack; changing the defaults file does not alter cards halfway through an opening.
- Save failure leaves the preview intact and clearly reports that the default was not persisted.
5. Selection and experiment compatibility
- Introduce experiment schema version 3 with
cardId, accepted revision/hash, resolution, and printing alongside the explicit material/light/camera values. - Read older versions using an explicit mapping for known fixture names. Reject ambiguous/unavailable identities with an explanation.
- An old fixture or accepted revision may differ visually from the current accepted card. Warn when loading a replacement; never claim an exact historical reproduction when those assets are unavailable.
- Keep defaults configuration distinct from experiment snapshots: a preset is a reusable starting point, while an experiment records one exact set of choices.
6. Implementation sequence
- Implement the accepted-card catalogue, safe asset routes, cache invalidation, and development/preview contract.
- Add the visual picker and resolution/printing state; integrate texture swapping and experiment migration.
- Add the shared surface-defaults schema/resolver and initial requested values; wire every selection path and Reset through it.
- Add Lab preset-save/reapply actions, validated persistence, and file-edit refresh handling.
- Refactor Pack texture loading/preparation for High, bounded caching, and per-card resolved surface presets.
- Verify consumers and retire obsolete drop-folder assets/references. Update the harness README and current-defaults documentation to describe the implemented behavior.
Keep picker/filtering, catalogue/variant resolution, defaults resolution/persistence, and pack texture ownership in focused modules rather than expanding main.ts with every responsibility.
7. Acceptance checks
- The five current accepted cards appear automatically with their available 12 resolution/printing variants; adding an approved package requires no manual copying or manifest editing in
public. - A synthetic 500-card catalogue can be searched and scrolled while thumbnail requests and decoded-image memory remain bounded. Opening the picker does not load high-resolution textures.
- Card switching preserves surface/light/pose choices, handles missing variants and rapid changes correctly, and releases obsolete textures.
- All asset routes reject traversal and unavailable files. Development and local preview use the same catalogue contract.
- Selecting Holographic/Foil starts at 0.33/1.00 finish strength; Metal/Linen starts at 1.00/0.05 surface detail. Test both toolbar and Lab paths, Reset, and new packs.
- Saving one group's defaults leaves the other group and lighting untouched; values survive a restart through the repository settings file. Invalid values, stale writes, and failed saves are handled visibly.
- Changing presets does not overwrite imported experiment values or an active pack's captured settings.
- High-resolution packs load only a bounded number of front texture sets, gate reveals on readiness, preserve animations and hidden-card appearance, and clean up correctly after failure, mode switches, and new packs.
- Run relevant catalogue, texture ownership, experiment, and Pack tests plus TypeScript/build checks. Browser checks cover drawer accessibility, mobile layout, real texture loading, and repeated pack/card switching; report actual GPU/memory observations separately from CPU tests.