destroyulator/LANES/LANE10-record-store.md
Monster Robot Party 8e61640c38 LANE10: SITE 7 — the real shop, imported from its own database
The level the whole game started as, and the only one that isn't authored.

robotmonster.party/store/ is assembled procedurally from Postgres (the wowplatter
virtual_* schema, served by recordgod), and this game's sites are already data — so
tools/import_store.py reads the live shop and emits assets/store/shop_floor.json:
the actual 6.66 x 9.51 m floor, 35 racks across 21 archetypes, 278 bins carrying
their real genre labels (HARD TRANCE, $12-$15 EURO/ITALO HOUSE), 21,159 records
of stock. Levels.record_store() loads it; 'store' joins ORDER as the seventh site.

The shop's schema IS the cascade. virtual_crate.rack_id already records which rack
holds which bin, so bins arrive frozen and supported_by their rack and none of the
structure is authored. To carry that, smashables gained two optional generic keys —
'id' and 'supported_by' — so any level can express support as data. Every existing
level is unaffected.

Two reconciliations, because a storefront is a renderer:
- Mesh sizes are a lie: 21 archetypes share a few stand-in GLBs, so each piece
  carries 'fit' (the archetype's real dims from the shop's table) and _glb_piece
  scales the visual to it and builds the collider from it. Also fixed racks being
  flattened to the floor — pos_y is a piece's BOTTOM, which is what sit_on means,
  so the ceiling beams, aircon and wall shelves now stay up where they belong.
- Nothing collides in a renderer: racks that sat inside each other for years get
  separated (weighted, so racks barely move and aisles keep their shape — 3 m of
  correction across 35), rack footprints inset 1.5 cm a side for the few genuinely
  wedged units, and the importer AUDITS ITS OWN OUTPUT with the same test
  probe_overlap runs. Bins are deliberately not separated from their rack: cargo
  inside a container is what the shop means, they spawn frozen, and the audit skips
  frozen bodies because a frozen body cannot be depenetrated across the room.

dev/probe_store.gd: 22 racks hold bins, 255 labels survived, and smashing the rack
carrying 22 bins releases exactly those 22 while the other 256 stay frozen.
All gates green: smoke clean, 7/7 sites 0.00 m/s, overlap CLEAN, LANE9 probes pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 00:49:49 +10:00

64 lines
3.2 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 10 — SITE 7: MONSTER ROBOT PARTY
*The level the whole game started as. Spec'd and executed by Fable, 2026-08-04.*
## The idea
Every other site is authored. This one is **imported from the real shop**. The live
storefront at `robotmonster.party/store/` is procedurally assembled from Postgres rows
(`virtual_rack`, `virtual_crate`, `virtual_rack_type*`, `virtual_crate_type` — the
wowplatter schema, now served by recordgod/storegod), and the game's sites are already
data. So Site 7 is not hand-placed: a converter reads the shop and emits a level.
`GET https://robotmonster.party/virtual/scene` returns the shop floor:
| | |
|---|---|
| room | 6.66 m × 9.51 m, 2.89 m ceiling |
| racks | 35 placed, across 21 archetypes |
| crates | 302, every one on a rack |
| labels | real: `HARD TRANCE`, `$12-$15 EURO/ITALO HOUSE`, `SOUND TRACKS, SPOKEN WORD & COMEDY` |
| stock | **22,049 records** across the bins (`n_items`) |
The rack archetype names (`wooden-rack-type-long`, `white-tub-3x3`, `chiu-long`) are the
same names as the GLBs in `3D-STORE/`, because both were generated from the same table.
## Why this is the best-fitting level in the game
The shop's schema **is** the cascade. `virtual_crate.rack_id` already says which rack
holds which bin, so `rack.supports = [its crates]` falls out of the data — knock a rack
and the real bins that really sit on it really go over. Nothing to author.
## Deliverables
### 1. Generic data-driven cascade *(`Main.gd`, small)*
Extend the `smashables` spec entry with two optional keys so a level can express support
without code: `"id"` (a name other entries can refer to) and `"supported_by"` (the id of
the piece holding this one up). Main builds in order, keeps `id -> Smashable`, and wires
`holder.supports.append(piece)`. Every existing level is unaffected.
### 2. `tools/import_store.py` — the converter
Fetches the live scene (`--url`, or `--offline <file>`), filters to the shop-floor space,
and emits `game/assets/store/shop_floor.json`:
- world-space rack positions, **re-centred** (the shop's origin is a corner; the game
centres its bounds on 0)
- each crate placed by `rack_pos + rotate_y(crate_local, rack.rotation_y)`, carrying its
real `label` and `n_items`
- archetype → game GLB + material mapping (tubs are `plastic`, timber racks `wood`,
columns and aircon `steel`)
- crates spawn **frozen** and supported by their rack: they don't jitter at spawn (the
stillness gate stays green) and they go live exactly when the rack does
- a **measured spawn point** — a grid scan for open floor, because a 6.66 × 9.51 room
holding 35 racks has very little of it, and spawning inside a rack is not a level
Re-runnable: when the real shop is rearranged, re-run it and the level changes.
### 3. `Levels.record_store()` — the site
Loads the JSON and returns a normal Floorplan spec. Timber floor, white walls, the
brand's pink as accent. Added to `Levels.ORDER` as the seventh site.
## Gates
Headless smoke clean · `probe_levels` **7/7** at 0.00 m/s · `probe_overlap` CLEAN ·
the LANE9 probes still green. Plus `dev/probe_store.gd`: the site builds, the rack→crate
cascade is wired, and smashing one rack releases exactly its own bins.