viz: the Eight Shapes + Your Own Sources (Grimoire) + live heart-rate source

- Grimoire: "The eight shapes" — the data typology (drift, flux, events,
  counts, accumulators, angles, enums, booleans; SHAPE->CLEAN->BOUND->SPEAK)
- Grimoire: "Your own sources" — the personal layer: heart (live), portfolio
  (designed: holdings as weights), natal chart (designed)
- body.heart: opt-in Web Bluetooth heart-rate source (standard BLE HR service,
  browser permission = consent, pulse never leaves the page). Menu: connect /
  disconnect / godtime-follows-your-heart (tempo = your pulse). Routes to the
  heart's true home in every skin: anahata, Tiferet, Qalb, Fire, Sol's gate,
  the Querent, the Lodge altar.
- tof.*/touch join hand.* in the personal routings; body.* joins the body family

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
type-two 2026-07-05 19:51:03 +10:00
parent 74338cf13c
commit 6079ff266a

View File

@ -364,6 +364,30 @@
<div class="hr"></div>
<h2>The eight shapes — every number the world sends has a temperament</h2>
<p class="lead">Beneath the hundred sources there are only <b>eight shapes of data</b>. Name the shape and the whole question of "how should this become sound?" answers itself. This is the instrument's deepest grammar — every feed, present or future, is one of these eight temperaments, and each temperament has a canonical way of being cleaned, bounded, and spoken.</p>
<p><b>1 · Drift</b> — smooth, slow, bounded. <i>The moon's phase, the seasons, life expectancy, the sun's height.</i> The world's breathing. It wants gentle smoothing and a known range, and it sounds like <b>modulation</b>: filters opening, space swelling, brightness turning. Drift is the tide under everything.</p>
<p><b>2 · Flux</b> — continuous but restless. <i>Wind, market velocity, bitcoin's fever, the room's loudness.</i> It jitters, so it wants the One-Euro filter (calm when idle, quick when it truly moves) and an adaptive window that learns its recent range. Flux sounds like <b>movement</b>: LFO rate, grit, the busyness of the percussion.</p>
<p><b>3 · Events</b> — silence, then a spike that carries a magnitude. <i>An earthquake, a wiki edit, a new wildfire, a flash of light.</i> Not a level but an <b>occurrence</b>. Events want envelopes — the quake's slow 3.5-second bloom, the edit's sharp spark — and they sound like <b>triggers</b>: hits, swells, gates thrown open, magnitude as velocity.</p>
<p><b>4 · Counts</b> — small integers stepping up and down. <i>Aircraft aloft, wildfires burning.</i> Discrete by nature; smoothing them into a continuum wastes their character. Counts sound like <b>steps</b>: how many drone voices, how many hats, a census turned to rhythm.</p>
<p><b>5 · Accumulators</b> — numbers that only ever grow. <i>The national debt, the human population.</i> As a level they are almost mute (normalized, they read "1.0, forever"), so the music lives in their <b>derivative</b> — which this instrument discovered by instinct when <kbd>debt.vel</kbd> and <kbd>clock.popvel</kbd> were built as their own feeds. The mass becomes a drone's weight; the velocity becomes its life.</p>
<p><b>6 · Angles</b> — degrees on a wheel, 0 to 360, and then the wrap. <i>Every planetary longitude, the zodiac hour.</i> An angle is not a quantity but a <b>position on a circle</b>: it wants sawtooth treatment (an orbit completing is a downbeat — Saturn crossing 0° Aries should be felt), circular mappings (pan, phase), and quantizing — twelve signs are twelve notes waiting.</p>
<p><b>7 · Enums</b> — a named phase from a small set. <i>The almanac's earth/leaf/flower/fruit element, the hour's zodiac animal.</i> Not quantities at all — <b>categories</b> — and treating them as sliders makes a fruit-day sound "33% louder" than a leaf-day, which is nonsense. An enum wants to <b>switch</b> things: the scale, the timbre, the sample bank. A categorical change is a mode change: the world modulating to a new key.</p>
<p><b>8 · Booleans</b> — yes or no. <i>Mercury retrograde, day or night, fertile or not.</i> They want to <b>toggle</b>: mute a layer, flip major to minor, throw the delay in. When retrograde switches on, the state of the world has changed, and the instrument should change state with it.</p>
<p>The whole pipeline, then, in four verbs: <b>SHAPE → CLEAN → BOUND → SPEAK.</b> Know the shape; clean it by its temperament (One-Euro for flux, envelope for events, derivative for accumulators, wrap-awareness for angles, hands-off for enums and booleans); bound it by its temperament (fixed range for drift, rolling window for flux, log for magnitudes); and let it speak in its native register — drift modulates, flux moves, events strike, counts step, angles cycle, enums switch, booleans toggle. Eight temperaments of number. The planet has no other kinds.</p>
<div class="hr"></div>
<h2>The sources — the world, listening</h2>
<p class="lead">Forty-odd feeds, and not one of them was invented for you. Every source in this instrument is a real measurement of a real thing happening right now — a satellite over the Pacific, a trade clearing on Binance, a tremor under Honshu, the Moon at some true longitude computed to the arc-second. The hub does not synthesize the world; it <i>listens</i> to it, normalizes what it hears into a clean 0..1 stream, and hands that stream to the matrix as a modulator. What follows is the whole choir, grouped by where in the world each voice lives. For each: what it truly measures, the tempo it naturally moves at, and why <i>this</i> — of all things — deserved to be a voice.</p>
@ -464,6 +488,20 @@
<div class="hr"></div>
<h2>Your own sources — the Source is also you</h2>
<p class="lead">The sacred is not only the sky. It is also the body, the wallet, the pulse — exercise and money and food and joy. The world's choir is the same for everyone; <b>your own sources</b> are the verse only you can sing. Everything in this layer is <b>opt-in, yours, and private</b>: nothing is read without your say-so, and your body's data goes to your browser and nowhere else.</p>
<p><b>♥ Your heart — live now.</b> If you have a Bluetooth heart-rate device (a chest strap, many watches and fitbits in broadcast mode), right-click the sky and choose <b>♥ connect your heart</b>. The browser itself asks your permission — that is the opt-in — and from that moment <kbd>body.heart</kbd> is a source like any other: your pulse in beats per minute, normalized 40→180, ready to be patched into anything. It routes where a heart belongs in every tradition: the <b>anahata</b> chakra, <b>Tiferet</b> at the Tree's solar centre, <b>Qalb</b> among the lata'if, the <b>Fire</b> phase (the heart is the fire-organ in Chinese medicine), the <b>Sun gate</b> on the Hermetic ladder, the <b>Querent</b> in the spread. And there is a second, deeper wiring: choose <b>godtime follows your heart</b> and the instrument's tempo becomes your actual pulse — the whole planet playing at the speed of your blood. Dance, and the world keeps up. Rest, and it rests. (Web Bluetooth needs Chrome or Edge; your pulse never touches the server.)</p>
<p><b>💰 Your holdings — designed, coming.</b> The dealgod market already plays one person's commerce; the general form is <b>the portfolio source</b>: you declare what you hold — tickers, coins, metals — and <i>how much of each</i>, and the amounts become <b>weights</b>. Ten shares of one thing and a thousand of another, and the thousand sings ten times louder: <kbd>me.portfolio</kbd> as your total's daily breath (drift), <kbd>me.portfolio.vel</kbd> as its churn (flux), each holding optionally its own feed. Gold droning at the foundation, your tech stocks glittering at Hod, the whole bag weighted exactly as your risk is weighted. Your finances are already an instrument; we only add the speakers.</p>
<p><b>✨ Your stars — designed, coming.</b> The natal layer: your birth — date, time to the ten-minute, place — computed by the same Swiss Ephemeris that already turns tonight's sky. Your natal positions become fixed reference tones, and the <b>live transits against them</b> become sources: the sky's slow conversation with the chart you were born under, audible. Saturn crossing your natal Sun as a months-long bass note. And nothing stops you loading a lover's chart, or a friend's — the instrument plays relationships too.</p>
<p class="foot">One Source, many Spirits, one Matter — and the Source was never only "out there." The instrument's ambition is simple: <b>everything that varies can sing</b>, and the first citizen of that everything is you.</p>
<div class="hr"></div>
<h2>The living patch — what drives what</h2>
<p class="lead">This is the factory routing: every cable in <kbd>config.json</kbd>, source by source, voice by voice. Each cable is a real feed normalized to <b>0..1</b>, bent by a <i>curve</i>, scaled by an <i>amount</i>, and poured into one destination of the modulation matrix. <b>lin</b> is honest and linear; <b>scurve</b> eases in and out (a soft, musical S); <b>exp</b> and <b>exp3</b> hug the floor and only bloom near the top (so grit and glitch stay clean until the world genuinely spikes). A <b>gate</b> silences the cable until the source crosses a threshold. <b>quantize</b> snaps a wandering number onto the notes of a scale, so a data stream sings in a key instead of wobbling formlessly. What follows is the whole instrument, wire by wire — imagine, but also know.</p>
@ -905,7 +943,7 @@
function familyOf(key) {
const p = (key || "").split(".")[0].toLowerCase();
if (["tof","light","hand","audio","mic","touch","room","cam"].includes(p)) return "body";
if (["tof","light","hand","audio","mic","touch","room","cam","body"].includes(p)) return "body";
if (["weather","air","quake","seismic","tide","temp"].includes(p)) return "planet";
if (["sun","iss","planes","plane","sky","aurora","moon","space"].includes(p)) return "sky";
if (["crypto","market","stock","btc","eth","fx"].includes(p)) return "markets";
@ -1896,6 +1934,7 @@
function chakraOf(key) {
const k = (key || "").toLowerCase();
const p = k.split(".")[0];
if (p === "body") return "heart"; // your pulse at anahata
// crown — cosmos & consciousness: the actual machinery of the sky
if (p === "iss" || p === "space" || /_lon|mercury|venus|jupiter|saturn/.test(k)) return "crown";
if (p === "sun" && !/elev/.test(k)) return "crown"; // solar wind
@ -2006,6 +2045,7 @@
};
function treeOf(key) {
const k = (key || "").toLowerCase(), p = k.split(".")[0];
if (p === "body") return "tiferet"; // the heart at the Tree's solar centre
if (k === "sun.speed") return "keter"; // the first swirlings
if (/sun_lon|zodiac/.test(k) || p === "iss" || k === "clock.births" || k === "clock.popvel") return "chokmah";
if (k === "astro.saturn" || p === "debt" || /inflation/.test(k)) return "binah"; // Saturn: time, weight, form
@ -2043,6 +2083,7 @@
};
function lodgeOf(key) {
const k = (key || "").toLowerCase(), p = k.split(".")[0];
if (p === "body") return "altar"; // your living heart, laid at the centre
if (p === "hand" || p === "tof" || p === "touch") // the candidate at the porch
return /\.x$|open/.test(k) ? "boaz" : "jachin";
if (/^sky\.|sun_lon|_lon|zodiac/.test(k) || k === "astro.saturn" || k === "astro.mars") return "east"; // the heavens, read from the East
@ -2074,6 +2115,7 @@
};
function ladderOf(key) {
const k = (key || "").toLowerCase(), p = k.split(".")[0];
if (p === "body") return "sun"; // the heart at Sol's gate
if (k === "astro.saturn" || p === "debt" || /inflation|poverty|hunger|zodiac/.test(k)) return "saturn";
if (/lifeexp|fertile|harmony|births|popvel/.test(k)) return "jupiter";
if (k === "astro.mars" || p === "fire" || /tension|quake\.event|deaths/.test(k)) return "mars";
@ -2134,6 +2176,7 @@
};
function lataifOf(key) {
const k = (key || "").toLowerCase(), p = k.split(".")[0];
if (p === "body") return "qalb"; // Qalb IS the heart
if (k === "sun.speed") return "akhfa"; // the most rarefied
if (p === "astro" || /zodiac|almanac/.test(k)) return "khafi"; // the hidden influences
if (/^sky\.|_lon/.test(k)) return "sirr"; // the secret geometry above
@ -2161,6 +2204,7 @@
};
function wuxingOf(key) {
const k = (key || "").toLowerCase(), p = k.split(".")[0];
if (p === "body") return "fire"; // the heart is the fire-organ (TCM)
if (/births|popvel|season|fertile|lifeexp|wind|harmony|almanac\.element/.test(k)) return "wood";
if (p === "fire" || /temp|mars|tension|ambient|light\.|sky\./.test(k) || k === "sun.speed") return "fire";
if (/saturn|quake|hunger|poverty|pressure|debt\.total/.test(k)) return "earth";
@ -2195,7 +2239,7 @@
};
function spreadOf(key) {
const k = (key || "").toLowerCase(), p = k.split(".")[0];
if (p === "hand" || p === "tof" || p === "touch") return "querent"; // you are the one asking
if (p === "hand" || p === "tof" || p === "touch" || p === "body") return "querent"; // you are the one asking
if (/retro/.test(k) || k === "clock.deaths") return "behind"; // what recedes, what looks backward
if (/^sky\.|sun\.|_lon|zodiac/.test(k) || p === "iss") return "crown"; // what is above you
if (/quake\.depth|debt\.total|saturn|poverty/.test(k)) return "foundation"; // the deep structure beneath
@ -3211,6 +3255,15 @@
() => setFxMode(fxMode === "auto" ? "full" : fxMode === "full" ? "ultra"
: fxMode === "ultra" ? "lite" : "auto"));
if (soloKey) ctxItem("clear solo (" + soloKey + ")", () => { soloKey = null; });
ctxSep();
if (!hrDevice) {
ctxItem("♥ connect your heart (bluetooth)", () => connectHeart());
} else {
ctxItem("♥ " + (heartBpm() ? Math.round(heartBpm()) + " bpm" : "listening…") + " · disconnect",
() => disconnectHeart());
ctxItem((heartDrivesGodtime ? "✓ " : "") + "godtime follows your heart",
() => { heartDrivesGodtime = !heartDrivesGodtime; });
}
}
ctxEl.classList.add("open");
ctxEl.style.left = Math.min(px, window.innerWidth - 252) + "px";
@ -3364,6 +3417,50 @@
grp.appendChild(hint);
}
// ---- your heart (Web Bluetooth, opt-in) ---------------------------------
// The standard BLE Heart Rate Service (0x180D). The browser's own permission
// prompt IS the opt-in; the pulse goes to this page and nowhere else. From
// connection on, body.heart is a source like any other — and godtime can be
// set to follow it, so the whole planet plays at the speed of your blood.
let hrDevice = null;
let heartDrivesGodtime = false;
function heartBpm() { const n = sources.get("body.heart"); return n ? n.raw : 0; }
async function connectHeart() {
if (!navigator.bluetooth) {
eventTicker.unshift({ text: "web bluetooth needs chrome or edge", tAdded: now(), src: "sys" });
return;
}
try {
const dev = await navigator.bluetooth.requestDevice({ filters: [{ services: ["heart_rate"] }] });
const server = await dev.gatt.connect();
const svc = await server.getPrimaryService("heart_rate");
const ch = await svc.getCharacteristic("heart_rate_measurement");
await ch.startNotifications();
ch.addEventListener("characteristicvaluechanged", (e) => {
const dv = e.target.value;
const flags = dv.getUint8(0);
const bpm = (flags & 1) ? dv.getUint16(1, true) : dv.getUint8(1); // spec: bit0 = 16-bit value
if (!bpm || bpm > 250) return;
const n = ensureSource("body.heart", { label: "your heart" });
n.raw = bpm;
n.norm = clamp((bpm - 40) / (180 - 40), 0, 1);
if (heartDrivesGodtime && !godtime.locked)
godtime.bpm = clamp(bpm, 40, 180);
});
hrDevice = dev;
dev.addEventListener("gattserverdisconnected", () => {
hrDevice = null;
eventTicker.unshift({ text: "heart disconnected", tAdded: now(), src: "sys" });
});
eventTicker.unshift({ text: "♥ your heart is in the choir", tAdded: now(), src: "sys" });
} catch (e) { /* user closed the chooser — their call, no fuss */ }
}
function disconnectHeart() {
if (hrDevice) { try { hrDevice.gatt.disconnect(); } catch (e) {} hrDevice = null; }
heartDrivesGodtime = false;
}
// ---- Web MIDI ----
async function enableMidi() {
if (!navigator.requestMIDIAccess) {