Asset Management
The Asset Management System lets you use custom visual and audio assets in Aikami through a simple local filesystem workflow. Assets live under static/game-assets/ and are indexed by a manifest scanner into tag-based lookups.
How It Works
Section titled “How It Works”-
Place files in
apps/frontend/client/static/game-assets/under the appropriate category subdirectory (sprites/,backgrounds/,music/,sfx/,ambient/). -
Run the scanner to index your files:
Terminal window bun run scripts/src/lib/ops/scan_assets.tsThis generates
manifest.jsonwith tag→path mappings. -
Browse your assets at
/dev/asset-browserin the dev sandbox.
Each file is indexed by a tag derived from its path — for example, sprites/generic-fantasy/elf.png becomes sprites:generic-fantasy:elf. The game engine resolves these tags at runtime, loading textures through PixiJS with transparent caching.
Asset Browser
Section titled “Asset Browser”Access the asset browser from the Dev Sandbox at /dev/asset-browser. It provides:
- Folder tree navigation by category
- File grid with image and audio file previews
- Category tabs to filter by asset type
- Upload instructions modal showing the local workflow
Background Crossfade
Section titled “Background Crossfade”Scene backgrounds transition smoothly using a 500ms alpha crossfade. Call setBackground(tag) on the game world to load and crossfade between background images through the PixiJS render pipeline.
Offline Asset Cache (C-373)
Section titled “Offline Asset Cache (C-373)”Once assets have been fetched, the game runs fully offline: every sprite, LPC layer, and audio file is served from a local content-hash-keyed cache with zero network round-trips.
How it works:
scan_assets.tsadditionally emitsasset_hashes.json— the SHA-256 + size of every file, alongsidemanifest.json.- On boot, the
initializing_asset_registrystage seeds a local Turso registry (assets,asset_sources,install_statetables) from the manifest + sidecar. Seeding is idempotent — later boots only run a meta guard check. - The AssetManager resolves each tag through registry → cache → sources. On a miss it fetches from the bundled source, verifies the SHA-256 against the registry hash before writing or serving, and records the install state.
- Binaries are stored hash-named in OPFS (Web/PWA) or the Tauri native disk cache (Desktop). Writes go to a temporary file first and are atomically renamed into place, so readers never observe a partially-written entry; reads verify the file’s SHA-256 again before serving (a corrupted entry is discarded and re-fetched). Cached assets resolve to
blob:object URLs — PixiJS loads them transparently via a registered blob-URL loader. - When a new game build bumps an asset’s hash, the old binary is automatically evicted and re-fetched on the next request; interrupted downloads are reconciled at boot.
Missing or optional assets degrade gracefully to the existing fallbacks with a logged warning — never a crash.
Firebase Storage sources & the online registry seed
Section titled “Firebase Storage sources & the online registry seed”Assets are mirrored to Firebase Storage so the AssetManager can fall back to an
online origin (C-373 asset_sources). The bucket layout mirrors the bundled
static/game-data tree:
gs://<project>.firebasestorage.app/ lpc/… # LPC spritesheets (upload_lpc_assets.ts) music/… sfx/… ambient/… # audio assets sprites/… backgrounds/… # image assets (tilesets, portraits, backgrounds) game-data/manifest.json # online registry seed — the available-asset catalog game-data/asset_hashes.jsonHow it works:
upload_assets.tsuploadsstatic/game-data/{music,sfx,ambient,sprites,backgrounds}plus the registry seed (manifest.json,asset_hashes.json) to the bucket.upload_lpc_assets.tsdoes the same for LPC (separate script — 12k+ files).- At boot,
AssetRegistryRepository.addFirebaseStorageSources(bucket)adds afirebase-storagesource row (priority 1) for every seeded asset — the download URLhttps://firebasestorage.googleapis.com/v0/b/<bucket>/o/<path>?alt=media. The bundled source (priority 0) is tried first; the bucket mirror is the fallback when the bundled path is unavailable. - Storage rules allow public read for
music/**,sfx/**,ambient/**,sprites/**,backgrounds/**,lpc/**andgame-data/**(admin-only write), matching the anonymous browser fetches the AssetManager issues. - The online
game-data/manifest.jsonis the discoverable catalog — the app reads themusic/sfxcategories from the manifest, so adding a track tostatic/game-data/music/…, re-runningscan_assets.ts, bundling and uploading makes it playable with no hardcoded references (audio_asset_resolver.tsmatches tracks by manifest tag, not name).
Source
Section titled “Source”- Engine scanner:
packages/frontend/engine/src/assets/asset_manifest.ts - CLI scanner:
scripts/src/lib/ops/scan_assets.ts - Registry:
packages/frontend/storage/src/lib/assets.ts - Cache + manager:
apps/frontend/client/src/lib/services/assets/ - UI:
apps/frontend/client/src/lib/views/asset-browser/ - Store:
apps/frontend/client/src/lib/services/assets/asset_store.svelte.ts