or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

animation.mdapplication.mdassets.mddisplay-objects.mdevents.mdfilters.mdgraphics.mdindex.mdmath.mdrendering.mdtext.mdtextures.mdutils.md
tile.json

animation.mddocs/

Animation and Ticker

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.

Capabilities

Ticker System

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
}

Ticker Listener

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;
}

Animated Sprite

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;
}

Animation Utilities

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;
}

Performance Animation

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();
});