Jump to content


Align timeline tween ends with dynamic duration

Go to solution Solved by GreenSock,

Recommended Posts


hello fellow humans.

feels really nice to join this awesome community.

i found so much help here already. now its time to make my own first post.


- - -


so! i would love to get some help on positioning tweens inside a timeline as i was not able to find an elegant solution until this point.


the attached image explains what i got and what i want. so i have a main tween in my timeline that has a duration of 2s. and a few others that are shorter in time. now, basically i want to dynamically align all the other tween endpoints with the main tween's endpoint. i say dynamically because tween durations will change within the website. i know that i can use the relative position parameter for this. and with absolute numbers it works beautifully:


// create timeline
let timeline = gsap.timeline();

// add tweens
timeline.add(container.fadeOut(), 0);
timeline.add(elements.fadeOut(),  '-=1.2');
timeline.add(footer.fadeOut(),    '-=1.4');
timeline.add(progress.reset(),    '-=1.8');


but what happens if for example my footer.fadeOut() tween changes its duration to 0.8s? with my code example, the endpoints of footer.fadeOut() and container.fadeOut() are not aligned anymore. how can i dynamically change the -1.2s to -0.8s?  how can i subtract the tweens own duration, relative from the timeline endpoint? and how can i do this elegantly without using tons of variables to get each tween's duration?


thank you so much for taking your time.

stay healthy, stay safe.




Link to comment
Share on other sites

Hey jaro and welcome to the community :) 


52 minutes ago, quastiqualle said:

basically i want to dynamically align all the other tween endpoints with the main tween's endpoint

For the second tween that you have you can do this using the '>' position parameter operator. Actually you just need to sequence it. No position parameter needed.

Then for the tweens after you can use the '<' position parameter operator:

let timeline = gsap.timeline();

// add tweens
timeline.add(footer.fadeOut(),   '<');
timeline.add(progress.reset(),   '<');

For more info see the position parameter post.

  • Like 1
Link to comment
Share on other sites

hey @ZachSaucier.

thank you for your answer.


of course i was already looking at the link you sent before posting. but based on whats written there, wouldnt adding the '<' position parameter align the start times instead of the end times? and '>' in fact would just sequence the tweens one after the other.



Relative to the previously added tween ("<" references the most recently-added animation's START time while ">" references the most recently-added animation's END time)



this is what i end up with:

See the Pen vYXXXzr by jaro_io (@jaro_io) on CodePen



this is what i want, but without using absolut values:

See the Pen vYXXXQa by jaro_io (@jaro_io) on CodePen



so my question is: how can i achieve the result from the second pen without relying on absolute position values?

thank you!


Link to comment
Share on other sites

Not sure if this helps, and I'm also not sure of how the durations are generated, but this kind of thing seems to work on initial test:


let dur_green = 4,
    dur_orange = 2,
    dur_grey = 3;
tl.to(".green",  { x: 200, duration: dur_green });
tl.to(".orange", { x: 200, duration: dur_orange }, '>' + dur_orange - dur_green  );
tl.to(".grey",   { x: 200, duration: dur_grey }, '>'  + dur_grey - dur_orange);

initially, I had the dur_ variables set to 3, 1 and 2 respectively as per your example. changed to 4,2 and 3 and the end times are still aligned.

although, on re-reading your post, perhaps this falls into the not-so-elegant category ...

  • Like 4
Link to comment
Share on other sites

Ah, sorry. I misunderstood what you were wanting. 


Things are added to the timeline based on their start point regardless of how long they are. This is the first time I think I've seen someone asking to position things by their end position instead :) 


I would use an approach similar to the one that darkgr33n suggests, perhaps a little more elegantly by using a helper function ;) 


See the Pen YzGGxMv?editors=0010 by GreenSock (@GreenSock) on CodePen


The above works great if the longest tween is the first one given. You might also need to have some additional code to make sure that happens if you're creating these tweens dynamically.

  • Like 4
Link to comment
Share on other sites

  • Solution

There are actually a ton of ways you could do this. Here's one other option - use a helper function that you can just feed a timeline to and it'll make all the children line up their end times: 

function alignEnds(tl) {
  let children = tl.getChildren().sort((a, b) => b.duration() - a.duration()),
      longest = children[0].duration();
  children.forEach(child => child.startTime(longest - child.duration()));

Then, if you're building a bigger timeline, you could just create a sub-timeline for this "grouped" set of tweens, sorta like: 

let master = gsap.timeline();
master.to(...); //whatever
let grouped = gsap.timeline();
alignEnds(grouped); // align their end times

master.add(grouped); // slap the aligned group into the master

Lots of flexibility. 

See the Pen 4ed3df882b55adc8b2235a30d02341a4 by GreenSock (@GreenSock) on CodePen

  • Like 3
Link to comment
Share on other sites


thank you so so much @GreenSock.

really really nice!


maybe someday you guys will also add a position parameter for aligning end points. something like'<>' or so.. 😇

Link to comment
Share on other sites

12 minutes ago, quastiqualle said:

maybe someday you guys will also add a position parameter for aligning end points.

Maybe. But like I said, I think you're the first person to want this functionality in the ~1.5 years I've worked at GreenSock so it doesn't seem like it's worth adding the kb for everyone at this point.

  • Like 1
Link to comment
Share on other sites

I'm not sure how we could adjust the API, though, because in your case you're trying to align the end of a bunch of things to another thing, right?. If you just want to match the end time of the previously-added animation, it's as simple as: 

tl.to(... {duration: 0.8, ...}, tl.recent().endTime() - 0.8);

Or if you know it's always at the end of the timeline, it's as simple as:

tl.to(..., {duration: 0.8, ...}, "-=0.8");


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