JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 20
  • Score
    100M100P100Q28032F
  • License MIT

A Storybook-like development environment for Phaser 3 components with interactive testing

Package Exports

  • phaser-viewer
  • phaser-viewer/test

Readme

Phaser Viewer Icon

Phaser Viewer

A Storybook-like development environment for Phaser 3 components with interactive testing capabilities.

Version 0.1.2 Phaser 3.90.0 TypeScript 5.9+ Node.js 18+ MIT License

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-viewer

2๏ธโƒฃ 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 script

Configuration (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

  1. PreloadScene starts first - Phaser Viewer automatically detects and runs your PreloadScene
  2. Assets are loaded - All assets defined in preload() method are loaded into memory
  3. ViewerScene launches - After loading completes, the viewer scene starts
  4. 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 server
  • npx phaser-viewer --port 3000 - Start on custom port
  • npx 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.ts files 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