Skip to content

Asset Loading

ESEngine provides the Assets resource (an AssetServer instance) for loading textures, Spine animations, materials, and generic files. Access it in any system via Res(Assets).

Accessing Assets

import { defineSystem, addStartupSystem, Res } from 'esengine';
import { Assets } from 'esengine';
addStartupSystem(defineSystem(
[Res(Assets)],
async (assets) => {
const tex = await assets.loadTexture('assets/player.png');
console.log(`Loaded ${tex.width}x${tex.height}, handle: ${tex.handle}`);
}
));

Texture Loading

loadTexture(path)

Loads an image and returns a TextureInfo object. The image is automatically flipped vertically for OpenGL UV conventions.

const tex = await assets.loadTexture('assets/player.png');
sprite.texture = tex.handle;

Returns: TextureInfo { handle: TextureHandle, width: number, height: number }

Other Texture Methods

MethodDescription
getTexture(path)Returns cached TextureInfo if already loaded, undefined otherwise
hasTexture(path)Returns true if the texture is cached
releaseTexture(path)Releases the texture from GPU memory and cache
releaseAll()Releases all cached assets

9-Slice Metadata

For 9-slice sprites, set border metadata after loading:

const tex = await assets.loadTexture('assets/panel.png');
assets.setTextureMetadata(tex.handle, {
left: 10, right: 10, top: 10, bottom: 10
});

Spine Loading

const result = await assets.loadSpine('assets/hero.json', 'assets/hero.atlas');
if (!result.success) {
console.error(result.error);
}

loadSpine automatically:

  1. Fetches the atlas file and writes it to the virtual filesystem
  2. Parses the atlas for texture filenames and loads each texture
  3. Fetches the skeleton file (.json or .skel binary) and writes it to the virtual filesystem
MethodDescription
loadSpine(skeleton, atlas, baseUrl?)Load Spine skeleton and atlas
isSpineLoaded(skeleton, atlas)Check if a Spine asset pair is already loaded

BitmapFont Loading

const fontHandle = await assets.loadBitmapFont('assets/my-font.fnt');

Supports .fnt (BMFont text format) and .bmfont (JSON metadata) files. The loader automatically resolves and loads referenced texture atlases.

MethodReturnsDescription
loadBitmapFont(path)Promise<number>Load a bitmap font file and its textures. Returns a font handle
getFont(path)number | undefinedGet cached font handle, undefined if not loaded
releaseFont(path)voidRelease the font and its textures from memory

Generic File Loading

MethodReturnsDescription
loadJson<T>(path, options?)Promise<T>Load and parse a JSON file
loadText(path, options?)Promise<string>Load a text file
loadBinary(path, options?)Promise<ArrayBuffer>Load a binary file
const config = await assets.loadJson<GameConfig>('assets/config.json');
const csv = await assets.loadText('assets/levels.csv');
const data = await assets.loadBinary('assets/tilemap.bin');

FileLoadOptions

OptionTypeDescription
baseUrlstringOverride the base URL for this request
noCachebooleanSkip cache — always fetch from network

Batch Loading

Load multiple assets in parallel with loadAll:

const bundle = await assets.loadAll({
textures: ['assets/bg.png', 'assets/player.png'],
spine: [{ skeleton: 'assets/hero.json', atlas: 'assets/hero.atlas' }],
json: ['assets/config.json'],
});
// Access loaded assets from the bundle
const bgTex = bundle.textures.get('assets/bg.png');
const config = bundle.json.get('assets/config.json');

AssetManifest

FieldTypeDescription
texturesstring[]Texture image paths
materialsstring[]Material file paths (.esmaterial)
spineSpineDescriptor[]Spine skeleton/atlas pairs
jsonstring[]JSON file paths
textstring[]Text file paths
binarystring[]Binary file paths

AssetBundle

The returned AssetBundle contains Maps keyed by path:

FieldType
texturesMap<string, TextureInfo>
materialsMap<string, LoadedMaterial>
spineMap<string, SpineLoadResult>
jsonMap<string, unknown>
textMap<string, string>
binaryMap<string, ArrayBuffer>

Material Loading

const loaded = await assets.loadMaterial('assets/effects/glow.esmaterial');
sprite.material = loaded.handle;

See Materials & Shaders for the full material API and .esmaterial file format.

Caching

All load methods cache by path. Loading the same path twice returns the cached result without a network request. Use the noCache option on generic file loaders to bypass caching:

const fresh = await assets.loadJson('assets/config.json', { noCache: true });

Base URL

Set assets.baseUrl to prefix all relative paths:

assets.baseUrl = 'https://cdn.example.com/game';
const tex = await assets.loadTexture('sprites/player.png');
// fetches https://cdn.example.com/game/sprites/player.png

Absolute paths and full URLs are not affected by baseUrl.

Embedded Assets

For Playable Ad builds, the editor’s build pipeline automatically embeds all referenced assets as data URIs into the output bundle. At runtime, assets.loadTexture() / assets.loadJson() and other load calls resolve from the embedded data instead of fetching over the network — no code changes are needed.

Addressable Assets

Addressable assets let you load resources by logical address, label, or group instead of raw file paths. The editor builds an AddressableManifest during the build process, which maps addresses and labels to asset paths.

Loading by Address

const texture = await assets.loadByAddress('player-idle');

Loading by Label

Load all assets tagged with a label. Returns an AssetBundle:

const bundle = await assets.loadByLabel('ui-sprites');
for (const [path, tex] of bundle.textures) {
console.log(`Loaded ${path}: ${tex.width}x${tex.height}`);
}

Loading by Group

Load all assets in a named group:

const bundle = await assets.loadGroup('level-1');

Setting the Manifest

The manifest is generated by the editor during build. At runtime, set it before loading:

import { Assets } from 'esengine';
const manifest = await assets.loadJson('assets/addressable-manifest.json');
assets.setAddressableManifest(manifest);

Next Steps