| name | dev-phaser-particles |
| description | Particle emitters for visual effects like fire, smoke, explosions, and magic |
Phaser Particles
"Create stunning visual effects with particle systems."
Before/After: Manual Particle System vs Phaser Particles
❌ Before: Manual Particle Management
class Particle {
x: number;
y: number;
vx: number;
vy: number;
life: number;
maxLife: number;
size: number;
alpha: number;
color: string;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
const angle = Math.random() * Math.PI * 2;
const speed = 50 + Math.random() * 200;
this.vx = Math.cos(angle) * speed;
this.vy = Math.sin(angle) * speed;
this.life = 0;
this.maxLife = 500 + Math.random() * 500;
this.size = 2 + Math.random() * 4;
this.alpha = 1;
this.color = `hsl(${Math.random() * 60 + 10}, 100%, 50%)`;
}
update(dt: number): boolean {
this.x += this.vx * dt / 1000;
this.y += this.vy * dt / 1000;
this.vy += 200 * dt / 1000;
this.life += dt;
this.alpha = 1 - (this.life / this.maxLife);
return this.life < this.maxLife;
}
render(ctx: CanvasRenderingContext2D) {
ctx.globalAlpha = this.alpha;
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fill();
ctx.globalAlpha = 1;
}
}
class ParticleSystem {
private particles: Particle[] = [];
explode(x: number, y: number, count: number) {
for (let i = 0; i < count; i++) {
this.particles.push(new Particle(x, y));
}
}
update(dt: number) {
this.particles = this.particles.filter(p => p.update(dt));
}
render(ctx: CanvasRenderingContext2D) {
for (const p of this.particles) {
p.render(ctx);
}
}
}
✅ After: Phaser Particle System
export class GameScene extends Phaser.Scene {
create() {
const explosion = this.add.particles(0, 0, 'explosion', {
speed: { min: 100, max: 400 },
angle: { min: 0, max: 360 },
scale: { start: 0.5, end: 2 },
alpha: { start: 1, end: 0 },
lifespan: 600,
quantity: 30,
emitting: false,
blendMode: 'ADD'
});
explosion.explode(30, 400, 300);
const fire = ..(, , , {
: { : , : },
: { : , : },
: { : , : },
: { : , : },
: ,
: ,
: ,
:
});
trail = ..(, , , {
: ,
: { : , : },
: { : , : },
: ,
: ,
: ,
: {
: ,
: ..(, , ),
:
}
});
trail.(.);
sparkles = ..(, , , {
: { : , : },
: { : , : , : },
: { : , : },
: { : , : },
: {
particle. = ...([
, ,
]);
}
});
}
}
When to Use This Skill
Use when:
- Creating explosion effects
- Adding fire/smoke effects
- Building magic spells
- Implementing weather effects
- Adding visual polish to actions
Quick Start
create() {
const particles = this.add.particles(0, 0, 'flare', {
speed: 100,
scale: { start: 1, end: 0 },
blendMode: 'ADD'
});
particles.startFollow(this.player);
}
Decision Framework
| Need | Use |
|---|
| Trail effect | startFollow() + emitting |
| Explosion | One-time burst emitter |
| Continuous effect | Always-on emitter |
| Zone-based emission | Emitter zone |
| Texture animation | Animated particle frames |
Progressive Guide
Level 1: Basic Particle Emitter
export class GameScene extends Phaser.Scene {
create() {
const particles = this.add.particles(400, 300, "flare", {
speed: 100,
scale: { start: 1, end: 0 },
blendMode: "ADD",
lifespan: 1000,
quantity: 1,
});
this.input.on("pointermove", (pointer: Phaser.Input.Pointer) => {
particles.emitParticleAt(pointer.x, pointer.y);
});
}
}
Level 2: Common Effects
create() {
const fire = this.add.particles(400, 500, 'fire', {
speed: { min: 50, max: 100 },
angle: { min: 240, max: 300 },
scale: { start: 0.5, end: 0 },
blendMode: 'ADD',
lifespan: 800,
frequency: 50,
quantity: 3
});
const smoke = this.add.particles(400, 480, 'smoke', {
speed: 30,
angle: { min: 250, max: 290 },
scale: { start: 0.3, end: 1 },
alpha: { start: 0.5, end: },
: ,
:
});
= () => {
explosion = ..(x, y, , {
: { : , : },
: { : , : },
: { : , : },
: { : , : },
: ,
: ,
:
});
explosion.(, x, y);
};
..(, {
(pointer., pointer.);
});
}
Level 3: Following Emitters
export class GameScene extends Phaser.Scene {
private trailEmitter!: Phaser.GameObjects.Particles.ParticleEmitter;
create() {
this.player = this.add.image(400, 300, "player");
this.trailEmitter = this.add.particles(0, 0, "trail", {
speed: 0,
scale: { start: 0.8, end: 0 },
alpha: { start: 0.5, end: 0 },
lifespan: 300,
quantity: 1,
frequency: 50,
emitZone: {
type: "edge",
source: new Phaser..(, , ),
: ,
},
});
..(.);
exhaust = ..(, , , {
: { : -, : },
: { : , : },
: { : , : },
: { : , : },
: ,
: ,
});
exhaust.(.);
}
}
Level 4: Advanced Particle Configurations
create() {
const sparkles = this.add.particles(400, 300, 'sparkle', {
speed: { min: 50, max: 150 },
angle: { min: 0, max: 360 },
scale: { start: 0, end: 0.5, ease: 'Back.easeOut' },
alpha: { start: 1, end: 0, ease: 'Linear' },
lifespan: { min: 500, max: 1000 },
quantity: 2,
frequency: 100,
blendMode: 'ADD',
rotate: { start: 0, end: 180 },
emitting: true
});
const rainZone = new Phaser.Geom.(, , .., );
rain = ..(, , , {
: { : , : .. },
: -,
: ,
: ,
: { : , : },
: { : , : },
: ,
: ,
: ,
: { : rainZone }
});
burstEmitter = ..(, , , {
: ,
: { : , : },
: { : , : },
: ,
: ,
: ,
: {
particle. = ...([, , ]);
}
});
..(, {
burstEmitter.(, pointer., pointer.);
});
}
Level 5: Particle System Manager
class ParticleManager {
private emitters = new Map<
string,
Phaser.GameObjects.Particles.ParticleEmitter
>();
constructor(private scene: Phaser.Scene) {
this.createPresets();
}
private createPresets() {
this.createEmitter("fire", {
key: "fire",
config: {
speed: { min: 50, max: 100 },
angle: { min: 240, max: 300 },
scale: { start: 0.5, end: 0 },
alpha: { start: 0.8, end: 0 },
blendMode: "ADD",
lifespan: 800,
frequency: 50,
},
});
.(, {
: ,
: {
: { : , : },
: { : , : },
: { : , : },
: { : , : },
: ,
: ,
: ,
},
});
.(, {
: ,
: {
: ,
: { : , : },
: { : , : },
: ,
: ,
},
});
}
() {
emitter = ...(, , key, config);
..(name, emitter);
emitter;
}
() {
emitter = ..(name);
(emitter) {
emitter.(emitter.. || , x, y);
}
}
() {
emitter = ..(name);
(emitter) {
emitter.(target);
}
}
() {
emitter = ..(name);
(emitter) {
emitter.();
}
}
() {
emitter = ..(name);
(emitter) {
emitter.();
}
}
() {
emitter = ..(name);
(emitter) {
emitter.();
..(name);
}
}
}
{
particles!: ;
() {
. = ();
..(, .);
..(, {
..(, pointer., pointer.);
});
}
}
Anti-Patterns
❌ DON'T:
- Create too many particles per frame
- Use large particle textures for small effects
- Forget to stop emitters when done
- Overuse blend modes (can kill performance)
- Create particles in update() loop
- Ignore particle lifespan
✅ DO:
- Limit particle count for mobile
- Use appropriate particle sizes
- Stop/remove unused emitters
- Use blend modes sparingly
- Create emitters once in create()
- Tune lifespan for desired effect
Code Patterns
Emit Zones
const rectZone = new Phaser.Geom.Rectangle(x, y, width, height);
particles.setEmitZone({
type: "random",
source: rectZone,
});
const edgeZone = new Phaser.Geom.Circle(x, y, radius);
particles.setEmitZone({
type: "edge",
source: edgeZone,
quantity: 20,
});
const pointZone = new Phaser.Geom.Circle(x, y, radius);
particles.setEmitZone({
type: "random",
source: pointZone,
});
Death Zones
const deathZone = new Phaser.Geom.Rectangle(300, 200, 200, 200);
particles.setDeathZone({
type: "onEnter",
source: deathZone,
});
Particle Callbacks
const particles = this.add.particles(400, 300, "spark", {
speed: 100,
lifespan: 1000,
onEmit: (particle: any) => {
particle.tint = 0xff0000;
particle.velocity.x *= Math.random();
},
onParticleEmit: (emitter, particle) => {
},
onParticleDeath: (emitter, particle) => {
},
});
Emitter Configuration Reference
| Property | Type | Description |
|---|
speed | number/min/max | Particle velocity |
angle | number/min/max | Emission angle |
scale | start/end | Size over life |
alpha | start/end | Opacity over life |
lifespan | number/min/max | Particle duration (ms) |
quantity | number | Particles per emission |
frequency | number | Time between emissions (ms) |
blendMode | string | Rendering blend mode |
rotate | start/end | Rotation over life |
emitZone | object | Zone for emission |
deathZone | object | Zone for death |
Common Blend Modes
| Mode | Description | Use For |
|---|
NORMAL | Default | Most effects |
ADD | Additive | Fire, sparks, magic |
MULTIPLY | Multiply | Shadows, smoke |
SCREEN | Screen | Glowing effects |
Checklist
Reference