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 columnsappearance 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.phphandleskind=hero|boss, persisting to the right store.herochat.jsgeneralised to readdata-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 viaW00tSprite(bigger than a player) when an appearance exists, else the current coloured marker.launch.jsattachesBOOT.bossLook[key]to boss issues beforesetSpills.
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.