From 35c094f8d816c1bbde9534032b53318f2c618e06 Mon Sep 17 00:00:00 2001 From: type-two Date: Fri, 10 Jul 2026 22:40:58 +1000 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=96=20ZERO=5FOMNI=5FBRIEF=20=E2=80=94?= =?UTF-8?q?=20zero=20mode,=20vibes/dimensions,=20OMNI=20panel=20(build=20b?= =?UTF-8?q?rief=20for=20Opus,=20by=20Fable)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- ZERO_OMNI_BRIEF.md | 227 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 ZERO_OMNI_BRIEF.md diff --git a/ZERO_OMNI_BRIEF.md b/ZERO_OMNI_BRIEF.md new file mode 100644 index 0000000..bc3a285 --- /dev/null +++ b/ZERO_OMNI_BRIEF.md @@ -0,0 +1,227 @@ +# ZERO MODE · VIBES · DIMENSIONS · the OMNI panel +### Build brief for the implementing model (Opus). Read fully before writing code. + +John's ask, verbatim spirit: *the full UI is an intense sensory assault. Give people a +**zero mode** — 7 sources left, 7 right, click a slot to see the feeds in that grouping +(same colors/chakra energy as the main UI), pick one or more, route them by hand to an +output, right-click to assign it (synth role / MIDI / …). They build everything from +zero. Save the whole thing as a **dimension** (a full hardcore scene save); save a +specific source→route→output combo as a **vibe** — "build a vibe, save a vibe, share a +vibe". And give OMNI a NICE UI panel.* + +--- + +## 0. Ground rules (unchanged from every Godstrument session) + +- **Canon:** `viz/index.html` is truth; the grimoire prose inside it must be updated to + match whatever ships (never the other way). Regenerate `GODSTRUMENT_MANUAL_SOURCE.md` + with the builder afterwards (`build_grimoire.py` pattern — carry-forward + dedupe). +- **Honesty rule:** nothing decorative. Every slot, knob, and control maps to a real + feed/dest/tweak. If a thing isn't wired, it doesn't render. +- **Verify with your own eyes:** preview server + login (invite + `/api/signup` recipe — + see memory `godstrument-local-verify`), console clean, then screenshot proof. +- **Deploy:** rsync git-tracked files to botchat (`humanjing@100.71.119.27`, app dir + `/home/humanjing/godstrument`), **never `--delete`**, never push `godstrument_users.db` + / `auth_secret` / `patches/`; `sudo -n systemctl restart godstrument`; curl-verify + cache-busted. First load post-deploy is slow (cold start). +- **auth.py changes must be additive** (new table / new column with default) — the + server's SQLite holds real user accounts. Never a destructive migration. +- Commit per milestone with the Co-Authored-By line. Adversarially review at the end + (a Workflow, as in previous sessions) and fix confirmed findings before deploy. + +## 1. What already exists — build on it, don't reinvent + +| Thing | Where (verify at build time) | Use it for | +|---|---|---| +| **14 concept groups** with `label`, `orbit`, `members` | `config.json:31-46` ("groups"); grimoire "The vibes — grouping by feeling" (~line 848-900, has the emojis: 💰 wealth, 💧 water, …) | The 7+7 zero slots. They are ALREADY called vibes in canon. | +| MOODS + applyMood | `viz/index.html:2275-2322` | The pattern for entering/leaving a named state; zero joins this family | +| First-visit flow (`gs_seen`, `gs_mood`) | `viz/index.html:2841-2842` | Zero as the new-user front door | +| serializePatch / loadPatch | `viz/index.html:2532-2567` | Dimensions ARE this; a blank dimension = `{routes:[], …}` | +| addRouteLocal / registerRoute / removeRouteLocal | `viz/index.html:2452-2468, 2921` | Zero-mode routing + vibe apply/remove | +| "patch to →" context submenu | `viz/index.html:5521` | Reuse for assigning a node to an output | +| Node tweaks (mute/gain/offset), setParamLocal | `viz/index.html:2036+, 2451` | OMNI panel knobs = views over these | +| MY PATCHES (account presets, one JSON blob) | `auth.py:46 (presets table), :249+ (endpoints)`; ⚙ panel UI | Rename surface to **Dimensions**; vibes get a sibling store | +| CHAKRAS (colors) | `viz/index.html:3427` | The zero-slot color language | +| Arranger panel (`arrbtn`, resizable, tabbed) | `viz/index.html:1497+, 2325-2330` | The UI pattern for the OMNI panel | +| KEY_ACTIONS + remappable keys | `viz/index.html:~6060-6110` | Key bindings for zero + OMNI panel | +| quantize option on routes | `viz/index.html:1398, 2415` | The "assign like a synth roll" — note outputs get scale/root/octaves | + +**Extraction discipline:** before each milestone, re-verify the exact lines above (they +drift) and extract any formula/shape you depend on into code comments citing +`viz/index.html:LINE`. + +## 2. ZERO MODE — dimension zero + +**Concept:** a fourth entry in the mood family, but deeper: not muted — **empty**. +No cables, no voices sounding, the field silent and almost blank. The user builds the +entire instrument by hand, one cable at a time. Leaving zero (to any mood / the storm) +restores the full factory experience. + +### Entry & exit +- Right-click sky → **`0 zero — build from nothing`** (top of the mood submenu), plus a + key (suggest `F11` or a free slot in DEFAULT_KEYS; check collisions). +- **First-visit choice card** (replaces the current silent default into first light): + three big options — 🌱 **start from zero** (build it yourself) · 🌅 **first light** + (a gentle song) · ⛈ **the full storm** (everything at once). Persist choice like + `gs_mood`. Returning users keep whatever they last used. +- Entering zero: snapshot the current patch to a holding slot (localStorage + `gs_prezero`) so exiting zero can offer "restore what you had" vs "keep my build". + Implementation: `loadPatch({routes: [], tweaks: {}, seqs: {}, …})` + a `zeroMode` + UI flag. Do NOT touch the hub or other users — this is all client-local, like moods. + +### The zero UI (the whole point: calm) +- **Hide the full node field.** Render instead: + - **7 slots down the left, 7 down the right** — the 14 groups from config.json in a + fixed, curated order (suggest: left = the elements/feelings: light, dark, fire, + water, earth, air, spirit · right = the domains: planet, cosmos, heavens, human, + market, wealth, summer). Each slot: a colored ring (its chakra/vibe hue — extract + or define a `GROUP_HUES` map; the grimoire's vibe emojis are the seed), the label, + and a live "breathing" glow driven by the group's average member value (already + computed for group nodes) — alive but quiet. + - **A center stage** — empty at first. Nodes the user builds land here. + - **An output rack** along the bottom (or right-center column): the destinations, + grouped and labeled in plain language: + - **OMNI voices:** lead (sings) · bass (roots) · pad (glows) · drone (hums) · perc (taps) + - **OMNI space & grit:** reverb.size · delay.feedback · saturation · glitch · + granular.density · crush · wavetable.morph · lfo.rate · master.space · filter.cutoff + - **🌀 earth echo** knobs (echo.*) — shown only when earth echo is on + - **MIDI** (when an out port is enabled): the CC map + lead/bass note channels + Each output is a small labeled socket, dark until something is patched into it. +- **Slot → picker drawer:** clicking a slot slides open a drawer listing that group's + member feeds: name, one-line plain-English description (extract from the grimoire + source blurbs / `signals` labels), live value bar, chakra color. Each row has ⊕. + Picking 1+ feeds **creates a node on the stage** (or adds to the slot's existing + node). The node renders like a mini group-node: the slot's color, member count badge. +- **Routing:** drag from a node to an output socket → lays a cable **per member feed** + to that dest at a sensible default amount (0.5, curve lin) — reusing addRouteLocal. + Alternatively right-click node → the existing "patch to →" submenu filtered to the + rack outputs. Cables render exactly like the main UI (same renderer — don't fork it). +- **Right-click assign (the "synth roll" ask):** right-click an output socket or a + cable → + - note outputs (lead.note/bass.note): **quantize picker** — scale (the 11 SCALES), + root (note name picker), octaves (1-3); presets "minor pent @C4" etc. + - CC/level outputs: amount slider + curve picker (lin/exp/exp3/log/scurve/inv) — + the existing route controls, surfaced. + - MIDI: choose CC number / channel (when midi enabled). +- **Guidance, not tutorial:** use the existing eventTicker for 3-4 contextual nudges + ("pick a source from a ring", "now drag it onto a voice", "press ♪ — that's YOUR + instrument"). No modal tutorial. The calm IS the feature. +- **Graduation:** a small "⛈ enter the storm" affordance; leaving zero shows the full + field with everything the user built still wired (their routes persist — zero is not + a sandbox, it's the same matrix). + +### Acceptance criteria (Z-AC) +From a fresh account in zero mode, with no instructions beyond the ticker nudges, this +sequence works in under a minute and makes sound: click a ring → pick `sun.speed` → +drag node to `filter.cutoff`; click another → pick `crypto.price` → drag to `lead` → +right-click lead → minor pent @ 60 → press ♪ → bitcoin sings through a sun-opened +filter. Verified in the preview with a screenshot; console clean; leaving zero → first +light works; re-entering zero offers restore. + +## 3. VIBES — build a vibe, save a vibe, share a vibe + +A **vibe** = a small, additive, shareable bundle of wiring: + +```json +{ "v": 1, "name": "sun filter", "emoji": "☀️", + "routes": [{"source": "sun.speed", "dest": "filter.cutoff", "amount": 0.85, "curve": "exp"}, + {"source": "crypto.price", "dest": "lead.note", "amount": 1.0, + "quantize": {"scale": "minor_pent", "root": 60, "octaves": 2}}] } +``` + +- **Apply = additive** (registerRoute upserts; nothing else touched). Tag applied + routes with `viaVibe: ""` so a vibe can be **toggled off** (remove exactly the + routes it added — removeRouteLocal). Multiple vibes stack; a route present in two + stays until both are off. +- **Save a vibe:** in zero mode, "💾 save as vibe" on the stage selection (or the whole + current zero build); in the full UI, right-click a node → "save these cables as a + vibe". Named + emoji. +- **Store:** account-side, in auth.py — **additive** migration: either a new `vibes` + table mirroring presets, or a `kind` column on presets defaulting `'dimension'`. + Endpoints mirror the preset ones (list/save/delete). Local fallback to localStorage + when signed out. +- **Share:** two mechanisms, both v1: + 1. **Vibe code:** compact string `GSV1.` — "copy vibe code" puts it + on the clipboard; an "import vibe" box (⚙ panel + zero mode) accepts a pasted code. + 2. **URL fragment:** `godstrument.pro/#vibe=GSV1....` — on load (post-login), offer + "apply the vibe you were sent?" Never auto-apply; show its name + route count + first. (Fragment never reaches the server — clean with the invite-only model.) +- **Validation:** parse defensively — unknown sources/dests in an imported vibe are + listed and skipped, not errors. Cap: 32 routes per vibe. + +### Vibes AC +Save a 2-route vibe, toggle it off/on, copy its code, hard-reload, import the code, +apply — identical wiring returns. A vibe code from another account applies cleanly. + +## 4. DIMENSIONS — the full scene save + +- **Rename the user-facing surface**: ⚙ "MY PATCHES" → **"DIMENSIONS"** ("a dimension + is the whole world you built — every cable, mix, groove, tempo, key"). Same + serializePatch blob, same endpoints — this is a naming + framing change; do NOT + break existing saved presets (they simply appear as dimensions). +- Zero mode ships with the blank state as **"dimension zero"** (a virtual, always- + available entry at the top of the list — not stored, generated). +- Grimoire: rewrite the "Saving your instrument" section for the dimension/vibe split: + *a dimension is everything; a vibe is a feeling you can hand to a friend.* + +## 5. The OMNI panel + +A dedicated synth panel, sibling to the tracks panel (same open/close/resize pattern — +`arrbtn` precedent). Button: **🎹 OMNI** bottom-right next to 🎛 tracks; key-bindable. + +- **Layout — a synth, not a mixer:** module strips: + - **VOICE:** the pluck voice selector — FM tine · 🎸 string · 🎛 GODSONIQ (with a + "sample 3s" button + sampling state) — wired to `Synth.stringVoice()` / + `Synth.godsoniq()` / `Synth.sampling()`; plus 🌐 tab feed toggle. + - **LEAD** (wavetable.morph knob) · **BASS** · **PAD** (pad.brightness) · + **DRONE** (drone.voices; a small "7.83 Hz" schumann lamp when earth echo is on) · + **PERC** (perc.density). + - **FX RACK:** filter.cutoff · reverb.size · delay.feedback · saturation · glitch · + granular.density · crush · lfo.rate · master.space (+ chorus shown as a fixed, + labeled, non-decorative indicator — it IS always on; label it honestly). + - **🌀 EARTH ECHO:** on/off + the six echo.* knobs (only enabled when on). + - **TRANSPORT:** ♪ toggle, mood selector, the current scale (from gScale, click → + scale picker), BPM readout linked to godtime. +- **Knob semantics (the crucial design):** every knob shows the **live world-driven + value** as an animated arc (from the dest's current value — the world's hand). + Dragging a knob adjusts the dest's **tweak gain/offset** (existing setParamLocal + machinery) — you're riding a fader the world is also pushing. Double-click resets + the tweak to neutral (the ⌘⇧-click semantic). A small dot shows when a knob has a + user tweak. Right-click a knob = the node's existing context menu (mute/solo/level/ + cables/patch to). **No new audio paths — the panel is a view over dests + tweaks.** +- Muted dests render dim; a grooved/p-locked dest shows a tiny grid icon. +- Works inside zero mode too (it doubles as zero's output rack detail view — if this + is cleanly achievable, the rack and the panel share components; if not, keep them + separate and simple). + +### OMNI AC +Open the panel: every knob's arc moves with live data; drag reverb.size up — audibly +more reverb and the dest tweak persists in the saved dimension; voice selector swaps +FM→string→GODSONIQ and plucks confirm; screenshot for the session log; console clean. + +## 6. Milestones (each: build → verify in preview → commit) + +- **Z0** — blank dimension + zero entry/exit + first-visit choice card + prezero restore. +- **Z1** — 7+7 slots + picker drawer + stage nodes (no routing yet). Colors/labels/live glow. +- **Z2** — routing to the output rack + right-click assign (quantize/curve/amount) + + ticker nudges. **Z-AC passes.** +- **Z3** — vibes: tag/apply/toggle, save to account (additive auth.py migration), + vibe code export/import + #vibe= fragment. **Vibes AC passes.** +- **Z4** — dimensions rename + dimension-zero entry + grimoire "Saving" rewrite. +- **Z5** — OMNI panel. **OMNI AC passes.** +- **Z6** — grimoire sections (zero mode gets its own tech-manual section in the style + of OMNI/Earth Echo/GODSONIQ: numbered how-to + spec table), regenerate the manual, + adversarial review workflow over the whole feature set, fix confirmed findings, + deploy to botchat, curl-verify live, update memory. + +## 7. Risks & taste notes + +- `viz/index.html` is ~7.5k lines of interlocking IIFE — add new sections as their own + IIFEs near their dependencies; do not restructure existing code to "make room". +- The 14-group order and hues are a **taste call** — propose them, note them as + one-line consts John can retune by ear/eye (the skins pattern). +- Zero mode must never fork the matrix/renderer: same routes, same cables, same synth. + If zero starts needing its own compute path, stop — the design has gone wrong. +- Don't gate existing users into zero — it's a door, not a wall. `gs_mood` returning + users land where they left off. +- Keep the first-visit card copy short and Godstrument-voiced. No onboarding-speak.