Situation
I saw a video about empowering an AI companion and figured I’d start with a desktop buddy. The first thing I wanted was to chat with him in real time, and probably to have him trash-talk my reading. Nowadays he bops to the music with me.
He’s a work in progress, meant to grow into a companion over time. Next for him: larger models, memory, and tool calls so he can join in games.

Approach
Two programs, one stream of events. The core, in Python, hears, thinks and speaks. The body only draws. One WebSocket joins them and carries small JSON events: the state (listening, thinking, speaking), the level of each voice, the line so far, a face to make, what he is touched with. The body never needs to know how a reply was made, so it can be replaced or replayed. The demo on this site replays that stream.
The models, today. Everything runs on one Windows laptop with an RTX 5090 Laptop GPU and its 24 GB of VRAM. The models change often; these are the current ones.
- Hearing: Parakeet TDT 0.6B v2, int8 ONNX, on the CPU with 8 threads. A 5 s clip comes back as text in 88 ms, from 0.74 GB of RAM and no VRAM at all. Whisper turbo on the GPU is the switch for when I speak French or my accent gets in the way.
- Thinking: a community fine-tune of Gemma 4 12B, quantization-aware (QAT), served by LM Studio on the GPU.
- Voice: Breeze TTS 2, 7.2 GB of weights, running in WSL2 on the same GPU.
- Body: plain JavaScript and one WebGL fragment shader, shown over other windows by a Tauri 2 shell (transparent, always on top, never takes focus).
- Web search: optional, behind a filter that blocks any query holding a private term.
The music. He hears what the PC plays through Windows’ WASAPI loopback, called through ctypes. The process loopback leaves out his own voice. Each block of audio turns into a few numbers (level, onsets, tempo and beat phase, low and high energy) and is dropped: no audio is stored, logged or handed to the model. Telling music from a podcast is the hard part. He weighs a steady beat and sustained harmonics against the 3 to 7 Hz syllable rhythm of speech and its pauses, so a documentary doesn’t set him bopping.
His memory. It is plain Markdown that I can read: a journal of every line heard and said, one file a day, kept forever; his notes on my world; what he thinks of himself; a recap per session; the threads still open. Every write passes a secrets filter first. Its own web page lets me read all of it, hide a line (it stays in the file but leaves his prompt), merge two, or redact a word everywhere.

His body. The fire, the eye, the arms and legs are drawn by one shader and a few hundred lines of spring physics, not by sprites. He reacts to the cursor, can be picked up and thrown, and dozes off when nobody is around.
The cut-down version. The demo has his body and a phrasebook of a few dozen lines, with a typed box that answers a handful of questions by keyword. No model, and no sound: he talks in text only. It is static files under the site’s content policy, and the browser fetches them only when the stage nears the screen.
Prototypes. I work through prototypes, and Burnie keeps picking up new styles and representations: his Pixel and Voxel looks on this page are two of them. New hardware stacks come next.
Result
- He runs daily on my laptop, started from the Start menu, with a tray icon to free the GPU.
- Speech in, a spoken answer out, and a character who reacts, all without leaving the machine, except for the optional web search.
- The body’s event stream is stable enough that the cut-down demo reuses it unchanged.
- The demo weighs about 31 KB compressed, and nothing loads until it is near the screen. His Pixel and Voxel looks are 2 to 3 KB each, fetched only when picked.
He’s good to chat with, and these days he criticizes my music choices too. He’s fun like that.
Next time
I would anticipate the RAMpocalypse and build a beefier VRAM setup early, to be more self-reliant.