Authoritative, turn-based multiplayer sessions on Cloudflare. The server holds the game state no client can be trusted with, resolves it, and writes a durable result to your own D1.
@pithy-sh/multiplayer
pithy add multiplayerThe server holds the game state no client can be trusted with, resolves it, and writes a durable result you own.
The session is the same for every game; what a game is lives behind a game model, resolved by kind. Three ship as examples, and you can register your own.
What it sits on
Pithy's first Durable Object. Adding it wires the DO binding and its class migration tag into wrangler.jsonc for every environment; a migration creates the result table.
A session holds hidden per-player state, an alarm-driven deadline, and a one-way publish to the leaderboard when it ends.
The honest bit
This is authoritative session infrastructure for games where a turn resolves discretely — board games, card games, wagering tables. It is not a tick-rate netcode layer for a shooter, and no amount of configuration turns it into one.
If you build it yourself
The rule is simple: never trust the client. Everything after that is the work.
Two clients acting at once must serialize somewhere. A Durable Object is that somewhere, and it is why this is not a table.
Each player sees their own hand, not everyone's. That has to be true on the server, not in the UI.
A player who walks away must not stall the game, which means an alarm, a timeout policy and a defined result.
The same player returning to the same session, with the same view, after their phone slept.
When it ends, something has to be written down — and published to a leaderboard exactly once.
pithy add multiplayerComposes with
In the dashboard
Live sessions, their membership, and the durable results they wrote.
The dashboard is the admin interface for your own application: whatever this capability writes, your team can look up, check and act on from a browser. Reading is free, forever, with no time limit. Connect the project when you deploy.
Everything else
Each one composes the same way. Nothing you skip costs you anything.
Designed, not shipped
Written down, argued out, and not built yet. Each one links to the issue it is being designed in, so you can read the reasoning or disagree with it.
One command installs the package, wires its bindings into every environment your project declares, and runs its migrations.