Lab

knob

The knob's controller from @audio-ui/core: a bounded value on a dial, turned by a vertical, circular or revolving drag, stepped, scrolled, typed and reset, and the geometry of its arcs.

pnpm add @audio-ui/core
import { createKnobController, ANGLE_GAP_RAD, ARC_OUTER_RADIUS, arcPath, CENTER_DEAD_ZONE_MIN_PX, /* … */ } from "@audio-ui/core/knob";
Adapters@audio-ui/react/knob, @audio-ui/elements/knob
ExportKindWhat it is
createKnobControllerfunctionA knob's behavior with no view attached: its value, held or controlled, every way of turning it, and what it looks like as a snapshot.
KnobChangeEventDetailstypeWhat onValueChange receives with each change: the reason, the event behind it, and cancel() to refuse the change.
KnobChangeEventReasontypeWhy the value changed: "drag", "keyboard", "wheel", "input-change" (a typed value) or "reset".
KnobCommitEventDetailstypeWhat onValueCommitted receives once a gesture ends: the reason and the event behind it.
KnobCommitEventReasontypeWhy the value was committed: the same reasons as a change.
KnobControllerinterfaceWhat createKnobController returns: the snapshot to draw from, and the press, keys, wheel, typed value and reset that turn it.
KnobDragModetypeHow a drag turns a knob: up and down, around its centre, or by the turns of the pointer.
KnobOptionsinterfaceThe options of createKnobController: the value, held or controlled, its range, scale, steps and anchor, the drag mode, the formatting and the callbacks.
KnobSnapshotinterfaceWhat a view draws a knob from.
ANGLE_GAP_RADconstGap at the bottom of the dial: the sweep runs clockwise from bottom-left to bottom-right.
ARC_OUTER_RADIUSconstOuter edge of the arcs in the viewBox; each stroke is centered inside it.
arcPathfunctionSVG arc along the dial between two normalized positions (0…1).
CENTER_DEAD_ZONE_MIN_PXconstThe smallest the hub's dead zone may be, in px, however small the knob.
CENTER_DEAD_ZONE_RELconstCircular drag: inside this fraction of the diameter the angle is synced but not accumulated, so crossing the hub doesn't jump.
DEFAULT_ARC_STROKE_WIDTHconstThe width of the track and indicator arcs in the 48 by 48 view box, unless given.
DOUBLE_TAP_MAX_MSconstThe longest two taps may be apart, in ms, to count as a double tap and reset the value.
FINE_DRAGconstHolding Shift turns the knob this much slower than the pointer moves.
LARGE_POSITION_STEPconstWith a scale that is not linear, a large step (Shift or Page Up and Down) moves this share of the travel.
LINEARconstThe linear scale, resolved once.
POSITION_STEPconstWith a scale that isn't linear, a key or wheel notch moves this share of the travel.
pointerAnglefunctionThe angle of a pointer around the centre of rect, in radians, 0 pointing right.
START_ANGLEconstRotation at min, in degrees clockwise from 12 o'clock.
STATE_ATTRIBUTES_MAPPINGconstdisabled, dragging and the drag mode become data attributes; the numbers stay in state.
SWEEP_ANGLEconstRotation travelled from min to max, in degrees.
steppedValuefunctionThe value direction steps away from current: by step (or largeStep) on a linear scale, by a share of the travel on any other, and always by at least one step.
TAP_MAX_MOVE_PXconstA press that moves less than this is a tap; two quick taps reset the value.
VERTICAL_DRAG_RANGE_PXconstVertical drag: pointer travel, in px, for the whole min…max range.
VIEWBOX_CENTERconstCenter of the 48×48 viewBox the arcs are drawn in.
WHEEL_DELTA_EPSILONconstA wheel movement smaller than this is ignored.

Usage

The controller follows the contract every controller shares: create it once, draw from its snapshot, send it the input.

import { createKnobController } from "@audio-ui/core/knob";

const knob = createKnobController({ min: 20, max: 20000, value: 1000, scale: "log", format: { maximumFractionDigits: 0 } });
OptionMeaning
value, defaultValue, min, max, step, largeStepAs for the fader
scale"linear", "log", or a function between 0 and 1
dragModeHow a drag turns into a value: "vertical", "circular" (the angle around the centre) or "revolution" (the turns of the pointer)
anchorThe value the arc grows from, such as 0 on a pan knob
format, locale, disabledAs for the fader

A knob resets on a double tap and on Alt with a press, inside the controller: it has no reset gesture in the element. press(event, control) takes the control, the element that gives the angle; keyDown(event) returns true when it handled the key. The snapshot has the angle of the pointer, the percent and the anchorPercent, ready for an arc.

A vertical drag covers the whole range over 150 px (VERTICAL_DRAG_RANGE_PX), and Shift turns it four times slower (FINE_DRAG). On a scale that is not linear, a key or a wheel notch moves 1% of the travel (POSITION_STEP), so a log knob steps as evenly as it looks; steppedValue is that rule as a function.

Drawing the dial

The dial sweeps 288 degrees (SWEEP_ANGLE), clockwise from the bottom left, with its gap at the bottom. arcPath(radius, from, to) is the SVG arc between two positions from 0 to 1 in its 48 by 48 view box, and pointerAngle the angle of a pointer around the centre of an element.

The Knob draws this controller in React.

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