Pending work lives above Completed milestones. Historical done items stay at the end so project memory is preserved without hiding the open work.
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.
The puzzle widget is done; no puzzles ship. In order:
- Chapter-embedded puzzles for chs 1–5 from already-mapped sources — zero new infra needed (see Puzzle » "Chapter-embedded puzzles" and "Ch5 trap puzzles").
- Puzzle sets: multi-puzzle sequencing + progress (see Puzzle » "Puzzle sets") — prerequisite for motif sets.
/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 inpgns/README.md.
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".
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.
See Learning infrastructure » "Progress tracking / dashboard", then "Spaced-repetition review". SRS needs miss data from P1/P3 to be useful — sequence it after them.
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.
-
promotion-overlay.js: pickertop/leftare relative toboardEl.parentElement(the widget), not to the board itself. Fix: addboardEl.offsetTop/boardEl.offsetLeftto 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.checksquare colors. -
is current features implemented as chessground designed it to be?
-
add credits to Kiyarash Fazeli — already covered by
theme.copyrightincourse/mkdocs.yml(© کیارش فاضلی — محتوای تعاملی تحت مجوز GPL-3.0. …), rendered site-wide by Material's default footer (.md-copyright) on every page. Verified in a freshmkdocs build:site/index.htmlcontains the.md-copyright__highlightdiv with the credit text.
- 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
palettenow lists bothslate(dark) anddefault(light) schemes withtoggleblocks (Farsi labels «حالت تاریک»/«حالت روشن»,prefers-color-schememedia 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 freshmkdocs build: bothdata-md-color-schemeradios render. - Sound effects for engine-play and local-play (move, capture, castle, check, game-start, takeback via
lib/sound.jssprite). - 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.
- Free viewer (
/view/) step-through sounds — extractedattachMoveSoundsintolib/viewer-sounds.js, reused infree-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
promotionslice (flagpfirst / SAN=); regression test added.
- 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 sharedglyphs[nag].namein place so<nag>hover tooltips render Farsi on every re-render;glyphLabel(nags)surfaces a Farsi quality badge in the viewer annotation card (keyed offcurData().nags). 6 tests (glyphLabel + localize idempotency + card badge show/hide). - Line exploration / side variations.
- 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.
- 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.jssprite). - 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).
- 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-solvedCSS 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-mountsmountPuzzleWidgetper puzzle via a newonSolvedcallback. Progress persists tolocalStorage["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
difficultyparam on{{ puzzle(...) }}and per-item on{{ puzzle_set(...) }}(author writes the Farsi label, e.g. «آسان»/«متوسط»/«سخت», same pattern ashint); rendered as a.puzzle-difficultybadge next to the puzzle label when set, omitted otherwise. Threaded throughdata-difficultyinmacros.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 inpgns/README.md(d5 break / queen infiltration / Greek-gift sac / bishop-knight combo), each with an original Farsi hint. FEN + UCI solutions independently re-verified withpython-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.
- 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_labelon thepractice_openingmacro; completion shows a "continue" link).
- Move counter — shows "حرکت X از N" (Persian digits) during practice, incrementing per ply.
- Per-move "why" annotation —
parsePgnMainlinenow extracts PGN move comments (chess.jsgetComments) and the widget shows the Farsi rationale of the move just played (user + opponent) in a panel below the board;italian-mainline.pgnannotated. 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.
demoingflag 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.)
- Italian as Black (
play_as='black', sameitalian-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.pgnshowing 7.Bd2 (blocking with the bishop) alongside the 7.Nc3 mainline. - Common opponent deviation — 3...Bc5 skipped — added
practice/pgn/italian-two-knights.pgnhandling 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.
- 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 of07-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(بخوانید → ببینید → تمرین کنید → بازی کنید).
- 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 acrosspractice.mdcards/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).
- 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.
- Promotion picker UI (piece-picker overlay, cancellable via Escape or click-outside).
- Captured-pieces side panel (compute from FEN diff) —
lib/captured-pieces.js(capturedFromFendiffs board vs. standard army → per-side captures + signed materialadvantage;capturedGlyphsrenders Unicode pieces in descending value order) +lib/captured-panel.js(two-row panel with+Nbadge on the leading side). Wired into local-playrender/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.
- Tabs for PGN game showcases — when a
{{viewer}}contains multiple games, they now render as arole="tablist"bar of clickable tabs (labelled by[Event]tag, falling back to «بازی N» in Persian digits) with onerole="tabpanel"per game; the first is active, clicking swaps the visible panel. All LPV instances stay mounted (toggled viahidden). 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).
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.
- 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 inpgns/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.
- Basic checkmates — K+Q vs K, K+R vs K, two-rook ladder mate on a new
/endgames/page (course/docs/endgames.md), reusingengine_playas-is (already shows "کیش و مات" viaformatStatus/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 withsf.py eval/mateto 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 tocourse/mkdocs.ymlnav.
- 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), verifiedis_checkmate()viapython-chessANDsf.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.
- 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 frompractice-opening-widget.js. Newdata-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.
- 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
quizwidget mode +{{ quiz(...) }}macro (question + options + answer + Farsi explanation); board questions reuse{{ board }}/puzzle. Add Farsi UI strings tosrc-widgets/strings.js.
- 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.mistakesinpractice-opening-widget.js). - Progress tracking / dashboard — localStorage record of chapters read, puzzles solved, practice clean-runs (key prefix
chess-tutorial:progress:, matching the existingchess-tutorial:namespace); show a small progress strip onindex.mdand a/progress/summary. No backend — static, per-device. - "Continue where you left off" —
src-widgets/lib/last-visited.jsrecords 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-learningslot onindex.md. Wired viabootstrap.jsboot()(kept out ofhydrate.jsto stay import-safe). Farsi stringcontinueLearning;.continue-learning-linkCSS. 6 tests. - Coordinate / board-vision trainer —
/coordinates/page +coordinatewidget mode. Empty board with coordinates hidden (Boardgained acoordinatesoption +enableSelect(onSelect)wired to chessgroundevents.select); names a random square, learner clicks it against a 30 s clock, correct/wrong flash viamarkSquare(sq, brush)(green/red), score + best-score (localStorage["chess-tutorial:coordinate:best"]), flip button to drill Black's view. Pure helpers inlib/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).
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.
- 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.
- First pass: link to a good external explainer. — new «پیجیان (PGN)» entry in
- 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 withpython-chess. Cross-links totactics.md#fork(the existing fork puzzle set). Verified in a freshmkdocs 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.mdetc.) already ends with «این بازی از دورهٔ Opening Compass ... اقتباس و به فارسی بازنویسی شده است» crediting him by name inline.
- Promote
- jadi
- analytics check
- Add a GPL-3.0
LICENSEfile (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.mdlicense note). - Deployment: static S3 hosting on Sotoon (
s3://fazelblog,https://chess.nlogn.ir), four-pass cache strategy viamake 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 viatools/github-mirror.sh.
- Find a PGN explorer/reviewer tool for authoring workflows, or build one tailored to this project.
- Opening course baseline.
- SEO-friendly tutorial/site URLs.
- Stack simplification.
- 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).
- 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.jssprite).
- 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.
- 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).
- 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-solvedclass). - 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.