Essay record

Building a Multiplayer Game of Life with Rust + Datastar

Record
Essay / / 3 min read / 851 words
On this page5 sections / +

DISCLOSURE: Some links may be affiliate links. Details

Last week I built and published a multiplayer Game of Life with Rust + Datastar. You can play it on my Labs Server.

In this post we'll walk through a bit about how it works.

What is it?

A multiplayer Game of Life hosted on my Labs Server.

  • A shared Game of Life session that runs in memory and resets when the server restarts
  • A player can choose their color and the shape they want to add to the board
  • Clicking adds it to the board
  • The game simulates the game of life
  • All players get the game state synced to them

Why build it?

I've been a longtime fan of Hypermedia Systems with tools like HTMX and Datastar. Like seriously I wrote several posts about building with these tools in this paradigm:

So of course I saw Anders Murphy's Game of Life in Clojure and wanted to build my own using my current favorite stack - high-level Rust.

How it's built

Game of Life stack: Rust and Axum backend connected to an HTML and Datastar frontend

Game of Life broadcast: a shared board renders the latest HTML snapshot and streams it to multiple Datastar browsers

The system basically works like this:

  • Simulation: A single game manager simulates the 50x50 board with a tick every 200ms. It renders a new HTML snapshot only when the board changes.
  • Player actions: Clicking sends a POST with the cell coordinates and the player's color, shape, and orientation. The server inserts that shape into the input queue to be rendered in the next simulation tick.
  • Subscribers: When a player opens the page, Datastar opens an SSE connection. The handler subscribes to tokio::sync::watch, sends the current snapshot immediately, then streams changes.
  • Delivery: Each update contains the full 50x50 board of HTML buttons. Datastar patches the board container, leaving the color and shape pickers alone. The stream uses Brotli compression when the client supports it.
  • State: The board is shared within one server process. It runs even with no viewers, but resets on restart. Separate server processes would have separate boards.

Is this efficient?

Not particularly. But it's also not that inefficient for my purposes - a small demo expected to be used by < 10 ppl at a time.

  • Bandwidth usage: If each compressed update were 8 kB, then 5 updates per second would use 8 kB × 5 × 60 = 2.4 MB / minute per player, or 144 MB / hour. With 10 players that's 24 MB / minute. 2.4 mb is about the size of a large embedded web image so not that bad to serve to each player each minute.
  • Server: The simulation evaluates 50 × 50 × 5 ticks / second = 12,500 cells per second, each checking up to 8 neighbors. We only compute the simulation tick once before sending out to subscribers. One sampled uncompressed HTML event was about 0.71 MB and is shared across every subscriber. So yeah a decent number of calculations but these are all simple boolean checks and cached / shared across subscribers so they mostly don't grow with users aside from connection overhead.
  • Client: A bit heavy handed to send HTML for 2,500 buttons on every changed snapshot. Compression saves bandwidth but the browser still has to decompress and process that HTML to update the board. But all in all not hard for modern computers / browsers to do.

So yeah a bit heavy to run a game like this but it's reasonable on basically any system built this millenium. If this ever does get wide usage may move to a small canvas drawn version and just send down game state deltas but we likely won't hit that.

Plus I'm running my machines on Hetzner so outbound bandwidth is pretty cheap so I don't mind too much. You can compare hosting options with CloudCompare.

Next

So that's my multiplayer game of life with Rust + Datastar.

If you're curious about building high-level webapps with Rust, I've got a few posts onthe subject and I built CloudSeed to make spinning up a simple scalable fullstack webapp in Rust super easy.

If you liked this post you might also like:

Built with CloudSeed Rust