Envelope

An editor for a breakpoint ramp, such as an ADSR shape or an automation curve.

Audio UI

Edits a ramp made of breakpoints, such as an ADSR shape or an automation curve. The registry component wraps the Envelope primitive from @audio-ui/react and draws the points, the segments between them and a grid.

Overview

  • Value: value is a list of { x, y, curve? } points. Both axes are normalized to 0…1, and the points are sorted by x. Map that range to your own unit, such as time or level.
  • Curves: a point's curve, from -1 to 1, bends the segment that leaves it. 0, or no value, draws a straight line. A positive curve holds the start of the segment and steepens its end; a negative curve is its mirror image, rushing the start and holding the end. The bend is the exponential of an analog envelope stage, (e^(k·t) - 1) / (e^k - 1) with k the curve times 11, so neither end turns vertical. The last point has no segment.
  • Pointer: drag a point to move it. Double-click empty space to add a point, or double-click a point to remove it. A point stays between its neighbors, so points never cross.
  • Point count: points are added and removed between minPoints (default 2, a start and an end) and maxPoints. Set both to the same number to fix the shape.
  • Grid: snap sets the grid that points snap to, for example 0.25 for quarters, or one step per axis, { x: 0.125, y: 0 }, to snap across and leave the level free. Hold Cmd/Ctrl to move off the grid. Without snap, points move freely. The registry component draws the grid.
  • Fine control: hold Shift while dragging to move a point at a quarter of the pointer's speed. The registry component shows the point's value above it while it is dragged or focused.
  • Accessibility: the points share one tab stop. The arrow keys move the focused point, and Delete or Backspace removes it. Each point is a role="slider". The registry component names the points "Point n of N". With the primitive, set aria-label and getAriaValueText yourself.

Installation

pnpm dlx shadcn@latest add @audio-ui/envelope

Anatomy

Import the primitive and assemble its parts.

import { Envelope } from "@audio-ui/react";

<Envelope.Root>
  <Envelope.Graph>
    <Envelope.Fill />
    <Envelope.Line />
  </Envelope.Graph>
  <Envelope.Segments>
    <Envelope.Segment />
  </Envelope.Segments>
  <Envelope.Points>
    <Envelope.Point />
  </Envelope.Points>
</Envelope.Root>

Usage

import { Envelope } from "@/components/audio-ui/envelope";

Uncontrolled: set only the initial points.

<Envelope
  defaultValue={[
    { x: 0, y: 0 },
    { x: 0.2, y: 1 },
    { x: 0.6, y: 0.5 },
    { x: 1, y: 0 },
  ]}
/>

Controlled: drive the points from state.

const [points, setPoints] = useState(initialPoints);

<Envelope
  onValueChange={setPoints}
  onValueCommitted={(next, details) => console.log("Committed:", next, details.reason)}
  value={points}
/>

Interaction

Pointer

Behavior · 10

Drag a point
Moves it; x stays between its neighbors and y within 0…1. Dragging never deletes a point. While dragging, the point follows the pointer even if a controlled value updates late.
Double-click empty space
Adds a point at that location, unless at maxPoints. Added on a bent segment it sits on the curve, and each half is bent to keep its shape.
Double-click a point
Removes it, unless at minPoints.
Hold Shift while dragging a point
Moves it at a quarter of the pointer's speed, for fine adjustments. The point does not jump when Shift is pressed or released mid-drag.
Alt + drag a segment
Bends it, like a DAW's automation lane: the segment's midpoint follows the pointer. A flat segment, or a press away from any segment, does nothing.
Alt + double-click a segment
Straightens it, instead of adding a point.
Alt + click a point
Removes it, unless at minPoints.
Drag a segment's handle
Bends the segment: its midpoint follows the pointer up or down. A segment between two points of the same level has nothing to bend.
Double-click a segment's handle
Straightens the segment.
Commit event
onValueCommitted fires when a drag that moved a point ends, and right away for an add or a remove.

A refused add or remove sets data-blocked for a moment on the graph or the point, which the registry styles turn into a short shake.

Keyboard

The points share one tab stop. On the focused point:

Keys · 4

ArrowUp / ArrowDown
Nudge the focused point's y by step
ArrowLeft / ArrowRight
Nudge the focused point's x by step (clamped between neighbors)
Shift + arrow
Nudge by 10 steps
Delete / Backspace
Remove the focused point, unless at minPoints

Each segment has a handle on its curve. The handles share one tab stop:

Keys · 4

ArrowLeft / ArrowRight
Move to the previous or next segment's handle
ArrowUp / ArrowDown
Lift or lower the handle, bending the segment by 5 steps
Shift + arrow
Bend by 50 steps
Delete / Backspace
Straighten the segment

API reference

Root

Groups all parts of the breakpoint envelope and owns its points, each normalized to 0…1 on both axes and kept sorted by x. Points are dragged and nudged with the keyboard; a double click on the Graph adds one and a double click (or Delete) on a Point removes it, within minPoints / maxPoints. Renders a <div> element.

Props · 11

Data attributes · 2

data-disabled
Present when disabled.
data-dragging
Whether a point is being dragged.

Graph

The drawing surface, a 100×100 stretched viewBox: holds Line and Fill, and a double click on it adds a point. Carries data-blocked briefly when adding is refused at maxPoints. Renders a <svg> element.

Data attributes · 3

data-disabled
Present when disabled.
data-dragging
Whether a point is being dragged.
data-blocked
Briefly true after an add was refused at maxPoints.

Line

The envelope curve through the points. Renders a <polyline> element.

Data attributes · 2

data-disabled
Present when disabled.
data-dragging
Whether a point is being dragged.

Fill

The area under the curve. Renders a <polyline> element.

Data attributes · 2

data-disabled
Present when disabled.
data-dragging
Whether a point is being dragged.

Points

Renders one child per point, in x order.

Props · 1

Point

A draggable handle for the point at index, positioned with left/bottom percentages over the Graph. It is a role="slider" on the point's level (y): give it an aria-label. One point at a time is the tab stop; arrow keys move it (Shift for larger steps), Delete or a double click removes it. Carries data-blocked briefly when removal is refused at minPoints. Renders a <div> element.

Props · 2

Data attributes · 4

data-disabled
Present when disabled.
data-dragging
Whether a point is being dragged.
data-blocked
Briefly true after a removal was refused at minPoints.
data-removable
Whether the point can currently be removed.

Registry component

Envelope accepts style props (size, className) plus primitive props from EnvelopePrimitive.Root.Props. aria-label / aria-labelledby name the envelope group.

Value and state

Props · 9

Layout and display

Props · 6

@audio-ui/react/envelope exposes Envelope.Root, Envelope.Graph (the SVG surface; double-click to add), Envelope.Line and Envelope.Fill (the curve and the area under it), Envelope.Points (renders one child per point), Envelope.Point (the draggable handle), Envelope.Segments (renders one child per segment) and Envelope.Segment (the handle on a segment's midpoint, which bends it). Every part accepts a render prop and className / style as functions of state; points expose data-dragging, data-removable, data-blocked, data-disabled and data-index, and segment handles data-dragging, data-flat and data-disabled.

Examples

ADSR with its stages read out

Audio UI

More Shadcn Envelope components

Browse 2 production-ready audio/ui Envelope components for players, mixers, and synth interfaces. These examples use the headless primitives from @audio-ui/react and stay fully compatible with Shadcn Create so radius, color, and typography match your configured theme.

Browse all 2 Shadcn Envelope components for copy-ready layouts, dashboards, and forms built with Tailwind CSS in the audio/ui library.

Built by Ouest Labs, the source code is available on GitHub.
RSS