Warming Up the Grid

Back to Projects

Ready To Race
Unlimited

A Browser Multiplayer Car-Racing Arena - Built with Next.js & Vibe Coding

Ready To Race Unlimited - browser car-racing game cover
Role
Developer
Vibe Coder
Type
Web Game
Racing Arena
Stack
Next.js · React
TypeScript
Build
Turbopack
Netlify
Approach
Vibe-Coded
AI-Assisted

Ready To Race Unlimited is a fully playable, real-time car-racing arena that lives entirely in the browser - odds, betting, a 60fps race simulation and a neon e-sports skin, with no backend at all. It's also an experiment in vibe coding: building a complete game by steering an AI conversationally, prompt by prompt, system by system.

01 --The Challenge

The Build Challenge

A racing game looks simple until you build one. It needs a race that's exciting but fair, betting math that actually pays out correctly, animation that stays smooth on any machine, a grid full of opponents, sound, and persistence - and here, all of it had to run client-side with zero server. The twist: the whole thing was built through vibe coding, so the real challenge was decomposing a game into prompts an AI could implement cleanly, then reviewing and steering the output.

"The hard part of a betting race isn't the visuals - it's making outcomes feel random and dramatic, yet provably fair and reproducible."

🎯

Technical Problem

Simulate a believable race with live lead-changes, drive an odds-based betting economy, and animate it all at 60fps - entirely in the browser, with no backend to authoritatively run the race.

🏁

The Goal

A self-contained Next.js game: deterministic seeded races, six cars with real stats, working bets and payouts, bot opponents, audio and a polished neon e-sports UI with swappable palettes.

🤖

The Constraint

Build it by vibe coding - describing each system to an AI and iterating - which demands a clear mental model of the architecture so the generated code stays consistent and debuggable.

02 --Tech Stack

Tech Stack & Approach

The whole game is a single Next.js (App Router) application bundled with Turbopack and deployed to Netlify. There's no database and no game server - every car, bet, race and saved stat lives in React state and the browser's localStorage. State is driven by hooks and reducers (the UI alone runs dozens of useState and useReducer stores), and the race itself is a hand-rolled simulation on requestAnimationFrame.

Naive Build vs. How It's Engineered

The Naive Approach
  • Move cars with Math.random() each frame - janky and unfair
  • Tie game speed to frame rate, so fast machines race faster
  • Hard-code one look and recompute payouts ad-hoc per bet
The Engineered Approach
  • A seeded PRNG so a race is deterministic and replayable
  • A fixed-timestep loop - identical physics at any FPS
  • Token-driven palettes and a single odds → payout formula

The Stack, Layer by Layer

Framework
Next.js · React · TypeScript
App RouterTurbopackNetlify

"A single client-side Next app - no server, no database. The browser is the whole game."

⚙️
Game Engine
rAF Simulation · Seeded RNG
Fixed-stepDeterministic60 FPS

"A hand-written race loop - velocity from stats, jitter for drama, finish detection per tick."

🎨
Presentation
CSS Tokens · Orbitron · Audio
PalettesWAAPIHTMLAudio

"Swappable neon palettes via CSS custom properties, plus countdown & ambient sound."

Core Systems at a Glance

Responsibility
Key Challenge
How It's Solved
⚙️ Race Engine
Advance six cars to the finish line.
Fair, dramatic, frame-rate independent.
Seeded PRNG + fixed-timestep accumulator loop.
💰 Betting & Economy
Take wagers, settle winnings.
Correct odds-based payouts & balances.
Single payout = stake × odds formula per car.
💾 State & Persistence
Track credits, stats, settings.
Survive reloads with no backend.
React reducers mirrored into localStorage.
03 --Architecture

Architecture & Game Loop

The Phase State Machine

The entire game is driven by one screen-phase state machine. Each phase owns its own UI and logic, and transitions are explicit - which keeps a complex game readable and made it easy to build phase-by-phase while vibe coding.

🏠
Home
🛰️
Lobby
💰
Betting
⏱️
Countdown
🏎️
Racing
🏆
Finished
💡

The race runs on a fixed-timestep loop: a requestAnimationFrame callback accumulates real elapsed time and advances the simulation in fixed 16ms steps (capped at four catch-up steps per frame). Physics is therefore identical whether the device runs at 30, 60 or 144Hz - and a pause flag simply re-queues the frame without advancing time.

Core Modules

⚙️

Race Engine

Seeded RNG · Fixed-step loop · Finish detect

💰

Betting & Odds

Wagers · Payout math · Live wager feed

🤖

Bots & Rooms

AI opponents · Public / private rooms

🔊

FX & Persistence

Audio · Palettes · localStorage

04 --Game Logic

Game Systems & Visual Language

Every car is a small data object - name, driver, colour, odds, recent form and two stats: speed and handling. The race converts those stats into a base velocity, then adds controlled randomness so no two runs are identical. Because the randomness flows from a single seed, the same seed always produces the same race - the basis of a fair, reproducible result.

// each car advances per fixed 16ms tick seed = roomSeed ?? Math.floor(1e4 * Math.random()) + 1 baseVel = 0.55 * (0.6*speed + 0.4*handling) / 100 + 0.1 * rng() strideΔ = (rng() - 0.5) * 0.2 // ± jitter → lead changes position += baseVel + strideΔ // first past the line wins payout = stake * car.odds // e.g. 50cr on 4.0x → 200cr

The six cars are tuned so odds, stats and drama line up: the favourite Thunder Strike sits at 2.5× with high speed, while the long shot Blue Thunder pays 12× - a bigger gamble with weaker odds. A 60% speed / 40% handling weighting decides the baseline, and the per-tick jitter is what creates the lead-changes that make a race worth watching.

Typography

A three-font e-sports system: Orbitron for display & numbers, Rajdhani for UI text, and JetBrains Mono for data, timers and stats - all loaded via Google Fonts.

Orbitron
Orbitron · DisplayRajdhani · InterfaceJetBrains Mono · Data
Color Tokens

A deep-violet base (--bg-0--bg-3) lit by neon accents - orange, cyan and pink over a violet glow - plus a win-green. The whole skin is token-driven, so palettes (Default · Cyber · eSports) swap with one attribute.

#070012
#0E001E
#160028
#1E0038
#F5EEFF
#FFFFFF
#FF6B00
#00E5FF
#FF2E7A
#00FF88
#A050FF
#FF00CC

In-Game Screens

The arena across its phases - home hub, the matchmaking lobby, grid sync, the betting board and the live race. Click any screen to open it in high resolution.

05 --The Build

The Vibe-Coding Build Process

Vibe coding only works if you bring the architecture. I drove the build in deliberate passes - scaffolding the app, then growing one system at a time, prompting the AI for each piece, reviewing the output, and refactoring before moving on. Treating the AI like a fast pair-programmer (not a vending machine) is what kept a feature-rich game coherent.

🧱

1 · Scaffold

Spun up a Next.js + TypeScript app on Turbopack, defined the screen-phase state machine, and stubbed each phase as an empty component so the skeleton was navigable first.

⚙️

2 · The Race Engine

Built the heart of the game next - the car data model, seeded PRNG, the velocity formula and the fixed-timestep requestAnimationFrame loop - and tuned it until races felt fair and tense.

💰

3 · Betting & Bots

Layered the economy on top: odds, the stake × odds payout, credit balances persisted to localStorage, plus bot opponents and a live wager feed to fill the grid.

4 · Juice

Added the feel - Orbitron/Rajdhani type, the token-driven neon palettes, countdown and ambient audio with volume fades, and Web-Animations transitions between phases.

🚀

5 · Ship

Wired up rooms, ranks, seasons and the daily bounty, did a polish-and-bugfix pass, and deployed the static build to Netlify as a no-backend, fully client-side game.

06 --Results & Reflection

Outcome & Impact

Key Outcomes

0
Frame-rate-independent fixed-timestep race loop
0
A complete game running fully client-side on Netlify

"A fully playable betting race - deterministic, 60fps and backend-free - built end-to-end through vibe coding."

📈 Outcome

A shipped, playable web game: six stat-driven cars, odds-based betting and payouts, a seeded fixed-step race engine, bots, rooms, ranks, seasons, audio and a swappable neon e-sports skin - all client-side.

🧗 Challenge

Making races feel random yet fair and reproducible, keeping the simulation smooth across frame rates, and holding a large codebase coherent while generating most of it through AI prompts.

💡 What I Learned

Vibe coding rewards architecture. The clearer my model of the engine, state machine and economy, the cleaner the generated code - the AI accelerates building, but the design decisions stay yours.

🚀 Next Steps

Add real-time multiplayer over WebSockets, server-authoritative seeds for trust, more tracks and cars, and a proper progression economy beyond local persistence.