Appearance
Tweens
A tween is the fundamental animation unit in AnimX. It accepts one or more target elements and a set of destination properties, then handles all interpolation internally. The engine reads the target's current state as the starting point, computes frame-by-frame values, and applies them to the DOM.
The four methods
AnimX provides four methods to create tweens, based on the animation direction:
| Method | Description |
|---|---|
animate(targets, options) | Animates from the element's current state to the values provided. |
animateFrom(targets, options) | Sets the values instantly, then animates back to the element's original state. |
sequence(targets, from, to) | Animates exactly from the start values to the end values. |
apply(targets, options) | Changes properties instantly with no animation. |
The animate method is the most common. The animateFrom method is used for entrance animations, sequence provides full control over start and end values, and apply changes properties instantly without animation.
animate - standard animations
The animate(target, options) method reads the element's current style when it runs. This becomes the starting point. The animation then moves toward the new values provided. The options object holds the properties to animate, plus settings like duration, ease, and callbacks.
The target parameter can be a DOM element, a CSS selector string, a list of elements, or a plain JavaScript object. The second parameter is an object with the properties to animate and the playback settings.
Transform Shorthands
AnimX understands transform shorthands directly. This means writing x: 220 instead of transform: 'translateX(220px)':
| Shorthand | CSS equivalent |
|---|---|
x, y, z | translateX, translateY, translateZ |
rotation | rotate (degrees) |
rotationX, rotationY | rotateX, rotateY |
scale, scaleX, scaleY | scale() |
skewX, skewY | skew() |
All non-transform properties are treated as normal CSS properties. They must be written in camelCase (e.g., backgroundColor, borderRadius, opacity, width, fontSize).
javascript
import { animate } from 'animx';
animate('.box', {
x: 220, // px by default
opacity: 0.5,
backgroundColor: '#ff2d6a',
borderRadius: '50%',
duration: 1,
})animateFrom - entrance animations
The animateFrom method works in reverse. The engine instantly applies the given values to the target, then animates back to the element's original state. This creates an "arrival" or entrance effect.
This method makes entrance animations easy. It removes the need for extra CSS classes to move the element off-screen first. The framework handles the initial jump internally:
javascript
import { animateFrom } from 'animx';
// On page load, the card appears from below
animateFrom('.card', {
y: 60, // start 60px below
opacity: 0, // start invisible
duration: 0.7,
ease: 'expo.out',
})When the animation finishes, the target is exactly at its original CSS position. No inline transforms are left behind.
sequence - explicit start and end states
The sequence(targets, from, to) method gives full control over both the start and end states. Pass the starting properties in the second parameter (from), and place the destination properties alongside all playback settings (duration, ease, delay, callbacks, etc.) in the third parameter (to):
javascript
import { sequence } from 'animx';
sequence('.box',
{ x: -100, opacity: 0 }, // from: initial properties
{ x: 0, opacity: 1, duration: 0.6, ease: 'quart.out' } // to: destination properties + playback config
)apply - instant style changes
The apply method changes properties instantly without animation. This is useful to reset states or adjust layouts before an animation starts:
javascript
import { apply } from 'animx';
apply('.box', { x: 0, opacity: 1 })Timing Properties
duration
The duration property sets the animation length in seconds. The default is 0.5 seconds. This is set globally via tweenManager.defaults.duration, but per-tween settings override it.
delay
The delay property sets how long to wait before the animation starts. This is also in seconds. The wait time starts when the tween is created or played.
javascript
import { animate } from 'animx';
animate('.box', {
x: 300,
duration: 1.2, // takes 1.2 seconds
delay: 0.4, // waits 400ms before starting
})Neither duration nor delay changes a tween's position in a Timeline. Timeline scheduling depends entirely on the position parameter passed to the Timeline's .animate() method.
Animating Plain JS Objects
AnimX isn't just for DOM elements. It can animate any numeric property on a plain JavaScript object. This is highly useful for games, canvas drawing, or framework-related state variables.
You can access the targets using the this.targets property or the targets themselves, which returns an array of the objects being animated.
Score: 0 | Health: 100
javascript
import { animate } from 'animx';
const state = { score: 0, health: 100 };
animate(state, {
score: 500,
health: 10,
duration: 2,
onUpdate: function() {
// Read the values as they animate
const current = this.targets[0];
drawToCanvas(current.score, current.health);
}
});Array Keyframes (Property Keyframes)
You can pass an array of values to any animatable property. AnimX will automatically distribute these values evenly across the duration of the animation, creating a multi-step sequence for that specific property.
javascript
import { animate } from 'animx';
animate('.box', {
x: [100, 200, 300],
y: [50, 0, -50], // bouncing path
backgroundColor: ['#ff0000', '#00ff00', '#0000ff'],
duration: 2,
ease: 'linear'
})This is equivalent to creating a timeline or writing explicit keyframes, but is much faster and cleaner for simple multi-step interpolations.
Easing
Easing controls the speed of change during the animation. Linear easing moves at a constant speed. Complex easing functions create non-linear movement (like starting fast and slowing down, overshooting, or bouncing) without changing the total duration.
The core easing families are shown below:
linear
cubic.out
expo.out
back.out
elastic.out
bounce.out
Each easing family has three variants to control how the speed is distributed:
| Variant | Behavior |
|---|---|
.in | Starts slow and speeds up. |
.out | Starts fast and slows down. This is the standard for UI elements. |
.inOut | Starts slow, speeds up in the middle, and slows down at the end. |
If no variant is specified, .out is applied by default (e.g., cubic acts as cubic.out).
Easing Family Characteristics
linear: Constant speed. Best for simple progress bars.quad/cubic/quart/quint: Smooth curves with different levels of acceleration.cubic.outis a good standard choice.expo.out: Starts extremely fast and slows down over a long tail. Good for quick UI entrances.back.out: Goes past the target value before settling back into place. Creates a bouncy, mechanical effect.elastic.out: Oscillates back and forth around the target value before stopping.bounce.out: Simulates a physical bounce when reaching the final value.
Parameterized easings:
js
ease: 'back.out(2.5)' // default overshoot is 1.70158 - higher = bigger overshoot
ease: 'elastic.out(1, 0.3)' // amplitude, period - lower period = faster oscillation
ease: 'steps(6)' // 6 discrete jumps - like a sprite animation
ease: 'steps(6, start)' // jump at the start of each interval instead of end
ease: 'cubic-bezier(0.34, 1.56, 0.64, 1)' // custom bezier curve
ease: t => t * t // raw easing function - receives 0-1, returns 0-1Looping Properties
repeat
The repeat parameter sets the number of animation loops. The number specifies additional plays after the first (e.g., repeat: 3 plays 4 times total). A value of -1 creates an infinite loop.
yoyo
The yoyo parameter alternates the playback direction on each loop. If yoyo is false, the tween snaps back to the start instantly. If true, the tween animates backward, making the motion smooth and continuous.
repeatDelay
The repeatDelay parameter adds a pause (in seconds) between each loop.
javascript
import { animate } from 'animx';
// Plays once, then 3 more times = 4 total. Yoyos back between each.
animate('.box', {
x: 200,
repeat: 3,
yoyo: true,
repeatDelay: 0.2, // 200ms pause at each end before changing direction
})
// Loop forever
animate('.box', { x: 200, repeat: -1, yoyo: true })
// Without yoyo - snaps back to start after each cycle
animate('.box', { x: 200, repeat: -1 })The progress bar in the demo above reflects the yoyo - watch it go forward, then backward on each alternate cycle.
Stagger
When a target matches multiple elements (like a CSS selector or a list of DOM nodes), AnimX animates them all at the same time by default. They start and end together.
The stagger parameter changes this. It delays the start time of each element, creating a ripple effect across the group.
The stagger parameter can be declared as a direct number or as an object for more control.
Direct Number
A direct number sets the exact delay (in seconds) between each element's start time:
javascript
import { animate } from 'animx';
animate('.item', {
y: -30,
stagger: 0.08, // element 0 starts at 0s, element 1 at 80ms, element 2 at 160ms...
})Object Configuration
An object allows for more advanced control over the stagger distribution:
javascript
import { animate } from 'animx';
animate('.item', {
y: -30,
stagger: {
each: 0.08, // seconds between each element's start
// OR:
amount: 0.6, // total time window - AnimX distributes all elements across it
from: 'center', // which element starts first:
// 'start' (default), 'end', 'center', 'edges', or an index number
ease: 'cubic.in', // curves the *distribution* - elements near the 'from' point
// get their delays closer together; distant ones get spread out
}
})each vs amount
The each property sets a fixed delay between elements, no matter how many there are. The amount property sets a total time window, and AnimX distributes all elements within that time.
from
The from parameter sets the starting point. For example, 'center' starts the animation from the middle element and moves outward. 'edges' starts from the outside elements and moves inward.
ease
The ease property inside the stagger object only controls the timing of the delays. It does not change how each element animates. The main ease property controls the actual movement.
grid
By default, AnimX treats elements as a flat list. If elements are visually arranged in a grid (like a checkerboard or a photo gallery), the grid parameter is used. It accepts an array of [columns, rows].
AnimX will calculate the physical 2D distance between elements. When combined with from: 'center', this creates a true circular ripple effect outward across the grid, rather than just delaying items one by one down the list.
javascript
import { animate } from 'animx';
animate('.cell', {
scale: 0,
opacity: 0,
stagger: {
amount: 1,
grid: [5, 4], // [columns, rows] - tells AnimX the 2D layout
from: 'center', // starts from the middle, ripples outward in a circle
}
})Callbacks
AnimX runs callbacks at key moments during the animation. These functions are added directly to the options object.
press play
javascript
import { animate } from 'animx';
const tween = animate('.box', {
x: 200,
duration: 1.5,
onStart: function() {
el.classList.add('is-animating');
},
onUpdate: function() {
// 'this' is bound to the tween instance
label.textContent = (this.progress * 100).toFixed(0) + '%';
},
onComplete: function() {
el.classList.remove('is-animating');
},
onRepeat: function() {},
onReverseComplete: function() {
console.log('back at start');
},
})When using standard function expressions (function() {} or method syntax), AnimX binds this to the Tween or Timeline instance. You can access properties like this.progress, this.targets, and this.time directly inside any callback. If you use arrow functions (() => {}), this retains its lexical scope, so you must reference the tween variable from outside the callback instead.
onStart
Fires once, when the tween begins playing for the first time. This is useful for adding a CSS class, starting audio, or showing a tooltip.
onUpdate
Fires every frame while the tween is active. When using a standard function expression, this.progress is a value between 0 and 1. This is useful for tying other actions to the animation, like drawing on a canvas or updating numeric displays.
onComplete
Fires once, when the tween finishes its last cycle. If repeat: -1, this never fires.
onRepeat
Fires each time a cycle repeats (not the first play, not the last complete).
onReverseComplete
Fires when the tween completes while playing in reverse (i.e., it played backward all the way back to t=0).
Per-Property Easing
A single tween uses the same easing curve for all its properties. To use different curves (for example, expo.out for x and bounce.out for y), two tweens must be run at the same time using a Timeline:
Both tweens target the same element at the exact same time (0 is the start position). They also share the same duration. By applying different curves, a complex motion path is created. In this example, x moves smoothly while y bounces, creating an arc.
javascript
import { timeline } from 'animx';
const tl = timeline()
tl.animate('.box', { x: 300, duration: 1.4, ease: 'expo.out' }, 0)
tl.animate('.box', { y: -80, duration: 1.4, ease: 'bounce.out' }, 0)Playback and Seeking
By default, a tween plays immediately when created.
paused
Set paused: true to stop it from starting automatically, allowing it to be controlled later with code.
javascript
import { animate } from 'animx';
const tween = animate('.box', {
x: 300,
duration: 1.5,
paused: true,
})
tween.play() // play forward from current position (or pass time: tween.play(0))
tween.resume() // unpause and continue in current direction
tween.pause() // freeze at current position
tween.reverse() // play backward from current positionseek()
js
tween.seek(0.75) // jump to 750ms (absolute time in seconds)
tween.progress = 0.5 // jump to 50% - progress is a 0-1 get/set property
tween.progress = 0 // jump back to start
tween.progress = 1 // jump to endtimeScale
The timeScale property changes the playback speed without changing the easing curve:
js
tween.timeScale = 2 // plays at 2× speed
tween.timeScale = 0.5 // plays at half speed (slow motion)
tween.timeScale = -1 // plays backward at normal speedinvalidate()
The invalidate() method makes the tween forget its starting values. On the next play, it will read the element's current state again. This is useful if the element was moved by something else after the tween was created:
js
tween.invalidate() // re-read live DOM values on next play
tween.play()kill()
The kill() method stops the tween immediately and removes it from memory:
js
tween.kill() // stop + clean up - the tween object becomes inertRelative Values
Numbers can be prefixed with +=, -=, or *=. This calculates the value based on the element's current state right when the tween starts, not when it was created.
This is very important for chained animations or interactive elements. It ensures the same tween works correctly for multiple elements, even if they start from different positions.
Add to Current Value (+=)
If multiple elements start at different positions, and x: '+=110' is applied, each element moves exactly 110 pixels from its own starting spot.
x: 0
x: 50
x: 100
javascript
import { animate } from 'animx';
// All three boxes shift +110px from wherever they currently are.
// Box at x:0 → ends at x:110
// Box at x:50 → ends at x:160
// Box at x:100 → ends at x:210
animate(boxes, { x: '+=110', stagger: 0.1 })Subtract (-=) and Multiply (*=)
The -= operator subtracts an amount from the current value. The *= operator multiplies the current value. Multiplication is useful for properties like scale or opacity where proportional changes are needed instead of fixed numbers.
x: '-=140'
opacity: '*=0.15'
javascript
import { animate } from 'animx';
// '-=' - moves left by 140px from its current x (160 → 20)
animate(minusBox, { x: '-=140', duration: 0.8, ease: 'cubic.out' })
// '*=' - multiplies current opacity by 0.15 (1 → 0.15)
animate(mulBox, { opacity: '*=0.15', duration: 0.8, ease: 'cubic.inOut' })These operators always read the live values right as the animation starts. If an element was moved by the user or another script, the relative tween still measures from its new position.
Overwrite Management
When multiple tweens animate the same target at the same time, conflicts happen if they change the same properties. The overwrite setting controls how to resolve this. By default, tweens use overwrite: 'auto'.
overwrite: 'auto' (Default)
When a new tween starts, it finds older tweens acting on the same target and same properties. It deletes those specific conflicting properties from the older tweens.
Properties on the older tweens that do not conflict keep animating normally.
In the demo below, the first tween animates x and rotation. Later, a second tween starts animating x to a new value. The auto setting lets the new tween take over x, but the first tween keeps animating rotation.
overwrite: true
Setting overwrite: true stops all older tweens on the target completely when the new tween starts.
In the demo below, the second tween uses overwrite: true. When it starts, the first tween is completely canceled. Both x and rotation stop.
overwrite: false
Setting overwrite: false turns off overwrite checks. Both tweens run at the same time. If they animate the same properties, they will fight over the values on every frame, which usually looks glitchy.
Quick reference
javascript
import { animate, animateFrom, sequence, apply } from 'animx';
// Four factory methods
animate(targets, options) // current → target values
animateFrom(targets, options) // target values → current
sequence(targets, from, to) // explicit from → to
apply(targets, options) // instant set, no animation
// Core timing options
duration // number - seconds (default: 0.5)
delay // number - seconds before the tween starts
ease // string | function - easing curve (default: 'cubic.out')
paused // boolean - don't autoplay on creation
// Looping options
repeat // number - extra plays after first (−1 = forever)
yoyo // boolean - alternate direction on each cycle
repeatDelay // number - seconds to pause between cycles
startAt // object of properties to apply instantly before the tween begins
id // custom string identifier for the tween
immediateRender // boolean, forces properties to apply instantly before delay
callbackScope // the 'this' context bound to all callbacks
onStartParams // array of arguments passed to onStart
onUpdateParams // array of arguments passed to onUpdate
onCompleteParams // array of arguments passed to onComplete
// Multi-target distribution
stagger // number | { each, amount, from, ease, grid }
// Lifecycle callbacks (no arguments passed - access tween via closure)
onStart
onUpdate
onComplete
onRepeat
onReverseComplete
// Instance API
tween.play() // play forward from current position
tween.resume() // unpause and continue in current direction
tween.pause() // freeze at current position
tween.reverse() // play backward from current position
tween.seek(seconds) // jump to time position
tween.progress // 0-1 get/set
tween.timeScale // speed multiplier, get/set
tween.kill() // stop and remove from ticker
tween.invalidate() // re-read live values on next play