Spaces:
Running on Zero
A newer version of the Gradio SDK is available: 6.20.0
Phaser 3 Game Template
A standardized Phaser 3 game template for rapid 2D web game development. This template provides a consistent architecture and pre-built components that AI coding agents can use to generate games efficiently.
Quick Start
# Install dependencies
npm install
# Start development server
npm run dev
# Build for production
npm run build
Project Structure
src/
βββ main.ts # Game entry point & Phaser configuration
βββ gameConfig.json # All game parameters (health, speed, damage, etc.)
βββ LevelManager.ts # Level flow management
βββ utils.ts # CRITICAL utility functions (DO NOT MODIFY)
βββ characters/ # Player and enemy classes
β βββ ExamplePlayer.ts # Template - copy then delete/rename
β βββ ExampleEnemy.ts # Template - copy then delete/rename
βββ scenes/
β βββ Preloader.ts # Asset loading (STANDARD - minimal changes)
β βββ TitleScreen.ts # Start screen (customize UI only)
β βββ BaseLevelScene.ts # Optional level base class
β βββ UIScene.ts # In-game HUD
β βββ VictoryUIScene.ts # Level complete screen
β βββ GameOverUIScene.ts # Death/failure screen
β βββ GameCompleteUIScene.ts # All levels complete screen
βββ styles/
β βββ tailwind.css # Tailwind CSS for UI styling
βββ test/
βββ setup.ts # Test configuration
public/assets/
βββ asset-pack.json # Asset manifest for Preloader
βββ animations.json # Animation definitions with origin data
Key Files Reference
main.ts
- Configures Phaser game instance
- Imports and registers all scenes in order:
- Preloader (auto-start)
- TitleScreen
- Level scenes
- UI scenes
gameConfig.json
All game parameters use { "value": X } wrapper format (self-documenting):
{
"configGroup": {
"parameterName": {
"value": 100,
"type": "number",
"description": "What this does"
}
}
}
Access in code: configGroup.parameterName.value
utils.ts - CRITICAL FUNCTIONS
DO NOT MODIFY these functions. They solve Phaser quirks.
| Function | Usage |
|---|---|
initScale() |
ALWAYS use for sprite scaling. Never use setScale() directly. |
resetOriginAndOffset() |
ALWAYS call after play() animation. |
initUIDom() |
ALWAYS use for UI scene DOM elements. |
addCollider() / addOverlap() |
ALWAYS use instead of scene.physics.add.collider/overlap. |
createTrigger() |
Create attack/detection zones. |
updateMeleeTrigger() |
Update melee attack zone position. |
createDecoration() |
Create decorative elements. |
computeRotation() |
Calculate projectile rotation. |
LevelManager.ts
Manages level progression:
// Add your level scene keys here
static readonly LEVEL_ORDER: string[] = [
"Level1Scene",
"Level2Scene",
// ...
];
Animation Format (animations.json)
{
"anims": [
{
"key": "player_idle_anim",
"type": "frame",
"frames": [
{ "key": "player_idle_01", "duration": 400 } // idle: 1 frame only
],
"repeat": -1,
"originX": 0.5,
"originY": 1.0
},
{
"key": "player_run_anim",
"type": "frame",
"frames": [
{ "key": "player_run_01", "duration": 400 }, // run: 2 frames
{ "key": "player_run_02", "duration": 400 }
],
"repeat": -1,
"originX": 0.5,
"originY": 1.0
}
]
}
Important: originX and originY are REQUIRED for utils.resetOriginAndOffset() to work correctly. Different animations may have different origins (e.g., attack animations often shift left/right).
Asset Pack Format (asset-pack.json)
{
"assetPack": {
"files": [
{ "type": "json", "key": "animations", "url": "assets/animations.json" },
{
"type": "image",
"key": "player_idle_01",
"url": "assets/player_idle_01.png"
},
{
"type": "image",
"key": "player_run_01",
"url": "assets/player_run_01.png"
},
{
"type": "image",
"key": "player_run_02",
"url": "assets/player_run_02.png"
},
{
"type": "tilemapTiledJSON",
"key": "level1_map",
"url": "assets/level1_map.json"
}
]
}
}
Creating a New Game
1. Define Game Config
Edit gameConfig.json to add your game's parameters.
2. Create Player Class
Copy ExamplePlayer.ts to create your player (e.g., Player.ts), then delete ExamplePlayer.ts:
- Load config values
- Implement movement in
update() - Implement
takeDamage()anddie() - Add animations
3. Create Enemy Classes
Copy ExampleEnemy.ts for each enemy type (e.g., EnemySoldier.ts), then delete ExampleEnemy.ts:
- Configure stats
- Implement AI in
executeAI() - Add unique behaviors
4. Create Level Scenes
Either extend BaseLevelScene or create from scratch:
export class Level1Scene extends BaseLevelScene {
constructor() {
super({ key: 'Level1Scene' });
}
create() {
this.createBaseElements();
// Level-specific setup
}
update(time, delta) {
this.baseUpdate(time, delta);
// Level-specific updates
}
// Implement abstract methods...
}
5. Register Levels
- Import in
main.ts - Add to
game.scene.add() - Add key to
LevelManager.LEVEL_ORDER
6. Customize UI
Modify the createDOMUI() methods in:
TitleScreen.ts- Start screen designUIScene.ts- In-game HUD- Victory/GameOver scenes - End screens
Standard Dimensions
| Element | Standard Height | Notes |
|---|---|---|
| Player | 128px | Standard human-sized character |
| Small enemy | 48-64px | Knee to waist height |
| Medium enemy | 80-100px | Slightly smaller than player |
| Large enemy/Boss | 150-256px | 1.5x to 2x player size |
| Tile size | 64px | Standard tile dimension |
UI Styling
UI uses Tailwind CSS with custom pixel-art styled components:
game-pixel-container-*- Pixel-styled containersgame-pixel-container-slot-*- Progress bar backgroundsgame-pixel-container-progress-fill-*- Progress bar fillsgame-pixel-container-clickable-*- Clickable buttons
Scene Lifecycle
- Preloader β Loads all assets
- TitleScreen β Press Enter to start
- Level1Scene + UIScene (parallel) β Gameplay
- On victory: VictoryUIScene β Next level OR GameCompleteUIScene β Title
- On death: GameOverUIScene β Restart level
Common Patterns
Playing Animations
// CORRECT - always use this pattern
playAnimation(animKey: string): void {
this.play(animKey, true);
utils.resetOriginAndOffset(this, this.facingDirection);
}
Scaling Sprites
// CORRECT - always use initScale
utils.initScale(
sprite,
{ x: 0.5, y: 1.0 }, // origin
undefined, // maxWidth (optional)
128, // maxHeight
0.6, // body width factor
0.85, // body height factor
);
// WRONG - never do this
sprite.setScale(2);
sprite.setDisplaySize(100, 100);
Adding Collisions
// CORRECT - guaranteed parameter order
utils.addCollider(this, player, enemies, (player, enemy) => {
player.takeDamage(enemy.damage);
});
// WRONG - parameter order may be swapped
this.physics.add.collider(player, enemies, callback);
Development Tips
- Always test animations - Make sure
originX/Yin animations.json are correct - Use groups - Add enemies/decorations to groups for easy management
- Check health - Use
getHealthPercentage()for UI updates - Clean up events - Always remove event listeners in
cleanupEventListeners() - Prevent double-triggers - Use flags like
isStarting,isRestarting
License
MIT