Skip to content

PixiJS Performance — Optimizing 2D Rendering

DodaTech Updated 2026-06-28 3 min read

In this tutorial, you will learn about PixiJS Performance. We cover key concepts, practical examples, and best practices to help you master this topic.

PixiJS performance optimization focuses on reducing draw calls, efficient texture management, memory pooling, and profiling to maintain 60fps.

What You'll Learn

By the end of this guide, you will reduce draw calls with sprite batching, use texture atlases to minimize texture swaps, cache complex graphics with render textures, use object pooling for particles, and profile with PixiJS debug tools.

Batch Sprites

// Use the same texture for all sprites to maximize batching
var texture = PIXI.Texture.from('tile.png');

for (var i = 0; i < 1000; i++) {
    var sprite = new PIXI.Sprite(texture);
    app.stage.addChild(sprite);
}
// All 1000 sprites render in 1-2 draw calls

Texture Atlas

PIXI.Assets.load('atlas.json').then(function() {
    var frame1 = PIXI.Texture.from('icon1.png');
    var frame2 = PIXI.Texture.from('icon2.png');
    // Using frames from a single atlas reduces texture swaps
});

Object Pooling

var bulletPool = [];

function getBullet() {
    return bulletPool.pop() || new Bullet();
}

function returnBullet(bullet) {
    bullet.visible = false;
    bulletPool.push(bullet);
}

Performance Profiling

// Display FPS
var fpsText = new PIXI.Text('FPS: 0', { fill: '#ffffff' });
app.stage.addChild(fpsText);

app.ticker.add(function() {
    fpsText.text = 'FPS: ' + Math.round(app.ticker.FPS) +
                   ' | Draw Calls: ' + app.renderer.geometry.drawCalls;
});

Common Mistakes

1. Using Many Different Textures

Each texture change breaks the batch. Use texture atlases to minimize switches.

2. Creating Graphics Each Frame

Creating new Graphics objects every frame causes Garbage Collection spikes. Pre-create and reuse.

3. Not Using Pooling

Creating and destroying objects frequently causes GC pauses. Use object pools.

4. Large Canvas Render Area

A 1920x1080 canvas with many sprites drops to 30fps on mobile. Use a smaller canvas or scale.

5. Ignoring Draw Calls

Target under 50 draw calls for smooth 60fps. Monitor with renderer debug stats.

Practice Questions

Q1: How do draw calls affect performance? A: Each draw call is a CPU-to-GPU round trip. Fewer calls = faster rendering.

Q2: What breaks sprite batching? A: Changing texture, blend mode, or shader between sprites.

Q3: How does a texture atlas help? A: All sprites share one texture, keeping them in the same batch.

Q4: What is object pooling? A: Reusing objects instead of creating/destroying them to avoid GC.

Q5: How do you measure FPS in PixiJS? A: Use app.ticker.FPS or monitor app.renderer.plugins.sprites.

Challenge: Build a particle system with 2000 particles using object pooling. Display draw call count and FPS. Compare performance with and without pooling.

FAQ

What is batch size limit?

WebGL typically batches up to 10922 sprites per draw call (based on MAX_TEXTURE_IMAGE_UNITS).

Does PixiJS support WebGL instancing?

Yes, via the Instance plugin for advanced batching.

How do I reduce memory usage?

Dispose unused textures, use lower resolution, limit texture cache.

What is the ideal sprite count for 60fps?

5000-10000 with batching. Beyond that, use particle system optimizations.

How do I detect performance bottlenecks?

Use Chrome DevTools Performance tab or PixiJS dev tools.

Try It Yourself

Monitor draw calls and FPS.

<!DOCTYPE html>
<html>
<head>
    <title>PixiJS Performance</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/7.3/pixi.min.js"></script>
</head>
<body style="font-family:sans-serif;padding:20px;">
<h2>Performance Monitor</h2>
<button onclick="addSprites(100)">Add 100</button>
<button onclick="clearSprites()">Clear</button>
<script>
var app = new PIXI.Application({ width: 500, height: 350, background: 0x1a1a2e });
document.body.appendChild(app.view);

var fpsText = new PIXI.Text('FPS: 0 | Draws: 0 | Sprites: 0', {
    fill: '#ffffff',
    fontSize: 14
});
fpsText.x = 10;
fpsText.y = 10;
app.stage.addChild(fpsText);

var spriteContainer = new PIXI.Container();
app.stage.addChild(spriteContainer);

// Create a reusable texture
var g = new PIXI.Graphics();
g.beginFill(0x4ecdc4);
g.drawCircle(0, 0, 8);
g.endFill();
var tex = app.renderer.generateTexture(g);

function addSprites(count) {
    for (var i = 0; i < count; i++) {
        var s = new PIXI.Sprite(tex);
        s.x = Math.random() * 480 + 10;
        s.y = Math.random() * 300 + 40;
        s.scale.set(0.5 + Math.random());
        s.tint = Math.random() * 0xffffff;
        spriteContainer.addChild(s);
    }
}

function clearSprites() {
    spriteContainer.removeChildren();
}

app.ticker.add(function() {
    var draws = app.renderer.drawCalls || app.renderer.geometry.drawCalls || 0;
    fpsText.text = 'FPS: ' + Math.round(app.ticker.FPS) +
                   ' | Draws: ' + draws +
                   ' | Sprites: ' + spriteContainer.children.length;
});
</script>
</body>
</html>

What's Next

Build a complete PixiJS project.

Project — Complete PixiJS project.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro