Dev.to WebDev πŸ›  Dev πŸ‘ 0 πŸ“– 3 min read

How I keep a multiplayer browser city alive with zero players online

I'm a solo dev from Uruguay building Balak City, a multiplayer open-world city that runs in the browser: one shared city where everyone walks, drives, runs missions and buys businesses at the same time. It's plain JavaSc

How I keep a multiplayer browser city alive with zero players online

Night render of the Balak City map

I'm a solo dev from Uruguay building Balak City, a multiplayer open-world city that runs in the browser: one shared city where everyone walks, drives, runs missions and buys businesses at the same time. It's plain JavaScript and Canvas 2D, no engine.

The question that shaped the whole architecture was simple: what happens to the city when nobody is online?

The problem

In a lot of browser multiplayer games, the first player to join a room becomes the "host" and simulates the world for everyone. That works until:

  • the host is on a cheap phone and the whole city stutters for everyone,
  • the host switches tabs and the browser throttles their timers,
  • the host leaves and the world freezes or resets.

For a city that's supposed to feel alive (traffic, pedestrians, police, factories producing goods), none of that was acceptable.

The solution: a headless player that never leaves

The city is simulated by a headless copy of the game itself, running on a small VPS:

  • The game client is a single HTML page. The server runs that same page in a headless browser with a special key in the URL that tells it "you are the host".
  • That page simulates cars, pedestrians, police and the economy, and broadcasts the state to the room.
  • Real players connect to rooms on Cloudflare Workers + Durable Objects, which relay state between the host and everyone else.
  • A tiny systemd service keeps the headless page alive and restarts it if it crashes.

The nice part: there is only one codebase. The host is literally the game, so every gameplay change automatically applies to the simulation too. To ship new code to the host without SSH, there's an authenticated endpoint that tells the headless page to reload.

Day render of the city

Bugs I didn't expect

Two hosts fighting over the same city. During a deploy, the old host and the new one were briefly alive together, both broadcasting different versions of reality. Cars teleported, missions duplicated. The fix was making the host role exclusive at the room level, so a second host is ignored until the first one is gone.

Leaks that only show up after days. Bikes and cars spawned for missions far away from any player were never cleaned up. With real players this never mattered because sessions are short; a host that runs for a week accumulated thousands of them. Every spawned object now has an owner and an expiry.

Hidden tabs. When a player minimized the game, the host removed their character after 15 seconds of silence, so coming back put them somewhere else. The fix was to separate "this player is hidden" from "this player is gone".

Measuring smoothness from real players

Each client sends a small performance summary every 20 seconds (FPS, frame time percentiles, worst frame, ping, data arrival gaps, reconnects). With two players in different countries you can compare their timelines: if both drop at the same moment, it's the server or the game; if only one drops, it's that player's device. That simple correlation has saved me hours of guessing.

The renders

The images in this post are Blender renders generated from the game's map data with Python scripts (roads, lots, buildings, cranes, the stadium, the airport). In the game you see the same city top-down. It started as a way to make promo images, but it also exposed layout mistakes I never noticed from above.

Try it

It's free and runs on PC and phones: https://balakapp.win/?utm_source=devto

I'd love feedback on performance on your device, and I'm happy to answer questions about the host setup in the comments.

πŸ“° Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.