zanntux Posted April 5 Share Posted April 5 Hello, I have a problem where I use the gsap.timeline for show/hide logic but it's not really smooth for the first 1-5 seconds. I expect this code to show/hide red and green box without flickering. But there is 1 frame where none of the boxes are shown. There is a small blue box under them for easier detection when the timeline is misbehaving. (I know I can achieve this with normal tweens, but the logic on my side is more complex and I'm using the timeline like a queue) Is this normal and why if it is or am I doing something wrong? I have isolated the problem with a simple codepen. See the Pen WNWMMaq by martin-nikolov (@martin-nikolov) on CodePen Link to comment Share on other sites More sharing options...
Rodrigo Posted April 5 Share Posted April 5 Hi @zanntux and welcome to the GSAP Forums! I'm not 100% sure, but this could be related to the fact that you call the init method, where you add the display none style to the elements. Then the GSAP instances are created and then a single tick runs before the GSAP timeline starts which could lead to this behaviour. Although a single GSAP tick is just 16 milliseconds, so IDK if that should be enough to show the blue element behind and to be noticeable. We'll look into this and let you know. Happy Tweening! 1 Link to comment Share on other sites More sharing options...
Solution GreenSock Posted April 7 Solution Share Posted April 7 It's not really a bug. It's just a fundamental logic problem in the way you're setting things up. Let me explain... In order for a callback to fire, the playhead must cross that spot on its parent timeline, or land directly on top of it. So it's based on the playhead moving (its new position). The timeline doesn't render for the first time until the next tick (it'd be silly to render right away by default because the playhead hasn't moved anywhere yet, so it'd be a waste of CPU cycles). That's why the very first one didn't fire right away. The timeline's playhead updates on each "tick" which is typically about every 16.67ms but that really depends on the browser and how busy the CPU is, etc. Your timeline is 2 seconds long and has repeat: -1. So let's say it renders almost at the end, at like 1.9857 seconds, and then on the next tick, the totalTime renders at 2.013 which means that it went past the end and wrapped around to the beginning, and 0.013 seconds into the timeline (from the start). In that ONE tick, it'd fire that callback that's at the very end of the timeline AND since it looped back to the beginning and went a little bit past, it ALSO triggers the callback that's sitting at the very start. Great. BUT What if the playhead happens to land EXACTLY at the end of the timeline (2 seconds precisely)? What do you think should happen? Obviously the callback at the end should fire, but should the callback that's sitting at the very START of the timeline also fire? I mean the end of the timeline and the start of the timeline are not the same technically, so it'd be weird if both fired. The playhead can't be at 2 seconds AND at 0 seconds. It wouldn't make a lot of sense to fire the callbacks from BOTH places on that ONE tick. See the problem? There are many ways to accomplish what I think you're trying to do there (alter visibility of things in a synchronized way), but I'd need to see what other requirements you have in order to offer the best recommendation. Thanks for the excellent minimal demo, by the way. 👍 2 1 Link to comment Share on other sites More sharing options...
zanntux Posted April 8 Author Share Posted April 8 Thank you for the detailed explanation! I didn't know the timeline will render on the next tick. I've made a new pen where show/hide is called in single delayedCall to make sure everything is synchronized. I will try to adapt this solution. I guess immediateRender is only for tweens? See the Pen gOyeezJ by martin-nikolov (@martin-nikolov) on CodePen Link to comment Share on other sites More sharing options...
GreenSock Posted April 8 Share Posted April 8 Sure, that's one way you could do it. A few suggestions: Don't use "new": // BAD let childTl = new gsap.timeline({}); // GOOD let childTl = gsap.timeline(); This can be simplified: // OLD elements.forEach((element, index, array) => { element.style.display = "none"; }); // NEW gsap.set(elements, {display: "none"}); Since you're not using params anyway, just use .add() instead of .call(): // OLD childTl.call(() => { //... }, [], 1); // NEW childTl.add(() => { //... }, 1); I think you could greatly simplify the logic too: See the Pen YzMaBME?editors=0010 by GreenSock (@GreenSock) on CodePen Like I said, there are many, many ways to tackle this. Hopefully this helps get you on your way to something that works well for you. 1 Link to comment Share on other sites More sharing options...
GreenSock Posted April 8 Share Posted April 8 Also, you can easily force a render of a tween or timeline, and even improve runtime performance slightly by forcing all the tweens inside a timeline to initialize and grab their start/end values like this: // jump to the end and immediately back to the start animation.progress(1).progress(0); 1 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