A VUMeter is a vertical bar meter — the kind you see on a mixing console or
audio interface. The bar rises and falls to show a signal level in real time. You drive it
from your sketch code by setting its value property (0–1 by default) in your
draw() loop.
Create a VUMeter with no options and it appears at a sensible default size. The
value property controls how high the bar is — 0 is empty, 1 is full.
The example below animates the level using sin() so you can see it move.
x and y,
ProControls places the control automatically so it does not overlap others.
Use label to add a text label, peak to show a hanging peak
indicator dot that falls slowly after the signal drops, and segments to
split the bar into discrete blocks (like a classic LED meter). Try changing these!
Use warnAt to set where the bar turns yellow, and dangerAt
to set where it turns red — both as fractions of 0–1. This lets you mark the
"safe zone," the "caution zone," and the "clip zone" visually, just like a
real mixing board.
Creating two VUMeters next to each other makes a classic stereo pair. Give each one
an explicit x and y so they sit side by side. Drive them
independently for a true left/right display.
A VUDial is a circular level indicator — like the large needle meters
on vintage studio gear. An arc sweeps from low to high as the value increases.
Set value from your draw() loop just like VUMeter.
A one-liner creates a circular meter. The arc sweeps around the dial as the value changes. Watch the arc respond to the animated value below.
The size option controls the diameter. You can add a label,
set warnAt and dangerAt thresholds for color changes,
and show a numeric readout with readout: 'raw'.
By default the dial goes from 0 to 1, but you can set min and max
to any range — for example, decibels from −60 to 0. The readout will show the mapped value,
not the raw 0–1 fraction.
In a real project you would drive the meter from audio analysis or a sensor reading.
Here we simulate a signal with noise to show how a responsive meter looks.
Use smoothing (0–1) to add ballistic lag so the needle does not jump instantly.
smoothing is available on both VUMeter and VUDial.
A value around 0.8–0.9 gives the classic "needle ballistics" feel of analog meters.
A LEDMeter is a horizontal bar of discrete LED segments — the kind of level meter you see on a guitar tuner or effects pedal. Unlike VUMeter, it always displays as distinct blocks and is usually wider than it is tall.
A one-liner creates a horizontal bar of LED segments. Set value (0–1)
from your sketch to light up segments from left to right.
Use segments to control how many LEDs the bar is divided into.
More segments means finer resolution. The width and height
options control the overall size of the bar.
Stack several LEDMeters vertically to create a channel strip or a multi-band display.
Position them with explicit y values so they line up neatly.
In practice you feed the LEDMeter from a computed number — the amplitude of an audio signal, the speed of a physics object, or anything that changes over time. Here a ConsolePanel shows the raw value alongside the meter.
An ADSRDisplay draws an Attack–Decay–Sustain–Release envelope shape — the classic four-parameter curve used in synthesizers to shape how a sound evolves over time. It is a read-only visual; pair it with four dials or sliders to let the user edit the envelope values.
Create an ADSRDisplay with default values and it shows a classic envelope shape.
The four properties are attack, decay, sustain,
and release — all 0–1 fractions of their maximum time.
Set width and height to fit the display in your layout.
The label option adds a title. The curve automatically fills
the available space.
The classic use case: four dials control the ADSR shape. In the onChange
of each dial, update the matching property on the ADSRDisplay.
The display redraws automatically.
You can update the ADSR properties from anywhere in your sketch — not just from a dial callback. Here the sustain level pulses slowly to show how the display responds to programmatic changes.
A Markup control displays styled text — paragraphs, bold, italic, links, and separators — rendered on the canvas. Use it for help text, status readouts, or any formatted copy that belongs inside your ProControls layout.
Pass a string to the text option. Plain text is displayed as-is.
The panel auto-sizes to fit its content.
Wrap text in **double asterisks** for bold and *single asterisks*
for italic. A line containing only --- becomes a horizontal rule that
separates sections.
Add a link with [label](url) syntax. Clicking a link opens the URL
in a new tab by default. You can override this with the onClick(href)
callback to handle the link yourself.
Set the text property at any time to update what the Markup panel displays.
This is useful for status readouts that should update as your sketch runs —
for example, showing the current frame rate or a sensor value.
text
only every few frames (e.g. frameCount % 10 === 0) to avoid unnecessary redraws.
A ConsolePanel displays text log output directly on the canvas —
replacing console.log() output that would otherwise only appear in the
browser's developer tools. New lines appear at the bottom and scroll up as the
panel fills.
Create a ConsolePanel and then call console.log() anywhere in your
sketch. ProControls intercepts the call and shows the output in the panel.
You can still see the output in the browser console too.
Set width and height to control the panel size.
The maxLines option caps how many lines are kept before older ones
are dropped. You can also set movable: false to lock the panel
in place so users cannot drag it around.
The most common pattern is to log values in onChange callbacks so you
can see what a control is doing as you interact with it. The ConsolePanel gives you
that feedback without switching to the browser's developer tools.
Call console.clear() to empty the panel, or use
log.clear() directly on the ConsolePanel instance.
Logging from draw() works, but throttle it (e.g., every 15 frames)
so the panel does not scroll too fast to read.
A TimeGraphPanel draws a scrolling time-series graph — like an
oscilloscope or a heart-rate monitor. Push new data points with push(value)
and the graph scrolls left to show the history. You can plot multiple series
on the same panel in different colors.
Create a TimeGraphPanel, then call push(value) every frame (or as often
as you have new data). The graph auto-scales to fit the values you push.
Set min and max to fix the vertical range (instead of
auto-scaling). The gridLines option draws horizontal reference lines,
and label adds a title to the panel.
Push data to named series to plot several lines on the same graph. Pass an object
to push() where each key is a series name and the value is the new data point.
Each series gets its own color automatically.
A TimeGraphPanel paired with a control lets you visualize how a value changes as the user interacts. Drag the slider below and watch your movements recorded in the graph as a live trace.
graph.clear() to reset all series, or
set graph.history (number of data points to keep) to control how far
back the graph scrolls.
By default each push() call is stamped with the current wall-clock time.
You can override this by including a time field (in seconds) in the data
object. This lets you replay pre-recorded data at the correct positions, graph sporadic
events that don't arrive every frame, or synchronize multiple graphs to a shared
timeline.
{ time: millis() / 1000, value: v } so the X axis reflects the
actual elapsed time between samples rather than frame count.
A StatusPanel is a real-time performance meter showing frame rate, frame time, control count, and JavaScript heap memory. It's perfect for monitoring your sketch during development — spot performance bottlenecks, watch how many controls you've created, and ensure your draw loop stays responsive at 60 FPS.
Create a StatusPanel with no options — it anchors to the bottom of
the canvas by default and shows live FPS, frame time (Δt in milliseconds),
active control count, and available heap memory.
Provide x and y to place the panel anywhere on the
canvas. Set width and height to control its size.
When you specify position, it no longer auto-resizes with the canvas.
The Δt (delta time) metric shows average frame time in milliseconds. For 60 FPS,
target is ~16.67ms. If Δt turns red and climbs above that, your draw()
loop or event handlers are doing heavy work. Watch the Controls
counter — it increments with each control you add.
Set status.visible = false to hide the panel without destroying it.
Turn it back on with status.visible = true. This is useful for hiding
debug overlays in production code or toggling the monitor on demand.
status.visible = true for debugging when needed.
A ListView displays a scrollable list of strings. Click any item to select it;
use the scroll wheel or scrollbar to navigate. The onSelect callback fires when
a row is clicked, passing the item and its index.
lv.items to update the list.
Use lv.selectedIdx to get or set the selection programmatically.
A GridView displays a scrollable table where each row is an object with named fields. Column widths are automatically computed from the header names and cell values. The header row stays fixed at the top (no vertical scroll). Horizontal scrolling is available when columns exceed the panel width. Click a row to select it.
gv.items with new data to update the grid.
Column headers are automatically derived from the object keys. Use gv.scrollX
and gv.scrollY to programmatically control scrolling.
A HeatMapView displays a grid of colored cells representing hierarchical data grouped by multiple dimensions.
Each cell's color intensity reflects the magnitude of its aggregated value. Click any cell to drill down one level; use
breadcrumbs at the top to jump back to earlier drill levels, or right-click to pop back one level.
When you reach the deepest dimension, clicking a cell fires the onSelect callback with the full drill path.
fields array defines the drill-down hierarchy. Start with product, then brand, then trim.
The valueField specifies which property to sum at each level. Reassign hm.items with new data to update the heatmap.
Use the breadcrumb bar to navigate, or right-click any cell to pop back one level.