Back to work

2026

Ring Racer

F-Zero meets Cookie Clicker. A neon multiplayer racer where everyone shares one track, progress saves to the cloud, and you drive from Earth to Alpha Centauri. Built on Yard.sh.

GameMultiplayerthree.js
Ring RacerPlay Ring Racer
Goal
Turn a little easter egg into a real online game with saves and live multiplayer
Role
Game designer, developer, 3D artist
Tools
three.js, Blender + Python, Yard.sh
Timeline
October 2026, launched October 21

Results

22 in the first 12 hours
Players
11 across two galaxies
Stages
21, all generated by script
Models
7.7k lines of game and server
Code

The pitch

I wanted a Cookie Clicker built on top of F-Zero. Those games always went fast, but I wanted to go ridiculously fast, without cheating. I'm still surprised I could do that from within a browser! Cookie clicking was the natural progression system to keep that going, so the rest was designing the levels and generators to keep it fun for me while I built it.

The story

A black hole is collapsing, and it's going to take the solar system with it. One racer thinks he can drive fast enough to stop it.

SPACE-Y sees an opportunity. They sponsor him, pick up unlimited government funding to do it, and give him everything he needs: rockets, ion thrusters, a warp drive, the best car anyone has ever built. Every world he races through, SPACE-Y follows. Mining rigs on the Moon. Starships on Mars. A space station over Saturn's rings. Siphons on the rim of the event horizon.

It works. He collapses the black hole safely and saves everyone. But every place he went is now a SPACE-Y colony, mined for profit forever. By the time he crash-lands in Alpha Centauri, SPACE-Y is the largest corporation in the galactic cluster. Every world there is a strange copy of home, and SPACE-Y is already mining all five.

You're the racer. Every generator you buy is another SPACE-Y outpost on the course, so the further you get, the more the company owns.

Earth. Where SPACE-Y starts.
The Moon, where the Mining Rigs go in.
Mars. Solar farms, rovers and a Starship launch row.
Saturn. SPACE-Y builds a station over the rings.
The Black Hole. Somebody has to collapse it.
Proxima b. Earth again, but stranger.
Toliman. Rings grown under glass.
Rigil Kent. Six-legged crawlers sift the dunes.
The Centauri Rings. Trawlers net the asteroid belt.
The double Black Hole. SPACE-Y got there first.

A 208-mile highway, live

Collapse the Black Hole and the track becomes the Interstellar Highway, a single 208-mile road to Alpha Centauri.

It runs in a browser because there's almost nothing to it. The road's shape is just math, a couple of sine waves, and the track itself is plain colored triangles in empty space, with no textures, lights or shadows. It's cut into about 470 chunks, and the GPU skips the ones behind you or more than about 17 miles ahead. Everything is positioned by distance along the road, so each car sends just four numbers ten times a second, whether it's on lap one of Earth or 150 miles out.

The first billboard answers the title card, which promises 25.7 trillion miles.
Three minutes later, the galaxy fills the sky.

Progress you can see on the car

Idle games usually hide your progress in a menu. I wanted it on the car. Every upgrade shows up on the model: a forcefield for the shield, a laser turret on the roof, hover jets for Moon Boots, ghost trails for Time Dilation. Other racers see your build too, so a maxed-out car is a flex.

The garage opens beside the track, so you keep driving while you shop.

The store borrows the best parts of Cookie Clicker. Buy ×1, ×10, ×100 or Max. Cards you can afford glow orange and the rest fill up toward their price. The Autopilot upgrade buys its brain one level at a time, from a pocket calculator to a crypto mining rig to "the universe, running on your car," with its reaction time printed right on the card.

Past the Black Hole there's no "you win." You crash-land in Alpha Centauri and lose your car parts and your bank, and keep your Stardust, achievements and fleets. It's a prestige system, told as a road trip.

Built on Yard.sh

The Yard.sh homepage: Build with agents. Deploy on yard.
yard.sh

Ring Racer runs on Yard.sh, my friend Tate's startup. This is the part that usually kills a side project. A single-player toy is easy. The moment you want accounts, saves and other people on screen, it turns into a backend project, and the fun part stops. Yard made all of it the small part. Going from "this should be its own game" to a live multiplayer game with saves and sign-in took one day.

Multiplayer: Rooms

I wanted everyone on one track because seeing other cars is what makes an idle game feel alive. With Yard that was one class. I wrote a RaceRoom that relays positions, crashes and laser hits, declared it in the project settings, and Yard runs it. The page connects to a room called everyone with a relative URL, so the same code works on my laptop, in a sandbox and in production. A heartbeat reconnects you after a deploy. I never touched a socket server.

Saves and scores: Database and a service

Progress lives in a Yard database behind a small /progress endpoint, with the SQL migrations checked in next to the game. The server makes the rules: totals only go up, levels only rise, and it alone hands out Stardust when you prestige, so a tweaked browser can't just write itself a billion rings. Guests get a save too, and it expires after 48 hours unless they sign in.

Sign-in: Yard Auth

You can play the second the page loads. If you sign in later, Yard Auth gives you an account and your guest save comes with you. No auth code of my own.

Hosting the game

The whole game is the project's landing page: a three.js app, its scripts and the car and fleet models as glTF. Yard hosts it at morgan.yard.sh/ring-racer, with the service and database sitting right behind it on the same domain.

What I learned

Login and accounts

Making people sign in before they play loses them. So everyone starts as a guest, and signing in later moves the guest save into the account on the server, so nothing gets lost in the handoff. The server is also the only one allowed to decide what counts: totals only go up, levels only rise, and guest saves expire after 48 hours so the table doesn't fill up with drive-by players. Accounts turned out to be less about logging in and more about deciding who owns a save and when.

Tracking

I added visitor tracking after launch, so most of the first day isn't in the data. Next time it goes in before the link goes out. Once it was in, each player gets one row: their racing name, a country from an IP lookup (the IP itself is never stored), the site that sent them, and when they first and last played. That's enough to see who's actually racing and where they came from, without collecting anything I'd feel weird about.

Role and stack

Solo: game design, code, 3D art and copy. three.js for the game, Blender driven by Python for every model, and Yard.sh for hosting, auth, realtime multiplayer, the database and releases. Built with Claude Code as my pair programmer.