eggroll Posted October 23, 2023 Share Posted October 23, 2023 Greetings everyone! I'm thrilled to be part of this community, and it's my first foray into using GSAP for animations. While it's proving to be a bit of a challenge, I'm making steady progress thanks to the documentation. I'm just about wrapping up my animations. In my current React project, I'm employing GSAP's ScrollTrigger to animate a component nested within a wrapper, which I've imported into my main JSX file. I've run into a small snag. When a user is scrolling and they hit the ScrollTrigger start line, the animation can retrigger too rapidly, resulting in a less-than-ideal visual experience. I'm wondering if there's a way to introduce some kind of buffer, perhaps in the form of margins, to prevent users from quickly toggling the animation on and off. I've posted a snippet of my code below. I'm eager to optimize my code for the best user experience possible. Your insights would be greatly appreciated! Looking forward to diving deeper into GSAP and learning more. Thank you in advance! Inside my animations.jsx export const SlideUp = ({ children, y }) => { const elementRef = useRef(null); useEffect(() => { const element = elementRef.current; gsap.set(element, { opacity: 0 }); const animateIn = () => { gsap.fromTo( element, { opacity: 0, y: y || 50 }, { opacity: 1, y: 0, duration: 1, ease: 'power3.out' } ); }; const scrollTrigger = ScrollTrigger.create({ trigger: element, start: 'top bottom', onEnter: () => { animateIn(); }, scrub: true, }); return () => { scrollTrigger.kill(); }; }, []); }; Inside my main page <SlideUp> <div className="image-row"> <div className="content-container"> <img className="project-image" src="images/img1.webp" alt="" draggable="false" /> </div> <div className="content-container"> <img className="project-image" src="images/img2.webp" alt="" draggable="false" /> </div> </div> </SlideUp> Link to comment Share on other sites More sharing options...
GSAP Helper Posted October 24, 2023 Share Posted October 24, 2023 Hi there! Welcome to the community, @eggroll ? I see you're using React - Proper animation cleanup is very important with frameworks, but especially with React. React 18 runs in strict mode locally by default which causes your useEffect() and useLayoutEffect() to get called TWICE. In GSAP 3.11, we introduced a new gsap.context() feature that helps make animation cleanup a breeze. All you need to do is wrap your code in a context call. All GSAP animations and ScrollTriggers created within the function get collected up in that context so that you can easily revert() ALL of them at once. Here's the structure: // typically it's best to useLayoutEffect() instead of useEffect() to have React render the initial state properly from the very start. useLayoutEffect(() => { let ctx = gsap.context(() => { // all your GSAP animation code here }); return () => ctx.revert(); // <- cleanup! }, []); This pattern follows React's best practices, and one of the React team members chimed in here if you'd like more background. We strongly recommend reading the React information we've put together at https://gsap.com/resources/React/ Happy tweening! Also, it's pretty tough to troubleshoot without a minimal demo. Here's a Stackblitz starter template that you can fork: https://stackblitz.com/edit/react-cxv92j Please don't include your whole project. Just some colored <div> elements and the GSAP code is best. See if you can recreate the issue with as few dependancies as possible. If not, incrementally add code bit by bit until it breaks. Usually people solve their own issues during this process! If not, then at least we have a reduced test case which greatly increases your chances of getting a relevant answer. Please share the StackBlitz link directly to the file in question (where you've put the GSAP code) so we don't need to hunt through all the files. Once we see an isolated demo, we'll do our best to jump in and help with your GSAP-specific questions. Link to comment Share on other sites More sharing options...
eggroll Posted October 24, 2023 Author Share Posted October 24, 2023 Hey GSAP Helper! Thanks a bunch for getting back to me! I've whipped up a quick demo of my site using StackBlitz. You can check it out here! Let me know if you can view the code. Going to take a deeper look into gsap.context() as well. Looking forward to hearing your thoughts! Link to comment Share on other sites More sharing options...
GreenSock Posted October 25, 2023 Share Posted October 25, 2023 Thanks for putting a demo together. I took a look and I'm kinda lost - what exactly is the problem? I scrolled up and down and didn't notice anything that fit this description: "When a user is scrolling and they hit the ScrollTrigger start line, the animation can retrigger too rapidly, resulting in a less-than-ideal visual experience" Help? Could you please be super specific about how exactly we can reproduce the issue? And I'd definitely recommend using gsap.context() so that you're doing proper cleanup in React. See https://gsap.com/react Link to comment Share on other sites More sharing options...
eggroll Posted October 25, 2023 Author Share Posted October 25, 2023 Hi GreenSock! I apologize for any confusion. To clarify, when I refer to an animation potentially retriggering too rapidly, I mean that it occurs while the current animation is still in progress, causing it to reset. My objective is to ensure that once an animation is triggered, it should complete before ScrollTrigger reactivates it. If you scroll down to the section where ExpandDivider is featured in the demo, you'll notice a momentary interruption in the animation. This happens as the user scrolls up and down activating the ScrollTrigger start line. Link to comment Share on other sites More sharing options...
eggroll Posted October 25, 2023 Author Share Posted October 25, 2023 I've gone ahead and updated the demo to showcase the retrigger animation problem that is more evident. Link to comment Share on other sites More sharing options...
Solution GreenSock Posted October 25, 2023 Solution Share Posted October 25, 2023 Ah, okay - just set overwrite: true on the staggered tween. Is that what you're looking for? https://stackblitz.com/edit/react-4vxqpg?file=src%2FAnimations.jsx Link to comment Share on other sites More sharing options...
eggroll Posted October 25, 2023 Author Share Posted October 25, 2023 Yes thank you so much! Is there a way I could have the animation timeout that way a user cannot reset the animation too quickly? I'm not seeing any GSAP property that allows me to do this. What comes to mind is setTimeout. Thanks in advance! Link to comment Share on other sites More sharing options...
GreenSock Posted October 25, 2023 Share Posted October 25, 2023 Sorry, I don't quite understand what you're asking. You can set a "delay" on any animation. Super easy. Is that what you're looking for? Are you saying that if a user scrolls up/down/up/down super fast right at the spot where the animation begins, you want to prevent it from running again or something? Link to comment Share on other sites More sharing options...
eggroll Posted October 25, 2023 Author Share Posted October 25, 2023 Yes correct! If a user scrolls up and down super fast where the animation begins it causes a flicker issue. I want to prevent the animation from being run if it is currently being animated. Link to comment Share on other sites More sharing options...
GreenSock Posted October 25, 2023 Share Posted October 25, 2023 Sure, just add some conditional logic. if (animation && animation.isActive()) { return; } https://stackblitz.com/edit/react-tgoqxz?file=src%2FAnimations.jsx Is that what you mean? Link to comment Share on other sites More sharing options...
eggroll Posted October 25, 2023 Author Share Posted October 25, 2023 It's fantastic! However, I've noticed that if animations have different durations, they reset independently based on their respective durations. How can I ensure that if two animations are triggered simultaneously on the same trigger line, they will reset and start playing at the same time? I've created a demo of the problem here. Link to comment Share on other sites More sharing options...
GreenSock Posted October 25, 2023 Share Posted October 25, 2023 This is all just logic and JavaScript stuff - we really try to keep these forums focused on GSAP-specific questions. In your demo, you've got completely different calls to the SplitWord function but it sounds like you're trying to somehow correlate them based on their proximity? Like...if you had 10 of them all strewn out at different spots across the entire height of the page, what behavior are you expecting? If any of them are running, none of them reset? Or only if they're within X pixels of each other? These are all logic things you've gotta decide and then wire it up accordingly. Maybe you use a global variable that keeps track of all the animations and you can check their progress and run whatever logic you want. Maybe you check the associated ScrollTrigger's start value to see if it's within a certain range and conditionally skip (or not). Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now