The constraint that shaped everything
When I started building a solitaire portal, I gave myself one rule: if a feature does not need a server, it does not get one. No user sessions, no API layer, no database. Progress and statistics live in localStorage. That single constraint eliminated most of the traditional game-portal stack before I wrote a line of game code.
The result is SolitairePicks — 15 classic card games, statically generated, playable in the browser with no install and no signup wall.
One file per game
Each game (Klondike, Spider, FreeCell, Pyramid, Golf, TriPeaks...) is a self-contained JavaScript file with the same small interface: deal a deck, render a tableau, validate moves, detect a win. No framework lifecycle to fight. When I fixed a Spider-specific edge case last week, the diff touched exactly one file.
The tradeoff is honest: I re-implement drag-and-drop per game instead of reusing a component library. For card games the interaction surface is small enough that this costs less than maintaining a shared abstraction nobody else depends on.
Statistics without a backend
Win-rate tracking runs entirely client-side. Every finished hand appends a row to localStorage; the stats page reads it on load. Cross-session progress persists without a single network request. If a player clears their browser data, they lose their history — acceptable for a free portal, and it keeps the privacy story simple: nothing about gameplay ever leaves the device.
What the classics look like
- Klondike — the Windows-era standard, draw-one and draw-three modes
- Spider — 1/2/4 suit difficulty tiers with per-tier win-rate tracking
- FreeCell, Pyramid, Golf and a dozen more — the "second coffee" tier
What I'd do differently
If I started today I'd still skip React for the game logic — but I'd add a tiny shared module for the drag layer earlier. Rebuilding it six times was the tuition fee for learning where the real commonality lives.
The portal lives at SolitairePicks. Feedback welcome, especially on game feel and difficulty tuning.
Top comments (0)