Animation system with frame-rate independent timing, ticker management, and sprite animation utilities. The ticker system provides the foundation for smooth animations and frame-based updates.
Core animation timing system with frame-rate independent updates.
/**
* Ticker system for animation timing
*/
class Ticker extends EventEmitter {
constructor();
/** Is ticker started */
started: boolean;
/** Animation speed multiplier */
speed: number;
/** Delta time since last frame */
readonly deltaTime: number;
/** Delta time in milliseconds */
readonly deltaMS: number;
/** Elapsed time since last frame */
readonly elapsedMS: number;
/** Last frame timestamp */
readonly lastTime: number;
/** Minimum FPS before deltaTime clamping */
minFPS: number;
/** Maximum FPS cap */
maxFPS: number;
/** Target frames per second */
readonly FPS: number;
/**
* Add callback to ticker
* @param fn - Callback function
* @param context - Callback context
* @param priority - Execution priority
* @returns This ticker
*/
add(fn: TickerCallback, context?: any, priority?: UPDATE_PRIORITY): this;
/**
* Add callback to run once
* @param fn - Callback function
* @param context - Callback context
* @param priority - Execution priority
* @returns This ticker
*/
addOnce(fn: TickerCallback, context?: any, priority?: UPDATE_PRIORITY): this;
/**
* Remove callback from ticker
* @param fn - Callback function
* @param context - Callback context
* @returns This ticker
*/
remove(fn: TickerCallback, context?: any): this;
/**
* Start ticker
*/
start(): void;
/**
* Stop ticker
*/
stop(): void;
/**
* Destroy ticker
*/
destroy(): void;
/**
* Update ticker manually
* @param currentTime - Current timestamp
*/
update(currentTime?: number): void;
/** Shared ticker instance */
static readonly shared: Ticker;
/** System ticker (used by Application) */
static readonly system: Ticker;
}
/**
* Ticker callback function
*/
type TickerCallback = (ticker: Ticker) => void;
/**
* Update priorities for ticker callbacks
*/
enum UPDATE_PRIORITY {
INTERACTION = 50,
HIGH = 25,
NORMAL = 0,
LOW = -25,
UTILITY = -50
}Individual ticker listener management.
/**
* Ticker listener for individual callback management
*/
class TickerListener {
constructor(fn: TickerCallback, context?: any, priority?: number, once?: boolean);
/** Callback function */
fn: TickerCallback;
/** Callback context */
context: any;
/** Execution priority */
priority: number;
/** Run once flag */
once: boolean;
/** Next listener in chain */
next: TickerListener;
/** Previous listener in chain */
previous: TickerListener;
/** Is destroyed */
destroyed: boolean;
/**
* Match function and context
* @param fn - Function to match
* @param context - Context to match
* @returns True if matches
*/
match(fn: TickerCallback, context?: any): boolean;
/**
* Emit callback
* @param ticker - Ticker instance
* @returns Next listener
*/
emit(ticker: Ticker): TickerListener;
/**
* Connect to another listener
* @param previous - Previous listener
*/
connect(previous: TickerListener): void;
/**
* Destroy listener
*/
destroy(): void;
}Sprite class with built-in texture-based animation support.
/**
* Animated sprite with texture frame animation
*/
class AnimatedSprite extends Sprite {
constructor(textures: Texture[] | FrameObject[], autoUpdate?: boolean);
/** Animation textures/frames */
textures: Texture[] | FrameObject[];
/** Current frame index */
currentFrame: number;
/** Animation speed (frames per second at 60 FPS) */
animationSpeed: number;
/** Loop animation */
loop: boolean;
/** Update anchor with frames */
updateAnchor: boolean;
/** Callback when animation completes */
onComplete: () => void;
/** Callback when frame changes */
onFrameChange: (currentFrame: number) => void;
/** Callback when animation loops */
onLoop: () => void;
/** Total number of frames */
readonly totalFrames: number;
/** Is animation playing */
readonly playing: boolean;
/**
* Start playing animation
*/
play(): void;
/**
* Stop animation
*/
stop(): void;
/**
* Go to specific frame and play
* @param frameNumber - Frame to go to
*/
gotoAndPlay(frameNumber: number): void;
/**
* Go to specific frame and stop
* @param frameNumber - Frame to go to
*/
gotoAndStop(frameNumber: number): void;
/**
* Update animation
* @param deltaTime - Time since last update
*/
update(deltaTime: number): void;
/**
* Destroy animated sprite
* @param options - Destroy options
*/
destroy(options?: DestroyOptions): void;
/**
* Create from array of image sources
* @param images - Array of image sources
* @returns New animated sprite
*/
static fromImages(images: string[]): AnimatedSprite;
/**
* Create from sprite sheet frames
* @param sheet - Sprite sheet
* @param frameNames - Array of frame names
* @returns New animated sprite
*/
static fromFrames(frameNames: string[]): AnimatedSprite;
}
/**
* Animation frame with timing information
*/
interface FrameObject {
/** Frame texture */
texture: Texture;
/** Frame duration in milliseconds */
time: number;
}Utility functions and classes for animation management.
/**
* Simple tween class for property animation
*/
class Tween {
constructor(target: any);
/** Target object */
target: any;
/** Is tween playing */
playing: boolean;
/** Tween duration */
duration: number;
/** Tween progress (0-1) */
progress: number;
/** Easing function */
easing: (t: number) => number;
/** Completion callback */
onComplete: () => void;
/** Update callback */
onUpdate: (progress: number) => void;
/**
* Animate to target values
* @param properties - Target property values
* @param duration - Animation duration in milliseconds
* @param easing - Easing function
* @returns This tween
*/
to(properties: Record<string, number>, duration: number, easing?: (t: number) => number): this;
/**
* Start tween
* @returns This tween
*/
start(): this;
/**
* Stop tween
* @returns This tween
*/
stop(): this;
/**
* Update tween
* @param deltaTime - Time since last update
*/
update(deltaTime: number): void;
/**
* Set completion callback
* @param callback - Completion callback
* @returns This tween
*/
call(callback: () => void): this;
}
/**
* Common easing functions
*/
const Easing = {
/** Linear interpolation */
linear: (t: number) => t,
/** Ease in (accelerate) */
easeIn: (t: number) => t * t,
/** Ease out (decelerate) */
easeOut: (t: number) => 1 - (1 - t) * (1 - t),
/** Ease in-out (accelerate then decelerate) */
easeInOut: (t: number) => t < 0.5 ? 2 * t * t : 1 - 2 * (1 - t) * (1 - t),
/** Elastic ease out */
elasticOut: (t: number) => Math.sin(-13 * (t + 1) * Math.PI / 2) * Math.pow(2, -10 * t) + 1,
/** Bounce ease out */
bounceOut: (t: number) => {
if (t < 1 / 2.75) {
return 7.5625 * t * t;
} else if (t < 2 / 2.75) {
return 7.5625 * (t -= 1.5 / 2.75) * t + 0.75;
} else if (t < 2.5 / 2.75) {
return 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375;
} else {
return 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375;
}
}
};
/**
* Animation timeline for sequencing animations
*/
class Timeline {
constructor();
/** Timeline duration */
duration: number;
/** Timeline progress */
progress: number;
/** Is timeline playing */
playing: boolean;
/** Timeline animations */
animations: TimelineAnimation[];
/**
* Add animation to timeline
* @param target - Target object
* @param properties - Properties to animate
* @param duration - Animation duration
* @param delay - Animation delay
* @returns This timeline
*/
add(target: any, properties: Record<string, number>, duration: number, delay?: number): this;
/**
* Play timeline
* @returns This timeline
*/
play(): this;
/**
* Stop timeline
* @returns This timeline
*/
stop(): this;
/**
* Update timeline
* @param deltaTime - Time since last update
*/
update(deltaTime: number): void;
}
interface TimelineAnimation {
target: any;
properties: Record<string, number>;
startValues: Record<string, number>;
duration: number;
delay: number;
startTime: number;
}High-performance animation utilities for large numbers of objects.
/**
* Animation pool for reusing animation objects
*/
class AnimationPool {
constructor();
/** Available animations */
available: Tween[];
/** Active animations */
active: Tween[];
/**
* Get animation from pool
* @param target - Target object
* @returns Pooled animation
*/
get(target: any): Tween;
/**
* Return animation to pool
* @param animation - Animation to return
*/
return(animation: Tween): void;
/**
* Update all active animations
* @param deltaTime - Time since last update
*/
update(deltaTime: number): void;
/**
* Clean up pool
*/
destroy(): void;
}
/**
* Batch animation system for many objects
*/
class BatchAnimator {
constructor();
/** Animation targets */
targets: any[];
/** Animation properties */
properties: string[];
/** Animation duration */
duration: number;
/** Animation progress */
progress: number;
/**
* Add target to batch
* @param target - Target object
* @param startValues - Starting values
* @param endValues - Ending values
*/
addTarget(target: any, startValues: Record<string, number>, endValues: Record<string, number>): void;
/**
* Update all targets
* @param deltaTime - Time since last update
*/
update(deltaTime: number): void;
/**
* Start batch animation
*/
start(): void;
/**
* Stop batch animation
*/
stop(): void;
}Usage Examples:
import {
Ticker,
AnimatedSprite,
Tween,
Timeline,
Easing,
Assets,
Sprite,
Container,
UPDATE_PRIORITY
} from 'pixi.js';
// Basic ticker usage
const ticker = new Ticker();
ticker.add((ticker) => {
// This runs every frame
console.log(`FPS: ${ticker.FPS}, Delta: ${ticker.deltaTime}`);
});
ticker.start();
// Animation with different priorities
ticker.add((ticker) => {
// High priority update (runs first)
updatePhysics(ticker.deltaTime);
}, null, UPDATE_PRIORITY.HIGH);
ticker.add((ticker) => {
// Normal priority update
updateVisuals(ticker.deltaTime);
}, null, UPDATE_PRIORITY.NORMAL);
ticker.add((ticker) => {
// Low priority update (runs last)
updateUI(ticker.deltaTime);
}, null, UPDATE_PRIORITY.LOW);
// Animated sprite creation
const walkTextures = [
await Assets.load('walk1.png'),
await Assets.load('walk2.png'),
await Assets.load('walk3.png'),
await Assets.load('walk4.png')
];
const animatedSprite = new AnimatedSprite(walkTextures);
animatedSprite.animationSpeed = 0.167; // 10 FPS at 60 FPS
animatedSprite.loop = true;
animatedSprite.play();
// Animation callbacks
animatedSprite.onComplete = () => {
console.log('Animation completed');
};
animatedSprite.onFrameChange = (currentFrame) => {
console.log(`Frame changed to: ${currentFrame}`);
};
animatedSprite.onLoop = () => {
console.log('Animation looped');
};
// Frame objects with custom timing
const customFrames = [
{ texture: walkTextures[0], time: 100 }, // 100ms
{ texture: walkTextures[1], time: 150 }, // 150ms
{ texture: walkTextures[2], time: 100 }, // 100ms
{ texture: walkTextures[3], time: 200 } // 200ms
];
const customAnimatedSprite = new AnimatedSprite(customFrames);
customAnimatedSprite.play();
// Simple property tweening
const sprite = new Sprite(await Assets.load('sprite.png'));
const tween = new Tween(sprite)
.to({ x: 400, y: 300, alpha: 0.5 }, 2000, Easing.easeInOut)
.call(() => {
console.log('Tween completed');
});
tween.start();
// Update tween manually or with ticker
ticker.add((ticker) => {
tween.update(ticker.elapsedMS);
});
// Complex animation timeline
const timeline = new Timeline();
timeline
.add(sprite, { x: 200 }, 1000, 0) // Move to x: 200 over 1s, start immediately
.add(sprite, { y: 200 }, 1000, 500) // Move to y: 200 over 1s, start after 0.5s
.add(sprite, { alpha: 0 }, 500, 1500) // Fade out over 0.5s, start after 1.5s
.play();
ticker.add((ticker) => {
timeline.update(ticker.elapsedMS);
});
// Sprite scaling animation with bounce
const scaleSprite = new Sprite(texture);
const scaleTween = new Tween(scaleSprite.scale)
.to({ x: 2, y: 2 }, 1000, Easing.bounceOut);
scaleTween.start();
// Rotation animation
const rotationSprite = new Sprite(texture);
ticker.add((ticker) => {
rotationSprite.rotation += 0.01 * ticker.deltaTime;
});
// Color animation using tint
const colorSprite = new Sprite(texture);
let hue = 0;
ticker.add((ticker) => {
hue += 0.01 * ticker.deltaTime;
const color = new Color();
color.setHsl(hue % 1, 1, 0.5);
colorSprite.tint = color.value;
});
// Performance optimization - pause ticker when not needed
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
ticker.stop();
} else {
ticker.start();
}
});
// Animation state machine
class AnimationStateMachine {
private currentState: string = 'idle';
private animations: Record<string, AnimatedSprite> = {};
constructor(private sprite: Container) {}
addAnimation(name: string, animation: AnimatedSprite) {
this.animations[name] = animation;
this.sprite.addChild(animation);
animation.visible = false;
}
setState(newState: string) {
if (this.animations[this.currentState]) {
this.animations[this.currentState].visible = false;
this.animations[this.currentState].stop();
}
this.currentState = newState;
if (this.animations[newState]) {
this.animations[newState].visible = true;
this.animations[newState].play();
}
}
}
// Character with multiple animations
const character = new Container();
const stateMachine = new AnimationStateMachine(character);
stateMachine.addAnimation('idle', new AnimatedSprite(idleTextures));
stateMachine.addAnimation('walk', new AnimatedSprite(walkTextures));
stateMachine.addAnimation('jump', new AnimatedSprite(jumpTextures));
// Switch animations based on input
stateMachine.setState('walk');
// Particle animation system
const particles: Sprite[] = [];
const particleCount = 100;
for (let i = 0; i < particleCount; i++) {
const particle = new Sprite(particleTexture);
particle.x = Math.random() * 800;
particle.y = Math.random() * 600;
particle.anchor.set(0.5);
particles.push(particle);
app.stage.addChild(particle);
}
ticker.add((ticker) => {
particles.forEach((particle, index) => {
particle.rotation += 0.01 * ticker.deltaTime;
particle.y += Math.sin(Date.now() * 0.001 + index) * 0.5;
particle.alpha = 0.5 + Math.sin(Date.now() * 0.002 + index) * 0.5;
});
});
// Clean up animations
window.addEventListener('beforeunload', () => {
ticker.destroy();
tween.stop();
timeline.stop();
animatedSprite.destroy();
});