# How it works

Import-once plans, random-access byte IO, canonical formats, async resolution, and production Wasm flags.

Canonical page: https://libassimp.xyz/docs/how-it-works

## One plan [#one-plan]

```mermaid
flowchart LR
  A["Entry bytes + supplied sidecars"] --> B["Random-access byte IOSystem"]
  R["Promise-capable resolve(name)"] -. "missing file" .-> B
  B --> C["Import + post-process once"]
  C --> D["Export target 0"]
  C --> E["Export target 1"]
  C --> F["Export target N"]
  D --> G["Atomic positional results"]
  E --> G
  F --> G
```

The custom IOSystem exposes named in-memory byte arrays through Assimp's random-access `Read`, `Seek`, and `Tell` contract. It is not Emscripten MEMFS: there is no path mount, duplicate filesystem copy, or public filesystem lifetime. A generic stream cannot replace it because importers seek, probe, and reopen sidecars.

`convertFormats` validates the whole request, copies inputs once, imports and post-processes one scene, then exports targets sequentially into isolated output stores. A later failure destroys all native output state and rejects with positional context. Singular `convert` creates a one-target plan and unwraps the same result path.

## Async resolution with one artifact [#async-resolution-with-one-artifact]

The package ships one baseline-compatible `libassimp.wasm` artifact:

```mermaid
flowchart TD
  A["Instantiate finalized artifact"] --> B{"Suspending + promising exist?"}
  B -- yes --> C["Wrap dispatch import and raw plan export with JSPI"]
  B -- no --> D["Plain import/export + pending abort"]
  D --> E["Await cached resolver promises"]
  E --> F["Replay staged plan"]
  C --> G["Same Promise API"]
  F --> G
```

The replay cache is per conversion and invokes the consumer resolver once per exact name. Each pending attempt stops host callbacks immediately, awaits newly discovered work, and reuses settled bytes on the next attempt. JSPI-capable Chromium suspends inside parsing instead. Both paths use the same final SHA and have exact output, resolver-trace, and error parity tests.

Each `Assimp` instance serializes singular and plural work through one rejection-safe FIFO queue. Separate instances are the parallelism boundary. `dispose()` rejects new calls and releases the runtime after queued work settles.

## Canonical formats [#canonical-formats]

Public targets are not Assimp exporter IDs. `glb` and `gltf` always route to glTF 2; `dae` and `step` are canonical names; FBX/PLY/STL encoding uses `exportOptions.binary`; OBJ sidecar behavior uses `exportOptions.materials` and defaults to materials.

- `3ds`: `result.3ds` — Autodesk 3DS (legacy)
- `3mf`: `result.3mf` — 3D Manufacturing Format
- `assjson`: `result.json` — Assimp JSON scene
- `dae`: `result.dae` — COLLADA Digital Asset Exchange
- `fbx`: `result.fbx` — Autodesk FBX
- `glb`: `result.glb` — glTF 2 binary container
- `gltf`: `result.gltf` — glTF 2 JSON with sidecars
- `obj`: `result.obj` — Wavefront OBJ
- `ply`: `result.ply` — Stanford Polygon Library
- `step`: `result.stp` — ISO 10303 STEP
- `stl`: `result.stl` — Stereolithography
- `usda`: `result.usda` — Universal Scene Description ASCII
- `usdz`: `result.usdz` — Universal Scene Description ZIP container
- `x`: `result.x` — DirectX X file
- `x3d`: `result.x3d` — Extensible 3D

The import table is directional: it lists readable extensions, not writable targets.

- 3D GameStudio Heightmap (HMP): `.hmp`
- 3mf: `.3mf`
- AC3D: `.ac`, `.acc`, `.ac3d`
- ASE: `.ase`, `.ask`
- Additive manufacturing file format(AMF): `.amf`
- Autodesk FBX: `.fbx`
- BVH Importer (MoCap): `.bvh`
- Blender 3D Importer (http://www.blender3d.org): `.blend`
- BlitzBasic 3D: `.b3d`
- CharacterStudio Motion Importer (MoCap): `.csm`
- Collada: `.dae`, `.xml`, `.zae`
- Direct3D XFile: `.x`
- Discreet 3DS: `.3ds`, `.prj`
- Doom 3 / MD5 Mesh: `.md5mesh`, `.md5camera`, `.md5anim`
- Drawing Interchange Format (DXF): `.dxf`
- Industry Foundation Classes (IFC) Importer (Web-IFC): `.ifc`
- Inter-Quake Model: `.iqm`
- LightWave Scene: `.lws`, `.mot`
- LightWave/Modo Object: `.lwo`, `.lxo`
- MMD: `.pmx`
- Milkshape 3D: `.ms3d`
- Nendo Mesh: `.ndo`
- Neutral File Format: `.enff`, `.nff`
- OFF: `.off`
- Ogre3D Mesh: `.mesh`, `.mesh.xml`
- Open Game Engine Exchange: `.ogex`
- Quake II Mesh: `.md2`
- Quake III BSP: `.bsp`, `.pk3`
- Quake III Mesh: `.md3`
- Quake Mesh / 3D GameStudio Mesh: `.mdl`
- Quick3D: `.q3o`, `.q3s`
- Return To Castle Wolfenstein Mesh: `.mdc`
- Silo SIB: `.sib`
- Stanford Polygon Library (PLY): `.ply`
- Stereolithography (STL): `.stl`
- TrueSpace Object: `.cob`, `.scn`
- USD Object: `.usd`, `.usda`, `.usdc`, `.usdz`
- Unreal Mesh: `.3d`, `.uc`
- VRML(WRL, X3DV) and Extensible 3D(X3D, X3DB): `.wrl`, `.x3d`, `.x3db`, `.x3dv`
- Valve SMD: `.smd`, `.vta`
- Wavefront Object: `.obj`
- XGL: `.xgl`, `.zgl`
- glTF: `.gltf`, `.glb`
- glTF2: `.vrm`

`assimpCapabilities`, the instance `formats` tables, `conversionEdges`, TypeScript unions, validation, and these matrices come from one checked-in compiler-derived registry. Native names never enter the public catalog.

## Post-processing [#post-processing]

`defaultPostProcess` is `Triangulate`, `GenUVCoords`, `JoinIdenticalVertices`, and `SortByPType`. Supplying `postProcess` is an exact replacement. `assimpCapabilities.postProcess` publishes every supported named step, bit value, description, and conflict.

## Production build [#production-build]

The artifact compiles and links with `-O3 -DNDEBUG`, fixed SIMD, mimalloc, Wasm exceptions, Closure-compiled glue, constructor evaluation, and standalone `wasm-opt -O4 --converge --traps-never-happen --skip-pass=code-folding`. The build explicitly pins `WASM_LEGACY_EXCEPTIONS=1`; exnref waits until every documented host floor supports it. LTO, relaxed SIMD, pthreads, Asyncify, and mode-specific JSPI artifacts remain absent.

The build manifest records exact definitions, compile/link/optimizer flags, import/export inventory, and raw/gzip/brotli size. CI ratchets those measured files rather than estimating them.