diff --git a/src/routes/(marketing)/(components)/bento/(animations)/auth.svelte b/src/routes/(marketing)/(components)/bento/(animations)/auth.svelte index 1b3127a30f3..8133e6cfe83 100644 --- a/src/routes/(marketing)/(components)/bento/(animations)/auth.svelte +++ b/src/routes/(marketing)/(components)/bento/(animations)/auth.svelte @@ -16,7 +16,15 @@ let currentAnimation: WriteAnimation | null = null; $effect(() => { - inView( + // The write animation can settle after the component has been destroyed + // (e.g. the user clicks the card mid-animation), by which point + // `bind:this` has already reset `button` to null. + const pulseButton = () => { + if (!button) return; + animate(button, { scale: [1, 0.95, 1] }, { duration: 0.25 }); + }; + + const stopInView = inView( container, () => { if (!isMobile()) return; @@ -28,9 +36,7 @@ 1000, password.length ); - currentAnimation.then(() => { - animate(button, { scale: [1, 0.95, 1] }, { duration: 0.25 }); - }); + currentAnimation.then(pulseButton); return () => { currentAnimation?.cancel(); currentAnimation = unwrite( @@ -43,14 +49,12 @@ { amount: 'all' } ); - hover(container, () => { + const stopHover = hover(container, () => { if (isMobile()) return; currentAnimation?.cancel(); currentAnimation = write('•••••••••••••', (v) => (password = v), 1000, password.length); - currentAnimation.then(() => { - animate(button, { scale: [1, 0.95, 1] }, { duration: 0.25 }); - }); + currentAnimation.then(pulseButton); return () => { currentAnimation?.cancel(); currentAnimation = unwrite( @@ -60,6 +64,13 @@ ); }; }); + + return () => { + stopInView(); + stopHover(); + currentAnimation?.cancel(); + currentAnimation = null; + }; }); diff --git a/src/routes/(marketing)/(components)/bento/(animations)/databases.svelte b/src/routes/(marketing)/(components)/bento/(animations)/databases.svelte index 526776a59fe..8ab79b4b243 100644 --- a/src/routes/(marketing)/(components)/bento/(animations)/databases.svelte +++ b/src/routes/(marketing)/(components)/bento/(animations)/databases.svelte @@ -65,7 +65,7 @@ let shouldAnimate = $state(false); $effect(() => { - hover(container, () => { + const stopHover = hover(container, () => { if (isMobile()) return; animate( table, @@ -99,7 +99,7 @@ }; }); - inView( + const stopInView = inView( container, () => { if (!isMobile()) return; @@ -137,6 +137,11 @@ }, { amount: 'all' } ); + + return () => { + stopHover(); + stopInView(); + }; }); diff --git a/src/routes/(marketing)/(components)/bento/(animations)/functions.svelte b/src/routes/(marketing)/(components)/bento/(animations)/functions.svelte index f20f91630ab..13f61447bce 100644 --- a/src/routes/(marketing)/(components)/bento/(animations)/functions.svelte +++ b/src/routes/(marketing)/(components)/bento/(animations)/functions.svelte @@ -25,7 +25,7 @@ $effect(() => { baseWidth = activeCommand.offsetWidth; - hover(container, () => { + const stopHover = hover(container, () => { if (isMobile()) return; widthAnim?.stop(); @@ -46,7 +46,7 @@ }; }); - inView( + const stopInView = inView( container, () => { if (!isMobile()) return; @@ -70,6 +70,13 @@ }, { amount: 'all' } ); + + return () => { + stopHover(); + stopInView(); + widthAnim?.stop(); + widthAnim = null; + }; }); diff --git a/src/routes/(marketing)/(components)/bento/(animations)/messaging.svelte b/src/routes/(marketing)/(components)/bento/(animations)/messaging.svelte index 5871c056ab7..975481b6195 100644 --- a/src/routes/(marketing)/(components)/bento/(animations)/messaging.svelte +++ b/src/routes/(marketing)/(components)/bento/(animations)/messaging.svelte @@ -26,7 +26,7 @@ [notification, { opacity: 1, y: 0, filter: 'blur(0px)' }, { duration: 0.2, at: 0.15 }] ]; - inView( + const stopInView = inView( container, () => { if (!isMobile()) return; @@ -39,7 +39,7 @@ { amount: 'all' } ); - hover(container, () => { + const stopHover = hover(container, () => { if (isMobile()) return; animate(to); @@ -47,6 +47,11 @@ animate(from); }; }); + + return () => { + stopInView(); + stopHover(); + }; }); diff --git a/src/routes/(marketing)/(components)/bento/(animations)/realtime.svelte b/src/routes/(marketing)/(components)/bento/(animations)/realtime.svelte index 462c26a68ca..25fc97a2e86 100644 --- a/src/routes/(marketing)/(components)/bento/(animations)/realtime.svelte +++ b/src/routes/(marketing)/(components)/bento/(animations)/realtime.svelte @@ -34,7 +34,7 @@ [topRightCursor, { scale: 1 }, { duration: 0.25, at: 0.35 }] ]; - inView( + const stopInView = inView( container, () => { if (!isMobile()) return; @@ -47,7 +47,7 @@ { amount: 'all' } ); - hover(container, () => { + const stopHover = hover(container, () => { if (isMobile()) return; animate(to); @@ -55,6 +55,11 @@ animate(from); }; }); + + return () => { + stopInView(); + stopHover(); + }; }); diff --git a/src/routes/(marketing)/(components)/bento/(animations)/sites.svelte b/src/routes/(marketing)/(components)/bento/(animations)/sites.svelte index 4edae6cff39..964f17e89ec 100644 --- a/src/routes/(marketing)/(components)/bento/(animations)/sites.svelte +++ b/src/routes/(marketing)/(components)/bento/(animations)/sites.svelte @@ -46,9 +46,10 @@ ]; let shouldAnimate = $state(false); + let secondsAnimation: ReturnType | null = null; $effect(() => { - hover(container, () => { + const stopHover = hover(container, () => { if (isMobile()) return; shouldAnimate = true; @@ -57,6 +58,7 @@ onUpdate: (latest) => (seconds = +latest.toFixed()), duration: 44 }); + secondsAnimation = animation; currentAnimation?.cancel(); currentAnimation = write( @@ -82,7 +84,7 @@ }; }); - inView( + const stopInView = inView( container, () => { if (!isMobile()) return; @@ -92,6 +94,7 @@ onUpdate: (latest) => (seconds = +latest.toFixed()), duration: 44 }); + secondsAnimation = animation; currentAnimation?.cancel(); currentAnimation = write( @@ -118,6 +121,15 @@ }, { amount: 'all' } ); + + return () => { + stopHover(); + stopInView(); + secondsAnimation?.stop(); + secondsAnimation = null; + currentAnimation?.cancel(); + currentAnimation = null; + }; }); diff --git a/src/routes/(marketing)/(components)/bento/(animations)/storage.svelte b/src/routes/(marketing)/(components)/bento/(animations)/storage.svelte index 1129572444d..c09f9b276ee 100644 --- a/src/routes/(marketing)/(components)/bento/(animations)/storage.svelte +++ b/src/routes/(marketing)/(components)/bento/(animations)/storage.svelte @@ -10,7 +10,7 @@ let image: HTMLElement; $effect(() => { - hover(container, () => { + const stopHover = hover(container, () => { if (isMobile()) return; animate(image, { borderRadius: '24px', filter: 'grayscale(25%)' }, { duration: 0.2 }); @@ -27,7 +27,7 @@ }; }); - inView( + const stopInView = inView( container, () => { if (!isMobile()) return; @@ -53,6 +53,11 @@ amount: 'all' } ); + + return () => { + stopHover(); + stopInView(); + }; });