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.

Who this is for: Anyone with a µcor account. Basic familiarity with synth modules helps. The optional Custom Code panel uses JavaScript with the Web Audio API.

Opening the Builder

The Module Builder lives inside the workstation. Open it from the top menu bar:

You can also launch it programmatically from the browser console:

Browser ConsoleJavaScript
// 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:

ZonePurpose
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.

TypeNotes
knobContinuous control with min/max/default. Bind to an audio node param via bind: { node, param }.
sliderSame data model as knob, vertical or horizontal.
button_groupDiscrete options. Useful for waveform, filter type, mode.
toggleBoolean on/off (mute, sync, bypass).
jack_in / jack_outVisual jack on the panel. The port wiring is configured in the Jacks Footer, not on the element itself.
ledStatus indicator. Drive it from custom code via setLED(id, on).
displayRead-only numeric or text readout.
label / image / section_boxDecorative. Sections can be coloured to group controls visually.
scopeLive waveform display, taps an analyser audio node.
rotary_switchN-position rotary, like a select but laid out as a dial.
keyboardMini 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:

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 footer (excerpt)JSON
{
    "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):

TypeWeb Audio EquivalentCommon Params
gainGainNodegain
biquadFilterBiquadFilterNodetype, frequency, Q, gain
oscillatorOscillatorNodetype, frequency, detune
delayDelayNodedelayTime
dynamicsCompressorDynamicsCompressorNodethreshold, ratio, attack, release
convolverConvolverNodebuffer (impulse response URL)
waveShaperWaveShaperNodecurve, oversample
stereoPannerStereoPannerNodepan
analyserAnalyserNodefftSize (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:

Connection examplesJSON
{
    "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.

I/O mapJSON
"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:

Custom code (excerpt)JavaScript
// 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. */ });
Sandboxing: Custom code runs in the same context as the workstation, with the Web Audio API and a small whitelisted helper API. There is no DOM access by default. Network calls require explicit user permission.

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.

POST /api/builder/ai-generateJSON
{
    "description": "A warm low-pass filter with cutoff knob, resonance knob, and CV input"
}

Response payload:

ResponseJSON
{
    "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:

Prompt Tips

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

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:

Default blueprintJSON
{
    "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.

MethodPathPurpose
GET/api/builder/modulesList your drafts & published modules
POST/api/builder/modulesCreate 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>/publishPublish to the registry
POST/api/builder/modules/<id>/unpublishTake a published module down
POST/api/builder/ai-generateGenerate a blueprint from a description
POST/api/builder/ai-refineRefine an existing blueprint
POST/api/builder/assets/uploadUpload skins / IRs / samples
All AI endpoints are rate-limited per user and counted against the same quota as the Workspace AI.

Support

Need a hand?

Ready to Build?

Open the workstation and pick Builder → New to design your first module.

Launch Workstation