Skip to content

fix(react-chess-game): board stuck on old position after puzzle change mid-animation#86

Merged
dancamma merged 1 commit into
mainfrom
fix/issue-83-promotion-flicker
Jul 11, 2026
Merged

fix(react-chess-game): board stuck on old position after puzzle change mid-animation#86
dancamma merged 1 commit into
mainfrom
fix/issue-83-promotion-flicker

Conversation

@dancamma

@dancamma dancamma commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Context

Issue #83 reports that onSolve fires before the promotion animation finishes: if the consumer swaps the puzzle in onSolve, the board flickers back to the old state.

Diagnosis (verified in a real browser via Storybook + Playwright)

Reproduced on main, and it's worse than a flicker: sampling the DOM after the solving promotion move, the board shows the new puzzle at t≈40ms but at t≈330ms it goes back to the old puzzle (queen on d8) and stays there.

The root cause is in react-chessboard v5: the branch that animates promotions registers a setTimeout(300ms) that reapplies the destination position, and never clears it when the position changes again (it does return without a cleanup). Our puzzle switch arrives with animationDurationInMs: 0, so its timer fires immediately and the stale promotion timer then overwrites everything.

Fix

As suggested in the issue ("if the board has changed then the animation shouldn't take place"):

  • useChessGame exposes a positionId, incremented only when a new position is loaded (fen prop change or setPosition), never on moves
  • Board uses key={positionId} on the <Chessboard>: on position change the board remounts cleanly and stale timers die with the unmounted instance

This also covers resetting the same puzzle mid-animation, not just puzzle changes.

Verification

  • Browser repro (Storybook + Playwright): with the fix the board switches to the new puzzle and stays there; regular move animations still play (transition: transform 300ms present on e2-e4)
  • jsdom regression test (promotionAnimationFlicker.test.tsx): fails without the fix, passes with it
  • Unit test for the positionId contract
  • 727 tests, lint, tsc and build all green

The upstream react-chessboard bug (uncleared timeout in the promotion branch) deserves a separate report.

Closes #83

🤖 Generated with Claude Code

…on loads

Solving a puzzle with a promotion move starts a 300ms animation inside
react-chessboard whose timer is never cleared on position change; when
onSolve immediately swapped the puzzle, the stale timer reapplied the
previous puzzle's position over the new one, leaving the board stuck on
the old state (#83).

useChessGame now exposes a positionId that increments whenever a new
position is loaded (fen prop change or setPosition) but not on moves,
and Board keys the Chessboard on it so a freshly loaded position always
mounts a clean board. Verified in a real browser via Storybook that the
flicker is gone and regular move animations still play.

Closes #83

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
react-chess-tools Ready Ready Preview, Comment Jul 11, 2026 4:49pm

@changeset-bot

changeset-bot Bot commented Jul 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2762a13

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@react-chess-tools/react-chess-game Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@dancamma
dancamma merged commit fb50ea5 into main Jul 11, 2026
3 checks passed
@dancamma
dancamma deleted the fix/issue-83-promotion-flicker branch July 11, 2026 16:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

solve fires before queening animation finishes

1 participant