pixijs-scene-particle-container

Use this skill when rendering thousands of lightweight sprites in PixiJS v8. Covers ParticleContainer with Particle instances, addParticle/removeParticle,…

INSTALLATION
npx skills add https://github.com/pixijs/pixijs-skills --skill pixijs-scene-particle-container
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

$28

const container = new ParticleContainer({

texture,

boundsArea: new Rectangle(0, 0, app.screen.width, app.screen.height),

dynamicProperties: {

position: true,

rotation: false,

color: false,

},

});

for (let i = 0; i < 10000; i++) {

container.addParticle(

new Particle({

texture,

x: Math.random() * app.screen.width,

y: Math.random() * app.screen.height,

}),

);

}

app.stage.addChild(container);

**Related skills:** `pixijs-scene-core-concepts` (scene graph basics), `pixijs-scene-sprite` (when you need full features per object), `pixijs-assets` (shared textures, atlases), `pixijs-performance` (batching, texture optimization), `pixijs-scene-container` (wrap with other display objects).

## Constructor options

### ParticleContainerOptions

All `Container` options (`position`, `scale`, `tint`, `label`, `filters`, `zIndex`, etc.) are also valid here — see `skills/pixijs-scene-core-concepts/references/constructor-options.md`. Note that `children` is omitted: use `particles` instead.

| Option              | Type                 | Default                                                                        | Description                                                                                                                                                                     |

| ------------------- | -------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

| `texture`           | `Texture`            | `null`                                                                         | Shared base texture for all particles. If omitted, the container falls back to the texture of the first particle added; every particle must share the same base texture source. |

| `particles`         | `T[]`                | `[]`                                                                           | Initial array of `Particle` (or `IParticle`) instances. Equivalent to calling `addParticle` for each, but skips per-call view updates.                                          |

| `dynamicProperties` | `ParticleProperties` | `{ vertex: false, position: true, rotation: false, uvs: false, color: false }` | Flags for which particle attributes re-upload to the GPU every frame. Only `position` is dynamic by default; mark what you animate, leave the rest static for speed.            |

| `roundPixels`       | `boolean`            | `false`                                                                        | Rounds particle positions to the nearest pixel. Produces crisper rendering for pixel-art styles at the cost of smooth sub-pixel motion.                                         |

| `shader`            | `Shader`             | default particle shader                                                        | Replaces the default particle shader. The custom shader must declare `aPosition`, `aUV`, `aColor`, plus any dynamic-only attributes enabled via `dynamicProperties`.            |

`boundsArea` is inherited from `Container` but is effectively required on `ParticleContainer`: the container returns empty bounds `(0, 0, 0, 0)` by default for performance, so without `boundsArea` it is culled as invisible when culling is active and `containsPoint` always misses.

### ParticleOptions

`Particle` is a lightweight struct, not a `Container` subclass — none of the `ContainerOptions` fields apply. The full option list:

| Option     | Type          | Default    | Description                                                                                                                            |

| ---------- | ------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------- |

| `texture`  | `Texture`     | —          | Required. Texture used to render this particle. All particles in the same `ParticleContainer` must share the same base texture source. |

| `x`        | `number`      | `0`        | X position in the container's local space.                                                                                             |

| `y`        | `number`      | `0`        | Y position in the container's local space.                                                                                             |

| `scaleX`   | `number`      | `1`        | Horizontal scale factor.                                                                                                               |

| `scaleY`   | `number`      | `1`        | Vertical scale factor.                                                                                                                 |

| `anchorX`  | `number`      | `0`        | Horizontal anchor in 0–1 range; `0` is left, `0.5` is center, `1` is right.                                                            |

| `anchorY`  | `number`      | `0`        | Vertical anchor in 0–1 range; `0` is top, `0.5` is center, `1` is bottom.                                                              |

| `rotation` | `number`      | `0`        | Rotation in radians.                                                                                                                   |

| `tint`     | `ColorSource` | `0xffffff` | Tint color as hex number or CSS color string. Combined with `alpha` into the internal `color` field.                                   |

| `alpha`    | `number`      | `1`        | Transparency (0–1). Values outside the range are clamped. Combined with `tint` into the internal `color` field.                        |

The constructor also accepts a bare `Texture` as its sole argument (`new Particle(texture)`), which is shorthand for `new Particle({ texture })` using the defaults above.

`Particle.defaultOptions` is a static object you can reassign to change defaults globally; see the "Particle creation" section below.

## Core Patterns

### Particle creation

const particle = new Particle({

texture,

x: 100,

y: 200,

scaleX: 0.5,

scaleY: 0.5,

anchorX: 0.5,

anchorY: 0.5,

rotation: Math.PI / 4,

tint: 0xff0000,

alpha: 0.8,

});

container.addParticle(particle);


`Particle` is a lightweight struct with flat numeric fields: `x`, `y`, `scaleX`, `scaleY`, `anchorX`, `anchorY`, `rotation`, `color`, `texture`. It also exposes `tint` (hex/CSS color) and `alpha` (0-1) as setters that combine into the internal `color` field. No transform hierarchy, no events, no filters.

You can pass a `Texture` directly as the sole argument: `new Particle(texture)`.

Override `Particle.defaultOptions` to change defaults globally:

Particle.defaultOptions = {

...Particle.defaultOptions,

anchorX: 0.5,

anchorY: 0.5,

};


### Pre-populating with the particles option

const particles = Array.from(

{ length: 10000 },

() =>

new Particle({

texture,

x: Math.random() * 800,

y: Math.random() * 600,

}),

);

const container = new ParticleContainer({

texture,

boundsArea: new Rectangle(0, 0, 800, 600),

particles,

});


Passing `particles` in the constructor is equivalent to creating the container empty and calling `addParticle` for each one, but avoids per-call view updates.

### Dynamic vs static properties and update()

const container = new ParticleContainer({

dynamicProperties: {

rotation: true,

},

});


`dynamicProperties` controls which particle attributes re-upload to the GPU every frame. The defaults on `ParticleContainer.defaultOptions.dynamicProperties` are:

{ vertex: false, position: true, rotation: false, uvs: false, color: false }


You only need to override the properties you are animating; the rest inherit the defaults (position dynamic, everything else static). Five properties in total:

- `vertex`: scale/anchor vertices

- `position`

- `rotation`

- `uvs`: texture coordinates (for frame-swapped particles)

- `color`: tint and alpha

Mark only what you animate; static properties are cheaper. If you change a static property at runtime, call `container.update()` to re-upload:

container.particleChildren.forEach((p) => {

p.tint = 0x00ff00;

});

container.update();


### Batch operations on particleChildren

// Bulk add

const batch = [];

for (let i = 0; i < 5000; i++) {

batch.push(

new Particle({ texture, x: Math.random() 800, y: Math.random() 600 }),

);

}

container.particleChildren.push(...batch);

container.update();

// Bulk remove

container.particleChildren.length = 0;

container.update();


`addParticle`, `addParticleAt`, `removeParticle`, `removeParticleAt`, and `removeParticles` all trigger view updates per call. For large batch operations, direct array manipulation plus a single `update()` is faster.

### Texture and shader options

`texture` in `ParticleContainerOptions` is optional. If omitted, the container falls back to the texture of the first particle added; every subsequent particle must share the same base texture source. Set it explicitly when you want to declare the atlas up front, or when the first particle might change mid-run:

const container = new ParticleContainer({ texture });


`shader` lets you replace the default particle shader with any `Shader` instance. The custom shader must declare the attributes the particle pipe uploads (`aPosition`, `aUV`, `aColor`, plus any dynamic-only attributes enabled via `dynamicProperties`). Use this for custom blending math, distance-field sprites, or non-standard effects:

const container = new ParticleContainer({ texture, shader: myCustomShader });


### Limitations

`ParticleContainer` intentionally sacrifices features for speed:

- No filters, masks, or blend modes on individual particles.

- No nested children on particles.

- No automatic bounds calculation.

- All particles must share the same base texture source (atlases work; multiple unrelated textures do not).

- Custom shaders are supported via the `shader` option.

### Container method migration

`ParticleContainer` uses a separate child management API optimized for GPU buffer updates. The standard `Container` child methods throw when called on a `ParticleContainer`.

Standard Container method
ParticleContainer equivalent

`addChild(child)`
`addParticle(particle)`

`removeChild(child)`
`removeParticle(particle)`

`addChildAt(child, index)`
`addParticleAt(particle, index)`

`removeChildAt(index)`
`removeParticleAt(index)`

`removeChildren(begin, end)`
`removeParticles(begin, end)`

`getChildAt(index)`
Access `container.particleChildren[index]` directly

`swapChildren()`
Not available

`reparentChild()`
Not available

## Common Mistakes

### [CRITICAL] Adding Sprites to ParticleContainer

Wrong:

const container = new ParticleContainer();

const sprite = new Sprite(texture);

container.addChild(sprite);


Correct:

const container = new ParticleContainer();

const particle = new Particle(texture);

container.addParticle(particle);


`ParticleContainer` does not accept `Sprite` children. `addChild` throws an error. Particles must be `Particle` instances (or any object implementing `IParticle`), added via `addParticle`. This is a complete rework from v7, where `ParticleContainer` accepted `Sprite` children.

### [HIGH] Not setting boundsArea on ParticleContainer

Wrong:

const container = new ParticleContainer();

// bounds is always (0, 0, 0, 0) — culling and hit testing fail


Correct:

const container = new ParticleContainer({

boundsArea: new Rectangle(0, 0, 800, 600),

});


`ParticleContainer` returns empty bounds `(0, 0, 0, 0)` by default for performance. Without `boundsArea`, the container is culled as invisible when culling is active, and `containsPoint` always misses. Set `boundsArea` to the region your particles occupy.

### [HIGH] Using children instead of particleChildren

Wrong:

container.addParticle(new Particle(texture));

console.log(container.children.length); // 0


Correct:

container.addParticle(new Particle(texture));

console.log(container.particleChildren.length); // 1


Particles are stored in the `particleChildren` array, not `children`. The standard `Container.children` array is empty on a `ParticleContainer`. All particle enumeration, counting, and manipulation must use `particleChildren` plus the `*Particle` methods.

### [MEDIUM] Do not use ParticleContainer as a normal container

`ParticleContainer` contains particles, not display objects. If you need to group a particle system with a background sprite or UI overlay, wrap the `ParticleContainer` itself inside a plain `Container`:

const world = new Container();

world.addChild(backgroundSprite, particleContainer, uiLayer);

BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card