Skip to content

Timelines

While a single animation moves properties from one state to another, a Timeline lets you group multiple animations, labels, and callbacks together in order.

Timelines make it easy to play things one after another without guessing delay times. The timeline calculates the total time automatically, letting you easily pause, play, reverse, or skip around the entire sequence.


Basic sequencing

By default, animations added to a timeline play one after another. An animation will wait for the previous one to finish before starting.

60 FPS

Instead of using AnimX.animate(), you call the identical .animate() method directly on your timeline instance:

js
const tl = AnimX.timeline()

tl.animate('.box', { x: 200, duration: 0.6 })
tl.animate('.box', { y: 100, duration: 0.6 }) // starts after x finishes

The timeline automatically calculates its total duration based on its children.


The position parameter

Playing things one after another isn't always enough. Sometimes you need animations to overlap or start at the exact same time.

The position parameter (the third argument in .animate()) lets you control exactly when an animation starts in the timeline.

0s
1s
2s
3s
4s
default
'<'
'>'
'+=0.4'
'<+=0.5'
0.5
'>+=0.5'
60 FPS

There are three ways to define a position:

1. Absolute time (number) Insert the animation at exactly N seconds from the start of the timeline.

js
tl.animate('.box', { x: 100 }, 1.5) // always starts at 1.5s

2. Relative to the end of everything (+=) If you don't provide a position (or use +=), the animation looks at all previous animations and waits until the longest running animation finishes.

For example, imagine you add two animations:

  1. Animation 1 runs from 0s to 10s.
  2. Animation 2 runs from 2s to 8s.

Even though Animation 2 was the last one you typed in the code, the latest active time is still 10s (from Animation 1). Therefore, using += will wait for that 10-second mark.

js
tl.animate('.box', { x: 100 }, '+=1')   // waits for the 10s mark, then adds 1s (starts at 11s)
tl.animate('.box', { y: 100 }, '-=0.5') // waits for the 10s mark, then subtracts 0.5s (starts at 9.5s)

3. Relative to the previous sibling (< and >) The < symbol aligns the current animation with the start of the previously added sibling animation. The > symbol aligns the current animation with the end of the previously added sibling animation.

Think of < and > as pointing to the left (start) or right (end) of the animation directly above it in your code.

You can also combine these with offsets to add or subtract time.

js
tl.animate('.b1', { x: 100 })           // Animation 1
tl.animate('.b2', { x: 100 }, '<')      // Starts exactly when Animation 1 starts
tl.animate('.b3', { x: 100 }, '>')      // Starts exactly when Animation 2 ends
tl.animate('.b4', { x: 100 }, '>+=0.5') // Starts 0.5s AFTER Animation 3 ends
tl.animate('.b5', { x: 100 }, '<+=0.5') // Starts 0.5s AFTER Animation 4 starts
tl.animate('.b6', { x: 100 }, 0.5)      // Starts exactly at 0.5 seconds into the timeline

Quick summary of `+=` vs `>`

  • > looks only at the animation directly above it. (In the example above, it would look at Animation 2 and start at 8s).
  • += looks at every animation added so far, and waits for the longest one to finish. (In the example above, it waits for Animation 1 and starts at 10s).

Labels and callbacks

Labels are bookmarks for specific points in your timeline. They let you reference a specific time without hardcoding exact seconds.

You can add a label at the current time using addLabel(). You can then use this label as the position parameter for other animations so they start at the exact same time.

Additionally, callbacks let you run your own JavaScript code at a specific point in the timeline.

In the demo below, watch how the text highlights exactly when the moving dot passes the markers.

'halfway' label
end callback
60 FPS
js
const tl = AnimX.timeline()

// 1. Move to 150px
tl.animate('.dot', { x: 150, duration: 1 })

// 2. Drop a label here
tl.addLabel('halfway') 

// 3. Fire a one-off callback (triggers when playing forward)
tl.call(() => console.log('Passed the halfway mark!')) 

// 4. Animate the label with a tiny duration so it scrubs perfectly in both directions
tl.animate('.log1', { opacity: 1, color: '#00d4ff', duration: 0.01 }, '<')

// 5. Continue moving to 300px
tl.animate('.dot', { x: 300, duration: 1 })
tl.call(() => console.log('End reached!'))
tl.animate('.log2', { opacity: 1, color: '#00d4ff', duration: 0.01 }, '<')

// You can jump to a label later:
// tl.seek('halfway')

.call(callback, params, position)

The .call() method executes a custom function at a specific point in your timeline.

Arguments:

  • callback (Function): The function to execute.
  • params (Array, optional): An array of arguments to pass to your callback function.
  • position (String | Number, optional): Exactly when the callback should fire. Follows the exact same Positioning rules as .animate() (e.g. <, >, +=0.5, etc.). By default, it appends to the end of the timeline.
js
// Fire exactly 2 seconds into the timeline
tl.call(() => console.log('2 seconds passed!'), [], 2)

// Pass arguments to the callback, firing immediately after the previous animation
tl.call((name, status) => {
  console.log(`${name} is ${status}`)
}, ['AnimX', 'Awesome'], '>')

NOTE

Callbacks only run when playing forward; they do not automatically "undo" anything when playing backward.

Also, .call() does not implicitly pass the timeline instance into your parameter array. However, this is automatically bound to the Timeline instance, meaning you can access properties like this.progress or this.duration directly inside your callback (so long as you use function() {} and not an arrow function).

Best Practice

If you are changing visual styles (like display: none or changing colors), use a 0-duration .apply() or .animate() instead of .call(). This allows AnimX to automatically revert the style changes when the timeline plays in reverse! Use .call() only for external side-effects like playing audio, sending analytics data, or triggering other game logic.


Nesting timelines

You can put timelines inside other timelines. This is great for keeping your code organized.

You can create functions that return small timelines, and add those directly to a master timeline.

60 FPS
js
function createIntro() {
  const tl = AnimX.timeline()
  tl.animate('.logo', { y: 0, opacity: 1 })
  return tl
}

function createOutro() {
  const tl = AnimX.timeline()
  tl.animate('.logo', { opacity: 0 })
  return tl
}

// Master sequence controls everything
const master = AnimX.timeline()
master.add(createIntro())
master.add(createOutro(), '+=2') // wait 2 seconds before the outro

Child timelines automatically follow the play/pause state, speed, and direction of their parent.


Timeline options

When creating a timeline, you can pass a configuration object to set its playback behavior. It accepts many of the same flags as a standard tween.

js
const tl = AnimX.timeline({
  paused: true,        // wait for tl.play()
  repeat: -1,          // loop forever (-1)
  yoyo: true,          // alternate direction on each repeat
  repeatDelay: 1,      // wait 1 second between repeats
  delay: 0.5,          // wait 0.5 seconds before starting the first time
  ease: 'power2.inOut' // applies easing to the timeline's overall progress!
})

If you add an ease to a timeline, it curves the flow of time for the entire sequence. Everything inside it will subtly speed up and slow down.


API Reference

Constructor

js
const tl = AnimX.timeline(options)
OptionTypeDefaultDescription
pausedbooleanfalseIf true, the timeline will not start playing automatically.
repeatnumber0Number of times to loop (-1 for infinite).
yoyobooleanfalseIf true, reverses playback direction on every other repeat cycle.
delaynumber0Initial delay before starting the first cycle (in seconds).
repeatDelaynumber0Delay between loop cycles (in seconds).
easestring | FunctionnullA timeline-level ease applied to the total duration playback.
onStartFunctionnullFired when the timeline begins playing.
onUpdateFunctionnullFired every frame while the timeline is active.
onCompleteFunctionnullFired when the timeline finishes.

Instance Methods

All methods that add animations return the timeline instance (this), allowing you to chain them: tl.animate(...).addLabel(...).animate(...).

MethodDescription
animate(targets, vars, position)Works like AnimX.animate(). Adds an animation to the timeline.
animateFrom(targets, vars, position)Works like AnimX.animateFrom(). Adds a 'from' animation.
sequence(targets, from, to, position)Works like AnimX.sequence(). Adds a 'from-to' animation.
apply(targets, vars, position)Works like AnimX.apply(). Adds an instant change.
add(child, position)Adds an existing Tween, Timeline, Function, or label string.
addLabel(name, position)Inserts a named label at the given position.
call(fn, params, position)Inserts a zero-duration callback.
remove(child)Removes a specific child and recalculates total duration.
clear(labels)Empties all children. Pass false to keep labels intact.

Playback Methods

MethodDescription
play(from)Starts or resumes playback. Optionally provide a time/label to start from.
pause(atTime)Pauses playback.
reverse(from)Plays backwards.
seek(timeOrLabel)Jumps to a specific time (in seconds) or a label string.
kill()Stops the timeline completely and cleans it up from memory.

Properties

PropertyTypeDescription
progressnumberGet or set the playback progress (0 to 1). Setting this seeks the timeline.
timeScalenumberGet or set the playback speed multiplier. 1 is normal, -1 is reverse.
totalDurationnumberThe absolute length of the timeline (in seconds), including repeats.