wanessalabs games production

SlowPoker (CampPing Protocol)

Texas Hold'em for a table of friends with no signal. Every phone runs the same rules, the dealer proves the deck is fair, and a panel shows every radio message.

ReactTypeScriptTailwindVitestCloudflare Pages

The last time I played cards at a campsite, somebody had brought a deck and nobody had brought a signal. That worked fine. What did not work was the evening we had phones, a table, and no way to use one with the other.

The Problem

Every poker app assumes a server. Not because poker needs one, but because somebody has to shuffle, somebody has to decide whose turn it is, and somebody has to be trusted not to look. Put four people around a fire with no bars and all three of those jobs have nowhere to live.

You can solve it by nominating one phone as the host. Then that person can see the deck, and everyone else has to take their word for it. That is fine among friends right up until it is not, which is exactly the moment a card game is worth playing.

What It Is

No-Limit Texas Hold’em for two to eight people, played on the phones already in their pockets, with no server, no accounts, and no internet. Play money only.

Solo against bots works today. The version that talks between devices runs across browser tabs on one machine right now, and over Bluetooth once the transport underneath it exists.

Nobody Is In Charge

The interesting problem was not dealing cards. It was turn order.

My first instinct was to have one phone announce whose turn it was. That is a host again, wearing a different hat. The better answer is that turn order is never announced at all. Every phone sorts the list of players the same way, so they all compute the same seating. The dealer button is just the hand number. Whose turn it is inside a hand was already something the rules could work out.

So there are no messages about turn order. Not fewer. None.

Each player broadcasts only their own move, and every phone runs it through the same rules. If a move arrives out of turn, every phone rejects it separately. There is no referee to convince, and nothing to corrupt by convincing one.

The dealer changes every hand, following the button around the table, so nobody holds even that much twice in a row. When the dealer walks off to find more firewood, the hand voids and the button moves on. There is no host to migrate, because there was never a host.

Proving The Deck

The dealer still knows the shuffle. That is unavoidable without a lot of cryptography, so instead of hiding it I made it checkable.

Before dealing, the dealer publishes a fingerprint of the deck. Not the deck: a hash of it, which tells you nothing. When the hand ends, the dealer reveals what that fingerprint was made from, and every phone re-derives the deck and replays the entire hand from scratch. If the cards do not match what everyone saw, it is obvious, and it is obvious to all of them at once.

This does not stop somebody cheating during the hand. It makes cheating detectable afterwards, by everybody, with nothing to trust. Around a campfire that is the version that actually enforces, because the people you would be cheating are sitting next to you.

There is a control after each hand that shows you the check and its result. I built it because the guarantee is worthless if nobody can see it.

The one piece of real cryptography here nearly went wrong quietly. I reused the random number generator from my earlier poker trainer, which takes a 32-bit seed. That is fine for making a test repeatable, and useless as a promise: four billion possibilities can be searched against a published fingerprint in seconds, so a determined opponent could work out the deck mid-hand while the whole ceremony still looked rigorous. It now uses a seed large enough that this is not a race anyone can run.

Slow Is The Point

The radio it is built for carries messages about the size of a tweet, takes up to two seconds to deliver one, and sometimes delivers the same one twice. I built the whole game against those assumptions from the first day rather than discovering them later on a hillside.

Which is why a playing card is one byte. Fifty-two things fit in a byte with room to spare, and once every card costs one, an entire hand’s history fits in a single message. Written the obvious way it would have been about twelve hundred bytes and needed to be broken into pieces, reassembled in order, and resumed when a piece went missing. That is the hardest thing to get right on a bad connection, and encoding it properly meant it never had to be got right at all.

The name is honest rather than aspirational. A poker app built for a fast connection and then moved onto this one would feel broken. One built for this from the start feels slow, which is a different thing and a survivable one.

Showing The Wire

All of that was an argument I could only make in a document. So the game now renders it. Under the table sits a panel listing every message the device sent or heard: what kind it was, which direction it went, and how many bytes it actually took. A deal commitment is 35. A fold is 6. A whole flop is 8.

I nearly built the easy version, a readable log of “Bo raises to $1.50”, and it would have been free because the game already holds that list. It would also have shown nothing the table above it was not already showing. The interesting thing about this game is not that people take turns. It is that a card table fits down a pipe this narrow.

Two rules keep the panel from being decoration. A byte count is never estimated: it is the length of the buffer the encoder actually produced, recorded after the transport accepted it. And playing solo, where there is no radio and nothing is transmitted, the panel says so in those words rather than letting an arrow imply a connection that is not there. It still runs the real encoder, which is the part that pays: a message too fat for the radio now fails while I am playing alone against bots, instead of on a hillside with no way to debug it.

Writing it also caught me overstating my own work. Two numbers I had written down as facts turned out to be one number each where the truth needed two, and the panel put them on screen next to the documents that had them wrong.

What I Learned

The bug I am most glad I found was one no rule could catch. A player could send a move on somebody else’s behalf, and every check passed, because the move itself was perfectly legal. What was forged was not the action, it was who made it. Rules can tell you a fold is allowed. Only identity can tell you it was yours to make.

The other lesson was about my own certainty. I opened it in a browser and the screenshots kept timing out, so I spent a while hunting an infinite loop that did not exist. The page was healthy the entire time; the screenshot tool was not. What that detour did turn up was real, though: not one of my tests had ever rendered the actual game, only its pieces. So a green suite had never once answered the question of whether the thing plays.

The newest lesson is that a test can be exhaustive and still be worthless. I wrote one to prove the new panel never shows a card its viewer should not see, and it checked all fifty-two of them, and it passed while the code was leaking every single one. It was searching the log’s text for a card written as “2c”, and a leaked card is not text, it is an object. Both things were called a card and neither could see the other. The only reason I found out was that I broke the code on purpose to watch the test fail, which is now the only way I trust a test that has never failed in front of me.

On The Hub, With A Caveat

It shipped hidden. The tagline said it worked offline with friends while you are camping, and Bluetooth does not exist yet, so on a public grid that sentence would have been a promise the game could not keep. It sat at a URL with no card anywhere, reachable only if you knew it was there.

It has a card now, in a section at the very bottom marked experimental, and the card no longer says that. It says you can play the bots today and that Bluetooth is still being built, because a hedge in a section title is not a licence for the thing underneath it to overclaim. Both halves of that are now tests: one fails if the old sentence comes back, and one fails if the caveat quietly disappears. Copy drifts. A rule written only in a comment drifts with it.

It is live. Which is a strange thing to ship: a game whose headline feature does not exist, sitting on a public grid, saying so in its own description. I think that is the honest version of shipping early. The alternative was leaving a finished game at a URL nobody knew, waiting on a radio, for the sake of one sentence I could have rewritten in a minute.

Not Included

No accounts, no server, no ads, no tracking, no network of any kind.

No real money, no buy-ins, no cash-out, no currency of any sort. The chips are play money and they reset.

No streaks, no notifications, no reason to come back tomorrow. And no clock: no countdown, no auto-fold, nothing that turns thinking for a moment into a loss. This is a game for people who are already sitting down together, and the whole point is that there is nowhere else to be.

Development timeline

1 logged update on 10 Aug 2026.

  1. Play Texas Hold'em with no signal in SlowPokerlaunch

    No-Limit Hold'em against bots, with no server and no internet. Check after every hand that the deck was not rigged, and watch a panel show each message the game would send, down to the byte. Bluetooth play is still being built.

Written from the release notes published with each update, not afterwards. See every project →