293a82c5e8
14 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
293a82c5e8 |
R42 THE LOOK: five lane-runs — the pub is dressed, the decks read, and the town is cast
John looked at R41's proof shots and named three faults. All three are fixed, at zero draw cost, and every lane corrected somebody's numbers on the way — including its own. E-LOOK (§42.1+§42.2a) — THE PREMISE WAS WRONG. "The pub props have no texture" (my brief, quoting E's own R41 note) is false: all 37 carry COLOR_0 and three.js renders it. The colour was BLEACHED — jukebox at saturation 0.02, 15 assets under 0.05; what the source library called colour was baked AO. So the fix was a palette imposed on colour already present, in place: 46 assets, draw delta +0 and tri delta +0 on every one, proved the honest way — the concatenated POSITION/NORMAL/TEXCOORD/index bytes are sha1-identical to R41, so footprints and origins provably did not move. (A first-pass bbox check ignored node rotations and "found" 3 phantom violations; thrown out for the byte comparison.) The banquette was 1990s office teal and went burgundy; the beer umbrella was white and went brewery green. THE DECK, diagnosed before being touched: 7 greys, chassis 0.05 luminance on a 0.033 bench = 1.21:1, and the one high-contrast feature was INSIDE-OUT (white ring around a dark disc; a turntable is a dark record on a light platter). Now Technics silver at 6.74:1, black vinyl, red start/stop. Node contract re-read from the shipped GLB: 4/4 + 1/1 PASS. Filed to R43, not fixed: deck_1200_rigged has NO PLINTH (bottom 43mm of 119mm lost to R41 join damage). E-CAST (§42.3) — 19 of 24 ship. Rejected: comical_luchador_01 (Mixamo Ch43, purple mask reading EL CHUPACABRA, identified from the file's own material name), a 3-heads-tall cartoon child, a robed wuxia elder, a WW2 infantryman — and dj_phrtt_01, AN UNCLOTHED BODY whose only texture is a bare-skin atlas, which was in the DEFAULT crowd and live on the depot. It is the R41 deny-list's failure class through a different door: an innocent name from another pipeline. Only rendering all 24 and LOOKING found it. Ruling 2 (prefer CC0) was REFUSED ON MEASUREMENT: Quaternius is 25 nodes / 23 joints and ZERO of 64 canonical tracks bind — it would have loaded silently and never animated. Replacements came from Mixamo's Ch## pool, filtered to the contract-clean 65-bone family (candidates ran 65..99 bones; named characters carry facial/hair bones). THE LICENCE GAP WAS UNREAD, NOT MISSING: every source FBX carries ApplicationVendor "Mixamo, Inc." internally. Adobe royalty-free, no attribution owed. B's amber rows are now real. B (§42.5) — MY ASSIGNED FIX WAS USELESS AND B PROVED IT. document.fonts.ready shipped, then measured: the atlas canvases are already byte-identical across boots, the game ships NO webfonts (document.fonts.size === 0), and ready fires 50ms BEFORE the first fillText. The real cause of unreproducible bookmarks is the wall-clock CROWD — 983 changed px of 921,600, ALL in the pedestrian band; 0 px with the crowd out. New DBG.freeze() takes stable bookmarks 2/5 -> 5/5. Also found: ?pop=0 boots 140 citizens (0 is falsy against the default). THE BENCH: D's filing correct on both counts. Front-vs-road 90.0deg -> 0.0deg, min=med=max over 60/60 instances; the streetlight arm now reaches 1.05m over the road where it reached 0.00. Both used a base yaw that pointed +Z down the street while their own comments claimed otherwise — the side term was already right, which is why it survived 41 rounds of reading. Also: on any box with CDN access 9 of 60 benches are the depot GLB, 90deg out from the house law — normalised at the geometry, once, at load. benchStops(plan) exported as one truth. C (§42.2b) — 122 vs 123 WAS THE CAMERA ASPECT, and nobody was wrong. Draw counts are post-frustum-cull and the sweep camera inherits the window aspect: 1.25->116, 1.60->122 (C's harness), 1.778->123 (F's), 2.37->124. Pinned MEASURE_ASPECT=16/9 with a 1.25 control. E's "keep the bench dark" advice was measured and declined with reason (deck-vs-bench was already 4.73:1, over threshold). "Reads as a black box" is a claim about pixels, so C measured pixels: near-black in the booth crop 57.5% -> 26.7%, distinct colours 228 -> 389. Bench rebuilt 3->7 boxes with an open record bay; headphones on the mixer; faceDoor aims booths at the player's entry — alignment within 45deg went 49% -> 92%. Two bugs found by looking: a fitting could be planted INSIDE A WALL (0.77m of a 0.86m half-depth in plaster), and every booth part sat 25mm sunk into its own worktop. D (§42.4) — five swaps IN PLACE at the same index (pickRig indexes these arrays and pedIndex is in the identity signature and the impostor atlas; removal would renumber the town). Identity signature pre- vs post-swap: 0 differing lines of 150 — who each citizen is did not move, only which body they wear. dj_phrtt_01 verified gone AT THE WIRE, not from source: a fresh default boot fetches 32 ped GLBs, none retired. THE CONTROL ARM FOUND A 41-ROUND-OLD BUG: the ped being RETIRED, comical_boy_01, binds only 3,132 of 3,460 tracks — six thumb bones lack the mixamorig prefix. It had been silently dropping six tracks per clip since it shipped. Testing the thing being thrown away found it. Imported B's benchStops mid-round: sitters now 0.0deg to the road, signatures byte-identical across the rewire. Corrected F's filing: the browse smoke was flaky-by-construction (a 16-25s race against a live sim), not deterministically red. F (§42.6) — qa.sh --strict 24 passed / 0 failed / 0 warn / 0 skipped. New Gate 11: period law (0/5 banned; CONTROL: R41's roster trips all five) and roster licence (24/24, 0 unverified; CONTROL: an amber row turns 20 red). r41_shots.py promoted warn -> strict. R41'S BYTE-HASH BAN IS REVERSED AND ITS STATED REASON WITHDRAWN AS WRONG. A gate may pin a hash under five in-run assertions (classic+flags boot, freeze().stillLive all-false, a second freeze removing 0 draws, settle until DBG.info() stops changing, hash with the dbg panel hidden): 5/5 bookmarks now pin to one sha256 over 3 fresh boots. Two findings got it there — the chunk streamer (a fixed settle is a bet on load) and the fps readout, which with everything else frozen was the last thing moving at 53-62 px. ?pop=0 fixed (Number.isFinite) — a no-op for 35 rounds. Three red flags_check gates fixed. Street: noon 282 · NIGHT 291/300 — the nine-draw margin INTACT, every R41 row reproducing to the digit. Interior at pinned 16:9: 123 @ dept/auto, margin 227. selfcheck 157,647/157,647, 0x5f76e76 unmoved. No tag — John's playtest rules the epoch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
422f17263e |
Lane C R41 §41.4: the shops get their stock — and the measuring instrument was wrong
110 fittings placed across 12 shop types via new kit41.js (96-row catalogue, 67 ids in pools) and ONE generic kitProp builder; recipes name pools, never asset ids. glb.js now honours seeded per-fitting variants, multi-GLB booths, and a MEASURED autoYaw instead of a 110-row facing table. THE INSTRUMENT WAS WRONG. drawSweep cleared every interior EXCEPT current, so every historical interior number carried a phantom second room — 'toy', untouched this round, 'gained' 4 draws. R39/R40's celebrated 'worst 188, margin 162' was inflated. Corrected, and with 110 new fittings placed: worst room in the game is 122 @ dept/auto, MARGIN 228. Per type: record 61->78, pub 45->59, band_room 39->50, stall 71->82, book 51->61, pawn 60->70, video 54->63, rsl 52->60, dept 116->122, opshop 102->105, milkbar 68->69, toy 86->86 (+0, the control). The pub finally has a bar (plywood_bar), banquettes, pokies, a stage flank. Milk bars get a bain-marie and pie warmer. The pawn shop gets an 808 and an SP-1200 on the bench. Record shops get a rigged DJ booth. Market stalls get 2-4 diggable bins each, closing R39's measured 44%-no-crate hole to 0/40. WARDROBE, route R5: 257.5 KB total (246 KB atlas + 17 KB index), ONE fetch, one material, one draw per fitting — 52 layers picked BY NAME, alpha-cropped, shelf-packed, 3.7% of source bytes, lazy behind ?stock=real. LICENCE CALL MADE EXPLICITLY: AUDIT.md says no real brands ship and the source library is prompted FROM real labels — the adidas jacket renders a legible trefoil. Screened on a contact sheet, then relabelled in parody voice (Paddy's Bootleg, Kaymart, Coogee Knits, Mombo, Stoosh). FIVE DEFECTS FOUND AND FIXED, one long-standing: buyMesh has been INVISIBLE on every GLB fitting since R9 (hiding every buyable item under ?stock=real) · DJ booths were nondeterministic (parts attached in network order) · booth gear floated at 0.92 m · batch.js dropped userData sub-tags on merge, so any post-batch flag read was already a no-op · the path guarantee could empty a room (pub/wide/4242 returned a bar, a stage and nothing else) — new restore pass, 129 pulled -> 101 restored over 480 rooms, path re-proved on every restore. Gates: 288-room sweep x 4 arms all pass; soak 60 rooms avg 3.83 ms worst 10.3 ms, leaks 0; 960-room corpus 0 path-fails 0 carves; determinism byte-equal across fresh contexts (sha256 c26b4848); ?noassets=1 60 rooms with 0 GLB / 0 manifest / 0 wardrobe / 0 stock fetches. DJ control nodes recorded on fitting.controlNodes for a future driver (glTF drops the limit constraints — a driver must clamp travel itself). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
eeba920d68 |
Lane C R39 §39.3: the op shop gets a bin — the verb table, and the margin was never six
THE TABLE (LANE_C_PUB §10, the deliverable): what a player can actually do in each of the 12 shop types, counted in 48 rooms per type. `record` digs (4.6 bins/room) and is the only room where anything can be sold. `stall` digs — in 27 of 48 rooms; the other 21 (44%) have NO crate, a measured correction to the round's binding fact #5. The other ten types offer looking. `?stock=real` is opt-in, so the default boot has zero `buyMesh` anywhere; garments/snacks/magazines/treasures are unbuyable in any mode; `interactable:true` on cases/fridges/returns/arcade is read by nothing. THE MECHANISM: `rummageBin` — a castored galvanised dump tub, rim 0.76 m, heaped with stickered bric-a-brac and a hand-lettered "EVERYTHING $2" card. 72 rooms: placed 72/72, reachable 72/72 (0.77–1.15 m), 0 carves, pathOK 72/72, deterministic 72/72, and the rest of the room byte-identical to pre-R39 72/72 (the spec is appended last). Armed end-to-end: aim → dig → 16 offers → BUY → bin depletes. Default: 0 bins, dig never opens. THE CONTENTS ARE NOT SHIPPED. `o.dig` defaults false, so the tub is furniture and the economy is untouched; `opts.fittingOpts.rummageBin.dig` (or `?opshopdig=1`) arms it. Held for John with the numbers: 44 record + 36 stall vs 147 op shops across 23 towns. THE BUDGET: `C-progress.md:841`'s GLB-on 344 is R9-era and stale — today's tree measured 319 before I touched it, so the margin was 31, not six. The bin costs +5 GLB-off / +10 GLB-on at opshop/hall; every other type byte-identical. Margin now 21. Also: `slot.pool` stops the scatter fill minting a material per item, so 12 goods cost less than 9 did. FILED, NOT FIXED: Lane E's bookshelf GLB ships transmission:1, which triggers three.js's transmission pre-pass and issues every draw in the room twice — opshop/hall 191→104, book/hall 101→51. Roughly half the interior budget. E's asset, so E/F rule. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
369a2be23e | Lane C R30 (v7.0-alpha ledger #2, implementation): sell.js — the sell counter lands. E at the bench → the mirrored price sticker; offer strictly below pricePaid by construction (8/8 scripted round trips lose money); type=type fail-closed (untyped item sells nowhere); wallet.sell = the credit mirror; game layer absent → no card, zero errors. Verified on :8144 no-store, stubbed game shape (F's core not landed); soak green avg 3.4ms · leak 0/0 · draws card-open ≡ closed | ||
|
|
c68bba8f32 |
Lane C round-9 C2: buy-anywhere — pull-and-buy on book spines + toy boxes
Book/toy shelves get pull-and-buy over the SAME wallet; records keep the deep dig. New stockpack.buildBuyableShelf(): a real shelf is merged, per-item-ADDRESSABLE meshes — one per atlas (all covers drawn from one seeded atlas → one draw/shelf), tagged noBatch so batch.js leaves them intact. Aim a spine/box → pull card (title/author-or-maker/$price/band from the pack index) → BUY debits the wallet, adds to inventory, and collapseBuyItem() zero-areas the item's quad in place (removed from the shelf, no geometry churn). Parody stock → no buy mesh → no card. Fail- soft per pack; atlasPool() keeps each shelf single-atlas (one draw). Test page: E interacts (bin→dig, shelf→card) + a #shelfBuy pull card; shelfBuySoak() buys one item per book/toy seed. Validated: raycast→card →BUY end-to-end (quad collapses to centre, cash/inventory update), buy-soak 6/6 collapseOk leak geo0/tex0, ?stock=real draws record 41/ book 58/toy 57 ≤350, drawSweep GLB-off 168/on 344 unchanged, placement determinism 0 fails, qa --strict GREEN 5/5. Shot: browse_buy_r9.jpg. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
5ae635a1e9 |
Lane C round-9 C1: seeded browse points (room.browsePoints) for Lane D rigs
layout.js placeBrowsePoints(): 1–3 deterministic floor poses in front of
browsable floor fittings, facing the goods. Guarantees (all asserted):
walkable (occ-free, not reserved), reachable from spawn (door→counter
flood-fill), ≥0.6m apart + clear of keeper stand, every archetype (rich
candidate ring — 4 sides×2 gaps + diagonals — plus a nearest-free-cell
fallback so tight/mismatched rooms still yield ≥1). Pure data: no meshes,
no draws; ≤350 law untouched. Exposed as room.browsePoints[]
{x,z,ry,atKind,slotIndex}, same coord frame + ry convention as
counter.stand (contract in LANE_C_NOTES).
Validated headless: 180 type×archetype×seed combos → 0 empties (177×3,
3×1 via fallback), determinism 0 fails, min-sep 0.7m, 0 keeper clashes.
Test page: cyan browse-post markers on the 'path' overlay + HUD count.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
fbc8ffa1c8 |
Lane C round-8: buy loop v0 + book/toy real stock (?stock=real)
C1 — buy loop v0 (new wallet.js): runtime-only economy — seeded cash (~$60–200), buy()/broke-gate/in-memory bag, onChange for a cash chip. World gen untouched (purchases never re-enter the plan/seeded build). Test page: #cashChip HUD + I-toggle inventory + dig BUY IT button (pull → bag, cash down, bin depletes); digSoak buys ≤2/visit. C2 — book spines + toy boxes wired to ?stock=real. stockpack.js keys each pack to a slot (record→sleeve, book→spine, toy→box); stock.js shelfLine builds real atlas-UV cover planes for book/toy shelves (static, no dig), fail-soft per pack. E's packs live: record 350/6, book 311/4, toy 273/5 (items/atlases). C3 — validated: draws ≤350 (record 41, book 42, toy 51), determinism 0 fails, leak-free (0 geo/tex delta ×20; buy-soak 12 visits/5 bought, leakGeo0/tex0), reload resets wallet, flag-off + ?noassets untouched, qa.sh --strict GREEN 5/5. Shot: docs/shots/laneC/buyloop_r8.jpg. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
3724a65505 |
Lane C R7 C1: ?stock=real — real GODVERSE sleeves in the crates
The stockAdapter seam built in v1 finally eats. Lane E's stock pack (parody-
transformed Discogs metadata + cover atlas) feeds record-shop bins + the dig
riffle behind ?stock=real. Economy stays a stub (buying = toast).
- Contract handshake (task 1, unblocked E): confirmed E's index schema as-is
in LANE_C_NOTES (items[{id,title,artist,price,price_band,atlas,uv}]; uv
origin top-left, C flips V for WebGL; fail-soft; per-type packs).
- stockpack.js (new): preloadStockPack/getStockPack (cached) + makeStockAdapter.
Atlas texture + material are shared/cached (like depot GLBs); each sleeve is
a cover PLANE sampling the atlas at its baked UV, so all real sleeves in a
room batch to ONE draw (record: 59 draws).
- stock.js binFan: real cover planes (else parody canvas). dig.js: riffles real
covers, pull card shows title/artist/$price/band. interiors.js: opts.stock=
'real' wires the adapter (warn-once + parody fallback if pack absent). Test
page reads ?stock=real, preloads record/book/toy, passes the adapter to the dig.
Validated (E's staged 24-sample; real covers drop in unchanged when E gets the
DB): determinism 0/30, leak-free rooms + real dig (0/0 over 25 cycles), draws
<=139 all rooms (record 59), fail-soft on no-pack types, ?dig=1&stock=real
leak-free. Flag-off + ?noassets untouched (procedural path byte-identical).
qa.sh --strict GREEN. F smoke hook + E contract in LANE_C_NOTES. Shot
docs/shots/laneC/stock_real_r7.jpg.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
35981ade5f |
Lane C R6 C1: interior draw batching (<=350 draws/room law)
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> |
||
|
|
7131f530a4 |
Lane C R5 C2: crate-riffle dig behind ?dig=1 (v2)
Ported 90sDJsim/web/world/dig.js → web/js/interiors/dig.js. Walk to a record bin, press E, riffle its sleeves (scroll/drag), click the front sleeve to pull it, BUY IT. Faithful to the source: hinge-forward riffle, pull-and-inspect panel, procedural fwip/thunk audio. - Riffle items = seeded procedural sleeves per bin via the stockAdapter(shop, 'sleeve') seam (parody 90s-AU records now; real GODVERSE records feed the same seam in round 6+). Same bin ⇒ same order. - Buy is STUBBED (toast + remove-from-bin; getCash returns a constant) — economy is round 6+ per integrator decision #1. - Own scene + camera; leak-free: per-open GPU resources (sleeve textures/ materials, crate parts) freed on every close(), persistent set freed on dispose(). Dig soak (20× enter/leave) → leakGeo 0 / leakTex 0. - Flag-gated (?dig=1): buildInterior is UNTOUCHED, so ?dig=0 boot is byte-identical to v1 (prime law). The dig is wired only in the test page via an E-key raycast; F owns the shell input/mode seam — hook documented in docs/LANES/LANE_C_NOTES.md. Verified: riffle + pull + buy-stub work; dig soak leak-free; placement determinism unaffected; close returns to the interior. qa.sh --strict GREEN. Shot: docs/shots/laneC/dig_riffle_r5.jpg. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
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>
|
||
|
|
fe40ea7d0a |
Lane C: round-3 GLB hero-prop validation (useGLB path)
Validated Lane E's 9 fitting GLBs in real rooms. 5 good, now live behind useGLB (wire_shelf, clothes_rack, bookshelf, cube_shelf_wide, work_table); record_crate broken (won't load) + counter too long/no-till fall back to primitive. Report: docs/LANES/LANE_C_GLB_VALIDATION.md. glb.js: real-metre scale clamped to footprint, per-kind yaw for Z-major assets (+90deg) per manifest facing convention, manifest.localBase for offline validation, awaitable upgrades. interiors.js: room.glbReady. interior_test.html: GLB toggle. Soak useGLB on (50 rooms): throws 0, pathFail 0, detFail 0, leakGeo 0, leakTex 0, worst 10.5ms, 256 upgrades. qa.sh --strict green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
8577c48594 |
Lane C: keeper stand pose on the counter contract (re-land on main)
buildInterior now returns room.counter = { mesh, pose, stand } and tags the counter
interactable with userData.keeperStand. stand = {x,z,ry} where a shopkeeper stands
(service side, facing the customer, rig-front = local -Z per keepers.js), clamped
in-bounds. Deterministic; purely additive.
Note: commit
|
||
|
|
0e9d3fb0f2 |
Lane C: on-demand seeded shop interiors (library + test page)
Every shop door opens into a unique, believable, seeded interior — generated
in ~4ms, byte-identical every revisit (shop.seed), themed by shop.type.
- interiors.js: buildInterior(shop, THREE, opts) public API — pure fn of shop,
returns {group, spawn, exits, places, dims, placement, dispose()}.
- theme.js: 9 CITY_SPEC type recipes (archetype/wallpaper/floor bias, clutter,
counter pos, fittings mix, stock kind, signage) + type aliasing + one-time
mergeRegistry() override seam for Lane F. Standalone (no hard registry dep).
- shell.js: room shell from lot x archetype (cosy/gallery/wide/hall/pokey),
glazed shopfront + street backdrop, blocked back doorway, interior lighting.
- fittings.js: parametric kit ported from 90sDJsim + extended (bins, crates,
4 shelf types, VHS aisle, glass case, counter+till, fridge, magazine/spinner
racks, armchair, escalator, pegboard, barred window, returns slot, art).
- layout.js: per-archetype zones, thriftgod shuffled wall-slot system,
occupancy grid, guaranteed door->counter flood-fill path (pull/carve).
- stock.js: v1 visual stock (pooled canvas sleeves/spines/boxes/garments/snacks
with price stickers) + stockAdapter hook for BaseGod content later.
- context.js: seed sub-streams + shared-geometry cache + leak-free disposeAll().
- glb.js: optional GLB hero-prop upgrade via Lane E manifest (off by default,
primitive fallback).
- interior_test.html: standalone page — seed/type/archetype, first-person walk,
wireframe/occupancy/path debug, 50-room soak (perf + leak + determinism).
Acceptance (verified): same seed -> identical placement (0/810 mismatches);
9 types x 5 archetypes render sensibly (docs/shots/laneC grid); build <50ms
(steady ~4ms, soak worst 8ms); leak-free dispose (geo/tex delta 0); door->counter
path always exists (0 fails, 0 carves); runs with zero assets and zero network.
Adversarial multi-agent review: 5 findings, all fixed and re-verified.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|