Package Exports
- phaser-viewer
- phaser-viewer/test
Readme
Phaser Viewer
A Storybook-like development environment for Phaser 3 components with interactive testing capabilities.
A lightweight Storybook alternative for Phaser 3 game components
โจ Features
| ๐ฎ | Storybook-like UI Hierarchical sidebar with organized component demos |
| ๐งช | Interactive Testing Built-in expect API with visual feedback and play logs |
| ๐ฅ | Hot Reload Instant feedback during development with Vite |
| ๐ฆ | No Setup Required Just create .demo.ts files and run npm command |
| โก | Asset Loading PreloadScene support for centralized asset management |
| ๐ฏ | TypeScript First Full type safety with automatic component and args inference |
๐ฆ Installation
npm install phaser-viewer
# or
yarn add phaser-viewer
# or
pnpm add phaser-viewer๐ Quick Start
1๏ธโฃ Install phaser-viewer
npm install phaser-viewer2๏ธโฃ Create your component demo
Create a .demo.ts file alongside your component:
// src/Button.demo.ts
import { expect, delay } from 'phaser-viewer';
import { Meta, Demo } from 'phaser-viewer';
import { Button } from './Button'; // Import your component
const meta = {
component: Button,
title: 'UI/Button',
description: 'Interactive button component'
} as const satisfies Meta<typeof Button>;
export default meta;
export const BasicButton: Demo<typeof meta> = {
name: 'Basic Button',
args: { x: 400, y: 300, text: 'Click Me!' },
create: (scene: Phaser.Scene, args) => {
return new Button(scene, args.x, args.y, args.text);
},
play: async (scene: Phaser.Scene, component) => {
await expect(component.getText(), 'Initial text').toBe('Click Me!');
// Test interaction
component.emit('pointerdown');
await delay(100);
await expect(component.getText(), 'After click').toBe('Clicked!');
}
};3๏ธโฃ Start the development server
npx phaser-viewer
# or add to package.json scripts:
# "phaser-viewer": "phaser-viewer"That's it! Your Phaser component viewer will start automatically. No React setup files needed!
๐ Project Structure
your-project/
โโโ src/ # Your Phaser components and demos
โ โโโ Button.ts # Button component implementation
โ โโโ Button.demo.ts # Button component demos
โ โโโ Sprite.ts # Sprite component implementation
โ โโโ Sprite.demo.ts # Sprite component demos
โโโ package.json # Include phaser-viewer scriptConfiguration (optional)
Create phaser-viewer.config.ts to customize:
interface PhaserViewerConfig {
filePath: string;
port?: number;
}
const config: PhaserViewerConfig = {
filePath: './src/**/*.demo.ts', // Demo files pattern (default: './src/**/*.demo.ts')
port: 5173 // Development server port (default: 5173)
};
export default config;๐งช Testing Your Components
Phaser Viewer includes a powerful testing API inspired by @storybook/test. Test results appear in the Play Logs panel with visual feedback:
import { expect, delay } from 'phaser-viewer';
export const InteractiveButton: Demo<typeof meta> = {
name: 'Interactive Button',
args: { x: 400, y: 300, text: 'Test Button' },
create: (scene: Phaser.Scene, args) => {
return new Button(scene, args.x, args.y, args.text);
},
play: async (scene: Phaser.Scene, component) => {
// Test initial state
await expect(component.getText(), 'Initial text').toBe('Test Button');
await expect(component.visible, 'Should be visible').toBe(true);
// Test button click
component.emit('pointerdown');
await delay(100);
await expect(component.getText(), 'After click').toBe('Clicked!');
// Test multiple clicks
component.emit('pointerdown');
await delay(100);
await expect(component.getText(), 'After second click').toBe('Clicked 2x');
}
};โก Asset Loading with PreloadScene
For components that require assets (images, sounds, etc.), you can create a PreloadScene class to handle asset loading:
1๏ธโฃ Create a PreloadScene class
// src/GoldPreloadScene.ts
import * as Phaser from 'phaser';
export class GoldPreloadScene extends Phaser.Scene {
constructor() {
super({ key: 'GoldPreloadScene' });
}
preload() {
// Load all assets your component needs
this.load.image('gold', 'img/gold.png');
this.load.image('silver', 'img/silver.png');
this.load.audio('coinSound', 'audio/coin.mp3');
}
}2๏ธโฃ Reference the PreloadScene in your demo
// src/Gold.demo.ts
import { Meta, Demo } from 'phaser-viewer';
import { Gold } from './Gold';
import { GoldPreloadScene } from './GoldPreloadScene';
const meta = {
component: Gold,
title: 'Sprites/Gold',
description: 'Gold coin sprite with preloaded assets',
preloadScene: GoldPreloadScene // โ Add this line
} as const satisfies Meta<typeof Gold>;
export default meta;
export const BasicGold: Demo<typeof meta> = {
name: 'Basic Gold Coin',
args: { x: 400, y: 300 },
create: (scene: Phaser.Scene, args) => {
// Assets are already loaded and available!
return new Gold(scene, args.x, args.y);
}
};3๏ธโฃ Use assets in your component
// src/Gold.ts
export class Gold extends Phaser.GameObjects.Sprite {
constructor(scene: Phaser.Scene, x: number, y: number) {
// The 'gold' texture is already loaded by GoldPreloadScene
super(scene, x, y, 'gold');
scene.add.existing(this);
// You can also use other preloaded assets
this.setInteractive();
this.on('pointerdown', () => {
scene.sound.play('coinSound'); // Audio is also preloaded
});
}
}How it works
- PreloadScene starts first - Phaser Viewer automatically detects and runs your PreloadScene
- Assets are loaded - All assets defined in
preload()method are loaded into memory - ViewerScene launches - After loading completes, the viewer scene starts
- Assets are available - Your components can immediately use the preloaded assets
This ensures smooth component rendering without loading delays or missing asset errors.
๐ ๏ธ Commands
npx phaser-viewer- Start development servernpx phaser-viewer --port 3000- Start on custom portnpx phaser-viewer --help- Show help
๐ฏ Best Practices
๐ Testing Guidelines
- Use descriptive test names for better debugging
- Test component properties and interactions separately
- Use
delay()for timing-dependent operations - Leverage
step()for organized test flow
๐ File Organization
- Keep
.demo.tsfiles close to component files - Use hierarchical titles (
UI/Button,Sprites/Gold) for better organization - Create PreloadScenes for asset-heavy components
โก Performance Tips
- PreloadScenes run once per story group - keep them lightweight
- Use
delay()sparingly - only when necessary for timing - Test real interactions rather than just component creation
๐ License
MIT License
๐ค Contributing
Contributions, issues and feature requests are welcome! Feel free to check issues page or contribute to the GitHub repository.
Phaser 3 โข React โข TypeScript