Back to projects
AlgorithmsSource available

Case study

Chess Tactical Lens

A local-first chess workspace that explains the immediate threats and consequences created by each move—without an engine, evaluation score, or best-move recommendation.

Chess Tactical Lens showing a knight fork, check, hanging queen, and tactical overlays

Project overview

Category
Algorithms

Technology

  • Next.js
  • TypeScript
  • React
  • chess.js
  • SQLite
  • Tailwind CSS
  • Vitest

Project links

Inside the project

Context

Chess tools usually answer a different question from the one a learner is asking. An engine can rank moves, but its score does not immediately explain what the latest move attacked, uncovered, stopped defending, or changed around a king. Chess Tactical Lens was built for human analysis during move-by-move review: it visualizes only the new tactical consequences of the latest move instead of drawing every relation already present on the board.

Role

I designed and implemented the complete product: the legal interactive board, deterministic tactical-transition analyzer, semantic overlay model, local persistence, game history, HTTP boundary, interface, fixtures, and automated test suite. I also defined the product boundary that keeps the application explanatory rather than prescriptive—there is no engine, computer opponent, evaluation score, or best-move language.

Constraints

Every explanation had to be caused by the latest move, reliable enough to display immediately, and independent of deeper engine search. The application also needed full chess legality, promotion handling, exact position reconstruction, and safe history edits. Because it is intentionally local-first and single-user, it uses SQLite without accounts or cloud infrastructure and is distributed as source rather than hosted as a public service.

Approach

The core analyzer creates complete BEFORE and AFTER snapshots, then diffs geometric attacks, effective attacks, defenders, absolute pins, legal king destinations, and local static-exchange results. The diff becomes typed semantic events—checks, forks, hanging pieces, lost or discovered defenses, blocked lines, x-rays, pins, and discovered attacks—with priorities, explanations, arrows, highlights, and attacker/defender metrics. React renders those events but does not infer chess tactics. The canonical state is the initial FEN plus an ordered move log; Next.js Route Handlers call an application service, SQLite transactions guard writes, and optimistic concurrency plus idempotency prevent silent conflicts or duplicate moves.

Outcome

The finished application supports click and drag input, legal move validation, explicit underpromotion, board flipping, a canonical SAN log, tactical overlays that can be toggled independently, continuous king-space control, and exact read-only review of every recorded position. Users can take back the latest move or explicitly truncate a continuation before branching. Seven deterministic motif demos make the system easy to inspect, while 83 automated tests cover the analyzer, chess rules, persistence, concurrency, history mutation, and HTTP contracts.

Lessons

The hardest part was not drawing arrows but deciding when an arrow tells the truth. Comparing position transitions rather than static attack maps eliminated pre-existing noise, while separating geometric relations from effective legal relations prevented pinned pieces and illegal king captures from producing misleading stories. Keeping tactical reasoning in a pure domain layer made complex causality rules testable and allowed the interface to stay focused on explanation rather than recommendation.

A local-first chess workspace that explains the immediate threats and consequences created by each move—without an engine, evaluation score, or best-move recommendation.

Explore all projects