How we built Mau-Mau
A card game where the whole design falls out of one sentence: a hand is a secret. Why the client decides nothing, the deck lives behind a lock, and two card packs share one grid.
Checked against the sources on 2026-08-30
One sentence decides everything
Mau-Mau is the second game built as a package on the engine’s host SDK - same five imported interfaces as boxing, same "not an XP, no level, no document" stance. But where boxing hands authority to the clients, this game hands them nothing, and the reason fits in a sentence: a hand is a secret.
A fighting game gives authority to the client because the alternative loses to lag. A card game cannot, because the alternative loses the game: whoever holds the deck can read every hand, and a client trusted not to look is a client that did not need the secret kept. There is no version of this game where the deck lives on somebody’s machine and the game is still worth playing.
Every design in the package follows from that. Boxing has five message types on three schedules; this game’s wire is one nudge carrying a number. Boxing predicts its own punches; this game predicts nothing, because it need not. Boxing uses no randomness; this game uses the platform’s, never a seeded stream a client could replay.
The build, in the order it happened
Cards and table rules, pure
What a card is, what a pack is, what a legal move is - values in, values out, no browser, no network, no clock. `bun test packages/maumau` plays whole hands in microseconds. Same argument as boxing, same payoff: the rules are trusted because a test plays faster than a human ever could.
Decide which Mau-Mau you are building - as data
Everybody thinks their Mau-Mau is the only one: do sevens stack, what does the jack do, how does the last card go out. Those are house rules, and they are settings - the thing boxing explicitly refused to have. The difference is symmetry: retuning a punch helps whoever throws it, which is one player; sevens stacking is the same game for everybody. There is no house rule one seat benefits from.
And they are pinned at the deal and refused afterwards - not because changing them mid-hand would be unfair, but because it would be incoherent: turning stacking off with six penalty cards owed is a state the rules have no answer for.
Watch out: Settings that are asymmetric are not settings, they are an unfair match. Sort every option by who it helps.
Run the whole game where no player can reach
The entire table logic runs once, at the arbiter, and every client is handed back a redaction: your cards in full, everybody else’s as a number. The client cannot cheat because the client does not know anything worth cheating with.
Teach the same rules to two authorities
The package teaches the whole of Mau-Mau to an in-memory arbiter, so four memory hosts in a test are four players who cannot decide anything for themselves - the same property the real authority has, expressed in a Map and provable in microseconds. The real one is a database function, because the production requirement is a lock: two players pressing a card in the same tick both read the same turn, and only one of them may have it.
Watch out: The test authority and the real authority must implement the same rules against the same state shape - or your tests prove a game you are not shipping.
Two packs, one grid
The game ships two card looks: hand-drawn faces that fill a 552x752 frame with smoothing, and 64x64 cards from 1993 that must be drawn pixelated or they are a smudge. They agree about almost nothing - except the grid, because the atlas builder insists on it: rows are the four suits, columns run A, 2…10, J, Q, K. So the cell-lookup is written once and neither finish appears in it.
And a finish is deliberately not a house rule: the authority pins rules because a table must play one game, but two players looking at two different card backs are still playing the same hand. What changes nothing anybody can be refused for does not belong in the pinned settings.
The words in the code
- Arbiter
- Here: the whole game. The only thing at the table allowed to see a hand.
- Seen
- The redaction a client receives - own cards in full, all others as counts.
- House rules
- Which Mau-Mau: symmetric settings, pinned at the deal, refused afterwards.
- Finish
- Which card art draws the table - per player, and deliberately not a rule.
- memoryHost / MemoryArbiter
- The test-side host and authority that make four players out of a Map.
What we would tell ourselves at the start
- Name your game’s one deciding sentence early. Ours was "a hand is a secret", and it answered every later argument.
- Authority is per-game, not per-platform: the same SDK carries a client-authoritative fighter and a fully authoritative card table.
- Randomness a client could reproduce is a hand a client can read.
- Concurrent turns need a lock, not a convention - two presses in one tick will happen on the first real evening.
- Keep cosmetics out of the rules object, or every skin becomes a rules negotiation.
Read the real thing
- packages/maumau in the repositoryThe arbiter header is the argument in full; the migration beside it is the lock.
- How we built the boxing gameThe same five interfaces handing authority the other way.
- The XP editor guideThe document-shaped way to build on the engine.
This is a map, not legal or tax advice - and an honest one about how it was drawn: the Germany guide was written by a person who walked the route; most other countries were drafted with AI against the official sources and have not yet been walked by someone who did it. Laws change. Every guide carries the date it was last checked and the sources to check it yourself - and if you have been through one of these routes, your corrections are exactly what this handbook wants.


