~/blog/i-made-my-dog-a-nintendogs

I made my dog a Nintendogs, and the face didn't turn out

Dante, my German Shepherd, now lives in the browser: no 3D models, just blended spheres and layered fur. From the side it's him; the face didn't turn out.

· 6 min read · Leer en español

From the side, it's Dante. From the front, it's some other dog.

A long-haired 3D German Shepherd lying in profile on the tiles of a patio, with a black saddle, tan legs and the doghouse with his name in the background.Open image full size

Dante in the game, from the side. This one's really him.

That's the honest summary of Dante, a Nintendogs-style game I built in a day with Claude. You pet him, feed him, throw him the ball, teach him tricks, and at night he goes to sleep in his doghouse. It runs in the browser, on your phone too, and it doesn't download a single 3D model: the whole dog comes out of code.

I played Nintendogs as a kid. Where I lived back then there was no room for a dog, so that was the only one I could have. Now that I have my own, it made me nostalgic.

Who Dante is#

Dante is one of my two German Shepherds. He's long-haired and holds two dog show championship titles in El Salvador (from ACANSAL, the country's FCI kennel club). If you've been to this site's home page, you've met him: he's the one peeking out of the terminal.

The other one is Kiara, the grumpy senior of the house, and she's in the game too, with her own state machine. If Dante gets too close, she growls, and he backs off with his ears pinned: "perdón Kiara 😳" (sorry, Kiara). And if you pet Kiara, Dante sits down to watch and mutters "ella no es campeona..." (she's not a champion...).

The full game: Dante sitting on a tiled path between two garden beds, with hunger, thirst, energy, happiness and cleanliness bars labeled in Spanish at the top left, and a toolbar along the bottom with pet, food, water, ball, brush, tricks, visitor and night.Open image full size

The patio at home, with Dante's bars at the top left.

From toy to Dante#

Four screenshots from the same angle on the patio. Top left, a toy dog made of spheres and cylinders, with stick legs. Top right, a smooth one-piece caramel body that looks like a bean with ears. Bottom left, now with a black saddle, a golden chest and fur. Bottom right, today's version, furrier, with realistic tiles and plants.Open image full size

Left to right, top to bottom: the first commit, the first one-skin mesh, the coat painted to match the photos, and today's version.

The first version didn't look like Dante. It was a dog made of loose parts, spheres and cylinders grouped together, like a wooden toy. It already ate, played and slept, but the legs were sticks and the head was a ball with a snout. Almost everything after that was changing how the dog is built.

The second one is already a single skin, though it looks more like a bean with ears than a German Shepherd. The third brings in the black saddle, the tan and the layered fur. The last one is today's, with the patio from my house and a real sky.

A dog made of blobs#

Nobody sculpted Dante. He's a list of simple shapes, ellipsoids and capsules, each one hanging off a bone. That's 101 shapes on 23 bones; three of them don't add, they subtract, to carve out the mouth and the eye sockets. The head, for example, is put together like this:

src/dog.js
P('sph',this.head,[0,0.06,0.09],[0.15,0.115,0.17],C.S,0.02,'head');     // frente (negra), en cuña
P('sph',this.head,[0,0.09,0.19],[0.075,0.055,0.1],C.S,0.014,'head');   // caballete sobre el stop
P('sph',this.head,[0,0.02,0.16],[0.165,0.085,0.12],C.K,0.012,'head');   // máscara alrededor de los ojos
P('sph',this.head,[0,-0.02,0.29],[0.11,0.09,0.31],C.K,0.012,'head');    // hocico más largo y angosto
P('sph',this.head,[0,-0.045,0.33],[0.115,0.06,0.24],C.K,0.01,'head');   // belfos (labio superior que cuelga)

Each line is a stretched sphere: which bone it goes on, where, how big, what color, how long the fur is there and which zone counts when you pet him. Dante's snout is one line of code.

Stack up spheres and you get a snowman, not a dog. What turns them into a single skin is a distance function: for any point in space it tells you how far it is from the surface, and where two shapes touch it blends them with a smooth union, like two drops of wax running together. The mouth and the eye sockets are the three shapes that subtract: they get carved out instead of stuck on.

To get a mesh out of that function, the game walks a 74 × 115 × 149 point grid with marching cubes. That gives 33,023 vertices and 65,944 triangles, and on my Mac it takes 332 ms every time the page loads. In lite mode it's 12,117 vertices in 109 ms.

The nice part is what you get for free. Since every vertex knows which shapes it came from, it also knows which bones it belongs to, and that's the skinning done. Sitting, lying down, rolling belly-up or standing in a show stack are just bone rotations. The colors work the same way: the black saddle, the tan and the mask are painted by a function in each bone's space, tuned against photos of Dante, and they blend at the edges with no seams.

Layered fur#

The fur isn't strands. It's 10 copies of the same mesh, each one a little farther out than the last. On each layer, a noise map decides which points survive: almost all of them on the inner one, very few on the outer one. From a distance, that reads as fur. The layers fall with gravity, sway, drag behind him when he runs and react where you move your hand.

Layers have one problem: along the outline you can tell they're sheets. For that there are 6,737 silhouette tufts that only show up when the skin is edge-on to the camera. That's why Dante's outline looks furry and not smooth. In lite mode it drops to 4 layers.

The patio and the sky#

The patio is the one at my house. The tiles and the bricks are crops from photos of the real patio, and the fur detail comes from a crop of Dante's chest.

The sky is an HDRI photo from Poly Haven that rotates with the time in El Salvador, so the sun in the sky matches the light casting the shadows. If you visit at night, it's night on the patio and Dante is in his doghouse. And if you leave him shut in after the sun's up, he starts crying: "¡DAVID! ¡la puerta!" (DAVID! The door!).

Where it hits the ceiling#

3D Dante seen from the front: a rounded head with a black snout, brown eyes and a half-open mouth above a very fluffy golden chest. He looks more like a plush toy than a German Shepherd.Open image full size

Dante from the front. I love him anyway.

From the front, the face reads as stylized. A head made of blended spheres doesn't have the hundreds of tiny planes a real face has. Wedge-shaped skull, almond eyes, blinking eyelids, brows, cheekbones, jowls: it's all there, and it still looks like a Dante plush, not Dante. Every round of tweaks from there barely moved the needle.

The next jump is a mesh sculpted or generated from his photos, with a skeleton. The good news is that everything else stays: the fur, the coat pattern, the behavior, the patio and the game. Only the base changes. That jump doesn't have a date.

How I built it#

I built it in a day, using Claude. That day came to 14 commits, all with Claude as co-author (13 with Fable 5.1, one with Opus 5.5). The only production dependency is Three.js; Vite does the build and Playwright runs the tests.

It even has tests. They run on every push, and one of them throws the ball to Dante and waits for him to bring it back. If you're curious how I work with Claude when it's not for fun, here's how I set up reviewers with subagents.

Play it#

It's at dante.davidquinta.tech, and the code is on GitHub. Drag over him to pet him: his head, belly and tail each react differently. If a visitor shows up at the gate, he'll bark until you calm him down. And if he can't pull off a trick, you know the deal: "con mango sí lo hago" (I'd do it for a mango).

If you made something like this for your dog, or your cat, tell me about it. And if you want the next post, there's the RSS feed.