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;