Skip to content

Latest commit

 

History

History
288 lines (239 loc) · 28.3 KB

File metadata and controls

288 lines (239 loc) · 28.3 KB

Chess Tutorial - TODO

Pending work lives above Completed milestones. Historical done items stay at the end so project memory is preserved without hiding the open work.

Focus roadmap (2026-07)

Priority ranking for making this a better training course. Items reference their home sections below — details live there, not here. Rationale: the interactive platform (engine, viewers, practice widget, puzzle widget) is feature-complete for a beginner course, but almost no training content exercises it — site-wide exactly one curated puzzle link exists (ch7). Content that uses existing widgets beats new widget modes.

P1 — Ship curated tactics puzzles (highest training ROI)

The puzzle widget is done; no puzzles ship. In order:

  1. Chapter-embedded puzzles for chs 1–5 from already-mapped sources — zero new infra needed (see Puzzle » "Chapter-embedded puzzles" and "Ch5 trap puzzles").
  2. Puzzle sets: multi-puzzle sequencing + progress (see Puzzle » "Puzzle sets") — prerequisite for motif sets.
  3. /tactics/ motif page + puzzle sourcing (see Tactics trainer). Recommended source: Lichess open puzzle DB (CC0), filtered to rating ≤1200 per motif, each hand-checked; attribution in pgns/README.md.

P2 — Finish-the-game skills ✅ done

Learners who know openings still can't convert won games. See Endgame trainer » "Basic checkmates" (K+Q / K+R vs. engine, reuses engine_play) and Checkmate patterns » "Pattern library".

P3 — Active recall on existing chapters (cheap multiplier)

The 9 chapters are read-only today. See Concept checks » "End-of-chapter quiz" (chs 1–4) and Active recall » "Guess-the-move". Multiplies the value of already-written content without new prose.

P4 — Progression loop

See Learning infrastructure » "Progress tracking / dashboard", then "Spaced-repetition review". SRS needs miss data from P1/P3 to be useful — sequence it after them.

P5 — Small content debts (interleave anytime)

How-to-read-PGN note, fork definition, historical-context blurbs, inline annotator credits (see Teaching notes and content additions).

Deprioritized for training value: Analysis mode, Board Editor, PWA, time controls, resign/draw buttons — platform depth, not learning value.

Active fixes / polish

  • promotion-overlay.js: picker top/left are relative to boardEl.parentElement (the widget), not to the board itself. Fix: add boardEl.offsetTop/boardEl.offsetLeft to the square-geometry offset so the picker aligns with the actual board square instead of the widget container top. Affects rank-1 (black) and rank-8 (white) promotions — the column is correct but the row is shifted upward by the height of any content above the board (e.g. the play-settings dropdowns).

  • Viewer: keep the board/PGN layout stable so the page does not jump while navigating moves. you don't need to follow through to move in screen when next/prev button hits

  • Viewer: scroll the current highlighted move into view while navigating.

  • Viewer: keep FEN/notation display LTR under chess positions as subtitle without breaking the surrounding RTL layout. or move them out of subtitle

  • Chessground dark-theme polish: inspect .move-dest, .last-move, and .check square colors.

  • is current features implemented as chessground designed it to be?

  • add credits to Kiyarash Fazeli — already covered by theme.copyright in course/mkdocs.yml (© کیارش فاضلی — محتوای تعاملی تحت مجوز GPL-3.0. …), rendered site-wide by Material's default footer (.md-copyright) on every page. Verified in a fresh mkdocs build: site/index.html contains the .md-copyright__highlight div with the credit text.

Shared UX / cross-cutting

  • Board flip button (pgn viewer for example and fen viewer doesn't need it )
  • Keyboard shortcuts help overlay (? button + panel on all viewer widgets, RTL-aware, Escape closes; 11 tests).
  • Mobile responsive layout.
  • Dark/light theme toggle. — Material palette now lists both slate (dark) and default (light) schemes with toggle blocks (Farsi labels «حالت تاریک»/«حالت روشن», prefers-color-scheme media match); no widget CSS is dark-locked (colors use --md-default-*/--md-accent-* vars or theme-neutral semantic colors), so both widgets and page chrome repaint correctly on switch. Verified in a fresh mkdocs build: both data-md-color-scheme radios render.
  • Sound effects for engine-play and local-play (move, capture, castle, check, game-start, takeback via lib/sound.js sprite).
  • Sound effects for viewer (step-through moves play piece sounds via lib/sound.js; promotion/castle/capture/move + delayed check, derived from SAN).
  • Touch/drag piece input on mobile.
  • PWA support.

Review findings (2026-05-30)

  • Free viewer (/view/) step-through sounds — extracted attachMoveSounds into lib/viewer-sounds.js, reused in free-viewer-widget.js.
  • Free viewer FEN load: validate via chess.js before rebuilding; FEN bar shows an inline error and keeps the value on failure.
  • Promotion sound audit: all five modes route promotions to the promotion slice (flag p first / SAN =); regression test added.

Feature roadmap by mode

Viewer

  • Arrow/highlight overlays for annotated moves (and reuse the same overlay system in Tutorial Mode).
  • Human-readable labels for move-quality annotations (good / bad / brilliant) where they improve readability. — lib/glyphs.js: NAG→Farsi label map (NAG_LABELS). localizeGlyphs() rewrites LPV's shared glyphs[nag].name in place so <nag> hover tooltips render Farsi on every re-render; glyphLabel(nags) surfaces a Farsi quality badge in the viewer annotation card (keyed off curData().nags). 6 tests (glyphLabel + localize idempotency + card badge show/hide).
  • Line exploration / side variations.

Board Editor

  • MVP: Empty board, drag pieces from a piece tray onto squares.
  • Set side to move, castling rights, en passant square.
  • Generate FEN from current setup, copy to clipboard.
  • "Play from here" → opens Free Play with this FEN.
  • "Create puzzle" → opens Puzzle Creator with this FEN.
  • Load FEN from text input to edit existing position.
  • Piece count validation (max 1 king per side, max 8 pawns, etc.).
  • Clear board / reset to starting position buttons.

Free Play vs Engine

  • MVP: Play from starting position or FEN, engine responds, game-over detection.
  • 3 difficulty levels (beginner / intermediate / advanced).
  • Choose color (play as white or black).
  • Undo / takeback (rewind last full move pair).
  • Engine thinking indicator (status text while Stockfish is computing).
  • Move sound effects (reuses lib/sound.js sprite).
  • Promotion piece picker dialog.
  • Resign / offer draw buttons.
  • Post-game: "Analyze" button → opens Analysis mode with the played game.
  • Time controls (optional clock per side).

Puzzle

  • MVP: FEN + solution line, validate user moves one by one, correct/incorrect feedback.
  • Hint button (highlight destination square of next correct move).
  • Retry on wrong move (snap back to last correct position, re-enable input).
  • Puzzle complete celebration state (status flash + .puzzle-solved CSS class).
  • Show engine's response moves (auto-plays opponent moves at 400 ms delay).
  • Puzzle URL format: ?fen=&solution=&hint= and ?data=<base64-json> (both supported).
  • Sound effects: move/capture/castle/check on correct + auto-played opponent moves, wrong-move buzz on rejection, won fanfare on solve (via lib/sound.js).
  • Puzzle Creator: set up position, record solution moves, generate shareable URL.
  • Puzzle sets: load multiple puzzles in sequence, track progress. — new puzzle_set(id, puzzles, title) macro (data-mode="puzzle_set") + puzzle-set-widget.js, which re-mounts mountPuzzleWidget per puzzle via a new onSolved callback. Progress persists to localStorage["chess-tutorial:puzzle-set:<setId>"] (lib/puzzle-progress.js); resumes from the first unsolved puzzle on revisit. 4 tests.
  • Difficulty rating per puzzle. — optional free-text difficulty param on {{ puzzle(...) }} and per-item on {{ puzzle_set(...) }} (author writes the Farsi label, e.g. «آسان»/«متوسط»/«سخت», same pattern as hint); rendered as a .puzzle-difficulty badge next to the puzzle label when set, omitted otherwise. Threaded through data-difficulty in macros.py → hydrate.js (readPuzzleAttrs/readPuzzleFromUrl, incl. ?difficulty=/?data=) → puzzle-widget.js/puzzle-set-widget.js. 2 tests.
  • Chapter-embedded puzzles (chs 1–4) — one FEN puzzle per chapter embedded via {{ puzzle(...) }}, positions taken from the Compass game ideas already mapped in pgns/README.md (d5 break / queen infiltration / Greek-gift sac / bishop-knight combo), each with an original Farsi hint. FEN + UCI solutions independently re-verified with python-chess, not copied from any Chessable puzzle text.
  • Ch5 trap puzzles — both Bartholomew traps (Petroff "Symmetry Shattered", Italian "Hungarian Disappointment") embedded as {{ puzzle(...) }} at the end of ch5, paraphrased into original Farsi hints. The stale "Ch5 already links puzzles inline" note above (Practice page section) is now literally true.

Practice Opening

  • MVP: Select an opening line (PGN), app plays opponent moves, user plays book moves.
  • scholar mate terminology: the 4-move Qxf7# mate is called «مات ناپلئونی» in Persian (Scholar's Mate ≡ Napoleon's Mate by language, like German Schäfermatt). Chapter/PGN unified to «مات ناپلئونی» with the fa.wikipedia link. (A prior over-correction to «مات دانشمند» was reverted.)
  • Wrong move feedback: show the book move, allow retry.
  • next page button (optional next_url/next_label on the practice_opening macro; completion shows a "continue" link).

Practice widget UX

  • Move counter — shows "حرکت X از N" (Persian digits) during practice, incrementing per ply.
  • Per-move "why" annotation — parsePgnMainline now extracts PGN move comments (chess.js getComments) and the widget shows the Farsi rationale of the move just played (user + opponent) in a panel below the board; italian-mainline.pgn annotated. Cleared on reset.
  • "نشان بده" (Show me) button — demonstrates the next book move (animate + sound + highlight), pauses ~900 ms, then snaps back to the current position and re-enables input without advancing the cursor so the learner plays it themselves. demoing flag guards re-entrancy; cleared on reset. (2 tests.)
  • Line completion recap — after completing a line, show which of the 4 principles each move illustrated (e.g. "۷ حرکت، ۴ اصل در عمل"). Can be a static data-principle per move in the PGN comment format {[مرکز] اصل اول}.
  • Clean-run recognition on completion — practice tracks wrong moves per attempt (state.mistakes, reset on retry); finishing a line with zero mistakes shows «بدون هیچ اشتباهی کامل شد! 🎯» instead of the plain complete message. (Note: the «تلاش دوباره» retry button was never actually hidden on completion — it lives permanently in .controls — so the stale "button disappears" premise was dropped; the value delivered is the clean-run flourish. 3 tests.)

Practice content — lines needed

  • Italian as Black (play_as='black', same italian-mainline.pgn) — flip the board; learner plays Black's book replies while White auto-plays. Adds the same line from the opponent side; no new PGN needed, just a second {{ practice_opening(... play_as='black') }} block on the practice page.
  • Ruy Lopez main line as White — 1.e4 e5 2.Nf3 Nc6 3.Bb5 a6 4.Ba4 Nf6 5.O-O Be7 6.Re1 b5 7.Bb3 — the other primary White weapon after 1.e4; pairs naturally with the Italian chapter. Needs a new annotated PGN (practice/pgn/ruy-lopez-mainline.pgn) with Farsi per-move comments.
  • Italian — handling Bb4+ check — added practice/pgn/italian-bd2.pgn showing 7.Bd2 (blocking with the bishop) alongside the 7.Nc3 mainline.
  • Common opponent deviation — 3...Bc5 skipped — added practice/pgn/italian-two-knights.pgn handling 3...Nf6 with the principled 4.d4.
  • Sicilian: basic structure — 1.e4 c5 2.Nf3 d6 3.d4 cxd4 4.Nxd4 Nf6 5.Nc3 e6 — added as practice/pgn/sicilian-basic.pgn, played as Black.

Practice page — navigation and learning path

  • Opening selector — implemented as a static card-grid of in-page links on the practice page (six lines: opening name, color, ply count); no practice_grid() YAML macro — six lines didn't justify the data-file indirection. Anchors become render targets if a macro is wanted later.
  • Embed practice at the end of ch7 — {{ practice_opening(...) }} for the Italian mainline now mounts at the bottom of 07-giuoco-piano.md, with a "خط‌های بیشتر" link to /practice/.
  • Chapter-end practice links — "تمرین این اصل ←" callout added to chs 1–4 pointing to the practice page. (Ch5 already links puzzles inline; ch6 is a game showcase; ch7 has the embedded widget.)
  • Learning path overview — added to index.md (بخوانید → ببینید → تمرین کنید → بازی کنید).

Persian learner pedagogy

  • Chess terms glossary page (course/docs/glossary.md, in nav) — ten terms (کنترل مرکز، توسعه، قلعه‌بندی، اتصال رخ‌ها، تمپو، آچمزی، سیخ، دام، پیاده گذشته، فیل بد), each with an original Farsi definition and a FEN board or chapter link. Inline retro-fit of glossary links into chapters deferred (existing Wikipedia links kept).
  • Principle cheat-sheet during practice — show the 4 principles (one line each) in a collapsed/expandable sidebar or tooltip during the practice widget so learners can cross-reference while playing. Avoids tab-switching to ch1–4.
  • Principle tagging in practice PGNs — annotate each practice move comment with the principle it demonstrates using a conventional prefix: {[اصل ۲: توسعه] اسب به f3 — پیاده e5 را زیر فشار می‌گیرد}. The widget can then badge each move as it plays, reinforcing the connection between principle and move.
  • Farsi opening names — verified consistent: بازی ایتالیایی (Italian), گشایش اسپانیایی (Ruy Lopez), and دفاع سیسیلی (Sicilian) each use one Farsi name across practice.md cards/headings, the practice PGN comments, and the ch2/ch4 chapter text — no گامبی وزیر content exists yet to check. No nav entries name individual openings, so no nav mismatch is possible.
  • "Opening line library" — retired as superseded by the card-grid opening selector and the concrete lines above (Italian ×3, Ruy Lopez, Sicilian).

Analysis

  • MVP: Free move entry for both sides, no opponent, position history with undo.
  • Engine evaluation bar (Stockfish score per position).
  • Best move suggestion on demand.
  • Branch/variation tree: explore alternatives without losing the main line.
  • Load PGN for post-game review.
  • Arrow drawing (click+drag to annotate).
  • Export analyzed game as PGN with engine eval comments.

Local Play

  • Promotion picker UI (piece-picker overlay, cancellable via Escape or click-outside).
  • Captured-pieces side panel (compute from FEN diff) — lib/captured-pieces.js (capturedFromFen diffs board vs. standard army → per-side captures + signed material advantage; capturedGlyphs renders Unicode pieces in descending value order) + lib/captured-panel.js (two-row panel with +N badge on the leading side). Wired into local-play render/updateUI. 11 tests. Note: FEN-only heuristic — exact from the standard start; a promotion reads as a captured pawn + the promoted piece (no move history available).
  • Optional board auto-flip on each turn.
  • Move clock (Fischer/increment).
  • "Analyze" button after game ends.

Tutorial Mode

  • Tabs for PGN game showcases — when a {{viewer}} contains multiple games, they now render as a role="tablist" bar of clickable tabs (labelled by [Event] tag, falling back to «بازی N» in Persian digits) with one role="tabpanel" per game; the first is active, clicking swaps the visible panel. All LPV instances stay mounted (toggled via hidden). Replaces the previous stacked-viewers layout. (1 test covering labels, default-active, and click-swap.)
  • Farsi translation of PGN move comments.
  • Lazy-mount boards on scroll (IntersectionObserver, 200 px lead; fallback to immediate mount).

Education & training

New learning modes and pedagogy beyond the opening course. Each item names the existing widget/lib it reuses (src-widgets/) so the result stays a static, offline build. Cross-cutting infrastructure (SRS, progress) is shared across modes. Puzzle "sets / difficulty rating" and the "how to read PGN" / "fork definition" notes are tracked under Puzzle and Content/curriculum respectively — items here reference, not duplicate, them.

Tactics trainer (themed motif sets)

  • Motif puzzle sets — shipped for 4 of the 7 motifs: fork «چنگال», pin «آچمزی», skewer «سیخ», discovered attack «کشف حمله» (2 puzzles each, {{ puzzle_set(...) }}) on /tactics/ (course/docs/tactics.md, in nav). Back-rank mate, deflection, and decoy remain open — same pattern, just more sets (tracked in GitHub issue #1).
  • Motif explainer + worked example — glossary entries for آچمزی and سیخ now cross-link to their /tactics/ set (#pin, #skewer); a دام link is still open pending a trap/decoy set. The richer "one annotated board/viewer example before the puzzles" treatment is not yet built — /tactics/ currently opens each section with one line of prose only.
  • Source the puzzles — decided: hand-authored FEN positions (fork/pin/skewer/discovered attack), each independently verified with python-chess (legal FEN, legal solution moves) rather than pulled from Lichess or Chessable. Documented in pgns/README.md » "Chapter-embedded puzzles". The Lichess open-puzzle-DB route from the roadmap is deferred — no reliable fetch path for rating-filtered, hand-checked positions was available this session.

Endgame trainer

  • Basic checkmates — K+Q vs K, K+R vs K, two-rook ladder mate on a new /endgames/ page (course/docs/endgames.md), reusing engine_play as-is (already shows "کیش و مات" via formatStatus/isCheckmate() on the learner's mating move, no widget changes needed). No explicit "mate in ≤N" limit — these are technique drills, not speed puzzles. Starting FENs sanity-checked with sf.py eval/mate to confirm none is a trivial already-won-in-1 position (the first ladder-mate draft was — fixed by centralizing the king).
  • King-and-pawn fundamentals — opposition, rule of the square, key squares: short annotated {{ viewer }} lessons each followed by a "play it out" board.
  • Rook-endgame fundamentals — Lucena (building a bridge) and Philidor (third-rank defence) as annotated viewers + practice boards.
  • Endgame page + nav — /endgames/, added to course/mkdocs.yml nav.

Checkmate patterns

  • Pattern library — back-rank, smothered (Philidor's legacy), Anastasia's, Arabian, Boden's, ladder, on a new /checkmates/ page (course/docs/checkmates.md). Each: one annotated {{ viewer }} (inline PGN with [FEN]/[SetUp] headers) + one {{ puzzle }}. All 6 are hand-composed minimal positions (not sourced games), verified is_checkmate() via python-chess AND sf.py puzzle (uniquely-best mate-in-1, mate-in-2 for smothered) per the chess-engine skill. Cross-linked from «دام» in the glossary. Two rounds of engine-caught bugs during construction: Arabian mate's first draft had a second unintended mate-in-1 (Rh5# alongside the intended Ra8#) — fixed by restricting the rook's starting square so only the corner line is reachable; several hand-derived N+R/2B compositions turned out illegal or non-mate on first pass (pawn/piece could block or capture) until brute-force-verified.

Active recall in viewers / showcase games

  • Guess-the-move (solitaire) mode — viewer variant that hides the next mainline move and asks the learner to play it on the board before revealing, scoring correct guesses. Combine viewer-widget.js (LPV) with the expected-move/snap-back validation pattern from practice-opening-widget.js. New data-mode="guess" + macro {{ guess_game(pgn_file=…) }}.
  • Quiz checkpoints in chapter games — at tagged critical moves in the historic-game PGNs (chs 1–6), pause the viewer and prompt «بهترین حرکت را پیدا کن» before continuing. Drive from a PGN move-comment convention (e.g. {?: find}) so authoring stays inside the PGN.

Concept checks (reading comprehension)

  • End-of-chapter quiz — a small multiple-choice / find-the-move check after each principle chapter (chs 1–4) reinforcing the principle just read. New lightweight quiz widget mode + {{ quiz(...) }} macro (question + options + answer + Farsi explanation); board questions reuse {{ board }}/puzzle. Add Farsi UI strings to src-widgets/strings.js.

Learning infrastructure (cross-cutting)

  • Spaced-repetition review — shared src-widgets/lib/srs.js (localStorage, SM-2-lite) that records misses from puzzles / practice / guess-the-move and re-serves due items on a /review/ page. Seed off the existing practice mistake counter (state.mistakes in practice-opening-widget.js).
  • Progress tracking / dashboard — localStorage record of chapters read, puzzles solved, practice clean-runs (key prefix chess-tutorial:progress:, matching the existing chess-tutorial: namespace); show a small progress strip on index.md and a /progress/ summary. No backend — static, per-device.
  • "Continue where you left off" — src-widgets/lib/last-visited.js records the last visited tutorial/practice page (localStorage["chess-tutorial:last-visited"] = {path,title,ts}, skips home/tools) and renders a resume link into a #continue-learning slot on index.md. Wired via bootstrap.js boot() (kept out of hydrate.js to stay import-safe). Farsi string continueLearning; .continue-learning-link CSS. 6 tests.
  • Coordinate / board-vision trainer — /coordinates/ page + coordinate widget mode. Empty board with coordinates hidden (Board gained a coordinates option + enableSelect(onSelect) wired to chessground events.select); names a random square, learner clicks it against a 30 s clock, correct/wrong flash via markSquare(sq, brush) (green/red), score + best-score (localStorage["chess-tutorial:coordinate:best"]), flip button to drill Black's view. Pure helpers in lib/coordinate-trainer.js (allSquares/pickSquare/ROUND_SECONDS/EMPTY_FEN); Farsi strings (coord*); {{ coordinate() }} macro; nav entry. 21 tests (board+lib+widget); verified end-to-end in a real browser (trusted click → score).

Content / curriculum

Historic-game annotation expansion

Chapters 1–4 each ship with a historic-game PGN containing 3–5 short Farsi annotations on critical moments. The full Opening Compass commentary (in pgns/principle-aligned/Opening Compass for Black and White by GM Mykhaylo Oleksiyenko.pgn) is much richer. Expand each PGN's annotations to match the depth of course/docs/tutorials/opening-principles/pgn/06-opera-game.pgn (one Farsi note per move):

  • course/docs/tutorials/opening-principles/pgn/01-rotlewi-rubinstein-1907.pgn — source: Compass lines 549–590.
  • course/docs/tutorials/opening-principles/pgn/02-morphy-hart-1857.pgn — source: Compass lines 645–675.
  • course/docs/tutorials/opening-principles/pgn/03-lasker-thomas-1911.pgn — source: Compass lines 1791–1822.
  • course/docs/tutorials/opening-principles/pgn/04-steinitz-bardeleben-1895.pgn — source: Compass lines 1988–2023.

Per-game game/chapter mapping is documented in pgns/README.md.

Teaching notes and content additions

  • Add a short tutorial on how to read PGN.
    • First pass: link to a good external explainer. — new «پی‌جی‌ان (PGN)» entry in course/docs/glossary.md, matching the existing term-entry pattern, linking the Farsi Wikipedia article «نشانه‌گذاری قابل‌حمل بازی».
    • Later: incorporate an in-site tutorial.
  • Add a glossary/teaching note for the definition of a fork. — «چنگال (فورک)» entry added to course/docs/glossary.md, matching the existing entry pattern (definition + {{ board }} example + cross-link). Example FEN (r3k3/2N5/8/8/8/8/8/4K3 b - - 0 1, knight on c7 checking the king while forking rook a8) verified valid/in-check with python-chess. Cross-links to tactics.md#fork (the existing fork puzzle set). Verified in a fresh mkdocs build.
  • Add historical-context blurbs for the featured games.
  • Credit GM Oleksiyenko / original annotators inline in chapters that reuse annotated games. — each Compass-sourced PGN (chs 1–4) carries an [Annotator "Adapted from GM Mykhaylo Oleksiyenko, Opening Compass"] tag, and the chapter markdown itself (01-center-control.md etc.) already ends with «این بازی از دورهٔ Opening Compass ... اقتباس و به فارسی بازنویسی شده است» crediting him by name inline.

Platform / publishing

  • Promote
    • jadi
  • analytics check
  • Add a GPL-3.0 LICENSE file (chessground is GPL-3.0-or-later; combined work is GPL).
  • Review license/terms-of-use for any Chessable-derived material before publishing (see pgns/README.md license note).
  • Deployment: static S3 hosting on Sotoon (s3://fazelblog, https://chess.nlogn.ir), four-pass cache strategy via make deploy.
  • Hosting model: fully static — MkDocs build → Vite bundle → s3cmd sync.
  • Published public GitHub mirror (fresh history, pgns/ excluded; full history backed up as git bundle + gitea) — https://github.com/Fazel94/chess-tutorial, exported via tools/github-mirror.sh.

Research / tooling

  • Find a PGN explorer/reviewer tool for authoring workflows, or build one tailored to this project.

Completed milestones

Opening course / platform

  • Opening course baseline.
  • SEO-friendly tutorial/site URLs.
  • Stack simplification.

Viewer

  • MVP: Display FEN, step through PGN, move list, keyboard nav.
  • Multi-language (FA/EN) with switcher.
  • "Play from here" button — hand off current position to Free Play vs Engine.
  • Move annotations (!, ?, !!, ??, !?, ?!) display.
  • Comment/annotation text display between moves.
  • Export current position as FEN (copy to clipboard).
  • Share button (copy URL with current move position).

Local Play

  • MVP: Alternating turns on one board, game-over detection.
  • Move history panel (SAN list matching engine-play style).
  • Undo / takeback.
  • Game persistence via localStorage (key: chess-tutorial:local-play:fen).
  • Sound effects (lib/sound.js sprite).

Free Play vs Engine

  • MVP: FEN load, Stockfish WASM worker, game-over detection.
  • Difficulty selector (beginner / intermediate / advanced).
  • Color selector (play as white or black).
  • Undo (rewinds one full move pair).
  • Engine thinking status indicator.
  • Move sound effects.
  • Promotion piece picker.
  • FEN bar (display + load arbitrary position mid-game).
  • Move history panel.

Tutorial Mode

  • Markdown renderer with {{board}} and {{viewer}} stub widgets.
  • Static board positions with captions.
  • Interactive PGN viewers with move list, NAG badges, comments.
  • Multi-game PGN selector (game tabs/dropdown).
  • Keyboard navigation (RTL-aware arrows).

Puzzle

  • MVP: FEN + UCI solution line, move-by-move validation.
  • Hint button (marks destination square, shows hint text in status).
  • Wrong-move snap-back with "wrong" flash status.
  • Auto-play opponent response moves (400 ms delay).
  • Solved state (flash + persistent .puzzle-solved class).
  • URL params: ?fen=&solution=&hint= and ?data=<base64-json>.
  • FEN bar (read-only display of current position).
  • Promotion piece picker for promotion moves in solutions.