Ten Games, One Engine
Adding a new solitaire variant here costs one configuration object. Everything else — dragging, undo, hints, scoring, saving — already exists.
Ten games is nine games too many
Klondike, Spider, FreeCell, Yukon, Russian, Pyramid, TriPeaks, Golf, Forty Thieves and Canfield are, from a player's point of view, ten different games. From a code point of view they are ten variations on a remarkably small set of ideas: piles of cards, a rule about what may be placed where, a rule about when the game is won, and a layout.
The naive way to build a site like this is to write ten games. That gets you ten separate implementations of dragging, ten undo systems, ten subtly different bugs, and a permanent tax on ever changing anything. We wrote one engine instead.
What the engine owns
Everything that is not a rule belongs to the shared engine. That turns out to be almost all of the work.
| The engine handles | Why it is shared |
|---|---|
| Layout and sizing | Every game is a set of pile positions on a board that must fit any screen |
| Drag & drop, tap-to-play | Identical interaction in all ten games; players should never relearn it |
| Undo | Snapshot the whole state, restore it. Rules-agnostic by design |
| Timer, score, move count | Same HUD everywhere, with per-game scoring rules passed in |
| Hints | The engine asks the game "what is a good move here?" and animates the answer |
| Saving and resuming | One serialiser for every game |
| Win detection and celebration | The game supplies the test; the engine supplies the confetti |
What a game actually is
A game, in this codebase, is an object that answers a handful of questions. How many decks? Where do the piles go? How is the initial deal laid out? Given a card and a target pile, is that move legal? Is the game won? What is a sensible hint?
Yukon and Russian Solitaire are the clearest illustration. They are the same game except that Yukon builds down in alternating colours and Russian builds down in the same suit. They share one file, and the difference between them is a single boolean passed into the same factory function.
No framework, no build step
There is no React here, no bundler, no transpiler and no node_modules in what gets deployed. The pages are static HTML, the styles are two stylesheets, and the logic is plain JavaScript modules loaded directly by the browser.
The pages themselves are generated — game pages, guides and this blog all come out of small Node scripts that read a content file and write HTML. That gives us the one real benefit of a build system, which is that shared page furniture cannot drift out of sync, without the cost, which is that nothing works until the toolchain does.
Even the sound effects avoid the pattern. Every flip, place, chime and buzz is synthesised live with the Web Audio API rather than loaded as an audio file, so there is nothing to download and nothing to license.
What it costs you to load
The practical result is a game page that is a few tens of kilobytes of markup, styles and script, plus the card images, which are preloaded on game pages so the first flip never appears blank, and cached aggressively because a deck of cards does not change.
No trackers, no advert scripts, no consent wall in front of the board. That is partly a values decision and partly a performance one: the fastest third-party script is the one that is not there.
The one thing sitting in front of all this is Cloudflare, which caches the site and filters malicious traffic. It adds nothing to the game pages. The privacy policy spells out what it sees.
Where the engine stops
The site now has twelve games, and ten of them run on the engine described above. Hearts and Spades, added in August 2026, do not, and the reason is worth saying plainly: they are not patience games.
Everything above assumes one player against a deck. Piles you drag cards between, one board state, one test for whether the game is won. Hearts and Spades are trick-taking games for four. Hands are dealt, cards are passed or bids are made, four seats play in turn, tricks are won, and scores build up over round after round until somebody reaches a target. There is no pile to drop a card onto and no single winning position. Forcing that through a configuration object designed for tableaux would have produced a worse version of both games and a worse engine.
So they share what is genuinely shared: the deck, the card artwork, the sound effects, the felt, the header, the save-and-resume habit and the page furniture. Underneath they have their own small table module, which knows about seats, a turn order, a trick in the middle and computer opponents that think about which card to play rather than picking a legal one at random. Two engines, twelve games. The rule is the same rule that produced the first engine: share what is actually the same, and stop there.
Frequently asked questions
Does this site work offline?
Partly. The pages are static and cache well, and every game saves its state locally, so a flaky connection will not lose your hand. There is no full offline install.
Do you track players?
Game state and lifetime statistics are stored in your own browser using localStorage. They are not sent anywhere, and clearing your browser data clears them.
Will you add more games?
Yes. For solitaire variants the engine is designed so that a new game is a configuration object rather than a new codebase, which is what makes adding them realistic. Games that are not patience at all, such as Hearts and Spades, get their own module instead of being forced through it.