PROCITY/docs/LANES/LANE_C_GLB_VALIDATION.md
m3ultra aa9c140eca Lane C R5 C1: v1.1 re-map — record_crate (fixed) + counter_till
Round-5 §Lane C task 1 (the v1.1 gate). Map Lane E's R4-late re-exports in
glb.js:

- record_crate FIXED (E stripped sourceless AO/roughness slots) → crate/
  recordBin upgrade to plastic crates with the procedural sleeves inside;
  removed the stale "fails to load" comment.
- counter → 'counter_till' (the real ~1.6m timber counter WITH a modelled
  till; NOT the 4m balcao). Footprint-fit + floor-plant + keeper-stand pose
  unchanged.
- Double-till resolved (documented): counter_till carries its own till, so
  the separate cash_register attach is dropped whenever the counter GLB is
  live (falls back to cash_register on the primitive counter otherwise);
  milkshake_mixer stays on the milk-bar bench, lifted +0.10m onto the taller
  GLB counter.

Validated (GLB on, via depot): sweep+soak {throws 0, path 0, det 0, worst
10.4ms}, 0 rooms with a visible primitive till, leak-free vs a saturated
baseline (the transient 2geo/4tex first-sight is record_crate + counter_till
cache-fill). Primitive path byte-unchanged (glb.js-only edit). qa.sh --strict
GREEN. Contact sheet docs/shots/laneC/glb_v1_1_r5.jpg. → F can tag v1.1
(LANE_C_NOTES.md).

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

134 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# LANE C — GLB validation report → for Lane E + Fable
## ROUND 5 / v1.1 (2026-07-14) — record_crate fixed + counter_till mapped
Lane E's R4-late re-exports validated and mapped (LANE_E_NOTES → C). Contact sheet:
[`docs/shots/laneC/glb_v1_1_r5.jpg`](../shots/laneC/glb_v1_1_r5.jpg).
- **`record_crate` FIXED** (E stripped the sourceless AO/roughness texture slots) — loads in the vendored
GLTFLoader (0.46·0.41·0.63 m, minY≈0, 5,000 tris). `crate`/`recordBin` now **upgrade** to plastic
crates with the procedural sleeves inside (was fail-soft to primitive). Removed the stale comment.
- **`counter_till` MAPPED** (`counter → 'counter_till'` in `KIND_TO_GLB`) — the new ~1.6 m timber counter
WITH a modelled till (1.61·1.15·0.64 m, minY≈0, 32k tris). Footprint-fit + floor-plant work unchanged;
yaw 0. Keeper-stand pose is a room-local pose, unaffected by the geometry swap (verified in HUD).
- **Double-till resolved (decision, documented in glb.js):** because `counter_till` carries its own till,
the separate `cash_register` counter-top attach is **dropped whenever the counter GLB is live** (falls
back to cash_register on the primitive counter if `counter_till` is ever absent). `milkshake_mixer`
stays on the milk-bar bench, lifted +0.10 m to sit on the taller GLB counter. Soak: **0 rooms with a
visible primitive till** (no double till).
- **Sweep + soak (GLB on)**: `throws 0 · pathFail 0 · determinismFail 0 · worst 10.4 ms`. Leak: 0/0
against a saturated baseline (the transient 2 geo / 4 tex on first sight is `record_crate` + `counter_till`
cache-fill, bounded — confirmed by a double-soak). Primitive path unchanged by C1 (glb.js-only).
Still open: nothing blocking. The `counter_till` material reads over-shiny in some lighting (TRELLIS
shell-soup) — cosmetic, E's bake pass will help; not a Lane C issue.
---
## 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`](../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 | **OVER**`drinks_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`](../shots/laneC/glb_validation_grid.jpg).