AssetLibrary
assets/asset-library.ts:87 Extends AbstractGameComponent
Game-tier registry that loads, caches, and hands out Asset resources — textures today, audio and other kinds later.
AssetLibrary is auto-attached to every Game and reached through
Game.assets. It lives at the game tier, not the world tier, because
assets outlive worlds: you do not want to reload the player spritesheet
every time a world is created or destroyed. Group assets with namespaces
(see below) when you want world- or level-scoped grouping without
world-scoped lifetime.
Under the hood it wraps PIXI's global Assets loader. That dependency is
an implementation detail reachable only through AssetLibrary.raw;
the surface here speaks in arcade2d Asset handles.
Preloading model
Loading is explicit and developer-driven. There is no lazy load-on-first-use: you preload the assets a phase needs, then run the phase that uses them. The intended granularity is coarse and eager — load a whole bundle/namespace at a boundary (entering a level), never one texture per object as it spawns:
await game.assets.loadMany(
['tiles/floor.png', 'tiles/wall.png', 'sprites/goblin.png'],
{ namespace: 'level-1' },
);
const world = game.createWorld({ ... }); // safe: every asset resolvedLoading eagerly at a coarse boundary is what makes a missing asset a load-time failure (ErrorCode.ASSET_LOAD_FAILED the moment the batch is awaited) rather than a gameplay-time surprise that only fires if a tester happens to encounter a particular object. AssetLibrary.get throwing on a missing key is the backstop for the residual "forgot to load the bundle entirely" mistake — not the primary safety net.
Idempotent loading
AssetLibrary.load is idempotent per (namespace, key). A path
already loaded under that identity resolves immediately to the existing
handle; a load still in flight returns the same in-flight promise rather
than starting a second fetch. Reusing a key for a different path within a
namespace is a programming error and throws
ErrorCode.ASSET_KEY_CONFLICT.
Namespaces
A namespace is a grouping whose keys are unique only within it. The DEFAULT_ASSET_NAMESPACE covers the simple case; reach for explicit namespaces when you want AssetLibrary.unloadNamespace to free a whole group at once (one namespace per level is the canonical use).
Unloading
Unloading is explicit; there is no automatic eviction. Free a single asset with AssetLibrary.unload or a whole group with AssetLibrary.unloadNamespace. Both release the underlying GPU resource via the renderer, not just the JS reference — the realistic win is dropping a finished level's textures, or (later) decoded audio buffers.
Constructors
constructor(host: Game): AssetLibrary Parameters
-
hostGame
Properties
enabled: boolean Per-component gate on the three update hooks (onPreUpdate,
onUpdate, onPostUpdate). When explicitly false, the engine skips
all three for this component during the host's tick — useful for
temporarily pausing behaviour (e.g. a freeze powerup) without removing
the component and losing its internal state.
Does not gate onAdded or onDestroy; those always fire so a host can
never end up with a half-attached component.
Accessors
game: Game The Game this component is attached to — identical to
AbstractComponent.host at this tier, exposed under the
game name so subclass code reads the same on every tier.
raw: AssetsClass Direct access to the underlying PIXI Assets loader.
Use with care. raw is an intentional escape hatch for cases the
arcade2d API doesn't cover — registering custom loader parsers, tuning
resolver preferences, background-loading, anything we haven't decided how
to model yet. Code that touches raw is coupled to PIXI's public API and
may break when:
- arcade2d upgrades PIXI (including minor versions).
- PIXI itself ships a breaking change.
- arcade2d swaps PIXI for a different loader.
None of those will be treated as breaking changes to arcade2d's own
surface. Prefer the typed methods on this component; reach for raw only
when no equivalent exists, and isolate the access behind your own helper
so the coupling is in one place.
Methods
get(key: string, namespace: string): Asset Retrieves a previously loaded or stored asset by key.
Throws on a miss rather than returning null — a missing asset at this
point means the expected preload never ran, which is a programming error
the engine surfaces loudly. Use AssetLibrary.getNullable when
absence is a legitimate, handled state.
Parameters
-
keystring -
namespacestring
Throws
EngineError with code
ErrorCode.ASSET_NOT_FOUND when no asset is stored under
(namespace, key).
Example
const player = game.assets.get('player') as ImageAsset;getAs(key: string, type: AssetConstructor<T>, namespace: string): T Retrieves an asset by key and asserts its concrete type, returning it
typed — so call sites avoid an unchecked as ImageAsset cast.
Pass the expected Asset subclass (e.g. ImageAsset) as a
runtime witness; the lookup verifies the stored asset is an instance of
it. This mirrors ComponentHost.getComponentByType and, unlike a
bare get<T>() generic, is type-safe at runtime: a wrong type is a
loud ErrorCode.ASSET_TYPE_MISMATCH, not a latent mis-cast.
Parameters
-
keystring -
typeAssetConstructor<T> -
namespacestring
Returns
T The stored asset, typed as T.
Throws
EngineError with code
ErrorCode.ASSET_NOT_FOUND when no asset is stored under
(namespace, key).
EngineError with code
ErrorCode.ASSET_TYPE_MISMATCH when the stored asset is not an
instance of type.
Example
const player = game.assets.getAs('player', ImageAsset); // typed, no cast
new Texture(player);getNullable(key: string, namespace: string): null | Asset Retrieves a previously loaded or stored asset by key, or null if none
is stored under (namespace, key).
The non-throwing counterpart to AssetLibrary.get; mirrors the
getNullableComponent convention on the component host. Use it when
absence is an expected, handled outcome rather than a programming error.
Parameters
-
keystring -
namespacestring
has(key: string, namespace: string): boolean Reports whether an asset is stored under (namespace, key).
Parameters
-
keystring -
namespacestring
Returns
boolean load(path: string, options: AssetLoadOptions): Promise<Asset> Loads a single resource and stores it for later retrieval by key.
Idempotent per (namespace, key): a matching asset that is already
loaded resolves immediately, and one still loading returns the shared
in-flight promise. See the class docs for the full preloading model.
Parameters
-
pathstring -
optionsAssetLoadOptions
Throws
EngineError with code
ErrorCode.ASSET_KEY_CONFLICT when (namespace, key) already
holds an asset loaded from a different path.
EngineError with code
ErrorCode.ASSET_TYPE_MISMATCH when no type is given and the
path's extension yields no recognised type.
EngineError with code ErrorCode.ASSET_LOAD_FAILED when the underlying loader rejects (network error, decode failure, unsupported format).
Example
const player = await game.assets.load('sprites/player.png', {
key: 'player',
namespace: 'level-1',
});loadMany(paths: readonly string[], options: AssetLoadManyOptions): Promise<readonly Asset[]> Loads many resources in parallel, each stored under its own path as key.
The promise resolves once every load settles, with the resulting
Asset handles in the same order as paths. If any load rejects,
the returned promise rejects with the first error — assets that loaded
successfully remain stored.
Use this for the eager, coarse-grained preload described in the class docs — load a level's whole asset set in one call before creating the world that uses it.
Parameters
-
pathsreadonly string[] -
optionsAssetLoadManyOptions
Throws
The same EngineError codes as AssetLibrary.load, surfaced from whichever path failed.
Example
await game.assets.loadMany(
['tiles/floor.png', 'tiles/wall.png'],
{ namespace: 'level-1' },
);onAdded(_deps: Record): void Lifecycle hook that is called when the component is added to the host object. Should not be called directly.
Parameters
-
_depsRecord
Returns
void onDestroy(): void Drops every tracked asset reference when the game tears down. The
underlying GPU resources are released by the PIXI application's own
destroy during Game.destroy, so this only needs to clear the
library's bookkeeping.
Returns
void onUpdate(_update: WorldUpdate, _deps: Record): void Lifecycle hook for the main update phase. Called once per world
tick, after every component's onPreUpdate and before any
onPostUpdate.
Parameters
-
_updateWorldUpdate -
_depsRecord
Returns
void store(key: string, asset: Asset, namespace: string): Asset Registers an externally-produced Asset under a key, without going through the loader.
This is the entry point for assets the engine did not fetch — a texture
generated at runtime, a render-texture snapshot, a procedurally-built
resource. AssetLibrary.load also routes through store once its
fetch resolves, so a stored asset is indistinguishable from a loaded one
at lookup time.
Parameters
-
keystring -
assetAsset -
namespacestring
Throws
EngineError with code
ErrorCode.ASSET_KEY_CONFLICT when (namespace, key) already
holds a different asset. Re-storing the identical instance is a
no-op and does not throw.
unload(key: string, namespace: string): Promise<void> Unloads a single asset, releasing its underlying GPU/loader resource and dropping it from the library.
Idempotent: unloading a key that isn't stored is a no-op, like
removeComponent on the component host. After this resolves,
AssetLibrary.get for the same key throws again until it is
reloaded.
Parameters
-
keystring -
namespacestring
Returns
Promise<void> A promise that resolves once the underlying resource is freed.
unloadNamespace(namespace: string): Promise<void> Unloads every asset in a namespace in one batch, releasing all of their underlying resources and dropping the namespace.
This is the coarse-grained eviction the namespace model is built for: give a level its own namespace, then drop the whole set on exit. Idempotent — unloading an unknown or already-empty namespace is a no-op.
Parameters
-
namespacestring
Returns
Promise<void> A promise that resolves once every underlying resource is freed.
Example
await game.assets.unloadNamespace('level-1'); // entering level 2use(bundle: AssetBundle<E>): BoundAssetBundle<E> Binds a declarative AssetBundle to this library, returning a
BoundAssetBundle whose load/get/unload are scoped to the
bundle's namespace and — crucially — typed to the bundle's declared keys.
This is the recommended entry point for any asset whose key is known at
authoring time. Where the untyped AssetLibrary.get accepts any
string and throws ErrorCode.ASSET_NOT_FOUND at runtime on a typo,
a bound bundle rejects an unknown key at compile time — turning "a rare
object's graphics component throws mid-session because its asset key was
wrong" into a tsc error. Keep the untyped methods for genuinely dynamic
keys.
Parameters
-
bundleAssetBundle<E>
Example
const lvl = game.assets.use(level1);
await lvl.load();
const zombie = lvl.get('zombie'); // typed to the bundle's keys