Self-hosted game server
HomeLab Kart
A party kart racer I wrote from scratch and run on my own hardware. Play it solo right here in the browser, or put it on a TV and let everyone's phone become a controller.
Why build this?
Most of this site shows services other people wrote, running on my server. This one is different: the game, the server and the netcode are mine. It exists to answer a question — can a second-hand office PC in my living room host something interactive for a room full of people, with nothing to install?
It can. The whole thing is one small Node process in a container, sitting next to Pi-hole and Jellyfin on the same box.
Two ways to play
Solo, from anywhere
Three laps against three AI drivers. The entire race runs inside your browser, so distance from my server makes no difference to how it feels.
Party, in one room
A TV shows the race, up to four phones scan a QR code and become controllers. Quick races or a championship across four circuits.
What's in the game
Four circuits
Palm Island, Forest Loop, Snow Ridge and Neon Circuit — each with its own theme and layout. A championship visits them in turn.
Three kart types
A trade-off between top speed, acceleration and grip. Everyone picks their own before the lights go out.
Items
Boost, a banana to drop behind you, and a bolt that slows everyone else down — collected from boxes on the track.
Championships
Three or five races, points for each finish, running standings between races and a champion at the end.
How it works
The interesting decision was where to run the physics. Proper online racing needs an authoritative server with prediction and reconciliation — weeks of work and a long tail of bugs. But a party game has one screen and everyone in the same room, so none of that is necessary: the screen runs the simulation and the server is a message relay. That one choice turned the hardest part of the project into a hundred lines.
TV / laptop ──── runs the game: physics, rendering, race rules
▲
│ WebSocket
Node server ──── rooms + input relay (containerised on ZimaOS)
▲
│ WebSocket
Phones ──── controllers only, they render nothing
Every sprite, texture and track surface is generated in code at load time — there is not a single image file in the project. It keeps the container at a few megabytes and means nothing has to be licensed.
How it was built
Driving feel first
One kart, one track, keyboard. If the driving was not fun, nothing else would matter — so nothing else got written until it was.
The loop
QR code on the screen, phone becomes a steering wheel, kart moves. The moment this worked the rest was just content.
Racing
Countdown, laps validated by checkpoints, live positions, finishing order, and the first items.
Championships
Several races, points, standings between rounds, a champion screen.
Content as data
Tracks and karts moved into plain data, so a new circuit is one entry in a list rather than a change to the engine.
Containerised
Packaged as a Docker app and installed on ZimaOS, where it sits beside every other service on the box.
Give it a go
Three laps, three opponents. No install, no account.