Fast, multipurpose JavaScript animation library for CSS, SVG, DOM, and JS objects with timelines, scroll triggers, physics, and interactive draggables
Scoped animation context for managing animation lifecycles, cleanup, and shared configuration across related animations.
Create scoped animation context for organized animation management and automatic cleanup.
/**
* Create scoped animation context
* @param parameters - Scope configuration
* @returns Scope instance
*/
function createScope(parameters?: ScopeParams): Scope;Usage Example:
import { createScope } from "animejs/scope";
const scope = createScope({
root: ".component",
defaults: {
duration: 1000,
ease: "outQuad",
},
});
// All animations inherit defaults and are tracked in scope
scope.animate(".box", { x: 100 });
// Cleanup all animations at once
scope.revert();Scoped context for managing animations, shared configuration, and lifecycle control.
/**
* Scope class for animation context management
*/
class Scope {
// ===== Properties =====
/**
* Default parameters applied to all animations in scope
* Shared configuration for consistent behavior
*/
defaults: DefaultsParams;
/**
* Root element for scoped queries
* All selectors are resolved within this root
*/
root: Document | DOMTarget;
/**
* Named methods added to scope
* Custom reusable animation functions
*/
methods: Record<string, ScopeMethod>;
/**
* Data storage for scope
* Store any custom data associated with scope
*/
data: Record<string, any>;
/**
* Media query match results
* Automatic tracking of responsive breakpoints
*/
matches: Record<string, boolean>;
// ===== Methods =====
/**
* Add named method to scope
* Create reusable animation function within scope
* @param methodName - Name for the method
* @param method - Method implementation
* @returns Scope instance for chaining
*/
add(methodName: string, method: ScopeMethod): Scope;
/**
* Add constructor function to scope
* Execute immediately and on scope refresh
* @param constructor - Function to execute
* @returns Scope instance for chaining
*/
add(constructor: () => Tickable | Revertible | void): Scope;
/**
* Add one-time constructor function
* Execute once, don't re-run on refresh
* @param constructor - Function to execute once
* @returns Scope instance for chaining
*/
addOnce(constructor: () => Tickable | Revertible | void): Scope;
/**
* Execute callback in scope context
* Runs immediately with scope context
* @param callback - Function to execute
* @returns Scope instance for chaining
*/
execute(callback: (scope: Scope) => void): Scope;
/**
* Keep animation time synced in scope
* Wrap constructor to maintain timing across refreshes
* @param callback - Constructor that returns Tickable
* @returns Scope instance for chaining
*/
keepTime(callback: () => Tickable): Scope;
/**
* Refresh scope
* Re-runs constructors and updates all animations
* @returns Scope instance for chaining
*/
refresh(): Scope;
/**
* Revert all scope animations and cleanup
* Removes all animations, timers, and event listeners
* @returns Scope instance for chaining
*/
revert(): Scope;
}Usage Examples:
import { createScope, animate } from "animejs";
// Create scope with defaults
const scope = createScope({
root: ".app",
defaults: {
duration: 800,
ease: "outQuad",
},
});
// Animations inherit defaults
const anim1 = scope.animate(".header", {
opacity: [0, 1],
// Automatically uses duration: 800, ease: 'outQuad'
});
const anim2 = scope.animate(".content", {
translateY: [50, 0],
duration: 1200, // Override default
});
// Cleanup all animations in scope
scope.revert();Configure defaults applied to all animations in scope:
const scope = createScope({
defaults: {
duration: 1000,
ease: "outCubic",
composition: "blend",
},
});
// These inherit defaults
scope.animate(".box1", { x: 100 });
scope.animate(".box2", { y: 100 });
scope.animate(".box3", {
rotate: 360,
duration: 2000, // Override default
});Scope all queries to specific root element:
// Scope to component
const componentScope = createScope({
root: ".my-component",
});
// Queries relative to root
componentScope.animate(".header", { opacity: 1 }); // Finds .my-component .header
componentScope.animate(".footer", { y: 0 }); // Finds .my-component .footer
// Multiple components with same structure
document.querySelectorAll(".card").forEach((card) => {
const scope = createScope({ root: card });
scope.animate(".title", { opacity: [0, 1] });
scope.animate(".content", { y: [20, 0] });
});Add reusable animation methods to scope:
const scope = createScope({
root: ".app",
});
// Add named method
scope.add("fadeIn", (targets, params) => {
return scope.animate(targets, {
opacity: [0, 1],
translateY: [20, 0],
...params,
});
});
scope.add("slideOut", (targets, params) => {
return scope.animate(targets, {
translateX: [0, 100],
opacity: [1, 0],
...params,
});
});
// Use named methods
scope.fadeIn(".box1");
scope.slideOut(".box2", { duration: 500 });Add initialization functions that run with scope:
const scope = createScope({
root: ".page",
});
// Add constructor - runs immediately and on refresh
scope.add(() => {
// Setup animations
scope.animate(".header", {
opacity: [0, 1],
translateY: [-50, 0],
});
scope.animate(".content", {
opacity: [0, 1],
delay: 300,
});
});
// Add one-time constructor - runs once only
scope.addOnce(() => {
console.log("Initializing scope");
// One-time setup
});
// Refresh re-runs constructors (except addOnce)
scope.refresh();Run code with scope context:
const scope = createScope({
root: ".container",
defaults: { duration: 1000 },
});
scope.execute((s) => {
// Access scope properties
console.log(s.root);
console.log(s.defaults);
// Create animations in scope
s.animate(".item1", { x: 100 });
s.animate(".item2", { y: 100 });
});Maintain animation time across scope refreshes:
const scope = createScope();
scope.keepTime(() => {
return animate(".box", {
rotate: 360,
duration: 5000,
loop: true,
});
});
// Animation continues from current time after refresh
scope.refresh();Store custom data in scope:
const scope = createScope();
// Store data
scope.data.animationSpeed = "fast";
scope.data.isRevealed = false;
scope.data.currentStep = 1;
// Access data
if (scope.data.animationSpeed === "fast") {
scope.defaults.duration = 500;
}
// Use in animations
scope.add(() => {
scope.animate(".step", {
opacity: scope.data.currentStep === 1 ? 1 : 0,
});
});Track responsive breakpoints in scope:
const scope = createScope({
matches: {
mobile: "(max-width: 768px)",
tablet: "(min-width: 769px) and (max-width: 1024px)",
desktop: "(min-width: 1025px)",
},
});
// Access match results
if (scope.matches.mobile) {
scope.animate(".menu", { translateX: ["-100%", 0] });
} else {
scope.animate(".menu", { opacity: [0, 1] });
}
// Auto-updates on viewport changes
window.addEventListener("resize", () => {
scope.refresh(); // Re-evaluates matches
});Complete lifecycle control:
// Create scope
const scope = createScope({
root: ".component",
defaults: { duration: 1000 },
});
// Add animations
scope.add(() => {
scope.animate(".element", { x: 100 });
});
// Refresh scope - re-runs constructors
scope.refresh();
// Cleanup all animations and revert
scope.revert();Use scopes for component-based animations:
class AnimatedComponent {
private scope: Scope;
constructor(element: HTMLElement) {
this.scope = createScope({
root: element,
defaults: {
duration: 600,
ease: "outQuad",
},
});
this.init();
}
private init() {
this.scope.add("show", () => {
return this.scope.animate(".content", {
opacity: [0, 1],
translateY: [20, 0],
});
});
this.scope.add("hide", () => {
return this.scope.animate(".content", {
opacity: [1, 0],
translateY: [0, -20],
});
});
}
show() {
this.scope.show();
}
hide() {
this.scope.hide();
}
destroy() {
this.scope.revert();
}
update() {
this.scope.refresh();
}
}
// Usage
const component = new AnimatedComponent(document.querySelector(".card"));
component.show();
// Cleanup when done
component.destroy();Organize complex apps with multiple scopes:
// Header scope
const headerScope = createScope({
root: ".header",
defaults: { duration: 500 },
});
headerScope.add(() => {
headerScope.animate(".logo", { opacity: [0, 1] });
headerScope.animate(".nav", { translateY: [-20, 0] });
});
// Main content scope
const contentScope = createScope({
root: ".main",
defaults: { duration: 800 },
});
contentScope.add(() => {
contentScope.animate(".article", { opacity: [0, 1] });
});
// Footer scope
const footerScope = createScope({
root: ".footer",
defaults: { duration: 600 },
});
// Cleanup all
function cleanup() {
headerScope.revert();
contentScope.revert();
footerScope.revert();
}Update animations on route changes:
const pageScope = createScope({
root: ".page",
});
pageScope.add(() => {
// Animations for current page state
const page = pageScope.root.getAttribute("data-page");
if (page === "home") {
pageScope.animate(".hero", { scale: [0.8, 1] });
} else if (page === "about") {
pageScope.animate(".team", { opacity: [0, 1] });
}
});
// On route change
router.on("change", () => {
pageScope.refresh(); // Re-evaluate animations
});Create responsive animations based on conditions:
const scope = createScope({
root: ".feature",
matches: {
mobile: "(max-width: 768px)",
},
});
scope.add(() => {
if (scope.matches.mobile) {
// Mobile animations
scope.animate(".content", {
translateY: [100, 0],
duration: 400,
});
} else {
// Desktop animations
scope.animate(".content", {
translateX: [-100, 0],
scale: [0.9, 1],
duration: 600,
});
}
});
// Refresh on resize
window.addEventListener("resize", () => {
scope.refresh();
});/**
* Scope configuration parameters
*/
interface ScopeParams {
/** Default parameters for all animations in scope */
defaults?: DefaultsParams;
/** Root element for scoped queries */
root?: string | Document | DOMTarget;
/** Media query definitions for responsive behavior */
matches?: Record<string, string>;
/** Initial data storage */
data?: Record<string, any>;
}
/**
* Default parameters for animations
*/
interface DefaultsParams {
/** Default duration */
duration?: number;
/** Default easing */
ease?: EasingParam;
/** Default composition mode */
composition?: TweenComposition;
/** Any other animation parameter */
[key: string]: any;
}
/**
* Scope method function type
*/
type ScopeMethod = (...args: any[]) => Tickable | Revertible | void;
/**
* Revertible object with cleanup
*/
interface Revertible {
revert(): void;
}
/**
* DOM target type
*/
type DOMTarget = HTMLElement | SVGElement;
/**
* Tickable animation or timer
*/
type Tickable = Timer | JSAnimation | Timeline;Install with Tessl CLI
npx tessl i tessl/npm-animejs