用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/feliperyba/ralph-orchestra --skill dev-phaser-particles命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Complete Developer workflow orchestration - task research sequence, implementation flow, validation gates, PRD synchronization, exit conditions.
Complete Game Designer workflow - skill invocation protocol, GDD creation, playtest flow with GDD review, design sessions. MUST load before starting assignments.
Complete PM Coordinator workflow - task assignment, project orchestration, PRD management, worker coordination. Use proactively when starting PM agent work.
正在显示 SKILL.md
基于 SOC 职业分类
| name | dev-phaser-particles |
| description | Particle emitters for visual effects like fire, smoke, explosions, and magic |
"Create stunning visual effects with particle systems."
// Manual particle system without Phaser
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; // Gravity
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) {
// Filter out dead particles - creates garbage!
this.particles = this.particles.filter(p => p.update(dt));
}
render(ctx: CanvasRenderingContext2D) {
for (const p of this.particles) {
p.render(ctx);
}
}
// No built-in emit zones
// No death zones
// No onEmit callbacks
// No texture/animated particles
// No blend modes (ADD, MULTIPLY)
}
// Problems:
// - Manual array filtering creates GC pressure
// - No built-in particle lifecycle management
// - Manual render loop for each particle
// - No texture support (only circles/rects)
// - No blend modes (ADD for fire/magic)
// - No emit zones (circle, rectangle, edge)
// - No death zones
// - No onEmit/onDeath callbacks
// - Performance degrades with many particles
// Phaser handles particles automatically
export class GameScene extends Phaser.Scene {
create() {
// Explosion emitter - ONE config!
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, // Don't auto-emit
blendMode: 'ADD' // Built-in blend modes!
});
// Trigger explosion anywhere - ONE line!
explosion.explode(30, 400, 300);
// Fire effect - continuous emitter
const fire = ..(, , , {
: { : , : },
: { : , : },
: { : , : },
: { : , : },
: ,
: ,
: ,
:
});
trail = ..(, , , {
: ,
: { : , : },
: { : , : },
: ,
: ,
: ,
: {
: ,
: ..(, , ),
:
}
});
trail.(.);
sparkles = ..(, , , {
: { : , : },
: { : , : , : },
: { : , : },
: { : , : },
: {
particle. = ...([
, ,
]);
}
});
}
}
Use when:
create() {
const particles = this.add.particles(0, 0, 'flare', {
speed: 100,
scale: { start: 1, end: 0 },
blendMode: 'ADD'
});
particles.startFollow(this.player);
}
| 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 |
export class GameScene extends Phaser.Scene {
create() {
// Simple particle emitter
const particles = this.add.particles(400, 300, "flare", {
speed: 100,
scale: { start: 1, end: 0 },
blendMode: "ADD",
lifespan: 1000,
quantity: 1,
});
// Particle at mouse position
this.input.on("pointermove", (pointer: Phaser.Input.Pointer) => {
particles.emitParticleAt(pointer.x, pointer.y);
});
}
}
create() {
// Fire effect
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
});
// Smoke effect
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.);
});
}
export class GameScene extends Phaser.Scene {
private trailEmitter!: Phaser.GameObjects.Particles.ParticleEmitter;
create() {
// Create player
this.player = this.add.image(400, 300, "player");
// Trail emitter
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.(.);
}
}
create() {
// Magic sparkles
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
});
// Rain effect
const rainZone = new Phaser.Geom.(, , .., );
rain = ..(, , , {
: { : , : .. },
: -,
: ,
: ,
: { : , : },
: { : , : },
: ,
: ,
: ,
: { : rainZone }
});
burstEmitter = ..(, , , {
: ,
: { : , : },
: { : , : },
: ,
: ,
: ,
: {
particle. = ...([, , ]);
}
});
..(, {
burstEmitter.(, pointer., pointer.);
});
}
class ParticleManager {
private emitters = new Map<
string,
Phaser.GameObjects.Particles.ParticleEmitter
>();
constructor(private scene: Phaser.Scene) {
this.createPresets();
}
private createPresets() {
// Fire preset
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.);
});
}
}
❌ DON'T:
✅ DO:
// Rectangle zone
const rectZone = new Phaser.Geom.Rectangle(x, y, width, height);
particles.setEmitZone({
type: "random",
source: rectZone,
});
// Edge zone (particles on perimeter)
const edgeZone = new Phaser.Geom.Circle(x, y, radius);
particles.setEmitZone({
type: "edge",
source: edgeZone,
quantity: 20,
});
// Random point zone
const pointZone = new Phaser.Geom.Circle(x, y, radius);
particles.setEmitZone({
type: "random",
source: pointZone,
});
// Particles die when entering zone
const deathZone = new Phaser.Geom.Rectangle(300, 200, 200, 200);
particles.setDeathZone({
type: "onEnter",
source: deathZone,
});
const particles = this.add.particles(400, 300, "spark", {
speed: 100,
lifespan: 1000,
onEmit: (particle: any) => {
// Customize each particle
particle.tint = 0xff0000;
particle.velocity.x *= Math.random();
},
onParticleEmit: (emitter, particle) => {
// Called when particle emits
},
onParticleDeath: (emitter, particle) => {
// Called when particle dies
},
});
| 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 |
| Mode | Description | Use For |
|---|---|---|
NORMAL | Default | Most effects |
ADD | Additive | Fire, sparks, magic |
MULTIPLY | Multiply | Shadows, smoke |
SCREEN | Screen | Glowing effects |