themeR / themeG / themeB (0–255 each), and used to tint the fallback face. Persists to /sketches/.settings./sketches/.settings.once a sketch is loaded
The hardware
p5-ring runs on a Waveshare RP2040-LCD-1.28 — a Raspberry Pi RP2040 with a 240×240 round LCD and a built-in accelerometer. USB-powered, no batteries, ~$15.
Step 1 — Get the firmware on the device
A new (or freshly wiped) device needs the p5-ring firmware before it can run sketches. This is also how you update later. No driver, no command line, no button-pressing — just Chrome or Edge.
- Download the firmware
.uf2with the button above (it also lives on the Releases page). - Click Put device in update mode. The screen goes dark and the device reappears as a USB drive named
RPI-RP2. - Drag the downloaded
.uf2onto theRPI-RP2drive. It copies across, the device reboots itself, and the firmware is live.
Prefer the old-school way? Hold the BOOTSEL button while plugging in USB to reach the same RPI-RP2 drive — both routes end at the same drag-and-drop. Already running p5-ring? Skip to Step 2.
Step 2 — Run a sketch
Plug p5-ring into a USB-C port. Then:
- Load a sketch — pick an example from the dropdown, or open any
.jsfile from your computer. - Connect p5-ring — pick the device in the browser dialog. You only do this once: the browser keeps the permission grant, so future visits auto-reconnect on page load. Plug-and-replug also re-attaches automatically.
- Push to device — sends the sketch over USB Serial. If you picked a file, it also auto-pushes whenever you save.
The browser shows a live preview at the same 240 × 240 resolution as the device, plus a quick check of anything that might not run on the on-device JS engine.
What you can draw
Shapes
background, fill, stroke, noFill, noStroke, strokeWeight
line, rect, circle, ellipse, triangle, point, arc
text, textSize, textAlign(LEFT | CENTER | RIGHT)
Transforms
translate, rotate, scale, push, pop (stack depth 8)
Helper: centerOrigin() moves the origin to (width/2, height/2).
Math
random, noise (Perlin), map, lerp, dist, constrain, radians, degrees
sin, cos, tan, atan2, sqrt, pow, abs, floor, ceil, round, min, max
Constants: PI, TWO_PI, HALF_PI
Globals you can read
width,height— both 240frameCount— increments every drawn framemillis()— ms since bootaccelX,accelY,accelZ— onboard accelerometer in gthemeR,themeG,themeB— the user's picked accent color (0–255 each). Use infill(themeR, themeG, themeB)to theme with the device.
Rotation behavior
Sketches stay upright by default. To make a sketch gravity-aware (canvas turns with the device so "up" stays up), call autoRotate() in setup(). The built-in tilt example demonstrates this.
Display shape
The LCD is round. The 240×240 corners are invisible. Keep important content within ~110 px of (120, 120).
Hello world
function setup() {}
function draw() {
background(0);
fill(0, 200, 255);
circle(width / 2, height / 2 + sin(frameCount * 0.05) * 30, 80);
}
Paste this into any .js file, open it with "Pick sketch file…", and the preview will animate.
JS dialect quirks
The on-device engine is mJS, a tiny strict subset of JavaScript. Versus p5 web:
- Use
let(notvar).varis auto-rewritten on load, butconstis not supported. - No arrow functions — write
function (x) { return x*2 }. - No classes; use object literals + functions.
- No template literals (
`like ${this}`) — concatenate with+. - No regex, no Promise, no async/await.
- Numbers in
+need an explicitstr()cast. Write"frame " + str(frameCount), not"frame " + frameCount.
The companion's lint catches these before you push.
Performance & errors
- Aim for under ~300 shapes per frame.
- Pre-allocate arrays in
setup(), not indraw(). - Alpha is approximated by blending against the last
background()color — layered translucency does not stack. strokeWeightis clamped to 8.
If a sketch crashes or stalls, the device flashes a red overlay for 3 seconds, persists the error to /sketches/.errors/last.log, and falls back to its built-in animated face. It won't get bricked.
Troubleshooting
- "Device not recognized" or no port listed — unplug and replug. Windows occasionally caches a bad descriptor.
- Companion can't find the port — close any terminal that's holding it, then click "Connect p5-ring".
- Sketch shows nothing / wrong colors — check the Live log for
[VM] ERRORlines. The most recent error is also on the device at/sketches/.errors/last.log.
Serial commands
Anything you can type into the cmd box at the bottom of the Live log. Commands are case-sensitive and terminated by Enter (the companion adds the newline for you). Output lines come back over the same Serial port and show up in the log.
Sketch runner
sketch info— print current runner state in one line:[INFO] active=1 error=0 crc=0x… heap_free=83000. Iferror=1, a second line[INFO] last_error: …follows.sketch list— enumerate built-in examples on the device. Prints[LIST] examples/<name>.js <size>per file, then[LIST] end.sketch use <name>— copy a built-in example over/sketches/current.jsand reload. Argument is just the filename (e.g.sketch use clock.js), or pass an absolute path to load from anywhere on the FS.sketch reload— re-readcurrent.jsfrom flash and runsetup()+draw()again. Useful if a previous error was cleared.sketch off— disable the JS runner and switch to the fallback animated face.sketch on— re-enable the JS runner (also clears any watchdog/parse error state so a broken sketch can retry).eject— alias forsketch reload(kept from the early FatFSUSB design).clean— no-op in this firmware build; reserved for future host-OS dotfile cleanup.
Display + face fallback
These work whenever the fallback face is active. They also work while a sketch is running, but most are harmless overlays.
happy·sad·thinking·listening·surprised·sleeping·speaking·angry·idle·calibrate— force a face state. Replies with[FACE] State -> <name>. calibrate turns the face into an IMU debug overlay (gravity arrow + ax/ay readout).alert <message>— show a 5 s overlay banner. Append|msto override duration:alert hi|10000. Long messages are truncated.bright <0-100>— set LCD backlight via PWM. The RP2040 backlight driver hardcodes the PWM wrap at 100, so values above 100 saturate.0= off,100= full.color <RRGGBB>— set the face accent color (iris, brow, mouth, alert chrome). Hex, optionally prefixed with#. Example:color FFA500for orange. Also exposed to sketches asthemeR/themeG/themeB(0–255 each).
Canvas rotation is no longer a Serial command — sketches own it via autoRotate()/noAutoRotate() in JS. The fallback face always auto-rotates regardless of what the last sketch left configured.
Persistence
bright, color, and any face-state command write /sketches/.settings on the device (a tiny key=value text file). Next boot, the device restores the last brightness, color, and face state automatically.
UPLOAD protocol (advanced)
The companion uses this internally — you usually don't need to type it. Useful for scripting your own pushes from a terminal or other tool.
UPLOAD <path> <byte-count>\n <raw bytes — exactly byte-count of them> \nEND\n
<path>is the on-device path; for sketches use/sketches/current.js. Subdirectories are created if missing.- Replies with
[UPLOAD] OK <n> bytes -> <path>on success, or[UPLOAD] FAIL …on FS error. After a successful write toSKETCH_PATHthe device queues a reload automatically. - The byte-count is mandatory and the body is raw — no escaping — so the host has to know the file length in advance.
Output line prefixes
Every line the firmware emits is tagged so the log is filterable. The companion uses these for the colored log:
[P5-RING]— boot + lifecycle events[LOADER]— filesystem init, default seeding[FACE]— face state transitions, alerts[IMU]— accel reads, rotation transitions[VM]— JS engine: load, errors, watchdog[CMD]— replies to your serial commands[INFO]— replies tosketch info[LIST]— replies tosketch list[UPLOAD]— UPLOAD protocol state
Tips
- The line input above the log is a real raw stream — anything you
type is sent verbatim. So you can paste short test snippets directly
(e.g.
sketch use sensors.js). - To diagnose a stuck sketch, send
sketch info— iferror=1the device has bailed out of the sketch and is showing the fallback face.sketch onretries. - To recover from a sketch that's pegging the watchdog: connect,
send
sketch off, then use the Examples dropdown to load something lighter. bright 0followed bybright 255is a quick visual confirmation that Serial is reaching the device.