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.
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.
