Pre-Release — API subject to change

ProControls for p5.js

An open source library of hardware-inspired UI controls for p5.js sketches — faders, rotary knobs, XY pads, step-sequencer grids, VU meters, LED displays, ADSR envelopes, menus, dialogs, and more. Built by David Stein and hosted at procontrols.org. Drop in one script tag, set a style, and your controls wire themselves up — no event handlers, no layout math, no boilerplate. Eight built-in themes (black, stainless, white, brushed, red, blue, yellow, dimpled) plus touch support out of the box.

ProControls.js p5.js 1.9+ MIT License ↗ Live Demo

Getting Started

Load the script file after p5.js, set ControlStyle, create controls in setup(), and call .draw() in draw(). Mouse, wheel, and touch events are wired automatically — no event handlers needed.

HTML setup

<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined&display=block" rel="stylesheet">
<script src="p5.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/dstein-art/proControls4p5js@master/ProControls.js"></script>
<script src="sketch.js"></script>

Minimal sketch

ControlStyle = 'black';  // set before creating controls

let vol, pan, pwr;

function setup() {
  createCanvas(600, 300);
  vol = new AnalogSlider({ x: 40,  y: 50, label: 'VOL' });
  pan = new Dial({         x: 120, y: 60, label: 'PAN' });
  pwr = new AnalogSwitch({ x: 220, y: 80, label: 'PWR', states: ['OFF', 'ON'] });
}

function draw() {
  proControlBackground();  // style-matched background
  // Controls render themselves — no draw loop needed.
}

// No event handlers. No draw loop. Controls self-register and self-draw.

Rebuilding controls at runtime

When recreating all controls (e.g. on a style switch), call proControlReset() first to clear stale registrations. Read current values before rebuilding to preserve them.

function buildControls() {
  proControlReset();              // clear old registrations
  ControlStyle = currentStyle;
  mySlider = new AnalogSlider({ value: mySlider?.value ?? 0.5 });
}

Removing a single control

mySlider.remove(); // deregisters from events; stop calling .draw() to remove visually

Common options (all controls)

Every control inherits these from the ProControl base class.

OptionTypeDefaultDescription
xnumber20Left edge of the control panel in canvas pixels.
ynumber20Top edge of the control panel in canvas pixels.
minnumber0Minimum value of the range.
maxnumber1Maximum value of the range.
valuenumberminInitial value. Writable at any time via ctrl.value = v.
labelstring''Text label drawn on the control panel.
scalestring'linear''linear' or 'log'. Log requires min > 0. Affects dragging, scrolling, and tick labels.
disabledbooleanfalseDraws a translucent overlay and blocks all interaction.
onChangefunctionnullCalled with the new value whenever it changes during interaction.
onReleasefunctionnullCalled once with the final value on mouse/touch release.
themeobject{}Partial theme override merged on top of the active style. See Themes.

AnalogSlider Input

A vertical fader with a draggable cap, optional scale ticks, and a live readout. Drag the cap or scroll the mouse wheel to change value. Double-click the cap to reset to the initial value.

new AnalogSlider(opts)

Options

OptionTypeDefaultDescription
horizontalbooleanfalseWhen true, the fader runs left-to-right instead of bottom-to-top. Default width becomes 180 and default height becomes 44. showScale defaults to false in horizontal mode.
widthnumberauto / 180Panel width. Vertical: auto-sized to fit tick labels when showScale is true. Horizontal: defaults to 180.
heightnumber180 / 44Panel height. Vertical default 180, horizontal default 44.
readoutstring'raw''raw' — numeric value · 'percent' — 0–100% · 'db' — dB relative to max (shows -∞ at min).
decimalsnumber2Decimal places for the 'raw' readout.
showScalebooleantrue / falseDraw tick marks and numeric labels along the track. Defaults true vertical, false horizontal.
stylestring'knob'Visual style — 'knob' (default), 'wheel' (cylinder with scrolling ribs), 'button' (minimal circular cap). Works for both vertical and horizontal orientations. See slider styles below.
showFaderbooleantrueShow or hide the draggable cap. false = display-only meter.
springBackbooleanfalseWhen true, the fader animates back to its initial value after mouse/touch release.
springDurationnumber1.0Seconds for the spring animation to complete.
springDefaultnumbervalueValue to restore on double-click reset (and spring-back target). Defaults to the initial value. Override when the control is rebuilt dynamically to pin the reset point.

Example

editable — changes update the preview
Log scale: Set scale: 'log' with a small positive min (e.g. 0.001) for a perceptually even frequency fader.

Slider styles

Set style on any vertical AnalogSlider to change its visual. Interaction is identical across all styles.

knob (default)
wheel
button

wheel — a cylinder visible through a slot. Ribs scroll with the value position; center notches mark the midpoint. Vertical: horizontal ribs, width defaults to 50px. Horizontal: vertical ribs, full slot is draggable. Scale defaults to off.

button — a minimal thin-groove track with a spherical circular cap. Works in both orientations. Width defaults to 40px and scale defaults to off.


MultiSlider Input

Several AnalogSlider faders arranged side-by-side in a single unit — useful for equalizers, mixer channel strips, or any bank of related faders. A single onChange/onRelease fires whenever any child slider changes, receiving a name → value object covering all sliders at once.

new MultiSlider(opts)

Options

OptionTypeDefaultDescription
slidersobject{}Each key is a slider name/label. The value is either a number (initial value) or an object with per-slider overrides (value, min, max, readout, …).
xnumber20Left edge of the first slider.
ynumber20Top edge of all sliders.
heightnumber180Slider height in pixels (shared by all children unless overridden per-slider).
minnumber0Shared minimum (overridable per-slider).
maxnumber1Shared maximum (overridable per-slider).
readoutstring'raw'Shared readout format — 'raw', 'db', or 'pct' (overridable per-slider).
decimalsnumber2Shared decimal places (overridable per-slider).
scalestring'linear'Shared scale — 'linear' or 'log' (overridable per-slider).
horizontalbooleanfalseWhen true, each child is a horizontal slider and the group stacks them vertically. Default width becomes 180 and default height becomes 44 per slider.
gapnumber4Pixel gap between adjacent sliders.
labelstring''Group label (not drawn — available for identification).
onChangefunctionnullCalled with a { key: value, … } object when any slider changes. Keys are slider labels with spaces and punctuation removed.
onReleasefunctionnullCalled with a { key: value, … } object on mouse/touch release.
stylestring'knob'Shared slider style — 'knob', 'wheel', or 'button'. Can be overridden per-slider.
springBackbooleanfalseWhen true, all sliders animate back to their initial values after release. Can be overridden per-slider.
springDurationnumber1.0Seconds for the spring animation to complete. Can be overridden per-slider.
themeobject{}Shared theme override applied to all children. See Themes.

Properties & methods

Property / methodDescription
.valuesGetter — returns { key: value, … } for all sliders (keys are labels with spaces/punctuation stripped). Setter accepts the same format to update any subset.
.slider(name)Returns the named child AnalogSlider for direct access (e.g. .value, .disabled).
.disabledGetter/setter — propagates to all child sliders.

Per-slider overrides

Pass an object instead of a plain number for any slider to override shared options for that specific channel.

const eq = new MultiSlider({
  x: 20, y: 40, height: 180,
  min: -12, max: 12, readout: 'raw', decimals: 1,
  sliders: {
    '60Hz':  0,           // plain number → uses shared min/max
    '250Hz': 0,
    '2kHz':  { value: 3, theme: { capIndicator: '#ff6600' } }, // object → per-slider overrides
    '8kHz':  0,
  },
  onChange:  v => console.log('eq changed', v),
  onRelease: v => console.log('eq released', v),
});

Example — vertical (default)

editable — changes update the preview

Example — horizontal with a spring-back override on one slider

editable — changes update the preview

RangeSlider Input

A fader with two draggable caps that define a low/high range. Drag either cap independently; caps constrain each other so they never cross. The region between the caps is filled with the accent colour. Scroll-wheel adjusts the cap nearest the cursor. Double-click a cap to reset it to its initial value.

new RangeSlider(opts)

Options

OptionTypeDefaultDescription
x, ynumber20, 20Top-left position.
widthnumber50 (v) / 180 (h)Panel width in pixels.
heightnumber180 (v) / 44 (h)Panel height in pixels.
minnumber0Minimum value.
maxnumber1Maximum value.
valueLownumberminInitial lower handle value.
valueHighnumbermaxInitial upper handle value.
horizontalbooleanfalseWhen true, renders as a horizontal slider. Width/height defaults swap accordingly.
readoutstring'raw'Value format — 'raw', 'percent', or 'db'.
decimalsnumber2Decimal places for 'raw' readout.
showScalebooleantrue (v) / false (h)Draw tick marks and value labels alongside the track.
showFaderbooleantrueDraw the cap handles. Set to false to show only the range fill (display-only mode).
labelstring''Caption drawn at the top of the panel.
onChangefunctionnullCalled with (valueLow, valueHigh) whenever either handle moves.
onReleasefunctionnullCalled with (valueLow, valueHigh) on mouse/touch release.
disabledbooleanfalseDisables interaction and renders a translucent overlay.
themeobject{}Partial theme override. See Themes.

Properties

PropertyDescription
.valueLowCurrent lower value (read/write). Setting it programmatically will not fire onChange.
.valueHighCurrent upper value (read/write).

Example — vertical

editable — changes update the preview

Example — horizontal

editable — changes update the preview

Dial Input

A rotary knob with a 270° arc sweep. Drag up/down or scroll the mouse wheel to turn it. A tooltip shows the live value while dragging. Double-click to reset to the initial value.

new Dial(opts)

Options

OptionTypeDefaultDescription
sizenumber70Square panel size in pixels. Knob, arc, and scale all scale proportionally.
readoutstring'raw'Same as AnalogSlider: 'raw', 'percent', 'db'.
decimalsnumber2Decimal places for the 'raw' readout.
showScalebooleanfalseDraw tick marks and labels around the arc. Increase size if labels clip.
showKnobbooleantrueShow or hide the knob body. false = arc-only display (used by VUDial).
stylestring'classic'Knob visual style — 'classic' · 'rubber' · 'grooved' · 'pointer'. See dial styles below.
springBackbooleanfalseWhen true, the knob animates back to its initial value after mouse/touch release.
springDurationnumber1.0Seconds for the spring animation to complete.

Example

editable — changes update the preview

Dial styles

Set style to choose a knob visual. All styles share the same interaction and arc track — only the knob body rendering changes.

classic (default)
rubber
grooved
pointer

MultiDial Input

Several Dial knobs arranged side-by-side in a single unit. A single onChange/onRelease fires whenever any dial changes, receiving a name → value object. A raised bevel panel frames the group. All dials share options by default; individual dials can override with per-dial objects.

new MultiDial(opts)

Options

OptionTypeDefaultDescription
dialsobject{}Each key is a dial name/label. Value is a number (initial value) or an object with per-dial overrides (value, min, max, style, …).
xnumber20Left edge of the first dial.
ynumber20Top edge of all dials.
sizenumber70Shared dial panel size in pixels (overridable per-dial).
minnumber0Shared minimum (overridable per-dial).
maxnumber1Shared maximum (overridable per-dial).
readoutstring'raw'Shared readout format (overridable per-dial).
decimalsnumber2Shared decimal places (overridable per-dial).
horizontalbooleantrueWhen true (default), dials are arranged in a horizontal row. When false, dials are stacked in a vertical column.
stylestring'classic'Shared knob style — 'classic', 'rubber', 'grooved', 'pointer' (overridable per-dial).
gapnumber4Pixel gap between adjacent dials.
onChangefunctionnullCalled with { key: value, … } when any dial changes. Keys are dial labels with spaces and punctuation removed.
onReleasefunctionnullCalled with { key: value, … } on mouse/touch release.
springBackbooleanfalseWhen true, all dials animate back to their initial values after release. Can be overridden per-dial.
springDurationnumber1.0Seconds for the spring animation to complete. Can be overridden per-dial.
themeobject{}Shared theme override. See Themes.

Properties & methods

Property / methodDescription
.valuesGetter — returns { key: value, … } (keys are labels with spaces/punctuation stripped). Setter accepts same format.
.dial(name)Returns the named child Dial for direct access.
.disabledGetter/setter — propagates to all child dials.

Example — horizontal row (default)

editable — changes update the preview

Example — vertical column with an individual dial override

editable — changes update the preview

Pads Input

XYPad Input

A two-axis drag surface. Click or drag to set X and Y values independently. Fires separate callbacks per axis. Y increases upward to match musical convention. Double-click to reset both axes to their initial values.

new XYPad(opts)

Options

OptionTypeDefaultDescription
widthnumber160Panel width in pixels.
heightnumber160Panel height in pixels.
minX / maxXnumber0 / 1Value range for the horizontal axis.
minY / maxYnumber0 / 1Value range for the vertical axis.
valueX / valueYnumbercenterCurrent X and Y position within the pad's range. Read or set at any time to get or move the crosshair programmatically.
scaleXstring'linear''linear' or 'log'. Log requires minX > 0.
scaleYstring'linear''linear' or 'log'. Log requires minY > 0.
crosshairColorstringtheme accentColor of the crosshair dot and lines.
onChangeXfunctionnullCalled with the new X value when it changes.
onChangeYfunctionnullCalled with the new Y value when it changes.
onChangefunctionnullCalled with (valueX, valueY) when either axis changes.
onReleasefunctionnullCalled with (valueX, valueY) on release.
springBackbooleanfalseWhen true, both axes animate back to their initial values after mouse/touch release.
springDurationnumber1.0Seconds for the spring animation to complete.

Example

editable — changes update the preview

Example — spring back to center

editable — changes update the preview

GridPad Input

A 2-D grid of cells with four modes: toggle flips each cell 0 ↔ 1 on click; percent raises or lowers each cell's 0–1 value while the mouse is held; button treats each cell as a momentary key with press/release callbacks and no stored value; colorselect cycles each cell through a list of colours on each click, with each colour mapped to a semantic value. Optional horizontal and vertical grouping draws a bevel separator every N cells. Double-click the label to reset all cells to their initial values.

new GridPad(opts)

Options

OptionTypeDefaultDescription
x, ynumber0Top-left position.
rowsnumber4Number of rows.
colsnumber4Number of columns.
modestring'toggle''toggle' — click to flip 0/1 · 'percent' — hold to raise/lower · 'button' — momentary press · 'colorselect' — click to cycle through colours.
optionsarray[]colorselect mode only. Each entry is either a colour string ('red', '#ff0000') or an object { color, value } where value is the semantic value returned by onChange. When value is omitted it defaults to the colour string.
cellSizenumber20Pixel size of each square cell.
cellGapnumber2Gap in pixels between cells.
hGroupnumber0Draw a bevel separator every N columns. 0 disables.
vGroupnumber0Draw a bevel separator every N rows. 0 disables.
groupGapnumber4Extra pixels added at each group boundary.
valuesarrayall 0Initial 2-D array [[row][col]]. For colorselect, pass indices or semantic values — both are accepted. Ignored in button mode.
ratenumber0.02Percent change per frame while mouse is held (percent mode only).
labelstring''Label drawn below the grid.
themeobject{}Partial theme override. See Themes.
onChange(values)functionnullCalled with a 2-D copy of values when any cell changes. In colorselect mode the grid contains the semantic value for each cell.
onRelease(…)functionnullToggle/percent: called with values on release. Button mode: called with (row, col) on release.
onPress(row, col)functionnullButton mode only — called with the row and column of the pressed cell.

Interaction — toggle mode

ActionEffect
Click cellFlip value between 0 and 1.

Interaction — percent mode

ActionEffect
Hold left clickRaise value toward 1 at rate per frame.
Hold right clickLower value toward 0 at rate per frame.
Double-click at 0Snap to 1.
Double-click at 1Snap to 0.
Double-click mid-rangeSnap to whichever boundary is closer.

Interaction — button mode

ActionEffect
Press cellCell highlights; onPress(row, col) fires.
ReleaseCell returns to default; onRelease(row, col) fires.

Interaction — colorselect mode

ActionEffect
Left clickAdvance to the next colour in options, wrapping around.
Right clickStep back to the previous colour.
Double-click labelReset all cells to their initial colour (index 0 by default).

Public API

MemberDescription
values (getter)Returns a deep copy of the 2-D values array. In colorselect mode returns semantic values, not indices.
getValue(r, c)Returns the value at row r, column c. In colorselect mode returns the semantic value of the current colour.
setValue(r, c, v)Sets the value at (r, c). In toggle mode snapped to 0/1; percent clamped 0–1; colorselect accepts an index integer.

Example — toggle mode (step sequencer)

editable — changes update the preview

Example — percent mode (velocity matrix)

editable — changes update the preview

Example — colorselect mode

editable — changes update the preview

Selectors Input

Switch Input

An illuminated discrete selector. Two states renders as a rocker toggle — click to flip. Three or more states renders as a vertical button stack — click any slot to select it. The active slot glows with the style's accent color. Double-click any slot or the label to reset to the initial state.

new Switch(opts)

Options

OptionTypeDefaultDescription
statesstring[]['OFF','ON']Array of state labels. 2 entries = rocker. 3+ entries = selector stack.
statenumber0Index of the initially active state.
springDefaultnumberstateState index to restore on double-click reset. Defaults to state. Useful when the control is rebuilt dynamically and you want reset to always target a fixed index.
widthnumber48Panel width in pixels.
heightnumberautoDefaults to 70 for 2-state; states.length × 26 + 20 for N-state.
onChangefunctionnullCalled with (stateIndex, stateLabel) on every click.

Reading state

sw.state            // active index (readable/writable)
sw.states[sw.state]  // active label string

Two-state rocker

editable — changes update the preview

N-state selector

editable — changes update the preview

IconButton Input

A square push button that renders a Material Symbols icon at its centre. Pass any icon name from the Material Symbols Outlined set as the icon option — the font is already included via the page's <link> tag. Supports momentary (default) and toggle modes. An optional text label is drawn inside the button below the icon.

new IconButton(opts)
Material Symbols font required. Add this to your <head>:
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined&display=block" rel="stylesheet">

Options

OptionTypeDefaultDescription
iconstring'star'Material Symbols icon name, e.g. 'play_arrow', 'volume_up', 'settings'. Full list at fonts.google.com/icons.
sizenumber44Width and height of the button in pixels. Both dimensions are equal.
togglebooleanfalseWhen true the button latches on each click, toggling .state between true and false. When false (default) the button fires once per click and does not latch.
statebooleanfalseInitial toggle state. Only meaningful when toggle: true.
iconSizenumberautoIcon font size in pixels. Defaults to round(size × 0.58).
x, ynumber0, 0Canvas position of the top-left corner.
labelstring''Text caption drawn inside the button below the icon.
onClickfunctionnullCalled on release. For toggle buttons receives the new state (true/false); for momentary buttons called with no arguments.
disabledbooleanfalseSuppresses all interaction and draws a disabled overlay.
themeobject{}Partial theme override. See Themes.

Properties

PropertyDescription
.stateRead/write. Current toggle state (true/false). Setting programmatically does not fire onClick.
.iconRead/write. Change the displayed icon at any time.
.disabledRead/write. Disables or re-enables the button.

Example

editable — changes update the preview

Selector Input

A multi-style option selector. Set style to choose the visual style. Scroll wheel and touch work for all styles. Double-click the selection display or the label to reset to the initial option (double-clicking the arrow buttons or gear wheel advances state as normal).

new Selector(opts)

Options

OptionTypeDefaultDescription
optionsstring[]['A','B','C']Array of option labels.
statenumber0Initial selected index into options.
stylestring'rotary'Visual style — 'rotary' or 'arrow'. See style descriptions below.
widthnumber140Total panel width in pixels.
heightnumber40Panel height in pixels.
onChangefunctionnullCalled with (index, label) whenever the selection changes.
onReleasefunctionnullCalled with (index, label) when the mouse/touch is released.
springBackbooleanfalseWhen true, the selection snaps back to its initial state after springDuration seconds.
springDurationnumber1.0Seconds before snapping back when springBack is enabled.
labelstring''Caption drawn below the panel.
disabledbooleanfalseDisables interaction and renders a translucent overlay.
themeobject{}Partial theme override. See Themes.

Properties

PropertyDescription
.stateCurrent selected index (read/write).
.optionsArray of option labels (read/write).

Style — rotary (default)

A mechanical drum-style selector inspired by vintage rotary counters. A display window shows the selected option; the drum's serrated edge is exposed on the right — horizontal ridges scroll as the drum rotates, giving a tactile feel. Adjacent options are visible while scrolling. Drag up/down, scroll wheel, or touch.

Teeth column sizing: width is max(14, round(height × 0.28)) px. The display window occupies the remaining panel width to the left.
editable — changes update the preview

Style — arrow

A compact left/right arrow selector. Pressing either arrow button steps to the adjacent option; the new selection slides into the display window from the direction of travel. Scroll wheel also works.

editable — changes update the preview

TagSelector Input

A multi-select chip panel. Each string in words is displayed as a rounded pill inside a box. Click any pill to toggle its selection; multiple pills can be selected simultaneously. Double-click the label to reset to the initial selection.

new TagSelector(opts)

Options

OptionTypeDefaultDescription
wordsstring[][]Array of strings to display as selectable chips. Each string may contain spaces (multi-word phrases are treated as one chip).
selectedstring[][]Initially selected words. Must be members of words.
widthnumber200Panel width in pixels. Chips wrap to new rows when they exceed this width.
heightnumberautoPanel height. Omit to auto-size to fit all chips. Provide a fixed value to enable vertical scrolling when chips overflow — a thin scrollbar appears automatically and mouse-wheel or drag scrolls the content.
labelstring''Caption shown at the bottom of the panel. Double-click it to reset selection.
onChangefunctionnullCalled with (selectedArray, addedWord, removedWord) on each toggle. Exactly one of addedWord / removedWord is non-null per click; both are null on a label double-click reset.
disabledbooleanfalseDisables interaction and renders a translucent overlay.
themeobject{}Partial theme override. See Themes.

Properties

PropertyDescription
.selectedGetter — returns current selection as string[]. Setter accepts a string[] to programmatically set selection.
.wordsArray of all chip strings (read/write). Reassigning marks layout dirty so chips reflow on next draw.

Example

editable — changes update the preview

SliderSelector Input

A vertical fader that snaps to discrete string options. It looks and behaves like an AnalogSlider — same panel, track, and brushed-metal cap — but instead of a continuous numeric range the slider clicks into one of the provided option strings. Tick marks at each position are drawn to the right of the track, and the active option's tick and label are highlighted in the accent colour. Scroll-wheel steps through options when hovering.

new SliderSelector(opts)

Options

OptionTypeDefaultDescription
optionsstring[][]The ordered list of selectable strings. Index 0 appears at the top of the track, the last index at the bottom.
statenumber0Initial selected index.
stylestring'knob''knob' — brushed-metal rectangular fader cap. 'button' — circular cap with a radial gradient, matching the AnalogSlider button style.
x, ynumber20, 20Canvas position.
widthnumberautoPanel width. Defaults to a size that fits the longest option label with padding.
heightnumberautoPanel height. Defaults to enough vertical space for all options at 22 px spacing (min 80 px).
labelstring''Caption rendered at the top of the panel.
onChangefunctionnullCalled with (index, string) whenever the selection changes during drag or scroll.
onReleasefunctionnullCalled with (index, string) on mouse release.
disabledbooleanfalseDisables interaction and renders a translucent overlay.
themeobject{}Partial theme override. See Themes.

Properties

PropertyDescription
.stateCurrent selected index (read/write).
.valueGetter — returns options[state] as a string. Setter accepts a string and updates state to its index (no-op if not found).
.optionsThe options array (read/write). Reassign to change the available choices; update .state if needed.

Interaction

GestureEffect
Drag capMoves the cap; snaps to the nearest option tick as you drag.
Scroll wheelSteps one option up or down when hovering over the control.

Example

editable — changes update the preview

Panel Container

A clipping container that groups ProControls into a positioned, optionally scrollable surface. Controls added with .add() are positioned relative to the panel's top-left corner — a slider at (10, 10) appears 10px from the panel edge, not the canvas edge. When child controls extend beyond the panel bounds, thin scrollbars appear automatically; the scroll wheel pans the view when no child control is hovered.

Constructor options

OptionTypeDefaultDescription
x, ynumber20, 20Panel top-left position on the canvas.
widthnumber300Panel width in pixels.
heightnumber200Panel height in pixels.
visiblebooleantrueInitial visibility. Set panel.visible = false to hide the panel and suppress all child events.
labelstring''Title shown in a bar at the top of the panel. When set, the scrollable content area starts below the bar and a minimize/maximize button appears on the right side of the bar. No title bar is shown when empty.
minimizedbooleanfalseInitial minimized state. When true the panel starts collapsed to just the title bar.
minimizablebooleantrueWhen false the −/+ toggle button is hidden and the panel cannot be collapsed.
movablebooleantrueWhen false dragging the title bar does not reposition the panel.
resizablebooleanfalseWhen true a resize grip appears in the bottom-right corner; drag it to change the panel's width and height at runtime.
onChangefunctionnullCalled with a { fieldName: value, … } snapshot object whenever any child control's value changes. See onChange / values below.
onReleasefunctionnullCalled with the same snapshot object when the user releases a child control.
themeobject{}Partial theme override. See Themes.

Methods & properties

NameDescription
.add(control)Attach a ProControl to the panel. The control is removed from the global registry and managed by the panel from that point on. Returns this for chaining.
.onChangeCallback fired with the full { fieldName: value, … } snapshot whenever any child changes. Can be set at construction or assigned later.
.onReleaseCallback fired with the same snapshot when the user releases any child control. Can be set at construction or assigned later.
.valuesRead-only getter. Returns a fresh { fieldName: value, … } snapshot of every child control's current value — same object shape as the onChange and onRelease arguments. Useful for polling the panel state without setting up a callback.
.visibleGet/set panel visibility. When set to false the panel and all children stop drawing and receiving events.
.minimizedGet/set minimized state. When true the panel collapses to only the title bar; the small −/+ button in the title bar also toggles this.
.minimizableRead/write. Hides the toggle button and disables collapse when false.
.movableRead/write. Prevents title-bar dragging when false.
.resizableRead/write. When true, a grip appears in the bottom-right corner allowing the user to drag-resize the panel.
.scrollX / .scrollYCurrent scroll offset in pixels. Read or write to programmatically scroll the panel.

onChange / onRelease / values

When onChange or onRelease are set, the panel listens to every child control and fires the respective callback — with a single snapshot object — on change or release. The same object is always available via panel.values.

Field names are derived from each control's label option with spaces and punctuation stripped (e.g. "Low Cut"LowCut). Controls without a label are named by class and a per-class counter: the first unlabelled AnalogSlider becomes AnalogSlider1, the second AnalogSlider2, and so on. MultiSlider and MultiDial follow the same rule — the slider/dial keys within their own values object also have spaces and punctuation stripped from the label.

Values per control type:

ControlValue in snapshot
AnalogSlider, Dialnumber
SwitchCurrent state label string (e.g. "On")
Selector, SliderSelectorSelected option string
MultiSlider, MultiDial{ name: value, … } object
GridPad2-D array of cell values
TagSelectorArray of selected tag strings
RangeSlider{ low, high }
XYPad{ x, y }
IconButtonboolean state
Markup, Menu, VUMeter, LEDMeter, ADSRDisplayomitted

Note: set any per-control onChange callbacks before calling panel.add(). Callbacks assigned after add() will work for the individual control but the panel notification will wrap the value that was set at add-time.

Scrolling

Scrollbars appear automatically when children extend beyond the panel boundaries. The scroll wheel scrolls the panel when the pointer is over the panel but not over a focused child control. If a child control (e.g. a Dial) is hovered, the scroll wheel is forwarded to that child instead. You can also drag the scrollbar thumbs directly.

Example — onChange

Example — grouped controls

Example — scrollable content


MessageDialog Container

A self-sizing, movable dialog that displays a formatted text message and optional action buttons. The message string is word-wrapped to fit the dialog width. Buttons are arranged in a single row at the bottom; if multiple buttons are provided the dialog widens automatically to fit them all on one line. Drag the title bar to reposition.

new MessageDialog(opts)

Options

OptionTypeDefaultDescription
messagestring''The text to display. Use \n for explicit line breaks. Long lines are wrapped automatically to fit the dialog width.
buttonsstring[][]Button labels shown in a row at the bottom of the dialog. Omit or pass an empty array for a message-only dialog.
x, ynumber20, 20Canvas position.
widthnumberautoDialog width. Defaults to at least 220 px or wide enough to fit all buttons on one row, whichever is larger.
labelstring''Title bar text. When set a styled title bar is shown at the top and the dialog can be repositioned by dragging it.
movablebooleantrueWhen false the dialog cannot be dragged.
onButtonfunctionnullCalled with (index, label) when a button is clicked.
disabledbooleanfalseDisables interaction and renders a translucent overlay.
themeobject{}Partial theme override. See Themes.

Properties

PropertyDescription
.messageRead/write. Reassigning triggers a layout rebuild on the next draw so the dialog resizes to fit the new text.
.buttonsRead/write. Reassigning the array rebuilds the button row on the next draw.
.movableRead/write. Toggle whether the dialog can be dragged at runtime.

Example

editable — changes update the preview

InputDialog Container

Extends MessageDialog with a single-line text input field between the message and the buttons. Clicking the input field captures keyboard events for typing, cursor movement, and editing. The cursor blinks and the text scrolls horizontally when the value overflows the field width. Pressing Enter fires onSubmit; clicking outside the field removes focus.

new InputDialog(opts)

Options

OptionTypeDefaultDescription
messagestring''Instructional text above the input. Supports \n and auto word-wraps.
inputValuestring''Initial text in the input field.
inputPlaceholderstring''Greyed hint text shown when the field is empty and unfocused.
buttonsstring[][]Button labels in a row at the bottom.
x, ynumber20, 20Canvas position.
widthnumberautoDialog width. Defaults to at least 220 px or wide enough to fit all buttons.
labelstring''Title bar text. When set the dialog can be dragged.
movablebooleantrueWhen false the dialog cannot be dragged.
onButtonfunctionnullCalled with (index, label) when a button is clicked.
onSubmitfunctionnullCalled with the current inputValue string when Enter is pressed.
disabledbooleanfalseDisables all interaction.
themeobject{}Partial theme override. See Themes.

Properties

PropertyDescription
.inputValueRead/write. The current text in the field. Reassign to change it programmatically.
.inputPlaceholderRead/write. Hint text shown when the field is empty and unfocused.
.messageRead/write. Reassigning triggers a layout rebuild on the next draw.
.buttonsRead/write. Reassigning rebuilds the button row on the next draw.

Keyboard interaction

KeyEffect
Printable charactersInserted at the cursor position.
Backspace / DeleteRemoves the character before / after the cursor.
/ Moves the cursor one character.
Home / EndJumps to the start or end of the text.
EnterFires onSubmit(inputValue).

Example

editable — changes update the preview


Displays

Read-only meters and display panels. Assign .value (or individual properties) each frame to drive them — no event wiring required.

VUMeter Display

Extends AnalogSlider. Overlays a segmented LED column (green → yellow → red) with peak hold on top of the fader track. Drive it each frame by assigning .value from audio analysis.

new VUMeter(opts)
Inherits all AnalogSlider options. Defaults overridden: readout: 'db', showScale: false, min: 0, max: 1.

Additional options

OptionTypeDefaultDescription
segCountnumber20Number of LED segments.
meterWidthnumber8Pixel width of the LED column.
colorLowstring'#00cc44'Segment color for the lower 60%.
colorMidstring'#cccc00'Segment color for 60–85%.
colorHighstring'#cc2200'Segment color for the top 15%.
showFaderbooleantruefalse = hide the fader cap entirely for a pure display meter.

Example

editable — changes update the preview

VUDial Display

Extends Dial. Replaces the filled arc with a ring of segmented LEDs with peak hold. Use showKnob: false for a pure meter ring, or true to show both the set position and the live level.

new VUDial(opts)
Inherits all Dial options. Defaults overridden: readout: 'db', showScale: false, min: 0, max: 1.

Additional options

OptionTypeDefaultDescription
segCountnumber24Number of LED arc segments.
colorLowstring'#00cc44'Color for the lower 60%.
colorMidstring'#cccc00'Color for 60–85%.
colorHighstring'#cc2200'Color for the top 15%.
showKnobbooleantruefalse = pure LED ring with no knob body.

Example

editable — changes update the preview

LEDMeter Display

A 7-segment numeric display. Segments are drawn as beveled hexagons with a canvas glow. Values are right-aligned; if the number is too wide for the digit slots, all segments show -----. Assign .value each frame.

new LEDMeter(opts)

Options

OptionTypeDefaultDescription
digitsnumber5Number of digit positions (including sign).
readoutstring'raw''raw', 'percent', or 'db'. dB clamps at −99 at min.
decimalsnumber2Decimal places. The dot is drawn in the gap between digits — no extra slot needed.
digitWnumber14Width of each digit character in pixels.
digitHnumber26Height of each digit. Segment thickness scales with this.
digitGapnumber4Gap between digits. Decimal point is centered here.
ledColorstringnullLED color. null uses theme.capIndicator.

Example

editable — changes update the preview
Panel width = padding×2 + digits×digitW + (digits−1)×digitGap. With defaults a 5-digit meter is 106 px wide.

ADSRDisplay Display

A display-only ADSR envelope graph inside a beveled panel. The envelope shape updates live whenever any property changes — pair it with dials or sliders to visualise synth parameters in real time.

new ADSRDisplay(opts)

Options

OptionTypeDefaultDescription
x, ynumber0Top-left position of the panel.
widthnumber220Panel width in pixels.
heightnumber120Panel height in pixels.
attacknumber0.1Attack time — any consistent unit (seconds, ms, etc.). Relative to decay and release.
decaynumber0.2Decay time.
sustainnumber0.7Sustain amplitude level, 0–1.
releasenumber0.3Release time.
envelopeColorstringnullLine and fill tint. null uses theme.capIndicator.
labelstring''Label drawn below the panel.
themeobject{}Partial theme override. See Themes.

Visual layout

Attack, Decay, and Release are displayed proportionally across 70% of the plot width. The sustain hold occupies the remaining 30% as a fixed visual segment. A, D, S, R labels appear below each segment; dashed dividers mark the phase boundaries.

Example

editable — changes update the preview

Markup Display

A scrollable text panel that renders a subset of Wiki Markup syntax — headings, bold, italic, bullet and numbered lists, indented blocks, horizontal rules, and links. Set text at any time to update the content; the panel re-parses and scrolls to the top automatically.

new Markup(opts)

Options

OptionTypeDefaultDescription
x, ynumber0Top-left position of the panel.
widthnumber280Panel width in pixels.
heightnumber200Panel height (visible viewport) in pixels.
textstring''Wiki Markup source. Can be set at any time.
fontSizenumber12Base font size in pixels. Headings scale relative to this.
paddingnumber10Inner padding on all sides.
lineSpacingnumber1.5Line-height multiplier applied to fontSize.
onClickfunctionnullCalled on any click inside the panel. Receives the link's URL string when a link is clicked, or null when clicking non-link text.
themeobject{}Partial theme override. See Themes.

Properties

PropertyTypeDescription
textstring (get/set)Current markup source. Setting resets scroll to top.
scrollYnumber (get/set)Current vertical scroll offset in pixels. Clamped to valid range automatically.

Wiki Markup syntax

SyntaxRenders as
= Heading 1 =Large heading with underline rule
== Heading 2 ==Medium heading
=== Heading 3 ===Small heading
'''bold'''Bold text
''italic''Italic text
'''''bold italic'''''Bold italic text
[[label]] or [[url|label]]Link text (rendered in accent color)
* itemBullet list item
** itemSub-bullet list item
# itemNumbered list item
## itemSub-numbered list item
: textIndented block with left bar
----Horizontal rule
(blank line)Paragraph gap

Scrolling

When content is taller than the panel, a thin scrollbar appears on the right edge. Scroll with the mouse wheel while hovering the panel. Set scrollY programmatically to jump to any position.

Example

editable — changes update the preview

ConsolePanel Display

A floating, scrollable log panel that intercepts console.log, console.warn, console.error, and console.info calls as well as uncaught runtime errors and unhandled promise rejections. Messages are color-coded by type, timestamped, and always auto-scroll so the most recently added line is visible at the bottom. Consecutive identical messages (same type and text) are collapsed into a single entry showing the repeat count and the most recent timestamp — e.g. [12:04:31 ×5] redraw tick. A CLR button clears the log; a −/+ toggle minimizes the panel to just its title bar. The panel is movable, resizable, and minimizable by default.

new ConsolePanel(opts)

Options

OptionTypeDefaultDescription
x, ynumber20, 20Canvas position of the panel's top-left corner.
widthnumber400Panel width in pixels.
heightnumber200Panel height in pixels.
labelstring'Console'Text shown in the title bar.
movablebooleantrueWhen false the panel cannot be repositioned by dragging.
resizablebooleantrueA resize grip appears in the bottom-right corner; drag it to resize the panel at runtime.
minimizablebooleantrueA −/+ toggle button appears in the title bar; clicking it collapses the panel to just the title bar.
minimizedbooleanfalseInitial minimized state.
maxMessagesnumber100Maximum number of messages retained. Oldest messages are dropped when the buffer is full.
timestampsbooleantruePrefix each message with a [HH:MM:SS] timestamp. Set to false to suppress.
interceptstring[]['log','warn','error','info']The console methods to intercept. Pass a subset to limit capture, e.g. ['error','warn'].
themeobject{}Partial theme override. See Themes.

Properties & methods

NameDescription
.clear()Clears all messages and resets scroll. Same as clicking the CLR button.
.messagesRead-only getter. Returns a shallow copy of the message array. Each entry is { type, text, time, count }; count is ≥ 1 when consecutive identical messages have been collapsed.
.remove()Removes the panel and restores all intercepted console methods to their originals.
.minimizedGet/set. When true the panel collapses to just the title bar.
.labelRead/write. Text shown in the title bar.
.resizableRead/write. Enables or disables the resize grip at runtime.
.minimizableRead/write. Shows or hides the minimize toggle button.
.movableRead/write. Enables or disables title-bar dragging at runtime.

Message colors

SourceColor
console.logTheme label color (default text)
console.infoTheme accent / indicator color
console.warnAmber #cc8800
console.error / uncaught errorsRed #dd3333

Interaction

GestureEffect
Drag title barRepositions the panel (when movable is true).
Click −/+ buttonMinimizes or restores the panel (when minimizable is true).
Scroll wheelScrolls the message log. The next incoming message will always snap back to the bottom.
Drag scrollbarScrolls by dragging the thin scrollbar on the right edge (visible when content overflows).
Click CLR buttonClears all messages.
Drag resize gripResizes the panel from the bottom-right corner (when resizable is true).
Console passthrough: intercepted methods still call the original browser console functions, so DevTools output is unaffected. Call .remove() to fully restore the originals.

Example

editable — changes update the preview

TimeGraphPanel Display

A scrolling time-series line graph panel. Push data points each frame to plot them against time — the oldest point scrolls off the left edge as new ones arrive on the right. Pass a plain number to plot a single variable, or an object ({key: value, …}) to plot multiple named variables simultaneously, each drawn in its own color with a legend. Y-axis range is auto-scaled to the data with 8% padding, or fixed by setting min and max. The panel is movable, resizable, and minimizable by default.

new TimeGraphPanel(opts)

Options

OptionTypeDefaultDescription
x, ynumber20, 20Canvas position of the panel's top-left corner.
widthnumber360Panel width in pixels.
heightnumber200Panel height in pixels.
labelstring'Time Graph'Text shown in the title bar.
maxSamplesnumber200Maximum number of data points retained. Oldest points are discarded when the buffer is full.
autoAdjustYbooleantrueAutomatically fit the Y axis to the min/max of the data currently in the buffer. Set to false to use fixed min/max bounds instead.
minnumber0Fixed Y-axis minimum. Only used when autoAdjustY is false.
maxnumber1Fixed Y-axis maximum. Only used when autoAdjustY is false.
lineWidthnumber1.5Stroke weight for data lines in pixels.
gridbooleantrueShow horizontal grid lines at 25%, 50%, and 75% of the Y range.
legendbooleantrueShow a color legend in the top-right corner of the plot (only visible when graphing multiple variables).
movablebooleantrueAllow repositioning by dragging the title bar.
resizablebooleantrueShow a resize grip in the bottom-right corner.
minimizablebooleantrueShow a −/+ toggle button to collapse the panel to just the title bar.
minimizedbooleanfalseInitial minimized state.
themeobject{}Partial theme override. See Themes.

Properties & methods

NameDescription
.push(value)Add a data point. Pass a number for single-variable mode, or a plain object ({key: value, …}) for multi-variable mode. Switching between modes resets the data buffer.
.clear()Remove all data points and reset variable tracking.
.autoAdjustYGet or set whether the Y axis auto-fits to the data range (true) or uses fixed bounds (false).
.dataRead-only getter. Returns a shallow copy of the current data array.
.minimizedGet/set. Collapses the panel to just the title bar when true.
.visibleGet/set. Hides the panel and suppresses events when false.

Example — single variable

Example — multiple variables


Themes & Styles

Set ControlStyle before creating controls. The style is captured at construction time, so controls built before a change keep their original look.

ControlStyle = 'brushed'; // before any new controls

Built-in styles

black
cyan accent
stainless
navy accent · polished chrome texture
white
red accent
brushed
orange accent · sine-wave grain
dimpled
blue accent · dimpled circle texture
red
yellow accent
blue
yellow accent
yellow
red accent · dark text

proControlBackground()

Use instead of p5's background(). Fills the canvas with the style color. 'brushed' and 'stainless' also draw per-row texture overlays via the native Canvas 2D API.

StyleTexture
blackFlat fill — #1a1a1a.
stainlessGaussian highlight profile: sharp specular band near the top third, soft secondary reflection below center, edge darkening, and a thin pure-white specular line at the peak.
whiteFlat fill — #e8e8e8.
brushedThree layered sine-wave frequencies (fine grain, visible stroke bands, slow tonal drift) plus a directional sheen band — simulates brushed aluminum.
dimpledBrushed aluminum base with a grid of small dimpled circles (12 px spacing) — each dot has a dark outer ring and a lighter inner highlight. Blue accent.
redFlat fill — #cc0000. Primary red background, darker red controls, yellow accent.
blueFlat fill — #0000cc. Primary blue background, darker blue controls, yellow accent.
yellowFlat fill — #e0d000. Warm yellow background, golden controls, red accent · dark text.

Runtime style switching

Rebuild controls with proControlReset() when switching styles. The Live Demo uses an AnalogSwitch to cycle all four styles.

const STYLES = ['black', 'stainless', 'white', 'brushed', 'dimpled', 'red', 'blue', 'yellow'];
const LABELS = ['BLACK', 'STEEL', 'WHITE', 'BRUSH', 'DIMPL', 'RED', 'BLUE', 'YLW'];
let currentStyle = 'black';

function buildControls() {
  proControlReset();
  ControlStyle = currentStyle;
  mySlider    = new AnalogSlider({ value: mySlider?.value ?? 0.5 });
  styleSwitch = new AnalogSwitch({
    states: LABELS,
    state:  STYLES.indexOf(currentStyle),
    label:  'STYLE',
    onChange: i => { currentStyle = STYLES[i]; buildControls(); },
  });
}

Per-control theme overrides

Pass a partial theme object to override individual color keys while keeping the rest of the active style.

KeyAffects
panelPanel background fill.
panelStrokePanel border and knob outline.
trackSlider groove / dial arc background.
capHighlightTop gradient color of the fader cap or knob.
capShadowBottom gradient color of the fader cap or knob.
capIndicatorAccent line / filled arc color / LED glow color.
scaleTextScale label text color.
scaleTickScale tick mark color.
labelControl label text color.
readoutReadout value text color.
readoutBgReadout pill background.
hoverGlowHover highlight fill (include alpha).
disabledOverlayOverlay when disabled: true.
fontp5 font object from loadFont(). null = canvas default.
new Dial({ label: 'MASTER', theme: { capIndicator: '#ffcc00' } });

Touch & Events

All mouse, wheel, touch events, and rendering are handled automatically by the library. No event functions and no draw loop are needed in your sketch. touch-action: none is applied to the canvas automatically to prevent iOS scroll conflicts.

Nothing to wire up. Just create controls — they start receiving events and drawing themselves immediately. Call .remove() when done.

How it works

Each control self-registers on construction into a shared array. Two p5.prototype.registerMethod hooks handle everything: a 'pre' hook fires at the start of every frame to dispatch mouse/wheel/touch events; a 'post' hook fires at the end of every frame and draws any control that wasn't already drawn explicitly that frame. This means you can still call c.draw() manually for z-order control — the post hook simply skips controls already rendered.

Coexisting with your own handlers

Registered library methods and sketch-level event functions both fire independently — they don't conflict. You can still define mousePressed() in your sketch for other logic.

Multi-touch: p5.js maps only the first touch to mouseX/mouseY, so only one control can be manipulated at a time. Two-finger gestures are unaffected.