Durak — six cards each, and somebody has to lose.
The classic game, played against bots, with friends who have your code, or around one screen in the same room. The rules live on the server and only on the server, so a client has nothing to argue with — and a card game on an authoritative server turns out to be a privacy problem before it is a rules problem.
Hand privacy
The hard partThe room's state contains every hand at the table. Synchronise it naively and each player is shipped everyone else's cards — invisible on screen, and perfectly readable in the console.
Hiding a hand in the interface is not hiding it. The fix has to happen before the bytes leave the server, and it cannot be a hand-rolled filter in the broadcast path, because every new field added to the room state is another chance to forget one. So the state schema itself declares what each seat is allowed to see, and the framework filters every patch per client on the way out. A player receives their own cards and the public table; the other hands are not withheld from the UI, they are never sent.
The room
Rooms are attached to the same HTTP server as the API rather than run beside it, which keeps one process, one port and one certificate. The cost is a routing subtlety worth writing down: a room socket connects to two path segments at the root — the same shape as a single-page route like /play/:code. A proxy cannot tell them apart by path, so the connection is routed by its upgrade header instead.
Realtime rooms and the REST API share a server, so there is no second deployment to keep in step and no second certificate to renew.
Because a room path and an app route are indistinguishable, routing switches on the handshake rather than the URL. It is documented before it is changed.
Play now deals you in against three bots — easy, medium or hard, and one takes over a seat that drops. Otherwise join a friend's code, put the table on a TV, or take a story table, which waits for its one human rather than filling the seat. Guests play without an account; signing in is what starts counting your games.
The Long Night
Story modeA random table teaches you nothing in particular. Twelve fixed ones, played in order, can: each seats named regulars at a set deck and variant, opens with a scene and closes with another, and asks for something harder than the usual bar — not to avoid being the fool, but to go out first. A table moves either the opposition or the rules from the one before it, never both, and a test fails if one moves both.
The six now play as differently as they talk. The Colonel will not spend a good trump cheaply; the Undertaker piles on once the deck is gone; the Apprentice throws trumps in and never transfers. A briefing names each one and how they play, in all three languages.
A story table has one human seat, no spectators and no takeover bot: leave, and it waits. The seed and every move are saved as you play, so a table interrupted by a deploy is dealt back exactly where it stood, for a week.
Signed in only — progress belongs to an account, so a guest has none to keep. The first three tables are free; the remaining nine wait behind a Campaign Pass that is built but not yet on sale.
Build
As deployedDeal yourself in and check the console.
Guests play without an account. The other hands are not in the payload — that is the whole claim, and it is inspectable.