fix(sim): boot silent (video off, audio 0) — no un-gestured auto-start

The post-load autoStart() flipped Video on and lifted audio to 3/10 with no
user gesture. Browser autoplay policy blocks an audio play() made outside a
gesture (muted video survives, sound does not), so auto-start showed video but
stayed silent. Boot SILENT instead and wait for the operator to turn Video on —
that click IS the gesture, and its handler couples audio to 3/10 and starts the
soundtrack in-gesture, so sound reliably comes up with video.

Updates the pytest e2e + Playwright e2e specs to assert boot-silent + the
video-on-couples-audio wiring instead of the old auto-start wiring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BenStullsBets
2026-06-30 06:31:38 -07:00
parent 020219f9a6
commit e5fe00e948
3 changed files with 43 additions and 31 deletions
+31 -12
View File
@@ -2,12 +2,15 @@
cleanly when Playwright or its browser binary is absent.
NOTE: headless engines relax BOTH autoplay and GPU compositing, so these assert
the WIRING (auto-start on load, dial→play/volume, video-off blanking) — real
Safari/iOS autoplay and real-GPU compositing still need a device by-ear/eye check.
the WIRING (boot-silent, video-on couples audio, dial→play/volume, video-off
blanking) — real Safari/iOS autoplay and real-GPU compositing still need a device
by-ear/eye check.
The experience AUTO-STARTS once the preload finishes: Video turns on and the audio
level dial rises to 3/10 with no user gesture (app.js autoStart()). Audio is a 010
range dial (not a checkbox); set it by writing `value` + firing an `input` event.
The experience BOOTS SILENT — video off, audio dial at 0 — so nothing plays until a
real user gesture. Turning Video ON (a click) couples the audio dial up to 3/10 and
starts the soundtrack IN that gesture, sidestepping the browser autoplay block that
swallowed an un-gestured auto-start. Audio is a 010 range dial (not a checkbox);
set it by writing `value` + firing an `input` event.
Install: pip install -e '.[e2e]' && python -m playwright install chromium
"""
@@ -63,7 +66,7 @@ def page(app_url):
pg = browser.new_page()
pg.goto(app_url)
# wait out the "Loading Universe…" splash (it overlays + blocks clicks); the
# auto-start fires as it dismisses.
# experience boots silent (video off, audio 0) as it dismisses.
pg.wait_for_selector("#loading", state="detached", timeout=60000)
yield pg
browser.close()
@@ -84,10 +87,23 @@ def _set_audio(page, level):
)
def test_app_auto_starts_video_and_audio(page):
# Once the preload finishes the experience auto-starts: Video on + audio at 3/10,
# video showing (black hidden), a scale soundtrack playing — no tap-to-start wall.
assert page.is_checked("#visual") is True
def test_app_boots_silent_video_off(page):
# The experience boots SILENT: Video off, audio dial at 0, screen black, both
# crossfade elements paused — nothing plays until a real user gesture.
assert page.is_checked("#visual") is False
assert page.evaluate("document.getElementById('audio').value") == "0"
assert page.evaluate("document.getElementById('audio-level-val').textContent") == "0"
page.wait_for_selector("#black:not(.hidden)") # screen blanked
assert page.evaluate(
"(() => { const a = document.getElementById('aud'), b = document.getElementById('aud-b');"
" return a.paused && b.paused; })()"
) is True
def test_video_on_couples_audio_to_three_and_plays(page):
# Turning Video on (a click gesture) lifts the audio dial to 3/10 and starts the
# soundtrack IN that gesture: video shows (black hidden), a scale soundtrack plays.
_toggle_visual(page) # off -> on
page.wait_for_function("document.getElementById('audio').value === '3'")
page.wait_for_function("document.getElementById('audio-level-val').textContent === '3'")
page.wait_for_selector("#black.hidden", state="attached") # video showing
@@ -113,8 +129,11 @@ def test_audio_dial_zero_silences(page):
assert page.evaluate("document.getElementById('audio').value") == "0"
def test_video_off_blanks_after_autostart(page):
# Video is auto-on; turning it off blanks the screen and hides the GPU layers.
def test_video_off_blanks(page):
# Turn Video on (boot is off), then off again: that blanks the screen and hides
# the GPU layers.
_toggle_visual(page) # off -> on
page.wait_for_selector("#black.hidden", state="attached")
_toggle_visual(page) # on -> off
page.wait_for_selector("#black:not(.hidden)")
page.wait_for_function(