
Horse Racing Elite
A horse racing game you can play right in your browser. You bet on one of six horses, then watch a smooth 60fps race play out, either on your own or in a room with friends.
- Role
- Genre
- Modes
- Stack
- Multiplayer
- Firebase Realtime Database
- Platform
01The Game
Horse Racing Elite is a betting arena that runs in the browser. There are six horses, you get 30 seconds to place a bet, then the race runs live and you’re paid out the moment it finishes. The whole thing sits inside a neon e-sports style theme, and you can switch between a few colour palettes if you want a different look.
The most important decision I made was that the game never picks a winner. Instead, it simulates the race. Each horse gets a starting speed based on its stats and a random seed, and then a physics loop moves them along the track step by step. So the race you’re watching isn’t a replay of a result that was decided earlier. The animation is the actual calculation happening in front of you.
This project was also my first real experiment with vibe coding. I broke the game down into separate systems, described each one to an AI, then reviewed and cleaned up the code it gave me before moving on to the next one.
Simulated, not picked
Whoever crosses the line first wins. Every player in the room runs the race from the same seed, so everyone sees exactly the same outcome.
Same race on any screen
The physics runs in fixed time steps, so the race plays out exactly the same whether your screen refreshes at 30, 60 or 144Hz.
A full arena
Around each race there’s a lot going on: rooms you can join with an invite code, bots to fill empty seats, ranks, seasons and a daily bounty to chase.
02Screenshots
These screenshots were captured straight from the game. Tap any of them to see it bigger.





03Core Loop
- 1
Lobby
You can play on your own, or create a multiplayer room and invite people with a code, or join someone else’s.
- 2
Bet
You have 30 seconds to pick one of the six horses and put down a bet of at least 10 credits.
- 3
Seed
The host grabs a single seed from the RNG service and saves it to the room, which means every player’s game runs the exact same race.
- 4
Race
After a countdown, the six horses race through a step-by-step physics simulation, and the lead can change hands several times along the way.
- 5
Payout
If your horse wins, you get your stake multiplied by the odds. The seed and block number are shown afterwards, so anyone can check how the race was decided.
04Key Features
Six stat-driven runners
Each horse has its own name, jockey, colour, odds, recent form, speed and stamina. The favourite, Thunder Bolt, pays 2.5×, while the long shot, Blue Storm, pays 12×.
Multiplayer rooms
Rooms run on the Firebase Realtime Database and you join them with an invite code. The host’s seed is what drives the race for everyone in the room.
Bots & live wager feed
AI opponents and a live feed of everyone’s bets help a room feel busy, even when there aren’t many real players in it.
Swappable palettes
You can switch between Default, Cyber and eSports themes. Because all the colours come from CSS tokens, changing the theme only takes one attribute.
Audio & motion
There’s a countdown sound and background audio that fades in and out, and the screens animate smoothly from one phase of the game to the next using the Web Animations API.
Ranks & seasons
Leaderboards, seasons and a daily bounty give players a reason to keep coming back to the arena.
05The Maths
You bet on a single horse to win, and the payout includes your original stake. To make sure the numbers held up, I wrote a faithful copy of the race engine and ran every one of the 10,001 possible seeds through it.
Starting velocity
Each horse starts with base = (0.6 × speed + 0.4 × stamina) / 100, and its velocity is then set to 0.55 × base + 0.1 × rng(). This is the only point in the race where a horse’s stats actually make a difference.
The race itself
Every 16 milliseconds, each lane gets a small, limited amount of random jitter added to it. This is basically a random walk with limits, and it’s what creates all the overtaking you see during a race.
Payout
The payout is floor(stake × odds), and that includes your stake. So if you bet 100 credits on Thunder Bolt at 2.5×, you get 250 back.
What the audit found
The audit showed that every horse wins roughly one race in six (between 16.5% and 16.9%). The difference the stats make (0.011) is about nine times smaller than the random part, and the random walk washes it out within about 10 of the roughly 1,470 ticks in a race. That means the fair price for every horse is really 6.0×, and the fixed odds on the board had never been checked against how the simulation actually behaves.
The fix it calls for
There are two ways to fix it. One is to give all six horses the same odds, set a little under 6.0× (5.70× would give a 95% return). The other is to make the stats affect every tick so the win rates genuinely differ, and then measure them again and set the odds from those results.
06Under the Hood
Fixed-timestep loop
The game uses requestAnimationFrame to keep track of real time, then moves the simulation forward in fixed 16ms steps. It will catch up by at most four steps in a single frame, and when the game is paused it keeps the frame loop going without moving time forward.
Seeds from the RNG service
Seeds come from an RNG service based on blockchain blocks. The game reaches it through a server-side /api/blockchain proxy, so the access token never ends up in the browser. If the service lags behind, it retries a few times, and if it’s down, the game falls back to a local seed.
Phase state machine
The game moves through a set of phases: Home → Lobby → Betting → Countdown → Racing → Finished. Each phase looks after its own screens and logic, which made it easy to build the game one phase per prompt.
Firebase rooms
Room details, invite codes and the shared race seed are all stored in the Firebase Realtime Database. When you play on your own, everything stays on your device.
07Challenges & Solutions
08Results & Takeaways
- A finished, playable arena with solo play and multiplayer rooms, bots, ranks, seasons, sound and a neon theme you can swap.
- Races are completely reproducible, so the same seed gives the same winner on any device.
- A written-up maths audit that found the gap between the odds and what the simulation really does, along with a plan to fix it.
What I learned
- Vibe coding works much better when you’ve thought through the architecture. The clearer my picture of the engine and the economy was, the cleaner the code that came back.
- The odds on a betting board need to be based on what the simulation actually does, and that has to be measured rather than assumed.
- In multiplayer, fairness depends on everyone getting the same result from the same input. You share the seed with everyone, not the result.