Project Setup
Set up a Phaser 3 project with Vite, TypeScript, and modern development tooling.
What you'll accomplish
Have a working Phaser development environment with hot reload.
Prerequisites
- Node.js 18+ installed
- Basic terminal knowledge
- Completed "What is Phaser?" lesson
Project Setup Options
You can set up a Phaser project in several ways:
| Method | Pros | Cons |
|---|---|---|
| Vite + TypeScript | Fast, modern, type safety | Requires build step |
| Phaser template | Ready to go | Less flexibility |
| CDN script tag | Simplest | No modules, no types |
We'll use Vite + TypeScript - the professional approach with the best developer experience.
Step 1: Create Project
Create a new Vite project:
bashnpm create vite@latest my-phaser-game -- --template vanilla-ts cd my-phaser-game
This creates a basic TypeScript project. We'll add Phaser next.
Step 2: Install Phaser
bashnpm install phaser
Step 3: Clean Up Template
Delete the template files we don't need:
Step 4: Update HTML
Replace index.html:
html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>My Phaser Game</title> <style> * { margin: 0; padding: 0; } body { background-color: #000; display: flex; justify-content: center; align-items: center; min-height: 100vh; } canvas { display: block; } </style> </head> <body> <script type="module" src="/src/main.ts"></script> </body> </html>
Step 5: Create Game Entry Point
Replace src/main.ts:
typescriptimport Phaser from 'phaser'; import { MainScene } from './scenes/MainScene'; const config: Phaser.Types.Core.GameConfig = { type: Phaser.AUTO, width: 800, height: 600, backgroundColor: '#2d2d2d', parent: 'game-container', physics: { default: 'arcade', arcade: { gravity: { x: 0, y: 0 }, debug: true, // Set to false for production }, }, scene: [MainScene], }; new Phaser.Game(config);
type: Phaser.AUTO- Automatically choose WebGL or Canvaswidth: 800, height: 600- Game resolution in pixelsbackgroundColor- Color shown when nothing else is drawnphysics.default: 'arcade'- Simple physics engine for most gamesphysics.arcade.debug: true- Show collision boxes (helpful for development)scene: [MainScene]- Which scenes to load
Step 6: Create Your First Scene
Create src/scenes/MainScene.ts:
typescriptimport Phaser from 'phaser'; export class MainScene extends Phaser.Scene { constructor() { super('MainScene'); } preload(): void { // We'll load assets here later } create(): void { // Create game objects const text = this.add.text(400, 300, 'Hello Phaser!', { fontSize: '32px', color: '#ffffff', }); text.setOrigin(0.5, 0.5); // Center the text // Log to confirm it's working console.log('MainScene created!'); } update(): void { // Game loop - runs 60x per second // We'll add game logic here } }
Step 7: Run the Development Server
bashnpm run dev
Open http://localhost:5173 in your browser. You should see "Hello Phaser!" on a gray background.
Tip
Vite provides hot reload - changes to your code appear instantly without refreshing!
Project Structure
Your project should look like:
my-phaser-game/
├── public/ # Static assets (images, sounds)
├── src/
│ ├── scenes/ # Game scenes
│ │ └── MainScene.ts
│ ├── main.ts # Entry point
│ └── vite-env.d.ts # TypeScript Vite types
├── index.html
├── package.json
├── tsconfig.json
└── vite.config.ts
Adding Assets
Download Sample Assets
For testing, download some free assets. Create a public/assets folder:
bashmkdir -p public/assets
For now, let's create a simple colored square programmatically.
Update MainScene.ts:
typescriptimport Phaser from 'phaser'; export class MainScene extends Phaser.Scene { private player!: Phaser.GameObjects.Rectangle; constructor() { super('MainScene'); } preload(): void { // No external assets yet } create(): void { // Create a simple rectangle as our player this.player = this.add.rectangle(400, 300, 50, 50, 0x00ff00); // Make it a physics object this.physics.add.existing(this.player); // Add some text this.add.text(400, 50, 'Use Arrow Keys to Move', { fontSize: '24px', color: '#ffffff', }).setOrigin(0.5); } update(): void { const cursors = this.input.keyboard?.createCursorKeys(); if (!cursors) return; const body = this.player.body as Phaser.Physics.Arcade.Body; const speed = 200; // Reset velocity body.setVelocity(0); // Handle input if (cursors.left.isDown) { body.setVelocityX(-speed); } else if (cursors.right.isDown) { body.setVelocityX(speed); } if (cursors.up.isDown) { body.setVelocityY(-speed); } else if (cursors.down.isDown) { body.setVelocityY(speed); } } }
Now you have a green square you can move with arrow keys!
TypeScript Configuration
The default tsconfig.json works, but here's an optimized version:
json{ "compilerOptions": { "target": "ES2020", "useDefineForClassFields": true, "module": "ESNext", "lib": ["ES2020", "DOM", "DOM.Iterable"], "skipLibCheck": true, "moduleResolution": "bundler", "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, "include": ["src"] }
Vite Configuration
Create vite.config.ts:
typescriptimport { defineConfig } from 'vite'; export default defineConfig({ base: './', // Relative paths (important for deployment) build: { outDir: 'dist', assetsDir: 'assets', sourcemap: false, }, server: { port: 5173, open: true, // Auto-open browser }, });
npm Scripts
Add useful scripts to package.json:
json{ "scripts": { "dev": "vite", "build": "tsc && vite build", "preview": "vite preview", "typecheck": "tsc --noEmit" } }
| Script | Purpose |
|---|---|
npm run dev | Start development server |
npm run build | Build for production |
npm run preview | Preview production build |
npm run typecheck | Check for TypeScript errors |
Common Issues
Frequently Asked Questions
Make sure you installed Phaser:
bashnpm install phaser
Then restart the dev server.
Check the browser console for errors. Common causes:
- Scene name mismatch
- Missing scene in config
- JavaScript error in create()
Click on the game canvas first! The canvas needs focus to receive keyboard events.
Make sure @types/phaser isn't installed - Phaser includes its own types. If installed, remove it:
bashnpm uninstall @types/phaser
Put images in public/assets/ and load them in preload():
typescriptpreload() { this.load.image('player', 'assets/player.png'); }
Verify Your Understanding
You've completed this lesson if you can:
Next: Learn about scenes and the game loop in depth.