Topics Covered in This JavaScript Tutorial:
Master GSAP's powerful timeline system by animating multiple elements in sequence, implementing clean chaining syntax, and leveraging timeline repeat functionality with RepeatDelay properties for professional web animations.
Exercise Preview

Exercise Overview
In this comprehensive exercise, you'll advance beyond basic GSAP animations to master timeline orchestration—a critical skill for creating sophisticated, sequenced animations that form the backbone of modern interactive web experiences. You'll learn to coordinate multiple elements, control timing with precision, and build reusable animation sequences that can be controlled programmatically.
Getting Started
Let's establish our development environment and examine the project structure we'll be working with.
- Navigate to the GSAP Timeline folder located in Desktop > Class Files > JavaScript Class. Open this folder in your code editor (Visual Studio Code, Sublime Text, or your preferred editor with folder support).
- In your code editor, open timeline.html from the GSAP Timeline folder to examine the project structure.
Preview timeline.html in Chrome to see the starting state.
You'll see a static logo similar to our previous exercise, but notice we've added a tagline below it. This dual-element setup will demonstrate the power of timeline sequencing.
Back in your code editor, examine the HTML structure within the body tag:
<img id="logo" src="img/noble-desktop-logo.svg" ALT="Noble Desktop"> <p id="tagline">Design. Code. Create.</p>Note the semantic IDs on both elements: logo and tagline. These descriptive identifiers will serve as our animation targets and make our code more maintainable.
Setup Requirements
Essential for accessing timeline methods and animation functions
Keeps your timeline logic separate and organized
Required for targeting specific elements in animations
Loading the GSAP JavaScript Library
Before we can harness GSAP's animation capabilities, we need to properly include the library in our project.
Add the GSAP library reference just before the closing
</body>tag. This placement ensures the DOM is fully loaded before our animations execute:</main> <script src="js/gsap.min.js"></script> </body>Create a dedicated script block for our custom animation code below the library import:
<script src="js/gsap.min.js"></script> <script></script> </body>
Animating the First Element
We'll begin by creating our initial animation using GSAP's from() method, which defines where an element starts and animates to its natural position.
Initialize your first GSAP animation with the basic method call:
<script> gsap.from(); </script>Configure the animation parameters to create a dynamic entrance effect for the logo:
gsap.from('#logo', {duration:1, scale:0, y:100});This animation starts the logo at zero scale and 100 pixels below its final position, then animates to its natural state over one second.
Save your file and reload the page in Chrome.
The logo should scale up from nothing while moving upward into position, creating an engaging entrance effect.
Animating Additional Elements
Now we'll add the tagline animation. Initially, we'll demonstrate the limitations of independent animations before showing how timelines solve these challenges.
Duplicate the logo animation to create a foundation for the tagline animation:
<script> gsap.from('#logo', {duration:1, scale:0, y:100}); gsap.from('#logo', {duration:1, scale:0, y:100}); </script>Modify the second animation to target the tagline element:
gsap.from('#logo', {duration:1, scale:0, y:100}); gsap.from('#tagline', {duration:1, scale:0, y:100});Save and reload the page in Chrome.
Both elements animate simultaneously with identical effects. While interesting, this simultaneous animation lacks the sequential flow we're aiming for. We want the tagline to appear after the logo completes its animation.
- Return to your code editor to implement proper sequencing.
Add a delay to the tagline animation to create the desired sequence:
gsap.from('#logo', {duration:1, scale:0, y:100}); gsap.from('#tagline', {duration:1, scale:0, y:100, delay:1});Save and reload the page in Chrome.
Perfect! The logo animates for one second, then the tagline begins its animation with a one-second delay, creating a seamless sequence.
- Switch back to your code editor for a visual enhancement.
Create visual contrast by making the tagline animate from above rather than below:
gsap.from('#tagline', {duration:1, scale:0, y:-100, delay:1});Save and reload the page in Chrome.
The contrasting directions (logo from below, tagline from above) create a more dynamic and visually interesting sequence.
Independent vs Timeline Animations
| Feature | Independent Tweens | Timeline Approach |
|---|---|---|
| Timing Control | Manual delay calculations | Automatic sequencing |
| Maintenance | Complex when scaling | Easy to modify |
| Playback Control | Cannot pause/reverse | Full control available |
| Code Organization | Scattered tweens | Unified timeline object |
Creating & Using a Timeline
While our delay-based approach works for simple sequences, it becomes unwieldy and fragile as complexity grows. GSAP timelines provide a robust solution that offers superior control, maintainability, and flexibility for complex animation sequences.
- Return to your code editor to implement our first timeline.
Create a new timeline instance that will serve as the container for our animation sequence:
let tl = gsap.timeline(); gsap.from('#logo', {duration:1, scale:0, y:100}); gsap.from('#tagline', {duration:1, scale:0, y:-100, delay:1});Attach our animations to the timeline instead of calling them independently:
let tl = gsap.timeline(); tl.from('#logo', {duration:1, scale:0, y:100}); tl.from('#tagline', {duration:1, scale:0, y:-100, delay:1});Save and reload the page in Chrome.
Notice the timing has shifted slightly. The timeline automatically sequences animations, so each one begins after the previous animation completes. The logo still takes one second, but now the tagline waits for the logo to finish, then waits an additional second due to its delay property.
Remove the redundant delay since the timeline handles sequencing automatically:
let tl = gsap.timeline(); tl.from('#logo', {duration:1, scale:0, y:100}); tl.from('#tagline', {duration:1, scale:0, y:-100});Save and reload the page in Chrome.
Now the tagline animates immediately after the logo completes, creating a smooth, precisely timed sequence without manual delay calculations.
Timeline Implementation Process
Instantiate Timeline
Create timeline variable using gsap.timeline() method to serve as animation container
Replace Individual Calls
Change gsap.from() calls to timeline.from() using your timeline variable name
Remove Manual Delays
Delete delay properties since timeline handles sequencing automatically
Test Sequential Flow
Verify animations play in order without gaps or overlaps
Cleaning up the Syntax with Chaining
GSAP supports method chaining, allowing us to write more concise, readable code. This pattern is particularly valuable in complex animation sequences where clarity and maintainability are crucial.
- Chain multiple methods from a single timeline reference
- Use only one semicolon at the sequence end
- Place each method on its own line for enhanced readability
Remove the timeline reference from each individual method call:
let tl = gsap.timeline(); .from('#logo', {duration:1, scale:0, y:100}); .from('#tagline', {duration:1, scale:0, y:-100});Remove the semicolons from intermediate method calls:
let tl = gsap.timeline(); .from('#logo', {duration:1, scale:0, y:100}) .from('#tagline', {duration:1, scale:0, y:-100})Connect the chain to your timeline variable:
let tl = gsap.timeline(); tl.from('#logo', {duration:1, scale:0, y:100}) .from('#tagline', {duration:1, scale:0, y:-100})Save and reload the page in Chrome.
The animation behavior remains identical, but your code is now more maintainable and follows industry best practices for method chaining.
Chaining timeline methods creates cleaner, more readable code. Use format: tl.from().to().from() with single semicolon at end and timeline name only once at beginning.
Adding More Elements to the Timeline
The timeline's sequential nature makes adding new animations straightforward—each new animation automatically follows the previous one in the sequence, eliminating the need for complex delay calculations.
Add a rotation effect to the logo that occurs between the scale animation and the tagline entrance:
tl.from('#logo', {duration:1, scale:0, y:100}) .to('#logo', {duration:1, rotate:360}) .from('#tagline', {duration:1, scale:0, y:-100})Note that we're using
to()instead offrom()because we want to animate from the current state to a rotated state.Save and reload the page in Chrome.
Observe the carefully orchestrated sequence:
- Logo scales up and moves into position
- Logo rotates 360 degrees
- Tagline scales up and moves into position
Adjusting Timing with the Position Parameter
While sequential timing works well for many scenarios, professional animations often require more nuanced timing control. GSAP's position parameter provides powerful tools for fine-tuning when animations start relative to each other.
The position parameter accepts various formats:
tl.from(target, {vars}, position)
Add a one-second pause before the logo rotation by using a relative position parameter:
tl.from('#logo', {duration:1, scale:0, y:100}) .to('#logo', {duration:1, rotate:360}, '+=1') .from('#tagline', {duration:1, scale:0, y:-100})The
+=1parameter tells GSAP to start this animation one second after the previous animation ends.Save and reload the page in Chrome.
Notice the deliberate pause between scaling and rotation, which can create dramatic emphasis or allow viewers to process the initial animation.
Create overlapping animations by starting the rotation before the scaling completes:
.to('#logo', {duration:1, rotate:360}, '-=.5')The negative value starts the rotation 0.5 seconds before the previous animation ends.
Save and reload the page in Chrome.
The overlapping effects create a more dynamic, fluid animation where scaling and rotation occur simultaneously for part of the sequence.
Use absolute positioning to start the tagline at exactly 3 seconds from the timeline's beginning:
.from('#tagline', {duration:1, scale:0, y:-100}, 3)Save and reload the page in Chrome.
The tagline now appears at exactly the 3-second mark, regardless of when the previous animations finish.
Synchronize the tagline with the logo rotation using the convenient start-alignment parameter:
.from('#tagline', {duration:1, scale:0, y:-100}, '<')Save and reload the page in Chrome.
Both the rotation and tagline animations now start simultaneously, creating a coordinated effect. You can also use variations like
'<2'to start 2 seconds after the previous animation begins. For comprehensive positioning options, refer to the official documentation at greensock.com/position-parameter.
Position Parameter Options
Relative Timing (+=/-=)
Use +=1 for delay after previous animation ends, or -=0.5 to start during previous animation. String values required.
Absolute Timing (numbers)
Use absolute numbers like 3 to start exactly 3 seconds from timeline start. No quotes needed for numeric values.
Synchronized Start (<)
Use < symbol to start exactly when previous animation begins. Add numbers like <2 for offset timing.
Timeline Repeat and Control Properties
One of the most powerful advantages of timelines is their ability to be controlled as a single unit. You can repeat, pause, reverse, or restart entire sequences with simple property changes.
Add repeat functionality to your timeline by configuring it during creation:
let tl = gsap.timeline( {repeat:2} );Save and reload the page in Chrome.
The entire sequence now plays three times total (original plus two repeats), demonstrating how timeline properties affect the entire animation sequence.
Add a pause between repetitions to let viewers appreciate the final state:
let tl = gsap.timeline( {repeat:2, repeatDelay:2} );Save and reload the page in Chrome.
The 2-second pause between repetitions creates a more professional, considered animation rhythm rather than jarring immediate repetition.
Create an infinite loop for ongoing ambient animation:
let tl = gsap.timeline( {repeat:-1, repeatDelay:2} );Save and reload the page in Chrome.
The animation now cycles continuously with 2-second pauses, perfect for hero sections or ambient interface elements that need persistent visual interest.
Safari Rendering Bug Solution (MacOS and iOS)
In Safari browsers, timeline repetitions can cause visual artifacts where duplicate images appear during animation cycles. This browser-specific rendering issue requires a CSS optimization hint to resolve.
The CSS will-change property informs the browser's rendering engine that an element will undergo specific transformations, allowing it to optimize accordingly. According to MDN Web Docs: "The will-change CSS property hints to browsers how an element is expected to change. Browsers may set up optimizations before an element is actually changed."
Since GSAP animations utilize CSS transforms under the hood, we can prevent Safari's rendering glitch by explicitly declaring this intent:
#logo {
will-change: transform;
Code Omitted To Save Space
}
Important: Use will-change sparingly and only when necessary, as it can impact performance if overused. Remove it when animations are complete in production applications.