Tween - Advanced Features
Callbacks, playback control, iterations, and advanced animation features
Advanced features for controlling and sequencing animations with FasterMotion.
Callbacks
Execute functions at specific points in the animation lifecycle.
onStart
Type: () => void
Called when animation begins playing.
FasterMotion.dom({
target: '#box',
to: { x: 200 },
duration: 1000,
onStart: () => {
console.log('Animation started!');
}
});Try it: onStart Callback
FasterMotion.dom({
target: '#box',
to: { x: 200, rotation: 360 },
duration: 1000,
onStart: () => {
console.log('Animation started!');
}
});onUpdate
Type: (progress: number) => void
Called on every frame during animation. Receives progress (0 to 1).
FasterMotion.dom({
target: '#box',
to: { x: 200 },
duration: 1000,
onUpdate: (progress) => {
console.log('Progress:', Math.round(progress * 100) + '%');
}
});onComplete
Type: () => void
Called when animation completes.
FasterMotion.dom({
target: '#box',
to: { x: 200 },
duration: 1000,
onComplete: () => {
console.log('Animation complete!');
}
});Try it: onComplete Callback
FasterMotion.dom({
target: '#box',
to: { x: 200, scale: 1.5 },
duration: 1000,
ease: 'back.out',
onComplete: () => {
console.log('Done!');
}
});All Callbacks Together
FasterMotion.dom({
target: '#box',
to: { x: 200, rotation: 360 },
duration: 2000,
onStart: () => {
console.log('Starting...');
},
onUpdate: (progress) => {
const percent = Math.round(progress * 100);
document.querySelector('#progress').textContent = percent + '%';
},
onComplete: () => {
console.log('Finished!');
}
});Try it: All Callbacks with Progress
FasterMotion.dom({
target: '#box',
to: { x: 200, rotation: 360 },
duration: 2000,
onStart: () => {
console.log('Starting...');
},
onUpdate: (progress) => {
const percent = Math.round(progress * 100);
document.querySelector('#progress').textContent = percent + '%';
},
onComplete: () => {
console.log('Finished!');
}
});Playback Control
Control animation playback with methods returned from FasterMotion.dom().
Basic Control Methods
const anim = FasterMotion.dom({
target: '#box',
to: { x: 200 },
duration: 2000
});
// Pause the animation
anim.pause();
// Resume from current position
anim.play();
// Stop and reset to start
anim.stop();
// Restart from beginning
anim.restart();Try it: Playback Control
const anim = FasterMotion.dom({
target: '#box',
to: { x: 200, rotation: 360 },
duration: 2000,
ease: 'linear'
});
// Control buttons available: Start, Pause, Resume, Stop, Restartseek()
Type: (time: number) => void
Jump to specific time in animation (milliseconds).
const anim = FasterMotion.dom({
target: '#box',
to: { x: 200 },
duration: 2000
});
// Jump to halfway point
anim.seek(1000);
// Jump to 75% complete
anim.seek(1500);progress()
Type: (value?: number) => number
Get or set animation progress (0 to 1).
const anim = FasterMotion.dom({
target: '#box',
to: { x: 200 },
duration: 2000
});
// Get current progress
const current = anim.progress(); // 0 to 1
// Set to 50% complete
anim.progress(0.5);
// Set to end
anim.progress(1);reverse()
Type: () => void
Reverse the animation direction.
const anim = FasterMotion.dom({
target: '#box',
to: { x: 200 },
duration: 1000
});
// Reverse direction
anim.reverse();
// Play backwards
anim.play();Try it: Reverse Animation
const anim = FasterMotion.dom({
target: '#box',
to: { x: 200, rotation: 360 },
duration: 1500,
ease: 'curve2.inOut'
});
// Reverse after 800ms
setTimeout(() => anim.reverse(), 800);Iterations
Repeat animations with different patterns.
repeat
Type: number | Default: 0
Number of times to repeat. Use -1 for infinite.
// Repeat 3 times
FasterMotion.dom({
target: '#box',
to: { x: 200 },
duration: 1000,
repeat: 3
});
// Infinite loop
FasterMotion.dom({
target: '#box',
to: { rotation: 360 },
duration: 2000,
repeat: -1,
ease: 'linear'
});Try it: Repeat Animation
FasterMotion.dom({
target: '#box',
to: { rotation: 360 },
duration: 1500,
repeat: 2,
ease: 'linear'
});yoyo
Type: boolean | Default: false
Alternate direction on each repeat.
// Bounce back and forth
FasterMotion.dom({
target: '#box',
to: { x: 200 },
duration: 1000,
repeat: 3,
yoyo: true,
ease: 'curve2.inOut'
});Try it: Yoyo Animation
FasterMotion.dom({
target: '#box',
to: { x: 200, scale: 1.5 },
duration: 800,
repeat: 3,
yoyo: true,
ease: 'curve2.inOut'
});repeatDelay
Type: number | Default: 0
Delay between repeats (milliseconds).
FasterMotion.dom({
target: '#box',
to: { x: 200 },
duration: 1000,
repeat: -1,
repeatDelay: 500 // Wait 500ms between repeats
});Infinite Pulse
// Pulsing scale animation
FasterMotion.dom({
target: '.button',
to: { scale: 1.1 },
duration: 600,
repeat: -1,
yoyo: true,
ease: 'curve2.inOut'
});Try it: Infinite Pulse
FasterMotion.dom({
target: '#box',
to: { scale: 1.3, opacity: 0.7 },
duration: 800,
repeat: -1,
yoyo: true,
ease: 'curve2.inOut'
});Advanced Patterns
Chained Animations
// Sequence using onComplete
FasterMotion.dom({
target: '#box',
to: { x: 200 },
duration: 1000,
onComplete: () => {
FasterMotion.dom({
target: '#box',
to: { y: 100 },
duration: 1000
});
}
});Pause on Hover
const anim = FasterMotion.dom({
target: '#box',
to: { rotation: 360 },
duration: 3000,
repeat: -1,
ease: 'linear'
});
const box = document.querySelector('#box');
box.addEventListener('mouseenter', () => anim.pause());
box.addEventListener('mouseleave', () => anim.play());Try it: Pause on Hover
const anim = FasterMotion.dom({
target: '#box',
to: { rotation: 360 },
duration: 3000,
repeat: -1,
ease: 'linear'
});
const box = document.querySelector('#box');
box.addEventListener('mouseenter', () => anim.pause());
box.addEventListener('mouseleave', () => anim.play());Progress Bar
const progressBar = document.querySelector('.progress');
FasterMotion.dom({
target: '#box',
to: { x: 500 },
duration: 3000,
onUpdate: (progress) => {
progressBar.style.width = (progress * 100) + '%';
}
});Try it: Progress Bar
const progressBar = document.querySelector('.progress-bar');
FasterMotion.dom({
target: '#box',
to: { x: 200 },
duration: 3000,
onUpdate: (progress) => {
progressBar.style.width = (progress * 100) + '%';
}
});Scrubber Control
const anim = FasterMotion.dom({
target: '#box',
to: { x: 300, rotation: 360 },
duration: 2000
});
// Pause immediately for scrubbing
anim.pause();
// Slider input
const slider = document.querySelector('#scrubber');
slider.addEventListener('input', (e) => {
anim.progress(e.target.value / 100);
});Try it: Scrubber Control
const anim = FasterMotion.dom({
target: '#box',
to: { x: 200, rotation: 360 },
duration: 2000
});
// Pause immediately for scrubbing
anim.pause();
// Slider input
const slider = document.querySelector('#scrubber');
slider.addEventListener('input', (e) => {
anim.progress(e.target.value / 100);
});Dynamic Duration
// Speed based on distance
function animateToPosition(x, y) {
const box = document.querySelector('#box');
const rect = box.getBoundingClientRect();
const dx = x - rect.left;
const dy = y - rect.top;
const distance = Math.sqrt(dx * dx + dy * dy);
// 1px per millisecond
const duration = distance;
FasterMotion.dom({
target: box,
to: { x, y },
duration,
ease: 'curve2.out'
});
}
document.addEventListener('click', (e) => {
animateToPosition(e.clientX, e.clientY);
});State Machine
let state = 'idle';
const states = {
idle: () => {
FasterMotion.dom({
target: '#box',
to: { scale: 1, rotation: 0 },
duration: 300
});
},
hover: () => {
FasterMotion.dom({
target: '#box',
to: { scale: 1.2, rotation: 5 },
duration: 300,
ease: 'back.out'
});
},
active: () => {
FasterMotion.dom({
target: '#box',
to: { scale: 0.95, rotation: 0 },
duration: 200
});
}
};
// Trigger state changes
function setState(newState) {
state = newState;
states[state]();
}
// Usage
box.addEventListener('mouseenter', () => setState('hover'));
box.addEventListener('mouseleave', () => setState('idle'));
box.addEventListener('mousedown', () => setState('active'));
box.addEventListener('mouseup', () => setState('hover'));Multi-Element Coordination
// Stagger multiple elements
const boxes = document.querySelectorAll('.box');
boxes.forEach((box, i) => {
FasterMotion.dom({
target: box,
to: { x: 200, rotation: 360 },
duration: 1000,
delay: i * 100, // Stagger by index
ease: 'back.out'
});
});Update While Running
const anim = FasterMotion.dom({
target: '#box',
to: { x: 200 },
duration: 2000
});
// Change target mid-animation
setTimeout(() => {
anim.stop();
FasterMotion.dom({
target: '#box',
to: { x: 100, y: 100 }, // New target
duration: 1000
});
}, 1000);Performance Tips
Batch Similar Animations
// Good: Single selector for multiple elements
FasterMotion.dom({
target: '.boxes',
to: { x: 100 },
duration: 1000
});
// Avoid: Individual animations
document.querySelectorAll('.boxes').forEach(box => {
FasterMotion.dom({
target: box,
to: { x: 100 },
duration: 1000
});
});Cleanup Animations
// Store reference for cleanup
const animations = [];
function createAnimation() {
const anim = FasterMotion.dom({
target: '#box',
to: { x: 200 },
duration: 1000
});
animations.push(anim);
}
// Cleanup on unmount/destroy
function cleanup() {
animations.forEach(anim => anim.stop());
animations.length = 0;
}Prefer Transform Properties
// Good: GPU-accelerated
FasterMotion.dom({
target: '#box',
to: { x: 100, scale: 1.2, rotation: 45 }
});
// Avoid: Triggers layout
FasterMotion.dom({
target: '#box',
to: { left: '100px', width: '200px' }
});Use will-change CSS
/* Hint browser to optimize */
.animated {
will-change: transform, opacity;
}
/* Remove after animation */
.animated.complete {
will-change: auto;
}Common Mistakes
Avoid
// Missing cleanup
setInterval(() => {
FasterMotion.dom({ target: '#box', to: { x: 100 } });
}, 1000);
// Conflicting animations
FasterMotion.dom({ target: '#box', to: { x: 100 } });
FasterMotion.dom({ target: '#box', to: { x: 200 } }); // Conflicts!
// Animating layout properties
FasterMotion.dom({ target: '#box', to: { width: '500px' } });Better
// Store and cleanup
const anim = FasterMotion.dom({ target: '#box', to: { x: 100 } });
// Later: anim.stop();
// Stop previous before new
if (currentAnim) currentAnim.stop();
currentAnim = FasterMotion.dom({ target: '#box', to: { x: 200 } });
// Use transform
FasterMotion.dom({ target: '#box', to: { scaleX: 1.5 } });TypeScript Support
import { FasterMotion, type Animation } from 'faster-motion';
// Typed animation reference
const anim: Animation = FasterMotion.dom({
target: '#box',
to: { x: 200, rotation: 360 },
duration: 1000,
ease: 'spring.bouncy',
onUpdate: (progress: number) => {
console.log(progress);
},
onComplete: () => {
console.log('Done');
}
});
// Type-safe control
anim.pause();
anim.play();
anim.progress(0.5);See Also
- Tween Basics - Core animation API
- Triggers & Scroll - Interactive triggers
- Timeline - Sequence animations
- Easing - Easing functions