Chess Den is a chess server I built for myself. It runs on a Windows PC, plays against Stockfish, reviews games and serves puzzles, and my phone connects to it over WiFi. No accounts, no ads, no cloud. Everything lives in one folder.

I built it in stages, numbered 0 to 8, in a single day, and the thing that made that workable was writing the spec before the code.
Spec first, then stages
The repository starts with a spec: the engine, the features, the tech and the look. Each stage then delivers a slice of it, and a stage is finished only when the test suite is green:
- Stages 0 and 1: the spec, the engine downloader and the UCI wrapper.
- Stages 2 and 3: the server, play against the computer, clocks and friend games.
- Stages 4 and 5: the analysis board, opening explorer and game review.
- Stage 6: the puzzle importer, trainer and an adaptive puzzle rating.
- Stage 7: a games archive with filters and statistics.
- Stage 8: settings, a start script, the phone layout and a browser smoke test.
The tests include a fake UCI engine, a small script that speaks the protocol, so the server logic can be tested without Stockfish. That is a better choice than it sounds: a real engine is slow and not deterministic, and the code worth testing is mine.
One language for both ends
I chose Node.js over Python for one concrete reason: the chess rules library, chess.js, runs on the server, for move validation, PGN and clocks, and in the browser. There is exactly one implementation of the rules. The board component is a JavaScript package anyway.
Recent Node also removes the usual install pain. It ships a built-in SQLite module and a Zstandard decoder in its standard library. That means no native modules to compile on Windows, no build tools, and no prebuilt-binary roulette. The runtime dependencies are four small pure-JavaScript packages, and there is no build step for the frontend.
Getting the engine safely
The engine is the one thing I could not ship in the repository, so a script fetches it. It looks up the latest official Stockfish release, detects the CPU, and picks the matching build. It verifies the SHA-256 that GitHub publishes for the asset, and then, before trusting the file, runs it: send uci, run a short search. If the binary crashes with an illegal instruction, it steps down to the next candidate:
node scripts\get-engine.js --dry-run # just show what it would do
node scripts\get-engine.js --force # re-download
node scripts\get-engine.js --tag sf_18 # a specific release
The current Stockfish ships "universal" builds that pick the fastest code path at runtime, so the CPU detection matters less than it did. The script still handles per-architecture releases, because the next release may bring them back.
Playing the computer fairly
The eight computer levels map onto Stockfish's Skill Level, a depth cap and a time cap per move. Level 1 searches one ply for 50 ms, and level 8 is full strength with a one second cap. The engine never spends more than about a thirtieth of its remaining clock on a move, so it plays sensibly in a 1 minute game. Clocks are held on the server, with increment, so a laggy phone cannot gain time.
From the phone
The server prints the address on your WiFi. A friend game creates a link and a QR code; the first person to open it gets the other seat, and anyone later just watches.

The layout was checked on a phone in dark mode:

Review, with the eval graph
After a game, the server runs a full engine pass at fixed depth. It marks inaccuracies, mistakes and blunders by how much the win chance drops, gives each side an accuracy percentage and draws a graph of the evaluation. For every flagged move it names the best one:

Puzzles from open data
Puzzles come from an openly licensed database of around five million. The importer streams the compressed file directly and unpacks it on the fly, with no separate extraction tool, into SQLite. A theme filter and an adaptive Glicko-2 puzzle rating decide what you see next.
What the structure bought me
- A spec is a to-do list you can argue with. It was cheap to change before any code existed.
- Stages with a green test suite let me stop anywhere. Every stage ended in something that worked.
- Fewer dependencies is a feature. Built-in SQLite and decompression removed the whole class of install problems on Windows.
- Credit what you use. The engine and the board libraries are open source under their own licences. The repository lists each one, with its licence, in an attribution file, and the engine's licence is saved next to the binary.