Maotuan · Desktop Companion

Why
Every AI coding session has the same dead time: you send a prompt, and for thirty seconds or ten minutes there is nothing to do but wait. Status spinners and pixel mascots tell you the agent is busy. None of them keep you company.
Maotuan started as a small game to play while waiting for Claude, and turned into the opposite of a status light: a creature with warmth, memory and a voice, that happens to also know when your agent is done.
What it does
- Lives on the desktop. Always on top, transparent, click-through except on its body. Stroke it with the mouse and it purrs; drag it and its feet dangle; fling it and it flies, bounces off the screen edge and lands with a squash. Left alone it yawns, stretches, twitches an ear.
- Talks. Type, or hold the mic and speak — transcription runs locally with Whisper, nothing leaves the machine. Replies come with emotion tags that pick the voice's mood, synthesized by MiniMax. Click it mid-sentence and it shuts up.
- Reads to you. Drop a txt / md / pdf or a novel: it reads sentence by sentence, keeps your place, gives an intro, answers questions about the text.
- Makes picture books. A story goes in; the brain rewrites it into pages for a five-year-old with a consistent hero; image-01 paints watercolor illustrations; a book window opens and it narrates page by page.
- Draws and hums. "Draw me a four-panel comic about…" shows up inline in the chat and in a gallery window. Ask for a song and it writes its own lyrics and hums them over a little pentatonic melody synthesized in the browser.
- Plays on the desktop. Rock-paper-scissors (it shouts the count and hops three times, hands pop out beside it), dice (it flings a die that tumbles and bounces), and a catch game where the window temporarily becomes an arena.
- Plugs into your life. Its own MCP server exposes
remember,pet_say,draw_picture,pet_singand Apple Music control; presets for Feishu, Slack, Notion, GitHub, Spotify, Google Calendar + Gmail, NetEase Music, or any custom stdio / HTTP server. - Watches your agents. One click installs a Claude Code hook and a Codex
notifywrapper; both ping a tiny local HTTP port. When a run finishes or needs your confirmation, it jumps up, sparkles and tells you.


How it is built
- Electron 44, ESM main process, a zero-dependency Canvas 2D renderer. Thirty-one skins share one interface: five hand-drawn (felted wool, jellyfish, slime, ghost, robot) on a shared behaviour state machine, six pixel sprites driven by one sprite engine, and eight are real Live2D anime characters (Live2D's official free sample models, downloaded on first use): a WebGL layer under the stage runs pixi.js + pixi-live2d-display, and the pet's lip-sync, gaze, blush, sleep, carry-sway, hop and spin are written onto the model's parameters every frame. Every character carries a reaction table — three or four different things it does when you click it, plus what it does when it wins, loses or ties at rock-paper-scissors, dice and the catching game, when it is petted, dropped or spun — with its own particles, expressions, lines and a matched MiniMax voice.

Six of them are desktop assistants drawn entirely in code — a floating holographic orb whose three orbital rings are computed in 3D, a talking terminal window with scrolling green text, a capsule robot with floating hands, an isometric cube, a cloud of drifting data motes, and a crescent-moon night light. Clicking any character plays one of four variants written around that body specifically: the fur ball squashes and rolls, the jellyfish flips over and rights itself, the ghost fades to nearly nothing. Eight more reactions fire from real moments — you come back after a while, it gets bored, it is thinking, the Codex run it was watching just finished, you feed it a file, it is late at night, you hold the mic.


Six more are painted rather than drawn in code. The first time you pick one, the app asks image-01 for a single four-cell expression sheet on a chroma-key screen — resting, eyes closed, laughing, crying — and slices it into four faces. Four separate generations were the obvious approach and the wrong one: the model holds identity across them but not body or brush, so the cat came back as four different cats. One picture makes sameness free. The renderer keys the screen out in the browser, then gives the still picture a life of its own: breathing, a slow float, a lean towards the cursor, a nod while it speaks, and a 0.4-second cross-fade between faces when its mood turns. No image ships in the repository or the installer.



- Codex is the brain. The OpenAI Codex SDK, signed in with your own
codex login, carries the persona, the notebook and the tools. It also works the other way round: point the pet at a folder, give it a task, and it runs Codex there with write access, narrating each step from the desktop and telling you when the job is done. - Voice pipeline. Streaming text is cut into sentences on the fly, each sentence synthesized ahead while the previous plays; an analyser drives the mouth from the real audio amplitude. Local
say/ System.Speech as an offline fallback. - Speech-to-text runs in a child process on the system Node (onnxruntime crashes under Electron's bundled Node — one of many small lessons), with Traditional→Simplified normalisation.
- Everything local. Keys in the system keychain, memory in a markdown file, images and songs cached on disk.

What I learned
- The product is the warmth, not the feature count. The moment it looked spiky instead of woolly, the whole thing felt wrong; three layers of curved fur strokes fixed more than any feature did.
- Companions must never guilt you. It has no hunger, no death, no decay. It just waits, and is glad when you come back.
- Tools beat claims. Codex once said it had an image-generation skill and drew nothing. Giving the brain a real
draw_picturetool — and telling it these are its only abilities — ended the hallucination.
Links
Source, installers and the full setup guide are on GitHub.