🚪 the doors: six front-door openings — the rig, the deal, the dawn

The front door becomes a skin: the first-visit card grows from three doors
to six, the walked door is REMEMBERED (gs_door) and opens the same way on
every arrival, and it's re-choosable any time (right-click sky → 🚪 the
doors, or say "doors"). Each door is one DOORS registry entry + one act —
delete the entry, the door is gone.

The classics (unchanged acts): 🌱 start from zero · 🌅 first light ·
⛈ the full storm. The new gig doors:

- 🎪 the rig — walk on stage: first light applied, beat panel + GODSPEED
  already open, and the sleeper fold tightened so only the ~8 liveliest
  uncabled hands stay in the field (8th-liveliest flowDisp sets the bar).
- 🃏 the deal — the world deals five cables from its liveliest feeds
  (family-diverse) onto a shuffled spread of ten dests, ONE card always
  pulsing (÷16 or ÷8); "🃏 deal again" chip; every arrival deals fresh;
  each hand is an ungodly mark so ⌘Z takes it back. Voice: "deal" redeal
  while the deal is your door.
- 🌒 the dawn — first light applied, then the players take the stage one
  at a time (~1.25s apart, cabled first, then by liveliness, 18 arrivals),
  each narrated in the ticker; cables only draw once their player is on
  stage (drawCables skips hidden sources); when the entrance ends the
  sleeper fold reconciles the rest.

Verified live (static serve + temp hook, removed & grep-verified 0):
six cards render; deal → exactly 5 routes, 1 pulsing, chip visible,
gs_door saved; redeal changes the hand, marks undo, ⌘Z restores the
previous hand exactly; rig → beat+GODSPEED open, field folded tight,
deal furniture closed; dawn → 24/24 hidden at curtain, players arrive
one-by-one with ticker narration and their cables, finale reconciles to
0 hidden; zero console errors; T O B G S + ⌘Z regression green;
grimoire + manual regenerated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
monsterrobotparty 2026-07-25 12:22:04 +10:00
parent 12a296f284
commit 3e0bb9ee68
2 changed files with 150 additions and 27 deletions

View File

@ -669,6 +669,11 @@
background: rgba(20,28,44,0.82); color: rgba(160,180,215,0.75); border: 1px solid rgba(120,150,200,0.22);
border-radius: 9px; padding: 4px 10px; font-size: 11px; -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
#sleepchip:hover { color: #cfe0ff; border-color: rgba(140,170,230,0.5); }
/* 🃏 the deal — the redeal chip sits above the sleeper chip */
#dealchip { position: fixed; left: 14px; bottom: 86px; z-index: 12; display: none; cursor: pointer;
background: rgba(28,24,46,0.85); color: rgba(200,185,235,0.85); border: 1px solid rgba(160,140,220,0.3);
border-radius: 9px; padding: 4px 10px; font-size: 11px; -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
#dealchip:hover { color: #e8ddff; border-color: rgba(180,160,240,0.6); }
</style>
<canvas id="stage"></canvas>
<div id="gear" title="controls"></div>
@ -1240,6 +1245,7 @@
<li><b>🕊 PSALM — sing, and the instrument answers.</b> Right-click the sky → <b>🕊 PSALM</b>, allow the microphone, and <b>sing</b>. The pitch is heard, <b>folded to the scale you're in</b> (so you're never out of key), and played as notes — a <b>🕊</b> chip shows the note leaving your throat. And the duet with <b>⚡ GODSPEED</b>: with the arp running, each note you sing <b>latches into the held chord</b>, one at a time — hum four notes and the machine arpeggiates the chord you sang. <b>It listens locally</b>: the analysis happens in the page, in its own silence, and <i>nothing ever leaves the machine</i> — no recording, no upload, just your voice becoming the instrument's.</li>
<li><b>✦ CANON — the shelf of worked examples.</b> Open <b>⚙ → DIMENSIONS</b> and at the top of the list, above your own saved worlds, sit four <b>✦ factory dimensions</b> that ship with the instrument — <i>the heartbeat</i> (a boom-bap kit with the swing and the kick's duck), <i>the wheel within the wheel</i> (WHEELS, made audible), <i>the squeeze</i> (the market pumping GODSQUASH), and <i>quiet arrival</i> (the earth echo, slow and sparse). Load one to hear a feature in its element, then save your own version under a new name — the ✦ ones are <b>read-only</b>, the same for everyone, a place to start rather than a thing to overwrite.</li>
<li><b>🪐 spheres — the music of the spheres.</b> Press <kbd>S</kbd> (or right-click the sky → <b>🪐 spheres</b>) and turn it <b>on</b>: the eight planets join the field as <b>modulation sources</b>, the slowest LFOs there are. Each planet offers three signals — <b>phase</b> (its heliocentric longitude, a sawtooth one full turn per orbit), <b>dist</b> (its eccentric breathing, in and out between perihelion and aphelion — Mercury and Mars swing hard, Venus barely), and <b>beat</b> (its <i>synodic</i> dance against Earth — Venus and Earth clasp every 583.9 days, the pentagram cycle). Route any of them like any source, or just say <i>"mars drive filter."</i> One knob rules time: the <b>rate</b>, from <b>1 to 3650 days of sky per bar</b> — at the default thirty, Venus' year is about seven and a half bars and Jupiter's a hundred and forty-four, real orbits compressed into slow musical arcs. And the <b>☸ orbital ratios</b> button sets the drum lanes' wheels to the true resonances — <b>4 : 8 : 16</b> (Io, Europa and Ganymede, locked at 1 : 2 : 4) and <b>8 : 13</b> (Venus to Earth, the pentagram in wheel form), so the polymeter you hear is one the solar system actually keeps. It is all <b>computed here, at the instrument's own clock</b> — the same JPL ephemeris SOLARGOD uses, vendored in, no network and no server, so the sky is deterministic: the same bar always shows the same heaven, and a saved patch reloads the identical sky.</li>
<li><b>🚪 The doors — how the world opens.</b> The front door is a skin like any other. On your first visit a card offers <b>six doors</b>, and the one you walk is <b>remembered</b> — every arrival after that opens the same way (right-click the sky → <b>🚪 the doors</b> to choose again, or say <i>"doors"</i>). The classics: <b>🌱 start from zero</b> (an empty field, build it yourself), <b>🌅 first light</b> (a gentle arrangement), <b>⛈ the full storm</b> (every hand at once). And the gig doors: <b>🎪 the rig</b> — you walk on stage with the <b>beat panel and GODSPEED already open</b> and the field folded to the eight liveliest hands, everything within reach; <b>🃏 the deal</b> — the world <b>deals you five cables</b> from its liveliest feeds onto five voices, <i>one card always pulsing</i>, with a <b>🃏 deal again</b> chip (and <kbd>⌘Z</kbd> takes any hand back) — redeal until it sings, and every arrival deals fresh; <b>🌒 the dawn</b> — the players <b>take the stage one at a time</b>, liveliest first, the field assembling itself over half a minute like an orchestra walking on. Same instrument behind every door — only the meeting changes.</li>
<li><b>⚡ Pulse — make the slow world playable.</b> Some of the planet's truest signals barely move — the national debt, the Moon's declination, a glacier of a currency. Right-click a node, open its cables, and tap the <b></b> chip on any cable to cycle <b>÷16 · ÷8 · ÷4 · bar</b>: the cable now <i>throbs on the godtime clock</i>, and the slow value becomes the <b>depth</b> of that throb. The debt stops being a frozen offset and becomes a sixteenth-note pressure whose weight is the debt itself — slow data as character, the clock as motion. Off by default; the world's own tempo is still the truth unless you ask for the heartbeat.</li>
<li><b>💤 The sleeper fold — and speed at a glance.</b> The field folds away <b>quiet feeds</b> — sources with no cables, no signal and nothing to say for a minute — behind a small <b>💤 chip</b> (bottom-left) that shows the count and brings them back with one click. The moment a folded feed <i>speaks</i>, it wakes itself and rejoins the field: the world breathes in and out of view. And every cable now moves at <b>the data's own rate</b> — streaming feeds race, glacial ones crawl — with the words to match: hover a column and each source row reads its speed (<i>streaming · ≈ every 3 bars · asleep, still 12m</i>), and a node's right-click readout says the same. What speed is that thing going at? Now it just tells you.</li>
<li><b>📽 The stage — send the visual to any screen.</b> Right-click the sky → <b>the stage</b> and a clean black mirror window opens, fed live from the canvas. Drag it to a projector, an AirPlay display, a second monitor — macOS treats it like any window — and <b>double-click for fullscreen</b>. The stage has a <b>camera</b>: the whole view by default (whatever you're in — a skin, the wheel, mind mode's POV), or right-click any node → <b>project this node</b> and the camera glides after that one sphere through its orbits, or <b>project its station</b> to frame a whole wheel and its satellites. Change cameras live from the menus while the projector runs; the audience sees the camera breathe from subject to subject.</li>
@ -1299,7 +1305,7 @@
<ol class="steps">
<li>Press <kbd></kbd> (top-right, or <kbd>F2</kbd>) to wake OMNI — the whole audio graph builds on the first press.</li>
<li>Your first visit opens gently in <b>🌅 first light</b>. Right-click the sky → <b>🌗 mood — how much world</b> to move between <i>first light</i>, <i>ambient drift</i> (all atmosphere, no drums) and <i>the full storm</i> (every hand at once).</li>
<li>Your first visit offers <b>🚪 six doors</b> — from <i>start from zero</i> to <i>the rig</i>, <i>the deal</i> and <i>the dawn</i> — and remembers the one you walk. Right-click the sky → <b>🌗 mood — how much world</b> to move between <i>first light</i>, <i>ambient drift</i> (all atmosphere, no drums) and <i>the full storm</i> (every hand at once), or <b>🚪 the doors</b> to change how the world opens.</li>
<li>Play notes three ways: enter <b>chakra view</b> (<kbd>C</kbd>) and click a wheel's core for a 12-key console (play it with the <kbd>Q…P</kbd> row or a MIDI keyboard); open <b>🎛 tracks</b> (<kbd>T</kbd>) to sequence a song; or just wire the world's data to play it hands-free.</li>
<li>Shape the character: swap the pluck voice (<b>🎸 string voice</b> / <b>🎛 GODSONIQ</b>), or drag any feed onto <kbd>crush</kbd>, <kbd>wavetable.morph</kbd> or <kbd>granular.density</kbd>.</li>
</ol>
@ -1358,7 +1364,7 @@
<h2>Building from zero — the empty instrument</h2>
<p class="lead">The full instrument is a sensory flood by design. <b>Zero</b> is the other door: an empty field with nothing wired, where you build the whole thing by hand, one cable at a time. Same matrix underneath — a calmer face on it. On your first visit the three-door card offers it (<b>🌱 start from zero</b>); after that, press <kbd>F11</kbd>, or ⚙ → <b>DIMENSIONS → ✦ dimension zero</b>, or the 🌗 mood menu → <b>0 zero</b>.</p>
<p class="lead">The full instrument is a sensory flood by design. <b>Zero</b> is the other door: an empty field with nothing wired, where you build the whole thing by hand, one cable at a time. Same matrix underneath — a calmer face on it. On your first visit the doors card offers it (<b>🌱 start from zero</b>); after that, press <kbd>F11</kbd>, or ⚙ → <b>DIMENSIONS → ✦ dimension zero</b>, the 🌗 mood menu → <b>0 zero</b>, or <b>🚪 the doors</b>.</p>
<ol class="steps">
<li>Down each side sit <b>seven vibe-rings</b> — the world grouped into the seven elements (left) and seven domains (right). Each ring <b>breathes</b> with its group's live average. Click one to open its drawer.</li>
@ -3978,9 +3984,107 @@
document.body.appendChild(wrap);
}
// The three doors, shown once on a first-ever visit (replaces the silent drop
// into first light). Backdrop/esc = first light, the gentle default.
function showFirstVisitCard() {
// ---- 🚪 THE DOORS — how the world opens -----------------------------------
// The front door is a skin like any other: six openings, each a different way
// to meet the same instrument. Your door is remembered (gs_door) and walked
// again on every arrival; right-click the sky → 🚪 the doors to choose again.
// Each door is ONE registry entry + one act — delete the entry, the door is gone.
let doorMode = null; // "rig" | "deal" | "dawn" while that door shapes the field (session-only)
let dawn = null; // the entrance in progress: { queue, next, t }
function doorRig() { // 🎪 walk on stage: performance surfaces up, the field folded tight
doorMode = "rig";
const _m = ungodly.muted; ungodly.muted = true; applyMood("first light"); ungodly.muted = _m;
sleepFold = true;
openBeat(); openGodspeed();
eventTicker.unshift({ text: "🎪 the rig — beat + GODSPEED up, the field folded to the liveliest hands. ♪ to sound, S for the spheres.", tAdded: now(), src: "sys" });
}
// 🃏 the deal's deck: dests worth being dealt, [key, amount, curve]
const DEAL_DESTS = [
["filter.cutoff", 0.6, "scurve"], ["pad.brightness", 0.5, "lin"], ["reverb.size", 0.45, "lin"],
["delay.feedback", 0.4, "exp"], ["lfo.rate", 0.4, "lin"], ["drone.voices", 0.5, "lin"],
["wavetable.morph", 0.45, "lin"], ["glitch", 0.25, "exp3"], ["master.space", 0.5, "scurve"], ["saturation", 0.35, "exp"]];
let dealChipEl = null;
function dealChip(show) {
if (!dealChipEl) {
dealChipEl = document.createElement("div"); dealChipEl.id = "dealchip"; dealChipEl.textContent = "🃏 deal again";
dealChipEl.title = "the world deals a fresh hand — five cables, one pulsing (⌘Z takes it back)";
dealChipEl.onclick = () => doorDeal(false);
document.body.appendChild(dealChipEl);
}
dealChipEl.style.display = show ? "block" : "none";
}
function doorDeal(silent) { // 🃏 the world deals a hand: five lively sources onto five voices
const pool = [...sources.values()].filter(n => !/^drum\./.test(n.key));
pool.sort((a, b) => ((b.flowDisp || 0) * 2 + (b.norm || 0)) - ((a.flowDisp || 0) * 2 + (a.norm || 0)));
if (!pool.length) { eventTicker.unshift({ text: "🃏 the world hasn't spoken yet — try the deal again in a moment", tAdded: now(), src: "sys" }); return; }
doorMode = "deal";
if (!silent) ungodlyMark("the deal");
loadPatch({ routes: [], tweaks: {}, seqs: {} });
seedBeat(); // a kit waits in the beat panel, off until you press ▶
const picked = [], seenFam = {};
for (const n of pool) { if (picked.length >= 5) break; if (seenFam[n.family]) continue; seenFam[n.family] = 1; picked.push(n); }
for (const n of pool) { if (picked.length >= 5) break; if (picked.indexOf(n) < 0) picked.push(n); }
const deck = DEAL_DESTS.slice();
for (let i = deck.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); const sw = deck[i]; deck[i] = deck[j]; deck[j] = sw; }
const pulseCard = Math.floor(Math.random() * picked.length); // one card is always dealt pulsing
picked.forEach((n, i) => {
const d = deck[i];
registerRoute({ source: n.key, dest: d[0], amount: d[1], curve: d[2], pulse: i === pulseCard ? (Math.random() < 0.5 ? 16 : 8) : 0 });
});
layoutDirty = true;
dealChip(true);
eventTicker.unshift({ text: "🃏 the deal: " + picked.map(n => n.label || n.key).join(" · ") + " — one card pulses. ♪ to hear it.", tAdded: now(), src: "sys" });
}
function doorDawn() { // 🌒 the players take the stage one at a time, liveliest first
doorMode = "dawn";
const _m = ungodly.muted; ungodly.muted = true; applyMood("first light"); ungodly.muted = _m;
const cabled = new Set();
for (const r of routesArr) cabled.add(r.source);
const list = [...sources.values()];
list.sort((a, b) => (cabled.has(b.key) - cabled.has(a.key)) || ((b.flowDisp || 0) - (a.flowDisp || 0)));
for (const n of list) n.hidden = true;
dawn = { queue: list.slice(0, 18), next: 0, t: 0 };
layoutDirty = true;
eventTicker.unshift({ text: "🌒 the dawn — the world takes the stage, one hand at a time.", tAdded: now(), src: "sys" });
}
function dawnPass(t) { // one arrival per beat-and-a-bit; then the fold takes over
if (!dawn) return;
if (!dawn.t) dawn.t = t + 1.0;
if (t < dawn.t) return;
const n = dawn.queue[dawn.next++];
if (n) {
n.hidden = false; layoutDirty = true;
eventTicker.unshift({ text: "🌒 " + (n.label || n.key) + " takes the stage", tAdded: now(), src: "sys" });
}
dawn.t = t + 1.25;
if (dawn.next >= dawn.queue.length) {
dawn = null; // the entrance is over — sleepFoldPass reconciles the rest
eventTicker.unshift({ text: "🌅 the world is on stage.", tAdded: now(), src: "sys" });
}
}
const DOORS = [
{ key: "zero", emoji: "🌱", title: "start from zero", desc: "an empty field. build the instrument yourself, one cable at a time.", act: () => enterZero() },
{ key: "light", emoji: "🌅", title: "first light", desc: "a gentle arrangement — a bass line, soft hats, a small melody. ease in.", act: () => applyMood("first light") },
{ key: "storm", emoji: "⛈", title: "the full storm", desc: "every one of the world's hands on it at once. the factory instrument.", act: () => applyMood("the full storm") },
{ key: "rig", emoji: "🎪", title: "the rig", desc: "walk on stage: beat + GODSPEED open, the field folded to the liveliest hands.", act: () => doorRig() },
{ key: "deal", emoji: "🃏", title: "the deal", desc: "the world deals you five cables — one always pulsing. redeal until it sings.", act: () => doorDeal(false) },
{ key: "dawn", emoji: "🌒", title: "the dawn", desc: "the players take the stage one at a time, liveliest first. watch it assemble.", act: () => doorDawn() },
];
function walkDoor(key, save) {
const d = DOORS.filter(x => x.key === key)[0];
if (!d) return;
doorMode = null; dawn = null; dealChip(false); // a new door closes the old one's furniture
if (save) try { localStorage.setItem("gs_door", key); } catch (e) {}
d.act();
}
// The doors card — first-ever visit, and any time from the sky menu.
// First visit: esc/backdrop = first light (the gentle default). Re-choosing: esc just closes.
function showDoorsCard(again) {
if (document.getElementById("firstcard")) return;
const wrap = document.createElement("div");
wrap.id = "firstcard";
@ -3988,10 +4092,10 @@
alignItems: "center", justifyContent: "center", background: "rgba(6,10,20,0.72)",
backdropFilter: "blur(8px)", WebkitBackdropFilter: "blur(8px)" });
const card = document.createElement("div");
Object.assign(card.style, { maxWidth: "640px", width: "88%", textAlign: "center",
Object.assign(card.style, { maxWidth: "760px", width: "92%", textAlign: "center",
color: "#d6e2f4", fontFamily: "inherit" });
const h = document.createElement("div");
h.textContent = "one world, three doors";
h.textContent = "one world, " + ["", "one", "two", "three", "four", "five", "six", "seven", "eight"][DOORS.length] + " doors";
Object.assign(h.style, { fontWeight: "800", fontSize: "clamp(22px,4vw,32px)", letterSpacing: "2px", marginBottom: "6px" });
const sub = document.createElement("div");
sub.textContent = "the planet is already playing. choose how you meet it.";
@ -3999,32 +4103,28 @@
card.appendChild(h); card.appendChild(sub);
const row = document.createElement("div");
Object.assign(row.style, { display: "flex", gap: "14px", flexWrap: "wrap", justifyContent: "center" });
const doors = [
["🌱", "start from zero", "an empty field. build the instrument yourself, one cable at a time.", () => enterZero()],
["🌅", "first light", "a gentle arrangement — a bass line, soft hats, a small melody. ease in.", () => applyMood("first light")],
["⛈", "the full storm", "every one of the world's hands on it at once. the factory instrument.", () => applyMood("the full storm")],
];
for (const [emoji, title, desc, act] of doors) {
for (const d of DOORS) {
const b = document.createElement("div");
Object.assign(b.style, { flex: "1 1 170px", minWidth: "160px", maxWidth: "200px", cursor: "pointer",
padding: "20px 16px", borderRadius: "16px", background: "rgba(20,28,44,0.7)",
border: "1px solid rgba(120,150,200,0.28)", transition: "transform .12s, border-color .12s" });
b.onmouseenter = () => { b.style.transform = "translateY(-3px)"; b.style.borderColor = "rgba(150,200,255,0.7)"; };
b.onmouseleave = () => { b.style.transform = ""; b.style.borderColor = "rgba(120,150,200,0.28)"; };
b.innerHTML = '<div style="font-size:34px;margin-bottom:8px">' + emoji + '</div>'
+ '<div style="font-weight:700;color:#eaf1ff;margin-bottom:6px">' + title + '</div>'
+ '<div style="font-size:12px;color:rgba(180,195,225,0.75);line-height:1.5">' + desc + '</div>';
b.onclick = () => { wrap.remove(); document.removeEventListener("keydown", onEsc, true); act(); };
b.innerHTML = '<div style="font-size:34px;margin-bottom:8px">' + d.emoji + '</div>'
+ '<div style="font-weight:700;color:#eaf1ff;margin-bottom:6px">' + d.title + '</div>'
+ '<div style="font-size:12px;color:rgba(180,195,225,0.75);line-height:1.5">' + d.desc + '</div>';
b.onclick = () => { wrap.remove(); document.removeEventListener("keydown", onEsc, true); walkDoor(d.key, true); };
row.appendChild(b);
}
card.appendChild(row);
const foot = document.createElement("div");
foot.textContent = "you can switch any time — right-click the sky → 🌗 mood";
foot.textContent = "your door is remembered — right-click the sky → 🚪 the doors to choose again";
Object.assign(foot.style, { marginTop: "22px", fontSize: "11px", color: "rgba(150,170,205,0.55)" });
card.appendChild(foot);
wrap.appendChild(card);
const onEsc = (e) => { if (e.key === "Escape") { wrap.remove(); document.removeEventListener("keydown", onEsc, true); applyMood("first light"); } };
wrap.onclick = (e) => { if (e.target === wrap) { wrap.remove(); document.removeEventListener("keydown", onEsc, true); applyMood("first light"); } };
const close = () => { wrap.remove(); document.removeEventListener("keydown", onEsc, true); if (!again) applyMood("first light"); };
const onEsc = (e) => { if (e.key === "Escape") close(); };
wrap.onclick = (e) => { if (e.target === wrap) close(); };
document.addEventListener("keydown", onEsc, true);
document.body.appendChild(wrap);
}
@ -4914,13 +5014,21 @@
if (sleepChipEl._t !== txt) { sleepChipEl._t = txt; sleepChipEl.textContent = txt; sleepChipEl.style.display = txt ? "block" : "none"; }
}
function sleepFoldPass(t) {
if (dawn) { sleepChip(0); return; } // 🌒 during the entrance, the dawn owns the field
const canFold = !chakraMode && !zeroMode && connected;
const cabled = new Set();
for (const r of routesArr) cabled.add(r.source);
let onStage = null; // 🎪 the rig folds harder: only the liveliest uncabled hands stay
if (canFold && doorMode === "rig") {
const flows = [...sources.values()].filter(n => !cabled.has(n.key)).map(n => n.flowDisp || 0).sort((a, b) => b - a);
onStage = flows.length > 8 ? Math.max(flows[7], 0.02) : 0; // the 8th-liveliest sets the bar (never below the quiet line)
}
let slept = 0;
for (const n of sources.values()) {
const asleep = canFold && !cabled.has(n.key) && !selection.has(n.key) && soloKey !== n.key &&
(n.norm || 0) <= 0.02 && (t - (n._lastMoveT != null ? n._lastMoveT : -1e9)) > 45;
const quiet = onStage != null
? (n.flowDisp || 0) < onStage
: (n.norm || 0) <= 0.02 && (t - (n._lastMoveT != null ? n._lastMoveT : -1e9)) > 45;
const asleep = canFold && !cabled.has(n.key) && !selection.has(n.key) && soloKey !== n.key && quiet;
if (asleep) slept++;
const hide = asleep && sleepFold;
if (hide !== !!n.hidden) { n.hidden = hide; layoutDirty = true; }
@ -5190,6 +5298,8 @@
if (has("stop") || has("pause")) { godspeakBeat(false); godspeakSay("beat stopped"); return; }
if (has("play") || has("start") || has("go")) { godspeakBeat(true); godspeakSay("beat playing"); return; }
}
if (has("doors") || has("doorway")) { showDoorsCard(true); godspeakSay("🚪 the doors"); return; }
if (has("deal") && doorMode === "deal") { doorDeal(false); godspeakSay("🃏 dealt"); return; } // "deal again" — only while the deal is your door
if (has("spheres") || has("planets")) { // 🪐 RESONANCE — the sky by voice
if (has("off") || (has("stop") && !has("start"))) { spheresEnable(false); godspeakSay("spheres off"); return; }
if (has("faster") || has("quicker")) { spheresSetRate(spheres.rate * 2); godspeakSay("spheres faster → " + spheres.rate + " d/bar"); return; }
@ -5222,13 +5332,18 @@
// clobber what you're playing. A reload no longer drops you into the wall.
if (!moodAppliedThisLoad) {
moodAppliedThisLoad = true;
let firstEver = false, saved = "first light";
let firstEver = false, saved = "first light", door = null;
try { firstEver = !localStorage.getItem("gs_seen"); } catch (e) {}
try { saved = localStorage.getItem("gs_mood") || "first light"; } catch (e) {}
try { door = localStorage.getItem("gs_door"); } catch (e) {}
setTimeout(() => {
if (firstEver) {
try { localStorage.setItem("gs_seen", "1"); } catch (e) {}
showFirstVisitCard(); // three doors: zero / first light / storm
showDoorsCard(false); // 🚪 the doors: zero / light / storm / rig / deal / dawn
} else if (door === "rig" || door === "dawn") {
walkDoor(door, false); // 🚪 walk your remembered door (its mood-mark is muted inside)
} else if (door === "deal") {
doorDeal(true); // a fresh hand every arrival — silent, no undo mark for the load itself
} else if (saved === "0 zero") {
enterZero(true); // a returning zero-builder comes back to zero, build intact (C2)
} else {
@ -5502,6 +5617,7 @@
}
}
dawnPass(t); // 🌒 the entrance, if one is playing
sleepFoldPass(t); // 💤 quiet feeds fold; they wake themselves when the world speaks
if (layoutDirty) doLayout();
spheresFrame(); // 🪐 RESONANCE — refresh the sphere sources on the great-year clock
@ -5588,7 +5704,7 @@
for (const r of routesArr) {
const s = sources.get(r.source);
const d = dests.get(r.dest);
if (!s || !d) continue;
if (!s || !d || s.hidden) continue; // 🌒 no wire to a player still in the wings
const a = r.activeDisp;
const va = Math.max(a, 0.10); // a patched cable NEVER vanishes: a silent source still shows its wire
@ -8256,6 +8372,7 @@
() => { beat.open ? closeBeat() : openBeat(); }, "B");
ctxItem("⏪ UNGODLY — take it back" + (ungodly.past.length ? " (" + ungodly.past.length + ")" : ""),
() => ungodlyUndo(), "⌘Z");
ctxItem("🚪 the doors — how the world opens", () => showDoorsCard(true));
const moodSub = ctxSub("🌗 mood — how much world");
const z0 = document.createElement("div"); z0.className = "it";
z0.textContent = zeroMode ? "0 zero — you're building it (a mood leaves)" : "0 zero — build from nothing";

View File

@ -673,6 +673,11 @@
background: rgba(20,28,44,0.82); color: rgba(160,180,215,0.75); border: 1px solid rgba(120,150,200,0.22);
border-radius: 9px; padding: 4px 10px; font-size: 11px; -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
#sleepchip:hover { color: #cfe0ff; border-color: rgba(140,170,230,0.5); }
/* 🃏 the deal — the redeal chip sits above the sleeper chip */
#dealchip { position: fixed; left: 14px; bottom: 86px; z-index: 12; display: none; cursor: pointer;
background: rgba(28,24,46,0.85); color: rgba(200,185,235,0.85); border: 1px solid rgba(160,140,220,0.3);
border-radius: 9px; padding: 4px 10px; font-size: 11px; -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
#dealchip:hover { color: #e8ddff; border-color: rgba(180,160,240,0.6); }
</style>
<style>
/* standalone-manual overrides — render the grimoire as a normal scrolling page */
@ -1220,6 +1225,7 @@
<li><b>🕊 PSALM — sing, and the instrument answers.</b> Right-click the sky → <b>🕊 PSALM</b>, allow the microphone, and <b>sing</b>. The pitch is heard, <b>folded to the scale you're in</b> (so you're never out of key), and played as notes — a <b>🕊</b> chip shows the note leaving your throat. And the duet with <b>⚡ GODSPEED</b>: with the arp running, each note you sing <b>latches into the held chord</b>, one at a time — hum four notes and the machine arpeggiates the chord you sang. <b>It listens locally</b>: the analysis happens in the page, in its own silence, and <i>nothing ever leaves the machine</i> — no recording, no upload, just your voice becoming the instrument's.</li>
<li><b>✦ CANON — the shelf of worked examples.</b> Open <b>⚙ → DIMENSIONS</b> and at the top of the list, above your own saved worlds, sit four <b>✦ factory dimensions</b> that ship with the instrument — <i>the heartbeat</i> (a boom-bap kit with the swing and the kick's duck), <i>the wheel within the wheel</i> (WHEELS, made audible), <i>the squeeze</i> (the market pumping GODSQUASH), and <i>quiet arrival</i> (the earth echo, slow and sparse). Load one to hear a feature in its element, then save your own version under a new name — the ✦ ones are <b>read-only</b>, the same for everyone, a place to start rather than a thing to overwrite.</li>
<li><b>🪐 spheres — the music of the spheres.</b> Press <kbd>S</kbd> (or right-click the sky → <b>🪐 spheres</b>) and turn it <b>on</b>: the eight planets join the field as <b>modulation sources</b>, the slowest LFOs there are. Each planet offers three signals — <b>phase</b> (its heliocentric longitude, a sawtooth one full turn per orbit), <b>dist</b> (its eccentric breathing, in and out between perihelion and aphelion — Mercury and Mars swing hard, Venus barely), and <b>beat</b> (its <i>synodic</i> dance against Earth — Venus and Earth clasp every 583.9 days, the pentagram cycle). Route any of them like any source, or just say <i>"mars drive filter."</i> One knob rules time: the <b>rate</b>, from <b>1 to 3650 days of sky per bar</b> — at the default thirty, Venus' year is about seven and a half bars and Jupiter's a hundred and forty-four, real orbits compressed into slow musical arcs. And the <b>☸ orbital ratios</b> button sets the drum lanes' wheels to the true resonances — <b>4 : 8 : 16</b> (Io, Europa and Ganymede, locked at 1 : 2 : 4) and <b>8 : 13</b> (Venus to Earth, the pentagram in wheel form), so the polymeter you hear is one the solar system actually keeps. It is all <b>computed here, at the instrument's own clock</b> — the same JPL ephemeris SOLARGOD uses, vendored in, no network and no server, so the sky is deterministic: the same bar always shows the same heaven, and a saved patch reloads the identical sky.</li>
<li><b>🚪 The doors — how the world opens.</b> The front door is a skin like any other. On your first visit a card offers <b>six doors</b>, and the one you walk is <b>remembered</b> — every arrival after that opens the same way (right-click the sky → <b>🚪 the doors</b> to choose again, or say <i>"doors"</i>). The classics: <b>🌱 start from zero</b> (an empty field, build it yourself), <b>🌅 first light</b> (a gentle arrangement), <b>⛈ the full storm</b> (every hand at once). And the gig doors: <b>🎪 the rig</b> — you walk on stage with the <b>beat panel and GODSPEED already open</b> and the field folded to the eight liveliest hands, everything within reach; <b>🃏 the deal</b> — the world <b>deals you five cables</b> from its liveliest feeds onto five voices, <i>one card always pulsing</i>, with a <b>🃏 deal again</b> chip (and <kbd>⌘Z</kbd> takes any hand back) — redeal until it sings, and every arrival deals fresh; <b>🌒 the dawn</b> — the players <b>take the stage one at a time</b>, liveliest first, the field assembling itself over half a minute like an orchestra walking on. Same instrument behind every door — only the meeting changes.</li>
<li><b>⚡ Pulse — make the slow world playable.</b> Some of the planet's truest signals barely move — the national debt, the Moon's declination, a glacier of a currency. Right-click a node, open its cables, and tap the <b></b> chip on any cable to cycle <b>÷16 · ÷8 · ÷4 · bar</b>: the cable now <i>throbs on the godtime clock</i>, and the slow value becomes the <b>depth</b> of that throb. The debt stops being a frozen offset and becomes a sixteenth-note pressure whose weight is the debt itself — slow data as character, the clock as motion. Off by default; the world's own tempo is still the truth unless you ask for the heartbeat.</li>
<li><b>💤 The sleeper fold — and speed at a glance.</b> The field folds away <b>quiet feeds</b> — sources with no cables, no signal and nothing to say for a minute — behind a small <b>💤 chip</b> (bottom-left) that shows the count and brings them back with one click. The moment a folded feed <i>speaks</i>, it wakes itself and rejoins the field: the world breathes in and out of view. And every cable now moves at <b>the data's own rate</b> — streaming feeds race, glacial ones crawl — with the words to match: hover a column and each source row reads its speed (<i>streaming · ≈ every 3 bars · asleep, still 12m</i>), and a node's right-click readout says the same. What speed is that thing going at? Now it just tells you.</li>
<li><b>📽 The stage — send the visual to any screen.</b> Right-click the sky → <b>the stage</b> and a clean black mirror window opens, fed live from the canvas. Drag it to a projector, an AirPlay display, a second monitor — macOS treats it like any window — and <b>double-click for fullscreen</b>. The stage has a <b>camera</b>: the whole view by default (whatever you're in — a skin, the wheel, mind mode's POV), or right-click any node → <b>project this node</b> and the camera glides after that one sphere through its orbits, or <b>project its station</b> to frame a whole wheel and its satellites. Change cameras live from the menus while the projector runs; the audience sees the camera breathe from subject to subject.</li>
@ -1279,7 +1285,7 @@
<ol class="steps">
<li>Press <kbd></kbd> (top-right, or <kbd>F2</kbd>) to wake OMNI — the whole audio graph builds on the first press.</li>
<li>Your first visit opens gently in <b>🌅 first light</b>. Right-click the sky → <b>🌗 mood — how much world</b> to move between <i>first light</i>, <i>ambient drift</i> (all atmosphere, no drums) and <i>the full storm</i> (every hand at once).</li>
<li>Your first visit offers <b>🚪 six doors</b> — from <i>start from zero</i> to <i>the rig</i>, <i>the deal</i> and <i>the dawn</i> — and remembers the one you walk. Right-click the sky → <b>🌗 mood — how much world</b> to move between <i>first light</i>, <i>ambient drift</i> (all atmosphere, no drums) and <i>the full storm</i> (every hand at once), or <b>🚪 the doors</b> to change how the world opens.</li>
<li>Play notes three ways: enter <b>chakra view</b> (<kbd>C</kbd>) and click a wheel's core for a 12-key console (play it with the <kbd>Q…P</kbd> row or a MIDI keyboard); open <b>🎛 tracks</b> (<kbd>T</kbd>) to sequence a song; or just wire the world's data to play it hands-free.</li>
<li>Shape the character: swap the pluck voice (<b>🎸 string voice</b> / <b>🎛 GODSONIQ</b>), or drag any feed onto <kbd>crush</kbd>, <kbd>wavetable.morph</kbd> or <kbd>granular.density</kbd>.</li>
</ol>
@ -1338,7 +1344,7 @@
<h2 id="building-from-zero-the-empty-instrument">Building from zero — the empty instrument</h2>
<p class="lead">The full instrument is a sensory flood by design. <b>Zero</b> is the other door: an empty field with nothing wired, where you build the whole thing by hand, one cable at a time. Same matrix underneath — a calmer face on it. On your first visit the three-door card offers it (<b>🌱 start from zero</b>); after that, press <kbd>F11</kbd>, or ⚙ → <b>DIMENSIONS → ✦ dimension zero</b>, or the 🌗 mood menu → <b>0 zero</b>.</p>
<p class="lead">The full instrument is a sensory flood by design. <b>Zero</b> is the other door: an empty field with nothing wired, where you build the whole thing by hand, one cable at a time. Same matrix underneath — a calmer face on it. On your first visit the doors card offers it (<b>🌱 start from zero</b>); after that, press <kbd>F11</kbd>, or ⚙ → <b>DIMENSIONS → ✦ dimension zero</b>, the 🌗 mood menu → <b>0 zero</b>, or <b>🚪 the doors</b>.</p>
<ol class="steps">
<li>Down each side sit <b>seven vibe-rings</b> — the world grouped into the seven elements (left) and seven domains (right). Each ring <b>breathes</b> with its group's live average. Click one to open its drawer.</li>