@@ -7,7 +7,7 @@ import Chessground from '@react-chess/chessground'
77import { BaseGame , GameNode , Color } from 'src/types'
88import { MoveClassificationIcon } from 'src/components/Common/MoveIcons'
99import type { DrawBrushes , DrawShape } from 'chessground/draw'
10- import { useCallback , useMemo , Dispatch , SetStateAction } from 'react'
10+ import { useCallback , useEffect , useMemo , Dispatch , SetStateAction } from 'react'
1111
1212interface MoveClassification {
1313 blunder : boolean
@@ -71,6 +71,19 @@ export const GameBoard: React.FC<Props> = ({
7171 const { playMoveSound } = useSound ( )
7272 const boardInstanceKey = game ?. id ?? 'board'
7373
74+ // After every position change, post-render layout shifts (stats panel,
75+ // move list) can move the board without changing its size, leaving
76+ // Chessground's cached bounds stale. Dispatching resize clears the cache
77+ // so the next click re-measures from the correct DOM position.
78+ // Chessground registers a permanent window.resize → bounds.clear() listener
79+ // at init, so this is the correct low-impact way to invalidate it.
80+ useEffect ( ( ) => {
81+ const timeout = window . setTimeout ( ( ) => {
82+ window . dispatchEvent ( new Event ( 'resize' ) )
83+ } , 50 )
84+ return ( ) => window . clearTimeout ( timeout )
85+ } , [ currentNode ] )
86+
7487 const after = useCallback (
7588 ( from : string , to : string ) => {
7689 if ( onPlayerMakeMove ) onPlayerMakeMove ( [ from , to ] )
0 commit comments