| .gitignore | ||
| README.md | ||
| spudface.py | ||
| spudface.service | ||
SpudFace 🥔
Procedural robot eyes for Raspberry Pi — Cozmo/Vector-style expressive face on a 7" touchscreen.
What it is
A lightweight Python/Pygame app that renders an animated robot face with two expressive eyes, a little potato sprout antenna, and text-to-speech. Controlled via JSON command file.
Features
- 10 moods: neutral, happy, thinking, sad, excited, sleeping, cool, confused, angry, dead
- Smooth transitions between expressions (parameter interpolation)
- Automatic blinking at random intervals
- Idle pupil wandering when neutral/thinking
- Heart eyes for love mood (circle bumps + triangle)
- Speech bubbles with large readable text
- Antenna sprout with gentle bob animation
- Happy bounce animation on excited moods
- Sound effects: tap click, poke boop, blink soft tone, happy chirp
- Text-to-Speech via gTTS (Google) — multiple accents, auto-speaks messages
- Mute toggle — 5 min mute, kills TTS, clears message queue
- Poke button — writes to
poke.jsonfor external integration - Face tap look — pupils follow where you tap (all moods)
- Fullscreen or windowed mode (via env vars)
- Header/footer with name, mood, time, wifi, CPU status
Quick Start
# Install dependencies
pip install pygame gtts
# Run (fullscreen on Pi display)
python3 spudface.py
# Or windowed (for desktop testing)
SPUDFACE_WINDOWED=1 python3 spudface.py
Controlling SpudFace
Write JSON to /run/user/1000/spudface/cmd.json:
{
"mood": "happy",
"say": "Hey there!",
"say_duration": 10,
"speak": true,
"status": "Online"
}
Fields
| Field | Default | Description |
|---|---|---|
| mood | — | Expression name (see below) |
| say | — | Text for speech bubble (auto-clears) |
| say_duration | 15 | Seconds to show message |
| speak | true | Auto-TTS speak the message |
| status | — | Bottom status bar text |
From OpenClaw (Spud agent)
echo '{"mood":"happy","say":"Hi!","say_duration":5}' > /run/user/1000/spudface/cmd.json
Supported Moods
| Mood | Description |
|---|---|
| neutral | Default, idle state with wandering pupils |
| happy | Wide eyes, squint, raised brows — triggers bounce |
| thinking | One-sided lookup, angled brows |
| sad | Droopy lids, inner brows up |
| excited | Big wide eyes, high brows — triggers bounce |
| sleeping | Nearly closed eyes, relaxed |
| cool | Half-lidded, slight smirk brows |
| confused | Different-sized pupils, angled brows |
| angry | Narrowed eyes, steep brow angle |
| dead | Flat line eyes, no pupils |
Touch Buttons (bottom bar)
| Button | Action |
|---|---|
| 📱 Poke | Writes poke.json, shows "Poked!", plays boop sound |
| 🕐 Time | Shows current time and date |
| 🔇/🔊 Mute | Toggles 5-min mute — kills TTS, clears queue, shows icon |
Face Tap Zones
- Eyes area: surprised blink + exclamation
- Mouth area: random quip (from built-in list)
- Other face: pupils track your touch position
TTS / Voice
SpudFace speaks messages aloud via gTTS (Google Text-to-Speech).
Supported accents: en (US), en-uk (British), en-au (Australian), en-in (Indian), nl (Dutch), + 50+ languages.
To change default accent, edit _generate_voice() in spudface.py.
Mute: When muted, messages still show on screen but don't speak. Tap mute again to unmute after 5 minutes (or it auto-expires).
Antenna
A little green potato sprout with:
- Curved stem that bobs gently
- Two triangular leaves
- Red berry on top with highlight
Bounce animation lifts the whole face when happy/excited.
Architecture
OpenClaw (Spud) → /run/user/1000/spudface/cmd.json
↓
spudface.py (Pygame loop, 30 FPS)
↓
7" touchscreen
Environment Variables
| Variable | Default | Description |
|---|---|---|
SPUDFACE_WINDOWED |
— | Set to 1 for windowed mode |
SPUDFACE_WIDTH |
800 | Window width |
SPUDFACE_HEIGHT |
480 | Window height |
SPUDFACE_CMD_FILE |
/run/user/1000/spudface/cmd.json |
Command file path |
Running as Service (systemd)
mkdir -p ~/.config/systemd/user/
cp spudface.service ~/.config/systemd/user/
systemctl --user enable spudface.service
systemctl --user start spudface.service
The service runs as your user (not root), starts after Wayland/X11 is ready.
Display Setup
SpudFace auto-detects the display and tries multiple backends:
- Wayland (default on Pi 5 with desktop)
- X11
- Direct framebuffer
Force a specific driver:
SDL_VIDEODRIVER=fbcon python3 spudface.py
Files
spudface.py— main applicationspudface.service— systemd service fileREADME.md— this file
License
MIT — do whatever you want with it.
Credits
- Expression approach inspired by Anki Cozmo/Vector
- OpenClawGotchi for the
FACE:/SAY:tag system concept - gTTS for text-to-speech