@forgeax/engine-runtime 0.1.3 → 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 (606) hide show
  1. package/README.md +49 -83
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/__tests__/animation-graph-collect-roundtrip.test.d.ts +2 -0
  4. package/dist/__tests__/animation-graph-collect-roundtrip.test.d.ts.map +1 -0
  5. package/dist/__tests__/animation-graph-serialize.unit.test.d.ts +2 -0
  6. package/dist/__tests__/animation-graph-serialize.unit.test.d.ts.map +1 -0
  7. package/dist/__tests__/asset-brand-and-name-retirement.test.d.ts +2 -0
  8. package/dist/__tests__/asset-brand-and-name-retirement.test.d.ts.map +1 -0
  9. package/dist/__tests__/asset-error-exhaustive.test-d.d.ts +11 -0
  10. package/dist/__tests__/asset-error-exhaustive.test-d.d.ts.map +1 -0
  11. package/dist/__tests__/asset-registry-guid-reverse.test.d.ts +2 -0
  12. package/dist/__tests__/asset-registry-guid-reverse.test.d.ts.map +1 -0
  13. package/dist/__tests__/asset-registry-hdr-equirect.test.d.ts +2 -0
  14. package/dist/__tests__/asset-registry-hdr-equirect.test.d.ts.map +1 -0
  15. package/dist/__tests__/asset-registry-mesh-pack-payload.dawn.test.d.ts +2 -0
  16. package/dist/__tests__/asset-registry-mesh-pack-payload.dawn.test.d.ts.map +1 -0
  17. package/dist/__tests__/asset-registry-mounts.test.d.ts +2 -0
  18. package/dist/__tests__/asset-registry-mounts.test.d.ts.map +1 -0
  19. package/dist/__tests__/asset-registry.browser.test.d.ts +2 -0
  20. package/dist/__tests__/asset-registry.browser.test.d.ts.map +1 -0
  21. package/dist/__tests__/asset-registry.dawn.test.d.ts +2 -0
  22. package/dist/__tests__/asset-registry.dawn.test.d.ts.map +1 -0
  23. package/dist/__tests__/asset-registry.listCatalog.test.d.ts +2 -0
  24. package/dist/__tests__/asset-registry.listCatalog.test.d.ts.map +1 -0
  25. package/dist/__tests__/asset-registry.mesh-bin.test.d.ts +2 -0
  26. package/dist/__tests__/asset-registry.mesh-bin.test.d.ts.map +1 -0
  27. package/dist/__tests__/asset-registry.pack-cache.test.d.ts +2 -0
  28. package/dist/__tests__/asset-registry.pack-cache.test.d.ts.map +1 -0
  29. package/dist/__tests__/asset-registry.raw-container-failfast.test.d.ts +2 -0
  30. package/dist/__tests__/asset-registry.raw-container-failfast.test.d.ts.map +1 -0
  31. package/dist/__tests__/asset-registry.recursive.spec.d.ts +2 -0
  32. package/dist/__tests__/asset-registry.recursive.spec.d.ts.map +1 -0
  33. package/dist/__tests__/asset-registry.unit.test.d.ts +2 -0
  34. package/dist/__tests__/asset-registry.unit.test.d.ts.map +1 -0
  35. package/dist/__tests__/asset.unit.test.d.ts +2 -0
  36. package/dist/__tests__/asset.unit.test.d.ts.map +1 -0
  37. package/dist/__tests__/audio-load-by-guid.unit.test.d.ts +2 -0
  38. package/dist/__tests__/audio-load-by-guid.unit.test.d.ts.map +1 -0
  39. package/dist/__tests__/backend-selection.integration.test.d.ts +2 -0
  40. package/dist/__tests__/backend-selection.integration.test.d.ts.map +1 -0
  41. package/dist/__tests__/basis-catalog-dispatch.integration.test.d.ts +2 -0
  42. package/dist/__tests__/basis-catalog-dispatch.integration.test.d.ts.map +1 -0
  43. package/dist/__tests__/builtin-asset-registry.unit.test.d.ts +2 -0
  44. package/dist/__tests__/builtin-asset-registry.unit.test.d.ts.map +1 -0
  45. package/dist/__tests__/collect-scene-asset.test.d.ts +1 -2
  46. package/dist/__tests__/collect-scene-asset.test.d.ts.map +1 -1
  47. package/dist/__tests__/collect-scene-mount-collapse.test.d.ts +2 -0
  48. package/dist/__tests__/collect-scene-mount-collapse.test.d.ts.map +1 -0
  49. package/dist/__tests__/collect-transient-roundtrip.test.d.ts +1 -1
  50. package/dist/__tests__/collect-transient-roundtrip.test.d.ts.map +1 -1
  51. package/dist/__tests__/collect-transient-skip.test.d.ts +1 -2
  52. package/dist/__tests__/collect-transient-skip.test.d.ts.map +1 -1
  53. package/dist/__tests__/compressed-texture-physical-extent.integration.test.d.ts +2 -0
  54. package/dist/__tests__/compressed-texture-physical-extent.integration.test.d.ts.map +1 -0
  55. package/dist/__tests__/dawn/mesh-update-dawn.test.d.ts +2 -0
  56. package/dist/__tests__/dawn/mesh-update-dawn.test.d.ts.map +1 -0
  57. package/dist/__tests__/dawn/upload-texture.dawn.test.d.ts +2 -0
  58. package/dist/__tests__/dawn/upload-texture.dawn.test.d.ts.map +1 -0
  59. package/dist/__tests__/draw-published.d.ts +2 -2
  60. package/dist/__tests__/draw-published.d.ts.map +1 -1
  61. package/dist/__tests__/dynamic-texture-store.unit.test.d.ts +2 -0
  62. package/dist/__tests__/dynamic-texture-store.unit.test.d.ts.map +1 -0
  63. package/dist/__tests__/errors.unit.test.d.ts +2 -0
  64. package/dist/__tests__/errors.unit.test.d.ts.map +1 -0
  65. package/dist/__tests__/extract-skin-mismatch.unit.test.d.ts +2 -0
  66. package/dist/__tests__/extract-skin-mismatch.unit.test.d.ts.map +1 -0
  67. package/dist/__tests__/fetch-binary-decompress.test.d.ts +2 -0
  68. package/dist/__tests__/fetch-binary-decompress.test.d.ts.map +1 -0
  69. package/dist/__tests__/four-path-compression.integration.test.d.ts +2 -0
  70. package/dist/__tests__/four-path-compression.integration.test.d.ts.map +1 -0
  71. package/dist/__tests__/fullscreen-feature-host.dawn.test.d.ts +2 -0
  72. package/dist/__tests__/fullscreen-feature-host.dawn.test.d.ts.map +1 -0
  73. package/dist/__tests__/guid-for-asset.unit.test.d.ts +2 -0
  74. package/dist/__tests__/guid-for-asset.unit.test.d.ts.map +1 -0
  75. package/dist/__tests__/handle-migration.test.d.ts +2 -0
  76. package/dist/__tests__/handle-migration.test.d.ts.map +1 -0
  77. package/dist/__tests__/helpers/register-runtime-components.d.ts.map +1 -1
  78. package/dist/__tests__/host-custom-kind-contract.test-d.d.ts +2 -0
  79. package/dist/__tests__/host-custom-kind-contract.test-d.d.ts.map +1 -0
  80. package/dist/__tests__/host-custom-kind-contract.test.d.ts +2 -0
  81. package/dist/__tests__/host-custom-kind-contract.test.d.ts.map +1 -0
  82. package/dist/__tests__/inspect-name.test.d.ts +2 -0
  83. package/dist/__tests__/inspect-name.test.d.ts.map +1 -0
  84. package/dist/__tests__/instantiate-mount-deferred-wiring.test.d.ts +2 -0
  85. package/dist/__tests__/instantiate-mount-deferred-wiring.test.d.ts.map +1 -0
  86. package/dist/__tests__/loadbyguid-payload.unit.test.d.ts +2 -0
  87. package/dist/__tests__/loadbyguid-payload.unit.test.d.ts.map +1 -0
  88. package/dist/__tests__/loadbyguid-texture-intern.unit.test.d.ts +2 -0
  89. package/dist/__tests__/loadbyguid-texture-intern.unit.test.d.ts.map +1 -0
  90. package/dist/__tests__/loader-extract-graceful.test.d.ts +2 -0
  91. package/dist/__tests__/loader-extract-graceful.test.d.ts.map +1 -0
  92. package/dist/__tests__/loader-name-survival.test.d.ts +2 -0
  93. package/dist/__tests__/loader-name-survival.test.d.ts.map +1 -0
  94. package/dist/__tests__/mesh-bin-contract.test.d.ts +2 -0
  95. package/dist/__tests__/mesh-bin-contract.test.d.ts.map +1 -0
  96. package/dist/__tests__/mesh-bin-skin-roundtrip.unit.test.d.ts +2 -0
  97. package/dist/__tests__/mesh-bin-skin-roundtrip.unit.test.d.ts.map +1 -0
  98. package/dist/__tests__/mesh-bin.test.d.ts +2 -0
  99. package/dist/__tests__/mesh-bin.test.d.ts.map +1 -0
  100. package/dist/__tests__/mesh-loader-skin-contract.unit.test.d.ts +2 -0
  101. package/dist/__tests__/mesh-loader-skin-contract.unit.test.d.ts.map +1 -0
  102. package/dist/__tests__/new-kind-refs-contract.test.d.ts +2 -0
  103. package/dist/__tests__/new-kind-refs-contract.test.d.ts.map +1 -0
  104. package/dist/__tests__/package-promotion.test.d.ts +2 -0
  105. package/dist/__tests__/package-promotion.test.d.ts.map +1 -0
  106. package/dist/__tests__/package-rename.test.d.ts +2 -0
  107. package/dist/__tests__/package-rename.test.d.ts.map +1 -0
  108. package/dist/__tests__/recover-error-exhaustive.test-d.d.ts +1 -1
  109. package/dist/__tests__/recover-error-exhaustive.test-d.d.ts.map +1 -1
  110. package/dist/__tests__/render-error-exhaustive.test-d.d.ts +1 -1
  111. package/dist/__tests__/render-error-exhaustive.test-d.d.ts.map +1 -1
  112. package/dist/__tests__/render-feature-prepared-graphics.fixture.d.ts +10 -0
  113. package/dist/__tests__/render-feature-prepared-graphics.fixture.d.ts.map +1 -0
  114. package/dist/__tests__/render-system-extract.unit.test.d.ts +2 -0
  115. package/dist/__tests__/render-system-extract.unit.test.d.ts.map +1 -0
  116. package/dist/__tests__/renderer-test-utils.d.ts +10 -0
  117. package/dist/__tests__/renderer-test-utils.d.ts.map +1 -0
  118. package/dist/__tests__/renderer.test-d.d.ts +2 -0
  119. package/dist/__tests__/renderer.test-d.d.ts.map +1 -0
  120. package/dist/__tests__/resolve-asset-handle-err.test.d.ts +2 -0
  121. package/dist/__tests__/resolve-asset-handle-err.test.d.ts.map +1 -0
  122. package/dist/__tests__/resolve-asset-handle.unit.test.d.ts +2 -0
  123. package/dist/__tests__/resolve-asset-handle.unit.test.d.ts.map +1 -0
  124. package/dist/__tests__/resolveName-fallback.test.d.ts +2 -0
  125. package/dist/__tests__/resolveName-fallback.test.d.ts.map +1 -0
  126. package/dist/__tests__/resolveName-null-package.test.d.ts +2 -0
  127. package/dist/__tests__/resolveName-null-package.test.d.ts.map +1 -0
  128. package/dist/__tests__/resolveName-unified-entry.test.d.ts +2 -0
  129. package/dist/__tests__/resolveName-unified-entry.test.d.ts.map +1 -0
  130. package/dist/__tests__/resolveName.test.d.ts +2 -0
  131. package/dist/__tests__/resolveName.test.d.ts.map +1 -0
  132. package/dist/__tests__/roots-to-scene-asset.test.d.ts +1 -1
  133. package/dist/__tests__/roots-to-scene-asset.test.d.ts.map +1 -1
  134. package/dist/__tests__/roundtrip-primitive.test.d.ts +2 -0
  135. package/dist/__tests__/roundtrip-primitive.test.d.ts.map +1 -0
  136. package/dist/__tests__/scene-bare-guid-refs-instantiate.test.d.ts +2 -0
  137. package/dist/__tests__/scene-bare-guid-refs-instantiate.test.d.ts.map +1 -0
  138. package/dist/__tests__/scene-instance-authoring.integration.test.d.ts +2 -0
  139. package/dist/__tests__/scene-instance-authoring.integration.test.d.ts.map +1 -0
  140. package/dist/__tests__/scene-mount-fixed-point.test.d.ts +2 -0
  141. package/dist/__tests__/scene-mount-fixed-point.test.d.ts.map +1 -0
  142. package/dist/__tests__/scene-mount-roundtrip.test.d.ts +2 -0
  143. package/dist/__tests__/scene-mount-roundtrip.test.d.ts.map +1 -0
  144. package/dist/__tests__/scene-mount-wrapper-roundtrip.test.d.ts +2 -0
  145. package/dist/__tests__/scene-mount-wrapper-roundtrip.test.d.ts.map +1 -0
  146. package/dist/__tests__/scene-sugar-instantiate.test.d.ts +2 -0
  147. package/dist/__tests__/scene-sugar-instantiate.test.d.ts.map +1 -0
  148. package/dist/__tests__/serialize-mounts-roundtrip.test.d.ts +2 -0
  149. package/dist/__tests__/serialize-mounts-roundtrip.test.d.ts.map +1 -0
  150. package/dist/__tests__/serialize-scene-asset.test.d.ts +1 -1
  151. package/dist/__tests__/serialize-scene-asset.test.d.ts.map +1 -1
  152. package/dist/__tests__/template-game-default-api-contract.test.d.ts +2 -0
  153. package/dist/__tests__/template-game-default-api-contract.test.d.ts.map +1 -0
  154. package/dist/__tests__/tileset-asset-validate.test.d.ts +2 -0
  155. package/dist/__tests__/tileset-asset-validate.test.d.ts.map +1 -0
  156. package/dist/__tests__/transcode-fallback.unit.test.d.ts +2 -0
  157. package/dist/__tests__/transcode-fallback.unit.test.d.ts.map +1 -0
  158. package/dist/__tests__/transient-runtime-behavior.test.d.ts +2 -0
  159. package/dist/__tests__/transient-runtime-behavior.test.d.ts.map +1 -0
  160. package/dist/__tests__/video-loader-consumption.test.d.ts +2 -0
  161. package/dist/__tests__/video-loader-consumption.test.d.ts.map +1 -0
  162. package/dist/__tests__/video-loader-smoke.dawn.test.d.ts +2 -0
  163. package/dist/__tests__/video-loader-smoke.dawn.test.d.ts.map +1 -0
  164. package/dist/backend-selection.d.ts +13 -0
  165. package/dist/backend-selection.d.ts.map +1 -0
  166. package/dist/collect-scene-asset.d.ts +3 -3
  167. package/dist/collect-scene-asset.d.ts.map +1 -1
  168. package/dist/createRenderer.d.ts +14 -2
  169. package/dist/createRenderer.d.ts.map +1 -1
  170. package/dist/errors/environment.d.ts +1 -1
  171. package/dist/errors/environment.d.ts.map +1 -1
  172. package/dist/index.d.ts +19 -81
  173. package/dist/index.d.ts.map +1 -1
  174. package/dist/index.mjs +105 -108
  175. package/dist/index.mjs.map +1 -1
  176. package/dist/renderer-host.d.ts +9 -0
  177. package/dist/renderer-host.d.ts.map +1 -0
  178. package/dist/renderer-host.mjs +62 -0
  179. package/dist/renderer-host.mjs.map +1 -0
  180. package/dist/scene-instances/index.d.ts +2 -0
  181. package/dist/scene-instances/index.d.ts.map +1 -0
  182. package/dist/scene-utils/mount-override-fold.d.ts +1 -2
  183. package/dist/scene-utils/mount-override-fold.d.ts.map +1 -1
  184. package/dist/systems/sprite-animation-tick.d.ts +1 -1
  185. package/dist/systems/sprite-animation-tick.d.ts.map +1 -1
  186. package/dist/systems/transparent-sort.d.ts +1 -2
  187. package/dist/systems/transparent-sort.d.ts.map +1 -1
  188. package/dist/tilemap-register-validate.d.ts.map +1 -1
  189. package/package.json +34 -33
  190. package/src/__tests__/active-camera.unit.test.ts +19 -9
  191. package/src/__tests__/animation-graph-collect-roundtrip.test.ts +213 -0
  192. package/src/__tests__/animation-graph-serialize.unit.test.ts +171 -0
  193. package/src/__tests__/append-injection.test.ts +1 -1
  194. package/src/__tests__/asset-brand-and-name-retirement.test.ts +102 -0
  195. package/src/__tests__/asset-error-exhaustive.test-d.ts +62 -0
  196. package/src/__tests__/asset-registry-guid-reverse.test.ts +575 -0
  197. package/src/__tests__/asset-registry-hdr-equirect.test.ts +78 -0
  198. package/src/__tests__/asset-registry-mesh-pack-payload.dawn.test.ts +232 -0
  199. package/src/__tests__/asset-registry-mounts.test.ts +806 -0
  200. package/src/__tests__/asset-registry.browser.test.ts +81 -0
  201. package/src/__tests__/asset-registry.dawn.test.ts +94 -0
  202. package/src/__tests__/asset-registry.listCatalog.test.ts +170 -0
  203. package/src/__tests__/asset-registry.mesh-bin.test.ts +316 -0
  204. package/src/__tests__/asset-registry.pack-cache.test.ts +969 -0
  205. package/src/__tests__/asset-registry.raw-container-failfast.test.ts +225 -0
  206. package/src/__tests__/asset-registry.recursive.spec.ts +1397 -0
  207. package/src/__tests__/asset-registry.unit.test.ts +1030 -0
  208. package/src/__tests__/asset.unit.test.ts +7107 -0
  209. package/src/__tests__/audio-load-by-guid.unit.test.ts +126 -0
  210. package/src/__tests__/backend-selection.integration.test.ts +11 -0
  211. package/src/__tests__/basis-catalog-dispatch.integration.test.ts +320 -0
  212. package/src/__tests__/bind-group-cache-keying.test.ts +4 -4
  213. package/src/__tests__/block-upload-math.unit.test.ts +2 -2
  214. package/src/__tests__/builtin-asset-registry.unit.test.ts +112 -0
  215. package/src/__tests__/builtin-shader-register-e2e.test.ts +1 -1
  216. package/src/__tests__/cache-false-eviction.test.ts +2 -1
  217. package/src/__tests__/cache-isolation-matrix.test.ts +2 -1
  218. package/src/__tests__/camera-clear-snapshot-equivalence.unit.test.ts +5 -6
  219. package/src/__tests__/clamp-to-last.e2e.browser.test.ts +29 -19
  220. package/src/__tests__/collect-scene-asset.test.ts +49 -52
  221. package/src/__tests__/collect-scene-mount-collapse.test.ts +391 -0
  222. package/src/__tests__/collect-subtree.unit.test.ts +1 -2
  223. package/src/__tests__/collect-transient-children-absent.test.ts +24 -10
  224. package/src/__tests__/collect-transient-roundtrip.test.ts +44 -20
  225. package/src/__tests__/collect-transient-skip.test.ts +24 -13
  226. package/src/__tests__/components.test-d.ts +1 -6
  227. package/src/__tests__/components.unit.test.ts +20 -19
  228. package/src/__tests__/composite-skybox-cross-world.browser.test.ts +59 -27
  229. package/src/__tests__/compressed-texture-physical-extent.integration.test.ts +139 -0
  230. package/src/__tests__/create-renderer-assembly.integration.test.ts +42 -29
  231. package/src/__tests__/createRenderer-dispose.test.ts +35 -402
  232. package/src/__tests__/createRenderer.browser-no-webgpu.test.ts +25 -30
  233. package/src/__tests__/createRenderer.unit.test.ts +1 -1
  234. package/src/__tests__/dawn/hello-sprite-nineslice-section.dawn.test.ts +27 -63
  235. package/src/__tests__/dawn/ibl-precompute-readback.dawn.test.ts +56 -47
  236. package/src/__tests__/dawn/instances-per-instance-pbr.dawn.test.ts +49 -29
  237. package/src/__tests__/dawn/instances-shadow.dawn.test.ts +26 -15
  238. package/src/__tests__/dawn/instances-uniform-fallback.dawn.test.ts +13 -14
  239. package/src/__tests__/dawn/material-alpha.dawn.test.ts +23 -31
  240. package/src/__tests__/dawn/material-cooked-fixture.dawn.test.ts +0 -18
  241. package/src/__tests__/dawn/{mesh-update.dawn.test.ts → mesh-update-dawn.test.ts} +42 -134
  242. package/src/__tests__/dawn/mipmap-srgb-linear.dawn.test.ts +14 -7
  243. package/src/__tests__/dawn/per-entity-material-texture-isolation.dawn.test.ts +16 -28
  244. package/src/__tests__/dawn/sprite-nineslice-mesh-bind.dawn.test.ts +23 -39
  245. package/src/__tests__/dawn/upload-texture.dawn.test.ts +198 -0
  246. package/src/__tests__/dawn/user-handle-mesh-render.dawn.test.ts +12 -14
  247. package/src/__tests__/dawn/user-mesh-upload.dawn.test.ts +27 -22
  248. package/src/__tests__/dawn/zero-manifest-mesh-fail.dawn.test.ts +25 -28
  249. package/src/__tests__/dawn/zero-manifest-ready.dawn.test.ts +10 -11
  250. package/src/__tests__/demo-sortscope-migration.unit.test.ts +5 -5
  251. package/src/__tests__/derive-bgl-integration.test.ts +34 -44
  252. package/src/__tests__/derive-render-data-skin.unit.test.ts +1 -1
  253. package/src/__tests__/draw-published.ts +11 -4
  254. package/src/__tests__/dynamic-texture-store.unit.test.ts +190 -0
  255. package/src/__tests__/equirect-bc6h.integration.test.ts +144 -21
  256. package/src/__tests__/errors.unit.test.ts +1203 -0
  257. package/src/__tests__/extract-frames-graceful-degradation.test.ts +3 -7
  258. package/src/__tests__/extract-frames-merge.test.ts +35 -22
  259. package/src/__tests__/extract-record-no-hardcoded-texture-fields.test.ts +5 -16
  260. package/src/__tests__/extract-skin-mismatch.unit.test.ts +322 -0
  261. package/src/__tests__/fetch-binary-decompress.test.ts +356 -0
  262. package/src/__tests__/four-path-compression.integration.test.ts +395 -0
  263. package/src/__tests__/frame-targets-shadow-regression.unit.test.ts +1 -1
  264. package/src/__tests__/fullscreen-feature-host.dawn.test.ts +80 -0
  265. package/src/__tests__/fullscreen-post-bgl-depth.test.ts +4 -2
  266. package/src/__tests__/fullscreen-post-depth-params-arity.test.ts +3 -3
  267. package/src/__tests__/fullscreen-post-process-pass.dawn.test.ts +39 -23
  268. package/src/__tests__/fullscreen-post-process-pass.unit.test.ts +4 -2
  269. package/src/__tests__/fxaa-pixel-diff.dawn.test.ts +28 -17
  270. package/src/__tests__/fxaa-validation-and-resize.dawn.test.ts +29 -18
  271. package/src/__tests__/fxaa-zero-overhead.dawn.test.ts +16 -12
  272. package/src/__tests__/geometry.unit.test.ts +525 -159
  273. package/src/__tests__/glyph-tilemap-worldid.test.ts +1 -1
  274. package/src/__tests__/gpu-resource-cow-survivor.test.ts +6 -4
  275. package/src/__tests__/guid-for-asset.unit.test.ts +102 -0
  276. package/src/__tests__/handle-migration.test.ts +136 -0
  277. package/src/__tests__/helpers/register-runtime-components.ts +4 -2
  278. package/src/__tests__/helpers/register-scene-components.ts +1 -1
  279. package/src/__tests__/host-custom-kind-contract.test-d.ts +47 -0
  280. package/src/__tests__/host-custom-kind-contract.test.ts +578 -0
  281. package/src/__tests__/inspect-name.test.ts +139 -0
  282. package/src/__tests__/instances.test-d.ts +1 -1
  283. package/src/__tests__/instantiate-mount-deferred-wiring.test.ts +112 -0
  284. package/src/__tests__/light-casters-9-light.browser.test.ts +73 -76
  285. package/src/__tests__/light-gpu-byte-neutral.unit.test.ts +7 -10
  286. package/src/__tests__/light-snapshot.test-d.ts +2 -2
  287. package/src/__tests__/lights-vec-negative.unit.test.ts +1 -1
  288. package/src/__tests__/lights.unit.test.ts +16 -500
  289. package/src/__tests__/loadbyguid-payload.unit.test.ts +117 -0
  290. package/src/__tests__/loadbyguid-texture-intern.unit.test.ts +213 -0
  291. package/src/__tests__/loader-extract-graceful.test.ts +146 -0
  292. package/src/__tests__/loader-name-survival.test.ts +213 -0
  293. package/src/__tests__/m3-vec-negative.unit.test.ts +3 -2
  294. package/src/__tests__/material-texture-uv-scale.unit.test.ts +101 -31
  295. package/src/__tests__/materials.unit.test.ts +10 -27
  296. package/src/__tests__/mesh-bin-contract.test.ts +28 -0
  297. package/src/__tests__/mesh-bin-skin-roundtrip.unit.test.ts +149 -0
  298. package/src/__tests__/mesh-bin.test.ts +38 -0
  299. package/src/__tests__/mesh-loader-skin-contract.unit.test.ts +120 -0
  300. package/src/__tests__/mesh-ssbo-grow.unit.test.ts +3 -3
  301. package/src/__tests__/mip-gate.unit.test.ts +1 -1
  302. package/src/__tests__/msaa-sprite-pixel-diff.dawn.test.ts +29 -68
  303. package/src/__tests__/new-kind-refs-contract.test.ts +132 -0
  304. package/src/__tests__/node-shims.d.ts +4 -6
  305. package/src/__tests__/package-promotion.test.ts +88 -0
  306. package/src/__tests__/package-rename.test.ts +103 -0
  307. package/src/__tests__/pass-selector.unit.test.ts +2 -2
  308. package/src/__tests__/pbr-pipeline.unit.test.ts +14 -21
  309. package/src/__tests__/pipeline-builder-msaa.unit.test.ts +6 -9
  310. package/src/__tests__/pipeline-cache-keying.unit.test.ts +6 -9
  311. package/src/__tests__/pipeline-spec.test.ts +16 -177
  312. package/src/__tests__/pipeline.unit.test.ts +154 -1693
  313. package/src/__tests__/point-light-shadow.dawn.test.ts +33 -42
  314. package/src/__tests__/point-light-shadow.unit.test.ts +19 -60
  315. package/src/__tests__/post-process-error-codes.unit.test.ts +4 -1
  316. package/src/__tests__/post-process-params-component.unit.test.ts +1 -1
  317. package/src/__tests__/post-process-params-extract.unit.test.ts +2 -5
  318. package/src/__tests__/postprocess-camera-consistency.test.ts +4 -7
  319. package/src/__tests__/profiler-assembly.integration.test.ts +1 -1
  320. package/src/__tests__/propagate-transforms.dawn.test.ts +12 -11
  321. package/src/__tests__/record-worldid-isolation.test.ts +7 -29
  322. package/src/__tests__/recover-error-exhaustive.test-d.ts +1 -1
  323. package/src/__tests__/render-error-exhaustive.test-d.ts +81 -71
  324. package/src/__tests__/render-feature-assembly.test-d.ts +20 -9
  325. package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +8 -6
  326. package/src/__tests__/render-feature-prepared-graphics.browser.test.ts +60 -558
  327. package/src/__tests__/render-feature-prepared-graphics.dawn.test.ts +57 -544
  328. package/src/__tests__/render-feature-prepared-graphics.fixture.ts +104 -0
  329. package/src/__tests__/render-feature-prepared-graphics.integration.test.ts +40 -248
  330. package/src/__tests__/render-feature-prepared-graphics.regression.integration.test.ts +83 -340
  331. package/src/__tests__/render-feature-recover.integration.test.ts +9 -49
  332. package/src/__tests__/render-feature-runtime-surface.test-d.ts +17 -20
  333. package/src/__tests__/render-schema-consumer.integration.test.ts +20 -13
  334. package/src/__tests__/render-schema-owner-boundary.unit.test.ts +2 -6
  335. package/src/__tests__/render-system-cross-world-overlay-queue.test.ts +5 -5
  336. package/src/__tests__/render-system-extract-dispatch-ordering.test.ts +16 -31
  337. package/src/__tests__/render-system-extract.test.ts +36 -51
  338. package/src/__tests__/render-system-extract.unit.test.ts +360 -0
  339. package/src/__tests__/render-system-fold-bucket.unit.test.ts +3 -5
  340. package/src/__tests__/render-system-fold-fallback.unit.test.ts +6 -3
  341. package/src/__tests__/render-system-fold-material.unit.test.ts +3 -5
  342. package/src/__tests__/render-system-fold-metrics.unit.test.ts +5 -5
  343. package/src/__tests__/render-system-fold-modegate.unit.test.ts +6 -6
  344. package/src/__tests__/render-system-fold.dawn.test.ts +7 -5
  345. package/src/__tests__/render-system-mega.test.ts +292 -190
  346. package/src/__tests__/render-system-owner-split-contract.test.ts +10 -32
  347. package/src/__tests__/render-system-record-multi-material-textureview.test.ts +59 -45
  348. package/src/__tests__/render-system-record-per-submesh-transparency.test.ts +23 -29
  349. package/src/__tests__/render-system-record.test.ts +398 -235
  350. package/src/__tests__/render-system-record.unit.test.ts +25 -26
  351. package/src/__tests__/render-system-skin-bg.unit.test.ts +8 -12
  352. package/src/__tests__/renderer-consumer.test-d.ts +16 -3
  353. package/src/__tests__/renderer-health.unit.test.ts +26 -916
  354. package/src/__tests__/renderer-lifecycle.integration.test.ts +19 -6
  355. package/src/__tests__/renderer-recover.unit.test.ts +49 -1069
  356. package/src/__tests__/renderer-result.test-d.ts +19 -9
  357. package/src/__tests__/renderer-surface.unit.test.ts +3 -5
  358. package/src/__tests__/renderer-test-utils.ts +56 -0
  359. package/src/__tests__/renderer.test-d.ts +59 -0
  360. package/src/__tests__/resolve-asset-handle-err.test.ts +111 -0
  361. package/src/__tests__/resolve-asset-handle.unit.test.ts +64 -0
  362. package/src/__tests__/resolve-depth-only-view.test.ts +1 -1
  363. package/src/__tests__/resolveName-fallback.test.ts +64 -0
  364. package/src/__tests__/resolveName-null-package.test.ts +38 -0
  365. package/src/__tests__/resolveName-unified-entry.test.ts +65 -0
  366. package/src/__tests__/resolveName.test.ts +64 -0
  367. package/src/__tests__/rhi-null-command-flow.unit.test.ts +43 -261
  368. package/src/__tests__/rhi-null-renderer-lifecycle.unit.test.ts +41 -169
  369. package/src/__tests__/roots-to-scene-asset.test.ts +199 -93
  370. package/src/__tests__/roundtrip-primitive.test.ts +351 -0
  371. package/src/__tests__/scene-bare-guid-refs-instantiate.test.ts +123 -0
  372. package/src/__tests__/scene-equirect-roundtrip.test.ts +103 -16
  373. package/src/__tests__/scene-instance-authoring.integration.test.ts +8 -0
  374. package/src/__tests__/scene-instance-bridge.integration.test.ts +1 -1
  375. package/src/__tests__/scene-instance-component.test.ts +1 -1
  376. package/src/__tests__/scene-mount-fixed-point.test.ts +257 -0
  377. package/src/__tests__/scene-mount-roundtrip.test.ts +987 -0
  378. package/src/__tests__/scene-mount-wrapper-roundtrip.test.ts +202 -0
  379. package/src/__tests__/scene-sugar-instantiate.test.ts +324 -0
  380. package/src/__tests__/serialize-mounts-roundtrip.test.ts +533 -0
  381. package/src/__tests__/serialize-scene-asset.test.ts +219 -22
  382. package/src/__tests__/shadow-caster-empty-schema.test.ts +3 -3
  383. package/src/__tests__/shadow-csm-cascade-loadop.test.ts +37 -17
  384. package/src/__tests__/shadow-csm-component.test.ts +3 -5
  385. package/src/__tests__/shadow-csm-extract.test.ts +2 -100
  386. package/src/__tests__/shadow-csm-orthoz.test.ts +2 -16
  387. package/src/__tests__/shadow-csm-runtime-vary.dawn.test.ts +19 -14
  388. package/src/__tests__/shadow-csm-tile-consistency.test.ts +32 -26
  389. package/src/__tests__/shadow-csm-ubo.dawn.test.ts +8 -49
  390. package/src/__tests__/shadow-csm-ubo.test.ts +3 -25
  391. package/src/__tests__/shadow-csm-viewport.browser.test.ts +1 -1
  392. package/src/__tests__/shadow-fields-observable.dawn.test.ts +67 -56
  393. package/src/__tests__/shadow-m1.dawn.test.ts +8 -9
  394. package/src/__tests__/shadow-mesh-ssbo-order.test.ts +11 -27
  395. package/src/__tests__/skin-errors.unit.test.ts +1 -1
  396. package/src/__tests__/skin-extract-getarrayview-count.unit.test.ts +7 -5
  397. package/src/__tests__/skylight-lazy-projection.test.ts +36 -15
  398. package/src/__tests__/sparse-tag-scene-roundtrip.test.ts +5 -5
  399. package/src/__tests__/sprite-cullmode-flip.dawn.test.ts +47 -64
  400. package/src/__tests__/sprite-lit-bgl-byte-identical.test.ts +12 -11
  401. package/src/__tests__/sprite-lit-extract-branch.test.ts +1 -1
  402. package/src/__tests__/sprite-lit-pipeline-cache-key.test.ts +1 -1
  403. package/src/__tests__/ssao-bgl.test.ts +16 -9
  404. package/src/__tests__/ssao-buffers.test.ts +2 -2
  405. package/src/__tests__/ssao-data.test.ts +2 -2
  406. package/src/__tests__/ssao-errors.test.ts +1 -1
  407. package/src/__tests__/ssao-passes.test.ts +64 -392
  408. package/src/__tests__/ssao-pipelines.test.ts +1 -1
  409. package/src/__tests__/ssao-uniform-layout.test.ts +8 -6
  410. package/src/__tests__/stencil-outline-pixel.dawn.test.ts +25 -17
  411. package/src/__tests__/swap-chain-format.unit.test.ts +5 -7
  412. package/src/__tests__/systems.unit.test.ts +536 -1326
  413. package/src/__tests__/template-game-default-api-contract.test.ts +362 -0
  414. package/src/__tests__/text.unit.test.ts +56 -33
  415. package/src/__tests__/tilemap-childed-despawn.test.ts +8 -14
  416. package/src/__tests__/tilemap-chunk-extract.overhang-bounds.test.ts +8 -12
  417. package/src/__tests__/tilemap-chunk-extract.propagate-order.test.ts +2 -1
  418. package/src/__tests__/tilemap-chunk-extract.test.ts +13 -17
  419. package/src/__tests__/tilemap-dirty-rebuild.test.ts +7 -11
  420. package/src/__tests__/tilemap-material-cache.test.ts +8 -13
  421. package/src/__tests__/tilemap-multi-atlas.test.ts +12 -32
  422. package/src/__tests__/tilemap-owner-boundary.unit.test.ts +5 -2
  423. package/src/__tests__/tilemap-region-pack.test.ts +8 -12
  424. package/src/__tests__/tilemap-spawn-flip-pivot.test.ts +8 -12
  425. package/src/__tests__/tilemap-uv-inset.test.ts +11 -14
  426. package/src/__tests__/tilemap-validate.test.ts +1 -1
  427. package/src/__tests__/tileset-asset-validate.test.ts +638 -0
  428. package/src/__tests__/transcode-fallback.unit.test.ts +207 -0
  429. package/src/__tests__/transform-hierarchy-pixel-diff.dawn.test.ts +36 -28
  430. package/src/__tests__/transient-fields-collect.test.ts +28 -21
  431. package/src/__tests__/transient-runtime-behavior.test.ts +227 -0
  432. package/src/__tests__/transparent-sort-tilemap-sprite-interleave.test.ts +4 -4
  433. package/src/__tests__/variant-selection.unit.test.ts +1 -1
  434. package/src/__tests__/video-extract-bindgroup.dawn.test.ts +89 -136
  435. package/src/__tests__/video-loader-consumption.test.ts +86 -0
  436. package/src/__tests__/video-loader-smoke.dawn.test.ts +60 -0
  437. package/src/__tests__/view-ubo-layout.browser.test.ts +0 -22
  438. package/src/__tests__/world-entity-key.test.ts +1 -1
  439. package/src/__tests__/world-scene-despawn.test.ts +1 -1
  440. package/src/__tests__/world-scene-instantiate.test.ts +2 -36
  441. package/src/__tests__/world-scene-nested.test.ts +1 -1
  442. package/src/__tests__/world-scene-override.test.ts +1 -1
  443. package/src/backend-selection.ts +69 -0
  444. package/src/collect-scene-asset.ts +28 -23
  445. package/src/components/__tests__/camera.test-d.ts +1 -1
  446. package/src/components/__tests__/camera.test.ts +1 -1
  447. package/src/components/__tests__/sprite-animation.test-d.ts +2 -2
  448. package/src/components/__tests__/tile-layer.test-d.ts +1 -1
  449. package/src/components/__tests__/tile-layer.unit.test.ts +2 -2
  450. package/src/createRenderer.ts +24 -36
  451. package/src/errors/environment.ts +1 -1
  452. package/src/index.ts +47 -113
  453. package/src/renderer-host.ts +33 -0
  454. package/src/scene-instances/__tests__/post-spawn-resolve-joints.unit.test.ts +1 -1
  455. package/src/scene-instances/index.ts +4 -0
  456. package/src/scene-utils/mount-override-fold.ts +3 -7
  457. package/src/systems/__tests__/transparent-sort.bench.ts +3 -3
  458. package/src/systems/sprite-animation-tick.ts +1 -1
  459. package/src/systems/transparent-sort.ts +38 -38
  460. package/src/tilemap-register-validate.ts +4 -4
  461. package/dist/__tests__/bind-group-cache-binding.test.d.ts +0 -2
  462. package/dist/__tests__/bind-group-cache-binding.test.d.ts.map +0 -1
  463. package/dist/__tests__/bind-group-cache-frame.test.d.ts +0 -2
  464. package/dist/__tests__/bind-group-cache-frame.test.d.ts.map +0 -1
  465. package/dist/__tests__/dawn/mesh-update.dawn.test.d.ts +0 -2
  466. package/dist/__tests__/dawn/mesh-update.dawn.test.d.ts.map +0 -1
  467. package/dist/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.d.ts +0 -2
  468. package/dist/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.d.ts.map +0 -1
  469. package/dist/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.d.ts +0 -2
  470. package/dist/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.d.ts.map +0 -1
  471. package/dist/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.d.ts +0 -2
  472. package/dist/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.d.ts.map +0 -1
  473. package/dist/__tests__/dispatch-fullscreen-pass-params.unit.test.d.ts +0 -2
  474. package/dist/__tests__/dispatch-fullscreen-pass-params.unit.test.d.ts.map +0 -1
  475. package/dist/__tests__/fog-producer-manifest.d.ts +0 -131
  476. package/dist/__tests__/fog-producer-manifest.d.ts.map +0 -1
  477. package/dist/__tests__/fog-producer-pixel-probe.d.ts +0 -42
  478. package/dist/__tests__/fog-producer-pixel-probe.d.ts.map +0 -1
  479. package/dist/__tests__/fog-producer-pixel.browser.test.d.ts +0 -2
  480. package/dist/__tests__/fog-producer-pixel.browser.test.d.ts.map +0 -1
  481. package/dist/__tests__/fog-producer-pixel.dawn.test.d.ts +0 -2
  482. package/dist/__tests__/fog-producer-pixel.dawn.test.d.ts.map +0 -1
  483. package/dist/__tests__/fog-producer-real-fixture.d.ts +0 -5
  484. package/dist/__tests__/fog-producer-real-fixture.d.ts.map +0 -1
  485. package/dist/__tests__/fog-producer-vfx-effect.d.ts +0 -3
  486. package/dist/__tests__/fog-producer-vfx-effect.d.ts.map +0 -1
  487. package/dist/__tests__/fog-scene-asset.integration.test.d.ts +0 -2
  488. package/dist/__tests__/fog-scene-asset.integration.test.d.ts.map +0 -1
  489. package/dist/__tests__/gpu-resource-store-cubemap-status.test.d.ts +0 -2
  490. package/dist/__tests__/gpu-resource-store-cubemap-status.test.d.ts.map +0 -1
  491. package/dist/__tests__/gpu-resource.test.d.ts +0 -2
  492. package/dist/__tests__/gpu-resource.test.d.ts.map +0 -1
  493. package/dist/__tests__/hdrp-bgl-slots.browser.test.d.ts +0 -2
  494. package/dist/__tests__/hdrp-bgl-slots.browser.test.d.ts.map +0 -1
  495. package/dist/__tests__/hdrp-buffers.unit.test.d.ts +0 -2
  496. package/dist/__tests__/hdrp-buffers.unit.test.d.ts.map +0 -1
  497. package/dist/__tests__/hdrp-execute-filter.unit.test.d.ts +0 -2
  498. package/dist/__tests__/hdrp-execute-filter.unit.test.d.ts.map +0 -1
  499. package/dist/__tests__/hdrp-gbuffer-attachments.browser.test.d.ts +0 -2
  500. package/dist/__tests__/hdrp-gbuffer-attachments.browser.test.d.ts.map +0 -1
  501. package/dist/__tests__/hdrp-pipeline-asset-type.test-d.d.ts +0 -2
  502. package/dist/__tests__/hdrp-pipeline-asset-type.test-d.d.ts.map +0 -1
  503. package/dist/__tests__/hdrp-ssao-boundary.test.d.ts +0 -2
  504. package/dist/__tests__/hdrp-ssao-boundary.test.d.ts.map +0 -1
  505. package/dist/__tests__/hdrp-ssao-falsification.test.d.ts +0 -2
  506. package/dist/__tests__/hdrp-ssao-falsification.test.d.ts.map +0 -1
  507. package/dist/__tests__/helpers/primitive-world.d.ts +0 -8
  508. package/dist/__tests__/helpers/primitive-world.d.ts.map +0 -1
  509. package/dist/__tests__/helpers/render-asset-port.d.ts +0 -15
  510. package/dist/__tests__/helpers/render-asset-port.d.ts.map +0 -1
  511. package/dist/__tests__/helpers/scene-asset-port.d.ts +0 -9
  512. package/dist/__tests__/helpers/scene-asset-port.d.ts.map +0 -1
  513. package/dist/__tests__/material-derived-coordinates.integration.test.d.ts +0 -2
  514. package/dist/__tests__/material-derived-coordinates.integration.test.d.ts.map +0 -1
  515. package/dist/__tests__/pipeline-layout-selection.test.d.ts +0 -2
  516. package/dist/__tests__/pipeline-layout-selection.test.d.ts.map +0 -1
  517. package/dist/__tests__/post-process-reads-narrowing.test-d.d.ts +0 -2
  518. package/dist/__tests__/post-process-reads-narrowing.test-d.d.ts.map +0 -1
  519. package/dist/__tests__/post-process-register-roundtrip.dawn.test.d.ts +0 -2
  520. package/dist/__tests__/post-process-register-roundtrip.dawn.test.d.ts.map +0 -1
  521. package/dist/__tests__/render-feature-zero-feature.browser.test.d.ts +0 -2
  522. package/dist/__tests__/render-feature-zero-feature.browser.test.d.ts.map +0 -1
  523. package/dist/__tests__/render-pipeline-trivial.dawn.test.d.ts +0 -2
  524. package/dist/__tests__/render-pipeline-trivial.dawn.test.d.ts.map +0 -1
  525. package/dist/__tests__/shadow-csm-caster-membership.test.d.ts +0 -2
  526. package/dist/__tests__/shadow-csm-caster-membership.test.d.ts.map +0 -1
  527. package/dist/__tests__/shadow-csm-pssm.test.d.ts +0 -2
  528. package/dist/__tests__/shadow-csm-pssm.test.d.ts.map +0 -1
  529. package/dist/__tests__/shadow-csm-temporal.browser.test.d.ts +0 -2
  530. package/dist/__tests__/shadow-csm-temporal.browser.test.d.ts.map +0 -1
  531. package/dist/__tests__/shadow-csm-viewport.test.d.ts +0 -2
  532. package/dist/__tests__/shadow-csm-viewport.test.d.ts.map +0 -1
  533. package/dist/__tests__/shadow-m2.dawn.test.d.ts +0 -2
  534. package/dist/__tests__/shadow-m2.dawn.test.d.ts.map +0 -1
  535. package/dist/__tests__/shadow-m3-calibrate-run.dawn.test.d.ts +0 -2
  536. package/dist/__tests__/shadow-m3-calibrate-run.dawn.test.d.ts.map +0 -1
  537. package/dist/__tests__/shadow-m3-calibrate.d.ts +0 -83
  538. package/dist/__tests__/shadow-m3-calibrate.d.ts.map +0 -1
  539. package/dist/__tests__/shadow-m3.dawn.test.d.ts +0 -2
  540. package/dist/__tests__/shadow-m3.dawn.test.d.ts.map +0 -1
  541. package/dist/__tests__/shadow-probe-control-flow.dawn.test.d.ts +0 -2
  542. package/dist/__tests__/shadow-probe-control-flow.dawn.test.d.ts.map +0 -1
  543. package/dist/__tests__/shadow-quality-metrics.dawn.test.d.ts +0 -2
  544. package/dist/__tests__/shadow-quality-metrics.dawn.test.d.ts.map +0 -1
  545. package/dist/__tests__/temporal-off-path.unit.test.d.ts +0 -2
  546. package/dist/__tests__/temporal-off-path.unit.test.d.ts.map +0 -1
  547. package/dist/__tests__/video-cache-regression.unit.test.d.ts +0 -2
  548. package/dist/__tests__/video-cache-regression.unit.test.d.ts.map +0 -1
  549. package/dist/asset-kind.d.ts +0 -4
  550. package/dist/asset-kind.d.ts.map +0 -1
  551. package/dist/errors/sprite-animation.d.ts +0 -3
  552. package/dist/errors/sprite-animation.d.ts.map +0 -1
  553. package/dist/scene-asset-port.d.ts +0 -17
  554. package/dist/scene-asset-port.d.ts.map +0 -1
  555. package/dist/scene-collect-errors.d.ts +0 -22
  556. package/dist/scene-collect-errors.d.ts.map +0 -1
  557. package/dist/shadow-m3-calibrate.d.ts +0 -40
  558. package/dist/shadow-m3-calibrate.d.ts.map +0 -1
  559. package/src/__tests__/bind-group-cache-binding.test.ts +0 -2513
  560. package/src/__tests__/bind-group-cache-frame.test.ts +0 -1511
  561. package/src/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.ts +0 -204
  562. package/src/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.ts +0 -297
  563. package/src/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.ts +0 -271
  564. package/src/__tests__/dispatch-fullscreen-pass-params.unit.test.ts +0 -321
  565. package/src/__tests__/fog-producer-manifest.ts +0 -162
  566. package/src/__tests__/fog-producer-pixel-probe.ts +0 -263
  567. package/src/__tests__/fog-producer-pixel.browser.test.ts +0 -26
  568. package/src/__tests__/fog-producer-pixel.dawn.test.ts +0 -55
  569. package/src/__tests__/fog-producer-real-fixture.ts +0 -805
  570. package/src/__tests__/fog-producer-vfx-effect.ts +0 -272
  571. package/src/__tests__/fog-scene-asset.integration.test.ts +0 -123
  572. package/src/__tests__/gpu-resource-store-cubemap-status.test.ts +0 -207
  573. package/src/__tests__/gpu-resource.test.ts +0 -1206
  574. package/src/__tests__/hdrp-bgl-slots.browser.test.ts +0 -50
  575. package/src/__tests__/hdrp-buffers.unit.test.ts +0 -70
  576. package/src/__tests__/hdrp-execute-filter.unit.test.ts +0 -200
  577. package/src/__tests__/hdrp-gbuffer-attachments.browser.test.ts +0 -64
  578. package/src/__tests__/hdrp-pipeline-asset-type.test-d.ts +0 -139
  579. package/src/__tests__/hdrp-ssao-boundary.test.ts +0 -237
  580. package/src/__tests__/hdrp-ssao-falsification.test.ts +0 -289
  581. package/src/__tests__/helpers/primitive-world.ts +0 -91
  582. package/src/__tests__/helpers/render-asset-port.ts +0 -65
  583. package/src/__tests__/helpers/scene-asset-port.ts +0 -23
  584. package/src/__tests__/material-derived-coordinates.integration.test.ts +0 -100
  585. package/src/__tests__/pipeline-layout-selection.test.ts +0 -298
  586. package/src/__tests__/post-process-reads-narrowing.test-d.ts +0 -52
  587. package/src/__tests__/post-process-register-roundtrip.dawn.test.ts +0 -230
  588. package/src/__tests__/render-feature-zero-feature.browser.test.ts +0 -152
  589. package/src/__tests__/render-pipeline-trivial.dawn.test.ts +0 -525
  590. package/src/__tests__/shadow-csm-caster-membership.test.ts +0 -232
  591. package/src/__tests__/shadow-csm-pssm.test.ts +0 -142
  592. package/src/__tests__/shadow-csm-temporal.browser.test.ts +0 -145
  593. package/src/__tests__/shadow-csm-viewport.test.ts +0 -74
  594. package/src/__tests__/shadow-m2.dawn.test.ts +0 -394
  595. package/src/__tests__/shadow-m3-calibrate-run.dawn.test.ts +0 -248
  596. package/src/__tests__/shadow-m3-calibrate.ts +0 -203
  597. package/src/__tests__/shadow-m3.dawn.test.ts +0 -288
  598. package/src/__tests__/shadow-probe-control-flow.dawn.test.ts +0 -264
  599. package/src/__tests__/shadow-quality-metrics.dawn.test.ts +0 -324
  600. package/src/__tests__/temporal-off-path.unit.test.ts +0 -69
  601. package/src/__tests__/video-cache-regression.unit.test.ts +0 -186
  602. package/src/asset-kind.ts +0 -7
  603. package/src/errors/sprite-animation.ts +0 -5
  604. package/src/scene-asset-port.ts +0 -32
  605. package/src/scene-collect-errors.ts +0 -30
  606. package/src/shadow-m3-calibrate.ts +0 -171
@@ -0,0 +1,1030 @@
1
+ // M6 w31 (round 5 D-15): column-mint + two-tier resolve integration TDD.
2
+ //
3
+ // D-15 corrected model (human-inputs implement-architecture-correction
4
+ // 2026-06-16T12:35:07Z): AssetRegistry has ZERO handle concept. There is no
5
+ // shared slot space shared with the World. A `handle` is purely an ECS column
6
+ // value -- a numeric indirect reference resolved two-tier purely by slot range:
7
+ // slot < BUILTIN_BASE -> BuiltinAssetRegistry.resolve(handle) (process-static)
8
+ // slot >= BUILTIN_BASE -> world.sharedRefs.resolve(handle) (user-tier RC)
9
+ // resolution is entirely on the ECS/render/extract side, never via AssetRegistry.
10
+ //
11
+ // Column-mint API (Implementer decision): user-tier payloads mint via
12
+ // `world.allocSharedRef(tag, payload)` (already on World). AssetRegistry no
13
+ // longer produces a column-usable handle; its residual job is GUID->payload
14
+ // cataloguing + `loadByGuid`.
15
+ //
16
+ // These cases are RED before w49 (AssetRegistry still carries `register` /
17
+ // by-handle `get`); w49 removes those entries and turns this file green.
18
+ import { readFileSync } from 'node:fs';
19
+ import { fileURLToPath } from 'node:url';
20
+ import {
21
+ AssetRegistry,
22
+ BUILTIN_CUBE,
23
+ BuiltinAssetRegistry,
24
+ HANDLE_CUBE,
25
+ } from '@forgeax/engine-assets-runtime';
26
+ import { World } from '@forgeax/engine-ecs';
27
+ import { AssetGuid } from '@forgeax/engine-pack/guid';
28
+ import type { MeshAsset } from '@forgeax/engine-types';
29
+ import { BUILTIN_BASE } from '@forgeax/engine-types';
30
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
31
+ import { makeMockShaderRegistry } from './helpers/mock-shader-registry';
32
+
33
+ const ASSET_REGISTRY_SRC = readFileSync(
34
+ fileURLToPath(new URL('../../../assets-runtime/src/asset-registry.ts', import.meta.url)),
35
+ 'utf8',
36
+ );
37
+
38
+ function mesh(): MeshAsset {
39
+ return {
40
+ kind: 'mesh',
41
+ vertices: new Float32Array(12 * 3),
42
+ indices: new Uint16Array([0, 1, 2]),
43
+ } as unknown as MeshAsset;
44
+ }
45
+
46
+ describe('D-15 column-mint via world.allocSharedRef (AC-24)', () => {
47
+ it('mints a user-tier slot >= BUILTIN_BASE and resolves to the same payload', () => {
48
+ const world = new World();
49
+ const payload = mesh();
50
+ const handle = world.allocSharedRef<'MeshAsset', MeshAsset>('MeshAsset', payload);
51
+ expect(handle).toBeGreaterThanOrEqual(BUILTIN_BASE);
52
+ const res = world.sharedRefs.resolve<'MeshAsset', MeshAsset>(handle);
53
+ expect(res.ok).toBe(true);
54
+ if (res.ok) expect(res.value).toBe(payload);
55
+ });
56
+
57
+ it('two distinct mints get distinct user-tier slots', () => {
58
+ const world = new World();
59
+ const a = world.allocSharedRef<'MeshAsset', MeshAsset>('MeshAsset', mesh());
60
+ const b = world.allocSharedRef<'MeshAsset', MeshAsset>('MeshAsset', mesh());
61
+ expect(a).not.toBe(b);
62
+ expect(a).toBeGreaterThanOrEqual(BUILTIN_BASE);
63
+ expect(b).toBeGreaterThanOrEqual(BUILTIN_BASE);
64
+ });
65
+ });
66
+
67
+ describe('D-15 builtin handle resolves via BuiltinAssetRegistry (AC-24)', () => {
68
+ it('HANDLE_CUBE (slot < BUILTIN_BASE) resolves through BuiltinAssetRegistry, not the World', () => {
69
+ expect(BuiltinAssetRegistry.resolve(HANDLE_CUBE)).toBe(BUILTIN_CUBE);
70
+ // builtin slot does not live in any World's SharedRefStore
71
+ const world = new World();
72
+ const res = world.sharedRefs.resolve(HANDLE_CUBE);
73
+ expect(res.ok).toBe(false);
74
+ });
75
+ });
76
+
77
+ describe('D-15 AssetRegistry has no handle concept (AC-25, static source assertion)', () => {
78
+ it('exposes no anonymous register(asset) -> Handle column-mint entry', () => {
79
+ // The old `register<T extends Asset>(asset): Result<Handle...>` mint moved
80
+ // to the ECS side (world.allocSharedRef). AssetRegistry must not declare it.
81
+ expect(ASSET_REGISTRY_SRC).not.toMatch(/\n {2}register<T extends Asset>\(asset: T\)/);
82
+ });
83
+
84
+ it('exposes no by-handle get(handle) resolution entry', () => {
85
+ // Payload resolution is two-tier by slot range on the ECS/render side;
86
+ // AssetRegistry no longer offers a by-handle `.get(handle)` lookup.
87
+ expect(ASSET_REGISTRY_SRC).not.toMatch(/\n {2}get<T extends Asset>\(handle:/);
88
+ });
89
+
90
+ it('holds no handle->payload Map (private assets: Map<number, Asset>)', () => {
91
+ expect(ASSET_REGISTRY_SRC).not.toMatch(/private readonly assets: Map<number, Asset>/);
92
+ });
93
+
94
+ it('holds no handle->guid reverse map (handleToGuid)', () => {
95
+ expect(ASSET_REGISTRY_SRC).not.toMatch(/handleToGuid/);
96
+ });
97
+ });
98
+
99
+ // ── M3: invalidate / invalidateAll API + generation TDD helpers ───────────
100
+
101
+ function makeMeshFixture(): MeshAsset {
102
+ return {
103
+ kind: 'mesh',
104
+ vertices: new Float32Array(36),
105
+ indices: new Uint16Array([0, 1, 2]),
106
+ attributes: {},
107
+ materialSlots: [{ slotName: 'Default' }],
108
+ submeshes: [
109
+ {
110
+ indexOffset: 0,
111
+ indexCount: 3,
112
+ vertexCount: 3,
113
+ materialSlot: 0,
114
+ topology: 'triangle-list' as const,
115
+ },
116
+ ],
117
+ } as unknown as MeshAsset;
118
+ }
119
+
120
+ function makeReg(): AssetRegistry {
121
+ return new AssetRegistry(makeMockShaderRegistry());
122
+ }
123
+
124
+ function parseGuid(s: string): AssetGuid {
125
+ const r = AssetGuid.parse(s);
126
+ if (!r.ok) throw new Error(`invalid test GUID: ${s}`);
127
+ return r.value;
128
+ }
129
+
130
+ describe('M3 invalidate(guid) (AC-03) [w6]', () => {
131
+ it('removes the catalogued asset after catalog then invalidate', () => {
132
+ const reg = makeReg();
133
+ const guid = 'a0000000-0000-4000-a000-000000000001';
134
+ const mesh = makeMeshFixture();
135
+ reg.catalog(guid, mesh);
136
+ expect(reg.lookup(guid)).toBeDefined();
137
+
138
+ (reg as unknown as { invalidate: (guid: string) => void }).invalidate(guid);
139
+
140
+ expect(reg.lookup(guid)).toBeUndefined();
141
+ });
142
+
143
+ it('is a no-op for a non-existent GUID', () => {
144
+ const reg = makeReg();
145
+ (reg as unknown as { invalidate: (guid: string) => void }).invalidate(
146
+ 'a0000000-0000-4000-a000-000000000002',
147
+ );
148
+ expect(reg.lookup('a0000000-0000-4000-a000-000000000002')).toBeUndefined();
149
+ });
150
+
151
+ it('clears the targeted body+index entry but leaves bystander entries intact (AC-03)', async () => {
152
+ const originalFetch = globalThis.fetch;
153
+ const reg = makeReg();
154
+ reg.configurePackIndex('/pack-index.json');
155
+
156
+ const targetGuid = 'a0000000-0000-4000-a000-000000000003';
157
+ const bystanderGuid = 'a0000000-0000-4000-a000-000000000004';
158
+ const targetUrl = '/packs/mesh-target.pack.json';
159
+ const bystanderUrl = '/packs/mesh-bystander.pack.json';
160
+ const packIndex = [
161
+ { guid: targetGuid, packageUrl: targetUrl, kind: 'mesh' },
162
+ { guid: bystanderGuid, packageUrl: bystanderUrl, kind: 'mesh' },
163
+ ];
164
+
165
+ function makePackFile(g: string): unknown {
166
+ return {
167
+ schemaVersion: '2.0.0',
168
+ kind: 'internal-text-package',
169
+ assets: [
170
+ {
171
+ guid: g,
172
+ kind: 'mesh',
173
+ payload: {
174
+ vertices: [
175
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
176
+ 0, 0, 0, 0, 0, 0, 0, 0,
177
+ ],
178
+ indices: [0, 1, 2],
179
+ attributes: {},
180
+ submeshes: [
181
+ { indexOffset: 0, indexCount: 3, vertexCount: 3, topology: 'triangle-list' },
182
+ ],
183
+ },
184
+ },
185
+ ],
186
+ };
187
+ }
188
+
189
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
190
+ if (url === '/pack-index.json') {
191
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
192
+ }
193
+ if (url === targetUrl) {
194
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(makePackFile(targetGuid)) });
195
+ }
196
+ if (url === bystanderUrl) {
197
+ return Promise.resolve({
198
+ ok: true,
199
+ json: () => Promise.resolve(makePackFile(bystanderGuid)),
200
+ });
201
+ }
202
+ return Promise.resolve({ ok: false, status: 404 });
203
+ });
204
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
205
+
206
+ const internal = reg as unknown as {
207
+ packFileCache: Map<string, unknown>;
208
+ packIndexCache: Map<string, unknown> | undefined;
209
+ invalidate: (guid: string) => void;
210
+ };
211
+
212
+ try {
213
+ // Prod-load both GUIDs so packIndexCache holds both entries and
214
+ // packFileCache holds both bodies (keyed by packageUrl).
215
+ const rt = await reg.loadByGuid<MeshAsset>(parseGuid(targetGuid));
216
+ const rb = await reg.loadByGuid<MeshAsset>(parseGuid(bystanderGuid));
217
+ expect(rt.ok).toBe(true);
218
+ expect(rb.ok).toBe(true);
219
+ expect(internal.packFileCache.has(targetUrl)).toBe(true);
220
+ expect(internal.packFileCache.has(bystanderUrl)).toBe(true);
221
+ expect(internal.packIndexCache?.get(targetGuid)).toBeDefined();
222
+ expect(internal.packIndexCache?.get(bystanderGuid)).toBeDefined();
223
+
224
+ internal.invalidate(targetGuid);
225
+
226
+ // Targeted clear: target body + index entry gone.
227
+ expect(internal.packFileCache.has(targetUrl)).toBe(false);
228
+ expect(internal.packIndexCache?.get(targetGuid)).toBeUndefined();
229
+
230
+ // Bystander survives: single-GUID invalidate must not evict unrelated
231
+ // cached bodies/index entries, and keeps the index Map alive (only
232
+ // invalidateAll nukes it to undefined).
233
+ expect(internal.packFileCache.has(bystanderUrl)).toBe(true);
234
+ expect(internal.packIndexCache?.get(bystanderGuid)).toBeDefined();
235
+ expect(internal.packIndexCache).not.toBeUndefined();
236
+
237
+ // Catalog entry removed + generation bumped (kept from round-1).
238
+ expect(reg.lookup(targetGuid)).toBeUndefined();
239
+ } finally {
240
+ if (originalFetch !== undefined) {
241
+ globalThis.fetch = originalFetch;
242
+ } else {
243
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
244
+ delete (globalThis as any).fetch;
245
+ }
246
+ }
247
+ });
248
+ });
249
+
250
+ describe('M3 invalidateAll() (AC-05 + AC-06) [w7]', () => {
251
+ it('clears all catalogued assets and returns clearedCount', () => {
252
+ const reg = makeReg();
253
+ const countBefore = reg as unknown as { assetCatalog: Map<string, unknown> };
254
+ const initialSize = countBefore.assetCatalog.size;
255
+ reg.catalog('a0000000-0000-4000-a000-000000000001', makeMeshFixture());
256
+ reg.catalog('a0000000-0000-4000-a000-000000000002', makeMeshFixture());
257
+ reg.catalog('a0000000-0000-4000-a000-000000000003', makeMeshFixture());
258
+
259
+ const result = (
260
+ reg as unknown as { invalidateAll: () => { clearedCount: number } }
261
+ ).invalidateAll();
262
+
263
+ // clearedCount includes builtins (constructor pre-populates 5 GUIDs).
264
+ expect(result.clearedCount).toBe(initialSize + 3);
265
+ expect(reg.lookup('a0000000-0000-4000-a000-000000000001')).toBeUndefined();
266
+ expect(reg.lookup('a0000000-0000-4000-a000-000000000002')).toBeUndefined();
267
+ expect(reg.lookup('a0000000-0000-4000-a000-000000000003')).toBeUndefined();
268
+ });
269
+
270
+ it('is idempotent: second call returns clearedCount 0', () => {
271
+ const reg = makeReg();
272
+ reg.catalog('a0000000-0000-4000-a000-000000000001', makeMeshFixture());
273
+
274
+ const internal = reg as unknown as {
275
+ invalidateAll: () => { clearedCount: number };
276
+ packIndexCache: Map<string, unknown> | undefined;
277
+ };
278
+
279
+ const first = internal.invalidateAll();
280
+ expect(first.clearedCount).toBeGreaterThan(0);
281
+
282
+ const second = internal.invalidateAll();
283
+ expect(second.clearedCount).toBe(0);
284
+ // No-op clear of an already-undefined index cache must not re-create a Map.
285
+ expect(internal.packIndexCache).toBeUndefined();
286
+ });
287
+
288
+ it('clears packFileCache and resets packIndexCache to undefined (AC-05, R2-1)', async () => {
289
+ const originalFetch = globalThis.fetch;
290
+ const reg = makeReg();
291
+ reg.configurePackIndex('/pack-index.json');
292
+
293
+ const guid = 'a0000000-0000-4000-a000-000000000040';
294
+ const packIndex = [{ guid, packageUrl: '/packs/mesh-all.pack.json', kind: 'mesh' }];
295
+ const packFile = {
296
+ schemaVersion: '2.0.0',
297
+ kind: 'internal-text-package',
298
+ assets: [
299
+ {
300
+ guid,
301
+ kind: 'mesh',
302
+ payload: {
303
+ vertices: [
304
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
305
+ 0, 0, 0, 0, 0, 0, 0,
306
+ ],
307
+ indices: [0, 1, 2],
308
+ attributes: {},
309
+ submeshes: [
310
+ { indexOffset: 0, indexCount: 3, vertexCount: 3, topology: 'triangle-list' },
311
+ ],
312
+ },
313
+ },
314
+ ],
315
+ };
316
+
317
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
318
+ if (url === '/pack-index.json') {
319
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
320
+ }
321
+ if (url === '/packs/mesh-all.pack.json') {
322
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packFile) });
323
+ }
324
+ return Promise.resolve({ ok: false, status: 404 });
325
+ });
326
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
327
+
328
+ const internal = reg as unknown as {
329
+ packFileCache: Map<string, unknown>;
330
+ packIndexCache: Map<string, unknown> | undefined;
331
+ invalidateAll: () => { clearedCount: number };
332
+ };
333
+
334
+ try {
335
+ // Prod load populates both shared caches.
336
+ const r = await reg.loadByGuid<MeshAsset>(parseGuid(guid));
337
+ expect(r.ok).toBe(true);
338
+ expect(internal.packFileCache.size).toBeGreaterThan(0);
339
+ expect(internal.packIndexCache).not.toBeUndefined();
340
+
341
+ internal.invalidateAll();
342
+
343
+ // Body cache fully cleared.
344
+ expect(internal.packFileCache.size).toBe(0);
345
+ // Index cache reset to undefined -- NOT an empty Map. An empty Map would
346
+ // short-circuit resolveCatalogEntry's `=== undefined` re-fetch guard
347
+ // (asset-registry.ts:2878) and reproduce the F17b pollution.
348
+ expect(internal.packIndexCache).toBeUndefined();
349
+ } finally {
350
+ if (originalFetch !== undefined) {
351
+ globalThis.fetch = originalFetch;
352
+ } else {
353
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
354
+ delete (globalThis as any).fetch;
355
+ }
356
+ }
357
+ });
358
+ });
359
+
360
+ describe('M3 generation drop: invalidate(guid) drops in-flight (AC-11) [w8]', () => {
361
+ let originalFetch: typeof globalThis.fetch | undefined;
362
+
363
+ beforeEach(() => {
364
+ originalFetch = globalThis.fetch;
365
+ });
366
+
367
+ afterEach(() => {
368
+ if (originalFetch !== undefined) {
369
+ globalThis.fetch = originalFetch;
370
+ } else {
371
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
372
+ delete (globalThis as any).fetch;
373
+ }
374
+ });
375
+
376
+ it('returns asset-invalidated when invalidate is called during loadByGuid', async () => {
377
+ const reg = makeReg();
378
+ reg.configurePackIndex('/pack-index.json');
379
+
380
+ const guid = 'a0000000-0000-4000-a000-000000000010';
381
+ const packIndex = [{ guid, packageUrl: '/packs/test-mesh.pack.json', kind: 'mesh' }];
382
+ const packFile = {
383
+ schemaVersion: '2.0.0',
384
+ kind: 'internal-text-package',
385
+ assets: [
386
+ {
387
+ guid,
388
+ kind: 'mesh',
389
+ payload: {
390
+ vertices: [
391
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
392
+ 0, 0, 0, 0, 0, 0, 0,
393
+ ],
394
+ indices: [0, 1, 2],
395
+ attributes: {},
396
+ submeshes: [
397
+ { indexOffset: 0, indexCount: 3, vertexCount: 3, topology: 'triangle-list' },
398
+ ],
399
+ },
400
+ },
401
+ ],
402
+ };
403
+
404
+ // Block the pack-file fetch so we can invalidate before it resolves.
405
+ let resolvePackFile!: (value: unknown) => void;
406
+ const packFilePromise = new Promise<unknown>((resolve) => {
407
+ resolvePackFile = resolve;
408
+ });
409
+
410
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
411
+ if (url === '/pack-index.json') {
412
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
413
+ }
414
+ if (url === '/packs/test-mesh.pack.json') {
415
+ return packFilePromise.then((v: unknown) => ({ ok: true, json: () => Promise.resolve(v) }));
416
+ }
417
+ return Promise.resolve({ ok: false, status: 404 });
418
+ });
419
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
420
+
421
+ try {
422
+ const loadPromise = reg.loadByGuid<MeshAsset>(parseGuid(guid));
423
+
424
+ // Invalidate while pack-file fetch is still blocked.
425
+ (reg as unknown as { invalidate: (g: string) => void }).invalidate(guid);
426
+
427
+ // Now release the pack-file fetch.
428
+ resolvePackFile(packFile);
429
+
430
+ const result = await loadPromise;
431
+ expect(result.ok).toBe(false);
432
+ if (!result.ok) {
433
+ expect(result.error.code).toBe('asset-invalidated');
434
+ }
435
+ // Catalog must NOT contain the asset (result was not written).
436
+ expect(reg.lookup(guid)).toBeUndefined();
437
+ } finally {
438
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
439
+ delete (globalThis as any).fetch;
440
+ }
441
+ });
442
+ });
443
+
444
+ describe('M3 generation drop: invalidateAll drops all in-flight (AC-12) [w9]', () => {
445
+ let originalFetch: typeof globalThis.fetch | undefined;
446
+
447
+ beforeEach(() => {
448
+ originalFetch = globalThis.fetch;
449
+ });
450
+
451
+ afterEach(() => {
452
+ if (originalFetch !== undefined) {
453
+ globalThis.fetch = originalFetch;
454
+ } else {
455
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
456
+ delete (globalThis as any).fetch;
457
+ }
458
+ });
459
+
460
+ it('returns asset-invalidated for all in-flight loads after invalidateAll', async () => {
461
+ const reg = makeReg();
462
+ reg.configurePackIndex('/pack-index.json');
463
+
464
+ const guidA = 'a0000000-0000-4000-a000-000000000010';
465
+ const guidB = 'a0000000-0000-4000-a000-000000000011';
466
+ const guidC = 'a0000000-0000-4000-a000-000000000012';
467
+
468
+ const packIndex = [
469
+ { guid: guidA, packageUrl: '/packs/mesh-a.pack.json', kind: 'mesh' },
470
+ { guid: guidB, packageUrl: '/packs/mesh-b.pack.json', kind: 'mesh' },
471
+ { guid: guidC, packageUrl: '/packs/mesh-c.pack.json', kind: 'mesh' },
472
+ ];
473
+
474
+ function makePackFile(g: string): unknown {
475
+ return {
476
+ schemaVersion: '2.0.0',
477
+ kind: 'internal-text-package',
478
+ assets: [
479
+ {
480
+ guid: g,
481
+ kind: 'mesh',
482
+ payload: {
483
+ vertices: [
484
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
485
+ 0, 0, 0, 0, 0, 0, 0, 0,
486
+ ],
487
+ indices: [0, 1, 2],
488
+ attributes: {},
489
+ submeshes: [
490
+ { indexOffset: 0, indexCount: 3, vertexCount: 3, topology: 'triangle-list' },
491
+ ],
492
+ },
493
+ },
494
+ ],
495
+ };
496
+ }
497
+
498
+ const resolvers: Array<(value: unknown) => void> = [];
499
+ const packFilePromises = [
500
+ '/packs/mesh-a.pack.json',
501
+ '/packs/mesh-b.pack.json',
502
+ '/packs/mesh-c.pack.json',
503
+ ].map(() => {
504
+ return new Promise<unknown>((resolve) => {
505
+ resolvers.push(resolve);
506
+ });
507
+ });
508
+
509
+ let resolverIdx = 0;
510
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
511
+ if (url === '/pack-index.json') {
512
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
513
+ }
514
+ if (url.startsWith('/packs/mesh-')) {
515
+ const p = packFilePromises[resolverIdx++];
516
+ if (p === undefined) throw new Error(`unexpected pack URL: ${url}`);
517
+ return p.then((v: unknown) => ({ ok: true, json: () => Promise.resolve(v) }));
518
+ }
519
+ return Promise.resolve({ ok: false, status: 404 });
520
+ });
521
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
522
+
523
+ try {
524
+ const loadA = reg.loadByGuid<MeshAsset>(parseGuid(guidA));
525
+ const loadB = reg.loadByGuid<MeshAsset>(parseGuid(guidB));
526
+ const loadC = reg.loadByGuid<MeshAsset>(parseGuid(guidC));
527
+
528
+ // All three are in-flight now. Invalidate all.
529
+ (reg as unknown as { invalidateAll: () => { clearedCount: number } }).invalidateAll();
530
+
531
+ // Now release all pack-file fetches.
532
+ resolvers[0]?.(makePackFile(guidA));
533
+ resolvers[1]?.(makePackFile(guidB));
534
+ resolvers[2]?.(makePackFile(guidC));
535
+
536
+ const results = await Promise.all([loadA, loadB, loadC]);
537
+ for (const r of results) {
538
+ expect(r.ok).toBe(false);
539
+ if (!r.ok) {
540
+ expect(r.error.code).toBe('asset-invalidated');
541
+ }
542
+ }
543
+
544
+ // Catalog must be empty.
545
+ expect(reg.lookup(guidA)).toBeUndefined();
546
+ expect(reg.lookup(guidB)).toBeUndefined();
547
+ expect(reg.lookup(guidC)).toBeUndefined();
548
+ } finally {
549
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
550
+ delete (globalThis as any).fetch;
551
+ }
552
+ });
553
+ });
554
+
555
+ describe('M3 integration: invalidate reload + generation match (AC-04 + AC-13) [w12]', () => {
556
+ let originalFetch: typeof globalThis.fetch | undefined;
557
+
558
+ beforeEach(() => {
559
+ originalFetch = globalThis.fetch;
560
+ });
561
+
562
+ afterEach(() => {
563
+ if (originalFetch !== undefined) {
564
+ globalThis.fetch = originalFetch;
565
+ } else {
566
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
567
+ delete (globalThis as any).fetch;
568
+ }
569
+ });
570
+
571
+ it('AC-04: invalidate(guid) then loadByGuid re-fetches fresh bytes (not stale cache)', async () => {
572
+ const reg = makeReg();
573
+ reg.configurePackIndex('/pack-index.json');
574
+
575
+ const guid = 'a0000000-0000-4000-a000-000000000020';
576
+ const packUrl = '/packs/mesh-reload.pack.json';
577
+ const packIndex = [{ guid, packageUrl: packUrl, kind: 'mesh' }];
578
+
579
+ // The service changes its response body between the two loads: the first
580
+ // pack-file request serves body-v1 (vertices[0] === 0), every subsequent
581
+ // request serves body-v2 (vertices[0] === 7). A genuine re-fetch after
582
+ // invalidate must observe body-v2; a stale-cache hit would still see v1.
583
+ function makePackBody(firstX: number): unknown {
584
+ return {
585
+ schemaVersion: '2.0.0',
586
+ kind: 'internal-text-package',
587
+ assets: [
588
+ {
589
+ guid,
590
+ kind: 'mesh',
591
+ payload: {
592
+ vertices: [
593
+ firstX,
594
+ 0,
595
+ 0,
596
+ 0,
597
+ 0,
598
+ 0,
599
+ 0,
600
+ 0,
601
+ 0,
602
+ 0,
603
+ 0,
604
+ 0,
605
+ 1,
606
+ 0,
607
+ 0,
608
+ 0,
609
+ 0,
610
+ 0,
611
+ 0,
612
+ 0,
613
+ 0,
614
+ 0,
615
+ 0,
616
+ 0,
617
+ 0,
618
+ 1,
619
+ 0,
620
+ 0,
621
+ 0,
622
+ 0,
623
+ 0,
624
+ 0,
625
+ 0,
626
+ 0,
627
+ 0,
628
+ 0,
629
+ ],
630
+ indices: [0, 1, 2],
631
+ attributes: {},
632
+ submeshes: [
633
+ { indexOffset: 0, indexCount: 3, vertexCount: 3, topology: 'triangle-list' },
634
+ ],
635
+ },
636
+ },
637
+ ],
638
+ };
639
+ }
640
+ const BODY_V1_X = 0;
641
+ const BODY_V2_X = 7;
642
+
643
+ let packFetches = 0;
644
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
645
+ if (url === '/pack-index.json') {
646
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
647
+ }
648
+ if (url === packUrl) {
649
+ packFetches += 1;
650
+ const body = packFetches === 1 ? makePackBody(BODY_V1_X) : makePackBody(BODY_V2_X);
651
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(body) });
652
+ }
653
+ return Promise.resolve({ ok: false, status: 404 });
654
+ });
655
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
656
+
657
+ try {
658
+ // First load: fetches body-v1, succeeds, writes to catalog.
659
+ const r1 = await reg.loadByGuid<MeshAsset>(parseGuid(guid));
660
+ expect(r1.ok).toBe(true);
661
+ expect(reg.lookup(guid)).toBeDefined();
662
+ expect(packFetches).toBe(1);
663
+
664
+ // Invalidate the catalogued asset.
665
+ (reg as unknown as { invalidate: (g: string) => void }).invalidate(guid);
666
+ expect(reg.lookup(guid)).toBeUndefined();
667
+
668
+ // Second load: must re-fetch the pack-file body (not serve packFileCache).
669
+ const r2 = await reg.loadByGuid<MeshAsset>(parseGuid(guid));
670
+ expect(r2.ok).toBe(true);
671
+ expect(reg.lookup(guid)).toBeDefined();
672
+
673
+ // (a) the reload re-fetched the body -> packFetches incremented to 2.
674
+ expect(packFetches).toBe(2);
675
+ // (b) the reloaded payload is the FRESH body-v2 (vertices[0] === 7),
676
+ // proving the stale cached body-v1 was NOT served.
677
+ if (r2.ok) {
678
+ expect(r2.value.vertices[0]).toBe(BODY_V2_X);
679
+ }
680
+ } finally {
681
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
682
+ delete (globalThis as any).fetch;
683
+ }
684
+ });
685
+
686
+ it('AC-13: invalidate then immediate reload -- generation matches, payload catalogued', async () => {
687
+ const reg = makeReg();
688
+ reg.configurePackIndex('/pack-index.json');
689
+
690
+ const guid = 'a0000000-0000-4000-a000-000000000021';
691
+ const packIndex = [{ guid, packageUrl: '/packs/mesh-genmatch.pack.json', kind: 'mesh' }];
692
+ const packFile = {
693
+ schemaVersion: '2.0.0',
694
+ kind: 'internal-text-package',
695
+ assets: [
696
+ {
697
+ guid,
698
+ kind: 'mesh',
699
+ payload: {
700
+ vertices: [
701
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
702
+ 0, 0, 0, 0, 0, 0, 0,
703
+ ],
704
+ indices: [0, 1, 2],
705
+ attributes: {},
706
+ submeshes: [
707
+ { indexOffset: 0, indexCount: 3, vertexCount: 3, topology: 'triangle-list' },
708
+ ],
709
+ },
710
+ },
711
+ ],
712
+ };
713
+
714
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
715
+ if (url === '/pack-index.json') {
716
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
717
+ }
718
+ if (url === '/packs/mesh-genmatch.pack.json') {
719
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packFile) });
720
+ }
721
+ return Promise.resolve({ ok: false, status: 404 });
722
+ });
723
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
724
+
725
+ try {
726
+ // Load, invalidate, reload immediately -- the new load picks up the
727
+ // updated generation and completes normally.
728
+ const r1 = await reg.loadByGuid<MeshAsset>(parseGuid(guid));
729
+ expect(r1.ok).toBe(true);
730
+
731
+ (reg as unknown as { invalidate: (g: string) => void }).invalidate(guid);
732
+
733
+ // Immediate reload after invalidate: new generation, catalog re-populated.
734
+ const r2 = await reg.loadByGuid<MeshAsset>(parseGuid(guid));
735
+ expect(r2.ok).toBe(true);
736
+ expect(reg.lookup(guid)).toBeDefined();
737
+ } finally {
738
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
739
+ delete (globalThis as any).fetch;
740
+ }
741
+ });
742
+ });
743
+
744
+ describe('M3 integration: generation discard error shape (AC-11 + AC-12) [w13]', () => {
745
+ let originalFetch: typeof globalThis.fetch | undefined;
746
+
747
+ beforeEach(() => {
748
+ originalFetch = globalThis.fetch;
749
+ });
750
+
751
+ afterEach(() => {
752
+ if (originalFetch !== undefined) {
753
+ globalThis.fetch = originalFetch;
754
+ } else {
755
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
756
+ delete (globalThis as any).fetch;
757
+ }
758
+ });
759
+
760
+ it('invalidate(guid) during load: error has code, hint, and expected with GUID', async () => {
761
+ const reg = makeReg();
762
+ reg.configurePackIndex('/pack-index.json');
763
+
764
+ const guid = 'a0000000-0000-4000-a000-000000000030';
765
+ const packIndex = [{ guid, packageUrl: '/packs/err-shape.pack.json', kind: 'mesh' }];
766
+
767
+ let resolvePackFile!: (value: unknown) => void;
768
+ const packFilePromise = new Promise<unknown>((resolve) => {
769
+ resolvePackFile = resolve;
770
+ });
771
+
772
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
773
+ if (url === '/pack-index.json') {
774
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
775
+ }
776
+ if (url === '/packs/err-shape.pack.json') {
777
+ return packFilePromise.then((v: unknown) => ({ ok: true, json: () => Promise.resolve(v) }));
778
+ }
779
+ return Promise.resolve({ ok: false, status: 404 });
780
+ });
781
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
782
+
783
+ try {
784
+ const loadPromise = reg.loadByGuid<MeshAsset>(parseGuid(guid));
785
+ (reg as unknown as { invalidate: (g: string) => void }).invalidate(guid);
786
+
787
+ resolvePackFile({
788
+ schemaVersion: '2.0.0',
789
+ kind: 'internal-text-package',
790
+ assets: [
791
+ {
792
+ guid,
793
+ kind: 'mesh',
794
+ payload: {
795
+ vertices: [
796
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
797
+ 0, 0, 0, 0, 0, 0, 0, 0,
798
+ ],
799
+ indices: [0, 1, 2],
800
+ attributes: {},
801
+ submeshes: [
802
+ { indexOffset: 0, indexCount: 3, vertexCount: 3, topology: 'triangle-list' },
803
+ ],
804
+ },
805
+ },
806
+ ],
807
+ });
808
+
809
+ const result = await loadPromise;
810
+ expect(result.ok).toBe(false);
811
+ if (!result.ok) {
812
+ expect(result.error.code).toBe('asset-invalidated');
813
+ expect(result.error.hint).toBeTruthy();
814
+ expect(result.error.hint).toContain('invalidate');
815
+ expect(result.error.expected).toContain(guid.toLowerCase());
816
+ }
817
+ } finally {
818
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
819
+ delete (globalThis as any).fetch;
820
+ }
821
+ });
822
+
823
+ it('invalidateAll during load: error has code, hint, and expected', async () => {
824
+ const reg = makeReg();
825
+ reg.configurePackIndex('/pack-index.json');
826
+
827
+ const guid = 'a0000000-0000-4000-a000-000000000031';
828
+ const packIndex = [{ guid, packageUrl: '/packs/err-all.pack.json', kind: 'mesh' }];
829
+
830
+ let resolvePackFile!: (value: unknown) => void;
831
+ const packFilePromise = new Promise<unknown>((resolve) => {
832
+ resolvePackFile = resolve;
833
+ });
834
+
835
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
836
+ if (url === '/pack-index.json') {
837
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
838
+ }
839
+ if (url === '/packs/err-all.pack.json') {
840
+ return packFilePromise.then((v: unknown) => ({ ok: true, json: () => Promise.resolve(v) }));
841
+ }
842
+ return Promise.resolve({ ok: false, status: 404 });
843
+ });
844
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
845
+
846
+ try {
847
+ const loadPromise = reg.loadByGuid<MeshAsset>(parseGuid(guid));
848
+ (reg as unknown as { invalidateAll: () => { clearedCount: number } }).invalidateAll();
849
+
850
+ resolvePackFile({
851
+ schemaVersion: '2.0.0',
852
+ kind: 'internal-text-package',
853
+ assets: [
854
+ {
855
+ guid,
856
+ kind: 'mesh',
857
+ payload: {
858
+ vertices: [
859
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
860
+ 0, 0, 0, 0, 0, 0, 0, 0,
861
+ ],
862
+ indices: [0, 1, 2],
863
+ attributes: {},
864
+ submeshes: [
865
+ { indexOffset: 0, indexCount: 3, vertexCount: 3, topology: 'triangle-list' },
866
+ ],
867
+ },
868
+ },
869
+ ],
870
+ });
871
+
872
+ const result = await loadPromise;
873
+ expect(result.ok).toBe(false);
874
+ if (!result.ok) {
875
+ expect(result.error.code).toBe('asset-invalidated');
876
+ expect(result.error.hint).toBeTruthy();
877
+ expect(result.error.hint).toContain('invalidate');
878
+ expect(result.error.expected).toBeTruthy();
879
+ }
880
+ } finally {
881
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
882
+ delete (globalThis as any).fetch;
883
+ }
884
+ });
885
+ });
886
+
887
+ describe('AC-05 InspectEntry.kind (brand removed)', () => {
888
+ it('inspect() returns entries with .kind (not .brand)', () => {
889
+ const reg = new AssetRegistry(makeMockShaderRegistry());
890
+ const guid = AssetGuid.format(AssetGuid.random());
891
+ reg.catalog(guid, {
892
+ kind: 'sampler' as const,
893
+ magFilter: 'linear' as const,
894
+ minFilter: 'linear' as const,
895
+ });
896
+ const snap = reg.inspect();
897
+ const entry = snap.assets.find((e) => e.guid === guid.toLowerCase());
898
+ expect(entry).toBeDefined();
899
+ expect(entry?.kind).toBe('sampler');
900
+ expect(entry?.name).toBe('');
901
+ expect(entry).toHaveProperty('kind');
902
+ expect(entry).not.toHaveProperty('brand');
903
+ });
904
+
905
+ it('inspect().assets[].kind mirrors payload.kind', () => {
906
+ const reg = new AssetRegistry(makeMockShaderRegistry());
907
+ const payload = {
908
+ kind: 'sampler' as const,
909
+ magFilter: 'linear' as const,
910
+ minFilter: 'linear' as const,
911
+ };
912
+ const guid = AssetGuid.format(AssetGuid.random());
913
+ reg.catalog(guid, payload);
914
+ const snap = reg.inspect();
915
+ const entry = snap.assets.find((e) => e.guid === guid.toLowerCase());
916
+ expect(entry, 'inspect entry for sampler').toBeDefined();
917
+ expect(entry?.kind).toBe('sampler');
918
+ });
919
+ });
920
+
921
+ describe('AC-06 parseAssetPayload passthrough + dev/prod consistency', () => {
922
+ let originalFetch: typeof globalThis.fetch | undefined;
923
+
924
+ beforeEach(() => {
925
+ originalFetch = globalThis.fetch;
926
+ });
927
+
928
+ afterEach(() => {
929
+ if (originalFetch !== undefined) {
930
+ globalThis.fetch = originalFetch;
931
+ } else {
932
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
933
+ delete (globalThis as any).fetch;
934
+ }
935
+ });
936
+
937
+ it('engine-known kind (mesh) parses correctly via prod path', async () => {
938
+ const reg = makeReg();
939
+ reg.configurePackIndex('/pack-index.json');
940
+
941
+ const guid = 'b0000000-0000-4000-a000-000000000010';
942
+ const packIndex = [{ guid, packageUrl: '/packs/ac06-mesh.pack.json', kind: 'mesh' }];
943
+
944
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
945
+ if (url === '/pack-index.json') {
946
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
947
+ }
948
+ if (url === '/packs/ac06-mesh.pack.json') {
949
+ return Promise.resolve({
950
+ ok: true,
951
+ json: () =>
952
+ Promise.resolve({
953
+ schemaVersion: '2.0.0',
954
+ kind: 'internal-text-package',
955
+ assets: [
956
+ {
957
+ guid,
958
+ kind: 'mesh',
959
+ payload: {
960
+ vertices: [
961
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
962
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
963
+ ],
964
+ indices: [0, 1, 2],
965
+ attributes: {},
966
+ submeshes: [
967
+ { indexOffset: 0, indexCount: 3, vertexCount: 3, topology: 'triangle-list' },
968
+ ],
969
+ },
970
+ },
971
+ ],
972
+ }),
973
+ });
974
+ }
975
+ return Promise.resolve({ ok: false, status: 404 });
976
+ });
977
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
978
+
979
+ const result = await reg.loadByGuid<MeshAsset>(parseGuid(guid));
980
+ expect(result.ok).toBe(true);
981
+ if (!result.ok) return;
982
+ expect(result.value.kind).toBe('mesh');
983
+ });
984
+
985
+ it('unmatched kind payload survives passthrough via prod loadByGuid', async () => {
986
+ const reg = makeReg();
987
+ reg.configurePackIndex('/pack-index.json');
988
+
989
+ const guid = 'b0000000-0000-4000-a000-000000000011';
990
+ const customPayload = { fieldA: 42, fieldB: 'hello' };
991
+ const packIndex = [{ guid, packageUrl: '/packs/ac06-unknown.pack.json', kind: 'host-custom' }];
992
+
993
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
994
+ if (url === '/pack-index.json') {
995
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
996
+ }
997
+ if (url === '/packs/ac06-unknown.pack.json') {
998
+ return Promise.resolve({
999
+ ok: true,
1000
+ json: () =>
1001
+ Promise.resolve({
1002
+ schemaVersion: '2.0.0',
1003
+ kind: 'internal-text-package',
1004
+ assets: [{ guid, kind: 'host-custom', payload: customPayload }],
1005
+ }),
1006
+ });
1007
+ }
1008
+ return Promise.resolve({ ok: false, status: 404 });
1009
+ });
1010
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
1011
+
1012
+ const result = await reg.loadByGuid(parseGuid(guid));
1013
+ expect(result.ok).toBe(false);
1014
+ });
1015
+
1016
+ it('dev-path catalog stores payload with kind faithfully', () => {
1017
+ const reg = makeReg();
1018
+ const guid = AssetGuid.format(AssetGuid.random());
1019
+ const payload = {
1020
+ kind: 'sampler' as const,
1021
+ magFilter: 'linear' as const,
1022
+ minFilter: 'linear' as const,
1023
+ };
1024
+ reg.catalog(guid, payload);
1025
+
1026
+ const stored = reg.lookup(guid);
1027
+ expect(stored).toBeDefined();
1028
+ expect(stored?.kind).toBe('sampler');
1029
+ });
1030
+ });