A generative instrument you play by moving through a 178-genre vector space. This page walks the whole pipeline: how one point on the star map becomes a song, how the song refuses to loop, and how a machine proves every genre still sounds like itself.
Part one
HOW A SONG IS MADE — seven stages, always in this order, every random draw pulled from seeded streams so the same seed always renders the same music.
app/targeting.js · weightsAt
The star map turns a point into a genre-weight blend: inverse-square distance over the ≤4 nearest anchors, plus a continuous snap-to-anchor pull scaled by how unambiguously nearest the closest star is — on a star ⇒ pure genre; between two ⇒ natural blend. Each genre neighborhood also gets its own key (name-hash mod 12), so crossing into a new dominant genre is a key change.
engine/genre-kernel.js · resolveMulti(weights, seed)
One mulberry32(seed) stream — mulberry32 is a tiny seeded random-number generator — with a fixed draw order. Scalars (bpm, swing, humanize, fx) blend by weighted lerp (a linear blend) of each parent's [lo,hi] range, then one sample. Pools (progression, kit, form, voicing) draw one parent proportional to weight, then pick inside that parent's pool — blends combine, never smear. Grouped dimensions draw ONE parent for the whole group so a recipe and its source pool always agree.
Energy-preserving pattern inheritance: for bass and lead patterns, a parent whose pattern-pool energy is ≥1.25 rungs above the runner-up and carries weight ≥.35 takes the draw outright — a dancey parent keeps its groove against a wash-heavy neighborhood. DX7 patches sharing an FM algorithm morph by lerping their ~144-dim param vectors. The MUSIC-MIND axes (adventure, color, voicing, reharm, pipes, rhythm complexity) draw dead last on the same stream.
Then constrain() keeps midpoints songs: the kit snaps to jungle/breaks/machine-four above 150 bpm, adventure is capped at .75, ≤2-chord progressions force reharm off, rhythm complexity is capped .4 above 165 bpm.
engine/genre-kernel.js · toState(choice, opts)
toState applies the 8 macro sliders (acoustic, density, dust, space, bright, feel, energy, vocal — post-resolution, zero-rng, all-neutral = byte-identical no-op), then builds sections: a form graph walked by one generic interpreter, with a duration solver that lands cycle counts within ±10% of the 180 s target. Past 175 s unevolved, the 3-minute rule splits plateaus and evolves at boundaries — a key walk of +2/−3/+5, a kit or lead re-roll, or a one-time form pivot.
Sampled by default: the state ships with the SF2 sample library (105 sampled instruments, plus 114 DX7 patches), while signature synths — tb303, reese, wobble, acid, synclead, modeld, vocoder — stay pure synth. The absent-knob law holds: if a feature wasn't chosen, the blueprint simply doesn't carry that knob — and an absent knob cannot change the output (the byte-identity law).
engine/csd-engine.js · buildEvents(state)
One function turns the state into every note. It runs in this exact order, each pass on its own seed stream:
engine/faust/state-engine.js · mapEvents
The event fabric becomes per-note Faust parameter sets: freq, gain and decay everywhere; the NOTE_PARAMS whitelist maps pipe annotations to real DSP sliders only where the module exposes them (cutoffMul ⇒ cutoff/tone, vib ⇒ vibrato) and silently drops the rest. Blue-note bends render only on sampler units; sampled drums emit one-shots with real tom repitch; found sounds get an auto-tune spec and a speech-rate cap for intelligibility.
engine/faust/state-engine.js · voiceUnits
Per-voice modules are picked from the synth fleet, dx7_algN cartridges and native PCM samplers — the SF2 default — with per-voice insert chains, pool-level dry/reverb/delay/ping-pong sends, and an fx bus: zita or a per-genre reverbColor module, plus a 3-band master compressor. The synth fleet and the DX7 cartridges are Faust compiled to WebAssembly; the sampled instruments are native PCM zone playback — everything mixed on one bus, live in your browser.
engine/faust/live.js · makeWalk
ONE authoritative walk shared by the live map and the offline journey renderer: each call builds exactly one chord bar — it polls the current target (retarget and glide just mutate what it reads), reseeds seed + serial×7919 per bar while instrument identity stays on the song seed, fills only on a section's last cycle, sweeps only on its first and last. Two output paths: the ring/worklet path (desktop — same voice topology ⇒ glide by feeding bars into the running stream; a topology change ⇒ bridge stream and equal-power crossfade) and the WAV-first path (mobile — rolling rendered WAV segments on a real audio element, pocket-proof).
Part two
HOW A SONG EVOLVES — nothing loops verbatim, and all of it is seeded.
Per-cycle humanity. Hats drop out 9% per hit; drum levels breathe (25% of hits ±15%); a quiet ghost snare lands on an off-slot in 40% of chord bars; later cycles of a section get busier; bass notes octave-pop 5%, push late 6%, rest 5%. With the rhythm knob: per-cycle bass-cell mutation (drop, anticipate, octave-flip — hard cap 2 per cycle) and melody rhythm cells that snap phrases onto one of three rhythm grids (dotted pairs, tresillo, 3-3-2), pitch material untouched. The snare-law guarantees no snare or hat bar three-peats anywhere.
Section form. 7 form graphs (dj, drop, wave, pop generative; ritual, anthem, transit hand-authored and video-locked) of typed nodes — ground, build, peak, release, exposed, cadence — walked by one interpreter. Past 175 s unevolved the track MUST evolve: modulate (a cumulative +2/−3/+5 semitone key walk — the whole band, samplers included, transposes), re-roll a fresh kit and lead from the anchor's own pools, or form-pivot, once per track and never into wave.
Glide and travel. While LIVE, moving the cursor queues a smooth glide — the continuous morph plus discrete voice and section flips — through the same per-bar path; the traveler walks a drawn path leg by leg, retargeting every bar. Blends interpolate every dimension including the mind axes.
Journeys. Waypoints are genre names or drawn points; weight vectors lerp leg by leg. Per track, the key walks the circle of fifths (+7 or +5 semitones mod 12), and a novelty memory remembers the last 2 tracks' kit/progression/bass/lead/found signature — a candidate matching ≥3 of 5 fields is rerolled, up to 6 attempts. Rendered journeys are DJ-mixed at the PCM level: downbeat-aligned seams, beatmatch when the bpm gap ≤8, a 2-bar crossfade when ≤40, a hard cut beyond that.
Part three
THE VERIFIER LOOP — how a machine keeps 178 genres honest.
Every render is measured on 23 symbolic features — bpm, off-grid feel, snare balance, hat and drum density, variation, wash, sub, motion, sevenths, break/chop/bed use, crackle, pump, compression, swing, humanize, acoustic, rubato, lead voices, soft top, interlock — and scored against 178 per-genre target rows of [lo, hi, weight] fences. The matrix renders every anchor at seeds 1, 2, 3 and requires 178/178 diagonal dominance: every genre scores highest as itself. Run after every change.
1 · Determinism. Same seed ⇒ byte-identical events; an absent knob ⇒ byte-identical output (zero rng draws). Every subsystem draws from its own seeded stream, so new dimensions draw dead last and untouched genres press byte-identically.
2 · The matrix. 178/178 diagonal-dominant after every change. If a tweak makes house stop sounding most like house, the change does not land.