Skip to content

@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.

MemberTypeDescription
meshesMap<string, MeshData>Geometry by mesh id.
texturesMap<string, TextureData>Device-neutral texture pixels by id.
materialsMap<string, Material>Authored materials by id.
skeletons / clips / skinsMap<string, …>Skeletal-animation assets (skins keyed by the skinned mesh id).
revisionnumberBumped on every add/replace, so a per-frame uploader can skip re-scanning when nothing changed.
addMesh/addTexture/addMaterial/addSkeleton/addClip/addSkin(id, data) => voidRegister 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.

SymbolShapeDescription
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.

SymbolSignatureDescription
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.

FormatEntry point(s)
glTF / GLBimportGltf(bytes, name), parseGlb, parseGltfJson, importModel(bytes, name) (auto-detects glTF/GLB/OBJ)
OBJparseObj(text, idPrefix)
FBX(the fbx module - parsed via importModel / the editor's import flow)
Unity .unitypackageisUnityPackage(entries), parseUnityScene(…), parseMaterial, prefab helpers
Unreal .uasset / projectdecodeUassetStaticMesh, parseUassetTexturePng, isUnrealProject, importUnrealProject(files, onProgress?)
GodotparseGodotText, parseGodotMeshResource, parseGodotMeshSurfaces, plus the godotImport IR types
Retarget / animmakeRetargeter, 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

SymbolSignatureDescription
weldMesh(m: MeshData) => MeshDataMerge duplicate vertices (shrinks geometry before shipping).
quantizePositions / dequantizePositions(Float32Array) ⇄ (Uint16Array + PosBbox)Positions → u16 over the mesh AABB, and back.
quantizeNormals / dequantizeNormals(Float32Array) ⇄ Int8ArrayNormals → 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.

SymbolSignatureDescription
PROJECT_VERSION2Current project format (v2 = quantized meshes; v1 = raw f32).
ProjectBundleinterfaceThe in-memory round-trip shape: scene, scenes, entry, prefabs, scripts, materials, meshMaterials, materialAssets, render, dock, assetSources, meshes[], textures[].
encodeProject(b: ProjectBundle) => Uint8ArraySerialize a bundle to the FRGE binary (quantizes meshes).
decodeProject(bytes: Uint8Array) => ProjectBundleParse 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.

SymbolSignatureDescription
SCENE_FILE_VERSION1Current ship-file format.
SceneFileinterface{ version, title?, entry?, scene, meshes: MeshJSON[], prefabs?, scenes?, scripts?, compiled?, materials?, meshMaterials?, materialAssets?, textures?, dock?, render? }.
MeshJSONinterfaceOne 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) => MeshJSONEncode one mesh (quantized) for the ship file.
saveScene(world, assets, types) => SceneFileSnapshot a live world + its meshes to a SceneFile.
loadScene(world, assets, types, file) => voidLoad a SceneFile into a world + asset store (dequantizes meshes).
bundleToSceneFile(b: ProjectBundle) => SceneFileThe export seam - convert an editor project bundle into the shippable JSON.
normalizeScripts(raw) => ScriptMapAccept 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).

SymbolSignatureDescription
encodeSceneContainer(base, meshes) => Uint8ArrayPack a SceneFile (sans meshes) + mesh buffers into one blob.
decodeSceneContainer(bytes) => { file, meshes }Unpack it.
isSceneContainer(bytes) => booleanMagic-number check.
compactSceneForShip(scene, types) => SceneJSONDrop editor-only data to slim the shipped scene.

See also

Awaken — browser-native WebGPU game engine.