@forgeax/engine-assets-runtime 0.1.4 → 0.1.7

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 (311) hide show
  1. package/README.md +453 -175
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/__tests__/aabb.unit.test.d.ts +2 -0
  4. package/dist/__tests__/aabb.unit.test.d.ts.map +1 -0
  5. package/dist/__tests__/artifact-integrity.unit.test.d.ts +2 -0
  6. package/dist/__tests__/artifact-integrity.unit.test.d.ts.map +1 -0
  7. package/dist/__tests__/artifact-io.unit.test.d.ts +2 -0
  8. package/dist/__tests__/artifact-io.unit.test.d.ts.map +1 -0
  9. package/dist/__tests__/asset-evidence-sdk.integration.test.d.ts +2 -0
  10. package/dist/__tests__/asset-evidence-sdk.integration.test.d.ts.map +1 -0
  11. package/dist/__tests__/asset-evidence.unit.test.d.ts +2 -0
  12. package/dist/__tests__/asset-evidence.unit.test.d.ts.map +1 -0
  13. package/dist/__tests__/asset-kind.unit.test.d.ts +2 -0
  14. package/dist/__tests__/asset-kind.unit.test.d.ts.map +1 -0
  15. package/dist/__tests__/asset-registry-catalog-reconcile.integration.test.d.ts +2 -0
  16. package/dist/__tests__/asset-registry-catalog-reconcile.integration.test.d.ts.map +1 -0
  17. package/dist/__tests__/asset-registry-catalog-reconcile.unit.test.d.ts +2 -0
  18. package/dist/__tests__/asset-registry-catalog-reconcile.unit.test.d.ts.map +1 -0
  19. package/dist/__tests__/asset-registry-catalog.unit.test.d.ts +2 -0
  20. package/dist/__tests__/asset-registry-catalog.unit.test.d.ts.map +1 -0
  21. package/dist/__tests__/asset-registry.pack-cache.test.d.ts +2 -0
  22. package/dist/__tests__/asset-registry.pack-cache.test.d.ts.map +1 -0
  23. package/dist/__tests__/asset-registry.unit.test.d.ts +2 -0
  24. package/dist/__tests__/asset-registry.unit.test.d.ts.map +1 -0
  25. package/dist/__tests__/asset-runtime-error-code-owner.test-d.d.ts +2 -0
  26. package/dist/__tests__/asset-runtime-error-code-owner.test-d.d.ts.map +1 -0
  27. package/dist/__tests__/catalog-replica.unit.test.d.ts +2 -0
  28. package/dist/__tests__/catalog-replica.unit.test.d.ts.map +1 -0
  29. package/dist/__tests__/catalog-source-v2.unit.test.d.ts +2 -0
  30. package/dist/__tests__/catalog-source-v2.unit.test.d.ts.map +1 -0
  31. package/dist/__tests__/catalog-source.unit.test.d.ts +2 -0
  32. package/dist/__tests__/catalog-source.unit.test.d.ts.map +1 -0
  33. package/dist/__tests__/catalog-subscription-order.unit.test.d.ts +2 -0
  34. package/dist/__tests__/catalog-subscription-order.unit.test.d.ts.map +1 -0
  35. package/dist/__tests__/catalog-subscription.unit.test.d.ts +2 -0
  36. package/dist/__tests__/catalog-subscription.unit.test.d.ts.map +1 -0
  37. package/dist/__tests__/decode-image-bytes-pass-through.test.d.ts +2 -0
  38. package/dist/__tests__/decode-image-bytes-pass-through.test.d.ts.map +1 -0
  39. package/dist/__tests__/decode-image-bytes.browser.test.d.ts +2 -0
  40. package/dist/__tests__/decode-image-bytes.browser.test.d.ts.map +1 -0
  41. package/dist/__tests__/decode-image-bytes.test-d.d.ts +2 -0
  42. package/dist/__tests__/decode-image-bytes.test-d.d.ts.map +1 -0
  43. package/dist/__tests__/decode-image-bytes.test.d.ts +2 -0
  44. package/dist/__tests__/decode-image-bytes.test.d.ts.map +1 -0
  45. package/dist/__tests__/dynamic-texture-store.unit.test.d.ts +2 -0
  46. package/dist/__tests__/dynamic-texture-store.unit.test.d.ts.map +1 -0
  47. package/dist/__tests__/errors-asset.unit.test.d.ts +2 -0
  48. package/dist/__tests__/errors-asset.unit.test.d.ts.map +1 -0
  49. package/dist/__tests__/inline-pack-loaders.unit.test.d.ts +2 -0
  50. package/dist/__tests__/inline-pack-loaders.unit.test.d.ts.map +1 -0
  51. package/dist/__tests__/instantiate-context.unit.test.d.ts +2 -0
  52. package/dist/__tests__/instantiate-context.unit.test.d.ts.map +1 -0
  53. package/dist/__tests__/instantiate-publication-fence.unit.test.d.ts +2 -0
  54. package/dist/__tests__/instantiate-publication-fence.unit.test.d.ts.map +1 -0
  55. package/dist/__tests__/instantiate.unit.test.d.ts +2 -0
  56. package/dist/__tests__/instantiate.unit.test.d.ts.map +1 -0
  57. package/dist/__tests__/loader-input-contract.unit.test.d.ts +2 -0
  58. package/dist/__tests__/loader-input-contract.unit.test.d.ts.map +1 -0
  59. package/dist/__tests__/loader-registry.unit.test.d.ts +2 -0
  60. package/dist/__tests__/loader-registry.unit.test.d.ts.map +1 -0
  61. package/dist/__tests__/material-dependency-invalidation.unit.test.d.ts +2 -0
  62. package/dist/__tests__/material-dependency-invalidation.unit.test.d.ts.map +1 -0
  63. package/dist/__tests__/material-generation-cache.unit.test.d.ts +2 -0
  64. package/dist/__tests__/material-generation-cache.unit.test.d.ts.map +1 -0
  65. package/dist/__tests__/material-load-consumer.test-d.d.ts +2 -0
  66. package/dist/__tests__/material-load-consumer.test-d.d.ts.map +1 -0
  67. package/dist/__tests__/material-ready.integration.test.d.ts +2 -0
  68. package/dist/__tests__/material-ready.integration.test.d.ts.map +1 -0
  69. package/dist/__tests__/material-stale-generation.unit.test.d.ts +2 -0
  70. package/dist/__tests__/material-stale-generation.unit.test.d.ts.map +1 -0
  71. package/dist/__tests__/mesh-bin-morph-v3.test.d.ts +2 -0
  72. package/dist/__tests__/mesh-bin-morph-v3.test.d.ts.map +1 -0
  73. package/dist/__tests__/mesh-bin.unit.test.d.ts +2 -0
  74. package/dist/__tests__/mesh-bin.unit.test.d.ts.map +1 -0
  75. package/dist/__tests__/mipmap-generator.unit.test.d.ts +2 -0
  76. package/dist/__tests__/mipmap-generator.unit.test.d.ts.map +1 -0
  77. package/dist/__tests__/pack-artifact-transcode-model-owner.test.d.ts +2 -0
  78. package/dist/__tests__/pack-artifact-transcode-model-owner.test.d.ts.map +1 -0
  79. package/dist/__tests__/pack-basis-load.integration.test.d.ts +2 -0
  80. package/dist/__tests__/pack-basis-load.integration.test.d.ts.map +1 -0
  81. package/dist/__tests__/payload-validate.unit.test.d.ts +2 -0
  82. package/dist/__tests__/payload-validate.unit.test.d.ts.map +1 -0
  83. package/dist/__tests__/plugin.test.d.ts +2 -0
  84. package/dist/__tests__/plugin.test.d.ts.map +1 -0
  85. package/dist/__tests__/registry-concurrency.bench.test.d.ts +2 -0
  86. package/dist/__tests__/registry-concurrency.bench.test.d.ts.map +1 -0
  87. package/dist/__tests__/registry-failure-retry.integration.test.d.ts +2 -0
  88. package/dist/__tests__/registry-failure-retry.integration.test.d.ts.map +1 -0
  89. package/dist/__tests__/registry-load-graph.integration.test.d.ts +2 -0
  90. package/dist/__tests__/registry-load-graph.integration.test.d.ts.map +1 -0
  91. package/dist/__tests__/registry-load-state.unit.test.d.ts +2 -0
  92. package/dist/__tests__/registry-load-state.unit.test.d.ts.map +1 -0
  93. package/dist/__tests__/registry-package-cache.unit.test.d.ts +2 -0
  94. package/dist/__tests__/registry-package-cache.unit.test.d.ts.map +1 -0
  95. package/dist/__tests__/registry-public-ready.unit.test.d.ts +2 -0
  96. package/dist/__tests__/registry-public-ready.unit.test.d.ts.map +1 -0
  97. package/dist/__tests__/resolve-asset-handle.unit.test.d.ts +2 -0
  98. package/dist/__tests__/resolve-asset-handle.unit.test.d.ts.map +1 -0
  99. package/dist/__tests__/scene-handle-fields.unit.test.d.ts +2 -0
  100. package/dist/__tests__/scene-handle-fields.unit.test.d.ts.map +1 -0
  101. package/dist/__tests__/scene-payload.unit.test.d.ts +2 -0
  102. package/dist/__tests__/scene-payload.unit.test.d.ts.map +1 -0
  103. package/dist/__tests__/scene-publication-fence.test.d.ts +2 -0
  104. package/dist/__tests__/scene-publication-fence.test.d.ts.map +1 -0
  105. package/dist/__tests__/scriptable-pack-public-surface.test-d.d.ts +2 -0
  106. package/dist/__tests__/scriptable-pack-public-surface.test-d.d.ts.map +1 -0
  107. package/dist/__tests__/static-rig.integration.test.d.ts +2 -0
  108. package/dist/__tests__/static-rig.integration.test.d.ts.map +1 -0
  109. package/dist/__tests__/validate-material.unit.test.d.ts +2 -0
  110. package/dist/__tests__/validate-material.unit.test.d.ts.map +1 -0
  111. package/dist/__tests__/video-pack-loader.integration.test.d.ts +2 -0
  112. package/dist/__tests__/video-pack-loader.integration.test.d.ts.map +1 -0
  113. package/dist/aabb.d.ts +3 -0
  114. package/dist/aabb.d.ts.map +1 -0
  115. package/dist/asset-registry.d.ts +554 -0
  116. package/dist/asset-registry.d.ts.map +1 -0
  117. package/dist/builtin-asset-registry.d.ts +22 -0
  118. package/dist/builtin-asset-registry.d.ts.map +1 -0
  119. package/dist/catalog-source.d.ts +2 -1
  120. package/dist/catalog-source.d.ts.map +1 -1
  121. package/dist/decode-image-bytes.d.ts +57 -0
  122. package/dist/decode-image-bytes.d.ts.map +1 -0
  123. package/dist/dynamic-texture-store.d.ts +89 -0
  124. package/dist/dynamic-texture-store.d.ts.map +1 -0
  125. package/dist/errors/asset.d.ts +201 -0
  126. package/dist/errors/asset.d.ts.map +1 -0
  127. package/dist/handles.d.ts +143 -0
  128. package/dist/handles.d.ts.map +1 -0
  129. package/dist/image-error.d.ts +6 -0
  130. package/dist/image-error.d.ts.map +1 -0
  131. package/dist/index.d.ts +32 -3
  132. package/dist/index.d.ts.map +1 -1
  133. package/dist/index.mjs +7233 -114
  134. package/dist/index.mjs.map +1 -1
  135. package/dist/internal.d.ts +1 -1
  136. package/dist/internal.d.ts.map +1 -1
  137. package/dist/loader-registry.d.ts +63 -0
  138. package/dist/loader-registry.d.ts.map +1 -0
  139. package/dist/loaders/inline-pack.d.ts +72 -0
  140. package/dist/loaders/inline-pack.d.ts.map +1 -0
  141. package/dist/loaders/mesh-bin.d.ts +21 -0
  142. package/dist/loaders/mesh-bin.d.ts.map +1 -0
  143. package/dist/loaders/pack-artifact.d.ts +20 -0
  144. package/dist/loaders/pack-artifact.d.ts.map +1 -0
  145. package/dist/material/dependency-graph.d.ts +9 -0
  146. package/dist/material/dependency-graph.d.ts.map +1 -0
  147. package/dist/material/generation-cache.d.ts +24 -0
  148. package/dist/material/generation-cache.d.ts.map +1 -0
  149. package/dist/material/inspection.d.ts +24 -0
  150. package/dist/material/inspection.d.ts.map +1 -0
  151. package/dist/material/loader.d.ts +59 -0
  152. package/dist/material/loader.d.ts.map +1 -0
  153. package/dist/material/runtime-shader.d.ts +14 -0
  154. package/dist/material/runtime-shader.d.ts.map +1 -0
  155. package/dist/mesh-bin.d.ts +3 -0
  156. package/dist/mesh-bin.d.ts.map +1 -0
  157. package/dist/mipmap-generator.d.ts +132 -0
  158. package/dist/mipmap-generator.d.ts.map +1 -0
  159. package/dist/payload-validate.d.ts +60 -0
  160. package/dist/payload-validate.d.ts.map +1 -0
  161. package/dist/plugin.d.ts +16 -0
  162. package/dist/plugin.d.ts.map +1 -0
  163. package/dist/registry/artifact-io.d.ts +16 -0
  164. package/dist/registry/artifact-io.d.ts.map +1 -0
  165. package/dist/registry/asset-evidence.d.ts +13 -0
  166. package/dist/registry/asset-evidence.d.ts.map +1 -0
  167. package/dist/registry/catalog-state.d.ts +47 -0
  168. package/dist/registry/catalog-state.d.ts.map +1 -0
  169. package/dist/registry/catalog.d.ts +48 -0
  170. package/dist/registry/catalog.d.ts.map +1 -0
  171. package/dist/registry/instantiate.d.ts +153 -0
  172. package/dist/registry/instantiate.d.ts.map +1 -0
  173. package/dist/registry/load-by-guid.d.ts +247 -0
  174. package/dist/registry/load-by-guid.d.ts.map +1 -0
  175. package/dist/registry/load-state.d.ts +26 -0
  176. package/dist/registry/load-state.d.ts.map +1 -0
  177. package/dist/registry/runtime-projection.d.ts +16 -0
  178. package/dist/registry/runtime-projection.d.ts.map +1 -0
  179. package/dist/registry/scene-publication-fence.d.ts +38 -0
  180. package/dist/registry/scene-publication-fence.d.ts.map +1 -0
  181. package/dist/registry/validate-material.d.ts +77 -0
  182. package/dist/registry/validate-material.d.ts.map +1 -0
  183. package/dist/resolve-asset-handle.d.ts +43 -0
  184. package/dist/resolve-asset-handle.d.ts.map +1 -0
  185. package/dist/resolve-tileset-runtime.d.ts +23 -0
  186. package/dist/resolve-tileset-runtime.d.ts.map +1 -0
  187. package/dist/scene-handle-fields.d.ts +88 -0
  188. package/dist/scene-handle-fields.d.ts.map +1 -0
  189. package/dist/scene-payload.d.ts +15 -0
  190. package/dist/scene-payload.d.ts.map +1 -0
  191. package/dist/wire-default-loaders.d.ts +29 -0
  192. package/dist/wire-default-loaders.d.ts.map +1 -0
  193. package/package.json +22 -9
  194. package/src/__tests__/aabb.unit.test.ts +97 -0
  195. package/src/__tests__/artifact-integrity.unit.test.ts +99 -0
  196. package/src/__tests__/artifact-io.unit.test.ts +127 -0
  197. package/src/__tests__/asset-evidence-sdk.integration.test.ts +32 -0
  198. package/src/__tests__/asset-evidence.unit.test.ts +32 -0
  199. package/src/__tests__/{asset-kind.test.ts → asset-kind.unit.test.ts} +1 -1
  200. package/src/__tests__/asset-registry-catalog-reconcile.integration.test.ts +74 -0
  201. package/src/__tests__/asset-registry-catalog-reconcile.unit.test.ts +89 -0
  202. package/src/__tests__/asset-registry-catalog.unit.test.ts +170 -0
  203. package/src/__tests__/asset-registry.pack-cache.test.ts +96 -0
  204. package/src/__tests__/asset-registry.unit.test.ts +511 -0
  205. package/src/__tests__/asset-runtime-error-code-owner.test-d.ts +63 -0
  206. package/src/__tests__/catalog-replica.unit.test.ts +196 -0
  207. package/src/__tests__/catalog-source-v2.unit.test.ts +158 -0
  208. package/src/__tests__/catalog-source.unit.test.ts +126 -0
  209. package/src/__tests__/catalog-subscription-order.unit.test.ts +65 -0
  210. package/src/__tests__/catalog-subscription.unit.test.ts +28 -0
  211. package/src/__tests__/decode-image-bytes-pass-through.test.ts +34 -0
  212. package/src/__tests__/decode-image-bytes.browser.test.ts +102 -0
  213. package/src/__tests__/decode-image-bytes.test-d.ts +108 -0
  214. package/src/__tests__/decode-image-bytes.test.ts +90 -0
  215. package/src/__tests__/decode-image-mime-owner.test.ts +2 -5
  216. package/src/__tests__/dynamic-texture-store.unit.test.ts +115 -0
  217. package/src/__tests__/errors-asset.unit.test.ts +92 -0
  218. package/src/__tests__/inline-pack-loaders.unit.test.ts +548 -0
  219. package/src/__tests__/instantiate-context.unit.test.ts +65 -0
  220. package/src/__tests__/instantiate-publication-fence.unit.test.ts +158 -0
  221. package/src/__tests__/instantiate.unit.test.ts +684 -0
  222. package/src/__tests__/loader-input-contract.unit.test.ts +89 -0
  223. package/src/__tests__/loader-registry.unit.test.ts +101 -0
  224. package/src/__tests__/material-dependency-invalidation.unit.test.ts +14 -0
  225. package/src/__tests__/material-generation-cache.unit.test.ts +46 -0
  226. package/src/__tests__/material-load-consumer.test-d.ts +42 -0
  227. package/src/__tests__/material-ready.integration.test.ts +508 -0
  228. package/src/__tests__/material-stale-generation.unit.test.ts +147 -0
  229. package/src/__tests__/mesh-bin-morph-v3.test.ts +22 -0
  230. package/src/__tests__/mesh-bin.unit.test.ts +152 -0
  231. package/src/__tests__/mipmap-generator.unit.test.ts +202 -0
  232. package/src/__tests__/pack-artifact-transcode-model-owner.test.ts +32 -0
  233. package/src/__tests__/pack-basis-load.integration.test.ts +168 -0
  234. package/src/__tests__/payload-validate.unit.test.ts +285 -0
  235. package/src/__tests__/plugin.test.ts +55 -0
  236. package/src/__tests__/registry-concurrency.bench.test.ts +40 -0
  237. package/src/__tests__/registry-failure-retry.integration.test.ts +69 -0
  238. package/src/__tests__/registry-load-graph.integration.test.ts +246 -0
  239. package/src/__tests__/registry-load-state.unit.test.ts +35 -0
  240. package/src/__tests__/registry-package-cache.unit.test.ts +53 -0
  241. package/src/__tests__/registry-public-ready.unit.test.ts +38 -0
  242. package/src/__tests__/resolve-asset-handle.unit.test.ts +238 -0
  243. package/src/__tests__/scene-handle-fields.unit.test.ts +129 -0
  244. package/src/__tests__/scene-payload.unit.test.ts +151 -0
  245. package/src/__tests__/scene-publication-fence.test.ts +129 -0
  246. package/src/__tests__/scriptable-pack-public-surface.test-d.ts +27 -0
  247. package/src/__tests__/static-rig.integration.test.ts +8 -0
  248. package/src/__tests__/validate-material.unit.test.ts +359 -0
  249. package/src/__tests__/video-pack-loader.integration.test.ts +83 -0
  250. package/src/aabb.ts +107 -0
  251. package/src/asset-registry.ts +2045 -0
  252. package/src/builtin-asset-registry.ts +164 -0
  253. package/src/catalog-source.ts +14 -70
  254. package/src/decode-image-bytes.ts +126 -0
  255. package/src/dynamic-texture-store.ts +234 -0
  256. package/src/errors/asset.ts +347 -0
  257. package/src/handles.ts +186 -0
  258. package/src/image-error.ts +45 -0
  259. package/src/index.ts +183 -16
  260. package/src/internal.ts +1 -0
  261. package/src/loader-registry.ts +157 -0
  262. package/src/loaders/inline-pack.ts +837 -0
  263. package/src/loaders/mesh-bin.ts +304 -0
  264. package/src/loaders/pack-artifact.ts +665 -0
  265. package/src/material/dependency-graph.ts +46 -0
  266. package/src/material/generation-cache.ts +177 -0
  267. package/src/material/inspection.ts +46 -0
  268. package/src/material/loader.ts +326 -0
  269. package/src/material/runtime-shader.ts +133 -0
  270. package/src/mesh-bin.ts +5 -0
  271. package/src/mipmap-generator.ts +450 -0
  272. package/src/payload-validate.ts +573 -0
  273. package/src/plugin.ts +48 -0
  274. package/src/registry/artifact-io.ts +259 -0
  275. package/src/registry/asset-evidence.ts +51 -0
  276. package/src/registry/catalog-state.ts +409 -0
  277. package/src/registry/catalog.ts +369 -0
  278. package/src/registry/instantiate.ts +1056 -0
  279. package/src/registry/load-by-guid.ts +1657 -0
  280. package/src/registry/load-state.ts +115 -0
  281. package/src/registry/runtime-projection.ts +63 -0
  282. package/src/registry/scene-publication-fence.ts +256 -0
  283. package/src/registry/validate-material.ts +385 -0
  284. package/src/resolve-asset-handle.ts +147 -0
  285. package/src/resolve-tileset-runtime.ts +72 -0
  286. package/src/scene-handle-fields.ts +221 -0
  287. package/src/scene-payload.ts +207 -0
  288. package/src/wire-default-loaders.ts +79 -0
  289. package/dist/__tests__/asset-graph-red.integration.test.d.ts +0 -2
  290. package/dist/__tests__/asset-graph-red.integration.test.d.ts.map +0 -1
  291. package/dist/__tests__/asset-kind.test.d.ts +0 -2
  292. package/dist/__tests__/asset-kind.test.d.ts.map +0 -1
  293. package/dist/__tests__/asset-registry-core.integration.test.d.ts +0 -2
  294. package/dist/__tests__/asset-registry-core.integration.test.d.ts.map +0 -1
  295. package/dist/__tests__/asset-registry-public-api.test-d.d.ts +0 -2
  296. package/dist/__tests__/asset-registry-public-api.test-d.d.ts.map +0 -1
  297. package/dist/__tests__/asset-runtime-core-lifecycle.integration.test.d.ts +0 -2
  298. package/dist/__tests__/asset-runtime-core-lifecycle.integration.test.d.ts.map +0 -1
  299. package/dist/__tests__/asset-runtime-snapshot.unit.test.d.ts +0 -2
  300. package/dist/__tests__/asset-runtime-snapshot.unit.test.d.ts.map +0 -1
  301. package/dist/__tests__/catalog-session-red.unit.test.d.ts +0 -2
  302. package/dist/__tests__/catalog-session-red.unit.test.d.ts.map +0 -1
  303. package/dist/__tests__/registry-lifecycle-red.integration.test.d.ts +0 -2
  304. package/dist/__tests__/registry-lifecycle-red.integration.test.d.ts.map +0 -1
  305. package/src/__tests__/asset-graph-red.integration.test.ts +0 -113
  306. package/src/__tests__/asset-registry-core.integration.test.ts +0 -161
  307. package/src/__tests__/asset-registry-public-api.test-d.ts +0 -31
  308. package/src/__tests__/asset-runtime-core-lifecycle.integration.test.ts +0 -79
  309. package/src/__tests__/asset-runtime-snapshot.unit.test.ts +0 -23
  310. package/src/__tests__/catalog-session-red.unit.test.ts +0 -276
  311. package/src/__tests__/registry-lifecycle-red.integration.test.ts +0 -80
@@ -0,0 +1,347 @@
1
+ // @forgeax/engine-assets-runtime -- asset cluster error classes.
2
+ //
3
+ // feat-20260704-runtime-tier1-decomposition M2 / w8 (D-3): asset-resolution
4
+ // cluster -- material parent-chain resolve, mesh-SSBO grow ceiling, and
5
+ // scene-collect GUID / forest-closure fail-fast errors. Class names, .code
6
+ // literals, and .detail shapes preserved byte-for-byte (OOS-4).
7
+ //
8
+ // The cluster union type is named AssetRuntimeError / AssetRuntimeErrorCode
9
+ // (not AssetError / AssetErrorCode) because @forgeax/engine-types already owns
10
+ // the AssetError class + AssetErrorCode union (asset-system-v1); D-8 grep
11
+ // uniqueness forbids the collision.
12
+
13
+ import type { MeshBinHeaderV4 } from '@forgeax/engine-pack';
14
+ import {
15
+ AssetError,
16
+ type AssetErrorDetail,
17
+ type AssetMeshBinContractFacts,
18
+ type AssetMeshBinContractViolationReason,
19
+ } from '@forgeax/engine-types';
20
+
21
+ export class MeshBinAssetError extends AssetError {
22
+ readonly subject = 'mesh-bin' as const;
23
+ readonly sourceKey: string;
24
+ readonly actual: string;
25
+ readonly recovery = 're-cook the source with its Meta sidecar through the build-time importer';
26
+
27
+ constructor(args: {
28
+ readonly sourceKey: string;
29
+ readonly expected: string;
30
+ readonly actual: string;
31
+ readonly header?: Partial<MeshBinHeaderV4> & { readonly byteLength?: number };
32
+ readonly reason?: AssetMeshBinContractViolationReason;
33
+ readonly expectedFacts?: AssetMeshBinContractFacts;
34
+ readonly actualFacts?: AssetMeshBinContractFacts;
35
+ }) {
36
+ const expectedFacts: AssetMeshBinContractFacts = args.expectedFacts ?? {
37
+ version: 4,
38
+ projectionVersion: 1,
39
+ };
40
+ const actualFacts: AssetMeshBinContractFacts = {
41
+ ...(args.header ?? {}),
42
+ ...(args.actualFacts ?? {}),
43
+ };
44
+ const detail: AssetErrorDetail = {
45
+ code: 'mesh-bin-contract-violation',
46
+ sourceKey: args.sourceKey,
47
+ reason: args.reason ?? 'header-invalid',
48
+ expected: expectedFacts,
49
+ actual: actualFacts,
50
+ };
51
+ super({
52
+ code: 'mesh-bin-contract-violation',
53
+ expected: args.expected,
54
+ hint: 're-cook the source with its Meta sidecar through the build-time importer',
55
+ detail,
56
+ });
57
+ this.sourceKey = args.sourceKey;
58
+ this.actual = args.actual;
59
+ }
60
+ }
61
+
62
+ // ── MaterialResolvedEmptyPassesError ──────────────────────────────────────
63
+
64
+ /**
65
+ * Detail for `RuntimeErrorCode 'material-resolved-empty-passes'`.
66
+ *
67
+ * Emitted at material parent chain walk time when the resolved passes list
68
+ * is empty. Two reasons: `'missing-parent'` (a parent handle is not
69
+ * registered) and `'no-pass-in-chain'` (the entire parent chain has no
70
+ * pass declarations). AI users switch on `.detail.reason` to surface the
71
+ * right recovery guidance.
72
+ *
73
+ * plan-strategy D-2/D-3: empty-passes is a runtime-layer error
74
+ * (RuntimeErrorCode, not AssetErrorCode).
75
+ */
76
+ export interface MaterialResolvedEmptyPassesDetail {
77
+ /** GUID of the material whose resolve produced empty passes. */
78
+ readonly materialGuid: string;
79
+ /** Root cause of the empty passes: missing parent vs entire chain has no passes. */
80
+ readonly reason: 'missing-parent' | 'no-pass-in-chain';
81
+ /** The raw numeric handle id of the unregistered parent. Only populated when reason='missing-parent'. */
82
+ readonly missingParentHandle?: number;
83
+ }
84
+
85
+ /**
86
+ * Structured error for material parent chain resolve yielding zero passes.
87
+ *
88
+ * Emitted by `AssetRegistry.passesOf` when the parent chain walk produces
89
+ * an empty passes list (AC-09, D-3 two-reason). Four-field surface:
90
+ * - `.code = 'material-resolved-empty-passes'` (closed RuntimeErrorCode)
91
+ * - `.expected` — expected-state description
92
+ * - `.hint` — actionable recovery guidance (differs per reason)
93
+ * - `.detail = { materialGuid, reason, missingParentHandle? }`
94
+ */
95
+ export class MaterialResolvedEmptyPassesError extends Error {
96
+ readonly code = 'material-resolved-empty-passes' as const;
97
+ readonly expected: string;
98
+ readonly hint: string;
99
+ readonly detail: MaterialResolvedEmptyPassesDetail;
100
+
101
+ constructor(
102
+ materialGuid: string,
103
+ reason: 'missing-parent' | 'no-pass-in-chain',
104
+ missingParentHandle?: number,
105
+ ) {
106
+ const expected =
107
+ reason === 'missing-parent'
108
+ ? `parent handle ${missingParentHandle} present in AssetRegistry`
109
+ : 'at least one material in the parent chain declares passes';
110
+ const hint =
111
+ reason === 'missing-parent'
112
+ ? `material ${materialGuid} references parent handle ${missingParentHandle} which is not registered; inspect AssetRegistry, register the parent first, or rebuild the material chain`
113
+ : `material ${materialGuid} has no passes and its entire parent chain also has no pass declarations; inspect the chain, add pass declarations to one member, then rebuild`;
114
+ const message =
115
+ reason === 'missing-parent'
116
+ ? `material ${materialGuid} parent handle ${missingParentHandle} not registered`
117
+ : `material ${materialGuid} parent chain resolves to zero passes`;
118
+
119
+ super(message);
120
+ this.name = 'MaterialResolvedEmptyPassesError';
121
+ this.expected = expected;
122
+ this.hint = hint;
123
+ this.detail = {
124
+ materialGuid,
125
+ reason,
126
+ ...(reason === 'missing-parent' && missingParentHandle !== undefined
127
+ ? { missingParentHandle }
128
+ : {}),
129
+ };
130
+ }
131
+ }
132
+
133
+ // ── MeshSsboCapacityExceededError ────────────────────────────────────────────
134
+
135
+ /**
136
+ * Detail for `RuntimeErrorCode 'mesh-ssbo-capacity-exceeded'`.
137
+ *
138
+ * Fired by `growMeshSsbo` (createRenderer.ts grow factory) when, after
139
+ * attempting pow2 doubling, the resulting `slotCount` still cannot
140
+ * accommodate the requested `requested` slot count under the device's
141
+ * `maxStorageBufferBindingSize` ceiling. This is a defensive fallback —
142
+ * the primary path for "request past device limit" is
143
+ * `mesh-ssbo-ceiling-reached`. The two codes share the same detail shape so
144
+ * AI users handle both arms identically; the discriminant identifies which
145
+ * branch fired so diagnostics can distinguish the primary vs defensive
146
+ * surface (research §F6.c).
147
+ *
148
+ * - `requested` — slot count requested by the caller (entity count for the frame)
149
+ * - `capacity` — current `slotCount` in the grow controller's state
150
+ * - `ceiling` — `device.limits.maxStorageBufferBindingSize` in BYTES (not slots)
151
+ */
152
+ export interface MeshSsboCapacityExceededDetail {
153
+ readonly requested: number;
154
+ readonly capacity: number;
155
+ readonly ceiling: number;
156
+ }
157
+
158
+ /**
159
+ * Structured error for the post-grow defensive fallback when mesh-SSBO
160
+ * capacity cannot accommodate the requested slot count.
161
+ *
162
+ * Emitted by `growMeshSsbo` in `createRenderer.ts` (D-5: fire, never
163
+ * throw). Four-field surface aligned with `SkinPaletteOverflowError`:
164
+ * - `.code = 'mesh-ssbo-capacity-exceeded'`
165
+ * - `.expected` — capacity >= requested
166
+ * - `.hint` — reduce per-frame entity count or split work across frames
167
+ * - `.detail = { requested, capacity, ceiling }`
168
+ */
169
+ export class MeshSsboCapacityExceededError extends Error {
170
+ readonly code = 'mesh-ssbo-capacity-exceeded' as const;
171
+ readonly expected: string;
172
+ readonly hint: string;
173
+ readonly detail: MeshSsboCapacityExceededDetail;
174
+
175
+ constructor(requested: number, capacity: number, ceiling: number) {
176
+ const expected = `mesh SSBO slotCount >= ${requested} (currently ${capacity}; device ceiling ${ceiling} B)`;
177
+ const hint =
178
+ `mesh SSBO grow could not satisfy needed=${requested} slots (capacity=${capacity}, ceiling=${ceiling} B); ` +
179
+ 'reduce per-frame entity count or split work across frames (defensive fallback path)';
180
+ super(
181
+ `mesh SSBO capacity exceeded: needed ${requested} slots, capacity ${capacity}, ceiling ${ceiling} B`,
182
+ );
183
+ this.name = 'MeshSsboCapacityExceededError';
184
+ this.expected = expected;
185
+ this.hint = hint;
186
+ this.detail = { requested, capacity, ceiling };
187
+ }
188
+ }
189
+
190
+ // ── MeshSsboCeilingReachedError ──────────────────────────────────────────────
191
+
192
+ /**
193
+ * Detail for `RuntimeErrorCode 'mesh-ssbo-ceiling-reached'`.
194
+ *
195
+ * Fired by `growMeshSsbo` when the requested slot count would exceed the
196
+ * device's `maxStorageBufferBindingSize` (the only ceiling per D-1; engine
197
+ * carries no private capacity constant). Same detail shape as
198
+ * `MeshSsboCapacityExceededDetail`.
199
+ *
200
+ * - `requested` — slot count requested by the caller
201
+ * - `capacity` — current `slotCount` in the grow controller's state
202
+ * - `ceiling` — `device.limits.maxStorageBufferBindingSize` in BYTES
203
+ */
204
+ export interface MeshSsboCeilingReachedDetail {
205
+ readonly requested: number;
206
+ readonly capacity: number;
207
+ readonly ceiling: number;
208
+ }
209
+
210
+ /**
211
+ * Structured error for mesh-SSBO grow refused because the request exceeds
212
+ * `device.limits.maxStorageBufferBindingSize`.
213
+ *
214
+ * Emitted by `growMeshSsbo` (D-5: fire, never throw). The frame renders a
215
+ * degraded subset (truncated to pre-grow capacity) per plan-strategy D-2 —
216
+ * no black frame. Four-field surface aligned with `SkinPaletteOverflowError`:
217
+ * - `.code = 'mesh-ssbo-ceiling-reached'`
218
+ * - `.expected` — requested * stride <= device.limits.maxStorageBufferBindingSize
219
+ * - `.hint` — reduce per-frame entity count or pick a higher-tier adapter
220
+ * - `.detail = { requested, capacity, ceiling }`
221
+ */
222
+ export class MeshSsboCeilingReachedError extends Error {
223
+ readonly code = 'mesh-ssbo-ceiling-reached' as const;
224
+ readonly expected: string;
225
+ readonly hint: string;
226
+ readonly detail: MeshSsboCeilingReachedDetail;
227
+
228
+ constructor(requested: number, capacity: number, ceiling: number) {
229
+ const expected = `mesh SSBO slot byte size <= device.limits.maxStorageBufferBindingSize (${ceiling} B)`;
230
+ const hint =
231
+ `requested ${requested} mesh SSBO slots would exceed device.limits.maxStorageBufferBindingSize (${ceiling} B); ` +
232
+ 'reduce per-frame entity count or run on an adapter with a larger storage buffer binding size';
233
+ super(
234
+ `mesh SSBO ceiling reached: needed ${requested} slots; capacity ${capacity}; ceiling ${ceiling} B`,
235
+ );
236
+ this.name = 'MeshSsboCeilingReachedError';
237
+ this.expected = expected;
238
+ this.hint = hint;
239
+ this.detail = { requested, capacity, ceiling };
240
+ }
241
+ }
242
+
243
+ // ── SceneCollectEntityRefOutOfClosureError ──────────────────────────
244
+
245
+ /**
246
+ * Detail for `RuntimeErrorCode 'scene-collect-entity-ref-out-of-closure'`.
247
+ *
248
+ * Emitted during rootsToSceneAsset when an entity field references a target
249
+ * outside the collected forest closure.
250
+ */
251
+ export interface SceneCollectEntityRefOutOfClosureDetail {
252
+ readonly entity: number;
253
+ readonly field: string;
254
+ readonly target: number;
255
+ }
256
+
257
+ /**
258
+ * Structured error for entity ref pointing outside the forest closure.
259
+ *
260
+ * Emitted during rootsToSceneAsset collect; fail-fast per charter P3.
261
+ * - `.code = 'scene-collect-entity-ref-out-of-closure'`
262
+ * - `.expected` — all entity refs resolve within the closure
263
+ * - `.hint` — Expand roots to include the target entity, or remove the reference.
264
+ * - `.detail = { entity, field, target }`
265
+ */
266
+ export class SceneCollectEntityRefOutOfClosureError extends Error {
267
+ readonly code = 'scene-collect-entity-ref-out-of-closure' as const;
268
+ readonly expected: string;
269
+ readonly hint: string;
270
+ readonly detail: SceneCollectEntityRefOutOfClosureDetail;
271
+
272
+ constructor(entity: number, field: string, target: number) {
273
+ const expected = `entity ${entity}.${field} references entity ${target} which is inside the forest closure`;
274
+ const hint = 'Expand roots to include the target entity, or remove the reference.';
275
+ super(`${expected} — ${hint}`);
276
+ this.name = 'SceneCollectEntityRefOutOfClosureError';
277
+ this.expected = expected;
278
+ this.hint = hint;
279
+ this.detail = { entity, field, target };
280
+ }
281
+ }
282
+
283
+ // ── SceneCollectAssetGuidUnresolvedError ────────────────────────────
284
+
285
+ /**
286
+ * Detail for `RuntimeErrorCode 'scene-collect-asset-guid-unresolved'`.
287
+ *
288
+ * Emitted at two points with different context on hand:
289
+ * - collect (handle→GUID): the shared handle is known → `.handle` is set.
290
+ * - serialize (GUID→refs): the GUID string is known but absent from the
291
+ * refs index → `.guid` is set. (`.handle` is meaningless there.)
292
+ * Exactly one of `handle` / `guid` is present per instance.
293
+ */
294
+ export interface SceneCollectAssetGuidUnresolvedDetail {
295
+ readonly field: string;
296
+ readonly handle?: number;
297
+ readonly guid?: string;
298
+ }
299
+
300
+ /**
301
+ * Structured error for a shared asset reference whose GUID cannot be resolved.
302
+ *
303
+ * Emitted during rootsToSceneAsset collect (handle) or
304
+ * serializeSceneAssetToPack (guid); fail-fast per charter P3.
305
+ * - `.code = 'scene-collect-asset-guid-unresolved'`
306
+ * - `.expected` — every shared asset reference has a catalogued GUID
307
+ * - `.hint` — Register the asset in AssetRegistry before collecting.
308
+ * - `.detail = { field, handle }` (collect) or `{ field, guid }` (serialize)
309
+ */
310
+ export class SceneCollectAssetGuidUnresolvedError extends Error {
311
+ readonly code = 'scene-collect-asset-guid-unresolved' as const;
312
+ readonly expected: string;
313
+ readonly hint: string;
314
+ readonly detail: SceneCollectAssetGuidUnresolvedDetail;
315
+
316
+ constructor(field: string, ref: number | string) {
317
+ const where = typeof ref === 'number' ? `handle ${ref}` : `guid '${ref}'`;
318
+ const expected = `shared field '${field}' (${where}) resolves to an asset whose GUID is catalogued`;
319
+ const hint =
320
+ 'source SceneAsset is not catalogued: call registry.catalog(guid, payload) first, ' +
321
+ 'or load through loadByGuid() which auto-catalogs GUID-scoped assets';
322
+ super(`${expected} — ${hint}`);
323
+ this.name = 'SceneCollectAssetGuidUnresolvedError';
324
+ this.expected = expected;
325
+ this.hint = hint;
326
+ this.detail = typeof ref === 'number' ? { field, handle: ref } : { field, guid: ref };
327
+ }
328
+ }
329
+
330
+ // -- AssetRuntimeErrorCode / AssetRuntimeError closed unions --------------------
331
+
332
+ /**
333
+ * Closed union of asset-cluster error codes. AI users perform exhaustive
334
+ * `switch (err.code)` without default; TS guards completeness.
335
+ */
336
+ export type AssetRuntimeErrorCode = AssetRuntimeError['code'];
337
+
338
+ /**
339
+ * Closed union of the asset-cluster structured error classes, each carrying
340
+ * an `AssetRuntimeErrorCode` discriminant on `.code`.
341
+ */
342
+ export type AssetRuntimeError =
343
+ | MaterialResolvedEmptyPassesError
344
+ | MeshSsboCapacityExceededError
345
+ | MeshSsboCeilingReachedError
346
+ | SceneCollectEntityRefOutOfClosureError
347
+ | SceneCollectAssetGuidUnresolvedError;
package/src/handles.ts ADDED
@@ -0,0 +1,186 @@
1
+ // @forgeax/engine-assets-runtime -- builtin mesh handles + scene-parse handle field
2
+ // name sets (feat-20260705-runtime-tier2-decomposition M1 / w4, D-4 F1
3
+ // straight-cut). Pure move from asset-registry.ts; zero identifier changes.
4
+
5
+ import type { Handle } from '@forgeax/engine-types';
6
+ import { handleSlot, toShared } from '@forgeax/engine-types';
7
+
8
+ // ─── Builtin handles (D-S9 / backward compat with hello-triangle + hello-cube) ─
9
+
10
+ /**
11
+ * Builtin unit-cube mesh handle (8 vertices + 36 indices, pos+normal
12
+ * interleaved). Pair with `MeshFilter` to spawn a cube entity.
13
+ *
14
+ * @remarks Typed as `Handle<'MeshAsset', 'shared'>` — feat-20260517
15
+ * unifies the engine-types and engine-ecs Handle brand SSOT into a single
16
+ * `Handle<T extends string, M extends 'unique'|'shared'>` declaration
17
+ * (research Finding 4 import-path-decoupled identity), and constructs the
18
+ * value via the brand-creation factory `toShared<'MeshAsset'>(N)` so
19
+ * the caller-side `as unknown as` cast is eliminated (AC-05). The
20
+ * `'shared'` mode signals the AssetRegistry owns the lifecycle — the
21
+ * ECS does not release the slot on despawn / removeComponent / set.
22
+ * Runtime value is a small u32 (1).
23
+ */
24
+ export const HANDLE_CUBE: Handle<'MeshAsset', 'shared'> = toShared<'MeshAsset'>(1);
25
+
26
+ /**
27
+ * Builtin triangle mesh handle (3 vertices). Pair with `MeshFilter`.
28
+ *
29
+ * @remarks Typed as `Handle<'MeshAsset', 'shared'>` (same narrow brand
30
+ * as HANDLE_CUBE; constructed via the `toShared<'MeshAsset'>(N)`
31
+ * factory per AC-05).
32
+ */
33
+ export const HANDLE_TRIANGLE: Handle<'MeshAsset', 'shared'> = toShared<'MeshAsset'>(2);
34
+
35
+ /**
36
+ * Builtin unit-quad mesh handle — 4 vertices, 6 indices, 2 triangles on
37
+ * the XY plane facing +Z. Pair with `MeshFilter` to spawn a sprite quad
38
+ * (feat-20260520-2d-sprite-layer-mvp / M-1 / w06).
39
+ *
40
+ * @derives Same-shape sibling of {@link HANDLE_CUBE} / {@link HANDLE_TRIANGLE}
41
+ * per requirements §2.1.C: built via the `toShared<'MeshAsset'>(N)`
42
+ * brand-creation factory; reserved-id 3 fills the namespace hole between
43
+ * HANDLE_TRIANGLE=2 and FIRST_USER_HANDLE=1024 (no `BUILTIN_HANDLE_`
44
+ * prefix per Q2 naming decision — discoverable next to existing
45
+ * builtins in IDE autocomplete; charter F1 single-entry indexability).
46
+ *
47
+ * @reuses {@link createPlaneGeometry}(1, 1) — the procedural plane factory
48
+ * already produces 8-floats-per-vertex interleaved (position + normal +
49
+ * uv) and is then expanded to the runtime 12-floats layout (adds
50
+ * tangent vec4) by {@link meshFromInterleaved}. This funnels HANDLE_QUAD
51
+ * onto the exact same vertex pipeline branch as BUILTIN_CUBE /
52
+ * BUILTIN_TRIANGLE and the procedural geometry factories — zero new
53
+ * layout discriminator (plan-strategy §3 RT4 + D-9 + charter P4
54
+ * consistent abstraction).
55
+ *
56
+ * @reuses `PROCEDURAL_FLOATS_PER_VERTEX` = 12 from
57
+ * `@forgeax/engine-geometry` (the single layout SSOT; the procedural
58
+ * `createPlaneGeometry` factory already returns 12F via
59
+ * `meshFromInterleaved`).
60
+ */
61
+ export const HANDLE_QUAD: Handle<'MeshAsset', 'shared'> = toShared<'MeshAsset'>(3);
62
+
63
+ /**
64
+ * Id=4 reserved builtin; occupies the next available slot under
65
+ * FIRST_USER_HANDLE=1024. BUILTIN_SPHERE is synthesised from
66
+ * `createSphereGeometry(1, 16, 12)` through the same
67
+ * `meshFromInterleaved` path as BUILTIN_QUAD, so the runtime
68
+ * 12-float stride is byte-identical to procedural output — zero
69
+ * new layout discriminator (charter P4 consistent abstraction).
70
+ */
71
+ export const HANDLE_SPHERE: Handle<'MeshAsset', 'shared'> = toShared<'MeshAsset'>(4);
72
+
73
+ /**
74
+ * Builtin cylinder mesh handle — procedural open cylinder (unit-height,
75
+ * radius=0.5, 16 radial segments, no caps). Pair with `MeshFilter`.
76
+ *
77
+ * @derives Same-shape sibling of {@link HANDLE_SPHERE}: synthesised from
78
+ * `createCylinderGeometry(0.5, 0.5, 1, 16, 1)` through the same
79
+ * `meshFromInterleaved` path as BUILTIN_SPHERE, so the runtime
80
+ * 12-float stride is byte-identical to all other built-in meshes —
81
+ * zero new layout discriminator (charter P4 consistent abstraction).
82
+ *
83
+ * @remarks Id=6 follows {@link HANDLE_NINESLICE_QUAD}=5 in the builtin slot
84
+ * sequence (FIRST_USER_HANDLE=1024 untouched).
85
+ * feat-20260701-editor-world-container-doc-ecs-collapse M0 / AC-16:
86
+ * GUID = deriveBuiltin('HANDLE_CYLINDER') UUIDv5
87
+ * (plan-strategy §2 D-6 + §5.6 builtin-guid-ssot gate)
88
+ */
89
+ export const HANDLE_CYLINDER: Handle<'MeshAsset', 'shared'> = toShared<'MeshAsset'>(6);
90
+
91
+ /**
92
+ * Builtin 9-slice quad mesh handle — 4×4 grid (16 vertices, 9 sub-quads,
93
+ * 54 indices) on the XY plane facing +Z. Pair with `MeshFilter` and a
94
+ * `MaterialAsset` whose first pass shader is `'forgeax::sprite'` and whose
95
+ * `values.slices` is non-zero to render a 9-sliced UI panel
96
+ * (feat-20260527-sprite-nineslice / M2 / w9).
97
+ *
98
+ * @derives Same-shape sibling of {@link HANDLE_QUAD}: synthesised from
99
+ * `createPlaneGeometry(1, 1, 3, 3)` which subdivides the unit quad into
100
+ * 3×3 sub-quads (9 cells). The 16 grid points and 54 indices feed
101
+ * {@link meshFromInterleaved} so the runtime 12-float vertex stride is
102
+ * byte-identical to all other built-in / procedural meshes — zero new
103
+ * layout discriminator (charter P4 consistent abstraction).
104
+ *
105
+ * @remarks Id=5 follows {@link HANDLE_SPHERE}=4 in the builtin slot
106
+ * sequence (FIRST_USER_HANDLE=1024 untouched). The vertex shader uses
107
+ * `vertex_index % 4` / `vertex_index / 4` to recover (i, j) grid
108
+ * coordinates and four anchor vec4s to map each grid cell to the right
109
+ * region of the source texture; only required when the sprite material
110
+ * declares non-zero `slices`. For the legacy zero-slice sprite path use
111
+ * {@link HANDLE_QUAD}.
112
+ *
113
+ * @reuses `PROCEDURAL_FLOATS_PER_VERTEX` = 12 from
114
+ * `@forgeax/engine-geometry` (sprite-pipeline binding table / vertex layout
115
+ * untouched). plan-strategy §D-2 NOTE clarifies
116
+ * the id=5 vs original-plan id=4 drift: HANDLE_SPHERE took id=4 in
117
+ * feat-20260529-fxaa-sphere-builtin before this feat landed.
118
+ */
119
+ export const HANDLE_NINESLICE_QUAD: Handle<'MeshAsset', 'shared'> = toShared<'MeshAsset'>(5);
120
+
121
+ /**
122
+ * Stable GUIDs for the builtin meshes — the dash-form of
123
+ * `deriveBuiltin('HANDLE_<NAME>')` (UUIDv5, ForgeaX namespace) in
124
+ * `@forgeax/engine-pack`. They are inlined here (not imported) because the
125
+ * pack derivation runs under top-level `await` (async SubtleCrypto) and
126
+ * dragging that into the AssetRegistry constructor — a synchronous hot path
127
+ * consumed engine-wide — would make the whole runtime module graph async.
128
+ *
129
+ * The single source of truth remains `deriveBuiltin`: a cross-package
130
+ * guard test (`builtin-guid-ssot.test.ts`) asserts each literal equals the
131
+ * derived value, so any drift in the derivation reds the suite. This pairs
132
+ * the previously-disconnected dual truths (the u32 `HANDLE_*` constants and
133
+ * the pack GUID strings) into one bidirectionally-resolvable table, so
134
+ * `guidOf(HANDLE_CUBE)` no longer returns `undefined`
135
+ * (docs/feedbacks/2026-06-03 §6.2 Tier 0).
136
+ */
137
+ export const BUILTIN_MESH_GUIDS: ReadonlyArray<readonly [Handle<'MeshAsset', 'shared'>, string]> = [
138
+ [HANDLE_CUBE, 'cbe42beb-8975-5096-b3a1-3dda4cb4c077'],
139
+ [HANDLE_TRIANGLE, '22592f07-d967-5116-b29c-fa9781929ba8'],
140
+ [HANDLE_QUAD, '339338aa-a338-581c-9fc5-744267ef8a51'],
141
+ [HANDLE_SPHERE, '95730fd2-9846-5f84-8658-0b3c971eb263'],
142
+ [HANDLE_NINESLICE_QUAD, '692d38b4-8cac-5fb2-9dcf-f389e076d6bf'],
143
+ // feat-20260701-editor-world-container-doc-ecs-collapse M0 / AC-16:
144
+ // cylinder builtin handle=6, GUID = deriveBuiltin('HANDLE_CYLINDER') UUIDv5
145
+ // (plan-strategy §5.6 builtin-guid-ssot gate)
146
+ [HANDLE_CYLINDER, 'ab20af21-0764-55be-a7f2-b80ab3d46a0a'],
147
+ ];
148
+
149
+ /** Resolve the stable producer GUID for one process-static builtin mesh handle. */
150
+ export function builtinMeshGuid(handle: Handle<string, 'shared'>): string | undefined {
151
+ const slot = handleSlot(handle);
152
+ return BUILTIN_MESH_GUIDS.find(([candidate]) => handleSlot(candidate) === slot)?.[1];
153
+ }
154
+
155
+ /**
156
+ * Field names known to carry handle<> schema-vocab references (plan-strategy
157
+ * D-4). parseScenePayload uses this allowlist to replace integer values
158
+ * with GUID strings from refs[] only for handle fields — a Transform.pos lane of 0,
159
+ * ChildOf.parent=0 and similar non-handle integers are left untouched.
160
+ *
161
+ * When a new handle<> field is added to a runtime component, its field name
162
+ * MUST be added here so parseScenePayload correctly resolves it.
163
+ */
164
+ export const HANDLE_FIELD_NAMES: ReadonlySet<string> = new Set([
165
+ 'assetHandle',
166
+ 'material',
167
+ 'skeleton',
168
+ 'clip',
169
+ // ParticleEffectPlayer.effect (shared<ParticleEffectAsset>) uses the same
170
+ // scene-pack refs[] index contract as every other scalar shared field.
171
+ 'effect',
172
+ // feat-20260630-equirect-kind-internalized-ibl-declarative-skyligh M3 / w27:
173
+ // Skylight.equirect + SkyboxBackground.equirect (shared<EquirectAsset>). The
174
+ // generic extractSceneEntityHandleGuids path already covers shared< fields by
175
+ // schema; this allowlist is the second scene-parse path (parseScenePayload),
176
+ // so the new handle field name is registered here too (R-1).
177
+ 'equirect',
178
+ ]);
179
+
180
+ /**
181
+ * Field names known to carry `array<handle<X>>` schema-vocab references
182
+ * (feat-20260608 M2 / w7: MeshRenderer.materials). Each element is a refs
183
+ * index that resolves to a GUID string. Coexists with HANDLE_FIELD_NAMES;
184
+ * a field name lives in exactly one set.
185
+ */
186
+ export const HANDLE_ARRAY_FIELD_NAMES: ReadonlySet<string> = new Set(['materials']);
@@ -0,0 +1,45 @@
1
+ // @forgeax/engine-assets-runtime -- runtime-local ImageError constructor
2
+ // (feat-20260705-runtime-tier2-decomposition M1 / w4, D-4 F1 straight-cut).
3
+ // Pure move from asset-registry.ts; zero identifier changes.
4
+
5
+ import type { ImageErrorDetailFor, ImageErrorFor } from '@forgeax/engine-types';
6
+ import { IMAGE_ERROR_HINTS } from '@forgeax/engine-types';
7
+
8
+ // Local minimal `ImageError` constructor (charter P5 producer / consumer
9
+ // split: the runtime AssetRegistry should not import @forgeax/engine-image
10
+ // errors module because the image package is the disk-side decoder; the
11
+ // runtime is the GPU consumer. Both packages share the `ImageError`
12
+ // interface SSOT in @forgeax/engine-types so runtime constructs the
13
+ // 4-field surface (.code / .expected / .hint / .detail) directly without
14
+ // duplicating the @forgeax/engine-image errors.ts class).
15
+ type UnsupportedMimeImageError = ImageErrorFor<'image-format-unsupported'>;
16
+ type UnsupportedMimeImageErrorDetail = ImageErrorDetailFor<'image-format-unsupported'>;
17
+
18
+ const IMAGE_ERROR_EXPECTED_LOCAL: Readonly<
19
+ Record<UnsupportedMimeImageErrorDetail['code'], string>
20
+ > = {
21
+ 'image-format-unsupported':
22
+ "mime is one of ['image/png', 'image/jpeg', 'image/x-tga']; texture format <-> colorSpace family agrees",
23
+ };
24
+
25
+ class RuntimeImageError extends Error implements UnsupportedMimeImageError {
26
+ readonly code: UnsupportedMimeImageError['code'];
27
+ readonly expected: string;
28
+ readonly hint: string;
29
+ readonly detail: UnsupportedMimeImageErrorDetail;
30
+ constructor(detail: UnsupportedMimeImageErrorDetail) {
31
+ const code = detail.code;
32
+ const expected = IMAGE_ERROR_EXPECTED_LOCAL[code];
33
+ const hint = IMAGE_ERROR_HINTS[code];
34
+ super(`[ImageError ${code}] expected: ${expected}; hint: ${hint}`);
35
+ this.name = 'ImageError';
36
+ this.code = code;
37
+ this.expected = expected;
38
+ this.hint = hint;
39
+ this.detail = detail;
40
+ }
41
+ }
42
+
43
+ export function makeImageError(detail: UnsupportedMimeImageErrorDetail): UnsupportedMimeImageError {
44
+ return new RuntimeImageError(detail);
45
+ }