CB Labs

12 — EMBEDDED · 2026

Living Orb

An ESP32-S3 round display rendered as a creature, not a status light: moods that remember, body language, and mitosis when it delegates work.

Built
An animated creature on a round display that reacts to my voice assistant.
Stack
ESP32-S3, a 360×360 round panel, frames pre-rendered on a PC GPU.
State
Done; personality update finished August 2026.

DONE · UPDATED 20 AUG 2026

Personality update finished 12 Aug 2026.

Carter Barnes · cloud engineer, federal Azure · Contact

Photo, AI-assisted edit · The Living Orb. Backdrop and finish regenerated from my photo.

What it is

A round 2.1-inch GC9B72 panel (360×360) on an ESP32-S3, rendering an animated orb that reacts to what my voice assistant is doing. Not a status LED: a character. Fourteen rounds of iteration: the thirteenth was entirely about personality, and the fourteenth made each arm eruption play out differently.

Drawing every pixel live measured about 2.2 µs a pixel: at 30 fps that affords an orb of radius 48 against a design at 96. So the orb is raymarched on the PC's GPU and baked into frames, and the ESP32 composites, grades and moves them at runtime.

How it works

Baked frames
151 frames, the whole assets partition. A random-walk scheduler splices calm, arms and storm segments, so it never plays the same loop twice.
Mood with memory
How it felt a minute ago affects how it looks now. Interaction charges it; silence relaxes it over about six minutes.
Body language
Lean, drift and settle: it perks up on the wake word, flinches on an error and nods while it speaks.
Mitosis on delegate
It divides when work is handed to a sub-agent.
Shapeshift
Form follows what it is doing.
Runtime only
Every personality effect transforms the existing frames, so a change ships as a 30-second firmware upload with no re-bake.

By the numbers

14
rounds of iteration; the thirteenth was all personality
0.87 ×
bake brightness against the reference, up from 0.16×
151
baked frames, the whole assets partition
360×360 px
round GC9B72 panel

What I learned

  1. 01

    Splitting in two says 'delegated' faster than any label

    Mitosis-on-delegate came from watching myself not know whether anything was happening.

  2. 02

    Judge a dark display by numbers, not phone photos

    A phone auto-exposes a near-black orb bright. Three rounds of color work chased photos before a measured composite showed the bake at 0.16× the reference; the fix brought it to 0.87×.

  3. 03

    Instruments lie when the screen is off

    When I ported the orb to Orvyn's wrist puck, the puck's frame-timing readouts kept reporting while its panel was dark, so every puck number taken before 19 Aug 2026 is suspect. If a metric can be produced with the thing under test switched off, it is not measuring the thing under test.

  4. 04

    Logs you compiled out are logs you do not have

    On the puck's build, the framework set the maximum log level to errors at compile time, so every info line in the orb renderer was silently gone. I spent real hours reading an empty console.

What went wrong

  1. 01

    A freeze that blamed the wrong frames

    It was a bus-acquisition race in the display driver. Every freeze landed on logo-morph frames, so the morph looked guilty; it never was. Those frames had the widest stripes, so they lost the race most often.

  2. 02

    The idle frame rate flapped

    At idle it alternated 33 ms and 47 ms frames, which looked worse than a steady 20 fps. The cause was a timing error of up to 1 ms on the panel's sync signal, which tipped frames over the boundary; timestamping the signal in the interrupt fixed it in the same session as the personality round.

Next · 13 / 18Grill IndexA free public API that scores grilling conditions 0–100 anywhere on the map and finds your best window to cook, tuned for charcoal, gas or smoker.