or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

actions.mdanimation.mdaudio.mdcameras.mddata-management.mdevents.mdgame-objects.mdindex.mdinput.mdloading.mdmath-geometry.mdphysics.mdrendering.mdscenes.mdtweens.mdutilities.md

cameras.mddocs/

0

# Camera System

1

2

Phaser's camera system provides flexible viewport management, smooth following, visual effects, and multi-camera support. Cameras determine what portion of the game world is visible and how it's rendered to the screen.

3

4

## Camera Manager

5

6

### Basic Camera Setup

7

Each scene has a camera manager that controls one or more cameras:

8

9

```javascript { .api }

10

class CameraScene extends Phaser.Scene {

11

create() {

12

// Access the main camera

13

const mainCamera = this.cameras.main;

14

15

// Camera properties

16

console.log('Camera position:', mainCamera.scrollX, mainCamera.scrollY);

17

console.log('Camera size:', mainCamera.width, mainCamera.height);

18

console.log('Camera zoom:', mainCamera.zoom);

19

console.log('Camera bounds:', mainCamera.getBounds());

20

21

// Basic camera operations

22

mainCamera.setPosition(100, 50); // Set camera viewport position

23

mainCamera.setSize(600, 400); // Set camera viewport size

24

mainCamera.setScroll(200, 100); // Set world scroll position

25

mainCamera.setZoom(1.5); // Set zoom level

26

mainCamera.setRotation(0.1); // Rotate camera view

27

28

// Camera background

29

mainCamera.setBackgroundColor('#2c3e50');

30

mainCamera.setAlpha(0.8); // Camera transparency

31

mainCamera.setVisible(true); // Camera visibility

32

}

33

}

34

```

35

36

### Multiple Cameras

37

Create and manage multiple cameras for split-screen or UI overlays:

38

39

```javascript { .api }

40

class MultiCameraScene extends Phaser.Scene {

41

create() {

42

// Main camera covers full screen

43

const mainCamera = this.cameras.main;

44

mainCamera.setViewport(0, 0, 800, 600);

45

46

// Add secondary camera for minimap

47

const minimap = this.cameras.add(600, 20, 180, 140);

48

minimap.setZoom(0.2);

49

minimap.setName('minimap');

50

minimap.setBackgroundColor('#000000');

51

52

// Add UI camera that ignores game objects

53

const uiCamera = this.cameras.add(0, 0, 800, 600);

54

uiCamera.setName('ui');

55

56

// Make UI elements only visible to UI camera

57

const healthBar = this.add.rectangle(50, 50, 100, 20, 0xff0000);

58

healthBar.setScrollFactor(0, 0); // Don't scroll with main camera

59

60

// Ignore specific objects on specific cameras

61

mainCamera.ignore(healthBar); // Main camera doesn't render UI

62

uiCamera.ignore([this.player, this.enemies]); // UI camera only renders UI

63

64

// Camera management

65

const cameras = this.cameras.getCamera('minimap');

66

this.cameras.remove(minimap); // Remove camera

67

this.cameras.removeAll(); // Remove all cameras except main

68

69

// Camera iteration

70

this.cameras.cameras.forEach(camera => {

71

console.log('Camera:', camera.name);

72

});

73

}

74

}

75

```

76

77

## Camera Movement

78

79

### Manual Control

80

Directly control camera position and properties:

81

82

```javascript { .api }

83

class CameraControlScene extends Phaser.Scene {

84

create() {

85

this.cameras.main.setScroll(0, 0);

86

87

// Keyboard controls

88

this.cursors = this.input.keyboard.createCursorKeys();

89

this.wasd = this.input.keyboard.addKeys('W,S,A,D');

90

}

91

92

update() {

93

const camera = this.cameras.main;

94

const speed = 5;

95

96

// WASD camera movement

97

if (this.wasd.A.isDown) {

98

camera.scrollX -= speed;

99

} else if (this.wasd.D.isDown) {

100

camera.scrollX += speed;

101

}

102

103

if (this.wasd.W.isDown) {

104

camera.scrollY -= speed;

105

} else if (this.wasd.S.isDown) {

106

camera.scrollY += speed;

107

}

108

109

// Mouse wheel zoom

110

this.input.on('wheel', (pointer, gameObjects, deltaX, deltaY) => {

111

if (deltaY > 0) {

112

camera.zoom = Phaser.Math.Clamp(camera.zoom - 0.1, 0.1, 3);

113

} else {

114

camera.zoom = Phaser.Math.Clamp(camera.zoom + 0.1, 0.1, 3);

115

}

116

});

117

118

// Smooth camera movement with lerp

119

const targetScrollX = this.player.x - 400;

120

const targetScrollY = this.player.y - 300;

121

122

camera.scrollX = Phaser.Math.Linear(camera.scrollX, targetScrollX, 0.05);

123

camera.scrollY = Phaser.Math.Linear(camera.scrollY, targetScrollY, 0.05);

124

}

125

}

126

```

127

128

### Camera Following

129

Make the camera automatically follow game objects:

130

131

```javascript { .api }

132

class CameraFollowScene extends Phaser.Scene {

133

create() {

134

this.player = this.add.sprite(400, 300, 'player');

135

136

// Basic following

137

this.cameras.main.startFollow(this.player);

138

139

// Following with options

140

this.cameras.main.startFollow(

141

this.player, // Target to follow

142

false, // Round pixels

143

0.05, // Lerp X (0 = instant, 1 = never catch up)

144

0.05, // Lerp Y

145

0, // Offset X

146

0 // Offset Y

147

);

148

149

// Set follow offset

150

this.cameras.main.setFollowOffset(-100, -50);

151

152

// Deadzone following (only move when target leaves zone)

153

this.cameras.main.setDeadzone(200, 150);

154

155

// Linear following with specific lerp values

156

this.cameras.main.setLerp(0.1, 0.1);

157

158

// Stop following

159

this.cameras.main.stopFollow();

160

161

// Conditional following

162

this.followActive = true;

163

if (this.followActive) {

164

this.cameras.main.startFollow(this.player, true, 0.08, 0.08);

165

}

166

}

167

168

update() {

169

// Dynamic follow target switching

170

if (this.input.keyboard.addKey('1').isDown) {

171

this.cameras.main.startFollow(this.player);

172

} else if (this.input.keyboard.addKey('2').isDown) {

173

this.cameras.main.startFollow(this.enemy);

174

}

175

176

// Adjust follow based on player state

177

if (this.player.body.velocity.x > 100) {

178

// Look ahead when moving fast

179

this.cameras.main.setFollowOffset(50, 0);

180

} else {

181

this.cameras.main.setFollowOffset(0, 0);

182

}

183

}

184

}

185

```

186

187

### Camera Bounds

188

Constrain camera movement within world boundaries:

189

190

```javascript { .api }

191

class CameraBoundsScene extends Phaser.Scene {

192

create() {

193

// Set world bounds

194

this.physics.world.setBounds(0, 0, 2000, 1200);

195

196

// Set camera bounds (camera won't scroll outside these)

197

this.cameras.main.setBounds(0, 0, 2000, 1200);

198

199

// Camera bounds with centering

200

this.cameras.main.setBounds(0, 0, 2000, 1200, true);

201

202

// Get current bounds

203

const bounds = this.cameras.main.getBounds();

204

console.log('Camera bounds:', bounds);

205

206

// Remove bounds

207

this.cameras.main.removeBounds();

208

209

// Dynamic bounds adjustment

210

this.events.on('levelComplete', () => {

211

// Expand camera bounds for next level

212

this.cameras.main.setBounds(0, 0, 3000, 1500);

213

});

214

}

215

}

216

```

217

218

## Camera Effects

219

220

### Fade Effects

221

Smooth fade in/out transitions:

222

223

```javascript { .api }

224

class CameraFadeScene extends Phaser.Scene {

225

create() {

226

// Fade in from black

227

this.cameras.main.fadeIn(1000); // Duration in ms

228

229

// Fade out to black

230

this.cameras.main.fadeOut(1000);

231

232

// Fade to specific color

233

this.cameras.main.fadeOut(1000, 255, 0, 0); // Fade to red

234

235

// Fade with callback

236

this.cameras.main.fadeOut(1000, 0, 0, 0, (camera, progress) => {

237

if (progress === 1) {

238

console.log('Fade complete');

239

this.scene.start('NextScene');

240

}

241

});

242

243

// Fade events

244

this.cameras.main.on('camerafadeincomplete', () => {

245

console.log('Fade in complete');

246

});

247

248

this.cameras.main.on('camerafadeoutcomplete', () => {

249

console.log('Fade out complete');

250

});

251

252

// Check fade status

253

console.log('Is fading:', this.cameras.main.fadeEffect.isRunning);

254

console.log('Fade progress:', this.cameras.main.fadeEffect.progress);

255

}

256

257

fadeToScene(sceneKey) {

258

this.cameras.main.fadeOut(1000);

259

this.cameras.main.once('camerafadeoutcomplete', () => {

260

this.scene.start(sceneKey);

261

});

262

}

263

}

264

```

265

266

### Flash Effects

267

Screen flash for impact or attention:

268

269

```javascript { .api }

270

class CameraFlashScene extends Phaser.Scene {

271

create() {

272

this.player = this.add.sprite(400, 300, 'player');

273

274

// White flash

275

this.cameras.main.flash(250); // Duration in ms

276

277

// Colored flash

278

this.cameras.main.flash(500, 255, 0, 0); // Red flash

279

280

// Flash with callback

281

this.cameras.main.flash(300, 255, 255, 0, false, (camera, progress) => {

282

if (progress === 1) {

283

console.log('Flash complete');

284

}

285

});

286

287

// Flash events

288

this.cameras.main.on('cameraflashstart', () => {

289

console.log('Flash started');

290

});

291

292

this.cameras.main.on('cameraflashcomplete', () => {

293

console.log('Flash complete');

294

});

295

}

296

297

playerHit() {

298

// Flash red when player takes damage

299

this.cameras.main.flash(200, 255, 0, 0);

300

}

301

302

powerUpCollected() {

303

// Flash yellow when power-up collected

304

this.cameras.main.flash(300, 255, 255, 0);

305

}

306

}

307

```

308

309

### Shake Effects

310

Screen shake for explosions and impacts:

311

312

```javascript { .api }

313

class CameraShakeScene extends Phaser.Scene {

314

create() {

315

this.player = this.add.sprite(400, 300, 'player');

316

317

// Basic shake

318

this.cameras.main.shake(500); // Duration in ms

319

320

// Shake with intensity

321

this.cameras.main.shake(1000, 0.05); // Intensity (0-1)

322

323

// Shake with direction

324

this.cameras.main.shake(300, 0.02, true); // Force horizontal shake

325

326

// Shake with callback

327

this.cameras.main.shake(500, 0.03, false, (camera, progress) => {

328

if (progress === 1) {

329

console.log('Shake complete');

330

}

331

});

332

333

// Shake events

334

this.cameras.main.on('camerashakestart', () => {

335

console.log('Shake started');

336

});

337

338

this.cameras.main.on('camerashakecomplete', () => {

339

console.log('Shake complete');

340

});

341

}

342

343

explosion(x, y) {

344

// Calculate shake intensity based on distance

345

const distance = Phaser.Math.Distance.Between(

346

this.cameras.main.scrollX + 400,

347

this.cameras.main.scrollY + 300,

348

x, y

349

);

350

351

const intensity = Phaser.Math.Clamp(1 - (distance / 500), 0, 0.1);

352

353

if (intensity > 0) {

354

this.cameras.main.shake(300, intensity);

355

}

356

}

357

}

358

```

359

360

### Pan Effects

361

Smooth camera panning to targets:

362

363

```javascript { .api }

364

class CameraPanScene extends Phaser.Scene {

365

create() {

366

this.player = this.add.sprite(100, 300, 'player');

367

this.treasure = this.add.sprite(700, 200, 'treasure');

368

369

// Pan to coordinates

370

this.cameras.main.pan(700, 200, 2000); // x, y, duration

371

372

// Pan with easing

373

this.cameras.main.pan(400, 300, 1500, 'Power2', false, (camera, progress, x, y) => {

374

if (progress === 1) {

375

console.log('Pan complete');

376

}

377

});

378

379

// Pan events

380

this.cameras.main.on('camerapanstart', () => {

381

console.log('Pan started');

382

});

383

384

this.cameras.main.on('camerapancomplete', () => {

385

console.log('Pan complete');

386

});

387

}

388

389

showTreasure() {

390

// Pan to treasure location

391

this.cameras.main.stopFollow(); // Stop following player

392

this.cameras.main.pan(this.treasure.x, this.treasure.y, 1000);

393

394

this.cameras.main.once('camerapancomplete', () => {

395

// Wait a moment then return to player

396

this.time.delayedCall(2000, () => {

397

this.cameras.main.pan(this.player.x, this.player.y, 1000);

398

this.cameras.main.once('camerapancomplete', () => {

399

this.cameras.main.startFollow(this.player);

400

});

401

});

402

});

403

}

404

}

405

```

406

407

### Zoom Effects

408

Smooth camera zooming:

409

410

```javascript { .api }

411

class CameraZoomScene extends Phaser.Scene {

412

create() {

413

this.player = this.add.sprite(400, 300, 'player');

414

415

// Zoom to level

416

this.cameras.main.zoomTo(2, 1000); // Zoom level, duration

417

418

// Zoom with easing and callback

419

this.cameras.main.zoomTo(0.5, 2000, 'Power2', false, (camera, progress, zoom) => {

420

if (progress === 1) {

421

console.log('Zoom complete, final zoom:', zoom);

422

}

423

});

424

425

// Zoom events

426

this.cameras.main.on('camerazoomstart', () => {

427

console.log('Zoom started');

428

});

429

430

this.cameras.main.on('camerazoomcomplete', () => {

431

console.log('Zoom complete');

432

});

433

}

434

435

enterBossArea() {

436

// Zoom out to show boss arena

437

this.cameras.main.zoomTo(0.7, 1500, 'Power2');

438

this.cameras.main.pan(this.bossArena.x, this.bossArena.y, 1500);

439

}

440

441

focusOnPlayer() {

442

// Zoom in for dramatic effect

443

this.cameras.main.zoomTo(1.5, 1000, 'Back.easeOut');

444

}

445

}

446

```

447

448

### Rotation Effects

449

Rotate camera view:

450

451

```javascript { .api }

452

class CameraRotationScene extends Phaser.Scene {

453

create() {

454

this.player = this.add.sprite(400, 300, 'player');

455

456

// Rotate to angle

457

this.cameras.main.rotateTo(0.5, false, 1000); // angle, shortestPath, duration

458

459

// Rotate with easing and callback

460

this.cameras.main.rotateTo(-0.3, true, 2000, 'Sine.easeInOut', false, (camera, progress, angle) => {

461

if (progress === 1) {

462

console.log('Rotation complete, final angle:', angle);

463

}

464

});

465

466

// Rotation events

467

this.cameras.main.on('camerarotatestart', () => {

468

console.log('Rotation started');

469

});

470

471

this.cameras.main.on('camerarotatecomplete', () => {

472

console.log('Rotation complete');

473

});

474

}

475

476

earthquake() {

477

// Random rotation for earthquake effect

478

const angle = Phaser.Math.FloatBetween(-0.1, 0.1);

479

this.cameras.main.rotateTo(angle, false, 100);

480

481

this.cameras.main.once('camerarotatecomplete', () => {

482

this.cameras.main.rotateTo(0, false, 100);

483

});

484

}

485

}

486

```

487

488

## Camera Controls

489

490

### Built-in Camera Controls

491

Phaser provides pre-built camera control schemes:

492

493

```javascript { .api }

494

class CameraControlsScene extends Phaser.Scene {

495

create() {

496

// Smoothed key control

497

const controlConfig = {

498

camera: this.cameras.main,

499

left: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A),

500

right: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D),

501

up: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W),

502

down: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S),

503

zoomIn: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q),

504

zoomOut: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E),

505

acceleration: 0.06,

506

drag: 0.0005,

507

maxSpeed: 1.0,

508

zoomSpeed: 0.02

509

};

510

511

this.controls = new Phaser.Cameras.Controls.SmoothedKeyControl(controlConfig);

512

513

// Fixed key control (immediate response)

514

const fixedConfig = {

515

camera: this.cameras.main,

516

left: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A),

517

right: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D),

518

up: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W),

519

down: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S),

520

speed: 0.5

521

};

522

523

this.fixedControls = new Phaser.Cameras.Controls.FixedKeyControl(fixedConfig);

524

}

525

526

update(time, delta) {

527

// Update camera controls

528

if (this.controls) {

529

this.controls.update(delta);

530

}

531

}

532

}

533

```

534

535

### Custom Camera Controls

536

Create custom camera control systems:

537

538

```javascript { .api }

539

class CustomCameraControlsScene extends Phaser.Scene {

540

create() {

541

this.cameras.main.setZoom(1);

542

543

// Mouse drag camera

544

this.input.on('pointerdown', () => {

545

this.isDragging = true;

546

this.dragStartX = this.input.activePointer.x;

547

this.dragStartY = this.input.activePointer.y;

548

this.cameraStartX = this.cameras.main.scrollX;

549

this.cameraStartY = this.cameras.main.scrollY;

550

});

551

552

this.input.on('pointermove', (pointer) => {

553

if (this.isDragging) {

554

const dragX = pointer.x - this.dragStartX;

555

const dragY = pointer.y - this.dragStartY;

556

557

this.cameras.main.setScroll(

558

this.cameraStartX - dragX,

559

this.cameraStartY - dragY

560

);

561

}

562

});

563

564

this.input.on('pointerup', () => {

565

this.isDragging = false;

566

});

567

568

// Edge scrolling

569

this.input.on('pointermove', (pointer) => {

570

const edgeThreshold = 50;

571

const scrollSpeed = 5;

572

573

if (pointer.x < edgeThreshold) {

574

this.cameras.main.scrollX -= scrollSpeed;

575

} else if (pointer.x > this.game.config.width - edgeThreshold) {

576

this.cameras.main.scrollX += scrollSpeed;

577

}

578

579

if (pointer.y < edgeThreshold) {

580

this.cameras.main.scrollY -= scrollSpeed;

581

} else if (pointer.y > this.game.config.height - edgeThreshold) {

582

this.cameras.main.scrollY += scrollSpeed;

583

}

584

});

585

586

// Touch pinch zoom

587

this.setupPinchZoom();

588

}

589

590

setupPinchZoom() {

591

let initialDistance = 0;

592

let initialZoom = 1;

593

594

this.input.on('pointerdown', (pointer) => {

595

if (this.input.pointer1.isDown && this.input.pointer2.isDown) {

596

initialDistance = Phaser.Math.Distance.Between(

597

this.input.pointer1.x, this.input.pointer1.y,

598

this.input.pointer2.x, this.input.pointer2.y

599

);

600

initialZoom = this.cameras.main.zoom;

601

}

602

});

603

604

this.input.on('pointermove', () => {

605

if (this.input.pointer1.isDown && this.input.pointer2.isDown) {

606

const currentDistance = Phaser.Math.Distance.Between(

607

this.input.pointer1.x, this.input.pointer1.y,

608

this.input.pointer2.x, this.input.pointer2.y

609

);

610

611

const scale = currentDistance / initialDistance;

612

const newZoom = initialZoom * scale;

613

614

this.cameras.main.setZoom(Phaser.Math.Clamp(newZoom, 0.5, 3));

615

}

616

});

617

}

618

}

619

```

620

621

## Advanced Camera Features

622

623

### Camera Culling

624

Optimize performance by culling off-screen objects:

625

626

```javascript { .api }

627

class CameraCullingScene extends Phaser.Scene {

628

create() {

629

// Disable culling for specific objects

630

this.cameras.main.disableCull = false; // Enable culling (default)

631

632

// Objects outside camera view won't be rendered

633

this.backgroundObjects = this.add.group();

634

635

// Force objects to always render (ignore culling)

636

this.ui = this.add.text(10, 10, 'Score: 0');

637

this.ui.setScrollFactor(0); // UI doesn't scroll with camera

638

639

// Custom culling for specific objects

640

this.particles = this.add.particles(0, 0, 'particle');

641

642

// Check if object is visible to camera

643

const isVisible = this.cameras.main.worldView.contains(this.player.x, this.player.y);

644

645

// Get camera world view

646

const worldView = this.cameras.main.worldView;

647

console.log('Camera world view:', worldView);

648

}

649

650

update() {

651

// Manual culling for performance

652

this.backgroundObjects.children.entries.forEach(obj => {

653

const inView = this.cameras.main.worldView.contains(obj.x, obj.y);

654

obj.setVisible(inView);

655

});

656

}

657

}

658

```

659

660

### Camera Masks

661

Use masks to create interesting visual effects:

662

663

```javascript { .api }

664

class CameraMaskScene extends Phaser.Scene {

665

create() {

666

// Create mask shape

667

const maskShape = this.add.graphics();

668

maskShape.fillStyle(0xffffff);

669

maskShape.fillCircle(400, 300, 150);

670

671

// Apply mask to camera

672

const mask = maskShape.createGeometryMask();

673

this.cameras.main.setMask(mask);

674

675

// Bitmap mask

676

const bitmapMask = this.add.image(400, 300, 'maskTexture');

677

const mask2 = bitmapMask.createBitmapMask();

678

this.cameras.main.setMask(mask2);

679

680

// Clear mask

681

this.cameras.main.clearMask();

682

683

// Animate mask

684

this.tweens.add({

685

targets: maskShape,

686

scaleX: 2,

687

scaleY: 2,

688

duration: 2000,

689

yoyo: true,

690

repeat: -1

691

});

692

}

693

}

694

```

695

696

This comprehensive camera system provides all the tools needed to create dynamic, engaging visual experiences with smooth movement, dramatic effects, and flexible viewport management.