Pixel Perfect Poker
A six-player No-Limit Hold’em Sit & Go with proper side pots, AI opponents that think using simulations, and a card deal that has to stay secret.
- Role
- Format
- 6-max NLHE Sit & Go
- Opponents
- 5 AI personalities
- Stack
- Multiplayer
- Firebase RTDB, host-authoritative
- Deal
- crypto.getRandomValues
01The Game
Pixel Perfect Poker is a single-table No-Limit Hold’em tournament with a retro pixel-art look. You play against five AI opponents, each with their own personality, or against your friends in a multiplayer room.
It’s the odd one out in the arcade. There are no odds, no payout multipliers and no house edge, because there’s no house at all. Chips only move between the players. Every other game creates a number that has to be checkable afterwards, but this one creates an order of cards that has to stay secret.
Secrecy over audit
If the seed were published, anyone could work out the whole deck. So the cards are dealt using the browser’s cryptographic random number generator instead.
Side pots, correctly
Pots are built up in layers based on how much each player has put in. Uncalled chips are returned, and any odd leftover chips go to the earliest seat.
Bots that don’t cheat
The bots only use information that every player can see. When they estimate their chances, they simulate the cards they can’t see rather than peeking at the real deck.
02Screenshots
These screenshots were captured straight from the game. Tap any of them to see it bigger.





03Core Loop
- 1
Deal
A newly shuffled deck is used for every hand, and the blinds are posted.
- 2
Betting
Betting happens pre-flop, on the flop, on the turn and on the river, following the minimum raise rules and giving the big blind its option.
- 3
Runout
When players are all in, the rest of the board is dealt out automatically.
- 4
Showdown
Hands are scored, side pots are paid out and the winning five cards light up.
- 5
Next level
The blinds go up every six hands until one player has all the chips.
04Key Features
A complete rules engine
It handles minimum raises, short all-ins that don’t reopen the betting, split pots, the wheel straight, heads-up blinds and players being knocked out.
Five personalities
Viper plays tight and aggressive, Luna loose and passive, Dmitri is the rock, Sasha is the maniac and Kane keeps things balanced.
Ten blind levels
Everyone starts with 2,000 chips, and the blinds go from 10/20 (100 big blinds) all the way up to 500/1000, which makes sure the tournament always finishes.
Multiplayer rooms
Firebase rooms with invite codes, showing who’s online, with the host sending out the game state and players’ actions queued up.
Pixel art with no images
Cards, chips and avatars are pixel images drawn as SVG, and every sound is chiptune generated in code.
Practice table & rankings
A practice table that walks new players through the basics, and a chart of hand rankings you can open during the game.
05The Maths
There’s no house edge to price here. The maths in this game is all about ranking hands, splitting side pots and estimating how likely an opponent is to win.
A hand as one integer
Each hand is turned into one number: first its category, then five tie-break ranks packed together in base 15. Comparing two hands is then just a matter of checking which number is bigger. The best five cards out of seven are found by checking all 21 combinations, and the wheel (A-5-4-3-2) is handled as a special case.
Pre-flop: the Chen formula
The bots rate their starting hands from about −1 to 20 (A-A is 20, K-K 16 and A-Ks 12). Below 8 big blinds they switch to going all in or folding, and they open with raises of 2.2 to 3.2 big blinds, plus one more for every player who just called.
Post-flop: Monte-Carlo equity
The bots run 130 quick trials, dealing random hands to up to three opponents from the cards they can’t see using a partial Fisher-Yates shuffle. That gives a margin of error of about 4.4%, which makes the bots misjudge situations a bit like real people do.
Personality in every threshold
Three settings, loose, aggr and bluff, shape every decision. Sasha will open with a hand rated at 0.36, while Dmitri waits for 0.457.
Two RNGs by design
Anything that decides which cards come out uses crypto.getRandomValues with a proper Fisher-Yates shuffle. Math.random is only used for small cosmetic variations in how the bots behave.
06Under the Hood
Engine owns the rules
A strict, step-by-step phase machine handles dealing, betting, pots, the showdown and the blinds. React only controls the pacing and the animations, which meant I could test the engine without any visuals at all.
No game server
The lobby and room details are stored in the Firebase Realtime Database. During live play, the host’s game is the one in charge, and other players’ actions are sent to it through a queue.
Assets as code
Because the pixel art is SVG and the chiptune is generated with WebAudio, the game doesn’t need a single image or audio file.
Honest notes
Using buf[0] % n introduces a tiny bias, about one part in 100 million for a 52-card deck. It makes no difference in play, but I wrote it down rather than hiding it.
07Challenges & Solutions
08Results & Takeaways
- A complete poker engine running in the browser, covering betting rules, side pots and split pots, the wheel straight, heads-up play, rising blinds and knockouts.
- A review confirmed that the crypto RNG and the Fisher-Yates shuffle are both correct, and that the randomness that matters for fairness is kept separate from the cosmetic kind.
- Next up: dealing the cards on the server, and committing to the deck order before revealing it, so friends can play each other for real.
What I learned
- Using two random generators is a deliberate design choice, not a shortcut.
- A game with hidden information can’t use the same fairness approach as a game without it.
- AI that feels human is mostly about getting the amount of imprecision just right.