Design modern interfaces for instruments and effects, on the web or in native DAWs. Customizable controls and themes powered by the Maru Audio platform.
Audio and MIDI File Drag Card shared by module faces and application hosts.
Host-controlled play/pause, seekable waveform and time display.
Pure peak decoding and waveform geometry.
Audio Clip Wave Layer shared by module faces and application hosts.
Clarence Barlow's stratified meter decomposition — assigns a metric weight to every rhythmic position in any time signature. Drives density control, humanization, syncopation measurement and onset probability weighting for generative sequencers.
The layout for a bars-across, dB-DOWN plot, as pure maths: beat and seconds-at-a-tempo mappings across the time axis, bar/beat/subdivision tick enumerations, a one-sided dB axis with 0 dB pinned at the top and reduction drawn downward, gutter labels that print the axis floor as -∞ rather than a number, and a clamped ceiling line for a hard budget. The x axis is piano-roll-geometry's — built on the same createLaneLayout and pinned against it in the tests — so a beat grid, a drum lane and a piano roll place beat 3 at the same fraction of their plot. The dB axis is restated rather than reused because response-geometry's is a symmetric ±range around a centred zero, which is the right shape for a filter curve and the wrong one for gain reduction. No React, no DOM — testable in Node and safe to lay out on the server.
A dynamics scope's chrome: a bars-across grid with bar lines heavier than beats and an optional sixteenth grid, a dB gutter reading downward from 0, a dashed hard-ceiling line with its own label (dashed because a budget is a limit, not a measurement), a playhead, and beneath the plot a strip of event lanes drawn as onset ticks at their exact beat — so a swung event visibly sits off its gridline — sharing the plot's own xForBeat, with the playhead continuing through them. It draws no signal itself: `children` is a render function handed the resolved layout, so a prediction envelope, a measured overlay and a waveform all live in the SAME coordinate space as the grid and cannot disagree about where a beat is. The playhead is either given as a phase (null draws none, which is the right picture for a stopped transport) or derived from a host transport through useBeatClock, whose source is reported back so the caption can distinguish host-locked from free-running. SVG, no measurement, renders on the server.
Canonical shadcn and Base UI button used by portable controls and website aliases.
Reusable molded artwork with controlled state and headless input.
Portable control-level MIDI CC menu and binding editor: assign a controller number and channel by right-clicking a control, then edit range, response curve, learn, or remove. The existing badge and drag-drop source strip remain optional paths through the same `midi` callbacks.
One reusable frame for custom controls: parameter-path resolution, drag target, activity state, editable badge, and the shared MIDI context menu.
The scoped ownership ledger used by nested MIDI-aware control frames so exactly one wrapper registers a parameter target.
Drag a MIDI CC source onto a control to bind it: a dependency-free pointer-capture drag protocol with rect hit-testing, an equivalent keyboard path (Enter to pick up, arrows to choose, Enter to drop), drop-target registration, the assignment badge and the drag ghost.
A row of MIDI CC chips you can turn and reorder. Turning is the ordinary knob gesture; reordering starts from a separate grip handle and works with pointer or arrow keys.
Every MIDI CC mapping of a host as one grouped list: by module or rack instance, with a by-CC sort, search and filters. Rows show the CC, input and channel, target, range and live activity, with Learn, Pick control, enable and remove; opening a row gives CC, channel and range, and Advanced adds input, value mode, takeover, curve and invert. Import, export, reset and clear are callbacks; the list keeps only view state.
The MIDI CC chips you drag onto a control to bind it: the mod wheel first, then the expressive controllers, then a numeric picker for the other hundred-odd numbers. Each chip is draggable by pointer, assignable from the keyboard, and pulses when its controller sends traffic.
The host's one toast for a hardware controller that moved but is not mapped: the source and channel, a live value, a chip you drag straight onto a control, Pick control (click or arrow keys and Enter) and Ignore. It never takes focus, fades after the control goes quiet, and guides any source-first pick. Every edit goes through the shared CC drag controller, so drops into sandboxed face frames work too.
The maths of a vibrating plate as pure functions: the 2D standing-wave equation, a frequency-to-mode heuristic for a modelled steel plate, and the amplitude-weighted random walk that makes particles settle on the nodal lines. No canvas, no DOM — so the same physics drives a canvas, a WebGL renderer, or a Node test.
Nodal patterns for a set of frequencies — the figure sand draws on a driven metal plate. Either a particle simulation finding the nodes over time or the standing wave as a field, on a square or circular plate. Parameter-driven, so it needs no audio source.
How the chords in a progression connect, as a shared-pitch-class network: an edge between every pair sharing a note, weighted by how many. A chart tells you the order chords arrive in; this tells you why one slides into the next and another lands like a cut — so you can see which substitutions are available before trying them.
Controlled twelve-column chord map with a shared piano roll, palette bands, activity trail, tension indicators and per-column seed controls. Hosts own chord generation and playback.
Everything analysis can say about what is sounding, in one card: the chord symbol with its alternatives, note names and the raw set encoding, the Forte set class, the interval-vector chart inline, and a self-consonance meter. The symbol answers what you are playing; everything below answers why it sounds like that. Chord naming is dependency-free — a ranked search over a quality dictionary that reads inversions from the bass note.
A pitch-class histogram plotted on the wheel where neighbouring slots are a fifth apart, so the seven notes of any key form one unbroken arc and a modulation is a short slide round the rim. An optional needle points at the tonal centre, its length and opacity scaled by confidence so an ambiguous passage never gets a decisive-looking answer.
The ramps every display paints magnitude with and the two wheels a harmony display paints pitch with, as pure functions. The ramps are the real multi-stop scientific colormaps from d3-scale-chromatic (viridis, magma, inferno, plasma, cividis, turbo), tabulated once into 256-entry lookups, plus grayscale and heat. The pitch wheels give each pitch class a hue by semitone or by circle-of-fifths position, measured from a tonic so a key keeps its colours when transposed; drawn on a pad layout, the wheel whose hues run smoothly across the pads is the relationship that layout makes visible.
Controlled compact grain artwork with shared gestures.
All authored custom knob studies and their shared headless wrapper. Silent visual source, with no product DSP or assets.
The QWERTY keyboard as a MIDI controller. Keyed on physical key position (event.code) so the layout survives AZERTY and Dvorak, with a text-field guard, held-key sustain, spacebar panic and browser-shortcut passthrough.
The plain buttons of a console face on Base UI's Button and Toggle: ConsoleButton (text with an optional console icon), ConsoleIconButton (a square icon-only button named by its label, which is also its tooltip) and ConsoleToggle (aria-pressed on/off with an accent border when pressed). Three heights read from the face's --uikit-control-h-sm|md|lg variables (24, 28, 32px by default, 44px on a touch face), four variants (ghost, outline, primary, subtle), an optional ConsoleTooltip with a shortcut, and focusableWhenDisabled so a busy or refused button keeps focus with aria-disabled. Hover, focus and pressed colours come from its own hoisted stylesheet, with transitions only under prefers-reduced-motion: no-preference.
Shared scoped CSS for molded tempo controls.
The small stroked glyphs the console controls and module faces share (transport, disclosure, add and remove, dice, menus, help, mute and solo) as one ConsoleIcon component on a 16-unit grid, drawn in currentColor and aria-hidden, so a die in a seed slot and a die in a face header are the same die.
The interaction states of the compact console controls as one small stylesheet, rendered through ConsoleStyles, which React 19 hoists into the document head and dedupes: hover washes, focus rings, pressed segments with a 3:1 edge, seed-slot actions revealed on hover or focus (always on touch), the mode menu rows, the active tab, with every transition behind prefers-reduced-motion. Also the control heights (sm 24, md 28, lg 32) read through --uikit-control-h-sm|md|lg via consoleHeight(), the value fill token (--uikit-value) and a visually-hidden style.
An on/off switch sized for a console row on Base UI's Switch (role switch, aria-checked, a hidden form input, Space and Enter toggle it): a control-height hit area around a 28 by 16px track, outlined and muted when off, filled with the accent when on, with no true/false text. focusableWhenDisabled keeps a refused switch in the tab order with aria-disabled. Colours from its own hoisted stylesheet, motion only under prefers-reduced-motion: no-preference.
A short visual label for a console control on Base UI's Tooltip, opening after a short hover delay and at once on keyboard focus, closing on Escape, blur or pointer leave. The child element itself is the trigger through Base UI's render prop, so it wraps any button without an extra element. The popup portals into the fullscreen element while a face is in browser fullscreen, carries the face's theme variables and an optional shortcut, stacks at --uikit-z-overlay, and fades only when motion is allowed.
How well notes agree, as pure functions — two models side by side: a 12-TET interval table for the answer a musician would give, and Plomp-Levelt roughness plus harmonic coincidence for the answer a cochlea would give. On top sit the pieces a UI needs: interval-class vectors, voice-leading smoothness, chord self-consonance, fitting notes to a weighted pitch-class context, and the min-max luminance banding that turns clustered scores into a readable brightness ranking.
Which of the twelve notes fit what is sounding now — a playing aid, not an analysis. Each pitch class is shaded by how well it agrees with a blend of the held chord and the tonal field the piece has established, so a note belonging to both glows brightest. The same maths the reference hardware lights its strum-bar LEDs with, including the min-max normalisation that turns narrowly-clustered consonance scores into a ranking you can actually read.
Portable context-menu actions for module faces and controls on Base UI's ContextMenu (right-click and touch long-press) and the ContextMenu key or Shift+F10, plus ActionMenu: the same menu opened from a button, the ellipsis in a card header. Both run on one Base UI Menu engine and one row renderer (check column, label, a right-aligned hint such as a shortcut or a size, submenu arrow, optional separators, and non-interactive readout rows for a figure such as a code size). Fields keep the browser's own menu. Both portal into the fullscreen element while a face is in browser fullscreen and stack at the --uikit-z-overlay token.
Two minimal monochrome SVG dials: a solid disc with a cut-in notch and an outlined circle with a matching inward pointer.
An independently importable minimal SVG dial using shared headless interaction and section-scoped accent colors.
An independently importable minimal SVG dial using shared headless interaction and section-scoped accent colors.
Value formatters for parameter readouts — Hz with a k-suffix, dB with a silence floor, pan as L/C/R, percentages and choices.
A shared caption/readout wrapper with optional bounded text fitting, narrow typography and ellipsis inside a designer-owned width.
Clamping, normalisation and step quantisation shared by every control, plus the SVG arc helpers the knob draws with.
The kit's shared visual vocabulary: the skins every control understands (default, flat, vintage, minimal, neon), the traits behind them, the helpers that turn a trait into a cap fill, an accent fill, a glow or a row of tick positions, and the provider that lets a panel declare its finish once for everything inside it.
The CSS custom property contract every control reads, with rich defaults and a few ready-made skins.
A delay's echo train on a time axis: a muted reference pip for the dry hit, then one pip per repeat at the moment it arrives and the height it arrives with, fading as well as shrinking so the tail stays readable. Two lanes turn it into a ping-pong view — left grows up from the midline, right grows down, and the first repeat's side comes from the shipped graph rather than from the display. Supply a tempo and it draws the beat grid the repeats are landing on, or missing.
How a developer actually reaches the diagnostic panel: right-click the face, or press Ctrl/Cmd+Shift+D. It owns everything the panel deliberately does not — whether the panel may be shown at all, the context menu (Open diagnostics / Copy runtime report / Reset counters), the resizable drawer docked right or bottom, the per-viewer tab and placement preferences, and the session's open/close lifecycle, so a closed panel costs nothing on the audio thread. The drawer is portalled into the face surface and absolutely positioned, so opening it never reflows the face. Right-clicks on text-editing islands, on module-owned [data-context-menu="browser"] targets and inside nested module context menus keep their own menu.
The eleven-tab developer view of a running plugin: Overview, Host, Transport/Clock, MIDI, Audio, Parameters, Presets/State, Events, Stimulus, Performance and Package. Controlled and presentational — it takes a DiagnosticSession and its snapshot and renders them, owning no bridge and opening no feed, so it embeds equally in a drawer, a dev-runner pane or a docs page. Its one editorial rule is that every value either comes from the snapshot or renders as an explicit Unreported cell: there is no `?? 0` anywhere, because a host that never reported its latency is not a host with zero latency, and a meter frame that never arrived is not silence. The stereo verdict consults per-channel RMS before correlation for the same reason — a silent pair correlates at exactly 1.0, and would otherwise be reported as perfect mono. The Overview leads with a status strip whose health verdict overrides a host's own claim when the feeds it promised have gone silent, because a dead feed is a broken host bridge however healthy the DSP says it is; Copy report puts a ten-line plain-text summary on the clipboard ahead of the JSON, because that is what gets pasted into chat. Nothing costs a frame while the panel is closed: the four canvas viewers share one animation frame that is never scheduled unless the Audio tab is visible, each tab is memoised over the slice of the snapshot it reads, and tables past 200 rows render only the band you can see.
Scoped frosted blue materials and procedural disc artwork.