npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dreams-engine/engine

v1.0.2

Published

A lightweight set of PixiJS v8 application extensions and utilities that add:

Readme

@dreams-engine/engine

A lightweight set of PixiJS v8 application extensions and utilities that add:

  • Core application helpers (events bus, registry map, lifecycle controls)
  • Localization (i18next integration with live text binding)
  • Styled logger for structured, readable console output
  • A static application registry to manage multiple PIXI.Application instances

Works as class-based PixiJS extensions; add them once and they augment every Application you create.

Installation

npm i @dreams-engine/engine

Quick Start

import { Application, extensions } from 'pixi.js';
import { CorePlugin, LocalizationPlugin, Logger, LocalizationOptions } from '@dreams-engine/engine';

// 1) Register PixiJS extensions once in your app's entry
extensions.add(CorePlugin, LocalizationPlugin);

async function main() {
  const app = new Application();
  await app.init({
    background: '#20242a',
    resizeTo: window,
    // Enable engine debug features
    debug: { pixiExtension: true, log: true },
    // Localization configuration
    localization: {
      lng: 'en',            // initial language
      fallbackLng: 'en',
      langPath: 'locales',  // where your JSON files are served from
      debug: true           // warns on missing keys
    } as LocalizationOptions,
  });

  document.body.appendChild(app.canvas);

  // Initialize localization service once
  await app.lang.init();

  // Try the logger
  Logger.info('Engine initialized');
}

main();

Features & Examples

CorePlugin

Adds helpers to every PIXI.Application:

  • events: An EventEmitter for app-level events.
  • registry: A Map<string, any> for simple data sharing.
  • pause/resume: Control the ticker.
  • show/hide: Toggle canvas visibility.
  • debug options: debug.log toggles the engine Logger, debug.pixiExtension exposes the current app at globalThis.__PIXI_APP__.

Example: events and registry

import { Application, extensions } from 'pixi.js';
import { CorePlugin, Logger } from '@dreams-engine/engine';

extensions.add(CorePlugin);

const app = new Application();
await app.init({ debug: { pixiExtension: true, log: true } });

// events
app.events.on('game:start', ({ level }) => Logger.log('Starting level', level));
app.events.emit('game:start', { level: 1 });

// registry
app.registry.set('playerName', 'Alice');
Logger.info('Player:', app.registry.get('playerName'));

// lifecycle
app.pause();
app.resume();
app.hide();
app.show();

LocalizationPlugin + LocalizationService

Provides app.lang with i18next under the hood. Loads JSON resources via PIXI.Assets and supports live text binding.

Files structure (example):

public/
  locales/
    en.json
    tr.json

Example: initialize and translate

import { Application, Text, extensions } from 'pixi.js';
import { LocalizationPlugin, LocalizationOptions } from '@dreams-engine/engine';

extensions.add(LocalizationPlugin);

const app = new Application();
await app.init({
  localization: { lng: 'en', fallbackLng: 'en', langPath: 'locales', debug: true } as LocalizationOptions
});

await app.lang.init();

const label = new Text({ text: app.lang.t('welcome_message'), style: { fill: 0xffffff, fontSize: 32 } });
app.stage.addChild(label);

Example: bind live text updates and change language

const scoreText = new Text({ text: '', style: { fill: 0xffff00, fontSize: 20 } });
app.stage.addChild(scoreText);
app.lang.bind(scoreText, 'score_label', { count: 0 });  // binds to key

// Later: update language at runtime
await app.lang.changeLanguage('tr');

// Add or remove bundles dynamically
app.lang.addBundle('en', 'translation', { dynamic_key: 'Hello Dynamic' }, true, true);
app.lang.removeBundle('en', 'translation');

Notes:

  • Set localization.langPath to the folder where your language files are served from.
  • If localization.debug is true, missing keys log a warning in the console.

Logger

A small, styled console logger. Enabled/disabled by CorePlugin via ApplicationOptions.debug.log.

Methods: log, info, warn, error, debug, trace, assert, table, dir.

Example:

import { Logger } from '@dreams-engine/engine';

Logger.log('Hello');
Logger.info('Loaded scene:', { id: 1 });
Logger.warn('Missing config, using defaults');
Logger.error('Failed to load asset');
Logger.debug('State:', { x: 10, y: 42 });
Logger.trace('Step');
Logger.assert(2 + 2 === 4, 'Math holds');
Logger.table([{ id: 1 }, { id: 2 }]);
Logger.dir({ deep: { nested: true } });

ApplicationRegistry

Manage multiple PIXI.Application instances from one place. The first app you register becomes the "master" app.

Example:

import { Application } from 'pixi.js';
import { ApplicationRegistry } from '@dreams-engine/engine';

const main = new Application();
await main.init({ background: '#000' });
ApplicationRegistry.addApp('main', main);

await (async () => {
  const overlay = new Application();
  await overlay.init({ background: 'transparent' });
  ApplicationRegistry.addApp('overlay', overlay);
})();

// Access anywhere
const app = ApplicationRegistry.getApp('main');
app.stage.removeChildren();

// Destroy when done
ApplicationRegistry.destroyApp('overlay');
ApplicationRegistry.destroyAllApps();

#### Master Application
- The first `addApp(id, app)` call marks that app as the master.
- Retrieve it anywhere via `ApplicationRegistry.getMaster()`.
- If the master app is destroyed (`destroyApp(masterId)` or `destroyAllApps()`), the master reference is cleared and `getMaster()` throws until a new app is added.

Example: use master as a shared event hub
```ts
import { ApplicationRegistry } from '@dreams-engine/engine';

// Overlay app finishes a Big Win animation
const master = ApplicationRegistry.getMaster();
master.events.emit('bigwin:finished', { amount: 1234 });

// Elsewhere (e.g., state machine bridge)
master.events.on('bigwin:finished', ({ amount }) => {
  // advance flow, show summary, etc.
});

## Types & Augmentations
The package augments PixiJS types so you get proper IntelliSense and type safety:

- `ApplicationOptions.localization?: LocalizationOptions`
- `ApplicationOptions.debug?: boolean | { pixiExtension?: boolean; log?: boolean }`
- `ApplicationOptions.animations?: Array<{ type: 'sprite'|'animatedSprite'|'spine'|'text'|'bitmapText'|'tween'; name: string; def: any }>| string`
- `Application.events: EventEmitter`
- `Application.registry: Map<string, any>`
- `Application.pause/resume/show/hide()`
- `Application.lang: LocalizationService`
- `Application.animations: AnimationPlugin`

See `src/global.d.ts` for the exact declarations.

### GameObjectFactory
Create Pixi display objects with typed options, build scenes from JSON, and load prefabs via `PIXI.Assets`.

- Methods: `container`, `sprite`, `text`, `graphics`, `animatedSprite`, `sprite-nine-slice` (`nineSliceSprite`), `sprite-tiling` (`tilingSprite`), `text-bitmap` (`bitmapText`), `particle-container` (`particleContainer`), `mesh`, `spine`.
- Extras: i18n binding for `text`/`bitmapText` via `keyword`/`keywordOpts` when `LocalizationPlugin` is active.
- JSON builder: `fromJson(defs, parent?)` with `type`, optional `label`, `ignore`, `children`.
- Prefabs: `prefab(id, opts?, parent?, ignore?)` loads JSON and instantiates.

Register and basic usage
```ts
import { extensions } from 'pixi.js';
import { GameObjectFactory } from '@dreams-engine/engine';

extensions.add(GameObjectFactory);

const container = app.create.container({ x: 100, y: 50 }, app.stage);
const logo = app.create.sprite({ texture: 'logo', anchor: 0.5, x: 200, y: 120 }, container);

// i18n-bound text (auto-updates on language changes)
const title = app.create.text({ keyword: 'welcome_message', style: { fontSize: 36, fill: 0xffffff } }, container);

Build from JSON

const defs = [
  { type: 'container', label: 'root', x: 0, y: 0, children: [
    { type: 'sprite', texture: 'logo', anchor: 0.5, x: 320, y: 120 },
    { type: 'text', keyword: 'current_language', style: { fontSize: 20, fill: 0xffff00 }, x: 320, y: 200 },
  ]}
];
const { rootNodes, sceneMap } = app.create.fromJson(defs, app.stage);

Prefabs

// Serve JSON under your public directory (e.g., /prefabs/ui.json)
const { rootNode, sceneMap } = await app.create.prefab('/prefabs/ui.json', { x: 0, y: 0 }, app.stage);

Notes

  • Texture fields accept alias/URL/Texture. The factory normalizes these via a resolver so sprites always receive a valid Texture.
  • Property application uses PIXI.utils.assignWithIgnore and skips meta fields (children, type, label, keyword, keywordOpts, etc.).
  • For spine, preload the skeleton or add it to PIXI.Assets and reference with spineAssetId.

Audio Plugin

Layered audio control built on top of @pixi/sound and exposed as app.audio.

  • Layers: logical buckets like bgm, sfx, ui. Add custom layers as needed.
  • Master: global volume (sound.volumeAll) and global mute/unmute helpers.
  • Layer control: per-layer volume/mute, stop/pause/resume all instances.

Register and configure

import { extensions } from 'pixi.js';
import { AudioPlugin } from '@dreams-engine/engine';

extensions.add(AudioPlugin);

await app.init({
  audio: { layers: ['bgm','sfx'], masterVolume: 0.8 }
});

Load sounds and play

import { sound } from '@pixi/sound';

// Add sounds (alias → URL)
sound.add('bgm', '/audio/bgm.mp3');
sound.add('click', '/audio/click.mp3');

// Start looping BGM on its layer
app.audio.bgm.play('bgm', { loop: true, volume: 0.3, singleInstance: true });

// Fire SFX when needed
app.audio.sfx.play('click', { volume: 0.9 });

// Master and layers
app.audio.setMasterVolume(0.7);
app.audio.muteAll();
app.audio.unmuteAll();
app.audio.getLayer('ui').setVolume(0.5);

Manifest-based loading (optional)

// public/manifest.json
{
  "bundles": [
    {
      "name": "audio",
      "assets": [
        { "alias": "bgm",   "src": "/audio/bgm.mp3" },
        { "alias": "click", "src": "/audio/click.mp3" }
      ]
    }
  ]
}
Assets.init({ manifest: '/manifest.json' });
await Assets.loadBundle('audio');
app.audio.sfx.play('click');

Animation Plugin (Registry)

Type-based animation registry exposed as app.animations. Lets you register reusable animations (sprite/animatedSprite/spine/text/bitmapText/tween) and apply them to any target.

Register

import { extensions } from 'pixi.js';
import { AnimationPlugin } from '@dreams-engine/engine';

extensions.add(AnimationPlugin);

Init-time bulk (optional)

await app.init({
  animations: [
    { type: 'tween', name: 'pulse', def: { gsap: { scale: 1.2, yoyo: true, repeat: 3, duration: 0.2 } } },
    { type: 'animatedSprite', name: 'idle', def: { generator: { prefix: 'f_', startIndex: 1, stopIndex: 4, pad: 2, suffix: '.png' }, fps: 12, loop: true } },
  ]
});
// Or from a bundle id (Assets.load) that returns either an array or a typed map
await app.animations.ready(); // wait for any in-flight bulk load

Manual registration

// sprite: texture swap + optional gsap tween + restore
app.animations.set('sprite', 'swap', { toTexture: 'atlas::icon_on', durationMs: 150, restore: true });

// animatedSprite: frames via generator or explicit list + fps
app.animations.set('animatedSprite', 'spin', { generator: { prefix: 'reel_', startIndex: 1, stopIndex: 10, pad: 2, suffix: '.png' }, fps: 24, loop: true });

// spine: animation name + speed + track
app.animations.set('spine', 'win', { anim: 'bigwin', loop: false, speed: 1 });

// text/bitmapText: content swap + duration/gsap
app.animations.set('text', 'flash', { text: 'READY!', durationMs: 300 });

// tween: generic gsap tween reusable on any DisplayObject
app.animations.set('tween', 'float', { gsap: { y: '-=10', yoyo: true, repeat: -1, duration: 0.8 } });

Applying animations

// sprite
const ctrl1 = app.animations.apply('sprite', 'swap', mySprite);
await ctrl1.finished; // resolves on completion or stop()
ctrl1.stop();

// animatedSprite
const ctrl2 = app.animations.apply('animatedSprite', 'spin', myAnimatedSprite);
// later
ctrl2.stop();

// spine
app.animations.apply('spine', 'win', mySpine);

// text
app.animations.apply('text', 'flash', myText);

// generic tween (works on any DisplayObject)
app.animations.apply('tween', 'float', myContainer);

Notes

  • fps maps to Pixi animationSpeed ≈ fps/60.
  • generator builds frame names using { prefix, suffix, startIndex, stopIndex, pad }.
  • sprite.restore=true restores the previous texture on completion/stop.
  • load(defsOrBundleId) and ready() help with async bulk registration.
  • If GSAP isn't present, sprite/text can fallback to durationMs timeout; other types no-op the tween.

Navigation Plugin

High-level screen navigation system inspired by Pixi Create.

  • Screens: simple classes extending PIXI.Container (or any Container) implementing optional hooks: prepare, show, hide, pause, resume, resize, update, blur, focus, onLoad(progress).
  • Asset preload: declare static assetBundles: string[] on your screen ctor to preload via PIXI.Assets before showing.
  • Background + current + popup: supports a persistent background screen and a single popup over the current screen.

Register

import { extensions } from 'pixi.js';
import { NavigationPlugin } from '@dreams-engine/engine';

extensions.add(NavigationPlugin);

Define a screen

import { Container } from 'pixi.js';

class MenuScreen extends Container {
  // Optional: preload bundles before first creation
  static assetBundles = ['ui'];
  // Optional: one-time async creation for heavy prefab setup
  async create() {
    // E.g., await GameObjectFactory.prefab('menu-root', this);
  }
  prepare() {/* layout elements */}
  async show() {/* run intro tween */}
  async hide() {/* run outro tween */}
  resize(w:number,h:number) {/* reposition */}
}

Use it

// set a persistent background (optional)
await app.navigation.setBackground(MenuScreen);

// show a screen
await app.navigation.showScreen(MenuScreen);

// present/dismiss a popup
await app.navigation.presentPopup(ModalScreen);
await app.navigation.dismissPopup();

// resize propagation is wired to ResizePlugin automatically

Load screen from JSON

// From JSON file path
const { screen, sceneMap } = await app.navigation.showScreenFromJson('scenes/main-menu.json');

// Access elements via sceneMap
const title = sceneMap.get('menuContainer/title');
title.text = 'Welcome!';

// Or pass JSON directly
const { screen, sceneMap } = await app.navigation.showScreenFromJson({
  assetBundles: ['ui', 'backgrounds'],
  metadata: { name: 'MainMenu', version: '1.0' },
  elements: [
    {
      type: 'container',
      label: 'menuContainer',
      children: [
        { type: 'sprite', label: 'background', src: 'bg.png', width: 1920, height: 1080 },
        { type: 'text', label: 'title', text: 'Main Menu', x: 960, y: 100, style: { fontSize: 48, fill: 0xffffff } }
      ]
    }
  ]
});

JSON Scene Schema

{
  "assetBundles": ["ui-bundle", "game-assets"],  // Optional: preload bundles before showing
  "metadata": {                                   // Optional: scene metadata
    "name": "MainMenu",
    "version": "1.0"
  },
  "elements": [                                   // Required: array of visual definitions
    {
      "type": "container",
      "label": "root",
      "x": 0,
      "y": 0,
      "children": [
        {
          "type": "sprite",
          "label": "bg",
          "src": "background.png",
          "width": 1920,
          "height": 1080
        },
        {
          "type": "text",
          "label": "title",
          "text": "Welcome",
          "x": 960,
          "y": 540,
          "style": { "fontSize": 64, "fill": 0xffffff }
        }
      ]
    }
  ]
}

Notes

  • app.navigation is created by the plugin and listens to app.scale.events('resize') to keep screens responsive.
  • Use app.ticker.add(screen.update, screen) pattern by defining update() on the screen; Navigation wires it automatically.
  • create() runs once per instance after its bundles are loaded and before prepare()/show(). Useful for async prefab creation.

Lifecycle

  • Show: assets (optional)create (once)prepareresizeticker.add(update, screen)showinteractiveChildren = true.
  • Hide/Remove: interactiveChildren = falsehideticker.remove(update, screen)removeChildreset.
  • Reuse: Screens retrieved from BigPool are reused; create() will not run again for the same instance. To force re-create in your screen, clear the flag in reset():
    delete (this as any)[Symbol.for('dc.screen.created')]

Focus & Blur

  • The plugin automatically maps browser focus signals to your screens:
    • Blur on: window.blur, document.visibilitychange(hidden), pagehide
    • Focus on: window.focus, document.visibilitychange(visible), pageshow
  • Navigation propagates blur()/focus() to background, currentScreen, and currentPopup if those hooks exist.
  • Typical usage: pause/slow animations and mute/duck audio on blur; resume/unmute on focus.
  • SSR/tests safe: Listeners are only attached when window and document are available.

Responsive Manager (Scene‑Scoped)

Declarative, JSON‑driven responsive layout per scene. Keeps your screen code free of if/else orientation logic by applying overrides on resize.

  • Scope: attach one ResponsiveManager per scene/screen (lifecycle friendly).
  • Sources: reads current orientation and game/safe sizes from the Resize plugin (app.scale.metrics).
  • Rules: orientation overrides, simple breakpoints, and relative placement keywords/percentages.

Add to a scene

import { ResponsiveManager } from '@dreams-engine/engine';

export class MenuScreen extends Container {
  private responsive!: ResponsiveManager;

  prepare() {
    // Pass optional root so manager auto-clears when this container is destroyed
    this.responsive = new ResponsiveManager(this.game, this);
    // Optional: use safe area from your scale config
    const m = (this.game as any).scale?.metrics;
    if (m) this.responsive.setSafeArea(m.gameWidth, m.gameHeight);
  }

  destroy() {
    this.responsive?.destroy();
    super.destroy({ children: true });
  }
}

Use with prefab/factory (automatic registration)

// defs comes from JSON/prefab. When a node has a `responsive` block,
// the factory will call responsive.add(node, rules) for you.
const rm = new ResponsiveManager(app);
const { sceneMap } = app.create.fromJson(defs, app.stage, { responsive: rm });
rm.applyAll(); // initial layout

With prefab

const rm = new ResponsiveManager(app);
// options.responsive passes the manager through to fromJson internally
const { rootNode, sceneMap } = await app.create.prefab('/prefabs/ui.json', { x: 0, y: 0 }, app.stage, undefined, { responsive: rm });
rm.applyAll();

JSON example

{
  "label": "playBtn",
  "type": "sprite",
  "texture": "btn",
  "anchor": 0.5,
  "responsive": {
    "landscape": { "x": "50%", "y": 900 },
    "portrait":  { "x": "50%", "y": "80%", "scale": 1.1 },
    "breakpoints": {
      "w<=800": { "scale": 0.85 },
      "ar<=1.6": { "y": 950 }
    },
    "relative": {
      "x": "center",   // left | center | right | percentage "50%"
      "y": "bottom"     // top | middle | bottom | percentage
    }
  }
}

Rules and precedence

  • Base props (from node) < orientation override (landscape/portrait) < matching breakpoints < runtime code.
  • Relative keywords use game and safe sizes from app.scale.metrics.
  • Supported props: x, y, scale, scaleX, scaleY, anchor, width, height.

Resize/Scale Plugin

Responsive scaling and alignment for your Application, inspired by Phaser 3’s Scale Manager.

  • Scale modes: FIT, ENVELOP, RESIZE, EXPAND, WIDTH_CONTROLS_HEIGHT, HEIGHT_CONTROLS_WIDTH, NONE.
  • Per-orientation configs: set different base sizes, safe areas, and alignment for landscape/portrait.
  • Events: resize (metrics), orientation:change, fullscreen:change, fullscreen:error.
  • Fullscreen helpers: startFullscreen(), stopFullscreen(), toggleFullscreen().

Register and configure

import { extensions } from 'pixi.js';
import { ResizePlugin, type ResizePluginOptions } from '@dreams-engine/engine';

extensions.add(ResizePlugin);

const resizeOpts: ResizePluginOptions = {
  landscape: { width: 1280, height: 720, scaleMode: 'FIT', align: 0.5, safeWidth: 1024, safeHeight: 576 },
  portrait:  { width: 720,  height: 1280, scaleMode: 'FIT', align: 0.5, safeWidth: 576,  safeHeight: 1024 },
  debounceDelay: 200,
};

const app = new Application();
await app.init({ resizeTo: window, resizeOpts });

// Access manager at runtime
const m = app.scale.metrics; // { orientation, displayWidth, displayHeight, scaleX, ... }

Listen to events

app.scale.events.on('resize', (metrics) => {
  console.log('Resized:', metrics.displayWidth, metrics.displayHeight);
});

app.scale.events.on('orientation:change', (o) => console.log('Orientation:', o));

Toggle fullscreen

await app.scale.toggleFullscreen();

Change scale mode at runtime

app.scale.setScaleMode('ENVELOP');             // for current orientation
app.scale.setScaleMode('FIT', 'landscape');    // override only landscape config

Notes

  • Renderer stays at the base logical size for consistent interaction; the canvas scales via CSS.
  • Make sure your page/layout gives the canvas parent a real size (100vw/100vh etc.).
  • Alignment accepts 0..1 values: { x: 0.5, y: 0.5 } centers the canvas.

Build

Inside packages/engine:

pnpm run build   # builds library with Vite (ESM + UMD)
pnpm run dev     # rebuilds on change
pnpm run clean   # removes dist

Build config: vite.config.ts outputs slot-engine.mjs and slot-engine.umd.js with externals for Pixi, i18next, gsap.

Compatibility

  • PixiJS v8 (class-based extensions)
  • TypeScript support out of the box (types emitted to dist/)