Skip to content
AI & Agents
Skill

/pixijs-performance

Use this skill when profiling or optimizing a PixiJS v8 app for FPS, draw calls, or GPU memory. Covers destroy patterns (cacheAsTexture(false), releaseGlobalResources), GCSystem and TextureGCSystem, PrepareSystem, object pooling, batching rules, BitmapText for dynamic text,

From plugin
pixijs-skills
30226 skills
Install
$ npx -y skills add pixijs/pixijs-skills --skill pixijs-performance --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/pixijs-performance

Context preview

The summary Claude sees to decide when to auto-load this skill.

Use this skill when profiling or optimizing a PixiJS v8 app for FPS, draw calls, or GPU memory. Covers destroy patterns (cacheAsTexture(false), releaseGlobalResources), GCSystem and TextureGCSystem, PrepareSystem, object pooling, batching rules, BitmapText for dynamic text,

SKILL.md

pixijs-performance.SKILL.md
name: pixijs-performance
description: "Use this skill when profiling or optimizing a PixiJS v8 app for FPS, draw calls, or GPU memory. Covers destroy patterns (cacheAsTexture(false), releaseGlobalResources), GCSystem and TextureGCSystem, PrepareSystem, object pooling, batching rules, BitmapText for dynamic text, culling (Culler, CullerPlugin, cullable, cullArea), resolution/antialias tradeoffs. Triggers on: FPS, jank, draw calls, batching, object pool, GCSystem, PrepareSystem, Culler, cacheAsTexture, memory leak, destroy patterns."
license: MIT

Profile before optimizing. PixiJS handles a lot of content well out of the box; browser DevTools Performance + GPU profiling should be your first move. Once you've found the bottleneck, apply the targeted pattern below (destroy, pool, batch, cache, or cull).

Quick Start

container.cacheAsTexture(true);
container.updateCacheTexture();
container.cacheAsTexture(false);
container.destroy({ children: true });

import { CullerPlugin, extensions } from "pixi.js";
extensions.add(CullerPlugin);

offscreenContainer.cullable = true;
offscreenContainer.cullArea = new Rectangle(0, 0, 256, 256);

// Tune GC via init options (ms). The `textureGC.*` properties are
// deprecated since 8.15.0 — use these on the Application init instead.
await app.init({ gcMaxUnusedTime: 60_000, gcFrequency: 30_000 });

**Related skills:** `pixijs-scene-container` (destroy options), `pixijs-scene-core-concepts` (render groups, layers, culling), `pixijs-scene-text` (BitmapText for dynamic content), `pixijs-assets` (atlasing), `pixijs-custom-rendering` (custom batchers).

Core Patterns

Proper destroy with cleanup

import { Sprite, Assets } from "pixi.js";

const texture = await Assets.load("character.png");
const sprite = new Sprite(texture);

// Destroy sprite only (preserve texture for reuse)
sprite.destroy();

// Destroy sprite AND its texture
sprite.destroy({ children: true, texture: true, textureSource: true });

When done with a loaded asset entirely:

Assets.unload("character.png");

This removes it from the cache and unloads the GPU resource.

Application destroy/recreate cycle

import { Application } from "pixi.js";

// Correct destroy that cleans global pools
app.destroy({ releaseGlobalResources: true });

const newApp = new Application();
await newApp.init({ width: 800, height: 600 });

Without `releaseGlobalResources: true`, pooled objects (batches, textures) from the old app leak into the new one, causing flickering and corruption.

Texture garbage collection

PixiJS auto-collects unused textures and GPU resources via `GCSystem`. Defaults: checks every 30 seconds, removes resources idle for 60 seconds. These are time-based (milliseconds).

import { Application } from "pixi.js";

const app = new Application();

await app.init({
  gcActive: true,
  gcMaxUnusedTime: 120000, // idle time before cleanup in ms (default: 60000)
  gcFrequency: 60000, // check interval in ms (default: 30000)
});

For manual control:

texture.source.unload(); // immediate GPU memory release

PrepareSystem for GPU upload

Upload textures and graphics to GPU before rendering to avoid first-frame hitches:

import "pixi.js/prepare";
import { Application, Assets } from "pixi.js";

const app = new Application();
await app.init();

// Don't render until assets are uploaded
app.stop();

const texture = await Assets.load("large-scene.png");

// Upload to GPU ahead of time
await app.renderer.prepare.upload(app.stage);

// Now rendering won't hitch on first frame
app.start();

`prepare.upload()` accepts a Container (uploads all textures, text, and graphics in the subtree) or individual resources.

cacheAsTexture for performance

`cacheAsTexture()` renders a container's subtree to a single texture, reducing draw calls for complex static content. Internally it creates a render group and caches the result.

**When to use:**

  • Many static children (UI panels, decorative backgrounds, complex Graphics)
  • Containers with expensive filters (cache the filter result)
  • Large subtrees that rarely change

**Tradeoffs:**

  • Uses GPU memory for the cached texture (larger containers = more memory)
  • Max texture size is GPU-dependent (typically 4096x4096; check `renderer.texture.maxTextureSize`)
  • Must call `updateCacheTexture()` after modifying children
  • Combining with masks is fragile (see the masking skill)
import { Container, Sprite } from "pixi.js";

const panel = new Container();
// ... add many static children ...

panel.cacheAsTexture(true);

// With options
panel.cacheAsTexture({ resolution: 2, antialias: true });

// Refresh after changes
panel.updateCacheTexture();

// MUST disable before destroying (see Common Mistakes below)
panel.cacheAsTexture(false);
panel.destroy();

**Avoid:** toggling on/off repeatedly (constant re-caching negates benefits), caching sparse containers (negligible gain), caching containers larger than 4096x4096.

Object recycling

Reuse objects by changing their properties instead of destroy/recreate:

import { Sprite, Container, Texture } from "pixi.js";

class BulletPool {
  private _pool: Sprite[] = [];
  private _container: Container;

  constructor(container: Container) {
    this._container = container;
  }

  public get(texture: Texture): Sprite {
    let bullet = this._pool.pop();

    if (!bullet) {
      bullet = new Sprite(texture);
      this._container.addChild(bullet);
    }

    bullet.texture = texture;
    bullet.position.set(0, 0);
    bullet.rotation = 0;
    bullet.scale.set(1);
    bullet.alpha = 1;
    bullet.tint = 0xffffff;
    bullet.blendMode = "normal";
    bullet.visible = true;
    return bullet;
  }

  public release(bullet: Sprite): void {
    bullet.visible = false;
    this._pool.push(bullet);
  }
}

Destroying and recreating is significantly more expensive than toggling `visible` and updating properties. GPU resources stay all

Read more
Ships withpixijs-skills

Official AI skills for PixiJS. These skills teach AI coding agents how to correctly use PixiJS

Get the whole plugin

Other skills on pixijs-skills.