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:
+31
-12
@@ -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 0–10
|
||||
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 0–10 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(
|
||||
|
||||
Reference in New Issue
Block a user