| number | 36 |
|---|---|
| title | No model loader on the api (a GLB gun, a GLB enemy) |
| status | shipped |
| gap | ~~no **model loader** on the api (`api.loadModel(url)` / `api.GLTFLoader`)~~ — the detailed ask is "30. No model loader" below |
| blocks | `waves` (30b, 30c), `dungeon` (torch bake) |
| workaround | yes (30c) — `build-gltf.mjs` bundles three's GLTFLoader + SkeletonUtils against a shim of the RUNTIME three (`globalThis.__wavesTHREE`), imported from a blob: +45 kB per module that does it, and it must track core's three version by hand |
Found in: 30b-waves. The round's Meshy pipeline can make a gun or an enemy as a .glb, and a
module zip can carry it (api.assetUrl('assets/gun.glb')), but the api hands a module THREE
only — no GLTFLoader. Bundling three's loader into a module pulls a SECOND copy of three (its
import … from 'three'), whose classes are not the scene's; aliasing three to the runtime
api.THREE needs a hand-written shim of ~40 names.
Ask: api.loadModel(url) -> Promise<THREE.Group> through core's own loader (the same path an
Explorer import takes), or api.GLTFLoader.
Meanwhile: the Waves guns are built from primitives (src/models.js); the enemies are the template's capsule groups.
30c: worked around in the module (row #36): Waves 2.1.0 bundles three's own loader against a
shim of api.THREE and ships Meshy guns, rigged walking enemies and a crystal inside its zip.
34 R7 (core 1.20): SHIPPED. api.loadModel('assets/x.glb', opts) resolves to a handle:
scene (the module's own copy), instance({ownMaterials?}) (more copies — own bones when
skinned), animations, info, release(obj), dispose(). Parsed once per URL through core's
loader (Draco, Meshopt, KTX2 — the transcoder fetched only for a file that needs it), automatic
LOD by default (or lod: false | {ratios, distances, minTriangles} | [{file, ratio}]), released
when the module unloads. Waves 2.3.0 and Dungeon Kit 2.4.0 load through it.