pixium
v1.1.0
Published
Helper utilities for PixiJS.
Maintainers
Readme
pixium
Helper library for PixiJS.
Install
npm install pixiumUsage
const { version, createAssetsManager } = require("pixium");
console.log(version());
const loader = createAssetsManager();
const manifest = [
{ alias: "timer_bg", src: "/assets/timer-bg.png" },
{ alias: "logo", src: "/assets/logo.png" },
];
// load(manifest, onProgress?)
await loader.load(manifest, (progress) => {
console.log("Loading progress:", progress);
});
// has(alias)
console.log(loader.has("timer_bg")); // true
// get(alias)
const timerBgTexture = loader.get("timer_bg");
// unload(manifest)
await loader.unload([{ alias: "logo", src: "/assets/logo.png" }]);
// unloadAll()
await loader.unloadAll();Scene Manager API
createSceneManager(config) helps you define all pages/scenes in one place and navigate with one function: go(pageId, params?).
It handles:
- redirects (
next) - guards (
canEnter,canLeave) - preloading (
preload) before page creation/enter - lifecycle hooks (
onEnter,onLeave) - transition selection (route/page/global fallback)
- history (
back,forward)
Quick start
import { createSceneManager } from "pixium";
const scenes = createSceneManager({
initial: "boot",
defaultTransition: { type: "fade", duration: 300 },
pages: {
boot: {
create: () => ({ id: "boot-scene" }),
next: "menu"
},
menu: {
create: () => ({ id: "menu-scene" }),
transitions: {
to: {
game: { type: "slide-left", duration: 450 }
}
}
},
game: {
create: ({ params }) => ({ id: "game-scene", params }),
onEnter: async ({ params }) => {
console.log("Entered game with params:", params);
}
}
}
});
await scenes.start();
await scenes.go("game", { level: 2 });
await scenes.back();Minimum config required from user
initial: first page idpages: map of page configs- each page must implement
create(ctx)
Everything else is optional.
Config shape
type TransitionSpec = {
type: "none" | "fade" | "slide-left" | "slide-right" | "zoom";
duration?: number;
easing?: string;
};
type SceneManagerConfig = {
initial: string;
pages: Record<string, {
preload?: (ctx: {
id: string;
params?: Record<string, unknown>;
}) => void | Promise<void>;
create: (ctx: { id: string; params?: Record<string, unknown> }) => unknown;
onEnter?: (ctx: {
pageId: string;
fromId: string | null;
params?: Record<string, unknown>;
direction: "forward" | "back" | "replace";
instance: unknown;
}) => void | Promise<void>;
onLeave?: (ctx: {
pageId: string;
toId: string;
params?: Record<string, unknown>;
direction: "forward" | "back" | "replace";
instance: unknown;
}) => void | Promise<void>;
next?: string | ((ctx: {
fromId: string | null;
toId: string;
params?: Record<string, unknown>;
direction: "forward" | "back" | "replace";
}) => string | null | Promise<string | null>);
canEnter?: (ctx: {
fromId: string | null;
toId: string;
params?: Record<string, unknown>;
direction: "forward" | "back" | "replace";
}) => boolean | Promise<boolean>;
canLeave?: (ctx: {
fromId: string | null;
toId: string;
params?: Record<string, unknown>;
direction: "forward" | "back" | "replace";
}) => boolean | Promise<boolean>;
transitionIn?: TransitionSpec;
transitionOut?: TransitionSpec;
transitions?: {
to?: Record<string, TransitionSpec>;
from?: Record<string, TransitionSpec>;
};
}>;
defaultTransition?: TransitionSpec;
notFound?: string;
maxHistory?: number;
runTransition?: (ctx: {
fromId: string | null;
toId: string;
params?: Record<string, unknown>;
fromInstance: unknown;
toInstance: unknown;
spec: TransitionSpec;
direction: "forward" | "back" | "replace";
}) => void | Promise<void>;
};Preload resources for a page
You can define a per-page preload hook for assets, data, or any async preparation step needed before the scene is entered.
Why use it:
- avoid frame spikes when entering heavy scenes
- preload likely-next scenes in the background
- keep
createfocused on building scene objects, not fetching resources
Behavior:
go(...)automatically calls pagepreloadbeforecreateandonEnterscenes.preload(pageId, params?)lets you preload manually (without navigation)
import { Container } from "pixi.js";
const scenes = createSceneManager({
initial: "menu",
pages: {
battle: {
preload: async ({ params }) => {
await assets.load(battleManifest(params.level));
},
create: () => new Container()
},
menu: {
create: () => new Container()
}
}
});
// Manual preload (e.g. while player is on menu)
await scenes.preload("battle", { level: 5 });
// go(...) will also run preload automatically
await scenes.go("battle", { level: 5 });Check page existence before navigating
Use exists(pageId) when routes are feature-dependent (DLC, experiments, role-based menus).
Why use it:
- avoid
try/catchjust to check route registration - safely render optional buttons or entries
if (scenes.exists("shop")) {
await scenes.go("shop");
}Get current active scene metadata
Use current() whenever systems outside scene code need active scene metadata.
Why use it:
- HUD/UI needs to know active scene
- save/replay systems need scene id + params snapshot
- debug overlays/devtools need live scene introspection
Returns:
nullwhen no scene is active yet- otherwise
{ id, instance, params }
const current = scenes.current();
if (current) {
console.log(current.id);
console.log(current.instance);
console.log(current.params);
}Reload the current scene
Use reload() to recreate the active scene instance. This is useful for restart/retry flows and resetting scene state.
Why use it:
- level retry button
- deterministic reset of transient scene state
- re-enter current route after external state changes
await scenes.reload();Keep current params when reloading:
await scenes.reload({ keepParams: true });Destroy cached scene instances
Use destroy(pageId?) to remove a cached scene instance and run its destroy(...) method when available (useful for GPU/resource cleanup).
Why use it:
- free GPU memory for scenes not needed soon
- aggressively clean up between large worlds/modes
- prepare for custom caching/persistence strategies
scenes.destroy("battle");Destroy the active scene instance directly:
scenes.destroyCurrent();Check whether a scene is active
Use isActive(pageId) to skip duplicate flow transitions.
Why use it:
- guard against repeated pause/menu opens
- prevent re-triggering scene-specific side effects
if (scenes.isActive("pause")) {
return;
}Check whether navigation is allowed
Use canGo(pageId, params?) to run route resolution + guards only, without triggering navigation, preload, or lifecycle hooks.
Why use it:
- disabled/enabled state for buttons
- menu validation before showing options
- "preview availability" checks in UI flows
Behavior:
- resolves redirects first
- runs
canLeave/canEnter - does not change history or active scene
if (await scenes.canGo("multiplayer")) {
await scenes.go("multiplayer");
}Replace current history entry
Use replace(pageId, params?) when navigation should not create a new history step.
Why use it:
- boot -> main menu handoff
- login -> app handoff
- cutscene -> gameplay handoff
- checkpoint reloads where current state should be overwritten
Behavior:
- navigates like
go(...) - replaces current history entry instead of pushing a new one
- keeps
back()behavior clean and predictable
await scenes.replace("menu");Scene events (on, off, once)
Use the event system for integrations like analytics, audio, saves, debugging, and devtools without adding scene-manager core logic.
When to use each event:
before-change: pre-transition hooks (audio prewarm, analytics "intent", autosave)change: confirmed navigation/reload success (track screen_view, update global UI)error: central error reporting/logging for scene operations
Listener API:
on(event, listener): subscribe and keep listeningonce(event, listener): subscribe for one event occurrenceoff(event, listener): remove a specific listener
const unsubscribeChange = scenes.on("change", ({ fromId, toId }) => {
analytics.track("scene_changed", { fromId, toId });
});
scenes.on("before-change", ({ toId }) => {
audioManager.preWarmForScene(toId);
});
scenes.on("error", ({ operation, error }) => {
console.error("Scene manager error:", operation, error);
});
// later
unsubscribeChange();Core methods and when to call them
start(params?): boot the manager atinitial; usually called once after app initgo(pageId, params?): navigate to a scene; your primary route change APIreplace(pageId, params?): navigate without adding history; overwrite current entryback()/forward(): move through scene history; useful for UI back buttons and debug navigationpreload(pageId, params?): warm scene resources early; call from menus/loading flowscanGo(pageId, params?): async guard check for UI gating without navigationexists(pageId): validate route registration before offering navigationisActive(pageId): avoid duplicate transitions for already-open scenescurrent(): read active{ id, instance, params }for external systemsreload({ keepParams? }): recreate active scene for retry/reset loopsdestroy(pageId?)/destroyCurrent(): release cached scene instances/resources
Pixi transition example
runTransition is where you animate the old/new Pixi containers.
const scenes = createSceneManager({
initial: "menu",
defaultTransition: { type: "fade", duration: 250 },
runTransition: async ({ fromInstance, toInstance, spec }) => {
const from = fromInstance as import("pixi.js").Container | null;
const to = toInstance as import("pixi.js").Container;
if (spec.type === "fade") {
// your tween/RAF fade logic here
}
if (spec.type === "slide-left") {
// your tween/RAF slide logic here
}
if (spec.type === "zoom") {
// your tween/RAF zoom logic here
}
},
pages: {
menu: { create: () => new Container() },
game: { create: () => new Container(), transitionIn: { type: "slide-left", duration: 400 } }
}
});Assets Manager API
createAssetsManager() returns a loader instance that works in any JavaScript runtime where PixiJS Assets is available (framework apps, vanilla apps, and game engines built on PixiJS).
load(manifest, onProgress?)
Loads assets from a manifest and skips aliases already loaded by this loader instance.
manifestsupports:- array format:
[{ alias: "timer_bg", src: "/assets/timer-bg.png" }] - object format:
{ timer_bg: "/assets/timer-bg.png" }
- array format:
onProgressreceives a value from0to1
await loader.load(manifest, (progress) => {
console.log("Progress:", progress);
});get(alias)
Returns a previously loaded asset from PixiJS Assets.
const texture = loader.get("timer_bg");has(alias)
Checks whether an alias is tracked as loaded by this loader instance.
if (loader.has("timer_bg")) {
console.log("timer_bg is loaded");
}unload(manifest)
Unloads only the assets listed in the provided manifest and removes them from tracked loaded aliases.
await loader.unload([{ alias: "logo", src: "/assets/logo.png" }]);unloadAll()
Unloads all assets currently tracked by this loader instance.
await loader.unloadAll();