eurorack-js / architecture
Visual architecture reference · July 2026

Voltages in.
Sound out.

A complete visual tour of the browser-based Eurorack emulator: who owns state, how patches become an atomic audio graph, where DSP runs, and how UI, MIDI, plugins, telemetry, and tests fit around the real-time core.

66built-in modules
12module categories
v3strict patch schema
1production DSP thread
User / browser UI Authoritative host / state AudioWorklet / DSP Validated / persisted data Failure boundary
01 · System overview

One rack, two threads

The browser owns interaction and persistent state. The AudioWorklet owns all production signal processing. RackHost is the authority between them.

Operational mental model

The shortest accurate picture of the running application.

Component map
flowchart LR
    U["Musician"] --> APP["EurorackApp
DOM & interaction"] subgraph MAIN["Browser main thread"] APP --> HOST["RackHost
authoritative runtime API"] HOST <--> STATE["RackState
modules · rows · params · cables"] HOST <--> REG["PluginRegistry
definitions & ownership"] APP <--> UI["Renderer + toolkit
stable UI mirrors"] HOST <--> ENG["AudioWorkletEngine
message controller"] APP <--> MIDI["MIDI manager"] MIDI --> ENG end subgraph WORKLET["AudioWorklet thread"] PROC["EurorackProcessor"] WREG["Worklet plugin registry"] DSP["DSP instances"] GRAPH["Compiled signal graph"] WREG --> PROC PROC --> DSP GRAPH --> DSP end ENG <--> PROC PROC --> OUT["Stereo Web Audio output"] classDef ui fill:#352910,stroke:#f6b94a,color:#fff; classDef host fill:#102b32,stroke:#57d5e8,color:#fff; classDef dsp fill:#271f3b,stroke:#b59af3,color:#fff; classDef data fill:#17301f,stroke:#79d991,color:#fff; class U,APP,UI,MIDI ui; class HOST,ENG host; class PROC,WREG,DSP,GRAPH dsp; class STATE,REG data;
Core invariantThere is no ScriptProcessor, timer, or main-thread fallback DSP path. If AudioWorklet is unavailable, audio does not start.
Control plane

DOM events, patch management, module layout, cables, saved settings, and the authoritative API live on the main thread.

Data plane

Voltage buffers, module processing order, feedback delays, output summing, and fault isolation live in the worklet.

Boundary

Versioned messages carry topologies, params, MIDI, telemetry, module events, profiling, and runtime state.

02 · Startup & ownership

Boot the control plane first

Core definitions are registered before the sidebar and rack render. Audio remains opt-in and is created only after a user gesture.

Application startup

Browser bootstrap through the first stable rack render.

Sequence
sequenceDiagram
    autonumber
    participant B as Browser
    participant A as EurorackApp
    participant H as RackHost
    participant R as PluginRegistry
    participant S as RackState
    B->>A: init()
    A->>H: init()
    H->>R: loadCorePlugin()
    R->>R: load + validate 66 definitions
    R-->>H: atomic registration
    H->>S: create stable UI mirrors
    H-->>A: host ready
    A->>A: bind DOM, theme, MIDI, patches
    A->>A: render sidebar and current rack
                        

Audio startup

The secure-context worklet path is created on demand.

Sequence
sequenceDiagram
    autonumber
    actor U as User
    participant A as EurorackApp
    participant H as RackHost
    participant E as WorkletEngine
    participant P as Processor
    U->>A: Start audio
    A->>A: create / resume AudioContext
    A->>H: startAudio(context)
    H->>E: create engine
    E->>E: add processor module
    E->>P: create AudioWorkletNode
    E->>P: topology revision 1
    P->>P: validate + compile graph
    P-->>E: topology-active(1)
    E-->>H: activation resolved
    H-->>A: audio running
                        

Ownership rules

Each layer has one job; crossing these boundaries is a design smell.

Responsibility
flowchart TB
    APP["EurorackApp"] -->|"renders & delegates"| HOST["RackHost"]
    HOST -->|"mutates"| STATE["RackState"]
    HOST -->|"creates / disposes"| MIRROR["Stable UI mirror"]
    HOST -->|"publishes"| ENGINE["WorkletEngine"]
    ENGINE -->|"messages"| PROC["EurorackProcessor"]
    PROC -->|"owns"| DSP["Production DSP instances"]
    PROC -->|"activates"| GRAPH["Compiled graph"]

    APP -.->|"never mutates production DSP"| DSP
    MIRROR -.->|"never produces sound"| GRAPH

    classDef ui fill:#352910,stroke:#f6b94a,color:#fff;
    classDef host fill:#102b32,stroke:#57d5e8,color:#fff;
    classDef dsp fill:#271f3b,stroke:#b59af3,color:#fff;
    classDef data fill:#17301f,stroke:#79d991,color:#fff;
    class APP ui;
    class HOST,ENGINE host;
    class STATE,MIRROR data;
    class PROC,DSP,GRAPH dsp;
                    
AuthorityRackHost is the only production owner of module lifecycle, parameters, cables, patch loading, runtime state, and audio activation.
03 · Patch to sound

A topology is a transaction

Every structural change becomes a revision. The worklet builds the candidate graph completely before swapping it into the live audio path.

End-to-end activation

From a user action to the next audible render quantum.

Sequence
sequenceDiagram
    autonumber
    actor U as Musician
    participant A as EurorackApp
    participant H as RackHost
    participant S as RackState
    participant E as WorkletEngine
    participant P as Processor
    participant G as compileGraph()

    U->>A: add module / move cable / load patch
    A->>H: authoritative command
    H->>S: validate and mutate state
    H->>E: setPatchState(runtime patch)
    E->>E: load required plugin worklets
    E->>P: topology(revision N)
    P->>P: validate plugins and module ownership
    P->>P: create or reuse DSP instances
    P->>G: compile candidate routes and order
    alt candidate is valid
        G-->>P: immutable execution plan
        P->>P: swap active modules + graph
        P-->>E: topology-active(N)
        E-->>H: resolve activation
        H-->>A: commit visible patch result
    else validation or compilation fails
        G-->>P: error
        P-->>E: host-error(N)
        E-->>H: reject activation
        Note over P: Previous audio graph stays active
    end
                    
AtomicityA compilation failure never leaves a half-connected rack. The previous graph keeps running until the full replacement is acknowledged.
04 · Graph compiler

Dependencies before samples

The compiler validates endpoints, discovers strongly connected components, inserts explicit feedback delays, and creates a deterministic processing order.

Compilation pipeline

What compileGraph() produces.

Flow
flowchart TB
    IN["Modules + cables + block size"] --> V["Validate module IDs, ports,
directions, buffers, duplicate inputs"] V --> ADJ["Build dependency adjacency"] ADJ --> SCC["Find strongly connected
components"] SCC --> COND["Build component DAG"] COND --> SORT["Topological sort"] SORT --> TIE["Tie break: manifest order →
rack order → instance ID"] TIE --> ROUTE["Create direct and delayed routes"] ROUTE --> PLAN["Execution plan:
ordered modules + routes + normals"] V -. invalid .-> ERR["Reject candidate topology"] classDef host fill:#102b32,stroke:#57d5e8,color:#fff; classDef dsp fill:#271f3b,stroke:#b59af3,color:#fff; classDef bad fill:#3a181d,stroke:#ff7b83,color:#fff; class IN,V,ADJ,SCC,COND,SORT,TIE host; class ROUTE,PLAN dsp; class ERR bad;

Feedback is explicit

Every route inside a feedback component uses a one-block delay.

SCC rule
flowchart LR
    subgraph BLOCK_N["Render block N"]
        A["Module A"] -->|"direct route"| B["Module B"]
        B -->|"write block N"| D[("delay buffer")]
        OLD[("block N−1")] -->|"feedback input"| A
    end
    D -.->|"becomes"| OLD

    SELF["Self-feedback module"] --> SD[("one-block delay")]
    SD --> SELF

    classDef dsp fill:#271f3b,stroke:#b59af3,color:#fff;
    classDef data fill:#17301f,stroke:#79d991,color:#fff;
    class A,B,SELF dsp;
    class D,OLD,SD data;
                        
WhyThe delay makes cycles deterministic and prevents execution order from secretly changing feedback behavior.
Input cardinality

One source per input. UI patching replaces an occupied input; imported duplicate destinations are rejected.

Output cardinality

Outputs can fan out to any number of inputs. Fan-in requires an explicit mixer or logic module.

Disconnection

Removing a cable restores the destination buffer to the port’s declared normal voltage.

05 · Audio render loop

One block at a time

At each quantum the processor timestamps MIDI, routes stable buffers, processes modules in dependency order, isolates failures, and sums output sinks to stereo.

Worklet render quantum

The hot path that must remain allocation-conscious and browser-independent.

Real-time loop
flowchart LR
    START["process() quantum"] --> MIDI["Begin MIDI block
compute sample offsets"] MIDI --> NORMALS["Restore unconnected
input normals"] NORMALS --> NEXT{"Next module in
compiled order"} NEXT --> ROUTE["Copy source samples into
stable destination buffers"] ROUTE --> RUN["instance.process()"] RUN --> OK{"Threw?"} OK -->|"no"| EVENTS["Drain bounded events
and capture profiling"] OK -->|"yes"| DISABLE["Disable instance
zero its outputs"] EVENTS --> MORE{"More modules?"} DISABLE --> MORE MORE -->|"yes"| NEXT MORE -->|"no"| SUM["Sum audio-output sinks
scale ±5V to ±1"] SUM --> TELEMETRY{"~30 Hz telemetry tick?"} TELEMETRY -->|"yes"| POST["Post params, LEDs,
declared fields/history"] TELEMETRY -->|"no"| END["End MIDI block"] POST --> END END --> RETURN["Return true"] classDef dsp fill:#271f3b,stroke:#b59af3,color:#fff; classDef data fill:#17301f,stroke:#79d991,color:#fff; classDef bad fill:#3a181d,stroke:#ff7b83,color:#fff; class START,NEXT,ROUTE,RUN,EVENTS,MORE,SUM,TELEMETRY,END,RETURN dsp; class MIDI,NORMALS,POST data; class OK,DISABLE bad;
Fault isolationA module exception disables only that instance and zeros its outputs; the rest of the rack continues rendering.
SignalDefault minimumDefault maximumInput normalUse
audio−5V+5V0VDC-coupled audio-rate signal
cv−5V+5V0VContinuous control voltage; pitch uses 1V/octave
gate0V10V0VHeld logical state; common threshold ≥1V
trigger0V10V0VShort 5–10ms pulse
any−10V+10V0VExplicitly signal-agnostic port
06 · Module contract

Self-contained definition, dual instantiation

Every module colocates metadata, DSP, and UI schema. The same definition creates a stable main-thread mirror and a separate production worklet instance.

Definition anatomy

The contract exported by modules/{id}/index.js.

Schema
flowchart TB
    DEF["Module definition"]
    DEF --> META["Metadata
id · name · hp · color · category · role"] DEF --> FACTORY["createDSP(options)"] FACTORY --> INSTANCE["DSP instance"] INSTANCE --> PARAMS["params"] INSTANCE --> INPUTS["stable input buffers"] INSTANCE --> OUTPUTS["stable output buffers"] INSTANCE --> LEDS["LED state"] INSTANCE --> METHODS["process() · reset() · optional hooks"] DEF --> UI["UI contract"] UI --> CONTROLS["knobs · switches · buttons · actions"] UI --> PORTS["inputs · outputs · voltage contracts"] UI --> STATE["patch-persisted ui.state"] DEF --> OPTIONAL["Optional browser bridge"] OPTIONAL --> RENDER["render() + css"] OPTIONAL --> TEL["bounded telemetry"] OPTIONAL --> EVENTS["handleWorkletEvent()"] classDef host fill:#102b32,stroke:#57d5e8,color:#fff; classDef dsp fill:#271f3b,stroke:#b59af3,color:#fff; classDef data fill:#17301f,stroke:#79d991,color:#fff; class DEF,META,UI,OPTIONAL,CONTROLS,PORTS,STATE,RENDER,TEL,EVENTS host; class FACTORY,INSTANCE,PARAMS,INPUTS,OUTPUTS,LEDS,METHODS dsp;

Two instances, one identity

The mirror survives audio start and stop; the worklet instance is the only one processed.

Thread split
flowchart TB
    DEF["Same validated module definition"]
    DEF --> MAIN["Main thread createDSP()"]
    DEF --> WORKLET["Worklet createDSP()"]
    MAIN --> MIRROR["Stable UI mirror
display + custom renderer state"] WORKLET --> PROD["Production DSP instance
voltage buffers + process()"] CONTROL["Control change"] --> HOST["RackHost.setParam()"] HOST --> MIRROR HOST -->|"param message"| PROD PROD -->|"bounded telemetry"| MIRROR PROD --> SOUND["Sound"] MIRROR -.->|"never process"| SOUND classDef host fill:#102b32,stroke:#57d5e8,color:#fff; classDef dsp fill:#271f3b,stroke:#b59af3,color:#fff; classDef data fill:#17301f,stroke:#79d991,color:#fff; class DEF,CONTROL,HOST host; class WORKLET,PROD,SOUND dsp; class MAIN,MIRROR data;
Control ruleCustom controls must call onParamChange. Directly mutating the mirror cannot affect audio.
07 · UI & cables

Declarative panels, transactional patching

The renderer turns module schemas into DOM controls, while cable gestures remain previews until a valid endpoint move commits one rack-state change.

Panel rendering

Shared controls for standard modules; bounded escape hatch for bespoke interfaces.

UI flow
flowchart TB
    DEF["Module definition"] --> MODE{"Custom render()?"}
    MODE -->|"no"| DECL["renderDeclarativeUI()"]
    DECL --> TOOLKIT["Toolkit components
knob · jack · switch · LED"] MODE -->|"yes"| CUSTOM["definition.render()"] CUSTOM --> BOUND["Bound toolkit + cleanup hooks"] TOOLKIT --> PANEL["Module panel DOM"] BOUND --> PANEL PANEL --> EVENT["Control interaction"] EVENT --> CHANGE["onParamChange(module, param, value)"] CHANGE --> HOST["RackHost.setParam()"] HOST --> SYNC["syncParamToModuleUI()"] classDef ui fill:#352910,stroke:#f6b94a,color:#fff; classDef host fill:#102b32,stroke:#57d5e8,color:#fff; class DEF,MODE,DECL,TOOLKIT,CUSTOM,BOUND,PANEL,EVENT ui; class CHANGE,HOST,SYNC host;

Cable gesture transaction

No disconnected intermediate topology reaches the worklet.

Interaction
flowchart TB
    DOWN["Pointer down on jack"] --> CONNECTED{"Already connected?"}
    CONNECTED -->|"no"| NEW["Preview new cable"]
    CONNECTED -->|"yes"| MOD{"Modifier?"}
    MOD -->|"Shift"| NEW
    MOD -->|"Ctrl / Cmd"| CYCLE["Cycle cables sharing jack"]
    MOD -->|"none"| MOVE["Preview moving endpoint"]
    CYCLE --> MOVE
    NEW --> DROP{"Drop target"}
    MOVE --> DROP
    DROP -->|"compatible jack"| COMMIT["Atomic connect / moveCable"]
    DROP -->|"Escape, click, blur,
incompatible jack"| RESTORE["Restore original connection"] DROP -->|"true drag to empty space"| REMOVE["Explicitly disconnect"] COMMIT --> REV["Publish one topology revision"] REMOVE --> REV classDef ui fill:#352910,stroke:#f6b94a,color:#fff; classDef host fill:#102b32,stroke:#57d5e8,color:#fff; classDef data fill:#17301f,stroke:#79d991,color:#fff; class DOWN,CONNECTED,MOD,NEW,CYCLE,MOVE,DROP ui; class COMMIT,REMOVE,REV host; class RESTORE data;
08 · MIDI & telemetry

Two tempos of communication

Sample-positioned MIDI moves toward DSP. Bounded display state moves back at UI rate. Large or infrequent results use a separate event boundary.

Cross-thread message lanes

Fast control messages, periodic snapshots, and command-boundary events have different contracts.

Message map
flowchart LR
    subgraph MAIN["Main thread"]
        MIDIDEV["Web MIDI device"] --> MM["MIDI manager"]
        CTRL["Panel control"] --> HOST["RackHost"]
        MIRROR["Stable UI mirrors"] --> RENDER["Renderer / displays"]
        BROWSER["Browser-only handlers
WAV export · DOM work"] end subgraph PORT["AudioWorklet MessagePort"] PMIDI["midi + audioTime"] PPARAM["validated param"] PTEL["telemetry ~30 Hz"] PEVENT["module-event + transferables"] PSTATE["runtime state / profiling"] end subgraph DSP["Worklet"] MS["Shared MIDI service
sampleOffset events"] MODS["All DSP modules"] COLLECT["Telemetry collector"] DRAIN["drainEvents()"] end MM --> PMIDI --> MS --> MODS HOST --> PPARAM --> MODS MODS --> COLLECT --> PTEL --> MIRROR MODS --> DRAIN --> PEVENT --> BROWSER HOST <--> PSTATE <--> MODS classDef ui fill:#352910,stroke:#f6b94a,color:#fff; classDef host fill:#102b32,stroke:#57d5e8,color:#fff; classDef dsp fill:#271f3b,stroke:#b59af3,color:#fff; classDef data fill:#17301f,stroke:#79d991,color:#fff; class MIDIDEV,MM,CTRL,RENDER,BROWSER ui; class HOST,PMIDI,PPARAM,PTEL,PEVENT,PSTATE host; class MS,MODS,COLLECT,DRAIN dsp; class MIRROR data;
MIDI timing

Note and transport events get a per-block sampleOffset. Every MIDI module sees the same non-destructive event arrays.

Telemetry

Params and LEDs always sync. Custom fields, methods, and history must be declared and bounded.

Module events

Infrequent transferable payloads cross via drainEvents() / handleWorkletEvent(), not continuous telemetry.

09 · Patches & state

Persist the score, not the instrument’s RAM

Patch schema v3 stores a strict, portable rack description. Runtime-only buffers are captured separately when audio stops and restored only to the next topology.

Canonical patch v3

Every reference is exact and every dependency is explicit.

Data model
flowchart TB
    PATCH["Patch state · version 3"]
    PATCH --> PLUGINS["plugins
plugin ID → patch contract version"] PATCH --> MODULES["modules[]
instance ID · type · row · index"] PATCH --> PARAMS["params{}
instance ID → declared finite values"] PATCH --> CABLES["cables[]
exact source and destination ports"] PATCH --> MAPS["midiMappings{}"] PLUGINS --> VALID["normalizePatch() + strict validation"] MODULES --> VALID PARAMS --> VALID CABLES --> VALID MAPS --> VALID VALID -->|"all valid"| LOAD["RackHost.loadPatch()"] VALID -->|"anything invalid"| REJECT["Reject whole patch"] classDef data fill:#17301f,stroke:#79d991,color:#fff; classDef host fill:#102b32,stroke:#57d5e8,color:#fff; classDef bad fill:#3a181d,stroke:#ff7b83,color:#fff; class PATCH,PLUGINS,MODULES,PARAMS,CABLES,MAPS data; class VALID,LOAD host; class REJECT bad;

Persistent vs runtime state

Small finite configuration and bulk live data take separate paths.

Lifecycle
flowchart TB
    CONFIG["Patch-persisted state"] --> P1["Visible controls"]
    CONFIG --> P2["ui.state values"]
    P1 --> JSON["JSON / local storage /
gzip URL hash"] P2 --> JSON LIVE["Runtime-only state"] --> L1["Looper buffers"] LIVE --> L2["Gesture recordings"] L1 --> CAP["captureRuntimeState()"] L2 --> CAP CAP --> STOP["Audio stop"] STOP --> NEXT["Next runtime topology only"] NEXT --> RESTORE["restoreRuntimeState()"] classDef data fill:#17301f,stroke:#79d991,color:#fff; classDef host fill:#102b32,stroke:#57d5e8,color:#fff; class CONFIG,P1,P2,JSON data; class LIVE,L1,L2,CAP,STOP,NEXT,RESTORE host;
TimeoutTopology acknowledgements and runtime-state requests have a five-second timeout; runtime capture failure cannot prevent audio shutdown.
10 · Plugin system

Trusted code, matched contracts

Plugins are not sandboxed. Registration is atomic on the main thread, and any active patch requires matching ownership and patch contracts in the worklet.

Plugin registration and activation

The two registries must agree before any plugin module can process audio.

Trust boundary
flowchart LR
    subgraph PACKAGE["Trusted plugin package"]
        MAN["Main manifest
id · version · apiVersion · patchVersion"] DEFS["Module definitions"] WURL["Worklet URL"] WENTRY["registerEurorackWorkletPlugin()"] end subgraph MAIN["Main-thread registry"] CHECK["Load every definition"] VALID["Validate contracts and collisions"] ATOMIC{"All valid?"} VISIBLE["Publish modules atomically"] end subgraph WORKLET["Audio activation"] LOAD["Load worklet URL on demand"] WREG["Worklet plugin registry"] MATCH{"Plugin + patch version +
module owner match?"} ACTIVE["Create DSP instance"] end MAN --> CHECK DEFS --> CHECK --> VALID --> ATOMIC ATOMIC -->|"yes"| VISIBLE ATOMIC -->|"no"| FAIL["Expose nothing"] WURL --> LOAD --> WENTRY --> WREG --> MATCH VISIBLE --> MATCH MATCH -->|"yes"| ACTIVE MATCH -->|"no"| REJECT["Reject topology"] classDef host fill:#102b32,stroke:#57d5e8,color:#fff; classDef dsp fill:#271f3b,stroke:#b59af3,color:#fff; classDef data fill:#17301f,stroke:#79d991,color:#fff; classDef bad fill:#3a181d,stroke:#ff7b83,color:#fff; class MAN,DEFS,WURL,WENTRY data; class CHECK,VALID,ATOMIC,VISIBLE host; class LOAD,WREG,MATCH,ACTIVE dsp; class FAIL,REJECT bad;
Core special caseBuilt-ins have a lazy main-thread manifest and a matching static worklet definition list. Their IDs, order, aliases, and graph revision must remain synchronized.
11 · Module catalog

The rack’s functional surface

The manifest provides deterministic default order; each definition owns its sidebar category. All signals remain DC-coupled regardless of semantic port labels.

66 built-in modules by role

Categories are UI taxonomy, while graph order is dependency-driven at runtime.

Catalog
flowchart TB
    RACK["eurorack-js module library · 66"]
    RACK --> MIDI["MIDI · 5
midi-cv · midi-4 · midi-cc
midi-clk · midi-drum"] RACK --> CLOCK["Clock · 5
clk · div · swing
burst · gate-delay"] RACK --> SOURCE["Sources · 5
nse · vco · wavetable
complex-vco · ensemble-vco"] RACK --> VOICE["Voices · 4
pluck · kick · snare · hat"] RACK --> MOD["Modulation · 6
lfo · quad-lfo · rnd
func · adsr · ochd"] RACK --> SEQ["Sequencers · 5
arp · seq · seq-switch
euclid · turing"] RACK --> QUANT["Quantizer · 1
quant"] RACK --> FILTER["Filters · 4
vcf · lpg · formant · resbank"] RACK --> FX["Effects · 11
fold · ring · dly · tape · verb · chorus
phaser · flanger · crush · loop · granulita"] RACK --> UTIL["Utility · 19
sh · logic · mult · matrix · joystick · envf
vca · atten · slew · db · pwm · cmp2 · comp
mix · scope · spectrum · plot · spectrogram · rec"] RACK --> OUTPUT["Output · 1
out"] RACK --> OTHER["Other · 0
reserved category"] classDef root fill:#102b32,stroke:#57d5e8,color:#fff; classDef ui fill:#352910,stroke:#f6b94a,color:#fff; classDef dsp fill:#271f3b,stroke:#b59af3,color:#fff; classDef data fill:#17301f,stroke:#79d991,color:#fff; class RACK root; class MIDI,CLOCK,SEQ,QUANT ui; class SOURCE,VOICE,MOD,FILTER,FX dsp; class UTIL,OUTPUT,OTHER data;
12 · Quality & delivery

Research, specify, test, listen

Module work starts with cited behavior and voltage contracts, moves through tests-before-DSP, then passes focused, matrix, integration, and browser validation.

Module delivery gate

The queue workflow prevents implementation before the contract is ready.

Workflow
flowchart TB
    C["candidate"] --> R["researching"]
    R --> SOURCES["Primary sources + demos +
electrical cross-checks"] SOURCES --> SPEC["Panel + voltage + DSP plan +
assumptions + test targets"] SPEC --> READY["spec-ready"] READY --> PLAN["Implementation Plan in research doc"] PLAN --> TESTS["Write focused tests first"] TESTS --> IMPL["implementing"] IMPL --> VALID["focused tests + DSP matrix audit"] VALID --> FULL["full npm test + listening / profiling"] FULL --> DONE["done"] SOURCES -. unresolved contradiction .-> BLOCK["blocked"] VALID -. failed contract .-> IMPL classDef host fill:#102b32,stroke:#57d5e8,color:#fff; classDef data fill:#17301f,stroke:#79d991,color:#fff; classDef bad fill:#3a181d,stroke:#ff7b83,color:#fff; class C,R,SOURCES,SPEC,PLAN,TESTS,IMPL,VALID,FULL host; class READY,DONE data; class BLOCK bad;

Validation layers

Different failures belong to different test suites.

Test pyramid
flowchart TB
    E2E["Playwright E2E
real browser interactions"] INT["Worklet + app integration
topology, lifecycle, patches"] CONTRACT["Contract tests
manifest, modules, plugins, research"] DSP["68 focused DSP suites
ranges, controls, reset, buffers"] UTILS["Utility unit tests
FFT, interpolation, slew, voltage"] AUDIT["DSP audit matrix
sample rates × block sizes × strict voltage"] UTILS --> DSP --> CONTRACT --> INT --> E2E DSP --> AUDIT AUDIT --> INT classDef ui fill:#352910,stroke:#f6b94a,color:#fff; classDef host fill:#102b32,stroke:#57d5e8,color:#fff; classDef dsp fill:#271f3b,stroke:#b59af3,color:#fff; classDef data fill:#17301f,stroke:#79d991,color:#fff; class UTILS data; class DSP,AUDIT dsp; class CONTRACT,INT host; class E2E ui;
13 · Change map

Where each concern lives

Use this as the final hop from architecture to code. Runtime-source links open the deployed files; repository-only material opens on GitHub.

Repository responsibility map

The smallest useful set of entry points for navigating the system.

Source index