or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

animation-interaction.mdapplication.mdassets.mddisplay-objects.mdgraphics-rendering.mdindex.mdtext.md

animation-interaction.mddocs/

0

# Animation & Interaction

1

2

Animation and interaction systems in PIXI.js that enable dynamic content and user input handling through frame-based animations, global update loops, and comprehensive event management.

3

4

## Core Animation Systems

5

6

### AnimatedSprite Class { .api }

7

8

Frame-based sprite animation system that automatically cycles through texture sequences.

9

10

```typescript

11

class AnimatedSprite extends Sprite {

12

// Animation Control

13

animationSpeed: number; // Speed multiplier (default: 1)

14

loop: boolean; // Whether animation repeats (default: true)

15

playing: boolean; // Current playback state (readonly)

16

autoUpdate: boolean; // Use Ticker.shared for updates

17

updateAnchor: boolean; // Update anchor from texture defaultAnchor

18

19

// Frame Management

20

textures: Texture[] | FrameObject[]; // Animation frame sequence

21

currentFrame: number; // Current frame index

22

totalFrames: number; // Total frame count (readonly)

23

24

// Event Callbacks

25

onComplete?: () => void; // Called when animation finishes

26

onFrameChange?: (frame: number) => void; // Called on frame change

27

onLoop?: () => void; // Called when animation loops

28

29

// Constructor

30

constructor(textures: Texture[] | FrameObject[], autoUpdate?: boolean);

31

32

// Playback Control

33

play(): void; // Start animation

34

stop(): void; // Stop animation

35

gotoAndPlay(frameNumber: number): void; // Jump to frame and play

36

gotoAndStop(frameNumber: number): void; // Jump to frame and stop

37

38

// Manual Updates

39

update(deltaTime: number): void; // Update animation state

40

41

// Static Factory Methods

42

static fromFrames(frames: string[]): AnimatedSprite;

43

static fromImages(images: string[]): AnimatedSprite;

44

}

45

46

interface FrameObject {

47

texture: Texture; // Frame texture

48

time: number; // Duration in milliseconds

49

}

50

```

51

52

### Ticker System { .api }

53

54

Global update loop system that manages frame-based updates and timing.

55

56

```typescript

57

class Ticker {

58

// Static Properties

59

static targetFPMS: number; // Target frames per millisecond (0.06)

60

static shared: Ticker; // Shared ticker instance

61

static system: Ticker; // System ticker instance

62

63

// Timing Properties

64

deltaTime: number; // Scaled time between frames

65

deltaMS: number; // Milliseconds between frames (scaled)

66

elapsedMS: number; // Raw milliseconds between frames

67

lastTime: number; // Last update timestamp

68

speed: number; // Time scale multiplier

69

started: boolean; // Whether ticker is running

70

autoStart: boolean; // Auto-start when listeners added

71

FPS: number; // Current frames per second (readonly)

72

count: number; // Number of listeners (readonly)

73

74

// FPS Limits

75

minFPS: number; // Minimum FPS (caps deltaTime)

76

maxFPS: number; // Maximum FPS (throttles updates)

77

78

// Listener Management

79

add<T>(fn: TickerCallback<T>, context?: T, priority?: number): this;

80

addOnce<T>(fn: TickerCallback<T>, context?: T, priority?: number): this;

81

remove<T>(fn: TickerCallback<T>, context?: T): this;

82

83

// Lifecycle

84

start(): void; // Start the ticker

85

stop(): void; // Stop the ticker

86

destroy(): void; // Clean up resources

87

88

// Manual Updates

89

update(currentTime?: number): void; // Manual frame update

90

}

91

92

type TickerCallback<T> = (this: T, deltaTime: number) => any;

93

94

class TickerListener<T = any> {

95

priority: number; // Execution priority

96

next: TickerListener; // Next listener in chain

97

previous: TickerListener; // Previous listener in chain

98

}

99

100

enum UPDATE_PRIORITY {

101

INTERACTION = 50, // Event system updates

102

HIGH = 25, // AnimatedSprite updates

103

NORMAL = 0, // Default priority

104

LOW = -25, // Application rendering

105

UTILITY = -50 // Background utilities

106

}

107

```

108

109

## Event System

110

111

### FederatedEvent Base { .api }

112

113

Core event class that provides DOM-compatible event handling with bubbling and propagation.

114

115

```typescript

116

class FederatedEvent<N extends UIEvent | PixiTouch = UIEvent | PixiTouch> implements UIEvent {

117

// Event Properties

118

type: string; // Event type (e.g., 'mousedown')

119

target: FederatedEventTarget; // Event target

120

currentTarget: FederatedEventTarget; // Current event target in propagation

121

timeStamp: number; // Event timestamp

122

bubbles: boolean; // Whether event bubbles

123

cancelable: boolean; // Whether event can be cancelled

124

defaultPrevented: boolean; // Whether preventDefault was called

125

126

// Event Phase

127

eventPhase: number; // Current propagation phase

128

readonly NONE: 0;

129

readonly CAPTURING_PHASE: 1;

130

readonly AT_TARGET: 2;

131

readonly BUBBLING_PHASE: 3;

132

133

// Propagation Control

134

propagationStopped: boolean;

135

propagationImmediatelyStopped: boolean;

136

137

// Native Event Reference

138

nativeEvent: N; // Original native event

139

originalEvent: FederatedEvent<N>; // Original federated event

140

141

// DOM Coordinates

142

layer: Point; // Layer-relative coordinates

143

page: Point; // Page-relative coordinates

144

readonly layerX: number;

145

readonly layerY: number;

146

readonly pageX: number;

147

readonly pageY: number;

148

149

// Event Management

150

manager: EventBoundary; // Event boundary manager

151

path: FederatedEventTarget[]; // Propagation path

152

153

// Methods

154

preventDefault(): void; // Prevent default behavior

155

stopPropagation(): void; // Stop propagation to next target

156

stopImmediatePropagation(): void; // Stop all further propagation

157

composedPath(): FederatedEventTarget[]; // Get propagation path

158

}

159

```

160

161

### Mouse and Pointer Events { .api }

162

163

Extended event classes for mouse and pointer interactions.

164

165

```typescript

166

class FederatedMouseEvent extends FederatedEvent<MouseEvent | PointerEvent | PixiTouch>

167

implements MouseEvent {

168

169

// Mouse State

170

button: number; // Pressed button (0=left, 1=middle, 2=right)

171

buttons: number; // Currently pressed buttons bitmask

172

173

// Modifier Keys

174

altKey: boolean; // Alt key pressed

175

ctrlKey: boolean; // Ctrl key pressed

176

metaKey: boolean; // Meta key pressed

177

shiftKey: boolean; // Shift key pressed

178

179

// Coordinates

180

client: Point; // Client coordinates

181

readonly clientX: number;

182

readonly clientY: number;

183

readonly x: number; // Alias for clientX

184

readonly y: number; // Alias for clientY

185

186

movement: Point; // Movement delta

187

readonly movementX: number;

188

readonly movementY: number;

189

190

offset: Point; // Target-relative coordinates

191

readonly offsetX: number;

192

readonly offsetY: number;

193

194

global: Point; // World coordinates

195

readonly globalX: number;

196

readonly globalY: number;

197

198

screen: Point; // Screen coordinates

199

readonly screenX: number;

200

readonly screenY: number;

201

202

detail: number; // Click count

203

204

// Utility Methods

205

getLocalPosition<P extends IPointData>(

206

displayObject: DisplayObject,

207

point?: P,

208

globalPos?: IPointData

209

): P;

210

211

getModifierState(key: string): boolean;

212

}

213

214

class FederatedPointerEvent extends FederatedMouseEvent implements PointerEvent {

215

// Pointer Properties

216

pointerId: number; // Unique pointer identifier

217

pointerType: string; // 'mouse', 'pen', 'touch'

218

isPrimary: boolean; // Whether primary pointer

219

220

// Touch/Pen Properties

221

width: number; // Contact width

222

height: number; // Contact height

223

pressure: number; // Applied pressure

224

tangentialPressure: number; // Barrel pressure (stylus)

225

tiltX: number; // X-axis tilt angle

226

tiltY: number; // Y-axis tilt angle

227

twist: number; // Rotation angle

228

altitudeAngle: number; // Altitude angle

229

azimuthAngle: number; // Azimuth angle

230

231

// Coalesced Events

232

getCoalescedEvents(): PointerEvent[];

233

getPredictedEvents(): PointerEvent[]; // Not supported

234

}

235

236

class FederatedWheelEvent extends FederatedMouseEvent implements WheelEvent {

237

deltaMode: number; // Delta measurement units

238

deltaX: number; // Horizontal scroll delta

239

deltaY: number; // Vertical scroll delta

240

deltaZ: number; // Z-axis scroll delta

241

}

242

```

243

244

### Event Target Interface { .api }

245

246

Interface defining interactive display object capabilities.

247

248

```typescript

249

interface FederatedEventTarget extends utils.EventEmitter, EventTarget {

250

// Interactive Properties

251

cursor: Cursor | string; // Preferred cursor style

252

interactive: boolean; // Enable interaction events

253

eventMode: EventMode; // Interaction mode

254

interactiveChildren: boolean; // Children can be interactive

255

hitArea: IHitArea | null; // Custom hit testing area

256

257

// Hierarchy

258

readonly parent?: FederatedEventTarget;

259

readonly children?: ReadonlyArray<FederatedEventTarget>;

260

261

// Methods

262

isInteractive(): boolean; // Check if interactive

263

264

// Event Handlers (Property-based)

265

onclick: FederatedEventHandler | null;

266

onmousedown: FederatedEventHandler | null;

267

onmouseenter: FederatedEventHandler | null;

268

onmouseleave: FederatedEventHandler | null;

269

onmousemove: FederatedEventHandler | null;

270

onglobalmousemove: FederatedEventHandler | null;

271

onmouseout: FederatedEventHandler | null;

272

onmouseover: FederatedEventHandler | null;

273

onmouseup: FederatedEventHandler | null;

274

onmouseupoutside: FederatedEventHandler | null;

275

276

onpointercancel: FederatedEventHandler | null;

277

onpointerdown: FederatedEventHandler | null;

278

onpointerenter: FederatedEventHandler | null;

279

onpointerleave: FederatedEventHandler | null;

280

onpointermove: FederatedEventHandler | null;

281

onglobalpointermove: FederatedEventHandler | null;

282

onpointerout: FederatedEventHandler | null;

283

onpointerover: FederatedEventHandler | null;

284

onpointertap: FederatedEventHandler | null;

285

onpointerup: FederatedEventHandler | null;

286

onpointerupoutside: FederatedEventHandler | null;

287

288

onrightclick: FederatedEventHandler | null;

289

onrightdown: FederatedEventHandler | null;

290

onrightup: FederatedEventHandler | null;

291

onrightupoutside: FederatedEventHandler | null;

292

293

ontap: FederatedEventHandler | null;

294

ontouchcancel: FederatedEventHandler | null;

295

ontouchend: FederatedEventHandler | null;

296

ontouchendoutside: FederatedEventHandler | null;

297

ontouchmove: FederatedEventHandler | null;

298

onglobaltouchmove: FederatedEventHandler | null;

299

ontouchstart: FederatedEventHandler | null;

300

301

onwheel: FederatedEventHandler<FederatedWheelEvent> | null;

302

303

// DOM-compatible Methods

304

addEventListener(type: string, listener: EventListenerOrEventListenerObject,

305

options?: AddListenerOptions): void;

306

removeEventListener(type: string, listener: EventListenerOrEventListenerObject,

307

options?: RemoveListenerOptions): void;

308

dispatchEvent(event: Event): boolean;

309

}

310

311

type EventMode = 'none' | 'passive' | 'auto' | 'static' | 'dynamic';

312

type FederatedEventHandler<T = FederatedPointerEvent> = (event: T) => void;

313

type Cursor = 'auto' | 'default' | 'none' | 'pointer' | 'grab' | 'grabbing' | /* ... */;

314

315

interface IHitArea {

316

contains(x: number, y: number): boolean;

317

}

318

```

319

320

### EventBoundary { .api }

321

322

Event management system that handles hit testing, event mapping, and propagation.

323

324

```typescript

325

class EventBoundary {

326

// Core Properties

327

rootTarget: DisplayObject; // Root event target

328

dispatch: utils.EventEmitter; // Global event emitter

329

cursor: Cursor | string; // Current cursor style

330

331

// Configuration

332

moveOnAll: boolean; // Emit move events on all objects

333

enableGlobalMoveEvents: boolean; // Enable global move events

334

335

constructor(rootTarget?: DisplayObject);

336

337

// Event Mapping

338

addEventMapping(type: string, fn: (e: FederatedEvent) => void): void;

339

mapEvent(e: FederatedEvent): void;

340

dispatchEvent(e: FederatedEvent, type?: string): void;

341

342

// Hit Testing

343

hitTest(x: number, y: number): DisplayObject;

344

345

// Event Propagation

346

propagate(e: FederatedEvent, type?: string): void;

347

propagationPath(target: FederatedEventTarget): FederatedEventTarget[];

348

all(e: FederatedEvent, type?: string | string[],

349

targets?: FederatedEventTarget[]): void;

350

351

// Event Creation

352

protected createPointerEvent(from: FederatedPointerEvent,

353

type?: string,

354

target?: FederatedEventTarget): FederatedPointerEvent;

355

protected createWheelEvent(from: FederatedWheelEvent): FederatedWheelEvent;

356

protected clonePointerEvent(from: FederatedPointerEvent,

357

type?: string): FederatedPointerEvent;

358

359

// Event Pool Management

360

protected allocateEvent<T extends FederatedEvent>(

361

constructor: { new(boundary: EventBoundary): T }

362

): T;

363

protected freeEvent<T extends FederatedEvent>(event: T): void;

364

}

365

```

366

367

## Type Definitions

368

369

### Animation Types

370

371

```typescript

372

// Animation frame with duration

373

interface FrameObject {

374

texture: Texture; // Frame texture

375

time: number; // Duration in milliseconds

376

}

377

378

// Ticker callback signature

379

type TickerCallback<T> = (this: T, deltaTime: number) => any;

380

381

// Update priority levels

382

enum UPDATE_PRIORITY {

383

INTERACTION = 50, // Event system priority

384

HIGH = 25, // Animation priority

385

NORMAL = 0, // Default priority

386

LOW = -25, // Rendering priority

387

UTILITY = -50 // Background tasks

388

}

389

```

390

391

### Event Types

392

393

```typescript

394

// Event modes for display objects

395

type EventMode = 'none' // No events

396

| 'passive' // Hit tested but no events

397

| 'auto' // Hit tested if parent interactive

398

| 'static' // Full interactivity

399

| 'dynamic'; // Interactive + mock events

400

401

// Event handler function

402

type FederatedEventHandler<T = FederatedPointerEvent> = (event: T) => void;

403

404

// Cursor styles

405

type Cursor = 'auto' | 'default' | 'none' | 'context-menu' | 'help'

406

| 'pointer' | 'progress' | 'wait' | 'cell' | 'crosshair'

407

| 'text' | 'vertical-text' | 'alias' | 'copy' | 'move'

408

| 'no-drop' | 'not-allowed' | 'e-resize' | 'n-resize'

409

| 'ne-resize' | 'nw-resize' | 's-resize' | 'se-resize'

410

| 'sw-resize' | 'w-resize' | 'ns-resize' | 'ew-resize'

411

| 'nesw-resize' | 'col-resize' | 'nwse-resize' | 'row-resize'

412

| 'all-scroll' | 'zoom-in' | 'zoom-out' | 'grab' | 'grabbing';

413

414

// Hit area interface

415

interface IHitArea {

416

contains(x: number, y: number): boolean;

417

}

418

419

// Touch event extension

420

interface PixiTouch extends Touch {

421

button: number;

422

buttons: number;

423

isPrimary: boolean;

424

width: number;

425

height: number;

426

tiltX: number;

427

tiltY: number;

428

pointerType: string;

429

pointerId: number;

430

pressure: number;

431

twist: number;

432

tangentialPressure: number;

433

layerX: number;

434

layerY: number;

435

offsetX: number;

436

offsetY: number;

437

isNormalized: boolean;

438

}

439

```

440

441

## Usage Examples

442

443

### Frame-Based Animation

444

445

```typescript

446

import { AnimatedSprite, Assets, Application } from 'pixi.js';

447

448

// Create application

449

const app = new Application();

450

document.body.appendChild(app.view);

451

452

// Load spritesheet with animation data

453

const sheet = await Assets.load('assets/character.json');

454

const walkAnimation = new AnimatedSprite(sheet.animations['walk']);

455

456

// Configure animation

457

walkAnimation.animationSpeed = 0.167; // 10 FPS at 60 FPS

458

walkAnimation.loop = true;

459

walkAnimation.anchor.set(0.5);

460

walkAnimation.position.set(400, 300);

461

462

// Add event handlers

463

walkAnimation.onComplete = () => {

464

console.log('Animation completed!');

465

};

466

467

walkAnimation.onFrameChange = (currentFrame) => {

468

console.log(`Frame changed to: ${currentFrame}`);

469

};

470

471

walkAnimation.onLoop = () => {

472

console.log('Animation looped!');

473

};

474

475

// Add to stage and play

476

app.stage.addChild(walkAnimation);

477

walkAnimation.play();

478

479

// Manual animation from textures

480

const textures = [

481

Assets.get('frame1.png'),

482

Assets.get('frame2.png'),

483

Assets.get('frame3.png')

484

];

485

486

const manualAnimation = new AnimatedSprite(textures);

487

manualAnimation.animationSpeed = 0.5;

488

489

// Animation with custom frame durations

490

const timedFrames = [

491

{ texture: Assets.get('idle.png'), time: 1000 }, // 1 second

492

{ texture: Assets.get('blink.png'), time: 100 }, // 0.1 seconds

493

{ texture: Assets.get('idle.png'), time: 2000 } // 2 seconds

494

];

495

496

const timedAnimation = new AnimatedSprite(timedFrames);

497

```

498

499

### Custom Animation with Ticker

500

501

```typescript

502

import { Ticker, Sprite, Assets } from 'pixi.js';

503

504

class CustomAnimator {

505

private sprites: Sprite[] = [];

506

private time: number = 0;

507

508

constructor() {

509

// Add to shared ticker with high priority

510

Ticker.shared.add(this.update, this, UPDATE_PRIORITY.HIGH);

511

}

512

513

private update = (deltaTime: number): void => {

514

this.time += deltaTime;

515

516

// Update all sprites

517

this.sprites.forEach((sprite, index) => {

518

// Floating animation

519

sprite.y += Math.sin(this.time * 0.1 + index) * 0.5;

520

521

// Rotation animation

522

sprite.rotation += deltaTime * 0.02;

523

524

// Scale pulsing

525

const scale = 1 + Math.sin(this.time * 0.15 + index) * 0.1;

526

sprite.scale.set(scale);

527

});

528

};

529

530

addSprite(sprite: Sprite): void {

531

this.sprites.push(sprite);

532

}

533

534

destroy(): void {

535

Ticker.shared.remove(this.update, this);

536

}

537

}

538

539

// Usage

540

const animator = new CustomAnimator();

541

const sprite = new Sprite(Assets.get('star.png'));

542

animator.addSprite(sprite);

543

544

// Create custom ticker for specific timing

545

const customTicker = new Ticker();

546

customTicker.maxFPS = 30; // Limit to 30 FPS

547

customTicker.add((deltaTime) => {

548

// Custom update logic at 30 FPS

549

console.log(`Update at ${customTicker.FPS} FPS`);

550

});

551

customTicker.start();

552

```

553

554

### Mouse and Touch Interaction

555

556

```typescript

557

import { Sprite, Assets, FederatedPointerEvent } from 'pixi.js';

558

559

const interactiveSprite = new Sprite(Assets.get('button.png'));

560

interactiveSprite.anchor.set(0.5);

561

interactiveSprite.position.set(400, 300);

562

563

// Enable interactivity

564

interactiveSprite.eventMode = 'static';

565

interactiveSprite.cursor = 'pointer';

566

567

// Property-based event handlers

568

interactiveSprite.onpointerdown = (event: FederatedPointerEvent) => {

569

console.log('Pointer down:', event.pointerId, event.pointerType);

570

interactiveSprite.tint = 0x888888; // Darken on press

571

};

572

573

interactiveSprite.onpointerup = (event: FederatedPointerEvent) => {

574

console.log('Pointer up:', event.pointerId);

575

interactiveSprite.tint = 0xFFFFFF; // Restore color

576

};

577

578

interactiveSprite.onpointermove = (event: FederatedPointerEvent) => {

579

// Get local coordinates

580

const localPos = event.getLocalPosition(interactiveSprite);

581

console.log('Local position:', localPos.x, localPos.y);

582

583

// Check modifier keys

584

if (event.shiftKey) {

585

console.log('Shift key held while moving');

586

}

587

};

588

589

// EventListener-style handlers

590

interactiveSprite.addEventListener('click', (event: FederatedPointerEvent) => {

591

console.log(`Clicked ${event.detail} times`); // Click count

592

593

// Handle multi-touch

594

if (event.pointerType === 'touch') {

595

console.log('Touch interaction');

596

}

597

});

598

599

// Drag functionality

600

let isDragging = false;

601

let dragOffset = { x: 0, y: 0 };

602

603

interactiveSprite.addEventListener('pointerdown', (event: FederatedPointerEvent) => {

604

isDragging = true;

605

const localPos = event.getLocalPosition(interactiveSprite.parent);

606

dragOffset.x = localPos.x - interactiveSprite.x;

607

dragOffset.y = localPos.y - interactiveSprite.y;

608

609

// Capture pointer for drag-outside behavior

610

interactiveSprite.setPointerCapture?.(event.pointerId);

611

});

612

613

interactiveSprite.addEventListener('globalpointermove', (event: FederatedPointerEvent) => {

614

if (isDragging) {

615

const globalPos = event.global;

616

interactiveSprite.x = globalPos.x - dragOffset.x;

617

interactiveSprite.y = globalPos.y - dragOffset.y;

618

}

619

});

620

621

interactiveSprite.addEventListener('pointerup', () => {

622

isDragging = false;

623

});

624

625

interactiveSprite.addEventListener('pointerupoutside', () => {

626

isDragging = false;

627

});

628

629

app.stage.addChild(interactiveSprite);

630

```

631

632

### Event Propagation and Bubbling

633

634

```typescript

635

import { Container, Graphics, FederatedPointerEvent } from 'pixi.js';

636

637

// Create nested container structure

638

const outerContainer = new Container();

639

const middleContainer = new Container();

640

const innerSprite = new Graphics()

641

.beginFill(0xFF0000)

642

.drawCircle(0, 0, 50)

643

.endFill();

644

645

// Set up hierarchy

646

outerContainer.addChild(middleContainer);

647

middleContainer.addChild(innerSprite);

648

app.stage.addChild(outerContainer);

649

650

// Position containers

651

outerContainer.position.set(200, 200);

652

middleContainer.position.set(100, 100);

653

654

// Enable interactivity

655

outerContainer.eventMode = 'static';

656

middleContainer.eventMode = 'static';

657

innerSprite.eventMode = 'static';

658

659

// Event capturing (fires before target)

660

outerContainer.addEventListener('click', (event: FederatedPointerEvent) => {

661

console.log('Outer container capturing phase');

662

}, { capture: true });

663

664

// Event bubbling (fires after target)

665

outerContainer.addEventListener('click', (event: FederatedPointerEvent) => {

666

console.log('Outer container bubbling phase');

667

console.log('Event phase:', event.eventPhase);

668

});

669

670

middleContainer.addEventListener('click', (event: FederatedPointerEvent) => {

671

console.log('Middle container clicked');

672

673

// Stop propagation to parent

674

if (event.shiftKey) {

675

event.stopPropagation();

676

console.log('Propagation stopped');

677

}

678

});

679

680

innerSprite.addEventListener('click', (event: FederatedPointerEvent) => {

681

console.log('Inner sprite clicked (target)');

682

console.log('Composed path:', event.composedPath().map(t => t.constructor.name));

683

684

// Prevent default and stop immediate propagation

685

if (event.ctrlKey) {

686

event.stopImmediatePropagation();

687

console.log('Immediate propagation stopped');

688

}

689

});

690

```

691

692

### Advanced Event Handling

693

694

```typescript

695

import { EventBoundary, FederatedPointerEvent, Graphics } from 'pixi.js';

696

697

// Custom hit area

698

const customButton = new Graphics()

699

.beginFill(0x00FF00)

700

.drawRect(0, 0, 100, 50)

701

.endFill();

702

703

// Define circular hit area larger than visual

704

customButton.hitArea = new Circle(50, 25, 40);

705

customButton.eventMode = 'static';

706

707

// Multi-pointer tracking

708

const activePointers = new Map<number, FederatedPointerEvent>();

709

710

customButton.addEventListener('pointerdown', (event: FederatedPointerEvent) => {

711

activePointers.set(event.pointerId, event);

712

console.log(`Active pointers: ${activePointers.size}`);

713

});

714

715

customButton.addEventListener('pointerup', (event: FederatedPointerEvent) => {

716

activePointers.delete(event.pointerId);

717

});

718

719

customButton.addEventListener('pointercancel', (event: FederatedPointerEvent) => {

720

activePointers.delete(event.pointerId);

721

});

722

723

// Gesture recognition example

724

let lastTapTime = 0;

725

let tapCount = 0;

726

727

customButton.addEventListener('tap', (event: FederatedPointerEvent) => {

728

const now = Date.now();

729

730

if (now - lastTapTime < 300) { // Double tap threshold

731

tapCount++;

732

} else {

733

tapCount = 1;

734

}

735

736

lastTapTime = now;

737

738

if (tapCount === 2) {

739

console.log('Double tap detected!');

740

tapCount = 0;

741

}

742

});

743

744

// Wheel event handling

745

customButton.addEventListener('wheel', (event: FederatedWheelEvent) => {

746

console.log('Wheel delta:', event.deltaY);

747

748

// Zoom based on wheel

749

const zoomFactor = event.deltaY > 0 ? 0.9 : 1.1;

750

customButton.scale.x *= zoomFactor;

751

customButton.scale.y *= zoomFactor;

752

753

// Prevent browser scrolling

754

event.preventDefault();

755

});

756

757

app.stage.addChild(customButton);

758

```

759

760

### Animation Timing and Control

761

762

```typescript

763

import { AnimatedSprite, Ticker, Assets } from 'pixi.js';

764

765

class AnimationController {

766

private animations: Map<string, AnimatedSprite> = new Map();

767

private globalSpeed: number = 1;

768

769

async loadAnimations() {

770

const sheet = await Assets.load('characters.json');

771

772

// Create different character animations

773

const walkAnim = new AnimatedSprite(sheet.animations['walk']);

774

const runAnim = new AnimatedSprite(sheet.animations['run']);

775

const idleAnim = new AnimatedSprite(sheet.animations['idle']);

776

777

// Configure each animation

778

walkAnim.animationSpeed = 0.167; // 10 FPS

779

runAnim.animationSpeed = 0.333; // 20 FPS

780

idleAnim.animationSpeed = 0.083; // 5 FPS

781

782

this.animations.set('walk', walkAnim);

783

this.animations.set('run', runAnim);

784

this.animations.set('idle', idleAnim);

785

}

786

787

playAnimation(name: string): void {

788

// Stop all animations

789

this.animations.forEach(anim => anim.stop());

790

791

// Play requested animation

792

const anim = this.animations.get(name);

793

if (anim) {

794

anim.gotoAndPlay(0);

795

}

796

}

797

798

setGlobalSpeed(speed: number): void {

799

this.globalSpeed = speed;

800

this.animations.forEach(anim => {

801

const baseSpeed = anim.animationSpeed / this.globalSpeed;

802

anim.animationSpeed = baseSpeed * speed;

803

});

804

}

805

806

// Custom frame interpolation

807

private frameInterpolation(anim: AnimatedSprite, targetFrame: number, duration: number): void {

808

const startFrame = anim.currentFrame;

809

const frameDistance = targetFrame - startFrame;

810

let elapsed = 0;

811

812

const updateLerp = (delta: number) => {

813

elapsed += delta;

814

const progress = Math.min(elapsed / duration, 1);

815

816

// Smooth interpolation

817

const smoothProgress = progress * progress * (3 - 2 * progress);

818

const currentFrame = startFrame + frameDistance * smoothProgress;

819

820

anim.currentFrame = Math.floor(currentFrame);

821

822

if (progress >= 1) {

823

Ticker.shared.remove(updateLerp);

824

}

825

};

826

827

Ticker.shared.add(updateLerp);

828

}

829

830

// Seamless animation transitions

831

transitionTo(fromName: string, toName: string, blendDuration: number = 0.5): void {

832

const fromAnim = this.animations.get(fromName);

833

const toAnim = this.animations.get(toName);

834

835

if (!fromAnim || !toAnim) return;

836

837

// Start blend

838

let blendProgress = 0;

839

const blendSpeed = 1 / (blendDuration * 60); // Assuming 60 FPS

840

841

const blendUpdate = (delta: number) => {

842

blendProgress += blendSpeed * delta;

843

844

// Cross-fade alpha values

845

fromAnim.alpha = 1 - blendProgress;

846

toAnim.alpha = blendProgress;

847

848

if (blendProgress >= 1) {

849

fromAnim.stop();

850

fromAnim.alpha = 1;

851

toAnim.alpha = 1;

852

Ticker.shared.remove(blendUpdate);

853

}

854

};

855

856

// Start target animation and blend

857

toAnim.gotoAndPlay(0);

858

toAnim.alpha = 0;

859

Ticker.shared.add(blendUpdate);

860

}

861

}

862

863

// Usage

864

const controller = new AnimationController();

865

await controller.loadAnimations();

866

867

// Keyboard controls

868

document.addEventListener('keydown', (event) => {

869

switch (event.key) {

870

case 'ArrowRight':

871

controller.playAnimation('run');

872

break;

873

case 'ArrowDown':

874

controller.playAnimation('walk');

875

break;

876

case ' ':

877

controller.playAnimation('idle');

878

break;

879

case '+':

880

controller.setGlobalSpeed(2);

881

break;

882

case '-':

883

controller.setGlobalSpeed(0.5);

884

break;

885

}

886

});

887

```

888

889

## Best Practices

890

891

### Performance Optimization

892

893

1. **Efficient Event Handling**: Use event delegation and avoid creating excessive listeners

894

2. **Ticker Management**: Remove unused ticker listeners and use appropriate priorities

895

3. **Animation Pooling**: Reuse AnimatedSprite instances for similar animations

896

4. **Hit Area Optimization**: Use simple geometric hit areas instead of pixel-perfect detection

897

898

### Memory Management

899

900

1. **Resource Cleanup**: Always call `destroy()` on unused animations and tickers

901

2. **Event Listener Removal**: Remove event listeners when objects are no longer needed

902

3. **Texture Sharing**: Share textures between multiple AnimatedSprite instances

903

4. **Pool Event Objects**: Use EventBoundary's event pooling for performance

904

905

### User Experience

906

907

1. **Responsive Feedback**: Provide immediate visual feedback for interactions

908

2. **Smooth Animations**: Use appropriate frame rates and easing for natural motion

909

3. **Accessibility**: Support keyboard navigation and screen readers

910

4. **Cross-Platform Compatibility**: Test touch interactions on mobile devices

911

912

This comprehensive system provides powerful animation and interaction capabilities that form the foundation for engaging, responsive applications with smooth animations and intuitive user interfaces.