Play the game: https://copet80.itch.io/lap-legends
I've made games before, but somehow I had never built any top-down racing game. And because I know myself extremely well... I also know that if I didn't give myself a strict time limit, this thing would quietly grow in scope until it turned into another multi-year side project (looking at you, Guilds n Glory 👀).
So I gave myself 48 hours.
No extensions. No polishing forever. Just build a tiny F1-inspired racer and ship it.
It turned out to be one of the most fun coding weekends I've had in years.
Why Build a Top-Down Racing Game?
It started with a simple conversation at work.
A colleague had hidden a tiny drifty F1 mini-game as an easter egg in our product. His version was intentionally oversteery, very "Initial D meets corporate software". I loved it, but I also found myself thinking:
"These are F1 cars... should they drift this much?"
He told me he might tighten the physics, which immediately made my developer brain go:
What if I just try building my own?
No copying his code. No reverse-engineering someone else's idea.
Just... see if I could recreate the feeling of tight, grippy F1 handling from scratch.
And that curiosity spiralled into a 48-hour sprint.
The 48-Hour Build Timeline
Here's roughly how the 48 hours went. It wasn't glamorous, but it was surprisingly steady:
0-4 hours: Core Rendering & Movement
Got the absolute basics in:
- rendering the car and track
- player input
- simple physics: acceleration, steering, friction
It didn't feel like an F1 car yet, but it moved, which was enough to keep me going.
4-8 hours: Track Integration & Game Loop
Pulled the real track into the game and added:
- off-road friction
- skid effects
- spark particles
By hour 8, I actually had something that resembled a tiny racing game.
8-16 hours: Racing Line & Autodrive
Implemented the racing line and built the autopilot to follow it.
Also created the title screen, where the bot drives around to make things look alive.
16-24 hours: Ghost Recording & Playback
Added ghost recording, playback, and local storage saving.
This was the moment the game suddenly felt replayable.
24-36 hours: UI & Leaderboard
Built the UI and wired the leaderboard to Firebase Storage.
Ghost data is encoded/decoded so each run is only ~3–4 KB.
36-48 hours: Polish & Deployment
Did the classic last-day marathon:
- UI polish
- bug fixing
- physics tuning
- final tweaks to the autopilot
- zipped the build and deployed to itch.io
And then it was done.
Challenges (AKA: Every Simple Idea Is Actually Three Ideas in a Trench Coat)
Challenge #1: Making the Bot Follow a Racing Line
This was way more fun than I expected.
The racing line is just a list of points. But making the bot follow it like a human driver --- not teleport, not cheat, not solve physics separately --- was trickier.
The bot uses the exact same steering logic as the player. No special rules.
Which means:
If the physics are bad, the bot exposes them instantly.
There's still one part I want to refine: letting the bot drive from the starting grid to the start checkered line so it can seamlessly hand off control to ghost playback. Right now there's the occasional snap or jump when switching from autopilot → recorded ghost data.
Challenge #2: Effects, Skidmarks & Performance
I really didn't want to drop into WebGL or WebGPU for such a small project.
So everything is a bit of a Frankenstein, but in a charming way.
- Cars, track, and UI are all DOM elements, styled with CSS.
- Spark effects are object-pooled DOM elements with CSS animations.
- Skid marks are drawn using plain 2D canvas, except the track is divided into many 1000×1000 pixel canvases placed in a grid. I only draw on the canvas cell where the skid happens. This works, but it also introduces some visible seams between canvases.
What I learned very quickly:
too many canvases reduce FPS.
Even if they look innocent.
Challenge #3: The Engine Sound (My Favourite Part)
This was the rabbit hole I didn't expect.
I built a small engine simulator that:
- pitches an engine loop up/down with speed
- fakes gear shifts
- downshifts under braking
- handles acceleration/deceleration smoothly
- snaps into new gear ratios realistically
It ended up sounding... actually pretty good.
This is the part of the game I'm proudest of.
It really sells the speed.
Building the Physics (A.K.A.: "I Thought I Understood Maths... Until I Didn't")
Going in, I wasn't planning to simulate aerodynamics, tyre temperatures, downforce, slip angles, or anything resembling real motorsport science. I just wanted the car to feel responsive, fast, and "F1-ish".
I actually ended up using very simple movement physics --- the same kind you'd use for flocking behaviour:
- acceleration
- friction
- a steering force
- rotation based on speed
And surprisingly... that was good enough!
The car felt tight, grounded, and fun.
Bugs (Because No Weekend Project Is Complete Without Them)
Bug #1: "F1 Train on Rails"
At one point, the turning was so tight that the car looked like it was running on an invisible track system. Zero drift. Zero slide. It turned like a robotics lab demo.
The fix was simple and elegant:
scale steering sensitivity based on speed.
Slow = more angle.
Fast = gentle input only.
Instantly felt better.
Bug #2: The Autopilot Had an Existential Crisis
The title screen features a bot driving the car automatically in a looping sequence. It's supposed to look smart and confident.
Instead, it started oscillating back and forth like it forgot how to human. It couldn't decide whether to brake or accelerate and kept stuttering at corners.
The fix?
Let the bot "look further ahead" on straights, and "look closer" when braking.
Basically: give it vision proportional to intention.
Suddenly it stopped panicking.
What I Cut (Because 48 Hours Is 48 Hours)
The biggest thing I couldn't polish fully:
the handoff between bot driving >> ghost playback.
Ghost data is recorded starting at the checkered line, which is ahead of the starting grid so the bot must drive from the grid to the exact ghost start point. That small transition is where the occasional snap happens. One day I'd love to smooth it out.
Shipping It Fast
With the deadline almost up, I prioritised:
- fun physics
- stable performance
- a working bot
- ghost replay
- track layout
- engine sound
- and just enough effects to feel satisfying
Aside from the core game systems, I also squeezed in:
- a multiplayer leaderboard
- ghost uploads to Firebase Storage
- encoded ghost data, reducing each ghost to ~3–4 KB
Then I zipped the build, uploaded it to itch.io, and called it done.
What I Learned
You don't need perfect physics to make a fun racing game.
You don't need advanced graphics APIs to make satisfying effects.
Sometimes, the constraints are what make a project fun.
Mostly, I rediscovered how joyful it is to tinker ---
try something, break something, try again, laugh, fix it, continue.
That's the whole point of coding for me.
Try It Out & Tinker Yourself
If you want to see what a tiny 48-hour F1 experiment looks like:
Play Lap Legends
https://copet80.itch.io/lap-legends
If this inspires you to build your own tiny game, even better.
Give yourself a deadline.
Take a weird idea.
And see where it leads.
You might surprise yourself.






Top comments (0)