Envelope Editor
envelope-editorControlsA 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.
default — loose pieces, bring your own panel
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-editorPulls in
First time? Add the registry to your components.json once:
{
"registries": {
"@syntho-ui": "https://engine.syntho.app/r/{name}.json"
}
}Usage
Controlled or uncontrolled, whichever suits the surrounding state.
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
| Prop | Type | Default | Description |
|---|---|---|---|
| value | { attack, decay, sustain, release } | — | Controlled envelope. Omit for uncontrolled operation. |
| defaultValue | ADSR | { 0.01, 0.2, 0.6, 0.4 } | Starting envelope when uncontrolled, and the reset target. |
| onChange | (value: ADSR) => void | — | Fires on every edit. |
| onChangeEnd | (value: ADSR) => void | — | Fires once when a gesture finishes. |
| ranges | EnvelopeRanges | — | Per-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. |
| frame | boolean | false | Wrap 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. |
| displayHeight | number | 160 | Height of the envelope display in pixels. The compact variant defaults it to 104. |
| knobVariant | KnobVariant | "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. |
| hideKnobs | boolean | false | Hide 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
sliderandswitchroles with livearia-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.