Agent skill
ta-phaser-camera-work
Implements camera controls, bounds, and follow behavior. Use proactively when setting up camera controls, camera bounds, or follow behavior.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/ta-phaser-camera-work
SKILL.md
Phaser Camera Work
"Cinematic camera controls that enhance gameplay and storytelling."
When to Use This Skill
Use when:
- Setting up camera follow behavior
- Implementing camera bounds
- Creating cinematic sequences
- Building camera transitions
- Adding visual polish with camera
Quick Start
// Smooth follow
this.cameras.main.startFollow(this.player, true, 0.08, 0.08);
// Camera bounds
this.cameras.main.setBounds(0, 0, 2000, 2000);
Decision Framework
| Need | Use |
|---|---|
| Player tracking | startFollow() with lerp |
| Confined area | setBounds() |
| Cinematic pan | pan() tween |
| Zoom effect | Camera zoom tween |
| Letterboxing | Custom camera for UI |
Progressive Guide
Level 1: Basic Camera Setup
export class GameScene extends Phaser.Scene {
create() {
// Get reference
const camera = this.cameras.main;
// Set background color
camera.setBackgroundColor("#2d2d2d");
// Set bounds (world limits)
camera.setBounds(0, 0, 2000, 1500);
// Follow player
camera.startFollow(this.player, true, 0.1, 0.1);
// Set zoom
camera.setZoom(1.5);
// Center camera on spawn
camera.centerOn(this.player.x, this.player.y);
}
}
Level 2: Camera Follow Behaviors
export class GameScene extends Phaser.Scene {
create() {
// Tight follow (no lag)
this.cameras.main.startFollow(this.player, true, 1, 1);
// Loose follow (smooth lag)
this.cameras.main.startFollow(this.player, true, 0.05, 0.05);
// Horizontal only (side-scroller)
this.cameras.main.startFollow(this.player, true, 0.1, 0);
// Locked Y, free X
this.cameras.main.startFollow(this.player, true, 0, 0.1);
// With deadzone (player can move without camera moving)
this.cameras.main.startFollow(this.player, true, 0.08, 0.08);
this.cameras.main.setDeadzone(
this.scale.width * 0.3,
this.scale.height * 0.3,
);
}
}
Level 3: Cinematic Camera Moves
export class CutsceneScene extends Phaser.Scene {
create() {
// Pan to location
const panToLocation = (x: number, y: number, duration = 2000) => {
this.tweens.add({
targets: this.cameras.main,
x: x,
y: y,
duration: duration,
ease: "Power2.easeInOut",
});
};
// Zoom in on object
const focusOn = (target: Phaser.GameObjects.Sprite, duration = 1000) => {
this.tweens.add({
targets: this.cameras.main,
x: target.x,
y: target.y,
zoom: 2,
duration: duration,
ease: "Power2.easeInOut",
});
};
// Dramatic reveal
const dramaticReveal = () => {
const camera = this.cameras.main;
// Start zoomed in
camera.setZoom(3);
camera.centerOn(this.boss.x, this.boss.y);
// Zoom out to show arena
this.tweens.add({
targets: camera,
zoom: 1,
x: this.arenaCenter.x,
y: this.arenaCenter.y,
duration: 2000,
ease: "Cubic.easeOut",
});
};
// Tracking shot
const trackingShot = (path: Phaser.Curves.Path, duration = 3000) => {
this.tweens.add({
targets: this.cameras.main,
x: path.points[0].x,
y: path.points[0].y,
duration: duration,
ease: "Linear",
onUpdate: (tween: any) => {
const progress = tween.progress;
const point = path.getPoint(progress);
this.cameras.main.centerOn(point.x, point.y);
},
});
};
}
}
Level 4: Multi-Camera Setups
export class GameScene extends Phaser.Scene {
private gameCamera!: Phaser.Cameras.Scene2D.Camera;
private uiCamera!: Phaser.Cameras.Scene2D.Camera;
private minimapCamera!: Phaser.Cameras.Scene2D.Camera;
create() {
// Main game camera
this.gameCamera = this.cameras.main;
this.gameCamera.setName("game");
this.gameCamera.setBounds(0, 0, 2000, 2000);
this.gameCamera.startFollow(this.player);
// UI camera (fixed, no scroll)
this.uiCamera = this.cameras.add(0, 0, this.scale.width, this.scale.height);
this.uiCamera.setName("ui");
this.uiCamera.setScrollFactor(0);
this.uiCamera.setBackgroundColor("rgba(0,0,0,0)");
this.uiCamera.setZoom(1);
// Minimap camera
this.minimapCamera = this.cameras.add(this.scale.width - 220, 20, 200, 200);
this.minimapCamera.setName("minimap");
this.minimapCamera.setBounds(0, 0, 2000, 2000);
this.minimapCamera.setZoom(0.1);
// Minimap border
this.add
.rectangle(this.scale.width - 120, 120, 204, 204, 0xffffff)
.setStrokeStyle(2, 0x000000)
.setScrollFactor(0);
// Add objects to specific cameras
this.player.name = "player";
// Minimap doesn't show everything
this.minimapCamera.ignore(this.someObjects);
}
}
Level 5: Advanced Camera Controller
class CameraController {
private states = new Map<string, CameraState>();
private currentState: string = "default";
private tween?: Phaser.Tweens.Tween;
constructor(private camera: Phaser.Cameras.Scene2D.Camera) {
this.setupStates();
}
private setupStates() {
// Default follow state
this.states.set("default", {
follow: null,
lerp: 0.08,
zoom: 1,
deadzone: { x: 0.3, y: 0.3 },
});
// Combat state
this.states.set("combat", {
follow: null,
lerp: 0.12,
zoom: 1.1,
deadzone: { x: 0.2, y: 0.2 },
});
// Sprint state
this.states.set("sprint", {
follow: null,
lerp: 0.15,
zoom: 1.2,
deadzone: { x: 0.1, y: 0.1 },
});
// Cinematic state
this.states.set("cinematic", {
follow: null,
lerp: 1,
zoom: 1,
deadzone: { x: 0, y: 0 },
});
}
setState(stateName: string, duration = 500) {
const state = this.states.get(stateName);
if (!state || stateName === this.currentState) return;
this.currentState = stateName;
// Kill existing tween
if (this.tween) {
this.tween.destroy();
}
// Transition to new state
this.tween = this.camera.scene.tweens.add({
targets: this.camera,
zoom: state.zoom,
duration: duration,
ease: "Power2.easeOut",
onUpdate: () => {
this.camera.setLerp(state.lerp, state.lerp);
if (state.deadzone) {
const w = this.camera.width * state.deadzone.x;
const h = this.camera.height * state.deadzone.y;
this.camera.setDeadzone(w, h);
}
},
});
}
setFollowTarget(target: Phaser.GameObjects.GameObject) {
this.camera.startFollow(target, true, 0.08, 0.08);
}
lookAt(
target: Phaser.Math.Vector2 | Phaser.GameObjects.GameObject,
duration = 500,
) {
const x =
target instanceof Phaser.GameObjects.GameObject ? target.x : target.x;
const y =
target instanceof Phaser.GameObjects.GameObject ? target.y : target.y;
this.tween = this.camera.scene.tweens.add({
targets: this.camera,
x: x,
y: y,
duration: duration,
ease: "Power2.easeInOut",
});
}
// Camera shake with decay
shake(intensity: number, duration: number) {
const startTime = Date.now();
const update = () => {
const elapsed = Date.now() - startTime;
if (elapsed >= duration) {
this.camera.resetFX();
return;
}
const progress = elapsed / duration;
const currentIntensity = intensity * (1 - progress);
this.camera.shake(16, currentIntensity);
this.camera.scene.time.delayedCall(16, update);
};
update();
}
// Smooth zoom to target
zoomTo(targetZoom: number, duration = 500) {
this.tween = this.camera.scene.tweens.add({
targets: this.camera,
zoom: targetZoom,
duration: duration,
ease: "Power2.easeOut",
});
}
}
Camera Methods Reference
| Method | Parameters | Description |
|---|---|---|
startFollow(target) |
target, roundPx, lerpX, lerpY | Follow game object |
stopFollow() |
- | Stop following |
setZoom(level) |
number | Set zoom level |
setBounds(x, y, w, h) |
bounds | Set world bounds |
setDeadzone(w, h) |
size | Set no-move zone |
pan(x, y, duration) |
position, ms | Pan to position |
setLerp(lerpX, lerpY) |
0-1 values | Set follow smoothness |
setScrollFactor(x, y) |
0-1 values | Set parallax |
centerOn(x, y) |
position | Center camera |
ignore(objs) |
array | Don't render objects |
Anti-Patterns
❌ DON'T:
- Set lerp too high (jittery) or too low (laggy)
- Forget camera bounds for open worlds
- Use zoom without considering gameplay impact
- Mix coordinate systems when panning | Ignore camera in multi-camera setups | Change camera during player input
✅ DO: | Tune lerp for game feel | Set bounds for world limits | Test gameplay at different zoom levels | Use consistent coordinate systems | Name cameras for debugging | Change camera between gameplay segments
Camera Effect Presets
const CAMERA_PRESETS = {
// Platformer
platformer: {
followLerp: 0.08,
zoom: 1,
deadzone: { x: 0.3, y: 0.4 },
},
// Top-down action
topdown: {
followLerp: 0.1,
zoom: 1.2,
deadzone: { x: 0.2, y: 0.2 },
},
// Bullet hell
bullethell: {
followLerp: 0.05,
zoom: 1,
deadzone: { x: 0.1, y: 0.1 },
},
// Cinematic
cinematic: {
followLerp: 0.03,
zoom: 1,
deadzone: { x: 0.05, y: 0.05 },
},
};
Checklist
- Camera follow tuned for game feel
- World bounds set correctly
- Deadzone configured
- Multi-camera setup working
- Lerp values appropriate
- Camera effects don't break gameplay
- Minimap (if used) updating correctly
Reference
- Camera API — Camera docs
- Camera Manager — Manager API
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?