Envelope Editor

envelope-editorControls

A worked example of composing the kit rather than a new control. The shape on top is the envelope display, the row underneath is four knobs, and both edit the same value: drag a handle and the knobs follow, turn a knob and the shape follows. Neither child owns the state — the editor does, and hands each a controlled value.

50 ms
300 ms
60%
900 ms

default — loose pieces, bring your own panel

50 ms
300 ms
60%
900 ms

frame + variant="compact" — the little black box

Drag a handle and the knobs follow; turn a knob and the shape follows. Both editors edit the same value.

Install

Copies the source into your project. Anything it depends on comes with it.

$ npx shadcn add @syntho-ui/envelope-editor

Pulls in

First time? Add the registry to your components.json once:

components.json
{
  "registries": {
    "@syntho-ui": "https://engine.syntho.app/r/{name}.json"
  }
}

Usage

Controlled or uncontrolled, whichever suits the surrounding state.

example.tsx
import { EnvelopeEditor } from "@/components/ui/envelope-editor"

<EnvelopeEditor
  defaultValue={{ attack: 0.01, decay: 0.2, sustain: 0.6, release: 0.4 }}
  onChange={(adsr) => voice.setEnvelope(adsr)}
/>

Props

PropTypeDefaultDescription
value{ attack, decay, sustain, release }Controlled envelope. Omit for uncontrolled operation.
defaultValueADSR{ 0.01, 0.2, 0.6, 0.4 }Starting envelope when uncontrolled, and the reset target.
onChange(value: ADSR) => voidFires on every edit.
onChangeEnd(value: ADSR) => voidFires once when a gesture finishes.
rangesEnvelopeRangesPer-segment bounds, shared by the display and the knobs. Defaults: A/D 1 ms–4 s, S 0–1, R 1 ms–8 s.
variant"default" | "compact""default"Layout preset. Compact shrinks the module: ~104 px display, mini knobs, tighter gaps, and a fixed four-column knob strip that never wraps. Explicit displayHeight/knobVariant still win.
framebooleanfalseWrap the editor in a framed panel — surface fill, hairline border, themed radius, tight padding — so it reads as one self-contained module, with the display recessed like a window.
displayHeightnumber160Height of the envelope display in pixels. The compact variant defaults it to 104.
knobVariantKnobVariant"small"Size preset passed through to the four knobs. The compact variant defaults it to mini.
knobIndicator"line" | "dot""line"Marker style passed through to the knobs.
hideKnobsbooleanfalseHide the knob row, leaving just the draggable shape.

Interaction

  • Drag with pointer capture, so the gesture keeps tracking past the edge of the control.
  • Shift while dragging for a fine pass; release it mid-gesture and coarse tracking resumes.
  • Double-click resets to defaultValue.
  • Arrow keys step normally, Shift+arrow steps finely, PageUp/PageDown jump by ten, Home/End go to the extremes.
  • Proper slider and switch roles with live aria-valuetext, so a screen reader announces the formatted value rather than the raw number.
  • The scroll wheel adjusts the value while the pointer is over the control; stepped ranges move at least one declared step per notch by default.