Files
human-experience-filter-art/simulator/e2e
BenStullsBets 4f4f21a767 feat(audio): Music becomes a crossfading playlist of 5 mellow synth tracks
Replace the single ethereal loop with the operator's chosen set — Music for
Manatees, Dewdrop Fantasy, Eastminster, Overheat, Concentration (Kevin MacLeod,
CC BY 4.0, drumless). The Music source now plays one track and every 5 min
crossfades to a random OTHER track (pure HEFScrub.pickNextIndex, never an
immediate repeat), altitude-independent, reusing the two audio elements; both
primed in-gesture for Safari. Intervals injectable via window.__hefMusicRotateMs
/ __hefMusicXfadeMs.

Media loudness-normalized + transcoded under the 25MB LFS limit (build_audio_media
MUSIC), committed via LFS; ethereal loop retired. CC-BY attribution added to
credits.html. Docs updated (music-candidate-pool = final set; audio-candidate-pool
ethereal section superseded).

+2 node unit (pickNextIndex), +2 e2e (music-playlist), audio-source spec updated.
40 unit + 49 e2e green; live probe confirms playback + rotation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 16:22:28 -07:00
..

Simulator E2E (Playwright)

Browser end-to-end tests for the Human Experience Filter simulator. The §9 pipeline requires an E2E browser tier for any UI surface; this is that tier.

What it covers

tests/altitude-lock.spec.ts drives the real simulator and asserts the altitude-morph behavior:

  • Zooming to a new altitude plays the morph that matches the clip it lands on (forward zoom-in, and .rev zoom-out).
  • After landing, the clip is locked — it does not change while parked (no secondary swap, no re-roll).

The played morph paths are read from window.__hefMorphs (a diagnostic array populated by advance() in static/app.js), which is reliable even when a morph is served from the in-memory blob cache. The locked clip is read from the Dev-Mode #scale-name readout.

Running

Prerequisites: the project Python venv on PATH (the Playwright webServer boots uvicorn simulator.app:app from the repo root), Node, and the Chromium browser.

# from this directory (simulator/e2e)
npm install
npx playwright install chromium
npm test

playwright.config.ts starts uvicorn on port 8099 automatically (reuseExistingServer locally) and points the tests at it.

Static-build E2E (Cloudflare publish)

tests/static-build.spec.ts verifies the built static site (Cloudflare publish — see deploy/cloudflare/README.md): it boots with NO /api/* server (baked JSON), and the WebGL dream shader runs on cross-origin media without tainting the GL texture (the CORS path R2 will use in production).

It uses playwright.static.config.ts (no uvicorn webServer) and a dual static server, serve-static.mjs, that serves the built dist/ (app, :8077) and dist-media/ (media with CORS + Range, :8078):

# from the repo root: build with the media base pointed at the local CORS server
.venv/bin/python -m tools.build_static --media-base http://localhost:8078/

# from this directory (simulator/e2e): start the dual server, then run the spec
DIST_DIR="$PWD/../../dist" MEDIA_DIR_E2E="$PWD/../../dist-media" node serve-static.mjs &
npx playwright test --config playwright.static.config.ts