Godstrument/ZERO_OMNI_BRIEF.md
type-two b6f1c59e15 📖 brief: STATUS + CONTINUATION — Z0-Z2 approved, C1-C4 instructions (Fable review)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 23:42:05 +10:00

293 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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: "<name>"` 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.<base64url(json)>` — "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.
---
# STATUS + CONTINUATION (Fable review, 2026-07-10)
**Z0Z2 verified and approved** (commits 2a705e3, d30cea4, 4e44533, 9a7f947): the three-door
card, the calm 7+7 ring field, spinning orbs, drag-to-route, the synth-roll assign menu —
all live-verified, Z-AC met (bitcoin sang through a sun-opened filter from zero), console
clean, syntax clean, field-draw correctly guarded. Genuinely good work.
Continue from here, in this order:
## C1. Fix: leaving zero silently DISCARDS the user's build (real bug)
`exitZeroToMood` always restores `gs_prezero`, replacing routesArr — so a user who built
cables in zero and clicks "first light" loses their build with no warning. The brief's
intent (§2 graduation): *"leaving zero shows the full field with everything the user
built still wired."* Fix: on exit, if the current (zero-built) patch has ≥1 route, offer a
small three-way choice (same visual language as the door card, but compact):
- **keep my build** — don't restore prezero; just drop the overlay + apply the mood's
mutes/gains only (the build stays as the whole patch);
- **bring the old world back** — current behavior (restore prezero);
- **weave them together** — restore prezero THEN re-registerRoute the zero-built routes
on top (registerRoute dedups by source|dest).
If the zero build has 0 routes, skip the prompt entirely (current behavior is right).
## C2. Zero build must survive a reload
Routes persist via the matrix, but `zeroUI.nodes` (picked feeds / stage orbs) don't — a
returning zero-user (gs_mood="0 zero") reloads into an empty stage even though their
cables exist. Persist the picks to localStorage (`gs_zeronodes`: {group: [srcKeys]}) on
every pick/route; restore in `zeroUI.open()`. Also reconstruct socket lit-state (already
done via refreshSockets) — verify with a reload test.
## C3. Orb interactions beyond drag (touch + depth)
HTML5 drag doesn't exist on touch, and orbs currently have no menu:
- **Tap-to-patch fallback:** click/tap an orb → it "arms" (glow ring, cursor hint);
click a socket → routeGroup(armed, dest); click elsewhere → disarm. Keep drag working.
- **Right-click an orb** → small menu: member list with × to remove a feed, "unpatch
everything from this orb", and (stub for Z3) "💾 save as vibe". Removing the last
member removes the orb.
- **⛈ graduation affordance:** a small fixed "⛈ enter the storm" pill inside the zero UI
(bottom-right above the rack) → runs the C1 exit flow with mood "the full storm".
## C4 = Z3 (vibes), Z5 (OMNI panel), Z4 (dimensions), Z6 (ship) — per the brief above
Follow the brief sections 3, 4, 5, 6 as written, with these additions learned since:
- The orb right-click "save as vibe" (C3) is the natural zero-mode entry to Z3 — a vibe
is exactly one orb's members + the routes they carry.
- auth.py vibes store: use the existing `CREATE TABLE IF NOT EXISTS` idiom (auth.py:44-46
style) so the server migrates itself on restart — additive only. Test locally against a
COPY of godstrument_users.db, never the live file, and remember the deploy never ships
the db.
- Vibe import parses user-pasted data → validate hard (source/dest against known sets,
numeric clamps, 32-route cap, try/catch the base64/JSON). This is a trust boundary.
- **Before the Z6 deploy, run the `/ship-check` skill** (pre-deploy security sweep) —
this feature set touches auth.py and user-pasted input, which is exactly its territory.
- Nit (low): while in zero, the chakra-view key (F3/C) flips chakraMode with nothing
drawn — make it a no-op in zero (or have it exit zero first via the C1 flow).
Keep the cadence: extraction-check → build → verify in the logged-in preview (z0test /
zeropass123 account exists) → screenshot → commit per milestone. Deploy only at Z6 after
the adversarial review. The grimoire is truth — Z6 writes zero/vibes/dimensions/OMNI-panel
sections in the tech-manual style (numbered how-to + spec table) and regenerates the manual.