What am I trying to do & context?
I am currently making a personal website, and I wanted center this container. You can an example on Aceternity.
With a modified version this container centered, the container would jump.
As a result I have created the code found on Replit (it is commented with further details on how the code works).
What is the problem I am facing?
At random intervals (around every 1-7 cycles) the animation seems to bug out and create two instances of itself, for a single frame. As show in the images below.
image of bug
I have attempted to localise the problem, with no success. The glitch seems to last for around a single frame. I truly
have no clue and have been stuck on this for a while.
Problem file location?
./src/app/ui/title-section/vanishing-words.tsx
Or press this link.
Theories
- It is possible that multiple nested motions, could be somehow effecting one another – I have tested to see if
onExitComplete
is being called multiple times, and it does not seem like it. - Uncommenting
b1
does seem to make it worse.
image of second bug - I have tested on Chrome and Safari browsers.
Code that is likely causing the problem
I have reduced the code down to this minimal state and have still been finding them problem.
<AnimatePresence
onExitComplete={() => {
// 5. The animation loops
setIsAnimating(false);
}}
>
<motion.div
key={`${currentWord}-${xOffSet}`}
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
ref={divRef}
transition={{ duration: 1 }}
initial={{ x: xOffSet }}
animate={{ x: 0 }}
>
<p>{relativeClause}</p>
<motion.div
key={currentWord}
>
{/* b1: Swapping out the div above with the one below seems to make it worse */}
{/* <motion.div
key={currentWord}
initial={{
opacity: 0,
y: 10,
}}
animate={{
opacity: 1,
y: 0,
}}
transition={{
duration: 0.4,
ease: "easeInOut",
type: "spring",
stiffness: 100,
damping: 10,
}}
exit={{
opacity: 0,
y: -40,
x: 40,
filter: "blur(8px)",
scale: 2,
position: "absolute",
}}
> */}
{currentWord.split("").map((letter, index) => (
<motion.span
key={currentWord + index}
initial={{
opacity: 0,
y: 10,
filter: "blur(8px)",
}}
animate={{
opacity: 1,
y: 0,
filter: "blur(0px)",
}}
transition={{
delay: index * 0.08,
duration: 0.3,
}}
className={clsx("inline-block", letter === " " && "w-1")}
>
{letter}
</motion.span>
))}
</motion.div>
</motion.div>
</AnimatePresence>
Ben Lewis-Jones is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
- Please update the key prop for the motion.div to ensure React properly handles component re-renders. Changing keys can force React to unmount and remount components, which might be causing the glitch.
- Having multiple
motion.div
elements nested and animated might cause conflicts or unexpected behavior. Try simplifying the structure and animations.
This codebase is working on my end. Please let me know if you have any questions.
<AnimatePresence
onExitComplete={() => {
setIsAnimating(false);
}}
>
<motion.div
key={`${currentWord}-${xOffSet}`}
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
ref={divRef}
initial={{ x: xOffSet }}
animate={{ x: 0 }}
exit={{ x: -xOffSet }} // Add exit animation to ensure smooth removal
transition={{ duration: 1 }}
>
<p>{relativeClause}</p>
<motion.div key={currentWord}>
{currentWord.split("").map((letter, index) => (
<motion.span
key={`${currentWord}-${index}`}
initial={{
opacity: 0,
y: 10,
filter: "blur(8px)",
}}
animate={{
opacity: 1,
y: 0,
filter: "blur(0px)",
}}
transition={{
delay: index * 0.08,
duration: 0.3,
}}
className={clsx("inline-block", letter === " " && "w-1")}
>
{letter}
</motion.span>
))}
</motion.div>
</motion.div>
</AnimatePresence>
1