Assets
import { boot } from "@f0rbit/forge/pixi";
const r = await boot({ mount: "#root", assets: [ { kind: "image", alias: "hero", url: "/sprites/hero.png" }, { kind: "atlas", alias: "tilemap", url: "/atlases/tilemap.json" }, ], // ...});assets returns Result<App, BootError> — if any asset fails, boot disposes the renderer and returns err({ kind: "asset_failed", alias, cause: AssetError }). Boot loads assets sequentially in the order given.
Standalone usage
Section titled “Standalone usage”The async loader is unified by a kind discriminator. The return type narrows on the kind — "image" yields Texture, "atlas" yields Spritesheet:
const a = app.assets;
const tex_r = await a.load("image", "hero", "/sprites/hero.png");if (tex_r.ok) tex_r.value; // Texture
const sheet_r = await a.load("atlas", "hero_atlas", "/sprites/hero.json");if (sheet_r.ok) sheet_r.value.textures["walk_0"]; // SpritesheetSynchronous getters split by kind:
a.has("hero"); // → truea.texture("hero"); // → Result<Texture, AssetError>a.atlas("hero_atlas"); // → Result<Spritesheet, AssetError>a.get<Spritesheet>("hero_atlas"); // → Result<T, AssetError> (untyped)a.dispose(); // clear cachetype AssetKind = "image" | "atlas";type LoadValue<K extends AssetKind> = K extends "image" ? Texture : Spritesheet;
type Assets = { load: <K extends AssetKind>(kind: K, alias: string, url: string) => Promise<Result<LoadValue<K>, AssetError>>; texture: (alias: string) => Result<Texture, AssetError>; atlas: (alias: string) => Result<Spritesheet, AssetError>; get: <T>(alias: string) => Result<T, AssetError>; has: (alias: string) => boolean; registry: () => AtlasRegistry; register_atlas: (alias: string, sheet: Spritesheet) => Result<void, AssetError>; dispose: () => void;};AssetError cases
Section titled “AssetError cases”type AssetError = | { kind: "load_failed"; alias: string; url: string; cause: string } | { kind: "not_loaded"; alias: string } | { kind: "invalid_atlas"; alias: string; issues: readonly string[] } | { kind: "wrong_kind"; alias: string; expected: string };Atlas JSON is the standard TexturePacker JSON-Hash format with optional animations arrays. Frame duration (ms) is converted to whole-tick durations using the configured fixed_dt — see Anim component.
The __default__ atlas
Section titled “The __default__ atlas”For “I just want to see something on screen”, forge auto-registers a 4-frame placeholder atlas at boot:
| Alias | Frames | Pixels |
|---|---|---|
__default__ | __default_0__, __default_1__, __default_2__, __default_3__ | 16×16 each, magenta / cyan / yellow / black |
It also defines a spin sequence (all four frames at 100ms each) so anim_c.play("__default__", "spin") works out of the box.
w.set(player, sprite_c, { texture: "__default__", frame: "__default_0__", anchor: { x: 0.5, y: 0.5 },});This is the pattern used in coin-collector/src/main.ts.
To skip the default atlas (e.g., production builds with no missing-art fallback):
const a = assets({ register_default: false });(Pass your own assets instance via the boot API isn’t currently supported — register_default: true is hard-coded inside boot. Bring-your-own atlases simply override entries with the same alias if you ever load "__default__" yourself.)
Migration from v0.2.0
Section titled “Migration from v0.2.0”The pair a.image(alias, url) / a.atlas(alias, url) async loaders are unified as a.load(kind, alias, url):
// v0.2.0await a.image("hero", "/sprites/hero.png");await a.atlas("hero_atlas", "/sprites/hero.json");
// v0.3.0await a.load("image", "hero", "/sprites/hero.png");await a.load("atlas", "hero_atlas", "/sprites/hero.json");The synchronous getter a.texture(alias) is unchanged. A new synchronous getter a.atlas(alias) returns the previously-loaded Spritesheet (mirrors texture for atlases). The BootOpts.assets: AssetSpec[] consumer-side shape is unchanged.