# Pixeldex · Phaser Pixel-Perfect Camera Starter

A complete Phaser 3 + TypeScript + Vite project that demos the pixel-perfect camera in action. Run `npm install` + `npm run dev` and you've got a playable scene with deadzone-follow camera, all pixel-perfect.

License: **CC0**.
Source: https://pixeldex.dev/prompts/phaser-pixel-perfect-camera

---

## What's in this folder

| File | Purpose |
|---|---|
| `src/PixelCamera.ts` | The camera helper class. Drop into any Phaser project. |
| `src/main.ts` | A demo scene showing camera-following-a-player with arrow-key movement. |
| `index.html` | Entry page (Vite picks this up). |
| `package.json` | Phaser 3.70+ and Vite as dev dep. |
| `vite.config.ts` | Configured with `base: './'` so itch.io uploads work. |
| `tsconfig.json` | Strict TypeScript. |

---

## Fastest path (~2 minutes)

```bash
cd phaser-pixel-camera-starter
npm install
npm run dev
```

Opens `http://localhost:5173`. Use arrow keys to move the pink square. The camera follows with a deadzone (you can move freely inside ~80px before the camera chases). All scrolling is pixel-perfect.

To ship: `npm run build` produces `dist/`. Zip that folder, upload to itch.io as a browser-playable HTML game.

---

## Using just the camera in your existing project

If you already have a Phaser project, just copy `src/PixelCamera.ts` into it.

```ts
import { PixelCamera } from './PixelCamera';

class GameScene extends Phaser.Scene {
 private pixelCam!: PixelCamera;
 private player!: Phaser.GameObjects.Sprite;

 create() {
 this.player = this.add.sprite(0, 0, 'player');
 this.pixelCam = new PixelCamera(this, this.player, {
 deadzoneWidth: 80,
 deadzoneHeight: 60,
 lerp: 0.1,
 });
 }

 update(time: number, delta: number) {
 this.pixelCam.update(time, delta);
 }
}
```

---

## How it works

Two things together make sprites pixel-perfect:

1. **`camera.roundPixels = true`** (set once on creation). This tells Phaser to snap individual rendered objects to integer pixel coords.
2. **`Math.floor(scrollX/scrollY)`** every frame after the lerp. This snaps the CAMERA itself to integer pixel coords.

Without step 2, the lerp produces fractional camera positions (e.g. `scrollX = 123.45`), which means everything else gets rendered at a fractional offset, and `roundPixels` only rounds individual sprites, not the camera. The combination eliminates sub-pixel jitter entirely.

---

## Tunable options

```ts
new PixelCamera(scene, target, {
 deadzoneWidth: 80, // Half-width of dead zone in pixels
 deadzoneHeight: 60, // Half-height of dead zone in pixels
 lerp: 0.1, // Chase strength: lower = looser follow, higher = snappier
});
```

`lerp` is frame-rate independent, internally it adjusts for the actual `delta` so the camera feels the same at 30fps and 144fps.

---

## Pairing ideas

- Use with [the Phaser web game walkthrough](https://pixeldex.dev/walkthroughs/ship-a-phaser-web-game-in-an-evening) to add a moving camera to the arcade dodger.
- Pair with the [sprite generator](https://pixeldex.dev/tools/sprite-generator/) for art that benefits from pixel-perfect scaling.

---

If you ship something with this, a link to https://pixeldex.dev helps. Not required.
