fix(audio): client soundtrack fallback when /api/ring lacks audio (stale server)

Root cause of 'no sound', found via the live readout: the operator's /api/ring
returned the ring WITHOUT the per-scale audio field (a server process predating the
audio code) → soundtrackUrl() was null → the element never got a src (readyState 0,
no error). The native test player proved the file itself plays. Fix: client falls
back to a scale-id→soundtrack map (mirrors build_pool_manifest.SCALE_AUDIO) so audio
works without a server restart. Verified: stale-ring sim now plays; audio-first-then-
video leaves both on. +2 E2E regression tests (7 total). Chromium + WebKit clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BenStullsBets
2026-06-26 13:42:12 -07:00
parent 56e352fe65
commit 97d2ddd573
2 changed files with 37 additions and 2 deletions
+17 -2
View File
@@ -960,10 +960,25 @@ function fadeVolume(el, to, ms, done) {
}, 30);
}
// The current altitude's soundtrack url (the ring carries each scale's `audio`).
// Fallback per-scale soundtrack paths, used when the ring from /api/ring lacks the
// `audio` field (e.g. a server process started before the audio field existed).
// Mirrors simulator/build_pool_manifest.py SCALE_AUDIO — the 5 scales + files are
// fixed, committed facts, so this keeps audio working without a server restart.
const SCALE_AUDIO_FALLBACK = {
cosmos: "cosmos/pillars.loop.mp3",
orbit: "orbit/spaceamb.loop.mp3",
coast: "coast/waves.loop.mp3",
reef: "reef/soundscape.loop.mp3",
abyss: "abyss/whale.loop.mp3",
};
// The current altitude's soundtrack url: the ring's `audio` field, else the
// scale-id fallback above.
function soundtrackUrl() {
const s = ring && ring.scales[ringIndex];
return s && s.audio ? "/media/audio/" + s.audio : null;
if (!s) return null;
const a = s.audio || SCALE_AUDIO_FALLBACK[s.id];
return a ? "/media/audio/" + a : null;
}
// Load `url` into the single element and fade it in. Call this SYNCHRONOUSLY from