Object Settings
The settings API lets user code expose a configurable settings panel directly on a node. Call settings.define() with a schema and a gear icon appears — clicking it opens a floating panel with the defined controls.

Supported Objects
settings is available in: js, worker, p5, canvas, canvas.dom, textmode, textmode.dom, three, three.dom, hydra, swgl, dom, and vue.
Basic Usage
await settings.define([
{ key: 'speed', type: 'slider', label: 'Speed', min: 0, max: 10, default: 1 },
{ key: 'color', type: 'color', label: 'Color', default: '#ff6600' },
{ key: 'mode', type: 'select', label: 'Mode', default: 'loop',
options: [
{ label: 'Loop', value: 'loop' },
{ label: 'Ping-pong', value: 'pingpong' },
{ label: 'Once', value: 'once' }
]
}
]);
// Read values synchronously after define() resolves
const speed = settings.get('speed');
const color = settings.get('color');
define() is async — it loads any persisted values before resolving. Always await it before calling get().
API Reference
settings.define(schema)
Defines the settings schema. Opens the settings panel UI. Returns a Promise that resolves once persisted values are loaded.
Call once at the top level of your code. Re-running the code redefines the schema.
settings.get(key)
Returns the current value for a field. Synchronous after define() has resolved.
const opacity = settings.get('opacity'); // number
const label = settings.get('label'); // string
const active = settings.get('active'); // boolean
settings.getAll()
Returns all current values as a plain object.
const { speed, color, mode } = settings.getAll();
settings.set(key, value)
Programmatically updates a setting value from code. The new value is persisted using the field's persistence setting and fires any registered onChange callbacks — so the panel updates in real time.
settings.set('gain', 0.8);
settings.set('mode', 'loop');
Useful for updating settings from received messages or internal computations:
recv((msg) => {
settings.set('gain', msg.value);
});
settings.onChange(callback)
Registers a callback that fires whenever a value changes — either from user interaction in the panel or from a settings.set() call.
settings.onChange((key, value, allValues) => {
console.log(key, value); // changed field
console.log(allValues); // all current values
});
Registering onChange marks the node as active (green border). Callbacks are automatically cleared when code is re-run, so re-registering each run is intentional.
settings.clear()
Resets all settings to defaults and clears persisted values.
Field Types
slider
A range slider. min and max are required.
{ key: 'speed', type: 'slider', label: 'Speed', min: 0, max: 5, step: 0.1, default: 1 }
| Property | Type | Description |
|---|---|---|
min |
number | Minimum value (required) |
max |
number | Maximum value (required) |
step |
number | Step increment (default: 1) |
default |
number | Initial value |
number
A numeric input field.
{ key: 'count', type: 'number', label: 'Count', min: 1, max: 100, default: 10 }
| Property | Type | Description |
|---|---|---|
min |
number | Minimum value |
max |
number | Maximum value |
step |
number | Step increment |
default |
number | Initial value |
boolean
A toggle switch.
{ key: 'loop', type: 'boolean', label: 'Loop', default: true }
string
A text input.
{ key: 'label', type: 'string', label: 'Label', placeholder: 'Enter text...', default: 'Hello' }
select
A dropdown with predefined options.
{
key: 'shape',
type: 'select',
label: 'Shape',
default: 'circle',
options: [
{ label: 'Circle', value: 'circle' },
{ label: 'Square', value: 'square' },
{ label: 'Triangle', value: 'triangle', description: 'Three-sided polygon' }
]
}
Options can also be a plain string array — each string becomes both the label and value:
{ key: 'shape', type: 'select', label: 'Shape', default: 'circle',
options: ['circle', 'square', 'triangle'] }
Option description shows as a tooltip (object form only).
color
A color picker. Value is a hex string (e.g. '#ff6600').
{ key: 'bg', type: 'color', label: 'Background', default: '#000000' }
Optionally provide presets to show a swatch grid above the picker:
{
key: 'palette',
type: 'color',
label: 'Color',
default: '#ff0000',
presets: ['#ff0000', '#00ff00', '#0000ff', '#ffff00']
}
Common Field Properties
All field types share these properties:
| Property | Type | Description |
|---|---|---|
key |
string | Unique identifier, used with settings.get(key) |
label |
string | Display name shown in the panel |
type |
string | Field type: slider, number, boolean, string, select, color |
description |
string | Optional tooltip shown on the label |
default |
any | Default value |
persistence |
string | Where to store the value (see below) |
Persistence
Control where values are stored using the persistence field property:
| Value | Behavior |
|---|---|
'node' |
Saved in the patch file — exported with the patch (default) |
'kv' |
Saved in local IndexedDB — persists across sessions but not exported |
'none' |
In-memory only — resets on page reload |
settings.define([
// Saved with patch — shared when you export or share the link
{ key: 'speed', type: 'slider', label: 'Speed', min: 0, max: 10, default: 1 },
// Local only — your personal preference, not exported
{ key: 'theme', type: 'select', label: 'Theme', persistence: 'kv',
options: [{ label: 'Dark', value: 'dark' }, { label: 'Light', value: 'light' }]
},
// Ephemeral — resets each session
{ key: 'debug', type: 'boolean', label: 'Debug mode', persistence: 'none', default: false }
]);
Reacting to Changes
Use onChange to update visuals or behavior in real time when the user adjusts a setting:
await settings.define([
{ key: 'hue', type: 'slider', label: 'Hue', min: 0, max: 360, default: 180 },
{ key: 'speed', type: 'slider', label: 'Speed', min: 0.1, max: 5, default: 1 }
]);
let hue = settings.get('hue');
let speed = settings.get('speed');
settings.onChange((key, value) => {
if (key === 'hue') hue = value;
if (key === 'speed') speed = value;
});
function draw() {
background(`hsl(${hue}, 80%, 10%)`);
// ...
}
Examples
Canvas — parametric animation
await settings.define([
{ key: 'count', type: 'slider', label: 'Circle count', min: 1, max: 50, default: 12 },
{ key: 'color', type: 'color', label: 'Color', default: '#4488ff' },
{ key: 'speed', type: 'slider', label: 'Speed', min: 0.1, max: 5, default: 1, step: 0.1 }
]);
let { count, color, speed } = settings.getAll();
settings.onChange((_, __, all) => { ({ count, color, speed } = all); });
function draw(ts) {
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = color;
for (let i = 0; i < count; i++) {
const angle = (i / count) * Math.PI * 2 + (ts * 0.001 * speed);
const x = width / 2 + Math.cos(angle) * 150;
const y = height / 2 + Math.sin(angle) * 150;
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI * 2);
ctx.fill();
}
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
Hydra — tunable shader
await settings.define([
{ key: 'freq', type: 'slider', label: 'Frequency', min: 1, max: 60, default: 10 },
{ key: 'sync', type: 'slider', label: 'Sync', min: 0, max: 1, step: 0.01, default: 0.1 }
]);
let freq = settings.get('freq');
let sync = settings.get('sync');
settings.onChange((k, v) => { if (k === 'freq') freq = v; if (k === 'sync') sync = v; });
osc(() => freq, () => sync, 0.8).rotate(0.1).out();
Worker — message-driven with live config
await settings.define([
{ key: 'interval', type: 'number', label: 'Interval (ms)', min: 50, max: 5000, default: 500 },
{ key: 'enabled', type: 'boolean', label: 'Active', default: true }
]);
let interval = settings.get('interval');
let enabled = settings.get('enabled');
let timerId = null;
function startTimer() {
if (timerId !== null) clearInterval(timerId);
timerId = setInterval(() => {
if (enabled) send(Date.now());
}, interval);
}
settings.onChange((key, value) => {
if (key === 'interval') { interval = value; startTimer(); }
if (key === 'enabled') enabled = value;
});
startTimer();
JS — update settings from incoming messages
await settings.define([
{ key: 'gain', type: 'slider', label: 'Gain', min: 0, max: 1, step: 0.01, default: 0.5 },
{ key: 'mode', type: 'select', label: 'Mode', default: 'sine',
options: [{ label: 'Sine', value: 'sine' }, { label: 'Square', value: 'square' }]
}
]);
// Settings panel can be controlled from messages
recv((msg) => {
if (msg.gain !== undefined) settings.set('gain', msg.gain);
if (msg.mode !== undefined) settings.set('mode', msg.mode);
});
// Or from the clock
clock.every('4:0:0', () => {
settings.set('gain', Math.random());
});
Make Settings the Primary Button
Once you've defined a settings panel, the gear icon lives in the overflow menu by default — <code> is what sits in the rightmost slot.
For code-stable patches where you mostly reach for the sliders and rarely the editor, swap them with setPrimaryButton('settings').
After this runs, the gear icon becomes the primary action and Edit code moves into the overflow menu. See JS Integrations for the full setPrimaryButton() reference.
For glsl, use the comment directive instead:
// @primaryButton settings
Notes
define()must be called at the top level of your code (not inside a callback or loop). Re-running the code resets the schema.- The settings panel only appears after
define()is called with a non-empty schema. If the schema is empty ordefine()is never called, no gear icon is shown. - Revert All appears in the panel when any field has a
defaultand the current value differs from it. Clicking it restores all fields to their defaults.
See Also
- JavaScript Runner — Full JSRunner documentation
- Data Storage — General-purpose persistent key-value storage
- Canvas Interaction — Mouse and keyboard events in visual objects