Taos Engine · Modules

Modules

Bundles

Bundle bundles many assets into a single .bundle archive so a game ships a few large downloads instead of hundreds of small files. Bundles load asynchronously, declare dependencies on one another, ship per-platform variants (mobile vs desktop), and can be streamed one entry at a time out of a large remote archive with HTTP Range requests. Assets are addressed by stable keys (guids or authored addresses) and grouped with labels, indexed by a catalog.json.

It sits under the existing loaders (GltfLoader, Texture, HDR/EXR/…): a bundle provides the bytes, the loaders decode them as before.

TypeScript
import { BundleManager, BundleAssets, detectProfile } from 'taos/assets/index.js';

const bundles = new BundleManager({ profile: detectProfile(device) });
await bundles.mountCatalog('assets/catalog.json'); // fetch + parse the index
await bundles.loadLabel('startup');                // loads every bundle the label touches (+ deps)

const assets = new BundleAssets(bundles, device);
const mesh = await assets.getMesh('guid-duck');  // bytes → GltfLoader → Mesh, cached

Archive format#

A .bundle is [ entry blobs ][ gzipped-JSON TOC ][ 32-byte footer ], little-endian. Each entry blob is compressed independently (gzip via the WHATWG CompressionStream, the same code path in browser and Node ≥ 18) so a single entry can be pulled and decompressed on its own. The footer at the end lets a reader learn the file size, read the last 32 bytes, then Range-read just the TOC. See bundle_format.ts.

Runtime#

Engine / scene integration#

BundleAssetResolver (bundle_resolver.ts) implements the engine's AssetResolver, so a bundleed game resolves scene/assembly asset references straight out of archives — no per-file fetch, no editor IPC:

TypeScript
import { BundleAssetResolver } from 'taos/engine/scene_runtime/index.js';
const resolver = new BundleAssetResolver(bundles, new BundleAssets(bundles, device));
instantiateScene(sceneDoc, { engine, resolver });

Catalog (catalog.json)#

JSONC
{
  "schema": 1,
  "bundles": [
    { "id": "shared", "url": "shared.bundle" },
    { "id": "art", "url": "art.bundle", "dependsOn": ["shared"],
      "variants": [{ "profile": "mobile", "url": "art.mobile.bundle" }] }
  ],
  "assets": { "guid-duck": { "bundle": "art", "labels": ["enemy"] } },
  "labels": { "enemy": ["guid-duck"] }
}

Building bundles#

A project declares groups in bundles.json (one group → one .bundle):

JSONC
{ "schema": 1, "groups": [
  { "id": "shared",    "include": { "paths": ["Content/Shared"] } },
  { "id": "art", "dependsOn": ["shared"],
    "include": { "labels": ["enemy"], "paths": ["Content/Mobs"] },
    "compression": "gzip" }
] }

Asset keys come from the editor's .meta guids (path-based otherwise); optional labels in a .meta sidecar carry into the catalog. v1 variants are authored from explicitly-listed sources; automatic texture transcode/downscale is a follow-up.

See also#