0
# Animation & Sprites
1
2
Frame-based animation system and animated sprite functionality for creating sprite animations and sequences. PixiJS provides efficient systems for both texture-based animations and programmatic animations.
3
4
## Capabilities
5
6
### Animated Sprite
7
8
Frame-based animation using texture sequences.
9
10
```typescript { .api }
11
/**
12
* Animated sprite for frame-based animations
13
*/
14
class AnimatedSprite extends Sprite {
15
/** Array of textures for animation */
16
textures: Texture[];
17
/** Current frame index */
18
currentFrame: number;
19
/** Whether animation is playing */
20
playing: boolean;
21
/** Whether animation should loop */
22
loop: boolean;
23
/** Animation playback speed */
24
animationSpeed: number;
25
/** Update anchor to match texture anchor */
26
updateAnchor: boolean;
27
/** Called when animation completes */
28
onComplete?: () => void;
29
/** Called when animation loops */
30
onLoop?: () => void;
31
/** Called when frame changes */
32
onFrameChange?: (currentFrame: number) => void;
33
/** Total frames */
34
readonly totalFrames: number;
35
36
/**
37
* Create animated sprite
38
* @param textures - Animation frames
39
* @param autoUpdate - Auto-update from ticker
40
*/
41
constructor(textures: Texture[], autoUpdate?: boolean);
42
43
/** Start animation */
44
play(): void;
45
46
/** Stop animation */
47
stop(): void;
48
49
/**
50
* Go to frame and play from there
51
* @param frameNumber - Frame to start from
52
*/
53
gotoAndPlay(frameNumber: number): void;
54
55
/**
56
* Go to frame and stop
57
* @param frameNumber - Frame to go to
58
*/
59
gotoAndStop(frameNumber: number): void;
60
61
/**
62
* Update animation
63
* @param deltaTime - Time since last update
64
*/
65
update(deltaTime: number): void;
66
67
/** Destroy animated sprite */
68
destroy(options?: boolean | IDestroyOptions): void;
69
}
70
```
71
72
### Spritesheet Management
73
74
Loading and managing sprite sheet animations.
75
76
```typescript { .api }
77
/**
78
* Spritesheet for managing texture atlases and animations
79
*/
80
class Spritesheet {
81
/** Base texture */
82
baseTexture: BaseTexture;
83
/** Spritesheet data */
84
data: ISpritesheetData;
85
/** Generated textures */
86
textures: Record<string, Texture>;
87
/** Generated animations */
88
animations: Record<string, Texture[]>;
89
/** Resolution */
90
resolution: number;
91
92
/**
93
* Create spritesheet
94
* @param texture - Base texture or image
95
* @param data - Spritesheet data
96
* @param resolutionFilename - Resolution from filename
97
*/
98
constructor(texture: BaseTexture | Texture, data: ISpritesheetData, resolutionFilename?: string);
99
100
/**
101
* Parse spritesheet data
102
* @param onProgress - Progress callback
103
*/
104
parse(onProgress?: (progress: number) => void): Promise<Record<string, Texture>>;
105
106
/** Destroy spritesheet */
107
destroy(destroyBase?: boolean): void;
108
}
109
110
interface ISpritesheetData {
111
frames: Record<string, ISpritesheetFrameData>;
112
animations?: Record<string, string[]>;
113
meta: {
114
scale: string;
115
format: string;
116
size: { w: number; h: number };
117
image: string;
118
};
119
}
120
121
interface ISpritesheetFrameData {
122
frame: { x: number; y: number; w: number; h: number };
123
trimmed?: boolean;
124
rotated?: boolean;
125
sourceSize?: { w: number; h: number };
126
spriteSourceSize?: { x: number; y: number; w: number; h: number };
127
anchor?: { x: number; y: number };
128
}
129
```
130
131
### Ticker-Based Animation
132
133
Using the ticker system for custom animations.
134
135
```typescript { .api }
136
/**
137
* Ticker for driving animations and updates
138
*/
139
class Ticker {
140
/** Shared ticker instance */
141
static shared: Ticker;
142
/** Current delta time */
143
deltaTime: number;
144
/** Elapsed time in milliseconds */
145
elapsedMS: number;
146
/** Current FPS */
147
FPS: number;
148
/** Animation speed multiplier */
149
speed: number;
150
/** Whether ticker is started */
151
started: boolean;
152
153
/**
154
* Add update function
155
* @param fn - Update function
156
* @param context - Function context
157
* @param priority - Update priority
158
*/
159
add<T = any>(fn: TickerCallback<T>, context?: T, priority?: number): this;
160
161
/**
162
* Remove update function
163
* @param fn - Function to remove
164
* @param context - Function context
165
*/
166
remove<T = any>(fn: TickerCallback<T>, context?: T): this;
167
168
/** Start ticker */
169
start(): void;
170
171
/** Stop ticker */
172
stop(): void;
173
174
/** Update manually */
175
update(currentTime?: number): void;
176
}
177
178
type TickerCallback<T = any> = (this: T, deltaTime: number) => void;
179
```
180
181
**Usage Examples:**
182
183
```typescript
184
import { AnimatedSprite, Spritesheet, Assets, Ticker } from "pixi.js";
185
186
// Load spritesheet and create animation
187
const sheet = await Assets.load('character-spritesheet.json');
188
const walkTextures = sheet.animations['walk'];
189
190
const animatedCharacter = new AnimatedSprite(walkTextures);
191
animatedCharacter.animationSpeed = 0.167; // 10 FPS (1/60 * 10)
192
animatedCharacter.loop = true;
193
animatedCharacter.play();
194
195
// Animation callbacks
196
animatedCharacter.onComplete = () => {
197
console.log('Animation completed');
198
};
199
200
animatedCharacter.onFrameChange = (frame) => {
201
console.log(`Frame changed to: ${frame}`);
202
};
203
204
// Manual animation control
205
animatedCharacter.gotoAndStop(0); // Go to first frame
206
animatedCharacter.gotoAndPlay(5); // Start from frame 5
207
208
// Custom ticker-based animation (requires TickerPlugin)
209
const sprite = Sprite.from('player.png');
210
let elapsed = 0;
211
212
// app.ticker.add((delta) => {
213
// elapsed += delta;
214
// sprite.x = Math.cos(elapsed * 0.1) * 100 + 200;
215
// sprite.y = Math.sin(elapsed * 0.1) * 50 + 150;
216
// sprite.rotation = elapsed * 0.05;
217
// });
218
219
// Programmatic spritesheet creation
220
const textures = [];
221
for (let i = 0; i < 8; i++) {
222
textures.push(Texture.from(`frame${i}.png`));
223
}
224
225
const programmaticAnimation = new AnimatedSprite(textures);
226
programmaticAnimation.animationSpeed = 0.5;
227
programmaticAnimation.play();
228
```
229
230
### Animation States
231
232
Managing complex animation states and transitions.
233
234
```typescript
235
// Animation state manager example
236
class AnimationStateMachine {
237
private currentState: string = 'idle';
238
private animations: Record<string, AnimatedSprite> = {};
239
private sprite: Container;
240
241
constructor() {
242
this.sprite = new Container();
243
}
244
245
addAnimation(name: string, textures: Texture[]) {
246
const animatedSprite = new AnimatedSprite(textures);
247
animatedSprite.visible = false;
248
this.animations[name] = animatedSprite;
249
this.sprite.addChild(animatedSprite);
250
}
251
252
setState(newState: string) {
253
if (this.animations[this.currentState]) {
254
this.animations[this.currentState].stop();
255
this.animations[this.currentState].visible = false;
256
}
257
258
this.currentState = newState;
259
260
if (this.animations[newState]) {
261
this.animations[newState].visible = true;
262
this.animations[newState].gotoAndPlay(0);
263
}
264
}
265
266
getSprite() {
267
return this.sprite;
268
}
269
}
270
271
// Usage
272
const character = new AnimationStateMachine();
273
character.addAnimation('idle', idleTextures);
274
character.addAnimation('walk', walkTextures);
275
character.addAnimation('jump', jumpTextures);
276
277
app.stage.addChild(character.getSprite());
278
character.setState('idle');
279
280
// State transitions based on input
281
document.addEventListener('keydown', (e) => {
282
switch(e.key) {
283
case 'ArrowLeft':
284
case 'ArrowRight':
285
character.setState('walk');
286
break;
287
case ' ':
288
character.setState('jump');
289
break;
290
default:
291
character.setState('idle');
292
}
293
});
294
```
295
296
### Tween Animation
297
298
While PixiJS doesn't include built-in tweening, it integrates well with external libraries:
299
300
```typescript
301
// Using external tween library (conceptual)
302
import { Sprite, Ticker } from "pixi.js";
303
304
// Custom simple tween implementation
305
class SimpleTween {
306
private object: any;
307
private property: string;
308
private startValue: number;
309
private endValue: number;
310
private duration: number;
311
private elapsed: number = 0;
312
private onComplete?: () => void;
313
private easing: (t: number) => number;
314
315
constructor(object: any, property: string, endValue: number, duration: number, easing?: (t: number) => number) {
316
this.object = object;
317
this.property = property;
318
this.startValue = object[property];
319
this.endValue = endValue;
320
this.duration = duration;
321
this.easing = easing || ((t) => t); // Linear by default
322
323
Ticker.shared.add(this.update, this);
324
}
325
326
private update(delta: number) {
327
this.elapsed += delta * (1000 / 60); // Convert to milliseconds
328
const progress = Math.min(this.elapsed / this.duration, 1);
329
const easedProgress = this.easing(progress);
330
331
this.object[this.property] = this.startValue + (this.endValue - this.startValue) * easedProgress;
332
333
if (progress >= 1) {
334
Ticker.shared.remove(this.update, this);
335
if (this.onComplete) {
336
this.onComplete();
337
}
338
}
339
}
340
341
onCompleteCallback(callback: () => void) {
342
this.onComplete = callback;
343
return this;
344
}
345
}
346
347
// Usage
348
const sprite = Sprite.from('player.png');
349
app.stage.addChild(sprite);
350
351
// Animate position
352
new SimpleTween(sprite, 'x', 400, 1000, (t) => t * t) // Quadratic easing
353
.onCompleteCallback(() => {
354
console.log('Movement complete');
355
// Chain another animation
356
new SimpleTween(sprite, 'rotation', Math.PI * 2, 2000);
357
});
358
359
// Animate alpha
360
new SimpleTween(sprite, 'alpha', 0.5, 500);
361
362
// Animate scale
363
new SimpleTween(sprite.scale, 'x', 2, 800);
364
new SimpleTween(sprite.scale, 'y', 2, 800);
365
```
366
367
### Performance Optimization
368
369
```typescript
370
// Efficient animation techniques
371
372
// 1. Object pooling for temporary animated sprites
373
class AnimatedSpritePool {
374
private pool: AnimatedSprite[] = [];
375
376
get(textures: Texture[]): AnimatedSprite {
377
let sprite = this.pool.pop();
378
if (!sprite) {
379
sprite = new AnimatedSprite(textures);
380
} else {
381
sprite.textures = textures;
382
sprite.gotoAndStop(0);
383
}
384
return sprite;
385
}
386
387
release(sprite: AnimatedSprite) {
388
sprite.stop();
389
sprite.visible = false;
390
sprite.parent?.removeChild(sprite);
391
this.pool.push(sprite);
392
}
393
}
394
395
// 2. Batch animation updates (requires TickerPlugin)
396
const animations: AnimatedSprite[] = [];
397
// app.ticker.add((delta) => {
398
// for (const animation of animations) {
399
// animation.update(delta);
400
// }
401
// });
402
403
// 3. Use appropriate animation speeds
404
// Too fast: Wastes GPU cycles
405
// Too slow: Appears choppy
406
const optimalSpeed = 0.167; // ~10 FPS for most game animations
407
408
// 4. Limit concurrent animations
409
const MAX_CONCURRENT_ANIMATIONS = 50;
410
let activeAnimations = 0;
411
412
function startAnimation(sprite: AnimatedSprite) {
413
if (activeAnimations < MAX_CONCURRENT_ANIMATIONS) {
414
sprite.play();
415
activeAnimations++;
416
417
sprite.onComplete = () => {
418
activeAnimations--;
419
};
420
}
421
}
422
```