DOMINION
The server owns the only true board.
A real-time, server-authoritative multiplayer property-trading game for 2 to 8 players. Buy 59 countries, build houses and hotels, run live auctions, and bankrupt each other on a 72-tile board — rebuilt on a pure deterministic engine so every match is provably fair and replayable.
2–8 players · provably fair · byte-identical recoveryOnline board games break four ways. DOMINION fixes all four.
The client is trusted to compute state
One authoritative server owns the only true board
Dice and money live on the client
Seeded, server-side dice; money never touches the client
One dropout freezes the whole table
Reconnect, plus an optional per-turn timer
40 tiles, 28 properties
72 tiles · 59 countries · 20 tiers

Nobody owns the truth.
Online board games desync, because the client is trusted to compute state. They are cheatable, because the dice and the money live on that same client. They stall the moment a player drops. And the classic board is small — 40 tiles, 28 properties.
DOMINION fixes all four at the root. One authoritative server owns the only true board. Dice are seeded and rolled server-side. An optional turn timer keeps a dropout from freezing the table. And the board grows to 72 tiles, 59 countries, and 20 tiers — until every street owns the world.
Four parts. One source of truth.
Engine
pureapply(state, action) returns the next game — zero side effects. Pure reducer + seeded dice means the whole match is a deterministic replay.
Contract
ZodEvery message is Zod-validated on the way in. The wire is the schema; nothing malformed ever reaches the engine.
Server
authoritativeFastify + Socket.IO, one gate: rate-limit → validate → force identity → apply → broadcast. The client is never trusted.
Web
render-onlyThe client only renders server state. It computes nothing that matters, so a desync is not even representable.

Every street is a real title deed. The rent ladder climbs exactly as the deed says — 72 properties, until every street owns the world.
Real-time authoritative multiplayer — no client trust, no desync. One server owns the only true board and broadcasts it to everyone.
Live auctions the instant a property is declined, every bid validated server-side.
Houses to hotels with real title-deed rent ladders — the rent climbs exactly like the deed says.
Deep trading — cash, property, and jail cards, swapped atomically or not at all.
Never stalls — reconnect mid-match and an optional turn timer stops one dropout from freezing the table.
Provably fair and crash-proof — seeded dice, an event-sourced action log, and byte-identical recovery.
Client
Server
AI
Data
- Pages
- Store · Zustand
- Components
- Renders server state only
- Zod schemas
- Every message validated
- The wire is the schema
- Gate: rate-limit → validate → identity → apply → broadcast
- Rooms
- Auth · HMAC
- Turn timer + kick
- Observability · pino / Prom / Sentry
- Pure reducer · apply(state, action)
- Seeded RNG
- 72-tile board
- Drizzle + Postgres
- ActionLog · event-sourced
- Snapshotter
- Recovery · byte-identical
No client trust. No desync.
- One authoritative server, the only true board.
- Seeded server-side dice — provably fair.
- Event-sourced log — byte-identical recovery.
I made the client stop lying.
Every online board game I played eventually desynced, or let someone nudge the dice, or froze the moment a friend’s phone died. The bug was never the game — it was the architecture. The client was allowed to compute things it had no business computing.
So I rebuilt it around a single idea: the server owns the only true board, and the client only draws it. A pure engine, a validated contract, seeded dice, and an event-sourced log. Because the whole match is a deterministic replay, a server can crash and come back byte-identical from Postgres.
No AI, on purpose — every number is auditable, nothing hides in a black box. It is a small game with a serious spine, and I would run a tournament on it tomorrow.
TAKE THE TABLE
Want to see a full match, or help build it out? Book a live demo, or bring ideas and pull requests — the engine is open to contribution.



































