From 8fc613ed207cd947d165f2a28ebfd0dad688c4fc Mon Sep 17 00:00:00 2001 From: teahubxyz Date: Wed, 21 Oct 2026 05:17:12 +0000 Subject: [PATCH] =?UTF-8?q?the=20room=20tone=20tries=20to=20start=20on=20l?= =?UTF-8?q?oad=20(plays=20where=20the=20browser=20allows,=20otherwise=20on?= =?UTF-8?q?=20the=20first=20tap)=20=E2=80=94=20the=20seed=20page=20is=20ne?= =?UTF-8?q?ver=20silent=20for=20want=20of=20a=20gesture?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01K6897PWcUEwHiqZMcVnNF6 --- index.html | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index dc453e9..b07dacb 100644 --- a/index.html +++ b/index.html @@ -647,13 +647,14 @@ function makeCrackle() { /* the bed: crackle whenever no music is playing. Decided from state, called whenever state changes. */ function bed() { clearTimeout(crackle.timer); - crackle.timer = setTimeout(() => { const want = state.primed && !state.playing && !state.holding && state.audio.paused; if (want) crackleOn(); else crackleOff(); }, 300); + crackle.timer = setTimeout(() => { const want = !state.playing && !state.holding && state.audio.paused; if (want) crackleOn(); else crackleOff(); }, 300); } function crackleOn() { if (crackle.on || state.holding) return; crackle.el ||= makeCrackle(); crackle.on = true; const base = crackle.base ?? crackle.el.volume, t0 = performance.now(); - crackle.el.volume = 0; crackle.el.currentTime = 0; crackle.el.play().catch(() => {}); + crackle.el.volume = 0; crackle.el.currentTime = 0; + crackle.el.play().catch(() => { crackle.on = false; clearInterval(crackle.ramp); }); // refused without a gesture: the first tap calls again clearInterval(crackle.ramp); crackle.ramp = setInterval(() => { const k = Math.min(1, (performance.now() - t0) / 600); if (!crackle.on) { clearInterval(crackle.ramp); return; } crackle.el.volume = base * k; if (k >= 1) clearInterval(crackle.ramp); }, 40); } @@ -675,11 +676,13 @@ function prime() { state.audio.play().then(() => { state.playing = true; state.primed = true; crackleOff(); setPlayIcon(); vizStart(); }).catch(() => { state.needTap = true; $("#cover").classList.add("tap"); }); return; } + if (!crackle.on) bed(); if (state.primed || state.current || (state.audio.src && !state.audio.paused)) return; try { state.audio.src = SILENCE; const p = state.audio.play(); if (p && p.then) p.then(() => { state.primed = true; bed(); }).catch(() => {}); } catch {} try { crackle.el ||= makeCrackle(); if (!crackle.on) crackleOn(); } catch {} } for (const ev of ["pointerdown", "touchend", "keydown"]) document.addEventListener(ev, prime, { capture: true, passive: true }); +setTimeout(bed, 400); // the room tone, from the start where the browser lets it /* iOS routes sound through Web Audio the moment the element is wired to an analyser, and suspends Web Audio when the screen locks (and obeys the mute switch). So on iOS the cover pulses to the beat from the sheet instead, and the music stays a plain