Oliver on the first shell build: *"I don't hear any of the games sounds.. daniel the umpire is
synthesized which is horrible and no music is playing on start"* — two independent causes.
- **Opaque fetch.** Capacitor serves the bundle through a custom WKURLSchemeHandler, and `fetch`
reports those responses as `status: 0, ok: false` with the whole body present and decoding
perfectly. All three loads in `audio.js` guarded with `if (!r.ok) throw`, so inside the app every
recorded sound failed at the door: the umpire fell through to the synthesized `say()`, no bed
started, no sample played. The synthesized sfx kept working, which made it read as a mixing bug
rather than a loader one. Fixed once, in the shared `bytes()` helper every audio fetch now routes
through — a status of 0 is the ABSENCE of an HTTP status, so trust it only when there is one and
a real 404 still falls back. Any future `!r.ok` on a bundle-relative fetch is this same bug.
- **The ring switch.** WKWebView's WebAudio runs in the SoloAmbient session, which the hardware
silent switch mutes outright — a silent game on a phone that lives on silent, with nothing on
screen to explain it. AppDelegate now sets AVAudioSession `.playback`, the games category.
Confirmed in the shell: the bed reaches PLAYING, the context is `running` with no gesture at all
(autoplay really is allowed in WKWebView, as LATER predicted), and `say()` never fires. On the web,
a genuinely missing file still falls back — checked both.
And the swipe flips: **right goes back**, the way iOS's own pop gesture goes (*"that's the iOS
way"*). Left now does nothing. Noted in PROJECT.md that on a platform gesture the platform's
convention beats the literal wording of the brief, and that is worth saying up front.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>