pixi-js

star 6

PixiJS v8 — fast 2D WebGL/WebGPU rendering engine. Covers Application setup, scene graph, sprites, graphics, text, assets, filters, events, and the ticker system.

pradeepmouli By pradeepmouli schedule Updated 4/17/2026

name: pixi-js description: PixiJS v8 — fast 2D WebGL/WebGPU rendering engine. Covers Application setup, scene graph, sprites, graphics, text, assets, filters, events, and the ticker system.

PixiJS v8

PixiJS is a 2D rendering engine for the web. It renders to <canvas> using WebGL, WebGPU, or the Canvas 2D API. Version 8 is a single-package rewrite with async initialization, a new Graphics API, and first-class WebGPU support.

When to Use

@useWhen building any 2D browser experience that needs hardware-accelerated rendering: games, data visualizations, interactive tools, animated UIs, or creative coding experiments.

@avoidWhen building 3D scenes (use Three.js), static document layouts (use CSS/HTML), or server-side rendering.

Critical v8 Rules

  • NEVER pass options to the Application constructor -- v8 initialization is async. Always call await app.init(options).
  • NEVER access app.renderer before init() resolves -- it is undefined until the promise settles.
  • NEVER use the v7 Graphics API (beginFill, drawRect, endFill, lineStyle). v8 uses a chainable shape-then-fill API: .rect().fill().stroke().
  • NEVER import from @pixi/ sub-packages -- v8 is a single package. Always import { ... } from 'pixi.js'.
  • NEVER create Sprites from unloaded textures -- always await Assets.load() first or use Sprite.from() only for already-cached textures.
  • NEVER change Text content every frame -- it re-rasterizes to a canvas texture. Use BitmapText for dynamic scores/timers.
  • NEVER rebuild Graphics geometry every frame -- it rebuilds the mesh. Use cacheAsTexture() or generateTexture() for static shapes.
  • NEVER add a container to itself -- creates an infinite loop.
  • NEVER forget destroy() -- PixiJS objects hold GPU resources. Leaking them causes memory growth.

Package Structure

// All imports from the single package
import { Application, Sprite, Graphics, Text, Assets, Container, Ticker } from 'pixi.js';

// Optional sub-exports (not imported by default)
import 'pixi.js/advanced-blend-modes';
import 'pixi.js/unsafe-eval';
import 'pixi.js/prepare';
import 'pixi.js/math-extras';

When creating an Application with manageImports: false, you must manually import the extensions you need (see references/configuration.md).

Application Bootstrap

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

const app = new Application();

await app.init({
  width: 800,
  height: 600,
  backgroundColor: 0x1099bb,
  antialias: true,
  preference: 'webgl' // 'webgl' | 'webgpu' | 'canvas' or array
});

document.body.appendChild(app.canvas);

// Load assets BEFORE creating display objects
const texture = await Assets.load('bunny.png');
const sprite = new Sprite(texture);
sprite.anchor.set(0.5);
sprite.position.set(app.screen.width / 2, app.screen.height / 2);
app.stage.addChild(sprite);

// Animation loop via ticker (auto-started by default)
app.ticker.add((ticker) => {
  sprite.rotation += 0.1 * ticker.deltaTime;
});

Scene Graph

Everything visible descends from Container. The app.stage is the root.

Class @useWhen
Container Grouping children for shared transforms, visibility, masking, or filtering
Sprite Displaying loaded images or texture atlas frames -- fast batched rendering
Graphics Drawing shapes, lines, curves programmatically; creating masks
Text Canvas-rendered rich text (font families, drop shadows, stroke)
BitmapText High-performance text from pre-rendered bitmap fonts (scores, HUDs)
HTMLText HTML/CSS-rendered text with <b>, <i>, custom tag styles
TilingSprite Repeating/scrolling backgrounds
NineSliceSprite Scalable UI panels that preserve corner/edge detail
AnimatedSprite Frame-by-frame sprite animation from spritesheet
Mesh Custom geometry with vertex data and shaders
ParticleContainer Ultra-fast rendering of 100k+ lightweight particles
RenderLayer Controlling draw order independently of scene hierarchy
DOMContainer Embedding HTML DOM elements in the PixiJS scene graph

See references/core-classes.md for detailed API signatures and examples.

Assets

// Initialize with a manifest for production apps
await Assets.init({
  manifest: {
    bundles: [
      {
        name: 'game-screen',
        assets: [
          { alias: 'hero', src: 'hero.{webp,png}' },
          { alias: 'spritesheet', src: 'sprites.json' }
        ]
      }
    ]
  }
});

// Load a bundle with progress
await Assets.loadBundle('game-screen', (progress) => {
  console.log(`${Math.round(progress * 100)}%`);
});

// Retrieve cached assets
const heroTexture = Assets.get('hero');

// Background loading for next screen
Assets.backgroundLoadBundle('next-screen');

Key points:

  • Assets.load() returns a promise. The resolved value is the parsed asset (Texture, Spritesheet, JSON, etc.).
  • Use Assets.init({ basePath }) for CDN prefixes.
  • Format negotiation: 'hero.{avif,webp,png}' picks the best format the browser supports.
  • Spritesheets: loading a .json atlas auto-creates Texture objects for each frame.

Graphics (v8 API)

The v8 Graphics API is shape-first, then fill/stroke. This is the single biggest API change from v7.

const g = new Graphics();

// Rectangle with fill and stroke
g.rect(0, 0, 200, 100).fill({ color: 0xff0000, alpha: 0.8 }).stroke({ width: 2, color: 0x000000 });

// Circle
g.circle(150, 150, 50).fill('blue');

// Rounded rectangle
g.roundRect(10, 10, 200, 100, 15).fill(0x00ff00);

// Path drawing
g.moveTo(0, 0).lineTo(100, 0).lineTo(100, 100).closePath().fill({ color: 0xffff00, alpha: 0.5 });

// Holes via cut()
g.rect(0, 0, 200, 200).fill(0x00ff00).circle(100, 100, 40).cut();

// Gradient fill
const gradient = new FillGradient({
  end: { x: 1, y: 0 },
  colorStops: [
    { offset: 0, color: 0xff0000 },
    { offset: 1, color: 0x0000ff }
  ]
});
g.rect(0, 0, 200, 100).fill(gradient);

Share geometry efficiently with GraphicsContext:

const ctx = new GraphicsContext().rect(0, 0, 50, 50).fill(0xff0000);

const g1 = new Graphics(ctx); // shares GPU geometry
const g2 = new Graphics(ctx); // zero extra cost

Text

// Canvas text (rich styling, expensive to update)
const text = new Text({
  text: 'Hello PixiJS!',
  style: {
    fontFamily: 'Arial',
    fontSize: 36,
    fill: 0xff1010,
    stroke: { color: '#4a1850', width: 5 },
    dropShadow: { color: '#000000', blur: 4, distance: 6 },
    wordWrap: true,
    wordWrapWidth: 300
  }
});

// BitmapText (fast updates, ideal for HUDs)
const score = new BitmapText({
  text: 'Score: 0',
  style: { fontFamily: 'Arial', fontSize: 24, fill: 0xffffff }
});

// HTMLText (supports <b>, <i>, custom tags)
const html = new HTMLText({
  text: '<b>Bold</b> and <custom>styled</custom>',
  style: {
    fontSize: 24,
    fill: 0x000000,
    tagStyles: { custom: { fill: '#00ff00', fontStyle: 'italic' } }
  }
});

Ticker

// Use app.ticker for the main loop
app.ticker.add((ticker) => {
  // ticker.deltaTime: ~1.0 at 60fps (dimensionless, frame-rate independent)
  // ticker.deltaMS: milliseconds since last frame
  sprite.x += speed * ticker.deltaTime;
});

// One-time callback
app.ticker.addOnce(() => {
  /* runs next frame only */
});

// Priority control
app.ticker.add(physicsTick, undefined, UPDATE_PRIORITY.HIGH);

// Manual rendering (disable auto-start)
const app = new Application();
await app.init({ autoStart: false });
function loop() {
  app.render();
  requestAnimationFrame(loop);
}
loop();

Filters

Filters are post-processing effects applied to any Container.

import { BlurFilter, AlphaFilter, ColorMatrixFilter } from 'pixi.js';

sprite.filters = [new BlurFilter({ strength: 8 })];

// Multiple filters chain
container.filters = [new AlphaFilter({ alpha: 0.5 }), new ColorMatrixFilter()];

// Use as mask
const maskGraphics = new Graphics().circle(200, 200, 100).fill(0xffffff);
sprite.mask = maskGraphics;
// Or inverse mask
sprite.setMask({ mask: maskGraphics, inverse: true });

Events

PixiJS uses a DOM-like federated event model.

sprite.eventMode = 'static'; // enable interaction
sprite.cursor = 'pointer';

sprite.on('pointerdown', (e) => {
  console.log('clicked at', e.global.x, e.global.y);
});

sprite.on('pointerover', () => {
  sprite.tint = 0xff0000;
});
sprite.on('pointerout', () => {
  sprite.tint = 0xffffff;
});

// Drag pattern
sprite.eventMode = 'static';
sprite.on('pointerdown', onDragStart);
function onDragStart(event) {
  this.alpha = 0.5;
  app.stage.on('pointermove', onDragMove);
  app.stage.once('pointerup', onDragEnd);
}

Event modes: 'none' (no events), 'passive' (no hit testing, receives bubbled events), 'auto' (hit test if parent does), 'static' (always hit tests), 'dynamic' (hit tests every frame).

Performance

  • RenderGroups: Call container.isRenderGroup = true on containers that move as a unit (e.g., game world). Transforms are applied on the GPU, avoiding per-child recalculation.
  • Culling: Set container.cullable = true and optionally container.cullArea = new Rectangle(...) to skip off-screen objects.
  • ParticleContainer: Use Particle (not Sprite) for 100k+ particles -- much lighter objects.
  • cacheAsTexture(): Freeze complex subtrees into a single texture. Call container.cacheAsTexture({ resolution: 1 }).
  • boundsArea: Set container.boundsArea = new Rectangle(...) to skip recursive bounds calculation for known-size containers.
  • Texture atlases: Batch draw calls by packing sprites into spritesheets.
  • roundPixels: true: For pixel art, prevents sub-pixel blurring.

Spritesheets

Spritesheets are the primary way to batch sprites efficiently.

// Load a spritesheet (JSON atlas + texture)
const sheet = await Assets.load('sprites.json');

// Access individual frames
const hero = new Sprite(sheet.textures['hero.png']);

// Access named animations (arrays of textures)
const walkFrames = sheet.animations['walk'];
const anim = new AnimatedSprite(walkFrames);
anim.animationSpeed = 0.15;
anim.play();

All frames from a single spritesheet share one GPU texture, enabling batch rendering (one draw call for many sprites).

Destroy Patterns

Always destroy objects when removing them permanently:

// Basic destroy
sprite.destroy();

// Destroy with children and textures
container.destroy({ children: true, texture: true, textureSource: true });

// Destroy application
app.destroy(true, { children: true, texture: true, textureSource: true });
// First arg: { removeView: true } removes canvas from DOM
// Second arg: DestroyOptions for the stage

When using Assets, unload assets you no longer need:

await Assets.unload('hero');
Assets.cache.remove('hero');

Configuration

See references/configuration.md for the full ApplicationOptions, AutoDetectOptions, renderer options, and AssetInitOptions reference.

Migration from v7

See references/migration-v8.md for the complete v7-to-v8 migration guide covering:

  • Async initialization
  • Single-package imports
  • New Graphics API (shape-first)
  • Texture/BaseTexture changes
  • ParticleContainer rework
  • Shader/Filter constructor changes
  • DisplayObject removal (Container is the base)
  • updateTransform replaced by onRender

Links

Install via CLI
npx skills add https://github.com/pradeepmouli/skillit --skill pixi-js
Repository Details
star Stars 6
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator
pradeepmouli
pradeepmouli Explore all skills →