
Claude Mascot ESP32
A 3D-printed Claude mascot powered by ESP32 firmware. Includes a web dashboard, an ST7789 TFT display, and a live GPIO visualizer.
What is it?
A 3D-printed Claude mascot with an ESP32 inside and a TFT display where an animated face lives. It's not a desk figure: it's a physical companion for Claude Code. When Claude Code is waiting for you to approve a tool, the mascot flags it on screen and with a sound; it also shows my Claude Max subscription usage, measures temperature and humidity, serves a web dashboard straight from the microcontroller, and shows live what every GPIO is doing.
Why I built it
I work with Claude every day and wanted it in physical form, but a static figure felt like too little. The trigger was practical: when I launch long tasks in Claude Code and switch windows, the permission prompt sits there waiting without me noticing. I wanted something on the desk that would tell me. From there it became my ESP32 test bench with a face: every new sensor ends up integrated into the mascot.
How it works
Claude Code integration
- Claude Code hooks (
PermissionRequest,PostToolUse,Stop) call HTTP endpoints on the mascot. When approval is requested, the screen switches to "Waiting for approval" with a double beep; once resolved, it shows happy eyes for two seconds and goes back to normal. - The state is resilient: a minimum duration so it never flickers, a 10-minute watchdog in case a hook gets lost, and if a notice (reminder, meeting) borrows the screen, the waiting state is restored afterwards. Bringing a magnet close dismisses it by hand.
- Claude Usage screen: two bars (5-hour window and weekly) with a countdown to the reset, read from a Raspberry Pi using the Claude Code OAuth session, without spending API credits.
Face and notices
- Eyes with random blinking, a sleepy half-blink and lateral saccades; 14 pixel-art expressions (happy, sad, angry, thinking, wink, dizzy...), each with its own jingle.
- Notices that borrow the screen: periodic reminders (drink water, stand up), Google Calendar meetings that the Pi syncs every five minutes, today's weather via Open-Meteo, a pomodoro and a stopwatch.
- TOKENS! easter egg: the ESP32's built-in Hall sensor detects a magnet and triggers a Pac-Man animation eating the letters, with a coin sound.
Dashboard and hardware
- Dashboard at
mascot.local: ambient readings, memory and chip health, retro melodies (Mario, Tetris, Zelda...), brightness, expressions and WAV recording from the microphone. - GPIO visualizer: all 26 DevKit pins live, with direction, level, detected PWM, ADC reading and active function.
- Swarm: one master and up to eight slave ESP32s discovered over mDNS, with OTA from the dashboard and automatic rollback; the face reports flashing progress.
- Multi-agent chat: the Pi orchestrates conversations between Claude agents (master and slaves, each with its own personality) and the mascot paints its turns on the LCD.
Stack
| Layer | Technology |
|---|---|
| Microcontroller | ESP32 DOIT DevKit v1 (ESP-WROOM-32) |
| Firmware | C++ with Arduino on PlatformIO; three environments (master, slave, display test) |
| Display | 2.25" ST7789 TFT (284×76) with LovyanGFX |
| Sensors and audio | BME280 (I²C), MAX98357A amplifier and MEMS microphone (I²S) with double-clap detector, built-in Hall sensor |
| Server | Arduino core WebServer and ESPmDNS, ArduinoJson, NVS for persistence |
| Raspberry Pi | Python: FastAPI proxy, calendar sync under systemd, pytest tests |
| Enclosure | 3D printing |
Status
Active. The mascot sits on my desk and the firmware keeps growing. Next steps:
- Voice activity detection and a wake word using the microphone already installed.
- Make it talk: a TTS pipeline from the Claude API.
- Two-way conversation: listen, transcribe and reply with audio.
Links
- Instagram reel: https://www.instagram.com/p/DYmaB-9sNC0/