diff --git a/viz/index.html b/viz/index.html index 424d5f0..13fc5ab 100644 --- a/viz/index.html +++ b/viz/index.html @@ -1808,9 +1808,11 @@ const MOOD_KEYS = ["glitch", "granular.density", "saturation", "tempo.nudge", "wavetable.morph", "lfo.rate", "reverb.size", "delay.feedback", "drone.voices", "pad.brightness", "perc.density", "master.space", "lead.note", "bass.note"]; + let moodAppliedThisLoad = false; // guard: apply a mood once per page load, not per reconnect function applyMood(name) { const m = MOODS[name]; if (!m) return; + try { localStorage.setItem("gs_mood", name); } catch (e) {} // your vibe survives a reload for (const k of MOOD_KEYS) { const t2 = tw(k); t2.mute = 0; t2.gain = 1; t2.offset = 0; } if (m.storm) { for (const k in seqs) seqs[k].on = false; @@ -2244,13 +2246,20 @@ if (Array.isArray(msg.routes)) { preLayoutRoutes(msg.routes); clientMatrix = true; // from here YOUR patch is computed locally - // first visit: greet gently — a song-shaped mood, not the full flood - let seen = false; try { seen = !!localStorage.getItem("gs_seen"); } catch (e) {} - if (!seen) { - try { localStorage.setItem("gs_seen", "1"); } catch (e) {} + // greet with your last mood (default: the gentle "first light"). Applied + // once per page load — never on a mid-session reconnect, so it can't + // clobber what you're playing. A reload no longer drops you into the wall. + if (!moodAppliedThisLoad) { + moodAppliedThisLoad = true; + let firstEver = false, saved = "first light"; + try { firstEver = !localStorage.getItem("gs_seen"); } catch (e) {} + try { saved = localStorage.getItem("gs_mood") || "first light"; } catch (e) {} setTimeout(() => { - applyMood("first light"); - eventTicker.unshift({ text: "🌅 first light — a gentle arrangement to start you off. right-click the sky → mood → the full storm when you're ready", tAdded: now(), src: "sys" }); + applyMood(saved); + if (firstEver) { + try { localStorage.setItem("gs_seen", "1"); } catch (e) {} + eventTicker.unshift({ text: "🌅 first light — a gentle arrangement to start you off. right-click the sky → 🌗 mood for more (or the full storm when you're ready)", tAdded: now(), src: "sys" }); + } }, 900); } } @@ -5694,7 +5703,15 @@ function paint() { btn.style.color = on ? "#7cffb2" : "#9fb4d8"; btn.style.borderColor = on ? "rgba(124,255,178,0.5)" : "rgba(120,150,200,0.25)"; } if (!AC) { btn.style.opacity = "0.3"; btn.title = "Web Audio not supported"; } - else btn.addEventListener("click", () => { on ? stop() : start(); paint(); }); + else btn.addEventListener("click", () => { + const wasOff = !on; + on ? stop() : start(); paint(); + if (wasOff) { // starting into the raw factory wall? point the way out + const anyGroove = Object.keys(seqs).some(k => seqs[k] && seqs[k].on); + if (!anyGroove) + eventTicker.unshift({ text: "♪ this is the full world at once — for a gentle song, right-click the sky → 🌗 mood → first light", tAdded: now(), src: "sys" }); + } + }); return { update(dests) { if (dests) Object.assign(D, dests); }, pluck }; })();