From 43eaceadc01dce441cd4f5679dd65ea3b0c202e9 Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Sun, 22 Mar 2026 23:31:50 +0100 Subject: [PATCH] fix: improve animation hook robustness - Add .catch handler to scheduleNext to prevent unhandled promise rejections from killing the scheduling loop - Replace `as unknown as Animation` cast with Cancellable interface for type-safe cleanup handles --- packages/web/src/hooks/useMascotAnimation.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/web/src/hooks/useMascotAnimation.ts b/packages/web/src/hooks/useMascotAnimation.ts index ae3d3f67..54db91ef 100644 --- a/packages/web/src/hooks/useMascotAnimation.ts +++ b/packages/web/src/hooks/useMascotAnimation.ts @@ -13,8 +13,9 @@ export function useMascotAnimation( containerRef: React.RefObject, state: MascotState, ): void { + interface Cancellable { cancel(): void } const timeoutRef = useRef(null); - const activeAnimations = useRef([]); + const activeAnimations = useRef([]); const abortedRef = useRef(false); useEffect(() => { @@ -93,6 +94,11 @@ export function useMascotAnimation( if (!abortedRef.current) { scheduleNext(fn, minMs, maxMs); } + }).catch(() => { + // Action failed — reschedule unless aborted + if (!abortedRef.current) { + scheduleNext(fn, minMs, maxMs); + } }); }, delay); } @@ -469,9 +475,7 @@ export function useMascotAnimation( // Store initial timeout so cleanup can cancel it activeAnimations.current.push({ cancel: () => clearTimeout(initialTimeout), - finished: Promise.resolve(), - playState: 'running', - } as unknown as Animation); + }); } // ═══ LONELY STATE ═══