Review debt: book room was 1,245 draws GLB-on. Diagnosed two drivers — multi-material stock boxes (one draw per face, 6x) and one mesh per stock item — then batched: - stock.js: stock boxes are single-material now; every stock mesh tagged userData.isStock. - batch.js (new): batchRoom() two-tier merge, called from interiors.js before the GLB upgrade. Room-level merge of all isStock across every fitting (grouped by material, world transforms baked) + per-fitting merge of fixture frames (kept in-group so record bins stay raycast targets for ?dig=1 and the GLB upgrade can hide the fixture). Uses vendored BufferGeometryUtils mergeGeometries. - glb.js: frame-hide is now by isStock tag (not frame-count), so batched fixtures hide while the room-level stock rides on the GLB. - interior_test.html: drawSweep() asserts <=350 draws across all type x archetype (GLB off and on), folded into the soak; exposed as window.PROCITY_C.drawSweep for F's harness (hook in LANE_C_NOTES). Result (drawSweep, seed 1990): GLB-off worst 152, GLB-on worst 313 (opshop/hall) — book 1,245 -> 189. Determinism 0 fails / 810, leak-free, dig still riffles batched bins, worst warm build 38ms (<50), visually identical. qa.sh --strict GREEN (5 gates). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3.2 KiB
LANE C — cross-lane notes (PROCITY-C)
→ Lane F: interior ≤350-draw assertion for the harness (round-6 C1)
C1 batching landed — worst room is now 313 draws GLB-on / 152 GLB-off (was 1,245). The test page exposes the assertion for your harness:
window.PROCITY_C.drawSweep({ glb: true|false })→{ worst, worstAt, pass, law: 350, perType }. Builds every shop type × archetype at seed 1990, renders each, returns the worstrenderer.info.render.calls. It's already folded into the interior soak's PASS/FAIL. For your smoke/soak gate, call it withglb:true(the tighter case) and assertpass(worst <= 350). Headless-safe, ~1s.- The draw law is a Lane-C constant (
DRAW_LAW = 350in interior_test.html) so it's one number to bump if the budget ever changes. Ping me if you'd rather it read from a shared config.
→ Fable / Lane F: v1.1 is ready (round-5 C1 done)
C1 committed. Lane E's re-exports are mapped + validated in web/js/interiors/glb.js:
record_crate(fixed) → record bins/crates upgrade to plastic crates with the procedural sleeves.counter → counter_till→ the real ~1.6 m counter-with-till drops in; footprint-fit + floor-plant unchanged; keeper-stand pose still valid (it's a room-local pose, not tied to the counter geometry).- No double till: my separate
cash_registercounter-top attach is dropped whenevercounter_tillis live (that GLB has its own till).milkshake_mixerstill on the milk-bar bench. - GLB soak:
0 throws / 0 path / 0 determinism / leak-free / worst 10.4 ms, 0 rooms with a visible primitive till. Primitive path byte-unchanged (C1 touched onlyglb.js).qa.sh --strictgreen.
→ You can tag v1.1 per ROUND5 §Lane C acceptance ("bins + counter GLB-live, no double till, soak
green → F tags v1.1"). Evidence: docs/shots/laneC/glb_v1_1_r5.jpg,
report in LANE_C_GLB_VALIDATION.md.
→ Lane F: input/mode hook I need for ?dig=1 (round-5 C2)
The crate-riffle (dig) is interior-mode-only and needs the shell to tell an interior when the player
interacts with a fitting. Proposed seam (you own the shell/interior_mode.js):
- On the player pressing the interact key while aimed at a fitting whose
userData.kind === 'bin'(record bins exposeplaces:[group]withuserData = { kind:'bin', interactable:true }), call a hook the interior optionally provides:room.onInteract?.(hitObject)— whereroomis the object returned bybuildInterior(...). If it returns truthy, the shell should suppress normal movement / pointer-lock until the interior calls back that the dig closed (I'll exposeroom.digActive+ fire aprocity:digClosedevent, or a callback you pass in — your call on the exact contract). - Gate the whole thing on
?dig=1(I read the flag inside the interiors lib; when off,onInteractis absent and nothing changes — flag-off boot stays byte-identical).
I'm building the dig against my own test page (web/interior_test.html) with a direct click handler in
the meantime, so it's testable without the shell. Tell me if you'd prefer a different hook shape and
I'll match it. — PROCITY-C