fix(audio): off/on Audio + Video toggles; fix Safari autoplay + GPU video-off

Operator-driven live-UI revision:
- Video + Audio are now Dev-Mode-style on/off toggles (Audio on = soundtrack);
  white-noise deferred (removed from the live control; pure machinery kept).
- FIX video-off not blanking: the <video>/<canvas> are GPU-composited and could
  paint above the auto-z #black on a real GPU — give #black z-index + its own
  layer AND hide the video layers (opacity 0) on video-off.
- FIX no soundtrack on Safari/iOS: Safari unlocks <audio> only when play() runs
  INSIDE the user gesture; the start gesture now primes both A/B elements
  synchronously, so the async crossfades are allowed to play.
- Toggles wired on 'change' (matches the Dev Mode switch).
- player/audio.py AUDIO_SOURCES -> {off, soundtrack}; tests + E2E updated.
- Verified in headless Chromium AND WebKit: audio plays, video-off blanks both
  layers, zero JS errors. 288 tests + 3 Playwright E2E pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BenStullsBets
2026-06-26 12:55:50 -07:00
parent aa76cd1c9f
commit 2722949805
16 changed files with 146 additions and 106 deletions
+2 -2
View File
@@ -36,12 +36,12 @@ class TransitionKind:
class Playback:
"""What should currently be playing. Visual and audio are orthogonal (audio
spec §2): `video` is whether the projector shows footage, `audio_source` is
the independent audio dial (off / soundtrack / white_noise)."""
the independent audio dial (off / soundtrack)."""
clip_id: Optional[str] # None = black walls
plan: Optional[RenderPlan] # None when black
video: bool # whether footage is shown (Visual on/off)
audio_source: str # the Audio dial source (off/soundtrack/white_noise)
audio_source: str # the Audio dial source (off/soundtrack)
volume: int
brightness: int