Lane C R16 (v3.1): stage.backline[] amp unification, drop primitive ampStacks (ledger #5, C half)
C exposes room.stage.backline[] — 2 seeded up-stage amp slots {x,z,ry,y} (pure data) — and
drops its primitive ampStacks from placeStage. Lane D plants E's guitar_amp GLB at backline[0]
(D's primitive fallback under ?noassets): one unified backline, GLB when present.
- backline[0] = (stage.x + stage.w*0.36, deckY, stage.z - stage.d*0.22) == D's R15-verified amp
pose exactly, so plumbing D's plant to backline[0] moves nothing on screen. backline[1] = spare
stage-left mirror. ry=pi (audience-facing), y=deckY.
- Verified fresh (seed 20261990): slots up-stage, on-deck, clear of all 4 bandPoses (nearest-bass
0.87 pub / 0.70 band_room / 0.92 rsl) and all watchPoints (>=1.95 m); determinism byte-identical;
0 leftover ampStack groups; drawSweep venues 122/120/131 (was 126/124/135, -~4 draws each) <=350.
- Determinism/golden-safe: dropping the amp loop only drops draws on the 'stage' sub-stream (nothing
downstream reads it); placement snapshot excludes ampStacks; interiors aren't hashed; ?classic has
no venues. Disjoint from F's flip. LANE_C_PUB §3 amended (v3.1 marker).
C->D handshake: backline shape live. Verify with D once the GLB is wired at backline[0].
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
b9e3f3a92d
commit
42b11e717d
@ -3,7 +3,35 @@
|
||||
*Status: **v1 complete & verified**. Standalone interiors library + test page. Every shop door opens
|
||||
into a unique, seeded, themed interior, generated on demand in ~4ms, byte-identical every revisit.*
|
||||
|
||||
Last updated: 2026-07-16 (round 15) · owner: PROCITY-C · reviewer: Fable
|
||||
Last updated: 2026-07-16 (round 16) · owner: PROCITY-C · reviewer: Fable
|
||||
|
||||
---
|
||||
|
||||
## Update 2026-07-16 (round 16, v3.1 THE FLIP) — the backline handoff (C's half of ledger #5)
|
||||
|
||||
R16 §Lane C (ledger #5, C's half): unify the amp. **`room.stage.backline[]`** now exposes 2 seeded up-stage
|
||||
amp slots `{x,z,ry,y}` (pure data, no meshes), and C's **primitive ampStacks are dropped** from `placeStage` —
|
||||
Lane D plants E's `guitar_amp` GLB at `backline[0]` (its own primitive fallback under `?noassets`), one amp
|
||||
system. Shape published in [LANE_C_PUB.md](docs/LANES/LANE_C_PUB.md) §3 (v3.1 amendment marker; rest of the
|
||||
frozen doc unchanged). **C→D handshake: backline shape is live.**
|
||||
|
||||
- `backline[0]` = stage-right `(stage.x + stage.w·0.36, deckY, stage.z − stage.d·0.22)` == D's R15-verified
|
||||
amp pose exactly, so wiring D's plant to it moves **nothing** on screen. `backline[1]` = stage-left spare
|
||||
(mirror). ry=π, y=deckY.
|
||||
- **Verified fresh (port-isolated, seed 20261990):** both slots up-stage, on-deck, clear of all 4 bandPoses
|
||||
(nearest-bass **0.87 m pub / 0.70 m band_room / 0.92 m rsl**) and all watchPoints (≥1.95 m); determinism
|
||||
byte-identical (placement + stage + watchPoints); 0 leftover ampStack prop groups; drawSweep glb-off venues
|
||||
**pub 122 · band_room 120 · rsl 131** (was 126/124/135 — the dropped primitives shaved ~4 draws each), worst
|
||||
161 (opshop/hall, unchanged). ≤350 ✓.
|
||||
- **Determinism/golden safety:** removing the ampStack loop only drops draws on the `stage` rng sub-stream,
|
||||
which nothing downstream reads; the `placement` snapshot excludes ampStacks (never tracked), so it's
|
||||
byte-identical. Interiors aren't hashed into any golden; the `?classic=1` boot has no venues → untouched.
|
||||
- Disjoint from F's flip (interiors don't read flags) — landed early so D isn't blocked. **Verify with D
|
||||
once wired** (ledger #5 D-half): re-render each archetype, confirm the GLB at `backline[0]` doesn't
|
||||
interpenetrate (pending D's R16 commit).
|
||||
|
||||
**Code:** `layout.js` placeStage (backline[] + drop the amp loop), `interiors.js` API doc. `theme.js` untouched
|
||||
(recipes carry no ampStack fitting — the primitives were placeStage-planted, not recipe fittings).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
> **v3.0-FROZEN** · 2026-07-16 · durable contract for Lane D + Lane F. Describes the *shipped* state;
|
||||
> changes require a version bump (CITY_SPEC amendment law). Verified R13 (build) + R14 (release audit).
|
||||
> **v3.1 amendment (2026-07-16):** §3 becomes the `stage.backline[]` contract (ledger #5 — the amp
|
||||
> unification); C dropped its primitive ampStacks. Everything else in this doc is unchanged and stands.
|
||||
|
||||
*The district ships **three** venue archetypes behind `?gigs=1` — `pub`, `band_room`, `rsl`. Lane A
|
||||
converts a chosen shop to a venue kind in place (`shop.type = kind`); C keys the interior recipe off
|
||||
@ -97,17 +99,22 @@ No `opts.gig` → a normal interior: `stage` + `watchPoints` are still returned
|
||||
`gigKey`** (room-tone + maybe the seeded radio `musicKey`), and D spawns no crowd. A seeded dark night reads
|
||||
true — the venue is just a quiet pub/club.
|
||||
|
||||
## 3. `guitar_amp` placement (v3.0 — RESOLVED R15)
|
||||
## 3. `stage.backline[]` — the amp slots (v3.1, ledger #5)
|
||||
|
||||
**Resolved.** D plants E's `guitar_amp` GLB (`band.js _addBackline`) up-stage-right at **`(stage.x +
|
||||
stage.w·0.36, deckY, stage.z − stage.d·0.22)`** — C's corrected pose (ledger #4). It's on-deck, up-stage of
|
||||
the front line, and flanks C's own primitive ampStack (stage-left) as a clean backline. **Verified R15 (fresh
|
||||
context, seed 20261990):** clearance to the bass rig **0.87 m (pub) / 0.92 m (rsl)** — no interpenetration
|
||||
(the original R14 pose `stage.z + 0.15` was down-stage, 0.29 m off the bass, and clipped it); amp↔primitive
|
||||
4.4 m (pub) / 3.5 m (rsl); on-deck both. C's `placeStage` plants **1–2 primitive `ampStack` fittings** at
|
||||
`(±stage.w·0.28, deckY, stage.z − stage.d·0.18)` as the asset-free backline fallback (no GLB slot, so they
|
||||
stay primitive). *v3.1:* full unification — C exposes a `stage.backline[]` slot list that D's GLB fills,
|
||||
replacing the primitive — stays deferred (no new contract fields in v3.0).
|
||||
`room.stage.backline = [ { x, z, ry, y } ×2 ]` — seeded up-stage amp/spare-cab poses, **pure data** (C plants
|
||||
no amp meshes as of v3.1). This is the unified backline: **Lane D plants E's `guitar_amp` GLB here** (its own
|
||||
primitive fallback under `?noassets`) — one amp system, GLB when present. C's old primitive ampStacks are
|
||||
**dropped** from all three venue recipes.
|
||||
- **slot[0]** = stage-right (the primary amp) at `(stage.x + stage.w·0.36, deckY, stage.z − stage.d·0.22)` —
|
||||
identical to D's R15-verified plant, so wiring D's amp to `backline[0]` moves nothing on screen.
|
||||
**slot[1]** = stage-left spare cab (mirror). `ry = π` faces the audience (+Z, the §0 convention); `y = deckY`.
|
||||
- **Guarantees** (verified fresh, seed 20261990, pub/band_room/rsl): every slot is **up-stage of the front
|
||||
line**, flanks the drum riser, **clear of all 4 bandPoses** (nearest-bass clearance **0.87 m pub / 0.70 m
|
||||
band_room / 0.92 m rsl**) and **all watchPoints** (≥1.95 m), and **on-deck** (within the deck footprint).
|
||||
Deterministic per `shop.seed`. **Lane D:** verify no interpenetration once wired (C's R15 clearance discipline).
|
||||
- **Draw impact:** dropping C's primitives shaved ~4 draws off each empty venue shell (drawSweep glb-off:
|
||||
pub 122 · band_room 120 · rsl 131 ≤350); D's GLB/primitive at `backline[0]` adds it back on the gig night.
|
||||
- *v3.2 (parked):* the drummer sit clip, instrument LOD, and C's `audioEmitter` idea.
|
||||
|
||||
## 4. Budgets (measured R14, seed 20261990, fresh context)
|
||||
- **Empty shells** (`drawSweep` glb-off): band_room **124** · pub **126** · rsl **135** — town-wide worst
|
||||
|
||||
@ -25,10 +25,12 @@
|
||||
// watchPoints: [ {x,z,ry,dance,slotIndex} ], // VENUE (R12/13, else []) — audience poses facing the stage;
|
||||
// // dance ~1/3 true. Cap by kind: pub/band_room 8, rsl 12. Same
|
||||
// // frame + ry convention as counter.stand (rig-front = local −Z).
|
||||
// stage: { x,z,w,d,deckY,riserY,frontZ,bandPoses }, // VENUE (R12/13, else null) — the band stage. bandPoses[4]
|
||||
// // (R13): front-line trio (guitar/vocal/bass) on the deck + a drummer
|
||||
// // (role 'drums', seated) up-stage on the riser. Each pose carries y
|
||||
// // (front line = deckY, drummer = riserY). ry=π faces the audience.
|
||||
// stage: { x,z,w,d,deckY,riserY,frontZ,bandPoses,backline }, // VENUE (else null) — the band stage. bandPoses[4]:
|
||||
// // front-line trio (guitar/vocal/bass) on the deck + a drummer (role
|
||||
// // 'drums', seated) up-stage on the riser. Each pose carries y (front
|
||||
// // line = deckY, drummer = riserY). ry=π faces the audience. backline[]
|
||||
// // (v3.1) = up-stage amp slots {x,z,ry,y} where Lane D plants the
|
||||
// // guitar_amp GLB (primitive fallback under ?noassets).
|
||||
// dims: { W, D, H, archetype, type }, // room metrics
|
||||
// placement, // deterministic placement summary (deep-equal per seed)
|
||||
// pathOK, // door→counter connectivity held (always true; carved if needed)
|
||||
@ -176,7 +178,7 @@ export function buildInterior(shop, THREE, opts) {
|
||||
counter: lay.counter, // { mesh, pose:{x,z,ry}, stand:{x,z,ry} } — Lane D keeper spawn pose
|
||||
browsePoints: lay.browsePoints, // [ {x,z,ry,atKind,slotIndex} ] 0..3 — Lane D browser rig poses (R9)
|
||||
watchPoints: lay.watchPoints || [], // venue: [ {x,z,ry,dance,slotIndex} ] audience poses, cap by kind (pub/band_room 8, rsl 12); else []
|
||||
stage: lay.stage || null, // venue: { x,z,w,d,deckY,riserY,frontZ,bandPoses[4] } (4-piece: trio + drummer on the riser); else null
|
||||
stage: lay.stage || null, // venue: { x,z,w,d,deckY,riserY,frontZ,bandPoses[4],backline[] } (4-piece + up-stage amp slots); else null
|
||||
audio: audioFor(recipe.key, ctx, opts, norm.raw), // { musicKey, toneKey, gigKey? } — Lane E manifest.audio keys (R11/R12)
|
||||
dims: { ...dims, archetype, type: recipe.key },
|
||||
recipe: { key: recipe.key, label: recipe.label, counterPos: recipe.counterPos, clutter: recipe.clutter },
|
||||
|
||||
@ -209,10 +209,12 @@ function placeBrowsePoints(grid, placed, counterStand, spawnCell, r) {
|
||||
return pts;
|
||||
}
|
||||
|
||||
// ── VENUE stage (pub, round 12 · behind ?gigs=1) ──────────────────────────────────────
|
||||
// Places a low stage centred on the back wall, PA cabinets flanking it on the floor, and 1–2 amps on the
|
||||
// deck. Stage + PA go into `placed` at priority 8 so the door→counter path loop never pulls them. Returns
|
||||
// the stage frame the crowd faces + 3 seeded band poses on the deck (Lane D drops the band trio in).
|
||||
// ── VENUE stage (v3, ?gigs) ───────────────────────────────────────────────────────────
|
||||
// Places a low stage centred on the back wall + PA cabinets flanking it on the floor (both into `placed` at
|
||||
// priority 8 so the door→counter path loop never pulls them). Returns the stage frame the crowd faces, the
|
||||
// 4 band poses on the deck, and `backline[]` — up-stage amp slots (v3.1, ledger #5) where Lane D plants E's
|
||||
// guitar_amp GLB. C no longer plants its own primitive amps: one unified backline, GLB when present, D's
|
||||
// primitive fallback under ?noassets. Pure pose data; Lane D drops the rigs + amp in.
|
||||
function placeStage(ctx, grid, W, D, roomGroup, r, spec = {}) {
|
||||
const wf = spec.deckWidthFrac || 0.58, deckH = spec.deckH || 0.32; // per-kind (round 13): band_room
|
||||
const sw = Math.min(W - 1.4, Math.max(3.0, W * wf)), sd = spec.deckDepth || 2.0; // barely a riser, rsl bigger
|
||||
@ -234,12 +236,7 @@ function placeStage(ctx, grid, W, D, roomGroup, r, spec = {}) {
|
||||
out.push({ fitting: pf, x: px, z: pz, ry: 0, hw: phw, hd: phd, rect: prect, priority: 8, kind: 'prop' });
|
||||
}
|
||||
|
||||
const deckY = f.deckY || deckH; // 1–2 amps on the deck behind the band
|
||||
for (let i = 0, n = 1 + (r() < 0.5 ? 1 : 0); i < n; i++) {
|
||||
const af = buildFitting('ampStack', ctx, {}, r);
|
||||
af.group.position.set(cx + (i === 0 ? -1 : 1) * sw * 0.28, deckY, cz - sd * 0.18);
|
||||
roomGroup.add(af.group);
|
||||
}
|
||||
const deckY = f.deckY || deckH; // deck top surface (band + backline stand height)
|
||||
|
||||
// 4-PIECE BAND (round 13, debt #3): front-line trio across the deck lip + a drummer up-stage on the
|
||||
// riser. ry=π faces the audience (+Z) under the rig-front=−Z house convention (see LANE_C_PUB.md). Each
|
||||
@ -251,7 +248,18 @@ function placeStage(ctx, grid, W, D, roomGroup, r, spec = {}) {
|
||||
}));
|
||||
const drums = { x: round(cx), z: round(cz - sd / 4), ry: round(Math.PI), role: 'drums', y: riserY, seated: true };
|
||||
const bandPoses = [...front, drums];
|
||||
return { placed: out, stage: { x: cx, z: cz, w: sw, d: sd, deckY, riserY, frontZ: round(cz + sd / 2), bandPoses } };
|
||||
|
||||
// BACKLINE (v3.1, ledger #5): up-stage amp/spare-cab slots — the unified backline that replaces C's old
|
||||
// primitive ampStacks. Pure data (no meshes): Lane D plants E's guitar_amp GLB here (primitive fallback
|
||||
// under ?noassets). Up-stage of the front line, flanking the drum riser, clear of every bandPose AND all
|
||||
// watchPoints (which sit downstage of frontZ), on-deck. slot[0] = stage-right (primary), slot[1] = spare
|
||||
// stage-left. ry=π faces the audience (+Z), same −Z convention as the band; y = deckY. Deterministic.
|
||||
// slot[0] == D's R15-verified guitar_amp pose (stage.w·0.36, deckY, stage.z − stage.d·0.22, 0.87 m bass
|
||||
// clearance), so plumbing D's plant to backline[0] moves nothing on screen.
|
||||
const backline = [sw * 0.36, -sw * 0.36].map(bx => ({
|
||||
x: round(cx + bx), z: round(cz - sd * 0.22), ry: round(Math.PI), y: round(deckY),
|
||||
}));
|
||||
return { placed: out, stage: { x: cx, z: cz, w: sw, d: sd, deckY, riserY, frontZ: round(cz + sd / 2), bandPoses, backline } };
|
||||
}
|
||||
|
||||
// ── WATCH POINTS (venue) — seeded audience floor poses facing the stage ──
|
||||
|
||||
Loading…
Reference in New Issue
Block a user