Jump to content
Search Community

Restart a child timeline

explorerzip test
Moderator Tag

Recommended Posts

I am new to the concept of nested timelines. Haven't had a real reason to use them, but thought I'd give it a try to reduce repeated code.

I have a child timeline that I want to play at the start of a master timeline and then restart it later on. The animation is for a banner ad. I added the child to the master and it plays once, but I can't seem to get it to restart. 

 How do I get it to restart later in the master timeline? It seems as if the restart call to the child timeline interferes with the first line in my master timeline.

See the Pen Yzpxqjv by explorerzip (@explorerzip) on CodePen

Link to comment
Share on other sites

  • explorerzip changed the title to Restart a child timeline
9 hours ago, tailbreezy said:

This is as easy as setting repeat: -1 on your master timeline.

Also no need to setup timeline with new gsap.timeline(). Just use gsap.timeline().

 


var masterTL = gsap.timeline({repeat:-1,
	defaults: {
		duration: 0.5,
		autoAlpha: 0
	}
});

 

 

Repeat: -1 won't work in my case because the master timeline needs to play just once. I only want to have the child timeline repeat once.
 

Link to comment
Share on other sites

2 hours ago, ZachSaucier said:

Just to be clear: If you add a tween or timeline to a timeline you probably shouldn't really control it outside of that timeline. If you need to do that sort of thing it's probably best to not add it to the timeline but just play it when you need it to.


What's are the reason that I shouldn't control a timeline inside another one? Is one timeline not able to see what the other is doing?

 

I'm also not sure what you mean by playing the child timeline when I need to. I assume that I need a delay in the child timeline?


Maybe my example isn't the best place to use a child timeline?

 

Link to comment
Share on other sites

I think you might be misunderstanding a fundamental concept with timelines - a child's playhead is always controlled by its parent timeline's playhead. That's a very powerful (and good) thing. Imagine you've got 100 tweens with duration: 2 that are all positioned at a startTime of 1 (second), so they're totally aligned. If you set the parent timeline's playhead to 1.5, that would instantly cause all those child tweens to have their playhead set to 0.5 seconds (remember, they start at 1 second, so if the parent playhead is at 1.5, that means it's 0.5-seconds into the tweens). 

 

So as the parent timeline's playhead sweeps across its children, it moves their playheads accordingly. 

 

Now let's imagine the parent timeline's playhead gets all the way to 5 seconds, so all those child tweens are completed (they were 2 seconds long, and started at the 1-second spot, thus they finished at 3 seconds). What would you expect to happen if you restart() one of those tweens? Logically, it would have to literally pick up that tween and move it so that the playhead is aligned properly with the parent timeline's playhead, meaning its new startTime would be 5! This could also affect the parent timeline's duration. For example, if it previously only had 5-seconds worth of animation in it, and then you restart() one of its children when the playhead is at the very end, now it'd have to be 7-seconds long (the 2-second tween just got shoved forward). 

 

See how it works? 

 

This is how the entire system works - there's a global timeline that everything gets placed on by default (including other timelines). Again, it's a super powerful (and surprisingly simple) concept that ensures everything is perfectly synchronized

 

By default, any timeline you create will have its smoothChildTiming property set to false, meaning that when you alter something in one of its children (like timeScale(), restart(), time(), etc.) it doesn't actually pick it up and move its startTime. Things are bolted down. You can, of course, set smoothChildTiming to true if you prefer and then things can slide around to align playheads and such, but of course that means the parent's duration can get altered and things can shift around in relation to one another. The global timeline has smoothChildTiming set to true, of course. 

 

Does that clear things up? 

  • Like 3
Link to comment
Share on other sites

45 minutes ago, GreenSock said:

I think you might be misunderstanding a fundamental concept with timelines - a child's playhead is always controlled by its parent timeline's playhead. That's a very powerful (and good) thing. Imagine you've got 100 tweens with duration: 2 that are all positioned at a startTime of 1 (second), so they're totally aligned. If you set the parent timeline's playhead to 1.5, that would instantly cause all those child tweens to have their playhead set to 0.5 seconds (remember, they start at 1 second, so if the parent playhead is at 1.5, that means it's 0.5-seconds into the tweens). 

 

So as the parent timeline's playhead sweeps across its children, it moves their playheads accordingly. 

 

I haven't needed to use child timelines before so I know I'm missing something. I don't really need to use a child timeline for this project, but figured I would take the opportunity to learn how they work since this project is simple.

Is it correct that all timelines play concurrently unless I use  paused:true?

 

Quote

Now let's imagine the parent timeline's playhead gets all the way to 5 seconds, so all those child tweens are completed (they were 2 seconds long, and started at the 1-second spot, thus they finished at 3 seconds). What would you expect to happen if you restart() one of those tweens? Logically, it would have to literally pick up that tween and move it so that the playhead is aligned properly with the parent timeline's playhead, meaning its new startTime would be 5! This could also affect the parent timeline's duration. For example, if it previously only had 5-seconds worth of animation in it, and then you restart() one of its children when the playhead is at the very end, now it'd have to be 7-seconds long (the 2-second tween just got shoved forward). 

 

See how it works? 

 

This is how the entire system works - there's a global timeline that everything gets placed on by default (including other timelines). Again, it's a super powerful (and surprisingly simple) concept that ensures everything is perfectly synchronized

 

I'm having a tough time visualizing how this works. I'll read it a few more times and view your YouTube content some more.

 

Quote

By default, any timeline you create will have its smoothChildTiming property set to false, meaning that when you alter something in one of its children (like timeScale(), restart(), time(), etc.) it doesn't actually pick it up and move its startTime. Things are bolted down. You can, of course, set smoothChildTiming to true if you prefer and then things can slide around to align playheads and such, but of course that means the parent's duration can get altered and things can shift around in relation to one another. The global timeline has smoothChildTiming set to true, of course. 

 

Does that clear things up? 


If I'm understanding correctly, the .add(wordTL.restart()) line is not doing executing because smoothChildTiming is set to false on my mainTL timeline? It also sounds like I can make smoothChildTiming to true, but it can cause some other issues?

Can you have a look at my codepen to see where I'm going wrong with my code?

Really appreciate you taking the time to reply Jack.

Link to comment
Share on other sites

49 minutes ago, explorerzip said:

Is it correct that all timelines play concurrently unless I use  paused:true?

Yes, assuming you mean non-nested ones. 

 

51 minutes ago, explorerzip said:

If I'm understanding correctly, the .add(wordTL.restart()) line is not doing executing because smoothChildTiming is set to false on my mainTL timeline?

It is executing, yes, but you're telling it to add() the result of wordTL.restart() (which returns the wordTL timeline) into that master timeline at the very end of it. You already put that at the beginning of the master timeline, but an animation instance cannot exist two places at the same time (just like a DOM node), so it removes it from where it was and puts it at the end because that's the last thing you requested. 

 

56 minutes ago, explorerzip said:

It also sounds like I can make smoothChildTiming to true, but it can cause some other issues?

It's not that it causes "issues" (like bugs or something) - it's just a different solution that can be super helpful in some cases but of course you need to understand what it's actually doing to avoid unexpected results. 

 

Think of a YouTube video, for example, that has a bunch of things happening during the video - maybe 3 things fade in, then other things zoom across the screen, etc. Imagine each of those actions are "tweens", and the overall video scrubber is the timeline. If you skip ahead on a YouTube video so that the playhead is in the middle, it'll instantly update all those sub-"tweens" (fades, zooms, etc.) to where they're supposed to be at that spot. Their individual playheads are controlled by (and synced up with) the parent timeline (YouTube video). 

 

So if you've got a fade-in at the beginning of a YouTube video (perhaps 1-second in), and then the entire video finishes playing, you wouldn't expect to restart() that individual fade (previously at 1-second in)...at the end. That'd be weird, right? And if you did restart just that sub-tween (fade) at that point (end of the YouTube video), what would you expect to happen if you dragged the YouTube video's playhead all the way back to the original position where that thing faded (1-second)? It can't live in both places at the same time. 

 

1 hour ago, explorerzip said:

Can you have a look at my codepen to see where I'm going wrong with my code?

Hopefully I explained the misunderstanding above (and why your code wasn't working as you had expected). 

 

As for how to "fix" it, there are many, many ways...

  1. Don't nest the timeline if your goal is to use it independently (have it play at one time...and then again at at different time...which isn't synchronized with other animations in a master timeline similar to a YouTube video). You can simply fire off instructions whenever you want, like with callbacks: 
    masterTL.add(() => wordTL.restart())
      .from(word2, {}, wordTL.duration())
      .to(word2, {}, "+=2")
      .add(() => wordTL.restart());

     

  2. - OR - Use a repeat value with a repeatDelay so that it repeats with the correct timing inbetween: 
    wordTL.repeat(1).repeatDelay(2); // repeat once with 2 seconds inbetween
    masterTL.add(wordTL)
      .from(word2, {duration: 1})
      .to(word2, {duration: 1});

     

  3. - OR - Pause the child timeline, and then just use various tweens to animate its playhead: 
    wordTL.pause();
    masterTL.add(wordTL.tweenFromTo(0, wordTL.duration()))
      .from(word2, {})
      .to(word2, {}, "+=2")
      .add(wordTL.tweenFromTo(0, wordTL.duration()));

     

I'm sure there are other ways too, but I don't want to overwhelm you :)

 

Trust me, once you "get it" regarding the timeline thing, everything falls into place and you'll be like "oh, that's so simple and logical..." but don't feel bad because a lot of people have been trained to only think in terms of individual "tweens" and it takes a little bit to step outside of that and see the broader picture. 

 

Basically, it's like changing a timeline's playhead has the effect of pulsing down through its children to update their playheads, and if those children have children, that pulses down through those, etc. Things can be nested as deeply as you want. I'd strongly recommend reading this article: https://css-tricks.com/tips-for-writing-animation-code-efficiently/

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

I think I'm starting to get what you mean, but I have much more experimenting to do. It does make sense that a timeline or any DOM objects can't be in two places at the same time.

Thanks also for your example code. I've never seen nor used arrow functions before as in your first example. Sadly I can't use arrow functions because I still have to support IE 🤦‍♂️ Banner ads need to show up on as many browsers as possible even though IE is basically dead.


Example 2 makes the most sense to me, but the trick is to get the repeatDelay value right.

 

Example 3 is interesting because I've also never used .tweenFromTo or .duration before.

 

Really appreciate the feedback Jack.

Link to comment
Share on other sites

6 hours ago, explorerzip said:

I've never seen nor used arrow functions before as in your first example. Sadly I can't use arrow functions because I still have to support IE

No problem! Arrow functions just make things more concise:

masterTL.add(function() { wordTL.restart(); })
  .from(word2, {}, wordTL.duration())
  .to(word2, {}, "+=2")
  .add(function() { wordTL.restart(); });

Happy tweening!

  • 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...