@forgeax/engine-runtime 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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,969 @@
1
+ // asset-registry.pack-cache.spec — M3/Fix B in-memory pack-file cache + in-flight
2
+ // dedup (TDD red phase for AC-02 / AC-06). The test file compiles and the
3
+ // "red" stage is intentional (type=test task) because fetchPackFile currently
4
+ // has no cache.
5
+ //
6
+ // Coverage:
7
+ // AC-02-sequential — pack.json fetched once per URL for sequential loads
8
+ // AC-02-concurrent — pack.json fetched once per URL for concurrent loads
9
+ // AC-02-reject — fetch reject clears in-flight, retry re-fetches
10
+
11
+ import { AssetRegistry } from '@forgeax/engine-assets-runtime';
12
+ import { AssetGuid } from '@forgeax/engine-pack/guid';
13
+ import {
14
+ authoringCapabilityForAssetKind,
15
+ type PackIndexEntry,
16
+ type MeshAsset as TypesMeshAsset,
17
+ } from '@forgeax/engine-types';
18
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
19
+ import { makeMockShaderRegistry } from './helpers/mock-shader-registry';
20
+
21
+ // ── test GUIDs ──────────────────────────────────────────────────────────────
22
+ const MESH_A_GUID = 'f0000000-0000-4000-f000-000000000001';
23
+ const MESH_B_GUID = 'f0000000-0000-4000-f000-000000000002';
24
+ const SHARED_PACK_URL = '/packs/shared-mesh.pack.json';
25
+
26
+ function parseGuid(s: string): AssetGuid {
27
+ const r = AssetGuid.parse(s);
28
+ if (!r.ok) throw new Error(`invalid test GUID: ${s}`);
29
+ return r.value;
30
+ }
31
+
32
+ // ── registry setup ──────────────────────────────────────────────────────────
33
+
34
+ function makeRegistry(): AssetRegistry {
35
+ return new AssetRegistry(makeMockShaderRegistry());
36
+ }
37
+
38
+ // ── pack fixture: two meshes sharing the same .pack.json ────────────────────
39
+
40
+ function makePackIndex(): Array<{ guid: string; packageUrl: string; kind: string }> {
41
+ return [
42
+ { guid: MESH_A_GUID, packageUrl: SHARED_PACK_URL, kind: 'mesh' },
43
+ { guid: MESH_B_GUID, packageUrl: SHARED_PACK_URL, kind: 'mesh' },
44
+ ];
45
+ }
46
+
47
+ function makeSharedPack(): unknown {
48
+ return {
49
+ schemaVersion: '2.0.0',
50
+ kind: 'internal-text-package',
51
+ assets: [
52
+ {
53
+ guid: MESH_A_GUID,
54
+ kind: 'mesh',
55
+ payload: {
56
+ vertices: [
57
+ -0.5, 0, 0.5, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0.5, 0, 0.5, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0.5, 0,
58
+ -0.5, 0, 1, 0, 1, 1, 1, 0, 0, 1,
59
+ ],
60
+ indices: [0, 1, 2],
61
+ attributes: {},
62
+ submeshes: [{ indexOffset: 0, indexCount: 3, vertexCount: 3, topology: 'triangle-list' }],
63
+ },
64
+ },
65
+ {
66
+ guid: MESH_B_GUID,
67
+ kind: 'mesh',
68
+ payload: {
69
+ vertices: [
70
+ 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0,
71
+ 0, 0, 1, 1, 1, 0, 0,
72
+ ],
73
+ indices: [1, 0, 2],
74
+ attributes: {},
75
+ submeshes: [{ indexOffset: 0, indexCount: 3, vertexCount: 3, topology: 'triangle-list' }],
76
+ },
77
+ },
78
+ ],
79
+ };
80
+ }
81
+
82
+ // ── AC-02 / AC-06: pack-file dedup ──────────────────────────────────────────
83
+
84
+ describe('pack-file cache', () => {
85
+ let originalFetch: typeof globalThis.fetch | undefined;
86
+
87
+ beforeEach(() => {
88
+ originalFetch = globalThis.fetch;
89
+ });
90
+
91
+ afterEach(() => {
92
+ if (originalFetch !== undefined) {
93
+ globalThis.fetch = originalFetch;
94
+ } else {
95
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
96
+ delete (globalThis as any).fetch;
97
+ }
98
+ });
99
+
100
+ it('AC-02 sequential: two loadByGuid calls sharing one pack URL trigger one fetch', async () => {
101
+ const reg = makeRegistry();
102
+ reg.configurePackIndex('/pack-index.json');
103
+
104
+ const packIndex = makePackIndex();
105
+ const sharedPack = makeSharedPack();
106
+
107
+ let packFetchCount = 0;
108
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
109
+ if (url === '/pack-index.json') {
110
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
111
+ }
112
+ if (url === SHARED_PACK_URL) {
113
+ packFetchCount++;
114
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(sharedPack) });
115
+ }
116
+ return Promise.resolve({ ok: false, status: 404 });
117
+ });
118
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
119
+
120
+ try {
121
+ const guidA = parseGuid(MESH_A_GUID);
122
+ const guidB = parseGuid(MESH_B_GUID);
123
+
124
+ const rA = await reg.loadByGuid<TypesMeshAsset>(guidA);
125
+ const rB = await reg.loadByGuid<TypesMeshAsset>(guidB);
126
+
127
+ expect(rA.ok).toBe(true);
128
+ expect(rB.ok).toBe(true);
129
+
130
+ // RED assertion: without cache, fetchPackFile is called twice (once per
131
+ // loadByGuid). With cache (after M3 impl), this must be 1.
132
+ expect(packFetchCount).toBe(1);
133
+ } finally {
134
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
135
+ delete (globalThis as any).fetch;
136
+ }
137
+ });
138
+
139
+ it('resolves a relative catalog entry against an absolute pack-index URL', async () => {
140
+ const reg = makeRegistry();
141
+ const packIndexUrl = 'http://127.0.0.1:15173/preview/pack-index/cow-survivor.json';
142
+ const packUrl =
143
+ 'http://127.0.0.1:15173/preview/.forgeax/games/cow-survivor/assets/shared.pack.json';
144
+ reg.configurePackIndex(packIndexUrl);
145
+
146
+ const packIndex = [
147
+ {
148
+ guid: MESH_A_GUID,
149
+ packageUrl: '../.forgeax/games/cow-survivor/assets/shared.pack.json',
150
+ kind: 'mesh',
151
+ },
152
+ ];
153
+ const sharedPack = makeSharedPack();
154
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
155
+ if (url === packIndexUrl)
156
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
157
+ if (url === packUrl)
158
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(sharedPack) });
159
+ return Promise.resolve({ ok: false, status: 404 });
160
+ });
161
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
162
+
163
+ try {
164
+ const result = await reg.loadByGuid<TypesMeshAsset>(parseGuid(MESH_A_GUID));
165
+ expect(fetchMock.mock.calls.map(([url]) => url)).toEqual([packIndexUrl, packUrl]);
166
+ expect(result.ok).toBe(true);
167
+ expect(fetchMock).toHaveBeenNthCalledWith(1, packIndexUrl, { cache: 'no-store' });
168
+ expect(fetchMock).toHaveBeenNthCalledWith(2, packUrl);
169
+ } finally {
170
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
171
+ delete (globalThis as any).fetch;
172
+ }
173
+ });
174
+
175
+ it('keeps an absolute catalog entry URL authoritative', async () => {
176
+ const reg = makeRegistry();
177
+ const packIndexUrl = 'http://127.0.0.1:15173/preview/pack-index/cow-survivor.json';
178
+ const packUrl = 'https://cdn.example.test/cow/shared.pack.json';
179
+ reg.configurePackIndex(packIndexUrl);
180
+
181
+ const packIndex = [{ guid: MESH_A_GUID, packageUrl: packUrl, kind: 'mesh' }];
182
+ const sharedPack = makeSharedPack();
183
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
184
+ if (url === packIndexUrl)
185
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
186
+ if (url === packUrl)
187
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(sharedPack) });
188
+ return Promise.resolve({ ok: false, status: 404 });
189
+ });
190
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
191
+
192
+ try {
193
+ const result = await reg.loadByGuid<TypesMeshAsset>(parseGuid(MESH_A_GUID));
194
+ expect(result.ok).toBe(true);
195
+ expect(fetchMock).toHaveBeenNthCalledWith(1, packIndexUrl, { cache: 'no-store' });
196
+ expect(fetchMock).toHaveBeenNthCalledWith(2, packUrl);
197
+ } finally {
198
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
199
+ delete (globalThis as any).fetch;
200
+ }
201
+ });
202
+
203
+ it('AC-02 concurrent: two concurrent loadByGuid calls share one in-flight fetch', async () => {
204
+ const reg = makeRegistry();
205
+ reg.configurePackIndex('/pack-index.json');
206
+
207
+ const packIndex = makePackIndex();
208
+ const sharedPack = makeSharedPack();
209
+
210
+ let packFetchCount = 0;
211
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
212
+ if (url === '/pack-index.json') {
213
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
214
+ }
215
+ if (url === SHARED_PACK_URL) {
216
+ packFetchCount++;
217
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(sharedPack) });
218
+ }
219
+ return Promise.resolve({ ok: false, status: 404 });
220
+ });
221
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
222
+
223
+ try {
224
+ const guidA = parseGuid(MESH_A_GUID);
225
+ const guidB = parseGuid(MESH_B_GUID);
226
+
227
+ const [rA, rB] = await Promise.all([
228
+ reg.loadByGuid<TypesMeshAsset>(guidA),
229
+ reg.loadByGuid<TypesMeshAsset>(guidB),
230
+ ]);
231
+
232
+ expect(rA.ok).toBe(true);
233
+ expect(rB.ok).toBe(true);
234
+
235
+ // RED assertion: without in-flight dedup, concurrent loads each trigger
236
+ // a fetch. With dedup (after M3 impl), this must be 1.
237
+ expect(packFetchCount).toBe(1);
238
+ } finally {
239
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
240
+ delete (globalThis as any).fetch;
241
+ }
242
+ });
243
+
244
+ it('AC-02 reject: fetch failure clears in-flight entry, retry fetches again', async () => {
245
+ const reg = makeRegistry();
246
+ reg.configurePackIndex('/pack-index.json');
247
+
248
+ const packIndex = makePackIndex();
249
+ const sharedPack = makeSharedPack();
250
+
251
+ let packFetchCount = 0;
252
+ let shouldReject = true;
253
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
254
+ if (url === '/pack-index.json') {
255
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
256
+ }
257
+ if (url === SHARED_PACK_URL) {
258
+ packFetchCount++;
259
+ if (shouldReject) {
260
+ return Promise.reject(new Error('network failure'));
261
+ }
262
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(sharedPack) });
263
+ }
264
+ return Promise.resolve({ ok: false, status: 404 });
265
+ });
266
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
267
+
268
+ try {
269
+ const guidA = parseGuid(MESH_A_GUID);
270
+
271
+ // First attempt: reject.
272
+ const r1 = await reg.loadByGuid<TypesMeshAsset>(guidA);
273
+ expect(r1.ok).toBe(false);
274
+ expect(packFetchCount).toBe(1);
275
+
276
+ // Second attempt: should fetch again (error not cached).
277
+ shouldReject = false;
278
+ const r2 = await reg.loadByGuid<TypesMeshAsset>(guidA);
279
+ expect(r2.ok).toBe(true);
280
+ expect(packFetchCount).toBe(2);
281
+ } finally {
282
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
283
+ delete (globalThis as any).fetch;
284
+ }
285
+ });
286
+ });
287
+
288
+ // ── M1 / F17b: pack-index fetch transient failure retry + no negative cache ───
289
+
290
+ describe('pack-index cache (F17b)', () => {
291
+ let originalFetch: typeof globalThis.fetch | undefined;
292
+
293
+ beforeEach(() => {
294
+ originalFetch = globalThis.fetch;
295
+ });
296
+
297
+ afterEach(() => {
298
+ if (originalFetch !== undefined) {
299
+ globalThis.fetch = originalFetch;
300
+ } else {
301
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
302
+ delete (globalThis as any).fetch;
303
+ }
304
+ });
305
+
306
+ it('AC-01 pack-index transient failure: retry succeeds after fetch recovery [w1]', async () => {
307
+ const reg = makeRegistry();
308
+ reg.configurePackIndex('/pack-index.json');
309
+
310
+ const packIndex = makePackIndex();
311
+ const sharedPack = makeSharedPack();
312
+
313
+ let packIndexFetchCount = 0;
314
+ let packIndexShouldReject = true;
315
+
316
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
317
+ if (url === '/pack-index.json') {
318
+ packIndexFetchCount++;
319
+ if (packIndexShouldReject) {
320
+ return Promise.reject(new Error('network failure'));
321
+ }
322
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(packIndex) });
323
+ }
324
+ if (url === SHARED_PACK_URL) {
325
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(sharedPack) });
326
+ }
327
+ return Promise.resolve({ ok: false, status: 404 });
328
+ });
329
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
330
+
331
+ try {
332
+ const guidA = parseGuid(MESH_A_GUID);
333
+
334
+ // Phase 1: pack-index fetch rejects -> loadByGuid fails.
335
+ const r1 = await reg.loadByGuid<TypesMeshAsset>(guidA);
336
+ expect(r1.ok).toBe(false);
337
+ expect(packIndexFetchCount).toBe(1);
338
+
339
+ // Phase 2: pack-index fetch recovers -> retry succeeds.
340
+ // RED assertion: with current HEAD (line 2814 new Map() pollution),
341
+ // packIndexCache is set to an empty Map on first failure, so
342
+ // resolveCatalogEntry skips re-fetch and returns undefined.
343
+ // After F17b fix, packIndexCache stays undefined -> re-fetches -> ok.
344
+ packIndexShouldReject = false;
345
+ const r2 = await reg.loadByGuid<TypesMeshAsset>(guidA);
346
+ expect(r2.ok).toBe(true);
347
+ expect(packIndexFetchCount).toBe(2);
348
+ } finally {
349
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
350
+ delete (globalThis as any).fetch;
351
+ }
352
+ });
353
+
354
+ it('AC-02 no negative cache: fetch called N times for N consecutive failures [w2]', async () => {
355
+ const reg = makeRegistry();
356
+ reg.configurePackIndex('/pack-index.json');
357
+
358
+ let packIndexFetchCount = 0;
359
+
360
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
361
+ if (url === '/pack-index.json') {
362
+ packIndexFetchCount++;
363
+ return Promise.reject(new Error('network failure'));
364
+ }
365
+ return Promise.resolve({ ok: false, status: 404 });
366
+ });
367
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
368
+
369
+ try {
370
+ const guidA = parseGuid(MESH_A_GUID);
371
+
372
+ // Three consecutive failures.
373
+ await reg.loadByGuid<TypesMeshAsset>(guidA);
374
+ await reg.loadByGuid<TypesMeshAsset>(guidA);
375
+ await reg.loadByGuid<TypesMeshAsset>(guidA);
376
+
377
+ // RED assertion: current HEAD sets packIndexCache = new Map() on first
378
+ // failure, short-circuiting subsequent re-fetches -> fetchCount == 1.
379
+ // After F17b fix, packIndexCache stays undefined -> each call re-fetches.
380
+ expect(packIndexFetchCount).toBe(3);
381
+ } finally {
382
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
383
+ delete (globalThis as any).fetch;
384
+ }
385
+ });
386
+ });
387
+
388
+ // -- M4 / F20: transportOrFail packIndexCache concurrent patch (AC-08) [w14] --
389
+
390
+ describe('transportOrFail packIndexCache concurrent patch (F20 / AC-08) [w14]', () => {
391
+ let originalFetch: typeof globalThis.fetch | undefined;
392
+
393
+ beforeEach(() => {
394
+ originalFetch = globalThis.fetch;
395
+ });
396
+
397
+ afterEach(() => {
398
+ if (originalFetch !== undefined) {
399
+ globalThis.fetch = originalFetch;
400
+ } else {
401
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
402
+ delete (globalThis as any).fetch;
403
+ }
404
+ });
405
+
406
+ it('N>=2 concurrent patch via transportOrFail: packIndexCache final state contains all entries', async () => {
407
+ const reg = makeRegistry();
408
+ reg.configurePackIndex('/pack-index.json');
409
+
410
+ const GUID_1 = 'f0000000-0000-4000-f000-000000000010';
411
+ const GUID_2 = 'f0000000-0000-4000-f000-000000000011';
412
+ const PACK_1 = '/packs/mesh-1.pack.json';
413
+ const PACK_2 = '/packs/mesh-2.pack.json';
414
+
415
+ // pack-index contains NEITHER GUID -> both fall through to transportOrFail.
416
+ const emptyPackIndex: never[] = [];
417
+
418
+ // Wire an ImportTransport that returns entries for each GUID.
419
+ const resolvers: Array<(value: unknown) => void> = [];
420
+ const blockedFetches = [GUID_1, GUID_2].map(() => {
421
+ return new Promise<unknown>((resolve) => {
422
+ resolvers.push(resolve);
423
+ });
424
+ });
425
+
426
+ let callIdx = 0;
427
+ const importTransport = {
428
+ fetchPack: vi.fn().mockImplementation(() => {
429
+ const blocked = blockedFetches[callIdx++];
430
+ if (blocked === undefined) throw new Error('unexpected fetchPack call');
431
+ return blocked;
432
+ }),
433
+ } as unknown as { fetchPack: ReturnType<typeof vi.fn> };
434
+
435
+ // Override the constructor to pass the importTransport.
436
+ const regWithTransport = new AssetRegistry(
437
+ makeMockShaderRegistry(),
438
+ // biome-ignore lint/suspicious/noExplicitAny: test mock
439
+ importTransport as any,
440
+ );
441
+ regWithTransport.configurePackIndex('/pack-index.json');
442
+
443
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
444
+ if (url === '/pack-index.json') {
445
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(emptyPackIndex) });
446
+ }
447
+ for (const [idx, packUrl] of [PACK_1, PACK_2].entries()) {
448
+ if (url === packUrl) {
449
+ const guid = idx === 0 ? GUID_1 : GUID_2;
450
+ return Promise.resolve({
451
+ ok: true,
452
+ json: () =>
453
+ Promise.resolve({
454
+ schemaVersion: '2.0.0',
455
+ kind: 'internal-text-package',
456
+ assets: [
457
+ {
458
+ guid,
459
+ kind: 'mesh',
460
+ payload: {
461
+ vertices: [
462
+ 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,
463
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
464
+ ],
465
+ indices: [0, 1, 2],
466
+ attributes: {},
467
+ submeshes: [
468
+ {
469
+ indexOffset: 0,
470
+ indexCount: 3,
471
+ vertexCount: 3,
472
+ topology: 'triangle-list',
473
+ },
474
+ ],
475
+ },
476
+ },
477
+ ],
478
+ }),
479
+ });
480
+ }
481
+ }
482
+ return Promise.resolve({ ok: false, status: 404 });
483
+ });
484
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
485
+
486
+ try {
487
+ // Start two concurrent loadByGuid calls. Both miss the catalog
488
+ // (pack-index is empty) and reach transportOrFail. The fetchPack
489
+ // promises are blocked, so both calls land in the race window.
490
+ const load1 = regWithTransport.loadByGuid<TypesMeshAsset>(parseGuid(GUID_1));
491
+ const load2 = regWithTransport.loadByGuid<TypesMeshAsset>(parseGuid(GUID_2));
492
+
493
+ // Settle the transport fetchPack calls with entries.
494
+ resolvers[0]?.({
495
+ ok: true,
496
+ entries: [{ guid: GUID_1, packageUrl: PACK_1, kind: 'mesh' }],
497
+ });
498
+ resolvers[1]?.({
499
+ ok: true,
500
+ entries: [{ guid: GUID_2, packageUrl: PACK_2, kind: 'mesh' }],
501
+ });
502
+
503
+ await Promise.all([load1, load2]);
504
+
505
+ // AC-08: packIndexCache final state must contain BOTH GUID entries.
506
+ // RED: with current HEAD (no serialisation), only the last new Map()
507
+ // survives -- one GUID's entry is lost. After F20 fix, both survive.
508
+ const internal = regWithTransport as unknown as {
509
+ packIndexCache: Map<string, unknown> | undefined;
510
+ };
511
+ const cache = internal.packIndexCache;
512
+ expect(cache).toBeDefined();
513
+ expect(cache?.size).toBe(2);
514
+ expect(cache?.get(GUID_1.toLowerCase())).toBeDefined();
515
+ expect(cache?.get(GUID_2.toLowerCase())).toBeDefined();
516
+ } finally {
517
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
518
+ delete (globalThis as any).fetch;
519
+ }
520
+ });
521
+ });
522
+
523
+ // -- transportOrFail patch preserves the transport's derived display name --
524
+ // Regression: the incremental patch loop copied packageUrl/kind/metadata but
525
+ // dropped `name`, so a GLB imported at runtime (studio Content Browser) showed
526
+ // its 1000+ sub-assets as blank rows. buildCatalog already derives the name
527
+ // (basename of the source), the transport carries it, and listCatalog reads it
528
+ // back via `entry.name` -- so the patch must persist it.
529
+
530
+ describe('transportOrFail packIndexCache patch preserves entry.name', () => {
531
+ let originalFetch: typeof globalThis.fetch | undefined;
532
+
533
+ beforeEach(() => {
534
+ originalFetch = globalThis.fetch;
535
+ });
536
+
537
+ afterEach(() => {
538
+ if (originalFetch !== undefined) {
539
+ globalThis.fetch = originalFetch;
540
+ } else {
541
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
542
+ delete (globalThis as any).fetch;
543
+ }
544
+ });
545
+
546
+ it('carries the transport entry name into the cache row and listCatalog', async () => {
547
+ const GUID = 'f0000000-0000-4000-f000-000000000020';
548
+ const PACK = '/packs/city.glb';
549
+ const NAME = 'city_Sample_512.glb';
550
+
551
+ const importTransport = {
552
+ fetchPack: vi.fn().mockResolvedValue({
553
+ ok: true,
554
+ entries: [{ guid: GUID, packageUrl: PACK, kind: 'scene', name: NAME }],
555
+ }),
556
+ } as unknown as { fetchPack: ReturnType<typeof vi.fn> };
557
+
558
+ const reg = new AssetRegistry(
559
+ makeMockShaderRegistry(),
560
+ // biome-ignore lint/suspicious/noExplicitAny: test mock
561
+ importTransport as any,
562
+ );
563
+ reg.configurePackIndex('/pack-index.json');
564
+
565
+ // pack-index is empty -> the GUID falls through to transportOrFail. The pack
566
+ // body fetch fails (404) after the patch lands, so loadByGuid rejects -- but
567
+ // the packIndexCache patch (the unit under test) has already run by then.
568
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
569
+ if (url === '/pack-index.json') {
570
+ return Promise.resolve({ ok: true, json: () => Promise.resolve([]) });
571
+ }
572
+ return Promise.resolve({ ok: false, status: 404 });
573
+ });
574
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
575
+
576
+ try {
577
+ await reg.loadByGuid(parseGuid(GUID)).catch(() => undefined);
578
+
579
+ const internal = reg as unknown as {
580
+ packIndexCache: Map<string, { name?: string }> | undefined;
581
+ };
582
+ expect(internal.packIndexCache?.get(GUID.toLowerCase())?.name).toBe(NAME);
583
+
584
+ const row = reg.listCatalog().find((e) => e.guid === GUID.toLowerCase());
585
+ expect(row?.name).toBe(NAME);
586
+ } finally {
587
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
588
+ delete (globalThis as any).fetch;
589
+ }
590
+ });
591
+ });
592
+
593
+ // -- M4 / F20: integration - two-GUID concurrent transportOrFail (AC-07) [w18] --
594
+
595
+ describe('integration: concurrent transportOrFail dual GUID (F20 / AC-07) [w18]', () => {
596
+ let originalFetch: typeof globalThis.fetch | undefined;
597
+
598
+ beforeEach(() => {
599
+ originalFetch = globalThis.fetch;
600
+ });
601
+
602
+ afterEach(() => {
603
+ if (originalFetch !== undefined) {
604
+ globalThis.fetch = originalFetch;
605
+ } else {
606
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
607
+ delete (globalThis as any).fetch;
608
+ }
609
+ });
610
+
611
+ it('two concurrent loadByGuid through transportOrFail: both catalogued + packIndexCache has both', async () => {
612
+ const GUID_1 = 'f0000000-0000-4000-f000-000000000020';
613
+ const GUID_2 = 'f0000000-0000-4000-f000-000000000021';
614
+ const PACK_1 = '/packs/integ-mesh-1.pack.json';
615
+ const PACK_2 = '/packs/integ-mesh-2.pack.json';
616
+
617
+ // pack-index is empty -- both GUIDs fall through to transportOrFail.
618
+ const emptyPackIndex: never[] = [];
619
+
620
+ // Block the transport fetchPack calls to create concurrency.
621
+ const resolvers: Array<(value: unknown) => void> = [];
622
+ const blockedFetches = [GUID_1, GUID_2].map(() => {
623
+ return new Promise<unknown>((resolve) => {
624
+ resolvers.push(resolve);
625
+ });
626
+ });
627
+
628
+ let transportCallIdx = 0;
629
+ const importTransport = {
630
+ fetchPack: vi.fn().mockImplementation(() => {
631
+ const blocked = blockedFetches[transportCallIdx++];
632
+ if (blocked === undefined) throw new Error('unexpected fetchPack call');
633
+ return blocked;
634
+ }),
635
+ };
636
+
637
+ const reg = new AssetRegistry(
638
+ makeMockShaderRegistry(),
639
+ // biome-ignore lint/suspicious/noExplicitAny: test mock
640
+ importTransport as any,
641
+ );
642
+ reg.configurePackIndex('/pack-index.json');
643
+
644
+ const fetchMock = vi.fn().mockImplementation((url: string) => {
645
+ if (url === '/pack-index.json') {
646
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(emptyPackIndex) });
647
+ }
648
+ for (const [idx, packUrl] of [PACK_1, PACK_2].entries()) {
649
+ if (url === packUrl) {
650
+ const guid = idx === 0 ? GUID_1 : GUID_2;
651
+ return Promise.resolve({
652
+ ok: true,
653
+ json: () =>
654
+ Promise.resolve({
655
+ schemaVersion: '2.0.0',
656
+ kind: 'internal-text-package',
657
+ assets: [
658
+ {
659
+ guid,
660
+ kind: 'mesh',
661
+ payload: {
662
+ vertices: [
663
+ 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,
664
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
665
+ ],
666
+ indices: [0, 1, 2],
667
+ attributes: {},
668
+ submeshes: [
669
+ {
670
+ indexOffset: 0,
671
+ indexCount: 3,
672
+ vertexCount: 3,
673
+ topology: 'triangle-list',
674
+ },
675
+ ],
676
+ },
677
+ },
678
+ ],
679
+ }),
680
+ });
681
+ }
682
+ }
683
+ return Promise.resolve({ ok: false, status: 404 });
684
+ });
685
+ globalThis.fetch = fetchMock as typeof globalThis.fetch;
686
+
687
+ try {
688
+ const load1 = reg.loadByGuid<TypesMeshAsset>(parseGuid(GUID_1));
689
+ const load2 = reg.loadByGuid<TypesMeshAsset>(parseGuid(GUID_2));
690
+
691
+ // Both are blocked at fetchPack. Release both transports.
692
+ resolvers[0]?.({
693
+ ok: true,
694
+ entries: [{ guid: GUID_1, packageUrl: PACK_1, kind: 'mesh' }],
695
+ });
696
+ resolvers[1]?.({
697
+ ok: true,
698
+ entries: [{ guid: GUID_2, packageUrl: PACK_2, kind: 'mesh' }],
699
+ });
700
+
701
+ const [r1, r2] = await Promise.all([load1, load2]);
702
+ expect(r1.ok).toBe(true);
703
+ expect(r2.ok).toBe(true);
704
+
705
+ // AC-07: packIndexCache must contain BOTH entries.
706
+ const internal = reg as unknown as {
707
+ packIndexCache: Map<string, unknown> | undefined;
708
+ };
709
+ const cache = internal.packIndexCache;
710
+ expect(cache?.size).toBe(2);
711
+ expect(cache?.get(GUID_1.toLowerCase())).toBeDefined();
712
+ expect(cache?.get(GUID_2.toLowerCase())).toBeDefined();
713
+
714
+ // Both assets must be in the catalog.
715
+ expect(reg.lookup(GUID_1)).toBeDefined();
716
+ expect(reg.lookup(GUID_2)).toBeDefined();
717
+ } finally {
718
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
719
+ delete (globalThis as any).fetch;
720
+ }
721
+ });
722
+ });
723
+
724
+ // ── refreshCatalog: re-fetch pack-index NOW so listCatalog reflects new assets ──
725
+ // Regression: after an import writes a new pack-index on disk, the registry kept
726
+ // its boot-time cache; listCatalog stayed stale until a page reload. refreshCatalog
727
+ // re-fetches immediately so the Content Browser + Add-to-Scene see the new asset.
728
+
729
+ describe('refreshCatalog re-fetches the pack-index immediately', () => {
730
+ let originalFetch: typeof globalThis.fetch | undefined;
731
+
732
+ beforeEach(() => {
733
+ originalFetch = globalThis.fetch;
734
+ });
735
+
736
+ afterEach(() => {
737
+ if (originalFetch !== undefined) globalThis.fetch = originalFetch;
738
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
739
+ else delete (globalThis as any).fetch;
740
+ });
741
+
742
+ it('surfaces a newly-added entry in listCatalog without any loadByGuid', async () => {
743
+ const reg = makeRegistry();
744
+ reg.configurePackIndex('/pack-index.json');
745
+
746
+ const NEW_GUID = 'f0000000-0000-4000-f000-0000000000a1';
747
+ // First served index is empty; the second (post-"import") carries one row.
748
+ let served: Array<{ guid: string; packageUrl: string; kind: string; name?: string }> = [];
749
+ globalThis.fetch = vi.fn().mockImplementation((url: string) => {
750
+ if (url === '/pack-index.json') {
751
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(served) });
752
+ }
753
+ return Promise.resolve({ ok: false, status: 404 });
754
+ }) as typeof globalThis.fetch;
755
+
756
+ try {
757
+ // Prime the cache with the empty index — the new GUID is absent.
758
+ const first = await reg.refreshCatalog();
759
+ expect(first).toBe(true);
760
+ expect(reg.listCatalog().find((e) => e.guid === NEW_GUID.toLowerCase())).toBeUndefined();
761
+
762
+ // Simulate an import writing a fresh pack-index, then refresh.
763
+ served = [
764
+ {
765
+ guid: NEW_GUID,
766
+ packageUrl: '/preview/new.pack.json',
767
+ kind: 'scene',
768
+ name: 'new.pack.json',
769
+ },
770
+ ];
771
+ const second = await reg.refreshCatalog();
772
+ expect(second).toBe(true);
773
+
774
+ const row = reg.listCatalog().find((e) => e.guid === NEW_GUID.toLowerCase());
775
+ expect(row).toBeDefined();
776
+ expect(row?.kind).toBe('scene');
777
+ expect(row?.name).toBe('new.pack.json');
778
+ } finally {
779
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
780
+ delete (globalThis as any).fetch;
781
+ }
782
+ });
783
+
784
+ it('returns false (keeps stale cache) when no pack-index URL is configured', async () => {
785
+ const reg = makeRegistry();
786
+ expect(await reg.refreshCatalog()).toBe(false);
787
+ });
788
+ });
789
+
790
+ // -- M5 / w36: real import patch preserves the complete producer row ---------
791
+
792
+ const M5_PACK_INDEX_URL = 'https://assets.example.test/game/pack-index.json';
793
+ const M5_GUID_A = 'f0000000-0000-4000-f000-0000000000a2';
794
+ const M5_GUID_B = 'f0000000-0000-4000-f000-0000000000a3';
795
+
796
+ function makeRichImportedEntry(
797
+ guid: string,
798
+ packageUrl: string,
799
+ sourceIndex: number,
800
+ ): PackIndexEntry {
801
+ const provenance = {
802
+ provider: 'fixture-importer',
803
+ version: '2.4.0',
804
+ source: 'fixture-source',
805
+ };
806
+ return {
807
+ guid,
808
+ packageUrl,
809
+ kind: 'mesh',
810
+ authoring: authoringCapabilityForAssetKind('mesh'),
811
+ sourcePath: `models/${guid}.source`,
812
+ packageId: 'fixture-package',
813
+ provenance,
814
+ revision: {
815
+ digest: 'sha256:fixture-revision',
816
+ observedAt: 17,
817
+ rootId: 'fixture-root',
818
+ },
819
+ sourceKey: `mesh/${guid}/main`,
820
+ sourceIndex,
821
+ relations: [
822
+ {
823
+ from: { type: 'asset', id: guid },
824
+ to: { type: 'resource', id: 'fixture-source' },
825
+ type: 'produces',
826
+ provenance,
827
+ },
828
+ ],
829
+ diagnostics: [
830
+ {
831
+ code: 'fixture-import-warning',
832
+ severity: 'warning',
833
+ expected: 'stable producer identity',
834
+ actual: 'imported during test',
835
+ hint: 'retain the producer row while resolving the locator',
836
+ authority: 'producer',
837
+ },
838
+ ],
839
+ };
840
+ }
841
+
842
+ function makeImportedMeshPack(guid: string): unknown {
843
+ return {
844
+ schemaVersion: '2.0.0',
845
+ kind: 'internal-text-package',
846
+ assets: [
847
+ {
848
+ guid,
849
+ kind: 'mesh',
850
+ payload: {
851
+ vertices: [
852
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
853
+ 0, 0, 0, 0, 0, 0, 0,
854
+ ],
855
+ indices: [0, 1, 2],
856
+ attributes: {},
857
+ submeshes: [{ indexOffset: 0, indexCount: 3, vertexCount: 3, topology: 'triangle-list' }],
858
+ },
859
+ refs: [],
860
+ artifacts: {},
861
+ },
862
+ ],
863
+ };
864
+ }
865
+
866
+ describe('M5 real import patch preserves CatalogRecord facts', () => {
867
+ let originalFetch: typeof globalThis.fetch | undefined;
868
+
869
+ beforeEach(() => {
870
+ originalFetch = globalThis.fetch;
871
+ });
872
+
873
+ afterEach(() => {
874
+ if (originalFetch !== undefined) {
875
+ globalThis.fetch = originalFetch;
876
+ } else {
877
+ // biome-ignore lint/suspicious/noExplicitAny: test teardown
878
+ delete (globalThis as any).fetch;
879
+ }
880
+ });
881
+
882
+ it('keeps producer identity while resolving the imported locator', async () => {
883
+ const packageUrl = './packs/imported-a.pack.json';
884
+ const resolvedUrl = 'https://assets.example.test/game/packs/imported-a.pack.json';
885
+ const entry = makeRichImportedEntry(M5_GUID_A, packageUrl, 4);
886
+ const importTransport = {
887
+ fetchPack: vi.fn().mockResolvedValue({ ok: true, entries: [entry] }),
888
+ };
889
+ const reg = new AssetRegistry(
890
+ makeMockShaderRegistry(),
891
+ // biome-ignore lint/suspicious/noExplicitAny: focused transport fixture
892
+ importTransport as any,
893
+ );
894
+ reg.configurePackIndex(M5_PACK_INDEX_URL);
895
+ globalThis.fetch = vi.fn().mockImplementation((url: string) => {
896
+ if (url === M5_PACK_INDEX_URL) {
897
+ return Promise.resolve({ ok: true, json: () => Promise.resolve([]) });
898
+ }
899
+ if (url === resolvedUrl) {
900
+ return Promise.resolve({
901
+ ok: true,
902
+ json: () => Promise.resolve(makeImportedMeshPack(M5_GUID_A)),
903
+ });
904
+ }
905
+ return Promise.resolve({ ok: false, status: 404 });
906
+ }) as typeof globalThis.fetch;
907
+
908
+ const result = await reg.loadByGuid<TypesMeshAsset>(parseGuid(M5_GUID_A));
909
+ expect(result.ok).toBe(true);
910
+ expect(importTransport.fetchPack).toHaveBeenCalledWith(M5_GUID_A, undefined);
911
+ expect(reg.listCatalog()).toContainEqual({
912
+ ...entry,
913
+ packageUrl: resolvedUrl,
914
+ });
915
+ });
916
+
917
+ it('keeps complete rows for concurrent import patches', async () => {
918
+ const entries = [
919
+ makeRichImportedEntry(M5_GUID_A, './packs/imported-a.pack.json', 4),
920
+ makeRichImportedEntry(M5_GUID_B, './packs/imported-b.pack.json', 5),
921
+ ];
922
+ const resolvers: Array<(value: unknown) => void> = [];
923
+ const importTransport = {
924
+ fetchPack: vi.fn().mockImplementation(() => {
925
+ return new Promise((resolve) => resolvers.push(resolve));
926
+ }),
927
+ };
928
+ const reg = new AssetRegistry(
929
+ makeMockShaderRegistry(),
930
+ // biome-ignore lint/suspicious/noExplicitAny: focused transport fixture
931
+ importTransport as any,
932
+ );
933
+ reg.configurePackIndex(M5_PACK_INDEX_URL);
934
+ globalThis.fetch = vi.fn().mockImplementation((url: string) => {
935
+ if (url === M5_PACK_INDEX_URL) {
936
+ return Promise.resolve({ ok: true, json: () => Promise.resolve([]) });
937
+ }
938
+ const entry = entries.find(
939
+ (candidate) => url === new URL(candidate.packageUrl, M5_PACK_INDEX_URL).href,
940
+ );
941
+ if (entry !== undefined) {
942
+ return Promise.resolve({
943
+ ok: true,
944
+ json: () => Promise.resolve(makeImportedMeshPack(entry.guid)),
945
+ });
946
+ }
947
+ return Promise.resolve({ ok: false, status: 404 });
948
+ }) as typeof globalThis.fetch;
949
+
950
+ const loads = [
951
+ reg.loadByGuid<TypesMeshAsset>(parseGuid(M5_GUID_A)),
952
+ reg.loadByGuid<TypesMeshAsset>(parseGuid(M5_GUID_B)),
953
+ ];
954
+ await vi.waitFor(() => expect(resolvers).toHaveLength(2));
955
+ resolvers[1]?.({ ok: true, entries: [entries[1]] });
956
+ resolvers[0]?.({ ok: true, entries: [entries[0]] });
957
+ const results = await Promise.all(loads);
958
+
959
+ expect(results.every((result) => result.ok)).toBe(true);
960
+ expect(reg.listCatalog()).toEqual(
961
+ expect.arrayContaining(
962
+ entries.map((entry) => ({
963
+ ...entry,
964
+ packageUrl: new URL(entry.packageUrl, M5_PACK_INDEX_URL).href,
965
+ })),
966
+ ),
967
+ );
968
+ });
969
+ });