PROCITY/docs/LANES/LANE_C_GLB_VALIDATION.md
m3ultra 34926324bd Lane C R4: hero props into rooms (arcade/booth/fridge/mixer/register)
Round-4 §Lane C — map the 4 new hero props + cash_register (manifest now
14 fittings), validate, measure, clean up.

- glb.js: map listening_booth→listeningCorner (record), drinks_fridge→fridge
  (milkbar), arcade_cabinet→new arcadeCabinet primitive (video focal prop).
  New attachCounterTop() places cash_register on every counter's till slot
  (hides the primitive till) + milkshake_mixer on the milk-bar benchtop;
  counter primitive + keeper stand untouched. All yaw 0 (no correction).
- fittings.js: new arcadeCabinet primitive (footprint/height matched to the
  GLB); counter exposes counterTop attach points + tags the primitive till.
- theme.js: arcadeCabinet in the video recipe; the 3 focal props (arcade,
  listeningCorner already, +) raised to priority 6 + placed first so the
  door-counter path loop can't pull them → 24/24 appearance.
- interiors.js: thread recipe.key to upgradeRoom (gates milkshake_mixer to
  milk bars).
- interior_test.html: load GLBs via the live depot: path (drop the deleted
  _local_glb localBase shim; ?localdepot=1 still works offline).

Validated (all via live depot): primitive sweep 810 {throws 0, pathFail 0,
detFail 0}; GLB-on soak {throws 0, path 0, det 0, leakGeo 0, leakTex 0,
worst 7.3ms}; all 5 new props render planted/scaled/facing right (contact
sheet docs/shots/laneC/glb_heroprops_r4.jpg). Room tris measured: milk-bar
GLB-on ~468k (drinks_fridge 77k + milkshake_mixer 73k) — reported to Lane E
as the #1 bake-pass target (not fixed, per integrator decision #2; interiors
render one-at-a-time so gate 3 is unaffected). record_crate still broken +
counter still oversized — both await Lane E re-export (C task 5). Deleted the
stale web/assets/_local_glb/ validation copy. qa.sh --strict GREEN.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 18:44:09 +10:00

7.6 KiB
Raw Blame History

LANE C — GLB validation report → for Lane E + Fable

ROUND 4 update (2026-07-14) — the 4 new hero props + cash_register

Mapped and validated the 5 round-4 hero GLBs (manifest now 14 fittings). Loaded via the live depot: path (all published, HTTP 200); the R3 _local_glb/ copy is deleted. Screenshot evidence: docs/shots/laneC/glb_heroprops_r4.jpg.

All 5 load cleanly (unlike the still-broken record_crate), follow glb_law (minY≈0, real metres), and match their manifest footprints — no per-kind yaw correction needed (yaw 0):

id / file native x·y·z (m) tris maps to placement
arcade_cabinet 0.75·1.70·0.85 25,142 new arcadeCabinet primitive (video recipe) floor, aisle zone, focal
listening_booth 0.88·1.60·0.71 53,502 listeningCorner (record) floor, window zone, focal
drinks_fridge 0.85·1.60·0.96 77,047 fridge (milkbar) floor, against wall
milkshake_mixer 0.38·0.50·0.27 73,492 counter-top (milkbar) ON counter benchtop (left slot)
cash_register 0.42·0.35·0.34 5,999 counter-top (all types) ON counter benchtop (till slot); hides primitive till

New mechanism: counter-top GLB attach (glb.js attachCounterTop) — cash_register replaces the primitive till on every counter; milkshake_mixer sits on the milk-bar benchtop. The counter primitive (correct height + keeper stand) is kept; only the till mesh is hidden. Focal props made reliable (priority 6 + placed first): 24/24 appearance across seeds, 0 carves, 0 path-fails.

Sweep + soak with all R4 mappings on: throws 0 · pathFail 0 · determinismFail 0 · leakGeo 0 · leakTex 0 · worst build 7.3 ms. GLB clones share cached geometry (SkeletonUtils.clone) → per-room dispose is leak-free (baseline taken after a full 9-type warmup).

⚠ Interior tris — one room over budget (task 4 report, NOT fixed per integrator decision #2)

Per-room triangles, single interior rendered alone (primitives vs GLB-on), seed 1990:

room prims tris GLB-on tris GLB-on draws note
pawn 812 7,019 161 fine
opshop 2,476 58,230 706 fine
video 5,712 61,669 461 arcade 25k dominates — fine
book 6,372 102,998 1,249 high draws (≈600 primitive spines)
record 2,530 115,867 337 listening_booth 53k — fine
milkbar 1,662 468,106 578 OVERdrinks_fridge (77k) ×up-to-3 + milkshake_mixer (73k)

→ Lane E bake-pass priority (future, not v1): drinks_fridge (77k) and milkshake_mixer (73k) are grossly over-tessellated for their visual role (a fridge and a bench appliance). Baking these two to ~510k would drop the milk-bar room from ~468k to well under 150k. cash_register (6k) and arcade_cabinet (25k) are already reasonable. Interiors render one-at-a-time (Lane F swaps scenes, the street is not drawn behind them), so this does not affect gate 3 (street budget) or the v1 tag — but it's the #1 candidate for the bake pass. Not blocking; reporting per task 4.

Still open (Lane E)

  • record_crate — STILL fails to load (Cannot read ...'uri'); record bins/crates stay primitive. Re-export.
  • counter — still the 4 m till-less asset; interiors keep the primitive counter. A ~2 m counter-with-till would let me drop cash_register's separate attach and map counter directly. When both land I re-map (C task 5).

ROUND 3 report (superseded above where they overlap) → for Lane E + Fable

PROCITY-C, 2026-07-14. Round-3 task "GLB path visual validation" (ROUND3_INSTRUCTIONS §Lane C). Validated Lane E's 9 fitting GLBs from pipeline/_normalized/ in real interior rooms via the interiors/glb.js upgrade path (useGLB on). Verdict below; the 5 "good" assets are live.

How validated

  • Served the 9 procity_fit_*.glb locally (web/assets/_local_glb/, copied from pipeline/_normalized/) and pointed glb.js at them via a new manifest.localBase (loads before/without the depot, per the round-3 instruction). Production still uses depot:<file> unchanged.
  • Toggle GLB props on the interior test page (web/interior_test.html) rebuilds every shop type with the GLBs and re-renders once they load; a headless sweep+soak checks throws/leaks/perf.
  • Convention followed: glb_law (metres, +Y up, base at origin) ✓ every asset measured minY≈0; facing ("Lane B/C rotate directional props") — Lane C now applies per-kind yaw in glb.js.

Result — soak with useGLB on (50 rooms, all types)

throws 0 · pathFail 0 · determinismFail 0 · leakGeo 0 · leakTex 0 · worst build 10.5ms (<50) · 256 GLB upgrades applied. GLB textures/geometries dispose leak-free on room exit (loader-cached

  • clone-shared; baseline taken after warmup). Acceptance met.

Good — live now (5 assets)

id / file native (x·y·z m) notes
wire_shelf · procity_fit_wire_shelf_01.glb 1.17 · 1.8 · 0.44 clean, full height, faces right (yaw 0)
clothes_rack · procity_fit_clothes_rack_01.glb 1.34 · 1.5 · 0.43 garments hang correctly, casters read well
bookshelf · procity_fit_bookshelf_01.glb 0.2 · 2.0 · 1.02 needs +90° yaw — modelled wide along Z; Lane C rotates it. Then spines face the aisle ✓
work_table · procity_fit_work_table_01.glb 0.44 · 0.75 · 1.04 needs +90° yaw (Z-major); goods sit on top ✓
cube_shelf_wide · procity_fit_cube_shelf_wide_01.glb 0.75 · 1.1 · 1.24 needs +90° yaw. ⚠ 1.24 wide → in narrow (2-col ≈0.84m) cube slots it clamps to ~0.75m tall. Fine in wide slots. Optional: a ~0.8m-wide cube variant.

Lane C applies the +90° yaw for the three Z-major assets (per the facing convention — no action needed from Lane E unless you want to re-bake them Z-forward). All plant on the floor; no z-fighting with the procedural stock/decor that rides on top.

⚠ Mismatches to fix (2 assets)

  1. procity_fit_record_crate_01.glb — BROKEN, will not load. GLTFLoader.loadAsync throws TypeError: Cannot read properties of undefined (reading 'uri'). The file has valid glTF magic and is 858 KB, but references an undefined uri (missing embedded image/buffer, or an extension the shipping bare core/loaders.js GLTFLoader can't resolve — it is the only one of the 16 that fails that loader; the other 8 fittings + street furniture load fine). Impact: record bins/crates fall back to primitives (fail-soft, no crash). Please re-export (and if it uses KTX2/meshopt, flag it — the core loader has no KTX2/meshopt/Draco decoder configured).
  2. procity_fit_counter_01.glb — too large for the interior counter slot; no till. It's a real 4.02 m-long × 1.1 m counter. Interior counter slots are ~1.42.2 m, so fitting to the slot squashes it to ~0.6 m tall, and it has no till/register modelled. Lane C therefore keeps the counter primitive (correct height + till + keeper stand). If you want a GLB counter for interiors, a ~2 m-long counter with a till would drop straight in (re-add counter to KIND_TO_GLB).

Notes for Lane E's local-depot mode (your round-3 §2)

When ?localdepot=1 / core/loaders.js resolves depot:<file> → local, Lane C needs no change: glb.js uses depot:<file> by default and only used localBase as a standalone validation shim. Point your local resolver at pipeline/_normalized/ and my useGLB path works through it as-is.

Screenshot evidence: docs/shots/laneC/glb_validation_grid.jpg.