@forgeax/engine-gltf 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +18 -11
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/__tests__/extension-admission.unit.test.d.ts +2 -0
  4. package/dist/__tests__/extension-admission.unit.test.d.ts.map +1 -0
  5. package/dist/__tests__/source-key-diagnostics.integration.test.d.ts +2 -0
  6. package/dist/__tests__/source-key-diagnostics.integration.test.d.ts.map +1 -0
  7. package/dist/bridge.d.ts +5 -6
  8. package/dist/bridge.d.ts.map +1 -1
  9. package/dist/check-extensions.d.ts.map +1 -1
  10. package/dist/cli-gltf.mjs +32 -16
  11. package/dist/cli-gltf.mjs.map +1 -1
  12. package/dist/gltf-importer.d.ts.map +1 -1
  13. package/dist/importer-entry.mjs +5 -1
  14. package/dist/importer-entry.mjs.map +1 -1
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.mjs +31 -10
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/node-file-entry.mjs +5 -1
  20. package/dist/node-file-entry.mjs.map +1 -1
  21. package/dist/parse-gltf.d.ts.map +1 -1
  22. package/dist/source-key.d.ts +26 -4
  23. package/dist/source-key.d.ts.map +1 -1
  24. package/package.json +13 -15
  25. package/src/__tests__/extension-admission.unit.test.ts +19 -0
  26. package/src/__tests__/gltf.unit.test.ts +1 -1
  27. package/src/__tests__/material-texture-transform.unit.test.ts +30 -0
  28. package/src/__tests__/meshopt-real-matrix.integration.test.ts +108 -24
  29. package/src/__tests__/morph-import.integration.test.ts +31 -44
  30. package/src/__tests__/source-key-diagnostics.integration.test.ts +140 -0
  31. package/src/__tests__/source-key-producer.integration.test.ts +2 -2
  32. package/src/bridge.ts +9 -10
  33. package/src/check-extensions.ts +8 -4
  34. package/src/cli-gltf.ts +1 -6
  35. package/src/gltf-importer.ts +1 -2
  36. package/src/index.ts +1 -0
  37. package/src/parse-gltf.ts +7 -5
  38. package/src/source-key.ts +51 -17
  39. package/dist/__tests__/asset-runtime-fixture.d.ts +0 -14
  40. package/dist/__tests__/asset-runtime-fixture.d.ts.map +0 -1
  41. package/src/__tests__/asset-runtime-fixture.ts +0 -278
package/README.md CHANGED
@@ -12,7 +12,7 @@ identifier is invented by the glTF bridge.
12
12
 
13
13
  If a source requests a UV set that the primitive does not provide, handle `gltf-material-uv-set-missing` using its material, primitive, slot, requested set, and available sets. Add the source UV set and re-import; do not substitute a custom mesh or discard the slot transform.
14
14
 
15
- > Runtime glTF 2.0 importer (Tier-C subset). Pure-function pipeline `parseGlb` / `parseGltf` / `toAssetPack` consumed by build-time CLI plugin bin `forgeax-engine-remote-gltf` (resolved via PATH-prefix scan for `forgeax-engine-remote-`) writing `<source>.meta.json` (external-asset-package; dispatch on top-level `importer: 'gltf'`); runtime spawn uses typed `assets.load(sceneGuid, sceneAssetKind)`, one World shared ref, and `world.instantiateScene` (no `loadGltf(url)` parallel API).
15
+ > Runtime glTF 2.0 importer (Tier-C subset). Pure-function pipeline `parseGlb` / `parseGltf` / `toAssetPack` consumed by build-time CLI plugin bin `forgeax-engine-remote-gltf` (resolved via PATH-prefix scan for `forgeax-engine-remote-`) writing `<source>.meta.json` (external-asset-package; dispatch on top-level `importer: 'gltf'`); runtime spawn happens via the existing `loadByGuid<SceneAsset>` plus `world.instantiateScene` 4-step recipe (no `loadGltf(url)` parallel API).
16
16
 
17
17
  > [!IMPORTANT]
18
18
  > `toAssetPack` and `reimportReuseMeta` return `Result` values. The producer derives semantic `sourceKey` values before GUID reuse; duplicate or ambiguous identities return `duplicate-source-key` / `ambiguous-source-key` and the CLI leaves the previous sidecar untouched. `sourceIndex` is a locator only, never a generated identity.
@@ -110,7 +110,7 @@ only its slot index. Canonical `SceneAsset` nodes carry `MeshFilter` plus an
110
110
  empty `MeshRenderer.materials` override vector, so imported defaults remain
111
111
  mesh-owned and reimport-safe.
112
112
 
113
- Out of scope (each routed to its own `feat-future-*` anchor in `requirements.md` OOS-1 .. OOS-15): KHR extensions (note: `EXT_mesh_gpu_instancing` happy-path is supported, see feat-20260518-gltf-instancing-and-name-component) / morph targets other than the explicit `COLOR_0` deferred signal / orthographic camera / sparse accessors / inspector future fields / pixel-parity vs three.js. Dense interleaved `COLOR_0` is supported; other interleaved accessor consumers retain their existing scope. v1.1 OOS additions (locked by feat-20260518-gltf-instancing-and-name-component): multi-primitive instancing / mesh-level + material-level + scene-level Name (only node.name lands as ECS `Name`) / instancing hard cap / SoA TRS direct-to-GPU pipe / IR-to-GPU direct path / ROTATION BYTE/SHORT normalized encoding / Babylon thin-instances style SoA channel / Bevy multi-tier Name propagation.
113
+ Out of scope (each routed to its own `feat-future-*` anchor in `requirements.md` OOS-1 .. OOS-15): KHR extensions other than the supported `EXT_mesh_gpu_instancing` and `KHR_texture_transform` paths / morph targets other than the explicit `COLOR_0` deferred signal / orthographic camera / sparse accessors / inspector future fields / pixel-parity vs three.js. Dense interleaved `COLOR_0` is supported; other interleaved accessor consumers retain their existing scope. v1.1 OOS additions (locked by feat-20260518-gltf-instancing-and-name-component): multi-primitive instancing / mesh-level + material-level + scene-level Name (only node.name lands as ECS `Name`) / instancing hard cap / SoA TRS direct-to-GPU pipe / IR-to-GPU direct path / ROTATION BYTE/SHORT normalized encoding / Babylon thin-instances style SoA channel / Bevy multi-tier Name propagation.
114
114
 
115
115
  ## Importer sub-asset PODs (7 kinds)
116
116
 
@@ -126,7 +126,7 @@ Out of scope (each routed to its own `feat-future-*` anchor in `requirements.md`
126
126
  | `skin` | `SkinAsset` | skeleton GUID |
127
127
  | `animation-clip` | `AnimationClip` | -- |
128
128
 
129
- Skinned glTFs (e.g. Khronos `Fox.glb` with 24 joints + 3 clips) flow through the same typed `assets.load(sceneGuid, sceneAssetKind)` + World `SceneAsset` shared-ref spine as static glTFs. The bridge (`gltfDocToSceneAsset`) auto-emits `Skin { skeleton: <skeleton-guid-string> }` on every node with `NodeIr.skinIndex !== null` when the caller passes `skeletonGuidBySkinIndex`; the World scene owner resolves the GUID to a shared ref at instantiate time, while mesh material dependencies load recursively from `MeshAsset.materialSlots[]`. `postSpawnResolveJoints` (`@forgeax/engine-runtime`) fills `Skin.joints[]` by walking `SkinAsset.jointPaths` against the spawn root's `ChildOf`-descendant subtree, so multiple `world.instantiateScene()` calls on the same skinned `SceneAsset` produce independently-posed instances (no cross-spawn joint sharing).
129
+ Skinned glTFs (e.g. Khronos `Fox.glb` with 24 joints + 3 clips) flow through the same `loadByGuid<SceneAsset>` + `assets.instantiate` spine as static glTFs. The bridge (`gltfDocToSceneAsset`) auto-emits `Skin { skeleton: <skeleton-guid-string> }` on every node with `NodeIr.skinIndex !== null` when the caller passes `skeletonGuidBySkinIndex`; `AssetRegistry._resolveSceneGuids` resolves the GUID to a runtime Handle at instantiate time, while mesh material dependencies load recursively from `MeshAsset.materialSlots[]`. `postSpawnResolveJoints` (`@forgeax/engine-runtime`) fills `Skin.joints[]` by walking `SkinAsset.jointPaths` against the spawn root's `ChildOf`-descendant subtree, so multiple `instantiate()` calls on the same skinned `SceneAsset` produce independently-posed instances (no cross-spawn joint sharing).
130
130
 
131
131
  Sample reference: `apps/hello/skin` -- 3 Khronos Fox foxes side-by-side, each running a different clip (Survey / Walk / Run). Asset source under `forgeax-engine-assets/khronos-gltf-samples/Fox/` (CC BY 4.0; ATTRIBUTION.md alongside).
132
132
 
@@ -141,7 +141,7 @@ Sample reference: `apps/hello/skin` -- 3 Khronos Fox foxes side-by-side, each ru
141
141
  | `gltf-malformed-header` | GLB magic / version / length header rejection or missing JSON chunk |
142
142
  | `gltf-version-unsupported` | `asset.version` is not `'2.0'` |
143
143
  | `gltf-buffer-out-of-bounds` | accessor reads past `bufferView.byteLength` |
144
- | `gltf-extension-unsupported` | `extensionsRequired[]` lists an extension outside the v1 allowlist (`['EXT_mesh_gpu_instancing']`) |
144
+ | `gltf-extension-unsupported` | `extensionsRequired[]` lists an extension outside the supported allowlist (`EXT_mesh_gpu_instancing`, `KHR_texture_transform`) |
145
145
  | `gltf-accessor-type-mismatch` | sparse / morph / interleaved / unknown componentType accessor (4 reasons) |
146
146
  | `gltf-texture-load-failed` | `externalLoader` rejected for a texture `uri`; `detail.uri` carries the failing URI; hint: `'check sidecar meta.json + textures/ directory + vite-plugin-pack /__pack/lookup'` |
147
147
  | `gltf-meta-missing` | sidecar `<source>.meta.json` is absent next to the `.gltf` / `.glb` source file |
@@ -154,6 +154,11 @@ Sample reference: `apps/hello/skin` -- 3 Khronos Fox foxes side-by-side, each ru
154
154
  | `gltf-color-accessor-unsupported` | `COLOR_0` type/component/normalized combination, sparse input, or morph-target input is deferred |
155
155
  | `gltf-color-accessor-malformed` | `COLOR_0` count, finite/range, buffer bounds, or reference validation failed |
156
156
 
157
+ Source-key conflicts are producer failures, not automatic renames. A
158
+ `duplicate-source-key` or `ambiguous-source-key` detail includes the semantic
159
+ `key` and the smallest conflicting `entries` (`kind`, `name`, and
160
+ `sourceIndex`); repair the source or its metadata and retry the same GUID.
161
+
157
162
  When `ImporterRegistry` + `runImport` consumes a glTF source, malformed base64 in a buffer data URI is returned as the existing `ImportError` `source-validation-failed` with `detail.diagnostics[].code === 'gltf-buffer-data-uri-invalid'`. The failed attempt publishes no Pack; after repairing the same source, Meta, and GUID declarations, the same registry/process can retry normally.
158
163
 
159
164
  ## Skin & Animation importer (feat-20260523)
@@ -166,17 +171,19 @@ When `ImporterRegistry` + `runImport` consumes a glTF source, malformed base64 i
166
171
  ## 4-step runtime recipe (apps/hello/gltf, M5)
167
172
 
168
173
  ```ts
169
- import { sceneAssetKind } from '@forgeax/engine-scene';
174
+ // 1. configure pack index (vite-plugin-pack provides /__pack/lookup/:guid in dev mode)
175
+ engine.assets.configurePackIndex('/box-pack-index.json');
170
176
 
171
- // 1. load the published SceneAsset through the typed owner decoder
172
- const sceneResult = await assets.load(sceneGuid, sceneAssetKind);
177
+ // 2-4. load mesh / material / scene by GUID, then instantiate scene into world
178
+ const sceneResult = await engine.assets.loadByGuid<SceneAsset>(sceneGuid);
173
179
  if (!sceneResult.ok) {
180
+ // GltfError surfaced upstream from the importer is converted into an AssetError
181
+ // here; the runtime AssetRegistry uses the existing 4-member AssetErrorCode.
174
182
  return;
175
183
  }
176
- // 2-3. World owns the ordinary shared ref and instantiates the scene
177
- const sceneHandle = world.internSharedRef('SceneAsset', sceneResult.value);
178
- const root = world.instantiateScene(sceneHandle);
179
- if (!root.ok) return;
184
+ const root = engine.assets.instantiate(sceneResult.value, world);
185
+ // `root` is the synthetic root Entity (carries SceneInstance + identity Transform);
186
+ // equivalent to world.instantiateScene(handle).
180
187
  ```
181
188
 
182
189
  ## CLI plugin — `forgeax-engine-remote-gltf`