compw00tergame designer
2026-07-18 ยท **Status:** building (autonomous goal) 2026-07-18-bosses-audio-martin-design.md

Boss editors, audio pipeline, The Martin pull โ€” design

Date: 2026-07-18 ยท Status: building (autonomous goal)

Five interlocking features, mostly around audio.

1. Boss character editors (like heroes)

Bosses are the fixed incidents the_wife / the_martin (config W00T_INCIDENTS, boss flag). Give each an editor page mirroring the hero editor: the AI appearance chat (pixel sprite) + a music track + the existing message/sound content.

  • Store on incident_types (per-incident content, keyed by name): new columns appearance TEXT (JSON, same schema as heroes) + music TEXT (audio_tracks id).
  • VocabRepository::saveIncidents() must preserve appearance/music when it rebuilds the table (else vocab.php save wipes them).
  • Shared AI endpoint: extract classes/AppearanceAgent.php (the raw cURL /v1/messages call + schema); hero_appearance.php handles kind=hero|boss, persisting to the right store. herochat.js generalised to read data-kind/data-subject/data-name.
  • New pages: bosses.php (list) + boss_edit.php + boss_save.php. Nav gains Bosses.
  • Render: game.js drawBoss(sx,sy,type,appearance) draws the boss via W00tSprite (bigger than a player) when an appearance exists, else the current coloured marker. launch.js attaches BOOT.bossLook[key] to boss issues before setSpills.

2. The Martin: proximity pull

game.js pull mode 'pull' currently adds a constant drag. Make it scale with closeness: strength = FAR + (NEAR-FAR)*(1 - min(dist,RANGE)/RANGE) โ€” gentle far away, very strong right next to him ("the closer, the more drawn"). Constants MARTIN_NEAR/FAR/RANGE.

3. Lobby music actually plays on the chooser

Bug: startMusic() is only called from choose()/resetToChooser(), never on load โ€” so the lobby song never plays on the chooser, and autoplay policy blocks pre-gesture audio anyway. Fix: call it on load AND unlock on the first pointer/key gesture (one-time listener), so the chosen lobby track plays as soon as the player touches the page.

4. Media editor: per-clip volume + trim

audio_tracks gains volume REAL DEFAULT 1, clip_start REAL DEFAULT 0, clip_end REAL DEFAULT 0 (0 end = natural end). media.php gets per-row volume slider + start/end inputs + a "preview clip" that auditions the trimmed portion at the set volume. AudioRepository::clip() returns {u,v,s,e}; all sound payloads (BOOT.sounds, BOOT.audio, join.php power/trait sounds) become clip objects. Client: playSfx(clip) seeks to s, stops at e, scales volume; action-loops loop within [s,e]; music applies volume (full-track loop). String inputs still tolerated.

5. Boss music takes over

Each boss's music track. When a boss issue is active, launch.js switches gameAudio to that boss's music (looping) and pauses the playlist; when the boss is cleared, the playlist resumes. BOOT.bossMusic[key]; updateBossMusic(issues) per state poll.

Files

config? no. classes/{Database,AudioRepository,VocabRepository,AppearanceAgent}.php, media.php, hero_appearance.php, assets/herochat.js, bosses.php, boss_edit.php, boss_save.php, includes/gamenav.php, launch/index.php, launch/join.php, assets/game.js, launch/launch.js.

Testing

CLI data-layer checks; media.php + boss editor via curl/Playwright; two-client launch/ run for Martin pull + boss music takeover + lobby music + trimmed SFX. Error log clean.