Inside your plugin UI
Your plugin interface is a real Svelte app inside your project. The Design Canvas is a visual editor over that source code — and you can edit the same files by hand or let the AI do it.
For plugin makers building and customizing their plugin's interface.
Your UI is just Svelte
There is no proprietary UI format. Your plugin's interface is a small Svelte 5 + Vite app that lives inside your project's ui/ folder, and Patchwerk runs it as a live dev server while you work. The Design Canvas is a window onto that running app — when you drag a knob on the canvas, Patchwerk edits ui/src/Plugin.svelte for you.
That means there are three equally valid ways to change your UI, and they all converge on the same file:
| You do this | What happens |
|---|---|
| Drag, resize, or restyle on the Design Canvas | Patchwerk rewrites the matching element in ui/src/Plugin.svelte |
Edit ui/src/Plugin.svelte in any code editor | The canvas hot-reloads and shows your change |
| Ask the AI for a layout or restyle | It writes the same file with the same conventions |
What lives in ui/
ui/
src/
Plugin.svelte ← your plugin's face — this is the file that matters
App.svelte ← shell that mounts Plugin.svelte and wires DSP bindings
app.css ← global styles
components/base/ ← your editable copies of built-in components
lib/patchwerk/ ← the API that connects UI to the audio engine
vite-plugins/ ← Patchwerk-owned plumbing (don't edit)
vite.config.ts
package.json
Plugin.svelte and anything under components/base/ are yours — edit freely, commit them, refactor them. The vite-plugins/ folder and the bridge files under src/lib/ are infrastructure Patchwerk re-syncs every time you open the project, so hand edits there get overwritten.
How a canvas drag becomes a code edit
Every visual edit runs through two layers:
- Instant preview — the live app's DOM is patched immediately, so the move feels native.
- Authoritative source write — the same edit is applied to
ui/src/Plugin.svelteas a structured code transform, not a blind text replace.
The source file is always the truth. The preview is a fast mirror you can rebuild any time by reloading. A useful rule: if a change would survive a full reload (position, props, text, structure), it was a source edit; if it wouldn't (selection, zoom, panel state), it was just editor state.
Tip
Give every element an id. The canvas finds, selects, and edits elements by their id attribute — anonymous <div>s are invisible to it. Use kebab-case names that say what the thing does: cutoff-knob, filter-section, not div-3.
Binding controls to your DSP
Controls connect to the audio engine through exposed parameters. Expose a parameter on a graph node (via the node's param menu, or ask the AI), then bind it with the dsp prop:
<Knob dsp={{ node: 'filter-1', param: 'cutoff' }} min={20} max={20000} label="Cutoff" unit="Hz" />
<Fader dsp={{ node: 'master', param: 'gain' }} min={-60} max={6} label="Master" unit="dB" />
The control picks up its live value, range, and label from the graph and writes changes straight to the engine. For read-only displays — meters, scopes, spectrum analyzers — bind a telemetry stream instead:
<VUMeter telemetry={{ node: 'vu-meter-1', kind: 'envelopeFollowerLevel' }} />
<Scope telemetry={{ node: 'scope-1', kind: 'scope' }} />
For custom visuals in <script>, the same data is available imperatively: patchwerk.param(nodeId, paramId) gives you a reactive value / set() pair, and patchwerk.telemetry(nodeId, kind) streams engine data at ~60 Hz.
Note
Bindings reference graph node IDs. If you rebuild the graph, old IDs go stale and the knobs silently stop doing anything — re-point your dsp props at the new nodes.
The component library is an eject system
The Components panel offers built-in audio controls — Knob, Fader, XYPad, Keyboard, ADSREditor, FilterResponse, Scope, FFTAnalyzer, VUMeter, and more. Placing one doesn't lock you into a black box: Patchwerk copies its full source into ui/src/components/base/<Name>.svelte and imports that local copy from Plugin.svelte.
That copy is yours. Restyle the knob's arc, change the drag behavior, add a glow — it's plain Svelte in your project. When Patchwerk ships an updated version of a component, untouched copies update in place; if you've modified a file, the new upstream version lands next to it as a .new file so your edits are never clobbered.
Hand-editing and hot reload
Because the UI is a normal Vite app, normal workflows apply. Open ui/src/Plugin.svelte in your editor of choice, save, and the canvas hot-reloads in place — no rebuild, no restart, parameter values intact. Two conventions keep hand edits and canvas edits compatible:
- Inline
stylefor position and size (position:absolute; left:…; top:…; width:…; height:…) — the canvas inspector reads and writes these. - Classes (e.g. Tailwind) for appearance — colors, borders, typography, rounding.
Your UI must fit the plugin's fixed canvas size (set in project settings) — that's the exact window your plugin gets inside a DAW.
Edit mode vs Preview mode
The canvas toolbar switches between two modes:
- Edit — clicks select elements, drags move them, the inspector edits props, and drawing tools (rectangle, frame, ellipse, text) insert new elements. Your controls don't react; you're manipulating the layout.
- Preview — the editor gets out of the way and pointer input goes through to the real UI. Turn the knobs, play the keyboard, and hear the engine respond — exactly what users get in their DAW.
Flip to Preview early and often. It's the fastest way to catch a control that looks right but binds to nothing.