# LANE C — GLB validation report (round 3) → 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:` 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.4–2.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:` → local, Lane C needs **no change**: `glb.js` uses `depot:` 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).