72 lines
4.6 KiB
Markdown
72 lines
4.6 KiB
Markdown
# LANE C — INTERIORS (every door opens)
|
||
|
||
> **Prompt for Opus 4.8.** You are working in `/Users/jing/Documents/PROCITY`. Read
|
||
> `docs/CITY_SPEC.md` and `docs/RESEARCH.md` first, then the two sources you are porting:
|
||
> `thriftgod/web/index.html` `buildShop()` (line ~1109+, archetypes `SHOP_SHAPES`, wall-slot
|
||
> system, seeded decor) and `90sDJsim/web/world/fittings.js` (parametric fittings kit — read it
|
||
> whole, it was written to be lifted). You own `web/js/interiors/*` and `web/interior_test.html`.
|
||
> Do not touch other lanes' files. Plain ES modules, three.js from `web/vendor/` importmap,
|
||
> randomness via `core/prng.js` only. Commit in small, described steps on `main`.
|
||
|
||
## Mission
|
||
|
||
The Vuntra move: **every shop door opens into a unique, believable, seeded interior** —
|
||
generated on demand in <50ms, byte-identical every revisit (`shop.seed`), themed by `shop.type`.
|
||
This lane is a standalone library + test page; Lane B wires it to real doors later via the
|
||
`procity:enterShop` / `procity:exitShop` events (contract in LANE_B).
|
||
|
||
## Architecture
|
||
|
||
- `web/js/interiors/interiors.js` — public API:
|
||
```js
|
||
buildInterior(shop, THREE) → { group, spawn:{x,z,ry}, exits:[{x,z,w, toStreet:true}],
|
||
places:[…userData-tagged interactables], dispose() }
|
||
```
|
||
Pure function of `shop` (a CityPlan shop record + its lot dims). No global state.
|
||
- `web/js/interiors/shell.js` — the room shell: floor/walls/ceiling sized from the lot
|
||
(`lot.w × lot.d`, storeys → ceiling height 3.2–4.5m), seeded from the 5 thriftgod archetypes
|
||
(**cosy / gallery / wide / hall / pokey**) adapted to lot proportions, plus door/shopfront
|
||
wall with real glazing (you can see a hint of street), back room doorway (blocked v1).
|
||
Materials: seeded pick of `wall-*.jpg` wallpapers, `tex-carpet-*`/`tex-lino-*` floors,
|
||
`tex-*` counters — all already in `web/assets/gen/`, all with flat-colour fallbacks.
|
||
- `web/js/interiors/fittings.js` — port 90sDJsim's kit and extend it. Needed set (see the
|
||
registry's fittings mixes): record bins & crates, clothes racks, wall/cube/metal shelving,
|
||
bookshelves, VHS aisle shelving, glass display case, counter + till, trestle tables, fridge,
|
||
magazine rack, poster/art frames (`art-*` future), pegboard walls. Parametric primitives
|
||
first; where a GLB upgrade exists use the manifest (see below) with primitive fallback.
|
||
- `web/js/interiors/layout.js` — the placer: per-archetype floor zones (window display / aisles
|
||
/ walls / counter-corner), the thriftgod **shuffled wall-slot system** so nothing overlaps,
|
||
density from shop seed (some shops crammed, some sparse), guaranteed walkable path from door
|
||
to counter (grid-mark occupied cells; verify connectivity with a flood fill — assert it).
|
||
- `web/js/interiors/stock.js` — v1 *visual* stock only: product boxes/sleeves/spines as
|
||
canvas-texture blocks on shelves (steal the dig.js sleeve-canvas trick — coloured cardboard +
|
||
price stickers). Real items are the content phase; leave a `stockAdapter` hook:
|
||
`(shop, slotKind) => texture/mesh` so BaseGod data can plug in without touching layout code.
|
||
- **GLB upgrades**: read `web/assets/manifest.json` if present (Lane E ships it) mapping fitting
|
||
ids → 3GOD depot files; promise-cached loader, placeholder-persists pattern. The test page
|
||
must be fully usable with no manifest and no network.
|
||
- Windows-from-street problem (Lane B fakes it): you own the *inside-looking-out* — a simple
|
||
backdrop plane beyond the glazing (street-ish gradient / `sky-*` slice) sells it in v1.
|
||
|
||
## Type theming (registry-driven)
|
||
|
||
Import `SHOP_TYPES` from `core/registry.js`; every type in CITY_SPEC's table gets a distinct
|
||
recipe (fittings mix, wallpaper bias, clutter level, counter position, signage-inside flavour).
|
||
A `record` shop must *instantly* read different from a `toy` shop from the doorway. Milk bar
|
||
counter faces the door; pawn shop is counter-forward with wall hooks; dept anchor is the
|
||
"grand hall" archetype with mixed sections.
|
||
|
||
## Test page (`web/interior_test.html`)
|
||
|
||
Standalone: seed input, type dropdown, archetype override dropdown, "re-roll", first-person walk
|
||
inside (reuse PointerLock pattern), wireframe/occupancy-grid debug toggle, and a "50-room soak"
|
||
button that builds+disposes 50 seeded interiors and reports ms/room + leaked geometries
|
||
(`renderer.info.memory` before vs after — must return to baseline).
|
||
|
||
## Acceptance
|
||
|
||
- Same seed twice → identical room (soak test asserts deep-equal on placement lists).
|
||
- All 9 types × 5 archetypes render sensibly (screenshot grid into `docs/shots/laneC/`).
|
||
- Build <50ms/room, dispose leak-free, flood-fill path door→counter always exists.
|
||
- Runs with zero assets (fallback colours) and zero network.
|