Runnin' Mules! A real-time multiplayer racing arcade
Role: creator · Where: personal (cege7480/sigma-derby) · Built: April–July 2026
Stack: Three.js + React Three Fiber · Rapier physics · Socket.IO · React 18 + TypeScript · Node/Express · Firestore · Google Cloud Run → Cloudflare Containers · Raspberry Pi + Pico + ESP32 (the physical track)
Play it live: runninmules.christaylor.ai · served from a Cloudflare container that sleeps between races; the first visitor wakes the stadium, and the announcer sits this deployment out
A real-time multiplayer digital horse-racing arcade: five horses, ten quinella bets, continuous race cycles. The Socket.IO server is authoritative on outcomes and payouts; clients are pure renderers, and a session can reconnect mid-race and slot back in without losing balance or wagers.
It is also a much older want than the commit window suggests. The first time I saw Sigma Derby on a Las Vegas casino floor, five mechanical horses lurching down a track while a crowd of strangers yelled at them, I wanted to build one. That kind of wanting is why most of us got into programming in the first place: we wanted to make the games. Then we found out what making one takes. Character art, rigged animation, voice work, illustration, and behind a machine like that one, electrical and mechanical engineering too: whole disciplines, each priced in years and usually in other people. I spent two decades collecting those years anyway.
What AI changed is what one person can do with them. It hands you the CliffsNotes on a discipline in hours instead of years. That does not make anyone an expert, because experience is still the half of true knowledge you cannot download (I have been saying so since 1998), but it meant that for the first time I could apply everything I had collected without first teaching a team everything I had learned. The four disciplines below stayed rented. The judgment did not.
How it was built, the AI angle
This is generative AI in the product, not just assistive AI in the editor.
| Discipline | Normally needs | Here |
|---|---|---|
| 3D horse models | a character artist | Meshy AI-generated GLBs, one per horse, each rigged with Walk/Trot/Gallop/Rest |
| Broadcast announcer | a voice actor + booth | Google Chirp 3 HD (en-US-Chirp3-HD-Charon), the whole phrase library rendered to MP3 on boot and cached in GCS |
| Splash / tutorial art | an illustrator | generated stills, reused as the four-step first-time-player walkthrough |
| Jockey rig | a technical animator | a v3 rig with a proper racing seat, plus a 13-joint procedural fallback horse with velocity-driven crossfade |
Measured 511 commits across all branches over ~12 weeks, 360 of them (70%) AI-attributed, mostly Claude co-authorship, plus 20 authored outright by copilot-swe-agent[bot] and
anthropic-code-agent[bot]. A further 139 commits come from semantic-release-bot, which automates
versioning and changelog generation; those are release plumbing, not AI, and aren't counted.
The hand-built parts are the ones you'd expect to be hand-built: the authoritative race simulation, the payout math, the reconnection protocol, and the security model.
The cast


Thunderbolt, Lucky Star, Dark Horse, Gold Rush, and Long Shot. Five horses, five jockeys, every card and portrait generated, each in a deliberately different art style. The pre-race paddock walk introduces them one at a time: a spotlight, the card, the jockey bio, then the gates.

The splash art pulls double duty as the four-step first-time-player tutorial, so the walkthrough reads native to the brand instead of bolted on.
The cutscenes
Generated footage from the intro reel and the in-game cutscene overlays, the part of the product that used to require an animation studio:
![]() The break: five wide out of the gate, dust included. |
![]() The delay: the goose has right of way. Nobody argues with the goose. |
![]() The celebration: the entire field, upright, in silks, dancing. |
![]() The teeth-throw: the cartoon overlay every client sees when one rider's rhythm crosses 85% while a rival's collapses. Yes, that flying object is what you think it is. |
The intro
The full opening number: three minutes and thirteen seconds of generated footage, compiled by the project's own intro pipeline and cut to "Cotton-Eye Joe." On the site it plays right here; on GitHub the poster links to the file.
The screens
The stadium

Procedural grandstands, pine-tree perimeter, lamp posts, scoreboards, and a stadium-shaped infield, with mowed turf and rake-lined dirt. Alfa Slab One for display headings; JetBrains Mono for every live numeral: odds, balance, timer.
Board + phone: the whole loop
![]() Board / kiosk: a full-screen attract overlay with the station code and QR. Phones scan it (or type the four-character code) to pair. |
![]() Racing: the QR fades out and the race-cam follows the field around the oval with a TV broadcast HUD. |
![]() Results: winning quinella and payout summary, then straight into the next cycle. |
![]() Phone: quinella picker with all ten pairings and odds (left), and the jockey rhythm minigame that modulates your horse's speed (right). |
The parts I'm proudest of
- A reusable camera cutscene system. Every shot is just a
{ position, lookAt, duration }function, so a new cutscene is a new array. Ships with the race-start gate cut, the pre-race paddock walk (one cameo per horse, spotlight card reveals the jockey bio), and a photo-finish inspector. - A ragdoll jockey. There's a rare chance each race that a horse stumbles; the jockey then detaches into a six-body ragdoll with spherical joints and gets launched into the grandstand. There is also a gameplay-triggered teeth-throw cutscene that fires when one rider's tap-rhythm crosses 85% while a rival's drops below 30%: cartoon overlay on every client, in-engine ragdoll on the board.
- Real observability for a toy. Custom metrics to Google Cloud Monitoring every 60s, visualized
in Grafana: request rate and latency, race throughput, betting economy, tap-rhythm distribution,
auth rejections by reason, HTTP 4xx/5xx, Firestore errors, and client-side errors via a
window.onerrorbeacon. - Security taken seriously anyway. The
/hardwareSocket.IO namespace requires a shared secret with constant-time compare (previously anyone could connect and spoof position events to alter race outcomes). Secrets live in Secret Manager and mount natively. Per-user rate limits on bets, taps, markers, and reactions. An aggregate marker cap so a careless admin can't inflate one player's balance indefinitely. - The iOS bug nobody warns you about. Mobile socket heartbeat-on-resume catches Safari's
half-open WebSocket failure mode:
socket.connected === truewhile every emit drops on the floor.
The machine
Runnin' Mules is the digital half of a two-part build. The other half is a physical racetrack in
the Sigma Derby tradition, and its control stack lives in the same repository: a Raspberry Pi
bridge speaking Socket.IO to the same authoritative game server, a Pico microcontroller under it
reading encoders and driving the lane motors over USB serial, an ESP32 LED controller, a sound
controller, a wiring diagram, and the 3D models for the printed parts. The /hardware namespace
with its shared-secret, constant-time authentication exists because the server was always meant to
trust exactly one privileged position feed: the machine's.
Electrical and mechanical engineering are two more disciplines I spent years studying without a project worthy of them. This is the part of the build where that changes; the screens above double as the display layer for a gameboard you will be able to stand next to.
Why it matters
Everything else in this portfolio is enterprise plumbing. This one is the counter-example: the same AI-assisted method, pointed at a domain with no requirements document and no stakeholders, still produced a deployed, monitored, security-reviewed, continuously released product, with 3D art and a broadcast voice a solo developer could not have made five years ago at any price.
It is also the honest test of the whole thesis. AI supplied the intelligence I rented; twenty-three years of experience decided what was worth building with it. A dream carried home from a casino floor, shipped, is what that combination is for.
Also, the jockeys throw their teeth. That part was not AI's idea.







