A Dumb Relay

January 3, 2026 by Farms

In the last post I landed on a "relay" shaped architecture for input replication. A central server that accepts inputs from players, orders them, and broadcasts them back out.

So what does that relay actually do? As little as possible.

One relay for all games

Back to the challenge goals - I want to make 52 games without deploying 52 servers. If every game needs its own custom server with game-specific logic, I'm going to drown in infrastructure toil which will suck the fun out of everything. The relay can't be game-specific if this is going to work.

A game-agnostic relay can only handle the bits that are the same for every game: managing sessions, collecting inputs, building ticks, replicating them to everyone.

Everything game-specific will happen elsewhere. The relay is deploy-once infrastructure, not game logic.

So what are our games always going to need?

  • Input replication
  • Player authentication
  • Session management

Input log replication

This system is designed around the idea of all the players having an identical copy of the list of inputs for each tick, and applying them to a deterministic game simulation to compute the state. Missing data or out of order data would lead to fatal desync of player state.

I want players to be able to drop-in/drop-out easily from these games, so there's no guarantee that a later joining player will have "old" inputs.

So the primary role of the relay is not only to disseminate inputs to players, but to maintain a persistent ordered log of inputs ready for any player to request the full or partial history for the session.

Player authentication

We need to know whose inputs are whose, and have some way of preventing players from spoofing each others inputs. It wouldn't be much fun if it was too trivial to just tell the relay to move your opponent.

However, I really don't want to build a user authentication system with logins. I really want the relay to stay pretty stateless (other than the input log).

My current hand-wavey plan is to build around the idea of players sharing a public key as their "id" and cryptographically signing their inputs as a simple way to achieve this. I'll dig into this in another post I think.

Session management (aka: Match-making)

Games need to be able to find and connect players together otherwise it's going to be pretty lonely.

The "match-making" topic could get messy, but for our requirements we really just need the ability for clients to generate a globally unique id and connect to the session. Any players who connect using the same id will be replicating the same log.

Since I'm focusing mostly on quick ".io" style games with fixed session lengths where everyone joins the same "current" session, I believe there's a fairly simple method for clients to indepentantly calculate an id for the "current" session based on something like a hash of a timestamp + game id or something like that. Again I'll dig into this at a later date, but it seems feasible and would reduce the complexity of needing a stateful API for game sessions/rooms.

Prior art

Colyseus

There's actually something a little similar to this game-agnostic model out there: Colyseus.

Colyseus is a state-replicating multiplayer framework that provides:

  • Authentication - identifying players
  • Match-making - connecting players
  • State sync - netcode for state replication

Honestly it looks pretty good! If I was actually trying make a successful browser game I would probably just use it. But we're not here for that, we're here to make our own questionable decisions and mistakes.

It's great that there is something out there as (1) it validates that I'm not totally crazy, and (2) allows us to compare the differences between the approaches.

The biggest divergence is that Colyseus is built around a State Replicating system and the Multitap Relay is an Input Replicating system.

In Colyseus you define a schema for your game session's state, and are provided an API to connect to a session, mutate the session's state, and sync a local copy of the state.

In Multitap you are provided an API to connect to a session, and sync a copy of the input log, and then clients will locally compute their copy of the state.

Cool so far doesn't sound too insane.

NATS

This design is basically a specialised message broker - like a tiny Kafka or NATS JetStream - but for game sessions.

In NATS you create topics, publish messages, and subscribe to receive new messages published to that topic.

The NATS "JetStream" feature builds on that to provide a durable persistent history of everything published to the topic, allowing fetching messages from the past.

This sounds a lot like what we are designing.

Similar to above, if this wasn't a hobby project where I explicitly want to build out stuff myself, I would probably build around NATS. You can even embed it into a Go application making it easier to distribute non-HA versions. Hmmm maybe I should just use it heh.

Key properties borrowed from the log-based messaging world:

  • Durable: The stream persists to disk. Crash recovery, session resume, client healing.
  • Replayable: Any client can replay from any point. Join late, reconnect, fill gaps - same mechanism.
  • Ordered: The relay establishes canonical ordering. No distributed consensus needed.

Replay, late-join, and packet-loss recovery aren't separate features - they're all just "read from the stream".

Photon's Quantum & Realtime

Quantum is a commercial deterministic multiplayer engine. It is based around an Input Replication model similar to our design.

In Quantum, input exchange is managed via game-agnostic server logic.

The Quantum client library communicates with Quantum server and runs local simulation, performing all input prediction and rollbacks.

Sound familiar.

Quantum (like Colyseus) provides the generic building blocks to base your game around. Only Quantum (like what we are building) is based around an Input Replicating deterministic execution model.

Other than being a commercial product designed to meet the needs of real commercial games, it seems the main divergence of design is in the platform targeting. The Photon suite of products target tight integration with commercial game engines like Unity and Unreal, whereas like Colyseus we want to target exclusively the web platform.

One deployment, many games

It's becoming much clearer what shape this framework needs to take after that little exploration. So here's some elevator pitches to myself to guide me:

  • Multitap is like a mini Quantum for web-based games
  • Multitap is like a diet Colyseus but based around input-replication rather than state-replication
  • Multitap's Relay is like a message broker for input log replication for session based games.