/groups-and-containers
Use this skill when using Groups or Containers in Phaser 4. Covers organizing game objects, object pooling, batch operations, and nested transforms with Containers. Triggers on: Group, Container, object pool, getFirstDead, children.
Claude Code
$ npx -y skills add phaserjs/phaser --skill groups-and-containers --agent claude-code
Codex
$ npx skills add phaserjs/phaser --skill groups-and-containers -a codex -y
Cursor
$ npx skills add phaserjs/phaser --skill groups-and-containers -a cursor -y
Gemini CLI
$ npx skills add phaserjs/phaser --skill groups-and-containers -a gemini-cli -y
GitHub Copilot
$ npx skills add phaserjs/phaser --skill groups-and-containers -a github-copilot -y
OpenCode
$ npx skills add phaserjs/phaser --skill groups-and-containers -a opencode -y
Windsurf
$ npx skills add phaserjs/phaser --skill groups-and-containers -a windsurf -y
SKILL.md
groups-and-containers.SKILL.mdname: groups-and-containers
description: "Use this skill when using Groups or Containers in Phaser 4. Covers organizing game objects, object pooling, batch operations, and nested transforms with Containers. Triggers on: Group, Container, object pool, getFirstDead, children."
Groups and Containers
> Logical grouping (Group), visual grouping with transform inheritance (Container), render-layer grouping (Layer), object pooling, and when to use each in Phaser 4.
**Key source paths:** `src/gameobjects/group/`, `src/gameobjects/container/`, `src/gameobjects/layer/` **Related skills:** ../sprites-and-images/SKILL.md, ../physics-arcade/SKILL.md
Quick Start
// In a Scene's create() method:
// --- Group: logical collection, no transform, great for pooling ---
const enemies = this.add.group();
enemies.create(100, 200, 'enemy'); // creates Sprite at (100,200)
enemies.create(300, 200, 'enemy');
// --- Container: visual parent with inherited transform ---
const hud = this.add.container(10, 10);
const icon = this.add.image(0, 0, 'heart');
const label = this.add.text(20, 0, 'x3');
hud.add([icon, label]); // children move/scale/rotate with hud
// --- Layer: render-ordering bucket, no position/scale ---
const bgLayer = this.add.layer();
const fgLayer = this.add.layer();
bgLayer.add(this.add.image(400, 300, 'sky'));
fgLayer.add(this.add.sprite(400, 300, 'player'));
Core Concepts
Group vs Container vs Layer
| Feature | Group | Container | Layer | |---|---|---|---| | **Purpose** | Logical collection / pool | Visual parent with transform | Render-order bucket | | **On display list** | No (children are) | Yes (renders children) | Yes (renders children) | | **Position/rotation/scale** | No | Yes (children inherit) | No | | **Children storage** | `children` (Set) | `list` (Array) | List (Structs.List) | | **Physics** | Via physics.add.group() | Limited (offsets if not at 0,0) | No | | **Input** | No (children can) | Yes (needs hit area shape) | No | | **Object pooling** | Yes (getFirstDead, kill) | No | No | | **Masks** | No | Yes (not per-child in Canvas) | Yes | | **Alpha/blend/visible** | No (batch via setVisible) | Yes | Yes | | **Nesting** | N/A | Container in Container | Cannot go in Container | | **Extends** | EventEmitter | GameObject | List | | **Factory** | `this.add.group()` | `this.add.container(x, y)` | `this.add.layer()` |
When to Use Each
**Group:** Managing collections of similar objects (enemies, bullets, coins), object pooling with active/inactive lifecycle, physics group collisions. No shared visual transform. Members can belong to multiple Groups simultaneously.
**Container:** Children inherit position, rotation, scale, alpha. Composite UI elements (health bars, inventory slots), moving/rotating clusters as one unit, nested transforms. By default exclusive -- a child can only belong to one Container (use `setExclusive(false)` to override).
**Layer:** Controlling render order of object batches, applying shared alpha/blend/mask. No position/scale/rotation. Lightweight render bucketing.
Container vs Group at a Glance
- **Container has position, rotation, scale, alpha** -- Group does not. If you need children to move/rotate as a unit, use Container.
- **Container is exclusive by default** -- adding a child removes it from its previous Container. Group is non-exclusive; a game object can be in many Groups.
- **Container is on the display list** -- it renders its children. Group is not on the display list; its children render individually on the Scene.
- **Group supports object pooling** -- getFirstDead, kill, killAndHide. Container does not.
- **Container has performance cost** -- each child requires matrix math per frame. Deeper nesting = more cost. Prefer Group or Layer when transforms are not needed.
Common Patterns
Creating and Populating Groups
// Empty group, add existing objects
const gems = this.add.group();
gems.add(existingSprite);
gems.addMultiple([sprite1, sprite2, sprite3]);
// Group with config -- creates children automatically
const coins = this.add.group({
classType: Phaser.GameObjects.Sprite,
key: 'coin',
quantity: 10, // overrides frameQuantity
setXY: { x: 50, y: 300, stepX: 60 },
setScale: { x: 0.5, y: 0.5 }
});
// Custom class type with pool limit
const bullets = this.add.group({
classType: Bullet, // must accept (scene, x, y, key, frame)
maxSize: 30,
defaultKey: 'bullet',
runChildUpdate: true // calls child.update() each frame
});Object Pooling with getFirstDead
The core pooling pattern: deactivate objects instead of destroying them, then reuse inactive ones.
// Setup pool
const bullets = this.add.group({
classType: Phaser.GameObjects.Sprite,
defaultKey: 'bullet',
maxSize: 30
});
// Fire a bullet -- get() finds first inactive member or creates one
function fireBullet(x, y) {
const bullet = bullets.get(x, y);
if (bullet) {
bullet.setActive(true);
bullet.setVisible(true);
bullet.body.velocity.y = -300; // if physics enabled
}
}
// Deactivate when off-screen or on hit
function killBullet(bullet) {
bullets.killAndHide(bullet); // sets active=false, visible=false
// If using physics, also reset the body:
// bullet.body.stop();
}
// Alternative: manual getFirst
const inactive = bullets.getFirst(false); // first where active===false
const active = bullets.getFirstAlive(); // first where active===true
const dead = bullets.getFirstDead(true, x, y); // first inactive, create if null**Pool helper methods on Group:**
| Method | Description | |---|---| | `get(x, y, key, frame)` | Shortcut: `getFirst(false, true, ...)` -- finds inactive or creates | | `getFirst(state, createIfNull, x, y, key, frame)` | First member matching active `state` | | `getFirstAlive(createIfNull, x, y, key, frame)` | First member where `active===true` | | `getF
Read more
name: groups-and-containers description: "Use this skill when using Groups or Containers in Phaser 4. Covers organizing game objects, object pooling, batch operations, and nested transforms with Containers. Triggers on: Group, Container, object pool, getFirstDead, children."
Groups and Containers
> Logical grouping (Group), visual grouping with transform inheritance (Container), render-layer grouping (Layer), object pooling, and when to use each in Phaser 4.
**Key source paths:** `src/gameobjects/group/`, `src/gameobjects/container/`, `src/gameobjects/layer/` **Related skills:** ../sprites-and-images/SKILL.md, ../physics-arcade/SKILL.md
Quick Start
// In a Scene's create() method: // --- Group: logical collection, no transform, great for pooling --- const enemies = this.add.group(); enemies.create(100, 200, 'enemy'); // creates Sprite at (100,200) enemies.create(300, 200, 'enemy'); // --- Container: visual parent with inherited transform --- const hud = this.add.container(10, 10); const icon = this.add.image(0, 0, 'heart'); const label = this.add.text(20, 0, 'x3'); hud.add([icon, label]); // children move/scale/rotate with hud // --- Layer: render-ordering bucket, no position/scale --- const bgLayer = this.add.layer(); const fgLayer = this.add.layer(); bgLayer.add(this.add.image(400, 300, 'sky')); fgLayer.add(this.add.sprite(400, 300, 'player'));
Core Concepts
Group vs Container vs Layer
| Feature | Group | Container | Layer | |---|---|---|---| | **Purpose** | Logical collection / pool | Visual parent with transform | Render-order bucket | | **On display list** | No (children are) | Yes (renders children) | Yes (renders children) | | **Position/rotation/scale** | No | Yes (children inherit) | No | | **Children storage** | `children` (Set) | `list` (Array) | List (Structs.List) | | **Physics** | Via physics.add.group() | Limited (offsets if not at 0,0) | No | | **Input** | No (children can) | Yes (needs hit area shape) | No | | **Object pooling** | Yes (getFirstDead, kill) | No | No | | **Masks** | No | Yes (not per-child in Canvas) | Yes | | **Alpha/blend/visible** | No (batch via setVisible) | Yes | Yes | | **Nesting** | N/A | Container in Container | Cannot go in Container | | **Extends** | EventEmitter | GameObject | List | | **Factory** | `this.add.group()` | `this.add.container(x, y)` | `this.add.layer()` |
When to Use Each
**Group:** Managing collections of similar objects (enemies, bullets, coins), object pooling with active/inactive lifecycle, physics group collisions. No shared visual transform. Members can belong to multiple Groups simultaneously.
**Container:** Children inherit position, rotation, scale, alpha. Composite UI elements (health bars, inventory slots), moving/rotating clusters as one unit, nested transforms. By default exclusive -- a child can only belong to one Container (use `setExclusive(false)` to override).
**Layer:** Controlling render order of object batches, applying shared alpha/blend/mask. No position/scale/rotation. Lightweight render bucketing.
Container vs Group at a Glance
- **Container has position, rotation, scale, alpha** -- Group does not. If you need children to move/rotate as a unit, use Container.
- **Container is exclusive by default** -- adding a child removes it from its previous Container. Group is non-exclusive; a game object can be in many Groups.
- **Container is on the display list** -- it renders its children. Group is not on the display list; its children render individually on the Scene.
- **Group supports object pooling** -- getFirstDead, kill, killAndHide. Container does not.
- **Container has performance cost** -- each child requires matrix math per frame. Deeper nesting = more cost. Prefer Group or Layer when transforms are not needed.
Common Patterns
Creating and Populating Groups
// Empty group, add existing objects
const gems = this.add.group();
gems.add(existingSprite);
gems.addMultiple([sprite1, sprite2, sprite3]);
// Group with config -- creates children automatically
const coins = this.add.group({
classType: Phaser.GameObjects.Sprite,
key: 'coin',
quantity: 10, // overrides frameQuantity
setXY: { x: 50, y: 300, stepX: 60 },
setScale: { x: 0.5, y: 0.5 }
});
// Custom class type with pool limit
const bullets = this.add.group({
classType: Bullet, // must accept (scene, x, y, key, frame)
maxSize: 30,
defaultKey: 'bullet',
runChildUpdate: true // calls child.update() each frame
});Object Pooling with getFirstDead
The core pooling pattern: deactivate objects instead of destroying them, then reuse inactive ones.
// Setup pool
const bullets = this.add.group({
classType: Phaser.GameObjects.Sprite,
defaultKey: 'bullet',
maxSize: 30
});
// Fire a bullet -- get() finds first inactive member or creates one
function fireBullet(x, y) {
const bullet = bullets.get(x, y);
if (bullet) {
bullet.setActive(true);
bullet.setVisible(true);
bullet.body.velocity.y = -300; // if physics enabled
}
}
// Deactivate when off-screen or on hit
function killBullet(bullet) {
bullets.killAndHide(bullet); // sets active=false, visible=false
// If using physics, also reset the body:
// bullet.body.stop();
}
// Alternative: manual getFirst
const inactive = bullets.getFirst(false); // first where active===false
const active = bullets.getFirstAlive(); // first where active===true
const dead = bullets.getFirstDead(true, x, y); // first inactive, create if null**Pool helper methods on Group:**
| Method | Description | |---|---| | `get(x, y, key, frame)` | Shortcut: `getFirst(false, true, ...)` -- finds inactive or creates | | `getFirst(state, createIfNull, x, y, key, frame)` | First member matching active `state` | | `getFirstAlive(createIfNull, x, y, key, frame)` | First member where `active===true` | | `getF
Phaser is a fast, free, and fun open source HTML5 game framework that offers WebGL and Canvas rendering across desktop and mobile web browsers and has been actively developed for over 13 years.
Other skills on phaser.
More skills from other plugins.
migrate-radix-to-base
Migrates React projects and components from Radix UI to Base UI. Use when asked to migrate from radix, move to base-ui, convert…
taste-skill
tasteskill v2, the anti-slop frontend skill. Art direction for websites, distilled from a study of 247 curated gallery sites (One…
Questions about groups-and-containers.
- Which coding agents can use groups-and-containers?
- groups-and-containers installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

