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.

Party mode sends every steering input through the server, so it is at its best when the phones and the screen share a network. Over the internet it still works — it just picks up the latency of the round trip.

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
Phaser 3 Node.js WebSocket (ws) Docker ZimaOS Procedural pixel art

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

0

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.

1

The loop

QR code on the screen, phone becomes a steering wheel, kart moves. The moment this worked the rest was just content.

2

Racing

Countdown, laps validated by checkpoints, live positions, finishing order, and the first items.

3

Championships

Several races, points, standings between rounds, a champion screen.

4

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.

5

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.