v3.0-alpha band room. New pub recipe (venue:true): stage + PA + amps at the back wall (new stage/paSpeaker/ampStack fittings, GLB slots stage/pa_speaker/amp for E), bar counter (keeper), sticky carpet, blocked back door = green room.
buildInterior returns for venues: room.watchPoints[] (6-8 seeded audience poses {x,z,ry,dance} facing the stage, dance ~1/3, counter.stand ry convention); room.stage {x,z,w,d,deckY,frontZ,bandPoses[3]} for Lane D's band; room.audio.gigKey ('gig-'+genreKey) set when Lane F passes opts.gig.
Flags-off byte-identical: venue code runs only for recipe.venue on its own seed sub-streams; non-pub rooms have watchPoints:[], stage:null, unchanged placement/audio.
Verified: 40-seed pub sweep (0 throws/carves/path-fails, 8 watchPoints, dance 0.38) + 60-room mixed soak (0 det/path fails, leak geo0/tex0, worst 19ms). Non-pub unchanged. Interface for D/F: docs/LANES/LANE_C_PUB.md. scaffold + manifest green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
56 lines
3.5 KiB
Markdown
56 lines
3.5 KiB
Markdown
# LANE C — pub venue interface (round 12, v3.0-alpha) → for Lane D + Lane F
|
||
|
||
*PROCITY-C, 2026-07-15. R12 §Lane C. The band room ships behind `?gigs=1` (A only emits `pub` shops
|
||
when the flag is on). Interface published here + in this commit's code; non-pub rooms are byte-identical
|
||
(the venue code only runs for `recipe.venue`, on its own seed sub-streams). Verified: 40-seed pub sweep +
|
||
60-room mixed soak — 0 throws · 0 carves · 0 path-fails · 0 determinism-fails · leak geo0/tex0 · worst 19 ms.*
|
||
|
||
## What `buildInterior` returns for a pub (type `'pub'`)
|
||
Everything below is **pure data on the return** (room-local coords, `counter.stand` ry convention:
|
||
rig-front = local −Z), so Lane D drops rigs straight in and Lane F reads state — no new lifecycle.
|
||
|
||
### `room.stage` — the band stage (null for non-venues)
|
||
```js
|
||
room.stage = {
|
||
x, z, // deck centre (against the back wall)
|
||
w, d, // deck size (m)
|
||
deckY, // top surface height (m) — band rigs stand at y = deckY
|
||
frontZ, // z of the deck lip (the crowd stands in front of this, +Z)
|
||
bandPoses: [ { x, z, ry, role } ×3 ], // guitar / vocal / bass, across the deck front, facing the crowd (ry=π → +Z)
|
||
}
|
||
```
|
||
**Lane D:** put the 3-piece band at `bandPoses` (lift to `y = deckY`); `role` hints instrument. Drummer
|
||
can sit up-stage on the riser (there's a raised riser at deck-centre-back) — your call, C just gives 3 front poses.
|
||
Instruments = E's GLBs when present, primitives otherwise (asset law).
|
||
|
||
### `room.watchPoints` — the audience (empty [] for non-venues)
|
||
```js
|
||
room.watchPoints = [ { x, z, ry, dance, slotIndex } ] // 6..8 seeded floor poses, all facing the stage centre
|
||
```
|
||
- `dance` is seeded **~⅓ true** ("a bit of both"). **Lane D:** `dance:false` → stand-and-watch idle
|
||
(subtle weight-shift); `dance:true` → bob/sway/step loop with a **seeded phase offset** so the crowd
|
||
doesn't metronome (use `slotIndex` or the pose coords to derive the phase).
|
||
- Every point is walkable, reachable from the door, and clear of the keeper stand, browse points, and the
|
||
stage/PA footprint. Deterministic per shop.seed. Crowd cap = `watchPoints.length` (F's smoke asserts ≤).
|
||
|
||
### `room.counter` / keeper — unchanged
|
||
The bar is a normal counter; the **barkeep is just a keeper** at `room.counter.stand` (existing R9 seam).
|
||
|
||
### `room.audio.gigKey` — the live bed
|
||
`room.audio = { musicKey, toneKey, gigKey? }`. **Lane F** passes gig state via `opts.gig` to `buildInterior`:
|
||
```js
|
||
buildInterior(pubShop, THREE, { gig: { on: true, genreKey: 'pubrock' } })
|
||
// → room.audio.gigKey === 'gig-pubrock' (gigKey = 'gig-' + genreKey)
|
||
```
|
||
- `gigKey` is present **only when a gig is on**. A quiet-night pub has no `opts.gig` → normal interior
|
||
(`toneKey` room-tone + maybe the seeded radio `musicKey`).
|
||
- **Prefer `gigKey` over `musicKey`** while the gig plays: `play(room.audio.gigKey || room.audio.musicKey)`.
|
||
- **Lane E:** please name the pub-rock live bed **`gig-pubrock`** in `manifest.audio` (music or a `gig`
|
||
section) so the key resolves; missing key → silence (audio law), band still visible.
|
||
|
||
## The archetype (C-owned, FYI)
|
||
`pub` recipe (`theme.js`, `venue:true`): stage + PA + amps at the back wall, bar counter (`corner`),
|
||
sticky-carpet floor, pub tables + bar-back shelf against the walls, the blocked back doorway doubles as
|
||
the **green room**. Primitive stage/PA/amp fittings today with **GLB slots for Lane E**: `stage`,
|
||
`pa_speaker`, `amp` (house GLB law; primitive fallback holds — a gig with no GLBs is still a gig).
|