Developer Documentation
Build your own audio modules directly inside µcor with the visual Module Builder. There is no SDK to install and no boilerplate. You assemble a module by dropping knobs, sliders, jacks and other elements onto a panel, wire up Web Audio nodes, and either save it as a private draft or publish it to the public registry.
Opening the Builder
The Module Builder lives inside the workstation. Open it from the top menu bar:
- Builder → New — start with a blank panel
- Builder → My Modules — reopen a saved draft
- Builder → Publish — ship the current module to the public registry
- Builder → Import VSTi — (preview) translate a VST instrument blueprint
You can also launch it programmatically from the browser console:
// Open with a blank blueprint
window.moduleBuilder.open();
// Open the saved-modules picker
window.moduleBuilder.showMyModules();
// Publish the current module
window.moduleBuilder.showPublish();
Builder Tour
The Builder overlay is split into four working zones:
| Zone | Purpose |
|---|---|
| Element Palette (left rail) | 14 drag-and-drop UI elements: knob, slider, button group, toggle, jack in/out, LED, display, label, image, section box, scope, rotary switch, keyboard. |
| Canvas (centre) | The module's visible panel. Drag elements, multi-select, snap to grid, resize the panel. |
| Properties Panel (right rail) | Edit the selected element: label, range, default, colour, audio binding. |
| Jacks Footer (bottom) | Add and remove input/output jacks, link them to audio nodes via the I/O map. |
Tabs at the top switch between Design (canvas + properties), Audio (node graph), Code (custom JS), and AI (chat assistant). The toolbar exposes Undo/Redo, Save, Preview, Test (load into the workspace), and Publish.
Element Palette
Drag any palette item onto the canvas. Each element gets a unique id (auto-generated el_N) and is stored in blueprint.elements. The element type determines which properties show up on the right.
| Type | Notes |
|---|---|
knob | Continuous control with min/max/default. Bind to an audio node param via bind: { node, param }. |
slider | Same data model as knob, vertical or horizontal. |
button_group | Discrete options. Useful for waveform, filter type, mode. |
toggle | Boolean on/off (mute, sync, bypass). |
jack_in / jack_out | Visual jack on the panel. The port wiring is configured in the Jacks Footer, not on the element itself. |
led | Status indicator. Drive it from custom code via setLED(id, on). |
display | Read-only numeric or text readout. |
label / image / section_box | Decorative. Sections can be coloured to group controls visually. |
scope | Live waveform display, taps an analyser audio node. |
rotary_switch | N-position rotary, like a select but laid out as a dial. |
keyboard | Mini piano keyboard that emits gate + 1V/oct CV. |
Properties Panel
Selecting one element shows its editable properties. Multi-select shows only properties common to every selection. Typical fields:
- label, x/y, width/height — layout
- min, max, default, step, scale (linear / log) — numeric range
- options — for button groups and rotary switches, an array of
{ value, label } - bind —
{ node: 'filter1', param: 'frequency' }hooks the control to an AudioParam - color — per-element accent (used for cable colour on jacks)
Jacks Footer
Jacks are the module's external I/O. Each entry in blueprint.jacks.inputs / blueprint.jacks.outputs declares a port the user can plug a cable into. Jacks must reference an audio.inputMap or audio.outputMap entry.
{
"jacks": {
"inputs": [{ "id": "in1", "label": "IN", "port": "input" }],
"outputs": [{ "id": "out1", "label": "OUT", "port": "output" }]
}
}
Layout & Snap Grid
Hold Shift while dragging to bypass the snap grid. The default panel size is 280 × 500 pixels (matches Eurorack-style modules elsewhere in µcor); resize with the corner handle. The Builder remembers up to 50 undo steps.
Audio Nodes
Switch to the Audio tab to wire up the actual signal path. Audio nodes are persisted under blueprint.audio.nodes. Each node has a unique id, a type, and node-specific params.
Allowed types (mapped 1:1 to Web Audio API):
| Type | Web Audio Equivalent | Common Params |
|---|---|---|
gain | GainNode | gain |
biquadFilter | BiquadFilterNode | type, frequency, Q, gain |
oscillator | OscillatorNode | type, frequency, detune |
delay | DelayNode | delayTime |
dynamicsCompressor | DynamicsCompressorNode | threshold, ratio, attack, release |
convolver | ConvolverNode | buffer (impulse response URL) |
waveShaper | WaveShaperNode | curve, oversample |
stereoPanner | StereoPannerNode | pan |
analyser | AnalyserNode | fftSize (used by scope elements) |
Connections
Connections are simple { from, to } pairs referencing node ids. The Builder canvas shows them as wires; you can drag from any output port onto any input port. To target a specific AudioParam, use the dotted form:
{
"audio": {
"connections": [
{ "from": "inputGain", "to": "filter1" },
{ "from": "filter1", "to": "outputGain" },
// CV input modulating cutoff:
{ "from": "cvIn", "to": "filter1.frequency" }
]
}
}
Input / Output Mapping
audio.inputMap and audio.outputMap connect jack ports to audio nodes. Whatever a user plugs into the input jack is routed into the named node; the named output node feeds whatever they connect to the output jack.
"inputMap": { "input": "inputGain" },
"outputMap": { "output": "outputGain" }
Custom Code
The Code tab exposes a JavaScript editor for advanced behaviour: scheduling, generating impulse responses, custom DSP, MIDI handling. Your code runs once when the module is instantiated, with these locals in scope:
audioContext— the sharedAudioContextnodes— map ofid → AudioNodefor everything declared inaudio.nodesparams— reactive object of bound element values (e.g.params.cutoff)setLED(id, on),setDisplay(id, text)— UI helpersonParam(name, fn),onGate(jack, fn)— event hooksdestroy(fn)— register a cleanup callback
// React to the Cutoff knob
onParam('cutoff', (value) => {
nodes.filter1.frequency.setTargetAtTime(value, audioContext.currentTime, 0.01);
});
// Trigger an envelope on gate
onGate('gate', (on) => {
setLED('led1', on);
});
destroy(() => { /* clean up timers, disconnects, etc. */ });
AI Generate
The AI tab is a chat assistant tied to the same multi-model pipeline that powers the Workspace AI. With an empty canvas, type a description and the AI returns a complete blueprint that you can preview before applying.
{
"description": "A warm low-pass filter with cutoff knob, resonance knob, and CV input"
}
Response payload:
{
"blueprint": { /* full blueprint object */ },
"message": "Generated blueprint for \"Warm Low Pass\". Click Apply to load it onto the canvas."
}
AI Refine
Once you have a blueprint loaded, follow-up prompts use /api/builder/ai-refine: the current blueprint is sent along with your instruction, and the assistant returns a modified version. Typical refinement requests:
- "Add a drive knob and a soft-clip stage before the filter."
- "Change the LFO to a triangle wave and route it to cutoff."
- "Add a stereo output and a panner controlled by the second LFO."
Prompt Tips
- Name controls explicitly (“cutoff knob”, not “a knob”).
- Mention ranges where they matter (“LFO from 0.1 to 20 Hz”).
- Describe the signal flow (“input → gain → filter → output”).
- Refine in small steps; the AI keeps your existing structure when possible.
My Modules
Drafts are private to your account. The My Modules picker lists everything you have saved, grouped by recent activity, and lets you open, duplicate, or delete entries.
Save & Preview
- Save Draft stores the current blueprint to
POST /api/builder/modules(orPUTon update). - Preview instantiates the module in a sandbox without exiting the Builder.
- Test on Canvas drops the module into the active workspace so you can patch it against other modules.
Publish
Publishing makes the module available to the registry under the type prefix user_. The publish action calls POST /api/builder/modules/<id>/publish and runs server-side validation: blueprint schema, audio graph reachability, asset paths, and a customCode lint. After it succeeds the module appears in Modules.
To take a module back down, use Builder → My Modules, open it, and choose Unpublish (POST /api/builder/modules/<id>/unpublish).
Asset Uploads
Custom skins, impulse responses, sample WAVs, and SVG knob graphics can be uploaded via POST /api/builder/assets/upload (multipart). The server returns a stable URL of the form /assets/builder/<filename> that you can reference from image elements or pass to convolver.buffer in custom code.
Blueprint Schema
Every module is a single JSON document. This is the default skeleton produced by Builder → New:
{
"meta": {
"name": "New Module",
"type": "user_new_module",
"description": "",
"category": "custom",
"tags": [],
"width": 280,
"height": 500
},
"elements": [],
"jacks": {
"inputs": [{ "id": "in1", "label": "IN", "port": "input" }],
"outputs": [{ "id": "out1", "label": "OUT", "port": "output" }]
},
"audio": {
"nodes": [
{ "id": "inputGain", "type": "gain", "params": { "gain": 1 } },
{ "id": "outputGain", "type": "gain", "params": { "gain": 1 } }
],
"connections": [{ "from": "inputGain", "to": "outputGain" }],
"inputMap": { "input": "inputGain" },
"outputMap": { "output": "outputGain" }
},
"customCode": ""
}
Element Types Reference
Full list as defined in js/module-builder.js:
knob, slider, button_group, toggle, jack_in, jack_out, led, display, label, image, section_box, scope, rotary_switch, keyboard.
Audio Node Types Reference
gain, biquadFilter, oscillator, delay, dynamicsCompressor, convolver, waveShaper, stereoPanner, analyser.
REST API
All Builder endpoints are auth-gated and live under /api/builder/ (proxied to the Flask backend). Bearer token from your µcor session is required.
| Method | Path | Purpose |
|---|---|---|
| GET | /api/builder/modules | List your drafts & published modules |
| POST | /api/builder/modules | Create a new draft |
| GET | /api/builder/modules/<id> | Fetch one module |
| PUT | /api/builder/modules/<id> | Update a draft |
| DELETE | /api/builder/modules/<id> | Delete a draft |
| POST | /api/builder/modules/<id>/publish | Publish to the registry |
| POST | /api/builder/modules/<id>/unpublish | Take a published module down |
| POST | /api/builder/ai-generate | Generate a blueprint from a description |
| POST | /api/builder/ai-refine | Refine an existing blueprint |
| POST | /api/builder/assets/upload | Upload skins / IRs / samples |
Support
Need a hand?
- Browse the Module Index to see how shipped modules are structured.
- Check the FAQ for common Builder questions.
- File issues or feature requests at [email protected].
Ready to Build?
Open the workstation and pick Builder → New to design your first module.
Launch Workstation