Contract: src/core/worlds.ts (three pocket worlds above the booth walls, portal/entry/exit anchors, stamp count) + additive world/stamp bus events. Briefs: SIDEB overview + WORLDS / MACHINES / SOCIAL(ambience) / AUDIO lanes, rescoped around the already-shipped SOCIAL_RESET (emotes, reset ritual, avatars) and first-five-minutes (heartbeat, beacons, flythrough) phases. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
62 lines
3.5 KiB
Markdown
62 lines
3.5 KiB
Markdown
# SIDE B — Lane E2: per-world grooves + SIDE B sound
|
||
|
||
Read `docs/briefs/SIDEB.md` + `src/core/worlds.ts` first. You own
|
||
**`src/audio/**`**. React to bus events only. The main booth groove/stems
|
||
engine is yours already — extend, don't fork.
|
||
|
||
## A1. World grooves (the big one)
|
||
|
||
On `world:enter {world}`: duck the booth mix out (300 ms) and start that
|
||
world's loop; on `world:exit`: reverse. Same synth toolkit (synth.ts), same
|
||
shrunk-time BPM feel. Keep each loop 2–4 bars, hypnotic, mixable levels.
|
||
|
||
- **acid**: 118 BPM, four-on-floor kick + off-hat, and THE 303: a 16-step
|
||
sawtooth acid line through a resonant lowpass (Q high) + accent/slide feel.
|
||
The line's filter cutoff is driven by three bands mapped to
|
||
`fader:move {faderId:'acid_0'|'acid_1'|'acid_2'}` (0..1 from Lane M's
|
||
pedestals): 0 = detuned/wrong (cutoff badly off per-band offsets), target ≈
|
||
band's sweet value (Lane M owns the targets; you just map value→cutoff
|
||
smoothly so sweeping is AUDIBLE and finding the sweet spot is satisfying —
|
||
add a subtle "lock shimmer" layer per locked band via
|
||
`machine:interact {action:'acid_lock'}`). On stamp: the full line + a clap
|
||
layer for 4 bars of glory.
|
||
- **dub**: 74 BPM half-time — deep sub bassline, sparse rimshot skank on the
|
||
2/4 through a **feedback echo** (delay ~3/8, feedback 0.55, highcut) and a
|
||
spring-reverb boing patch. `machine:interact {action:'dub_feed'}` = the big
|
||
SPROING (bandpassed noise burst into the echo, feedback momentarily 0.8).
|
||
While carrying the charge (Lane M emits `machine:interact
|
||
{action:'dub_pickup'|'dub_drop'}`): the echo wet rises — you carry the wet.
|
||
- **disco**: 122 BPM — four-on-floor, octave bass, offbeat open hat, a little
|
||
string stab loop. `machine:interact {action:'disco_cue', index}` = per-tile
|
||
cue blip (pitch by index, pentatonic); player steps echo the blip a fifth
|
||
down. Stamp = filtered-disco string swell.
|
||
|
||
## A2. SIDE B SFX + stem tie-ins
|
||
|
||
- Portal: `world:enter` whoosh-drop (pitch dive + vinyl slow-down effect),
|
||
`world:exit` reverse spin-up.
|
||
- `stamp:got`: press-stamp THUNK + one-shot fanfare in that world's key.
|
||
- `stamp:all`: golden riser; then permanently add a **bonus percussion stem**
|
||
(shaker/conga layer) to the booth mix (new stem in the stems set, unmuted
|
||
only when stamp:all has fired — persists via Lane M's synced stamp state;
|
||
derive "all stamped" at boot by listening for `stamp:got` count===total or
|
||
an initial re-emit — coordinate exact boot handshake in your handoff).
|
||
- `machine:interact {action:'bunny_flee'}`: a shy squeak (soft, quiet, rare).
|
||
|
||
**Already shipped — coexist, don't rebuild:** emote audio (airhorn etc.),
|
||
the reset ritual's power-down collapse, and the zero-repair HEARTBEAT
|
||
(commit caac3da) are live. World grooves must duck WHATEVER the booth is
|
||
playing — including the heartbeat pre-first-repair — and hand it back on
|
||
exit; verify entering a pocket in a dead booth and in a won booth both sound
|
||
right, and that a reset while you're inside a pocket doesn't wedge the mix
|
||
(the exit handback must re-evaluate booth state, not restore a stale snapshot).
|
||
|
||
## Verify + handoff
|
||
|
||
Typecheck clean; extend `demo-audio.html` with a SIDE B panel (world
|
||
enter/exit buttons, the three acid faders, dub feed, disco cues, emote pops,
|
||
reset) and verify every path by ear + zero console errors in the demo AND a
|
||
real-game smoke (launch config `turncraft-laneB` port 5184 if free).
|
||
Handoff: `docs/SIDEB_E2_handoff.md` incl. any events you need Lane M to emit
|
||
that aren't listed here (coordinate via handoff, not by editing their code).
|