@awaken/assets
Asset storage, the shared import IR, every model/engine importer, and the persistence formats. It depends on @awaken/core and @awaken/render (for MeshData, Material, and texture types).
This package is the seam between importing (turning a Unity/Godot/Unreal/glTF project into engine data) and shipping (writing that data to a binary project or a self-contained game file).
ts
import { AssetStore, spawnImportedScene, encodeProject, bundleToSceneFile } from "@awaken/assets";AssetStore
The in-memory library of everything a scene references, keyed by string id. It is data-only - the renderer uploads from it, the animation system reads skeletons/clips/skins from it.
| Member | Type | Description |
|---|---|---|
meshes | Map<string, MeshData> | Geometry by mesh id. |
textures | Map<string, TextureData> | Device-neutral texture pixels by id. |
materials | Map<string, Material> | Authored materials by id. |
skeletons / clips / skins | Map<string, …> | Skeletal-animation assets (skins keyed by the skinned mesh id). |
revision | number | Bumped on every add/replace, so a per-frame uploader can skip re-scanning when nothing changed. |
addMesh/addTexture/addMaterial/addSkeleton/addClip/addSkin | (id, data) => void | Register an asset. |
has/hasTexture/hasMaterial, list/listTextures/listMaterials | - | Membership + key listing. |
TextureData stores pixels device-neutral (data is RGBA8, with an optional role), so the renderer can compress for the local GPU at upload - a project ships safely to any device.
Import IR (types)
Every importer produces the same ImportedScene intermediate representation, so one consumer (spawnImportedScene) handles all sources. See the Import Overview for the pipeline philosophy.
| Symbol | Shape | Description |
|---|---|---|
ImportedScene | { meshes: ImportedMesh[]; roots: ImportedNode[]; skeletons?; clips? } | The whole imported scene. |
ImportedMesh | { id; data: MeshData; color; modelName?; submesh?; skin? } | One mesh + its default colour and optional per-vertex skin binding. |
ImportedNode | { name; position; rotation; scale; meshId; children; animator? } | One node in the imported hierarchy. |
spawnImportedScene
The single consumer of the IR: register the scene's assets in an AssetStore, then instantiate its node hierarchy into a World as GameObjects with MeshRenderer components.
| Symbol | Signature | Description |
|---|---|---|
spawnImportedScene | (world, scene, store, opts?) => Entity[] | Register meshes/skeletons/clips/skins, spawn the node tree, return the root entities. opts.onAnimator is called for skinned nodes so the caller can attach an Animator (the assets layer can't reference the runtime type). |
AnimatedNode | { entity; clip; skeleton } | Reported for each skinned node via onAnimator. |
Importers
Each importer parses a source format into an ImportedScene (or a richer result for whole-project imports). They are all generic - no model-pack-specific hardcoding.
| Format | Entry point(s) |
|---|---|
| glTF / GLB | importGltf(bytes, name), parseGlb, parseGltfJson, importModel(bytes, name) (auto-detects glTF/GLB/OBJ) |
| OBJ | parseObj(text, idPrefix) |
| FBX | (the fbx module - parsed via importModel / the editor's import flow) |
Unity .unitypackage | isUnityPackage(entries), parseUnityScene(…), parseMaterial, prefab helpers |
Unreal .uasset / project | decodeUassetStaticMesh, parseUassetTexturePng, isUnrealProject, importUnrealProject(files, onProgress?) |
| Godot | parseGodotText, parseGodotMeshResource, parseGodotMeshSurfaces, plus the godotImport IR types |
| Retarget / anim | makeRetargeter, buildCharSkeleton, buildIdleClip, remapSkin |
Awaken3D file formats also round-trip here: parseMaterialFile/serializeScriptFile/parseScriptFile/serializePrefabFile/parsePrefabFile. See Import Overview and the per-engine pages (Unity, Godot, Unreal, Models).
Geometry helpers
| Symbol | Signature | Description |
|---|---|---|
weldMesh | (m: MeshData) => MeshData | Merge duplicate vertices (shrinks geometry before shipping). |
quantizePositions / dequantizePositions | (Float32Array) ⇄ (Uint16Array + PosBbox) | Positions → u16 over the mesh AABB, and back. |
quantizeNormals / dequantizeNormals | (Float32Array) ⇄ Int8Array | Normals → octahedral int8, and back. |
quantizeUvs / dequantizeUvs | (Float32Array) ⇄ (Uint16Array + UvBbox) | UVs → u16 over the UV bbox, and back. |
Quantization cuts per-vertex bytes ~32 → ~12 and is idempotent (a value on the grid re-quantizes to the same index), so re-saving never compounds error. It backs both the binary project and the shipped scene file.
Persistence
Two output formats, both defined here. Their exact byte-level shapes and version relationship are in Data Formats & Versions.
The binary project (.awaken)
A glTF-.glb-style container: a JSON metadata chunk followed by one binary blob holding every mesh/texture byte.
| Symbol | Signature | Description |
|---|---|---|
PROJECT_VERSION | 2 | Current project format (v2 = quantized meshes; v1 = raw f32). |
ProjectBundle | interface | The in-memory round-trip shape: scene, scenes, entry, prefabs, scripts, materials, meshMaterials, materialAssets, render, dock, assetSources, meshes[], textures[]. |
encodeProject | (b: ProjectBundle) => Uint8Array | Serialize a bundle to the FRGE binary (quantizes meshes). |
decodeProject | (bytes: Uint8Array) => ProjectBundle | Parse it back (dequantizes to Float32Array, so the in-memory MeshData is identical either way). |
The shipped scene (SceneFile JSON)
The self-contained JSON the standalone player loads as scene.awaken.json.
| Symbol | Signature | Description |
|---|---|---|
SCENE_FILE_VERSION | 1 | Current ship-file format. |
SceneFile | interface | { version, title?, entry?, scene, meshes: MeshJSON[], prefabs?, scenes?, scripts?, compiled?, materials?, meshMaterials?, materialAssets?, textures?, dock?, render? }. |
MeshJSON | interface | One mesh's geometry as base64 typed-array bytes, optionally quantized (q) with bbox/uvbb; indices are u16 (idx16) when the mesh has < 65536 verts. |
ScriptAsset / ScriptMap | { name, source, kind? } / Record<string, ScriptAsset> | Scripts keyed by stable id (so renaming is safe); kind:"editor" scripts are not shipped. |
meshToJSON | (id, data) => MeshJSON | Encode one mesh (quantized) for the ship file. |
saveScene | (world, assets, types) => SceneFile | Snapshot a live world + its meshes to a SceneFile. |
loadScene | (world, assets, types, file) => void | Load a SceneFile into a world + asset store (dequantizes meshes). |
bundleToSceneFile | (b: ProjectBundle) => SceneFile | The export seam - convert an editor project bundle into the shippable JSON. |
normalizeScripts | (raw) => ScriptMap | Accept the legacy name → source shape and return the current id-keyed shape. |
bundleToSceneFile is a pure function, so it currently ships geometry + vertex/material colour but not albedo textures (encoding base64 PNG needs a browser canvas the editor supplies separately). See Export to a game file.
The ship container
An optional single-blob binary wrapper around a SceneFile + its meshes (used by the compressed export path).
| Symbol | Signature | Description |
|---|---|---|
encodeSceneContainer | (base, meshes) => Uint8Array | Pack a SceneFile (sans meshes) + mesh buffers into one blob. |
decodeSceneContainer | (bytes) => { file, meshes } | Unpack it. |
isSceneContainer | (bytes) => boolean | Magic-number check. |
compactSceneForShip | (scene, types) => SceneJSON | Drop editor-only data to slim the shipped scene. |
See also
- Import Overview - the shared-IR import philosophy.
- Data Formats & Versions - the three formats side by side, with migrations.
- Export to a game file - where
bundleToSceneFile+ the container are used. - Projects - saving/loading the binary
.awakenproject. - @awaken/render - the
MeshData/Material/TextureRoletypes this package stores.