# 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).