Render Loop
At the core of PixiJS lies its render loop, a repeating cycle that updates and redraws your scene every frame. Unlike traditional web development where rendering is event-based (e.g. on user input), PixiJS uses a continuous animation loop that provides full control over real-time rendering.
This guide provides a deep dive into how PixiJS structures this loop internally, from the moment a frame begins to when it is rendered to the screen. Understanding this will help you write more performant, well-structured applications.
Overview
Each frame, PixiJS performs the following sequence:
- Tickers are executed (user logic)
- Scene graph is updated (transforms and culling)
- Rendering occurs (GPU draw calls)
This cycle repeats as long as your application is running and its ticker is active.
Step 1: Running Ticker Callbacks
The render loop is driven by the Ticker
class, which uses requestAnimationFrame
to schedule work. Each tick:
- Measures elapsed time since the previous frame
- Caps it based on
minFPS
andmaxFPS
- Calls every listener registered with
ticker.add()
orapp.ticker.add()
Example
app.ticker.add((ticker) => {
bunny.rotation += ticker.deltaTime * 0.1;
});
Every callback receives the current Ticker
instance. You can access ticker.deltaTime
(scaled frame delta) and ticker.elapsedMS
(unscaled delta in ms) to time animations.
Step 2: Updating the Scene Graph
PixiJS uses a hierarchical scene graph to represent all visual objects. Before rendering, the graph needs to be traversed to:
- Recalculate transforms (world matrix updates)
- Apply custom logic via
onRender
handlers - Apply culling if enabled
Step 3: Rendering the Scene
Once the scene graph is ready, the renderer walks the display list starting at app.stage
:
- Applies global and local transformations
- Batches draw calls when possible
- Uploads geometry, textures, and uniforms
- Issues GPU commands
All rendering is retained mode: objects persist across frames unless explicitly removed.
Rendering is done via either WebGL or WebGPU, depending on your environment. The renderer abstracts away the differences behind a common API.
Full Frame Lifecycle Diagram
requestAnimationFrame
│
[Ticker._tick()]
│
├─ Compute elapsed time
├─ Call user listeners
│ └─ sprite.onRender
├─ Cull display objects (if enabled)
├─ Update world transforms
└─ Render stage
├─ Traverse display list
├─ Upload data to GPU
└─ Draw