Pixijs Ticker

作者 pixijs83760c6f5346MIT346 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫7 天前更新

Use this skill when running per-frame logic or controlling the PixiJS v8 render loop. Covers Ticker.add/addOnce/remove, deltaTime vs deltaMS vs elapsedMS, UPDATE_PRIORITY ordering, maxFPS/minFPS capping, speed scaling, Ticker.shared vs new instances, per-object onRender hook, manual rendering. Triggers on: Ticker, UPDATE_PRIORITY, deltaTime, deltaMS, elapsedMS, onRender, app.ticker, maxFPS, minFPS, Ticker.shared.

AI 產生的概覽

說明 PixiJS v8 中如何透過 Ticker 控制渲染迴圈:回呼、時間增量、優先順序、影格率上限與手動渲染。

功能
說明如何在 PixiJS v8 的 Ticker 上註冊與移除逐格回呼,包括 add、addOnce、remove 以及情境綁定。介紹 deltaTime、deltaMS、elapsedMS 三個時間值、UPDATE_PRIORITY 順序、maxFPS 與 minFPS 限制、速度縮放、Ticker.shared 與新建實例、依物件設定的 onRender 鉤子,以及手動渲染。也列出常見錯誤,例如把 deltaTime 當成毫秒,或使用已被移除的 updateTransform。
適用情境
適用於在 PixiJS v8 應用程式中撰寫逐格邏輯或控制渲染迴圈的情境。遇到 Ticker 回呼、時間增量、更新優先順序、影格率限制或手動渲染相關問題時可參考。
執行需求
需要一個 PixiJS v8 專案;未包含指令碼或憑證,文件僅為說明內容。

app.ticker runs registered callbacks every frame and drives app.render() at UPDATE_PRIORITY.LOW. Each callback receives the Ticker instance; read deltaTime as a frame-rate-independent multiplier (≈1.0 at 60fps) or deltaMS for real-time calculations.

Quick Start

ts
app.ticker.add((ticker) => {  sprite.rotation += 0.01 * ticker.deltaTime;  sprite.x += (200 / 1000) * ticker.deltaMS;});
app.ticker.add(  (ticker) => {    updatePhysics(ticker.deltaMS);  },  undefined,  UPDATE_PRIORITY.HIGH,);
app.ticker.maxFPS = 30;app.ticker.speed = 0.5;
sprite.onRender = () => {  sprite.scale.x = Math.sin(performance.now() / 500);};

Related skills: pixijs-application (Application setup and sharedTicker option), pixijs-performance (frame rate optimization), pixijs-migration-v8 (v7 ticker signature changes).

Core Patterns

Time units

The Ticker exposes three timing values, each for different use cases:

PropertyTypeScaled by speed?Capped by minFPS?Use case
deltaTimedimensionless (~1.0 at 60fps)yesyesFrame-rate-independent animation multipliers
deltaMSmillisecondsyesyesTime-based calculations (pixels/sec)
elapsedMSmillisecondsnonoRaw measurement, profiling
ts
import { Application } from "pixi.js";
const app = new Application();await app.init({ width: 800, height: 600 });
app.ticker.add((ticker) => {  // deltaTime: dimensionless scalar, ~1.0 at 60fps  sprite.rotation += 0.1 * ticker.deltaTime;
  // deltaMS: real milliseconds (speed-scaled, capped)  sprite.x += (200 / 1000) * ticker.deltaMS; // 200 pixels per second
  // elapsedMS: raw milliseconds (no scaling, no cap)  console.log(`Raw frame time: ${ticker.elapsedMS}ms`);});

Tension note: deltaTime is not milliseconds. It is deltaMS * Ticker.targetFPMS where targetFPMS is 0.06 (i.e. 1/16.67). At exactly 60fps, deltaTime is 1.0. At 30fps, deltaTime is 2.0. This catches people who treat it as a time value.

Priority ordering and context binding

ts
import { Application, UPDATE_PRIORITY } from "pixi.js";
const app = new Application();await app.init({ width: 800, height: 600 });
// INTERACTION (50) > HIGH (25) > NORMAL (0) > LOW (-25) > UTILITY (-50)// app.render() is registered at LOW by the TickerPlugin
app.ticker.add(  (ticker) => {    // Physics runs before normal-priority callbacks    updatePhysics(ticker.deltaMS);  },  undefined,  UPDATE_PRIORITY.HIGH,);
app.ticker.add((ticker) => {  // Default priority (NORMAL = 0), runs after HIGH but before render  updateAnimations(ticker.deltaTime);});
// Pass `this` as the second argument to preserve context on class methodsclass GameSystem {  public speed = 5;  public position = 0;
  public update(ticker: Ticker): void {    this.position += this.speed * ticker.deltaTime;  }}
const system = new GameSystem();app.ticker.add(system.update, system);app.ticker.remove(system.update, system); // must match both fn and context

Frame rate capping

ts
import { Ticker } from "pixi.js";
const ticker = new Ticker();
ticker.maxFPS = 30; // Cap at 30fps (skips frames to maintain interval)ticker.minFPS = 10; // Cap deltaTime so it never exceeds 10fps worth
// If maxFPS < minFPS, minFPS is lowered to match// If minFPS > maxFPS, maxFPS is raised to match

maxFPS skips update calls to enforce a ceiling. minFPS caps deltaTime/deltaMS so large frame drops don't produce enormous deltas (default minFPS is 10).

Per-object onRender hook

ts
import { Sprite, Assets, Application } from "pixi.js";
const app = new Application();await app.init({ width: 800, height: 600 });
const texture = await Assets.load("bunny.png");const sprite = new Sprite(texture);app.stage.addChild(sprite);
sprite.onRender = (renderer) => {  sprite.rotation += 0.01;};

onRender is called during scene graph traversal, before GPU rendering. It is an alternative to a global ticker callback when logic is tied to a specific display object.

Ticker.shared, Ticker.system, and new Ticker

ts
import { Ticker, UPDATE_PRIORITY } from "pixi.js";
// Ticker.shared: singleton, autoStart=true, protected from destroy()const shared = Ticker.shared;
// Ticker.system: separate instance used by engine background tasks,// independent of the main scene ticker. It's a plain Ticker instance// (autoStart=true, _protected=true) with no intrinsic priority; listeners// are typically added at UTILITY priority by convention.const system = Ticker.system;
// new Ticker(): custom instance, autoStart=false, you manage the lifecycleconst custom = new Ticker();custom.autoStart = true; // start when first listener is addedcustom.add((ticker) => {  console.log(ticker.deltaMS);});
// One-shot callback that auto-removes after firingcustom.addOnce(() => console.log("fires once"), null, UPDATE_PRIORITY.NORMAL);
// When done:custom.stop();custom.destroy();

Application creates its own Ticker by default. Set sharedTicker: true in app.init() to use Ticker.shared instead. Ticker.shared and Ticker.system are both _protected and will not actually be destroyed if you call destroy() on them. Read ticker.FPS for the measured frame rate and ticker.count for the current listener count.

App lifecycle and manual rendering

ts
import { Application } from "pixi.js";
const app = new Application();await app.init({ autoStart: false });
// Pause and resume the built-in render loop at any time.app.start();app.stop();
// Or drive the loop yourself (headless, visibility-gated, fixed timestep, etc.)function animate() {  app.ticker.update(); // fires registered callbacks  app.render(); // renders the stage  requestAnimationFrame(animate);}animate();

app.start() and app.stop() are added by the TickerPlugin and map to ticker.start() / ticker.stop(). Use autoStart: false plus your own frame driver when you need to pause on tab blur, run a fixed-timestep loop, or render offscreen.

Speed scaling

ts
import { Application } from "pixi.js";
const app = new Application();await app.init({ width: 800, height: 600 });
app.ticker.speed = 0.5; // Half speed (slow motion)app.ticker.speed = 2.0; // Double speed
// speed affects deltaTime and deltaMS, but NOT elapsedMS

Common Mistakes

[CRITICAL] Ticker callback expects delta as first argument

Wrong:

ts
app.ticker.add((dt) => {  bunny.rotation += dt;});

Correct:

ts
app.ticker.add((ticker) => {  bunny.rotation += ticker.deltaTime;});

v8 passes the Ticker instance as the callback argument, not a delta number. The v7 pattern (dt) => ... compiles but dt is the entire Ticker object, so arithmetic on it produces NaN.

[HIGH] Using updateTransform for per-frame logic

Wrong:

ts
class MySprite extends Sprite {  updateTransform() {    super.updateTransform();    this.rotation += 0.01;  }}

Correct:

ts
class MySprite extends Sprite {  constructor() {    super();    this.onRender = this._onRender.bind(this);  }  private _onRender() {    this.rotation += 0.01;  }}

updateTransform was removed in v8. Use the onRender callback for per-object per-frame logic.

[MEDIUM] Treating deltaTime as milliseconds

Wrong:

ts
app.ticker.add((ticker) => {  // Tries to move 100px/sec but deltaTime is ~1.0, not ~16.67  sprite.x += (100 * ticker.deltaTime) / 1000;});

Correct:

ts
app.ticker.add((ticker) => {  // Using deltaMS for time-based movement  sprite.x += (100 / 1000) * ticker.deltaMS;  // Or using deltaTime as a frame-rate multiplier  sprite.x += 1.5 * ticker.deltaTime;});

deltaTime is a dimensionless scalar (~1.0 at 60fps), not milliseconds. Use deltaMS for real time calculations. Use deltaTime as a simple multiplier when you want "per frame at 60fps" behavior.

API Reference

來源與署名

來源:pixijs/pixijs-skills位於skills/pixijs-ticker提交83760c6

授權條款: MIT

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架