# GLB asset import The `glb-static.1` compiler creates immutable model artifacts from self-contained GLB 2 files. This is the first model-processing stage of milestone 7. GPU installation and authored-world model references are now connected through the [static renderer](MODEL_RENDERING.md) and [authored-model integration](AUTHORED_MODELS.md). Default Darkwind art remains procedural; prefab model composition remains open. The [skeletal profile](SKELETAL_ANIMATION.md) now adds bounded skin import and rendering. [Rigid node animation](ANIMATION_CLIPS.md) is now supported in the development compiler and renderer probe. [Material textures](MATERIAL_TEXTURES.md) extend this path with embedded PNG/JPEG maps under `glb-textured.1`. ## Run the importer ```sh npm run import:model -- games/engine-zoo/assets/lantern-plinth.glb /tmp/lantern-plinth.model.json ``` The output path must be new. Input is a regular file of at most 8 MiB. The command launches the importer in a separate process with a 256 MiB JavaScript heap and a 30-second deadline. Source data never chooses code, filesystem paths or network resources. The compiler performs no external fetches. Input/output envelopes are bounded to 16 MiB. These are process/heap limits for trusted compiler code, not an OS sandbox or total-RSS guarantee. The CLI checks the worker input identity and output checksum before writing. It writes and syncs a temporary file, then publishes it with an exclusive hard link in the destination directory. Existing paths are never overwritten, failed writes do not expose a partial final artifact, and temporary files are cleaned up. This is atomic visibility, not a power-loss durability guarantee. `npm run build:author` also packages `import-model.js` and `asset-worker.js`. Run `node author-dist/import-model.js ` outside the source tree without development dependencies. The existing Docker build includes this entire directory. ## Supported profile - One JSON chunk and one embedded BIN chunk, with exact framing, byte lengths and padding. No URIs or required/optional extensions. - Triangle-list meshes with unsigned 8/16/32-bit indices, or non-indexed triangles. Reserved restart indices and out-of-range references fail. - Float32 positions and normals; float32 or normalized unsigned 8/16-bit UVs. Packed, interleaved and sparse accessors are decoded with range/alignment checks. Position bounds are required and checked against decoded values. - Missing normals generate flat face normals by expanding indexed triangles. Degenerate triangles without normals fail explicitly. Provided normals must be approximately unit length and are normalized into float32 output. - Opaque metallic/roughness materials with base color, emissive factor and double-sided metadata; the textured profile adds base color, metallic/roughness and emissive maps. The [surface profile](SURFACE_MATERIALS.md) adds normal/occlusion maps and authored/generated tangents. The [masked profile](ALPHA_MATERIALS.md) adds alpha cutoff and matching shadows. Alpha blending, vertex-color and other unsupported attributes produce source-path errors. - Named node hierarchies, TRS and decomposable affine matrices, explicit/default scene selection, reused meshes and mirrored transforms. All nodes are checked for cycles, multiple parents and excessive depth, even outside the selected scene. Composed hierarchy matrices retain shear and reflection information. The implementation follows the [Khronos glTF 2.0 specification](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html). Coordinates retain its right-handed, Y-up convention and metre units. The API accepts an explicit uniform unit scale and scene selection; the CLI currently uses scale 1 and the default scene. UV coordinates are preserved. Unsupported texture/material features, animation and skins beyond their documented subsets, morph targets, cameras, non-triangle topology and compressed extensions are rejected until their processing/runtime paths exist. ## Budgets and artifact identity The profile admits at most 1 MiB JSON, 1,024 accessors, 1,024 buffer views, 2,097,152 decoded accessor values, 131,072 emitted vertices, 393,216 indices, 256 source primitives, 256 nodes, 128 authored materials plus a default, 16 scenes and 64 hierarchy levels. The selected scene admits at most 4,096 primitive instances and 262,144 instanced triangles. World matrices and computed bounds are finite and bounded. Missing-normal expansion and repeated mesh instances consume their respective budgets before publication. Each artifact contains packed position/normal/UV arrays, uint32-compatible indices, material and node catalogs, source locations, local/world matrices, mirrored flags, per-primitive/node/scene bounds and an independent set of conservative world-space AABB proxy candidates. Those boxes are metadata for later collision processing, not installed physics colliders or a substitute for accurate collision meshes. Identity includes the original byte hash, importer version, processing settings and complete normalized output. Signed zero is canonicalized so the direct API, JSON transport and isolated process agree exactly. Source files and provenance remain separate from runtime derivatives. Outputs own and freeze their data. The fixed profile must change when processing semantics or limits change. ## Evidence and remaining work The project-owned lantern-plinth fixture includes indexed meshes, generated flat normals, materials, hierarchy, scale, rotation and a mirrored instance. Regenerate its GLB with `python tools/cli/model-fixture.py`. Tests also cover sparse substitutions, interleaved normals/normalized UVs, invalid framing, nonfinite values, inconsistent declared bounds, unsupported features, cyclic/multi-parent nodes, singular/sheared local transforms, mesh expansion, scene-wide budgets, worker checksums and portable packaged CLI execution. The current compiler also generates [portable static-model detail variants](MODEL_LOD.md#portable-import-artifacts) in the isolated process/editor Worker. Format 7 binds these variants to the original model artifact; retained formats 1–6 remain supported. The importer alone does not publish a catalog, update a world, install GPU buffers or coordinate asset-job revisions. Those paths are supplied by the authored-model integration below; independent streamed variants and broader asset processing remain open. Skeletal import is added by the subsequent profile linked above. The existing prefab coordinator remains separate. No complete milestone is closed by this compiler stage. The [static model renderer](MODEL_RENDERING.md) now installs these artifacts in the Engine Observatory. The [authored-model integration](AUTHORED_MODELS.md) adds world placement, portable embedded catalogs and static triangle collision.