Jump to content
Search Community

Best way to convert a series of TweenMax sequences into a manageable TimelineMax variable

sorciereus test
Moderator Tag

Go to solution Solved by Jonathan,

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hi there, I have the following TweenMax sequence:


expandedAnimation = function() {
var i = 0;
var a = 1;
var d = 2.25;
var t = 0;
var o = 4.25;

TweenMax.set('#dc_logo', {alpha:a});
TweenMax.set('#videoContent', {alpha:i});
TweenMax.set('#exp_txt1', {alpha:i});
TweenMax.set('#exp_txt2', {alpha:i});
TweenMax.set('#exp_txt3', {alpha:i});
TweenMax.set('#exp_txt4', {alpha:i});
TweenMax.set('#exp_txt5', {alpha:i});
TweenMax.set('#exp_txt6', {alpha:i});
TweenMax.set('#exp_txt2_1', {alpha:i});
TweenMax.set('#exp_txt2_2', {alpha:i});
TweenMax.set('#exp_txt2_3', {alpha:i});
TweenMax.set('#exp_txt2_4', {alpha:i});
TweenMax.set('#exp_txt2_5', {alpha:i});
TweenMax.set('#exp_join', {alpha:i});
TweenMax.set('#bar', {alpha:a, width:0});
TweenMax.set('#logo', {alpha:a});

TweenMax.to('#exp_txt1', t, {alpha:a, delay:.25});
TweenMax.to('#exp_txt2', t, {alpha:a, delay:.5});
TweenMax.to('#exp_txt3', t, {alpha:a, delay:.75});
TweenMax.to('#exp_txt4', t, {alpha:a, delay:1});
TweenMax.to('#exp_txt5', t, {alpha:a, delay:1.25});
TweenMax.to('#exp_txt6', t, {alpha:a, delay:1.5});

TweenMax.to('#exp_txt1', t, {alpha:i, delay:d});
TweenMax.to('#exp_txt2', t, {alpha:i, delay:d});
TweenMax.to('#exp_txt3', t, {alpha:i, delay:d});
TweenMax.to('#exp_txt4', t, {alpha:i, delay:d});
TweenMax.to('#exp_txt5', t, {alpha:i, delay:d});
TweenMax.to('#exp_txt6', t, {alpha:i, delay:d});

TweenMax.to('#exp_txt2_1', t, {alpha:a, delay:2.5});
TweenMax.to('#exp_txt2_2', t, {alpha:a, delay:2.75});
TweenMax.to('#exp_txt2_3', t, {alpha:a, delay:3});
TweenMax.to('#exp_txt2_4', t, {alpha:a, delay:3.25});
TweenMax.to('#exp_txt2_5', t, {alpha:a, delay:3.5});

TweenMax.to('#exp_txt2_1', t, {alpha:i, delay:o});
TweenMax.to('#exp_txt2_2', t, {alpha:i, delay:o});
TweenMax.to('#exp_txt2_3', t, {alpha:i, delay:o});
TweenMax.to('#exp_txt2_4', t, {alpha:i, delay:o});
TweenMax.to('#exp_txt2_5', t, {alpha:i, delay:o}); 

TweenMax.to('#exp_join', t, {alpha:a, delay:4.25});
TweenMax.to('#bar', .5, {width:82, delay:4.25});

TweenMax.to('#exp_join', t, {alpha:i, delay:5.5});
TweenMax.to('#bar', t, {alpha:i, delay:5.5});
TweenMax.to('#logo', t, {alpha:i, delay:5.5});

TweenMax.to('#dc_logo', t, {alpha:i, delay:5.5});
TweenMax.to('#videoContent', t, {alpha:a, delay:5.5, onComplete:startVideo});
startVideo = function() {

I know this is probably simple for some, but I'd like to convert this to TimelineMax because I need the animation to stop executing if my banner is closed, and reset, and begin animation again if it's re expanded. Right now, if you close the ad mid animation, and then re-expand, the code that was previously executing is still running, and then a new set starts again making a huge mess.


When I tried converting to TimelineMax by using the var tl = new TimelineMax() and then tl.add to each one the delays got all messed up and I wasn't sure how to get the same results. Is there an easier way to reset/pause my function without totally redoing all my delays and etc? Any help would be appreciated. 


Thank you

Link to comment
Share on other sites

  • Solution

Hello sorciereus,


Here is a way you can try to setup your timeline, which will result in greater timeline management and reuse of animation parts:


For example you can setup your different parts like this below example. The functions return the child timelines to be used in the add() method for your master timeline:

/* create master timeline instance in a paused state
var masterTL = new TimelineMax({paused:true});

function carMove() {

    var tl = new TimelineMax();

    tl.to("#car", 2, {
        x: "+=200"
    /* more tweens go here */
    return tl;

function wheelsRotate() {
    var tl = new TimelineMax();
    tl.to("#wheels", 2, {
        rotation: "+=360"
    /* more tweens go here */
    return tl;

.add(carMove(),"car") // since both tweens use the 'car' label they will play at the same time
.add(wheelsRotate(),"car") // see position parameter video below

The GSAP add() method accepts a tween, timeline, callback, or label (or an array of them) to the timeline.




If you go to the homepage. The main homepage banner is made this way.


Look at the code comments in this GreenSock codepen:


See the Pen yhEmn by GreenSock (@GreenSock) on CodePen


This is the recommended way to setup and manage multiple nested timelines in GSAP by GreenSock. It gives you the best control for managing your animation, and makes adding or removing nested timelines much easier. Then when you adjust the position parameter in the add() method, you can change the timing  much faster if things change in your master timeline.


Each part of your animation is in a separate function, which returns that timeline in the add method. Even though you could use other ways to manage your timeline, doing it this way guarantees you have a manageable timeline that will be easier to maintain and manage as your animation grows and becomes more complex! And gives you the ability to seek() and set up a scrubber to further test your animation, like in the Home Page banner.


Also this video by Carl, can also give you ideas on setting up a timeline for sequencing your animation.



And the position parameter video:



I hope this helps! :)

  • Like 1
Link to comment
Share on other sites

Does the TweenMax.set work properly in TimelineMax? Also, say I have a sequence I want to begin at the same time, following another sequence, for example if you look at my code:

TweenMax.to('#exp_txt1', t, {alpha:i, delay:d});
TweenMax.to('#exp_txt2', t, {alpha:i, delay:d});
TweenMax.to('#exp_txt3', t, {alpha:i, delay:d});
TweenMax.to('#exp_txt4', t, {alpha:i, delay:d});
TweenMax.to('#exp_txt5', t, {alpha:i, delay:d});
TweenMax.to('#exp_txt6', t, {alpha:i, delay:d});

That all shares the same delay, how would I accomplish that? 

Link to comment
Share on other sites

Sorry I'm struggling a bit with using delay in timelinemax - when I convert and do as you said everything plays all at once in a mess - can you use the code I provided to show more of an example? Sorry I'm needing this rather urgently and finding TimelineMax difficult with the delays and how that would directly convert from what I have to simulate the timing.   I did this:


var masterTL = new TimelineMax({paused:true});
var i = 0;
var a = 1;
var d = 3.3;
var t = 0;
var t2 = .2;
var o = 6.2;

function setProperties() {
var tl = new TimelineMax(); 
tl.add( TweenMax.set('#dc_logo', {alpha:a}) );
tl.add( TweenMax.set('#videoContent', {alpha:i}) );
tl.add( TweenMax.set('#exp_txt1', {alpha:i}) );
tl.add( TweenMax.set('#exp_txt2', {alpha:i}) );
tl.add( TweenMax.set('#exp_txt3', {alpha:i}) );
tl.add( TweenMax.set('#exp_txt4', {alpha:i}) );
tl.add( TweenMax.set('#exp_txt5', {alpha:i}) );
tl.add( TweenMax.set('#exp_txt6', {alpha:i}) );
tl.add( TweenMax.set('#exp_txt2_1', {alpha:i}) );
tl.add( TweenMax.set('#exp_txt2_2', {alpha:i}) );
tl.add( TweenMax.set('#exp_txt2_3', {alpha:i}) );
tl.add( TweenMax.set('#exp_txt2_4', {alpha:i}) );
tl.add( TweenMax.set('#exp_txt2_5', {alpha:i}) );
tl.add( TweenMax.set('#exp_join', {alpha:i}) );
tl.add( TweenMax.set('#exp_us', {alpha:i}) );
tl.add( TweenMax.set('#bar', {alpha:a, width:0}) );
tl.add( TweenMax.set('#logo', {alpha:a}) );
return tl;


function line1() { 
var tl2 = new TimelineMax();
tl2.add( TweenMax.to('#exp_txt1', t, {alpha:a}) );
tl2.add( TweenMax.to('#exp_txt2', t, {alpha:a}) );
tl2.add( TweenMax.to('#exp_txt3', t, {alpha:a}) );
tl2.add( TweenMax.to('#exp_txt4', t, {alpha:a}) );
tl2.add( TweenMax.to('#exp_txt5', t, {alpha:a}) );
tl2.add( TweenMax.to('#exp_txt6', t, {alpha:a}) );

tl2.add( TweenMax.to('#exp_txt1', t2, {alpha:i}) );
tl2.add( TweenMax.to('#exp_txt2', t2, {alpha:i}) );
tl2.add( TweenMax.to('#exp_txt3', t2, {alpha:i}) );
tl2.add( TweenMax.to('#exp_txt4', t2, {alpha:i}) );
tl2.add( TweenMax.to('#exp_txt5', t2, {alpha:i}) );
tl2.add( TweenMax.to('#exp_txt6', t2, {alpha:i}) );
return tl2;

function line2() {
var tl3 = new TimelineMax();
tl3.add( TweenMax.to('#exp_txt2_1', t, {alpha:a}) );
tl3.add( TweenMax.to('#exp_txt2_2', t, {alpha:a}) );
tl3.add( TweenMax.to('#exp_txt2_3', t, {alpha:a}) );
tl3.add( TweenMax.to('#exp_txt2_4', t, {alpha:a}) );
tl3.add( TweenMax.to('#exp_txt2_5', t, {alpha:a}) );

tl3.add( TweenMax.to('#exp_txt2_1', t2, {alpha:i}) );
tl3.add( TweenMax.to('#exp_txt2_2', t2, {alpha:i}) );
tl3.add( TweenMax.to('#exp_txt2_3', t2, {alpha:i}) );
tl3.add( TweenMax.to('#exp_txt2_4', t2, {alpha:i}) );
tl3.add( TweenMax.to('#exp_txt2_5', t2, {alpha:i}) ); 

tl3.add( TweenMax.to('#exp_join', t, {alpha:a}) );
tl3.add( TweenMax.to('#exp_us', t, {alpha:a}) );
tl3.add( TweenMax.to('#bar', .5, {width:82}) );

tl3.add( TweenMax.to('#exp_join', t2, {alpha:i}) );
tl3.add( TweenMax.to('#exp_us', t2, {alpha:i}) );
tl3.add( TweenMax.to('#bar', t2, {alpha:i}) );
tl3.add( TweenMax.to('#logo', t2, {alpha:i}) );
return tl3;

function endAnimation() {
var tl4 = new TimelineMax();
tl4.add( TweenMax.to('#dc_logo', t, {alpha:i}, 0) );
tl4.add( TweenMax.to('#videoContent', t, {alpha:a, onComplete:startVideo}, 0) );
return tl4;
startVideo = function() {

stopVideo = function() {
vplayer.currentTime = 0;


expandedAnimation = function() {
.add(setProperties(), 0) 
.add(line1(), .3)
.add(line2(), 3.3)
.add(endAnimation(), 7)

And it just looks nothing like the TweenMax without the TimelineMax - it's junk. Obviously I'm getting the setting wrong - it would be nice to get a bit more help here if possible. 

Link to comment
Share on other sites

Have you looked at the videos i posted above?

If you look at the videos I posted above, Carl goes into converting a bunch of TweenMax tweens into a TimelineMax timeline. In the video he shows how he removes the delay property and uses the position parameter instead. I suggest you look at those videos and also check out the TimelineMax Docs.


In your functions there is no need to use the add() method just use your timeline instance inside the function. And just use the add() method for your master timeline.

So this:

tl3.add( TweenMax.to('#exp_join', t2, {alpha:i}) );

would become this

tl3.to('#exp_join', t2, {alpha:i});

And do that for the rest of your tweens inside your functions. Also i notice you have your master timeline masterTL inside a
expandedAnimation function but i don't see anywhere where you are calling that function to run. I would just take that code in the masterTL and move it outside of your expandedAnimation function.

Also you could also setup a codepen example so we can test your code live and in context. Here is a video on how to create a codepen demo example:




Link to comment
Share on other sites

You might have to fix your codepen. In your CSS your are missing a squiggly bracket ( } )for the first CSS rule #expanded. And since you are missing images and video files codpen is throwing errors. I would suggest to just make a reduced codepen and use a placeholder image url's like this




And remove the video files if you cant provide the absolute path. You are also calling the vplayer.play() but you have no variable that vplayer references. And you did not include TweenMax into your codepen. Also i noticed inside your functions your not returning your timeline instance. And you are calling expandedAnimation() before your functions are loaded.


Try to make those changes, thanks!

Link to comment
Share on other sites

Jonathan has given excellent advice, but to add a little more info. 


The reason things get messed up when you wrap your code with tl.add(TweenMax.to()) is because every time you add() something to a timeline it naturally goes at the end of the timeline, and then you also have delays in your tweens which compounds shifts in the timing.


There are basically 2 ways to do easily convert what you have.


1: use the add() method BUT give each tween a position of 0

tl.add(TweenMax.to('#exp_txt1', t, {alpha:a, delay:.25}), 0);
tl.add(TweenMax.to('#exp_txt2', t, {alpha:a, delay:.5}), 0);
tl.add(TweenMax.to('#exp_txt3', t, {alpha:a, delay:.75}), 0);
tl.add(TweenMax.to('#exp_txt4', t, {alpha:a, delay:1}), 0);
tl.add(TweenMax.to('#exp_txt5', t, {alpha:a, delay:1.25}, 0);
tl.add(TweenMax.to('#exp_txt6', t, {alpha:a, delay:1.5}), 0);

Basically this adds all the tweens at a time of 0, but the delay will offset their start times.

2: Use tl.to(), tl.set(), etc and convert your delays to absolute position values (read the article on the position parameter Jonathan supplied above)
tl.to('#exp_txt1', t, {alpha:a}, 0.25)
tl.to('#exp_txt2', t, {alpha:a}, 0.5);
tl.to('#exp_txt3', t, {alpha:a}, 0.75);
tl.to('#exp_txt4', t, {alpha:a}, 1);
tl.to('#exp_txt5', t, {alpha:a}, 1.25);
tl.to('#exp_txt6', t, {alpha:a}, 1.5);
Also, I'm just realizing that each tween above is offset by 0.25 and you could just use a staggerTo()
tl.staggerTo("#exp_txt1, #exp_txt2, #exp_txt3", t, {alpha:1}, 0.25);

[docs id=js.TimelineLite.staggerTo()" linktext="TimelineMax.staggerTo() docs]

  • Like 2
Link to comment
Share on other sites

Jumping in here only because I have so much background in Rich Media expanded ads. Ads that have expansion functionality typically use a specific vendor's API to handle the functionality, one of which may be frequency capping, expansion and engagement metrics, and can vary by publisher. For instance MSN specs are that if the user left the ad expanded when they left the page, it will be expanded when they return.


Do you know which Rich Media vendor this ad will be served and trafficked from? Expansion and video are both qualifiers for "is this ad rich media?".


If it is Doubleclick Studio, studio's enabler.js should handle killing animation and resetting. Here are the templates filtered for HTML5 and IAB Billboard which is 970x250.




Here are templates filtered for HTML5, expanding and 970x250



  • Like 1
Link to comment
Share on other sites

Thanks so much for all the responses! Very helpful.  Somnamblst, I also work alot with RM Doubleclick templates, and you are correct, the template usually kills off and resets the animation automatically - i was however using a custom template that DC whipped up for me on the fly for a last minute request for a special ad. 


I solved this by rewriting the code into straight TimelineMax sequence that wasn't broken into functions. It works perfectly Here was my result:


var tl = new TimelineMax({paused:true, onComplete:startVideo}); 
tl.to('#dc_logo', 0, {alpha:a}, 0)
.to('#videoContent', 0, {alpha:i}, 0)
.to('#exp_txt1', 0, {alpha:i}, 0) 
.to('#exp_txt2', 0, {alpha:i}, 0) 
.to('#exp_txt3', 0, {alpha:i}, 0) 
.to('#exp_txt4', 0, {alpha:i}, 0) 
.to('#exp_txt5', 0, {alpha:i}, 0) 
.to('#exp_txt6', 0, {alpha:i}, 0) 
.to('#exp_txt2_1', 0, {alpha:i}, 0) 
.to('#exp_txt2_2', 0, {alpha:i}, 0) 
.to('#exp_txt2_3', 0, {alpha:i}, 0) 
.to('#exp_txt2_4', 0, {alpha:i}, 0) 
.to('#exp_txt2_5', 0, {alpha:i}, 0) 
.to('#exp_join', 0, {alpha:i}, 0) 
.to('#exp_us', 0, {alpha:i}, 0) 
.to('#bar', 0, {alpha:a, width:0}, 0) 
.to('#logo', 0, {alpha:a}, 0) 

.to('#exp_txt1', t, {alpha:a}, "+=.2")
.to('#exp_txt2', t, {alpha:a}, "+=.2")
.to('#exp_txt3', t, {alpha:a}, "+=.2")
.to('#exp_txt4', t, {alpha:a}, "+=.2")
.to('#exp_txt5', t, {alpha:a}, "+=.2")
.to('#exp_txt6', t, {alpha:a}, "+=.2")

.to('#exp_txt1', t2, {alpha:i}, 3.3)
.to('#exp_txt2', t2, {alpha:i}, 3.3)
.to('#exp_txt3', t2, {alpha:i}, 3.3)
.to('#exp_txt4', t2, {alpha:i}, 3.3)
.to('#exp_txt5', t2, {alpha:i}, 3.3)
.to('#exp_txt6', t2, {alpha:i}, 3.3)

.to('#exp_txt2_1', t, {alpha:a}, "+=.2")
.to('#exp_txt2_2', t, {alpha:a}, "+=.2")
.to('#exp_txt2_3', t, {alpha:a}, "+=.2")
.to('#exp_txt2_4', t, {alpha:a}, "+=.2")
.to('#exp_txt2_5', t, {alpha:a}, "+=.2")

.to('#exp_txt2_1', t2, {alpha:i}, 6.2)
.to('#exp_txt2_2', t2, {alpha:i}, 6.2)
.to('#exp_txt2_3', t2, {alpha:i}, 6.2)
.to('#exp_txt2_4', t2, {alpha:i}, 6.2)
.to('#exp_txt2_5', t2, {alpha:i}, 6.2) 

.to('#exp_join', t, {alpha:a})
.to('#exp_us', t, {alpha:a}, "+=.2")
.to('#bar', .5, {width:82}, "-=.2")

.to('#exp_join', t2, {alpha:i}, 7.5)
.to('#exp_us', t2, {alpha:i}, 7.5)
.to('#bar', t2, {alpha:i}, 7.5)
.to('#logo', t2, {alpha:i}, 7.5)

.to('#dc_logo', t, {alpha:i}, 7.7)
.to('#videoContent', t, {alpha:a}, 7.7);

function startVideo() {

I then do a tl.restart on expansion, so no matter where it is animating on close, and then re-expansion the animation always starts from the beginning. (also completing similar resets on the video that is called at the completion of the animation sequence) - I think I was overthinking it too much. This solved it just fine. 


Thanks again! 

  • Like 1
Link to comment
Share on other sites

Allow me to butt in a bit. I am curious as to why there is so much repetition in your code. Even in this timeline version that you have shown now, there is a bit of refactoring that could be done and it should give you the same results.


Like this:

You can remove the var declaration and chain the variables with commas if you would like. 
It's personal choice
var i = 0,
    a = 1,
    d = 1.3,
    t = .1,
    t2 = .2,
    o = 1.2;

var tl = new TimelineMax({paused:true, onComplete:startVideo}); 

Put your elements in arrays of logical chunks
var arrayText1 = ['#exp_txt1', '#exp_txt2', '#exp_txt3', '#exp_txt4', '#exp_txt5', '#exp_txt6'];
var arrayText2 = ['#exp_txt2_1', '#exp_txt2_2', '#exp_txt2_3', '#exp_txt2_4', '#exp_txt2_5'];
var arrayOne = ['#exp_join','#videoContent', '#exp_us'];
var arrayTwo = ['#dc_logo','#bar','#logo'];

I see no reason to use a .to tween of 0 duration.
That's effectively a .set tween
The tween methods will take an array and interate thru all the elements,
you can even call some array-specific methods inside the tween, check the bellow
tl.set(arrayText1.concat(arrayText2,arrayOne), {alpha:i})
  .set(arrayTwo,  {alpha:a}) 
  .set('#bar', {width:0})

Use .staggerTo or from for this sort of repeating code
Your original arrayText1 has not been modified,
so you should be able to use it here as originally intended
  .staggerTo(arrayText1, t, {alpha:a}, "+=.2"+t, "+=.2")

I don't know why you have a absolute time positioning here
if you are using variables for lenght of the tweens. 
I personally would use relative time positioning in this case
  .staggerTo(arrayText1, t2, {alpha:i}, t2, "+=2.3")

More of the same. 
This is where building this timeline using functions would be useful,
because you are repeating what you have just done
  .staggerTo(arrayText2, t, {alpha:a}, "+=.2"+t, "+=.2")

Same comment as above.
Depending on the effect you are after,
you could even simplify the above and bellow lines into
a single one using repeat:1, yoyo:true and repeatDelay options
  .staggerTo(arrayText1, t2, {alpha:i}, t2, "+=2.3")

A little more refactoring of your code
  .staggerTo(['#exp_join','#exp_us'], t, {alpha:a}, "+=.2")
  .to('#bar', .5, {width:82}, "-=.2")

  .staggerTo(['#exp_join','#exp_us','#bar','#logo'], t2, {alpha:i}, t2, "+=3")

  .to('#dc_logo', t, {alpha:i}, "+=2")
  .to('#videoContent', t, {alpha:a}, "-="+t);

I can't guarantee it will work out of the box as I have nothing to test it against and I cannot be sure of what result you were after but, this is the logic I read inside your timeline.


Ultimately, the less code you write, the better code you write - Less prone to error and easier to maintain/amend.


Also, make sure you name your variables something more meaningful than single letters. Someone, somewhere, someday, might have to read you code and I am sure he/she will not be your best mate ever again if you only use single letters as variable names...

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