Klondike solitaire with nothing in the way: no ads, no accounts, no server. It is a static page that installs as an app and plays offline. The part that matters is one TypeScript solver, which runs at build time to pick the deals and in a Web Worker at runtime to answer the question every solitaire player eventually asks: can I still win this?

A Klondike table mid-game on a dark, warm leather table: a Deco card back on the stock, hearts and clubs foundations started top right, seven tableau columns of cream cards with large corner indices, under a floating glass toolbar with a mono score readout and a three-dot table switch
Fig. 1 Ninety moves into a draw-one deal on Studio, the default table. The score floors at zero because this line recycles the stock.Screenshot of solitaire.lukeghanna.com at 1440×810, 29 September 2026. The deal is from the bank; the moves were fed in from the solver's own solution through the app's test hook.

Every deal is proven winnable

Random Klondike deals are sometimes impossible, and a player cannot tell a lost deal from a lost game. So there are no random deals. A 32-bit seed drives a mulberry32 generator and a Fisher–Yates shuffle, so a seed fully determines a deal, and a build script solves seeds across every CPU core until it has 2,000 winnable ones for each draw mode. The banked solutions run 118 to 261 moves in draw one and 101 to 189 in draw three.

A new game picks a random banked seed and skips the last 200 the player has seen. Solutions are not stored: the solver is deterministic, so the tests re-solve banked seeds with the bank's own node budget and replay each solution through the engine to a win, a sample on every run and all 4,000 on demand.

The guarantee has one stated limit. The solver assumes unlimited passes through the stock, and Vegas scoring allows one pass in draw one and three in draw three, so the settings say plainly that a Vegas deal may not be winnable.

One solver, three jobs

The search is a depth-first search with a transposition table. Its state key sorts the tableau columns, so positions that differ only in which column holds which pile collapse into one, and it encodes the stock as a position in its draw cycle rather than as two piles. Safe foundation moves are applied without branching, and stock play is folded into compound moves (draw until a given card is on top, then play it), which removes most of the branching a Klondike search wastes on the stock.

It runs in two passes. A pruned pass that only considers useful tableau moves finds most wins quickly. If it runs out of moves, a complete pass searches everything, and only a complete pass that runs out can answer "unwinnable". Running out of budget or time always answers "couldn't tell", never "lost".

Hint or Winnable?
the current position goes to the worker; input never waits
Search
pruned pass, then complete pass, within 1.5 s
Winnable
highlight the first move of the winning line
Couldn’t tell
fall back to a heuristic hint
Unwinnable
offer to rewind to the last winnable position
Fig. 2 What the in-game solver answers, and what the app does with each answer.Drawn from src/solver/solve.ts, src/solver/rewind.ts and src/ui/useSolver.ts.

The hint is the first move of an actual winning line, not the first legal move. The Winnable? button runs the same search and reports the verdict, and the check also runs by itself when the player has no productive moves left. When the answer is no, rewind walks back through the game's history: it tests the newest position first, then binary-searches the rest, since the opening deal is known to be winnable, and undoes to the most recent position the solver can prove.

The same table with a toast at the bottom reading 'Still winnable. Keep going!'
Fig. 3 The Winnable? check on the same position. The worker searches while the table stays live.Screenshot of solitaire.lukeghanna.com at 1440×810, 29 September 2026.

Nothing moves unless you move it

Many solitaire apps play safe cards to the foundations for you, and this one used to by default. Cards moving that the player never touched made the game harder to read, so auto-move is now opt-in and off for everyone, including players who had it on. With it on, a card the player pulls down from a foundation stays down: the cards held back are derived from the turn history rather than stored, so undo, redo and a reload need no extra state.

The one thing that always moves by itself is the finish. Once every tableau card is face up, the game is usually decided, but not always: draw three can bury a card in the stock, and Vegas can run out of passes. Auto-finish tries a greedy pass first (play the lowest card that fits a foundation, otherwise draw) and falls back to a short solver run that respects the pass limit. If neither finds a finish, play just continues, and it checks again after the next move. When it does fire, input locks and the cards leave one every 110 ms, each on the normal move transition, so the finish reads as a stream you can watch. The win waits until the last card lands, then the classic bouncing-card cascade plays on a canvas that is never cleared. Reduced motion quickens the finish rather than skipping it and leaves out the cascade; only the Animation: Off setting makes the finish instant.

The win cascade: cream cards bouncing off the bottom of the screen, each leaving a trail of copies of itself across the dark table
Fig. 4 The win cascade, about two seconds in. Each card leaves a trail because the canvas is never cleared. The timer reads 0:00 because the moves were fed in instantly.Screenshot of solitaire.lukeghanna.com at 1440×810, 29 September 2026, the same deal played to the end from its banked solution.

The table

There are three tables, switched from the toolbar: Studio, a warm charcoal with a leather grain and a stitched rail; Felt, green with a choice of five cloths; and Paper, a light linen. Every texture is CSS gradients and inline SVG noise, so the table ships no image files. The cards are drawn in HTML: one large rank-and-suit index in the top-left corner, where it stays readable in a fanned column, and one big pip, with no court art. The four-colour deck and five card backs, Deco by default, work on every table. Type is Geist, bundled so it works offline.

All 52 cards are absolutely positioned elements keyed by card id, and each card's position is a pure function of the game state and the layout, so every state change animates through CSS transforms with no animation code per move. A card turning face up does a real 3D flip. A card that can be picked up lifts slightly under the pointer, and tapping a card with nowhere to go shakes it and every card above it, and moves nothing. Tap sends a card to its best destination, double-tap sends it to a foundation, drag works with a five-pixel threshold, Space draws, and Enter picks up and drops, so the whole game plays from the keyboard, with every move announced to screen readers.

The Settings dialog on its Appearance tab: a live preview of a Deco card back and three cards, then pickers for the table (Studio, Felt, Paper), the card back (Deco, Amber, Ink, Oxblood, Navy), two- or four-colour suits, and animation speed
Fig. 5 Settings opens on Appearance, with a live preview above the pickers. Game and Controls hold the rules, scoring and key bindings.Screenshot of solitaire.lukeghanna.com at 1440×810, 29 September 2026.
The same position on the Paper table: a light linen background, a light glass toolbar, and the same cream cards and Deco backs
Fig. 6 The same position on Paper. Only the table and the chrome change; the cards read the same on all three.Screenshot of solitaire.lukeghanna.com at 1440×810, 29 September 2026.

The game is saved after every move as the seed plus the list of turns, and replayed on load, so undo, redo, the timer and the score survive a reload. Every read from storage is validated, settings from older versions migrate once on load, and the app still works when storage is unavailable. The sounds are synthesized with Web Audio, so there are no audio files.

On a phone

Version 1.3, on 1 October 2026, gave phones their own layout. A phone is one condition, portrait and at most 640 px wide, shared by the CSS and the layout code. Seven columns cap how wide a card can be, so on a phone the margins and the gaps between columns drop to 3 px, and the tableau fans run taller: each face-up card steps down 40% of a card's height instead of 26%. Cards show rank and suit side by side in one big index, and the waste fans wider so the whole index shows. The toolbar shrinks to a 30 px strip that only reads out the score, moves, time and draw mode, and the controls move to a thumb bar at the bottom: New, Undo, Hint, Redo and More. New opens a Game sheet (new game, restart this deal, draw one or three) and More opens Stats, Settings and Winnable?; on a phone the table is picked in Settings. Every dialog becomes a bottom sheet that closes when dragged down 80 px or flicked. The installed app locks to portrait, an install hint appears only after the first finished game, and on Android a rejected tap and a win buzz, following the sound setting; iOS Safari has no vibration.

Status

Live at solitaire.lukeghanna.com as Cloudflare Workers static assets with no Worker script, installable as an app, and fully playable offline once loaded; a new deploy takes over open tabs as soon as it installs. On an iPhone home screen it runs full-bleed under a translucent status bar, with the page behind the safe areas matching the table, and a gold-spade icon on leather. Draw one and draw three, standard, Vegas or no scoring, and stats per draw mode, with a one-time import from solitaired.com. Klondike only for now; the engine is structured for FreeCell and Spider next. The source is on GitHub, where CI runs the unit tests and the build on every push to main and every pull request. 203 unit tests across 28 files and 53 Playwright tests, 86 runs across a desktop and a Pixel 7 profile, including one that plays a banked deal to a win, one that moves cards with the keyboard alone, and one that checks a tap with no move shakes and moves nothing.

At a glance
Deal bank
2,000 per draw mode
Solver
DFS + transposition table
Hint budget
1.5 s, in a worker
Repeats skipped
last 200 deals
Tables
Studio · Felt · Paper
Tests
203 unit · 53 e2e