Train on your own blunders, not generic puzzles — a local chess trainer built from your real Chess.com games.
Blitzr is a personal side project, not a product. It's built to run on one machine for one person, against that person's own Chess.com game history. There is no hosted version, no accounts, and no multi-user support — if you run it, it's your own local instance against your own Chess.com username.
It ingests your Chess.com games via their public Published-Data API, figures out which openings you actually play, flags the moment you deviate from a repertoire you define yourself, runs Stockfish in your browser to find your blunders, drills you on those exact positions — deviations and blunders alike — with spaced repetition, and rolls your blunders up across every analyzed game so you can see what actually keeps going wrong.
Blitzr is unaffiliated with Chess.com. It uses Chess.com's public, unauthenticated Published-Data API under their terms. It does not use Chess.com's name, logos, or marks in any way that implies endorsement or affiliation.
- Config for your Chess.com username
- Incremental sync of your games into SQLite
- Browse UI — game list, board replay, openings aggregated by ECO
- User-defined repertoire + deviation detection
- Stockfish (WASM) analysis — blunder detection, plus tactical explanations (hanging pieces, forks, pins, skewers)
- Spaced-repetition drilling
- Cross-game recurring-blunders aggregate
- Hand-authored opening and endgame lessons with an interactive board
- Position checklist — a live tactical scan of whatever position you're viewing
- Add a game by pasting its PGN — for games Chess.com's public API doesn't expose at all
- Next.js (App Router, Server Actions), TypeScript
- SQLite by default, pluggable via
DB_TYPE(onlysqliteis implemented today) - Tailwind CSS v4
- chess.js for PGN parsing/move validation, react-chessboard for the board UI
- Stockfish (WASM), run client-side in a Web Worker for per-game blunder analysis
- pnpm, Vitest, ESLint + Prettier, Husky pre-commit hooks
pnpm install
cp .env.example .env.local # fill in CHESSCOM_USERNAME
pnpm devOpen http://localhost:3000, then click Sync games to fetch your Chess.com history. Re-running sync only fetches months that aren't fully synced yet, plus the current month.
The games list explains chess jargon as you hover it — the time class column (bullet/blitz/rapid/ daily) tells you what each one means in minutes-per-player, the same way ECO codes and repertoire terms are explained elsewhere in the app.
SQLite is created automatically at ./data/blitzr.db on first run — no config needed beyond
your username. To reset, delete the file and re-sync.
The UI is available in English (default) and Spanish — set NEXT_PUBLIC_LOCALE=es in
.env.local and restart. It's a single-user app with no accounts, so there's no in-app
switcher: one instance runs in one language, chosen once.
Blitzr runs on port 9877 in production mode, so it doesn't collide with other local dev projects on 3000.
First-time setup:
npm install -g pm2
pnpm build
pm2 start "pnpm start -p 9877" --name blitzr
pm2 save
pm2 startup # follow the printed command to register with launchdOpen http://localhost:9877.
Day-to-day commands:
pm2 status # check if blitzr is running
pm2 logs blitzr # tail logs
pm2 restart blitzr # restart after a rebuild
pm2 stop blitzr # stop
pm2 delete blitzr # remove from pm2 entirelyUpdating the app:
git pull
pnpm install
pnpm build
pm2 restart blitzrpnpm dev # Start dev server
pnpm build # Production build
pnpm test # Run unit tests (Vitest)
pnpm test:watch # Run tests in watch mode
pnpm lint # ESLint
pnpm format # Prettier (write)
pnpm format:check # Prettier (check)- Base URL:
https://api.chess.com/pub, no API key required. - Every request sends a descriptive
User-Agent(Chess.com throttles requests without one). - Archives are fetched serially, never in parallel, and 429s are retried with backoff.
- Games are synced incrementally: months already fully synced are skipped on future runs; the current month is always re-fetched since it can still gain new games.
Not every game reaches your synced history — Chess.com's "Play Bots" personality games don't appear in the public API at all. Add game by PGN on the Games page takes any pasted PGN and analyzes it exactly like a synced game: board replay, opening detection, repertoire diff, and Stockfish analysis all work the same. It's saved under its own freshly generated ID, so re-running Sync games afterward can never overwrite or remove it.
On /repertoire, build an opening tree per color by playing moves on an editable board — each
move you play is added as a node, and you can branch to prepare more than one reply to an
opponent's try. Every synced game is then diffed against your tree: the game page flags the
first move where you left your own prepared line (an opponent playing something you haven't
prepped for isn't a deviation — only your own moves count). While you're building it, playing
a move that leaves a piece hanging shows the same plain-English warning as the analysis pages,
right there on the board.
On a game's page, Analyze with Stockfish runs the engine — entirely in your browser, in a Web Worker — over every position in that game and reports each blunder (a swing of 200+ centipawns) plus the biggest one. See "Reading the evaluation" below for how to interpret the numbers. Nothing is sent to a server; analysis runs client-side and only the result is saved, so re-opening the game later shows it without re-running the engine.
To analyze more than one game at a time, Analyze all on the Games page runs the engine over every synced game that doesn't have a saved analysis yet, one after another, showing progress as it goes. Each game's result is saved as soon as that game finishes, so closing the tab partway through (or clicking Cancel) doesn't lose what's already done — running it again later just picks up wherever it left off.
Every game's header also links out to the opening's Chess.com page ("Learn more about this opening"), and once a game's analyzed, a one-line "Biggest moment" summary and a running material count (a plain piece-value tally — no engine needed, works even before you've analyzed) show up alongside the board. Blunder lists spell moves out in plain English too ("Queen captures pawn on f6, check"), not just algebraic notation — and where a blunder simply hangs a piece (left attacked and undefended, capturable for free), lets the opponent fork two pieces at once, skewers a piece into exposing a less valuable one behind it, or pins a piece to your king, a line explains that too ("This leaves the queen on f6 hanging — it can be captured for free" / "This allows a fork — the knight on b5 now attacks the queen on c7 and the rook on a7 at once" / "This skewers the queen on d5 — if it moves, the bishop on c4 captures the rook on g8" / "This pins the knight on c6 to the king — it can't move without exposing the king to the bishop on b5"). A "How to read this" glossary alongside the blunder list spells out each of these terms in plain language too. All four checks are intentionally simple (no evaluation of unequal trades, no relative pins to anything other than the king, no simulation of a future opponent move creating a fork or skewer) — they won't catch every kind of mistake, so plenty of blunders show no reason at all, just the eval swing.
Each blunder also names the engine's suggested move instead, with a plain-English description and
— when the same simple checks explain it — why it's actually better ("better was Nd7 (Knight to
d7) — saves the rook on h6, which was hanging"). Stepping through the board on a game's page (with
the ◀/▶ buttons, the move list, or the left/right arrow keys) shows the same explanation for
whatever move you're currently viewing, right alongside the arrow pointing at the engine's
suggestion. A game's page opens on the first move already played rather than the last, and a
Play button (or the Space key) auto-advances through the game — pausing automatically on a
blunder rather than requiring you to step through every quiet move to find one — until it reaches
the end, or you pause it yourself. 0 jumps back to the start.
Not every good move pays off immediately — sometimes the point only becomes clear a few moves later, which is hard to judge from notation alone if you can't calculate that far ahead yet. When the engine's own expected follow-up is available, it shows up as a "Plan: ..." line next to the suggestion, and — since a short move list still asks you to picture the position yourself — as a small interactive board underneath it, with its own Start/Previous/Next/End controls so you can actually step through where the plan leads instead of just reading it.
- Centipawns (cp), shown as e.g.
+1.4or-0.8: material/positional advantage in units of a pawn, always from White's point of view — positive favors White, negative favors Black.+1.4means "White is up about a pawn and a half's worth of advantage," not literally a pawn ahead. - Mate scores, shown as
M3or-M2: a forced checkmate in that many moves,Mfor White delivering it,-Mfor Black. - Blunder: any move after which the eval swings 200+ centipawns against the player who just moved. A move that was already losing and stays losing isn't flagged again — only the swing matters. Every blunder is also tagged Mistake (200–399cp) or Blunder (400cp+) so you can tell a near-miss from a disaster at a glance.
- If you're new to reading engine evals, the chessprogramming.org Evaluation page covers the same centipawn/mate-score convention Stockfish (and Blitzr) uses.
Stepping through a game on its page, a Position checklist panel sits next to the board, below the move list, and updates as you move through the game — it scans whatever position you're currently looking at for hanging pieces, forks, pins, and skewers on either side, split into "Your pieces" and "Opponent's pieces." Unlike the blunder explanations above (which only fire on a move that actually swung the eval), this checks the position itself, so it's useful at any point in any game — including one you haven't run Stockfish on at all — for figuring out what to look for next instead of just moving pieces around. It's capped to the 3 most valuable findings per side so a busy position doesn't turn into a wall of text, and the same "How to read this" glossary from the analysis dialog is right there too, in case "skewer" or "fork" isn't a familiar term yet. It stays in view the whole time you're stepping through a game — no scrolling down to check it and back up to move again — and collapses down to one line ("nothing to flag right now") on a quiet position so it doesn't crowd out the move list when there's nothing to say.
Each finding is also drawn directly on the board — a highlighted square for a hanging piece, an arrow for a fork/pin/skewer — so there's no mental step mapping "the knight on b5" back to an actual square. If a busy position makes that too much at once, every finding has its own Hide/Show link right next to its sentence, so you can dismiss just the ones you don't want without losing the rest.
On /drill, every repertoire deviation and every blunder from your own moves becomes a card:
you're shown the position right before the mistake and have to find the move that should have
been played (any of your repertoire's prepared replies for a deviation card, the engine's
suggested move for a blunder card). Get it right and the card comes back further out; get it
wrong and it comes back tomorrow, with the correct move revealed as an arrow. Whatever move you
actually play, right or wrong, also gets checked for a hung piece, same as the Repertoire board.
The deck stays in sync automatically — build more repertoire or analyze more games, and new
cards just show up next time you visit.
Stuck on a card? Hint reveals progressively more each time you click it — first which piece to move, then which square it's on, then the full move as an arrow. Finished a session but don't want to wait until tomorrow for the cards you got wrong? Shuffle and restart on the session-complete screen replays the same cards in a new order — and it's a real do-over, not just practice: answering again actually updates that card's schedule, same as a normal answer.
A session is capped at 15 cards (the most overdue ones first) rather than throwing every due card at you at once — if there's more waiting, the session-complete screen says so with a link to load the next batch. Filter the deck by All / Deviations / Blunders and by opening if you only want to work on one thing at a time. And once you're mid-session: Space or Enter moves on to the next card, and H triggers the hint — no mouse needed.
On /blunders, every blunder from your own moves — across every game that's been analyzed so
far — is rolled up into one view: grouped by opening, grouped by moved piece, and a top-10
"worst blunders" list (each entry in plain English, not just algebraic notation, plus a hung-piece
explanation when that's what happened) linking back to each game. It's scoped to whatever's been
analyzed (analyze more games, individually or with Analyze all, to fill it in further) rather
than implying full coverage of your history.
On /learn, short plain-language lessons (English and Spanish, see "Language" above) introduce
common openings and endgames — not a repertoire, just the ideas behind one natural line, move by
move. The index shows each one as a square card with a small preview of the position it leads to,
switched between an "Openings" and an "Endgames" tab. Opening a lesson gives you a large
interactive board to step through it, with each move getting its own one-line note on why it's
played, right above the board — a flip button next to the board controls lets you view the line
from either side.
Openings: 14 lessons so far, spanning every major first move and both colors — King's Pawn Opening, Sicilian Defense, French Defense, Queen's Gambit, Italian Game, Caro-Kann Defense, Scandinavian Defense, King's Indian Defense, English Opening, Nimzo-Indian Defense, Grünfeld Defense, King's Gambit, Scotch Game, and Pirc Defense — not a full opening encyclopedia, but adding more from here is just a content-only change. Adapted from a specific page of Wikibooks' Chess Opening Theory (CC BY-SA).
Endgames: 3 lessons so far — King and Queen vs. King, King and Rook vs. King, and King and Pawn vs. King (opposition) — each one a complete, real technique demonstration that plays all the way to an actual checkmate (or, for the pawn ending, to the pawn promoting), not just a tabiya. Adapted from a different chapter of the same Wikibooks book, Chess/The Endgame.
The overall summary lives behind a "?" button next to the board controls rather than always taking up space on the page — worth reading once, not on every visit. Summaries are written in original wording rather than reproduced from any source, with a link back (opens in a new tab) for attribution and further reading.
A Quiz tab next to Study switches from reading the line to playing it from memory: you're only
tested on one side (whichever color the board is currently oriented to — defaults to the side the
lesson is written from, flip it to practice the other), the opponent's replies play themselves
after a short pause. A "Not quite — try again" nudge appears
on a wrong guess with no penalty for retrying immediately, a "Show move" button (or the H key)
reveals the answer as an arrow if you're stuck, and each move's explanation still appears the
instant you get it right. A "Restart" button (or the R key) is always available, not just once
you finish, so you can bail out and start over mid-line. The board stays visible at the final
position when you finish, alongside how many mistakes and hints it took. It's fully
self-contained to this page — no spaced repetition, no saved progress — the deliberately
lightweight way to actually test what you just read instead of only skimming it.
Each opening lesson also cross-links to your own Chess.com history: "You've played this in N of
your games (WW/DD/LL)" (or a note that you haven't yet), linking through to /openings. This
checks your synced games' actual moves against the lesson's line, rather than Chess.com's ECO
categorization — a lesson teaches a starting position, but real games almost always continue past
it into a more specific named variation, which is what Chess.com actually tags the game with.
Endgame lessons skip this line entirely — a game doesn't "reach" a constructed endgame position
the way it reaches an opening tabiya.
- Your Chess.com username lives in
.env.local(config), never in code. The API is unauthenticated and public, so there's no secret to leak —.env.exampledocuments the one variable you need. data/*.db(your synced games) is gitignored and never committed.public/stockfish/(the ~7MB WASM engine) is gitignored too —pnpm installcopies it fromnode_modulesvia apostinstallscript, so it's never committed either.
- Chess piece icons (
components/PieceGlyph.tsx) are the "light" (white) pieces from Wikimedia Commons' SVG chess piece set, originally by Cburnett, used under the BSD license.