🔌 honesty pass — every control now does what it says

Retire the wired-audit debt so nothing is decorative-pretending-to-be-wired:
- FREEZE now works: a group freeze snapshots each member and holds it (was a
  set-but-never-read flag). Verified: holds 0.2 while the source moves to 0.9.
- .mid export is full-fidelity: real per-step velocity + ratchets expanded to
  sub-notes (was hardcoded vel 100, single hits). Chance/Play-One stay live-only
  — honest for a deterministic file.
- Hide the level/trim sliders on note voices (they never applied to a pitch —
  no more dead sliders).
- Grimoire honesty: soften "every source is a real measurement" to name the
  honest models (demographic tide, room-sensor sim); drop the phantom ⚙ SPELLS
  panel claim. Manual regenerated to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
type-two 2026-07-10 00:34:57 +10:00
parent 74df16c90f
commit e2170060c7
2 changed files with 27 additions and 9 deletions

View File

@ -84,7 +84,7 @@ The whole pipeline, then, in four verbs: **SHAPE → CLEAN → BOUND → SPEAK.*
## The sources — the world, listening
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 *listens* 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 *this* — of all things — deserved to be a voice.
Forty-odd feeds, and not one of them was invented to flatter you. **Nearly every source 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. A few, honestly, are **models** rather than live gauges: the human birth-and-death tide is a demographic model, and the room sensors (your hand, the light) fall back to a gentle simulator until a real rig is plugged in. Where the world truly is measured the hub does not synthesize it; it *listens*, 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 *this* — of all things — deserved to be a voice.
Read every source through three lenses at once. **The feed**: the actual API or computation behind it. **The character**: how fast it moves, because tempo is destiny in a modulation matrix — a sub-second feed is a rhythm engine, a decade-scale feed is ballast that barely breathes. **The lore**: what it *means* that this signal has a seat in the ensemble. A signal's normalization range (its `lo`/`hi` in **config.json**) is its tuning: it tells the hub what counts as "silent" and what counts as "full open" for that voice.
@ -596,7 +596,7 @@ MIDI-learn any of these at your synth and the planet drives your favorite hardwa
A patch you have played into being — the cables you dragged, the amounts you leaned, the mutes and freezes, the tempo you locked — is a whole instrument, and it deserves to survive the tab closing.
Open **⚙ → MY PATCHES** and **save**. The entire live state is written to your account, keyed to your login (*monsterrobotparty@gmail.com*): every route with its amount and curve, every group and orbit, the running mix of gains and mutes and freezes, and the godtime tempo. From any device, **load** it back and the exact instrument returns — the same planet, wired the same way, pulsing at the same locked BPM. (Locally, spells live as `patches/*.json` and cast the same full state from the ⚙ panel's SPELLS section; MY PATCHES is that power, carried to the cloud and back.)
Open **⚙ → MY PATCHES** and **save**. The entire live state is written to your account, keyed to your login (*monsterrobotparty@gmail.com*): every route with its amount and curve, every group and orbit, the running mix of gains and mutes and freezes, and the godtime tempo. From any device, **load** it back and the exact instrument returns — the same planet, wired the same way, pulsing at the same locked BPM. (Locally, spells live as `patches/*.json` on the host; MY PATCHES is that same power for signed-in players, carried to your account and back.)
---

View File

@ -547,7 +547,7 @@
<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>
<p class="lead">Forty-odd feeds, and not one of them was invented to flatter you. <b>Nearly every source is a real measurement of a real thing happening right now</b> — 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. A few, honestly, are <b>models</b> rather than live gauges: the human birth-and-death tide is a demographic model, and the room sensors (your hand, the light) fall back to a gentle simulator until a real rig is plugged in. Where the world truly is measured the hub does not synthesize it; it <i>listens</i>, 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>
<p>Read every source through three lenses at once. <b>The feed</b>: the actual API or computation behind it. <b>The character</b>: how fast it moves, because tempo is destiny in a modulation matrix — a sub-second feed is a rhythm engine, a decade-scale feed is ballast that barely breathes. <b>The lore</b>: what it <i>means</i> that this signal has a seat in the ensemble. A signal's normalization range (its <kbd>lo</kbd>/<kbd>hi</kbd> in <b>config.json</b>) is its tuning: it tells the hub what counts as "silent" and what counts as "full open" for that voice.</p>
@ -1010,7 +1010,7 @@
<p class="lead">A patch you have played into being — the cables you dragged, the amounts you leaned, the mutes and freezes, the tempo you locked — is a whole instrument, and it deserves to survive the tab closing.</p>
<p>Open <b>⚙ → MY PATCHES</b> and <b>save</b>. The entire live state is written to your account, keyed to your login (<i>monsterrobotparty@gmail.com</i>): every route with its amount and curve, every group and orbit, the running mix of gains and mutes and freezes, and the godtime tempo. From any device, <b>load</b> it back and the exact instrument returns — the same planet, wired the same way, pulsing at the same locked BPM. (Locally, spells live as <kbd>patches/*.json</kbd> and cast the same full state from the ⚙ panel's SPELLS section; MY PATCHES is that power, carried to the cloud and back.)</p>
<p>Open <b>⚙ → MY PATCHES</b> and <b>save</b>. The entire live state is written to your account, keyed to your login (<i>monsterrobotparty@gmail.com</i>): every route with its amount and curve, every group and orbit, the running mix of gains and mutes and freezes, and the godtime tempo. From any device, <b>load</b> it back and the exact instrument returns — the same planet, wired the same way, pulsing at the same locked BPM. (Locally, spells live as <kbd>patches/*.json</kbd> on the host; MY PATCHES is that same power for signed-in players, carried to your account and back.)</p>
<div class="hr"></div>
@ -1443,16 +1443,24 @@
const n = dests.get(key);
if (!n || !n.isNote) continue;
const ch = /bass/.test(key) ? 1 : 0, root = seqRootFor(key);
const sq = seqs[key]; // per-step velocity + ratchet ride here
const ev = [];
for (let b = 0; b < arr.bars; b++) {
const st = arr.grid[key][b];
if (st !== "A" && st !== "B" && st !== "C") continue;
const steps = arrBank(key, true)[st];
for (let s2 = 0; s2 < 16; s2++) {
const d = stepFirst(steps[s2]); // export the stack's first candidate
const d = stepFirst(steps[s2]); // Play-One → first candidate (a file is deterministic)
if (d < 0) continue;
const note = root + SEQ_ROWS[d], tick = (b * 16 + s2) * TICKS16;
ev.push([tick, 0x90 | ch, note, 100], [tick + TICKS16 - 2, 0x80 | ch, note, 0]);
const note = root + SEQ_ROWS[d];
const vel = Math.round(clamp(sq && sq.vel ? sq.vel[s2] : 0.8, 0.05, 1) * 127);
const rat = clamp(Math.round(sq && sq.rat ? sq.rat[s2] : 1), 1, 4);
const base = (b * 16 + s2) * TICKS16, subLen = TICKS16 / rat;
for (let h = 0; h < rat; h++) { // ratchets real sub-notes
const t0 = base + Math.round(h * subLen);
const t1 = Math.max(t0 + 1, base + Math.round((h + 1) * subLen) - 2);
ev.push([t0, 0x90 | ch, note, vel], [t1, 0x80 | ch, note, 0]);
}
}
}
if (!ev.length) continue;
@ -2187,6 +2195,10 @@
if (tweaks[key] && tweaks[key].mute >= 0.5) return true;
return groupsOf(key).some(g => tweaks["@" + g] && tweaks["@" + g].mute >= 0.5);
}
const frozenVals = {}; // freeze: a held photograph per source
function isFrozenLocal(key) {
return groupsOf(key).some(g => tweaks["@" + g] && tweaks["@" + g].freeze >= 0.5);
}
function tweakNorm(key, norm) {
let v = norm;
for (const g of groupsOf(key)) {
@ -2204,6 +2216,10 @@
const sv = {};
for (const [k, n] of sources) {
let v = (soloKey && k !== soloKey) ? 0 : tweakNorm(k, n.norm || 0);
if (isFrozenLocal(k)) { // freeze: hold the value it had when the group froze
if (frozenVals[k] == null) frozenVals[k] = v;
v = frozenVals[k];
} else if (frozenVals[k] != null) delete frozenVals[k];
const sq = seqs[k];
if (sq && sq.on) { // sample & hold: the world only speaks on your steps
if (sq.steps[seqCurStep] && sq._sampled !== seqCurStep) { sq.held = v; sq._sampled = seqCurStep; }
@ -5230,8 +5246,10 @@
ctxItem(node.muted ? "unmute" : "mute", () => toggleMuteLocal(node.key), "click");
if (isSrc) ctxItem(soloKey === node.key ? "unsolo" : "solo",
() => { soloKey = soloKey === node.key ? null : node.key; }, "⌥-click");
ctxSlider("level", t0.gain, 0, 2, x => { t0.gain = x; }, x => x.toFixed(2) + "×");
ctxSlider("trim", t0.offset, -1, 1, x => { t0.offset = x; });
if (!node.isNote) { // level/trim don't apply to a pitch — no dead sliders
ctxSlider("level", t0.gain, 0, 2, x => { t0.gain = x; }, x => x.toFixed(2) + "×");
ctxSlider("trim", t0.offset, -1, 1, x => { t0.offset = x; });
}
ctxSep();
// every cable this node carries, each with its amount + unpatch