spud.cherry.surf · Download for macOS
A hand-crocheted potato who lives in the corner of your screen — and hands you a little card of encouragement, one day at a time.
He's a real crocheted doll, 3D-scanned and brought to life on your desktop. He follows your cursor, mutters to himself, remembers what you tell him, and knits you a golden card when you least expect it.
He doesn't take up a window. He doesn't ping you. He just sits in the bottom-right corner of your day, glancing over when you move your mouse, holding out something kind.
Tap the little white card in his hands and he hands you today's line — something warm, something dry, something you needed to hear.
- Tap the card to draw. Like it?
Keep it ♥and it goes into your book. - Draws are an unlimited little gacha — "the good ones don't run out. tap the card again, go on."
- Every card renders on the physical card in his hands — not a speech bubble. The card is the whole point.
- Works fully offline: a hand-written pool ships in the app, so he's never speechless.
Everything you keep lands in the Card Book — filter it down to just the goldens, or just the ones you loved.
Every so often he goes quiet, takes his time, and knits a golden card by hand. Most of them are a famous line he's been saving up, signed by whoever first said it. But once he knows you well enough, now and then he weaves one live instead — out of the things you've actually talked about — and signs that one himself. Rare on purpose. Kept forever.
The card in the popup is the same one he's holding out to you in the corner.
Hover over him and a little chat box slides out. Tell him what's on your mind — "today was a lot" — and he answers in his own voice.
- He replies in character — powered by a live LLM, grounded in whoever's currently on duty.
- Each buddy has a genuinely different voice: Spud above takes your side and leaves one easy handle to pick back up; the gardener would meet the same day with soil and rain, the taco with snacks and all-caps.
- He remembers — and everything he keeps is yours to unpick, anytime.
What he learns about you gets distilled into the Memory quilt — one patch per thing, the sunny ones stitched in gold, the rainy ones in blue. It's the whole of what he knows, in one place, and every patch has an × on it.
Six little souls, each a different kind of comfort. Spud comes with the app; the other five you don't buy — you earn them, through five different kinds of care: keep · favorite · confide · show up · go gold. Once a friend, always a friend; tap Set active to put anyone on duty.
Spuddy isn't a screensaver — he has needs and moods, and they drift over time (a small personality engine ticks in the background).
- Bored? He entertains himself — chases his tail, hums, tips his card back to re-read it, practices his wave.
- Sleepy? He nods off, jerks upright, and a poke startles him awake.
- Missing you? He taps the glass to get your attention. Respond and he cheers; ignore him and he just wilts for a moment and quietly backs off — he'll never nag.
- Been away a while? He gives you a little welcome-back.
He mutters through it all in soft dashed thought-bubbles ("the lamp hums. i don't mind it.") and only speaks in a solid bubble when he's actually talking to you.
And the small stuff: 90 minutes glued to your chair and he'll ask you to stretch. Past 11pm and he'll nudge you toward bed.
Nothing here is a canned clip. Every movement is authored on an eased-curve rig where the origin is always the contact point, squash preserves volume (sx·sy ≈ 1), springs overshoot on a cubic-bezier(.34, 1.56, .64, 1), and each one is paired with a soft synth blip. The long, self-directed ones — humming to himself, dozing off, reading his own card — are the ones I sweated the most.
…and a dozen more under the hood — the big stretch, chasing his tail, juggling the card, waving, cheering into confetti, holding the card out to you, wilting when he's ignored, sneezing it askew, plus tap-squish, eye-roll, shy peek, hop, pirouette, look-around, and a horizontal fling that sets him spinning and settles on an underdamped spring.
This isn't a sprite. Under the hood:
- It's a real crocheted doll. Every buddy started as a physical hand-crocheted amigurumi, photographed, AI-3D-scanned (Rodin), then retopologized in Blender +
gltf-transformdown to 1–3 MB PBR.glbfiles — real yarn fibers, real stitches, lit in real time with image-based lighting and Khronos PBR Neutral tone mapping in three.js. - The encouragement lives on the card in his hands — a live canvas texture painted onto the doll's own held card, not an overlay. The card is the soul of the potato.
- His eyes and head follow your cursor across the whole screen (eyes lead, head trails); left alone, he blinks and glances around on his own.
- Grab him and fling him anywhere — a horizontal throw sets him spinning, and he settles back with an underdamped spring.
- He's part-rigged — independent claws, eyes, and card, driven by an eased-keyframe motion system, so he can wave, present, roll his eyes, and flip his card.
- He stays out of your way — a transparent, always-on-top, click-through window docked in the corner. Clicks pass straight through to whatever's behind him.
cd app
yarn install
yarn startA little potato appears in the bottom-right corner, and a matching one lands in your menu bar (Show / Hide, Language, Quit). Prefer the packaged app? Grab the signed DMG above.
Chat and Golden Stitch talk to an LLM through a tiny Cloudflare Worker gateway (server/) — the API key lives server-side as a Worker secret and never enters the app or the repo. The build ships pointing at a hosted gateway; to run your own, deploy the Worker (or run it locally) with your own key:
cd server
cp .dev.vars.example .dev.vars # add OPENAI_API_KEY=... (or Anthropic / Gemini / DeepSeek)
npm run dev # http://localhost:8787Then point the app at it:
The gateway starts chat at GPT and each day's card pools at Claude; either walks on down the same chain (Claude · GPT · Gemini · DeepSeek, skipping any backend you haven't given a key) when one's having an off day, and both primaries flip at runtime from KV with no redeploy. It meters a per-device daily budget and pre-generates each day's card pools on a cron — so one shared key can safely carry a lot of little potatoes. With no gateway reachable, he falls back to built-in lines — everything still works, he just can't answer you in the moment. Full deploy + secrets in server/README.md.
app/ TypeScript throughout (yarn typecheck / yarn build)
├─ electron/src/ main process (bundled to electron/*.cjs by esbuild) —
│ transparent always-on-top window · tray · global cursor
│ polling · AI gateway calls (keys stay server-side)
└─ src/
├─ main.ts bootstrap — builds scene + brain, wires the modules
├─ app/ features — gacha draws · chat + memory · speech bubbles ·
│ Book/Buddies panels · taps & drags · unlocks
├─ scene/ three.js — scene · part rig hinges · PBR + IBL lighting ·
│ eased-keyframe motions · the live card texture
├─ ui/ popup markup — overlay · cards · book · buddies · effects
├─ brain.ts the personality engine — needs, moods, autonomous behavior
├─ content.ts every line, persona, and unlock rule
└─ types.ts · store.ts · sfx.ts · remote.ts
server/ optional Cloudflare Worker gateway (key vault · budget · cron),
also TypeScript (src/worker.ts · generate.ts · providers.ts)
The 3D pipeline (real doll → scan → Blender + gltf-transform → Draco/WEBP .glb) and per-character card-plane calibration are documented in app/README.md.
Spuddy is split-licensed, on purpose:
- The code is open. The source under
app/andserver/is MIT — fork it, learn from it, build your own thing with it. SeeLICENSE. - My work on Spuddy isn't. The parts I actually made — the 3D modeling & rigging, the hand-keyed animations, the renders, the written lines, and the Spuddy app & name — are all-rights-reserved. Please don't lift them. See
ASSETS-LICENSE.md. - The dolls aren't mine to give. Each buddy is based on a hand-crocheted doll originally made by someone else — I don't claim those underlying designs, and neither should you.
In short: take the engine and learn from it — just don't lift my models, animations, or writing. 🥔











