Jump to content
Search Community

GSAP 3 tween a timeline object

Abdou-tech test
Moderator Tag

Go to solution Solved by PointC,

Recommended Posts

I don't have a codepen but basically what i want to achieve is this:

 

I have some data loading in the background, and i'm using GSAP3 to create a timeline that's animating an svg infinitly, it's a preload animation basically. What i want to do is that when the data is loaded, i want to pause the current timeline object, animate it until the progress is 1, and then when the animation is completely finished i want to create another animation to smoothly animate the preloader out of the screen and then show the loaded data.


I saw an example of this in GSAP2 using TweenMax where: you pass the tweenmax object into the to() method, animate the progress property and then assign a callback function to the onComplete() property to kill the timeline object, but that doesn't seem to work in GSAP3, the svg abruptly jumps to the it's final state (where the progress is equel to 1) instead of animating to it. Can you please tell me how can i achieve this? I can't seem to find any example of this in GSAP3.

 

Thanks in advance!

Link to comment
Share on other sites

Oh i just found a solution i don't know if it's the only one but for those intrested: you basically pause the timeline, then create another timeline let's call it tl2, then you call the to() method on tl2 passing the first timeline as the target, and then you animate the progress property to 1 normally just like you would do with any other css property, if you want to do something when the animation finishes, just pass a callback function to the onComplet property just like this:

 

const endLoading = () => {
  	// tl is a timeline object tweening infinitly...
  	tl.pause();
	let tl2 = gsap.timeline();	
	tl2.to(tl, {
		duration: 0.5,
		progress: 1,
		onComplete: () => {
			tl.kill();
			console.log("Finished!");
            // Do some stuff...
		},
	});
};

 

Link to comment
Share on other sites

54 minutes ago, Abdou-tech said:

What i want to do is that when the data is loaded, i want to pause the current timeline object, animate it until the progress is 1, and then when the animation is completely finished i want to create another animation to smoothly animate the preloader out of the screen and then show the loaded data.

Why not use the onRepeat callback to do that? It's a lot simpler than pausing the timeline then playing it to the end...

onRepeat: () => {
  if(someCondition) {
    myTL.kill();
    mySecondTL.play();
  }
}

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Thank you so much for you reply! That makes much more sense haven't thought of that, im trying to achieve the same result using your solution but have one small issue: just before stopping, the animation kicks off again for a very short period then it stops (the progress is around 0.05 when it stops) any idea of what's causing this?

Link to comment
Share on other sites

I could be misunderstanding what you're suggesting, but it sounds like that's the exact situation that the original poster of this thread is in and the answer is the exact same. You'd need to either have the loader animation repeat (if you want it to continue animating) or it finishes in which case nothing extra has to be done. So I'm a bit confused why you'd need to do the original approach of the original poster in this situation.

 

There are definitely other cases where animating the progress of an animation in a tween is the best way to do things. I just don't see a case where it is the best way to do things related to this sort of thing.

Link to comment
Share on other sites

23 hours ago, Abdou-tech said:

but have one small issue: just before stopping, the animation kicks off again for a very short period then it stops (the progress is around 0.05 when it stops) any idea of what's causing this?

This is an edge case (I've never seen someone have an onRepeat kill() its own animation but it's entirely valid) that should be resolved in the next release.

 

Explanation: 

A lot of effort went into making sure repeats/loops are perfectly synchronized and never lead to time gaps. Most other animation engines use a technique that creates small gaps because they basically wait for the animation to complete, and then on that next update, they restart the animation. Sounds logical, right? But since things only get updated around 60 times per second, that means there is ALWAYS some amount of time gap. Like if the animation is supposed to last 1 second, the final update might actually happen 2ms before the end, and then 14.67ms later on the next update it's like "ok, the animation is officially done now, so restart()"...which means that there's now 14.67ms of time slippage. That builds up on each repeat. After a while, it can be a full second or two behind! That time slippage can make it drift out of sync with other animations. Very bad. 

 

That never happens in GSAP. 

 

Let's talk about your case: imagine that scenario where the playhead renders 2ms before the end of the timeline, and then the next "tick" happens 16.67ms later which is now technically 14.67ms AFTER the spot where it's supposed to repeat (loop back to the start). It must render at a time of 0 and fire the onRepeat, and then immediately (on the same tick) render as if the playhead is at 14.67ms in. So in this case, it was doing all that properly but you were killing the animation INSIDE the onRepeat which was in the middle of a render cycle that then went ahead and (in this example) rendered it at 14.67ms (and never again, since it's killed). 

 

Make sense?

 

I just needed to add some code to sense that condition and abort that 14.67 synchronization render if you kill the animation inside the onRepeat. 

 

If none of that made sense to you, don't worry about it. The short answer is: it'll be fixed in the next release (and you already have a workaround here). 👍

 

I already updated the beta at https://assets.codepen.io/16327/gsap-latest-beta.min.js (you may need to clear your cache)

  • Like 4
Link to comment
Share on other sites

13 hours ago, GreenSock said:

 It must render at a time of 0 and fire the onRepeat, and then immediately (on the same tick) render as if the playhead is at 14.67ms in. So in this case, it was doing all that properly but you were killing the animation INSIDE the onRepeat which was in the middle of a render cycle that then went ahead and (in this example) rendered it at 14.67ms (and never again, since it's killed). 

 

Oh now i kinda see the problem, so if i understood this correctly, we're always limited to that 16.7ms per tick to update things and render the next frame, and if the animation finishes 14.67ms before the next tick, which means the animation took only 2ms of the whole tick, we will always be left with 14.67ms of wasted time just waiting for the next tick to kick off and execute the restart() function, and that happens on each tick which means if the animations takes just 1s, around 0.8s (60 x 14.67ms) are completely wasted doing nothing but waiting right?

 

But i'm kinda confused on how does GSAP get around that, so if i got this correctly, GSAP does not restrict itself to the 16.67ms tick to update, instead it fires the onRepeat callback and starts rendering the next frame immediatly after the first one finishes, so according to this example and theoritically speaking, gsap renders about 8 frames in one tick insted of 1 frame, am I correct? So in my case, what happned is this: when i click the mouse to kill the animation, i do that somewhere in the middle of some "tick" but GSAP was already frames ahead (let's say frame 5 ) in that same "tick", so then when the next onRepeat is called, the one that's just after the mouse click, the animation is killed, but when the next tick (the next 16.7ms) kicks off, it renders those extra calculated frames that were calculated before the mouse click.

And that kinda explains why the animation was repeating but stopping on different progresses, it depended on how many extra frames were already rendered before i clicked the mouse i guess.

 

This is what i got from this 😅, not sure if i got this correctly please correct me if I'm wrong.

 

Thanks for your time, and for the detailed explanation!

Link to comment
Share on other sites

No, I think you misunderstood most of what I was trying to say :)

 

Core concept: animation is an illusion - it boils down to updating properties multiple times per second (usually about 60 times per second, thus 16.67ms between each update/tick). This is how ALL animations work on computers (even CSS animations/transitions). 

 

11 hours ago, Abdou-tech said:

according to this example and theoritically speaking, gsap renders about 8 frames in one tick insted of 1 frame, am I correct?

No, not at all. I'm not sure where you got that "8 frames in one tick" thing. 

 

Imagine in a perfect world, things run at exactly 60fps (which often isn't the case, depending on the CPU load, etc.) and you've got updates spaced out like this with 16.67ms inbetween each:

|----|----|----|----|

But maybe your tween is scheduled to end (or repeat) somewhere INBETWEEN those updates:

|----|----|----|----|
       ^// tween ends 

This is the scenario I'm talking about. GSAP factors that overshoot into its calculations. So if the tween is supposed to repeat at that spot (inbetween ticks), when it updates on the next tick it should render as if it is partially into that tween now. It should NOT start at zero again. However, developers may have code inside of an onRepeat that expects it to run at exactly 0, or there could be a callback positioned between the very start of that animation and where the playhead is supposed to render now, so it shouldn't get skipped. To accommodate that, GSAP does ONE extra render at precisely 0 in this scenario, calls the onRepeat, and then renders where the playhead is on the current tick (slightly past the start). 

 

Other animation engines will often just start over from zero and not factor in the overshoot at all, thus time slips every single repeat. The drift gets larger and larger. That never happens in GSAP. 

 

Does that clear things up? 

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...