Dive into the intricacies of GreenSock animation with this comprehensive tutorial that covers topics like sequencing tweens with TimelineLite, adjusting timing with the position parameter, and creating an animated progress bar. Learn how to group multiple tweens for easy sequencing and manipulate animation timing for a more dynamic display.
This exercise is excerpted from Noble Desktop’s past web development training materials created in partnership with GreenSock. It is compatible with GreenSock version 2. To learn current skills in web development, check out our coding bootcamps in NYC and live online.
Topics covered in this GreenSock tutorial:
Sequencing tweens with TimelineLite, Adjusting timing with the position parameter, Using labels in a TimelineLite, Modifying an ease with config(), Seeking a position relative to a label, Creating an animated progress bar
Exercise Preview
Photo courtesy of istockphoto: Image #11068094
Exercise Overview
TimelineLite allows you to group multiple tweens together for easy sequencing. No longer do you have to make sure that each tween’s delay somehow matches the durations and delays of all previous tweens; TimelineLite does that for you. In this exercise, you will create a TimelineLite, add some tweens to it, and try out a few ways of offsetting the start times of each tween.
Previewing the Finished Animation
To take a look at the animation we’ll be building, open up Google Chrome.
Hit Cmd–O (Mac) or Ctrl–O (Windows), navigate to Desktop > Class Files > yourname-GSAP Class > TimelineLite, and double–click on finished.html.
-
Take note of the sequence, which happens as follows:
The background fades in, the word INTO slides in from the left, the words THE WIND slide in from the right, the main copy slides up from the bottom, then the three red buttons swing in (in a staggered order).
While all this is happening, a white progress bar advances along the x-axis on the top of the browser.
Reload the page as many times as you need to get a feel for the animation.
Examining the DOM Structure & JavaScript
In a code editor, open start.html from the TimelineLite folder.
Take a look at the HTML structure on lines 11–18 to see how the elements in the DOM are structured. There is an
<h2>
containing the word INTO and another<h2>
containing the phrase THE WIND. After that, there is a<p>
with the body copy and a<div>
containing the three buttons.-
Check out the JavaScript variables on lines 35–41. Like in previous exercises, we’ve assigned some variables such as
$
mainCopy to refer to the various DOM elements. Pay particular attention to the lines shown in bold below that may look unfamiliar:var $bg = $("#bg"), $into = $("h2").eq(0), //the first h2 in the document $theWind = $("h2").eq(1), //the second h2 in the document $mainCopy = $("p"), $buttons = $(".button"), $progress = $(".progress"), tl;
We will use the tl variable to reference the TimelineLite we’ll build in the exercise.
There are multiple
<h2>
tags on the page (containing the INTO and THE WIND bits of text), but we can use jQuery’s eq() method to target them more specifically. By simply appending .eq(0) and .eq(1), we will be able to animate them independently without adding any additional classes.jQuery’s eq() Method
The .eq() selector selects an element with a supplied index that identifies the position of this element in the set. Note that this index is zero-based, and refers to the position of the element within the jQuery object, not within the DOM tree.
-
We are going to have elements that will animate in 3D space. Add the following bold code to make sure all these elements are transformed with perspective:
$progress = $(".progress"), tl; CSSPlugin.defaultTransformPerspective = 800;
Remember that transformPerspective allows us to set a distance of where the virtual camera is from the element that’s being animated. The code you wrote will apply the same transformPerspective to every element that will be animated in 3D space.
Sequencing Tweens with TimelineLite
-
Let’s get started creating our first timeline! Add the following bold code to instantiate a new TimelineLite:
CSSPlugin.defaultTransformPerspective = 800; tl = new TimelineLite(); });
-
For our first tween, add the following bold code that uses TimelineLite’s from() method to create and insert a TweenLite from() tween into the timeline:
tl = new TimelineLite(); tl.from($bg, 0.8, {opacity:0})
NOTE: Do not type a semi-colon to end this statement. You’ll be chaining tweens to the timeline in the following steps and a semi-colon will break the chain unless it’s at the end of the final tween.
-
Save the file and preview the page in a browser. The background fades in from an opacity of 0 and the tween’s duration is 0.8 seconds.
The great thing about TimelineLite is that, rather than setting delays for each tween, we can simply chain them together with a period. Each animation will display in the order that we list them in the code!
-
In your code editor, chain the next tween to the previous one, as shown in bold:
tl = new TimelineLite(); tl.from($bg, 0.8, {opacity:0}).from($into, 0.5, {opacity:0, x:-200})
This means that the INTO text will take 0.5 seconds to enter from the left, from an x value of –200 and fade in from an opacity of 0.
Save the file and preview the page in a browser. Great, as soon as the background finishes fading in, the word INTO animates in, all without specifying a delay time!
Switch to your code editor.
-
If we write all our tweens on one long line, it will be difficult to read. Luckily, we are able to chain tweens by putting them each on their own line and making sure each line starts with a period. Hit Return (Mac) or Enter (Windows) so the second tween is on its own line, as follows:
tl.from($bg, 0.8, {opacity:0}) .from($into, 0.5, {opacity:0, x:-200})
-
Let’s add the tween for THE WIND, which will look quite similar to the one we just added. Type the following bold code:
tl = new TimelineLite(); tl.from($bg, 0.8, {opacity:0}) .from($into, 0.5, {opacity:0, x:-200}) .from($theWind, 0.5, {opacity:0, x:200})
Save the file and preview the page in a browser. The words THE WIND have the same behavior, but they come in from the opposite side—and most importantly, the tween doesn’t begin until INTO has slid into position.
Switch to your code editor.
-
Chain the following tween to the sequence to bring in the main copy:
tl.from($bg, 0.8, {opacity:0}) .from($into, 0.5, {opacity:0, x:-200}) .from($theWind, 0.5, {opacity:0, x:200}) .from($mainCopy, 0.8, {opacity:0, y:50})
Save the file and preview the page in a browser. The main copy now rises from the bottom of the screen (fading in over the course of 0.8 seconds from an opacity of 0) as soon as THE WIND is in place.
Switch to your code editor.
-
TimelineLite’s staggerFrom() method works exactly like the staggerFrom() method in TweenMax! Let’s stagger the appearance of the buttons. Remember that the
$
buttons var references all three items with the .button class. Add the following bold tween (keep it all on one line):tl.from($bg, 0.8, {opacity:0}) .from($into, 0.5, {opacity:0, x:200}) .from($theWind, 0.5, {opacity:0, x:200}) .from($mainCopy, 0.8, {opacity:0, y:50}) .staggerFrom($buttons, 0.7, {rotationX:-90, opacity:0, transformOrigin:"center top", ease:Back.easeOut}, 0.2)
These properties should look familiar from the previous exercises. We are using transformOrigin:
"
center top"
to make sure the buttons have the “flipping down from the top” effect we created when animating the Jive graphic.NOTE: Remember that the stagger amount (in this case, 0.2 seconds) comes after all the other properties.
Save the file and preview the page in a browser. Very cool, all our tweens are playing in direct sequence and the buttons are staggered in nicely.
Adjusting the Sequence’s Timing with the Position Parameter
It’s a little monotonous having each tween start the moment the last one ends. What if we want to offset the start times of each tween? For greater flexibility, the position parameter allows us to add tweens at a specific time (or at a time relative to the end of the timeline).
How do we access the position parameter? Well, TimelineLite’s from() method accepts a position value as the fourth parameter. The format is:
tl.from(target, duration, {properties}, position)
To see how this works, let’s focus on the tween that controls THE WIND. To create some overlap in the animation, lets start the $
theWind animation 0.25 seconds before $
into ends.
-
In your code editor, find the
$
theWind tween (around line 49) and add the following bold code:.from($theWind, 0.5, {opacity:0, x:200}, "-=0.25")
NOTE: This is a string value. It is a value that is relative to the current end of the timeline. The value is negative, meaning this tween will start 0.25 seconds before the current end of the timeline (i.e., 0.25 seconds before
$
into finishes animating).Position Parameter Values
You can use a number to indicate an absolute time in terms of seconds.
Alternatively, you may use a string with a
"
+="
or"
–="
prefix to offset the insertion point relative to the END of the timeline. For example,"
+=2"
would place the object 2 seconds after the end, leaving a 2-second gap."
–=2"
would create a 2-second overlap.You may also use a label like
"
myLabel"
to have the object inserted exactly at the label or combine a label and a relative offset like"
myLabel+=2"
to insert the object 2 seconds after"
myLabel"
or"
myLabel–=3"
to insert it 3 seconds before"
myLabel"
. Save the file and preview the page in a browser. The change is subtle, but if you reload the page and pay attention, you’ll notice that before INTO has finished animating, the tween for THE WIND begins.
Switch to your code editor.
-
Let’s add a little delay between the appearance of
$
theWind and the introduction of the$
mainCopy text. We can do this by passing in a positive relative value as the position parameter. Add the following bold code:.from($mainCopy, 0.8, {opacity:0, y:50}, "+=0.5")
Once again, this string value is relative to the current end of the timeline. The value
"
+=0.5"
will make the$
mainCopy animation start half a second after the$
theWind animation finishes. Save the file and preview the page in a browser. Again, the change is subtle, but it does slightly enhance the feel of the overall sequence. It is important to know how to attain this precise level of control in your animations!
Using Labels in a TimelineLite
We want to fine-tune the staggerFrom() tween, but we don’t want to watch the whole animation each time we need to preview our changes. Let’s use TimelineLite’s labels to simply jump to the beginning of the staggerFrom() sequence.
A label allows us to give a name to a specific point in time in our timeline. Labels can be used to mark insertion points for tweens in the timeline or to navigate to a particular time.
Switch to your code editor.
-
Add the following bold code to create a label, adding it as the position parameter:
.staggerFrom($buttons, 0.7, {rotationX:-90, opacity:0, transformOrigin:"center top", ease:Back.easeOut}, 0.2, "buttons")
TimelineLite will now mark the moment at the very START of the staggerFrom() sequence with the label buttons. It is important to remember that labels mark the beginning of a sequence.
-
Add the following bold code beneath the staggerFrom() sequence:
.staggerFrom($buttons, 0.7, {rotationX:-90, opacity:0, transformOrigin:"center top", ease:Back.easeOut}, 0.2, "buttons") tl.seek("buttons")
This seek() method allows us to jump to the buttons label, thus bypassing the tedium of watching the whole beginning part of our animation.
Save the file and preview the page in a browser. With the seek(
"
buttons"
) code, we are skipping the initial tweens, which will make it easier to focus on the staggerFrom() sequence.
Using Config() to Modify the Back Ease
Switch back to your code editor.
-
Let’s make the “swinging” animation of the labels a bit more dramatic. The Back ease’s config() method will allow us to do so. Add the following bold code:
.staggerFrom($buttons, 0.7, {rotationX:-90, opacity:0, transformOrigin:"center top", ease:Back.easeOut.config(12)}, 0.2, "buttons")
You can configure the amount of overshoot for the Back ease using the config() method. The higher the number, the more dramatic the overshoot effect. To see visualizations of the Back ease’s curve, with different config values, be sure to see the Ease Visualizer at greensock.com/docs/Easing/Back
Save the file and preview the page in a browser. Wow, the buttons’ swinging animation is much more pronounced now. It may be too much!
Switch back to your code editor.
-
Let’s change the labels’ swing to a more modest value:
.staggerFrom($buttons, 0.7, {rotationX:-90, opacity:0, transformOrigin:"center top", ease:Back.easeOut.config(3)}, 0.2, "buttons")
Save the file and preview the page in a browser. That looks better.
Seeking a Position Relative to a Label
Suppose we didn’t want to seek() directly to the buttons label, but wanted to see the few moments leading up to the staggerFrom() sequence. Rather than creating a new label, we can seek() a position relative to a label. Let’s try it out.
Switch back to your code editor.
-
In the seek() method, add the following bold code:
tl.seek("buttons-=1")
This changes the seek position to 1 second before the label.
-
Save the file and preview the page in a browser.
Now we can see what happens in the one second preceding the staggerFrom() sequence. Although our INTO THE WIND animation is not terribly long, you can imagine how useful this feature would be when creating a five-minute animation!
Switch back to your code editor.
Delete the entire line with the seek() method. Now that the staggerFrom() animation is refined, we won’t need it anymore.
Creating an Animated Progress Bar
-
Scroll up to approximately line 9 and notice the following div:
<div class="progress"></div>
This is a div that stretches across the full width of the top of the browser. To create the “progress bar” effect we saw in the exercise preview, we are going to create a tween to change the scale X of this div (in essence, the width of the element).
-
Add the following bold code after the staggerFrom() method:
.staggerFrom($buttons, 0.7, {rotationX:-90, opacity:0, transformOrigin:"center top", ease:Back.easeOut.config(3)}, 0.2, "buttons") .from($progress, 1, {scaleX:0, transformOrigin:"left", ease:Linear.easeNone})
-
Save the file and preview the page in a browser.
Oops, the bar is playing after all the other tweens, because we simply chained it on to the sequence and didn’t specify anything in the position parameter.
Switch back to your code editor.
-
Add the following bold code to make the progress bar tween start at the very beginning of the timeline:
.from($progress, 1, {scaleX:0, transformOrigin:"left", ease:Linear.easeNone}, 0)
We have just entered a position parameter of 0. Notice this is the number zero, NOT a string value. Thus it refers to an absolute time of 0, the very start of the timeline.
Save the file and preview the page in a browser. Looking good, but the duration is still 1 second, not the entire length of the TimelineLite.
-
Let’s make sure the progress bar’s duration is exactly equal to the length of the timeline by replacing 1 with the following method (in bold):
.from($progress, tl.duration(), {scaleX:0, transformOrigin:"left", ease:Linear.easeNone}, 0)
We have just added a dynamic value that is equal to the duration of the timeline. If we were to add several more tweens to the timeline sequence, this dynamic value would change automatically and the progress bar would still function as expected.
Save the file and preview the page in a browser. The page would be a bit better if the progress bar faded out and disappeared from view once everything loaded.
Switch back to your code editor.
-
Add the following line of code:
.from($progress, tl.duration(), {scaleX:0, transformOrigin:"left", ease:Linear.easeNone}, 0) .to($progress, 0.4, {opacity:0, top:-8});
NOTE: Now that we are finished chaining the tweens, remember to end the sequence with a semi-colon, as a best practice.
-
Save the file and preview the page in a browser. That’s a more elegant ending to the animation.
You can find out lots more about TimelineLite at greensock.com/docs/TimelineLite
Recap: Various Ways You Can Use the Position Parameter
tl.from(element, 1, {x:100});
(No position parameter specified) appends to the end of the timeline
tl.from(element, 1, {x:100}, 2);
Appends it at exactly 2 seconds into the timeline (absolute position)
tl.from(element, 1, {x:100}, "+=2");
Appends it 2 seconds after the end (with a gap of 2 seconds)
tl.from(element, 1, {x:100}, "myLabel");
Places it at "
myLabel"
tl.from(element, 1, {x:100}, "myLabel+=2");
Places it 2 seconds after "
myLabel"
Be sure to watch the video and explore the demos that illustrate the many uses of the position parameter at greensock.com/position-parameter