@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
@@ -6,25 +6,13 @@
6
6
  // Each original file body sits in its own block-scope so helper names
7
7
  // cannot collide; describe() inside still registers globally with vitest.
8
8
 
9
+ import { AssetRegistry } from '@forgeax/engine-assets-runtime';
9
10
  import { World } from '@forgeax/engine-ecs';
11
+ import { Camera, MeshFilter, MeshRenderer } from '@forgeax/engine-render';
10
12
  import {
11
13
  SPRITE_PREMULTIPLIED_ALPHA_BLEND,
12
14
  SpriteRegionOverride,
13
15
  } from '@forgeax/engine-render/authoring';
14
- import type { DispatchEntry } from '@forgeax/engine-render/internal';
15
- import * as recordModule from '@forgeax/engine-render/internal';
16
- import {
17
- Camera,
18
- createEngineMetrics,
19
- detectNineSliceScaleTooSmall,
20
- extractFrame,
21
- isLitMaterialSnapshot,
22
- type MaterialSnapshot,
23
- MeshFilter,
24
- MeshRenderer,
25
- prepareExtractContext,
26
- writeMaterialSnapshotPayload,
27
- } from '@forgeax/engine-render/internal';
28
16
  import { propagateTransforms, Transform } from '@forgeax/engine-scene';
29
17
  import { ShaderRegistry, type ShaderRegistryDevice } from '@forgeax/engine-shader';
30
18
  import type {
@@ -33,40 +21,200 @@ import type {
33
21
  MaterialPass,
34
22
  MeshAsset,
35
23
  ParamSchemaEntry,
36
- PassSelector,
37
24
  } from '@forgeax/engine-types';
38
25
  import { derive } from '@forgeax/engine-types';
39
26
  import { describe, expect, it } from 'vitest';
40
- import { createTestRenderAssetOwner } from './helpers/render-asset-port';
27
+ import { createEngineMetrics } from '../../../render/src/engine-metrics';
28
+ import { isLitMaterialSnapshot } from '../../../render/src/record/helpers';
29
+ import * as recordModule from '../../../render/src/record/main-pass-material';
30
+ import { detectNineSliceScaleTooSmall } from '../../../render/src/record/main-pass-material';
31
+ import * as spriteRecordModule from '../../../render/src/record/main-pass-sprite-draws';
32
+ import { filterDispatchBySelector } from '../../../render/src/record/shadow-pass';
33
+ import type { DispatchEntry, MaterialSnapshot } from '../../../render/src/render-system-extract';
34
+ import { extractFrame, prepareExtractContext } from '../../../render/src/render-system-extract';
35
+
36
+ // ─── from render-system-record-pbr-ubo-stable.test.ts ───
37
+ {
38
+ // render-system-record-pbr-ubo-stable - feat-20260527-sprite-nineslice M2 / w6.
39
+ //
40
+ // PBR Material UBO byte-sequence regression net (D-7 isolation):
41
+ // any deviation in the PBR write path's byte sequence (even 1 byte) caused
42
+ // by the sprite-branch schema-driven UBO extension (w11) MUST fail this test
43
+ // — that triggers R-8 fallback (revert D-7 to physically isolated sprite
44
+ // write function).
45
+ //
46
+ // w11 will extract the inline PBR UBO write path
47
+ // (render-system-record.ts:2194-2277 -- baseColor, metallic, roughness,
48
+ // channelMap u32 packing, emissive, occlusionStrength, paramSnapshot
49
+ // schema-driven overlay) into a pure helper
50
+ // `buildPbrMaterialUboPayload(material) -> Uint8Array(288B)` so this
51
+ // regression test can exercise the PBR write byte-for-byte.
52
+ //
53
+ // The helper MUST produce the exact byte sequence the inline path produced
54
+ // pre-feat (no slices-related side effects on the PBR layout). This test
55
+ // asserts the PBR baseline against literal byte values.
56
+ //
57
+ // Coverage:
58
+ // - 304 B payload (STANDARD_PBR_UBO_SIZE)
59
+ // - slot 0 = baseColor.rgb + 1 (alpha hardcoded)
60
+ // - slot 1 first 8 B = metallic, roughness (f32x2)
61
+ // - slot 1 last 4 u32 (channelMap) = [2, 1, 0, 0]
62
+ // - slot 2 = emissive.rgb + emissiveIntensity
63
+ // - slot 3 first 4 B = occlusionStrength; rest stays 0 (no schema overlay
64
+ // in default-standard-pbr path; paramSnapshot reuses slot 0/1/2 by
65
+ // position).
66
+ //
67
+ // Anchors: plan-strategy §R-8, §5.3 key tests #2; AGENTS.md §Error model
68
+ // (closed-union AssetErrorCode unchanged, baseline test does not depend on
69
+ // new error members).
41
70
 
42
- describe('derived material record stop-draw (w28)', () => {
43
- it('returns a structured bounds error before a slot can be uploaded', () => {
44
- const result = writeMaterialSnapshotPayload(
45
- {
46
- baseColor: new Float32Array([1, 1, 1]) as unknown as MaterialSnapshot['baseColor'],
47
- metallic: 0,
48
- roughness: 1,
49
- materialParamSchema: [{ name: 'albedo', type: 'texture2d' }],
50
- textureCoordinates: new Map([
51
- [
52
- 'albedo',
53
- {
54
- set: 0,
55
- transform: { offset: [0, 0], scale: [1, 1], rotation: 0 },
56
- physicalUvScale: [1, 1],
57
- },
58
- ],
59
- ]),
60
- },
61
- 16,
62
- );
71
+ const mod = recordModule as unknown as {
72
+ buildPbrMaterialUboPayload?: (material: MaterialSnapshot) => Uint8Array;
73
+ applyMaterialTextureUvScales?: (
74
+ payload: ArrayBuffer | Uint8Array,
75
+ material: MaterialSnapshot,
76
+ world: World,
77
+ ) => void;
78
+ };
63
79
 
64
- expect(result).toMatchObject({
65
- ok: false,
66
- error: { code: 'material-payload-bounds', detail: { action: 'stop-draw' } },
80
+ function makePbrSnapshot(opts: {
81
+ baseColor?: readonly [number, number, number, number];
82
+ metallic?: number;
83
+ roughness?: number;
84
+ emissive?: readonly [number, number, number];
85
+ emissiveIntensity?: number;
86
+ occlusionStrength?: number;
87
+ clearcoat?: number;
88
+ clearcoatRoughness?: number;
89
+ specularTint?: readonly [number, number, number];
90
+ }): MaterialSnapshot {
91
+ return {
92
+ baseColor: opts.baseColor ?? [0.5, 0.6, 0.7, 1],
93
+ metallic: opts.metallic ?? 0.1,
94
+ roughness: opts.roughness ?? 0.4,
95
+ materialShaderId: 'forgeax::default-standard-pbr',
96
+ paramSnapshot: undefined,
97
+ ...(opts.emissive !== undefined && { emissive: opts.emissive }),
98
+ ...(opts.emissiveIntensity !== undefined && { emissiveIntensity: opts.emissiveIntensity }),
99
+ ...(opts.occlusionStrength !== undefined && { occlusionStrength: opts.occlusionStrength }),
100
+ ...(opts.clearcoat !== undefined && { clearcoat: opts.clearcoat }),
101
+ ...(opts.clearcoatRoughness !== undefined && { clearcoatRoughness: opts.clearcoatRoughness }),
102
+ ...(opts.specularTint !== undefined && { specularTint: opts.specularTint }),
103
+ } as unknown as MaterialSnapshot;
104
+ }
105
+
106
+ describe('PBR Material UBO byte sequence regression net (M2 / w6, D-7 isolation)', () => {
107
+ it('export: buildPbrMaterialUboPayload helper is exported from render-system-record', () => {
108
+ expect(typeof mod.buildPbrMaterialUboPayload).toBe('function');
109
+ });
110
+
111
+ it('304 B payload size + standard PBR slot layout (baseline)', () => {
112
+ if (typeof mod.buildPbrMaterialUboPayload !== 'function') {
113
+ throw new Error('helper not exported yet');
114
+ }
115
+ const snap = makePbrSnapshot({
116
+ baseColor: [0.5, 0.6, 0.7, 1],
117
+ metallic: 0.1,
118
+ roughness: 0.4,
119
+ emissive: [0, 0, 0],
120
+ emissiveIntensity: 0,
121
+ occlusionStrength: 1,
122
+ clearcoat: 0.85,
123
+ clearcoatRoughness: 0.12,
124
+ specularTint: [0.11, 0.22, 0.33],
125
+ });
126
+ const buf = mod.buildPbrMaterialUboPayload(snap);
127
+ expect(buf.byteLength).toBe(304);
128
+ const f32 = new Float32Array(buf.buffer, buf.byteOffset, buf.byteLength / 4);
129
+ // feat-20260613 fix-issue-1 (D-8 channelMap split): the 4 channelMap
130
+ // u32 slots collapse into 4 independent f32 channel selectors at
131
+ // f32[6..9] (metallicChannel/roughnessChannel/aoChannel/extraChannel).
132
+ // baseColor.rgb + alpha=1 (alpha hardcoded in PBR write path).
133
+ expect(f32[0]).toBeCloseTo(0.5);
134
+ expect(f32[1]).toBeCloseTo(0.6);
135
+ expect(f32[2]).toBeCloseTo(0.7);
136
+ expect(f32[3]).toBe(1);
137
+ // metallic + roughness (first 8 B of slot 1).
138
+ expect(f32[4]).toBeCloseTo(0.1);
139
+ expect(f32[5]).toBeCloseTo(0.4);
140
+ // 4 channel selectors as f32 (default = B/G/R/_ glTF packing).
141
+ expect(f32[6]).toBe(2); // metallicChannel <- B
142
+ expect(f32[7]).toBe(1); // roughnessChannel <- G
143
+ expect(f32[8]).toBe(0); // aoChannel <- R
144
+ expect(f32[9]).toBe(0); // extraChannel <- reserved
145
+ // offsets 40..47 implicit pad (vec3 align=16 before emissive).
146
+ expect(f32[10]).toBe(0);
147
+ expect(f32[11]).toBe(0);
148
+ // emissive.rgb + emissiveIntensity (offset 48..63).
149
+ expect(f32[12]).toBe(0);
150
+ expect(f32[13]).toBe(0);
151
+ expect(f32[14]).toBe(0);
152
+ expect(f32[15]).toBe(0);
153
+ // occlusionStrength (offset 64..67).
154
+ expect(f32[16]).toBe(1);
155
+ // alphaCutoff (offset 68).
156
+ expect(f32[17]).toBe(0);
157
+ // clearcoat layer (offsets 72..79).
158
+ expect(f32[18]).toBeCloseTo(0.85);
159
+ expect(f32[19]).toBeCloseTo(0.12);
160
+ // specularTint vec3 (offsets 80..92).
161
+ expect(f32[20]).toBeCloseTo(0.11);
162
+ expect(f32[21]).toBeCloseTo(0.22);
163
+ expect(f32[22]).toBeCloseTo(0.33);
164
+ expect(f32[72]).toBe(1);
165
+ });
166
+
167
+ it('writes schema-carried alphaCutoff into the baseline PBR payload', () => {
168
+ if (typeof mod.buildPbrMaterialUboPayload !== 'function') {
169
+ throw new Error('helper not exported yet');
170
+ }
171
+ const payload = mod.buildPbrMaterialUboPayload({
172
+ ...makePbrSnapshot({}),
173
+ paramSnapshot: { alphaCutoff: 0.5 },
174
+ } as MaterialSnapshot);
175
+ const f32 = new Float32Array(payload.buffer, payload.byteOffset, payload.byteLength / 4);
176
+ expect(f32[17]).toBeCloseTo(0.5);
177
+ });
178
+
179
+ it('keeps engine-owned texture UV tails aligned across PBR and sprite layouts', () => {
180
+ const apply = mod.applyMaterialTextureUvScales;
181
+ if (typeof apply !== 'function') throw new Error('helper not exported yet');
182
+ const world = new World();
183
+ const pbrPayload = new ArrayBuffer(304);
184
+ apply(pbrPayload, makePbrSnapshot({}), world);
185
+ const pbrF32 = new Float32Array(pbrPayload);
186
+ expect(pbrF32[26]).toBe(1);
187
+ expect(pbrF32[34]).toBe(1);
188
+ expect(pbrF32[42]).toBe(1);
189
+ expect(pbrF32[50]).toBe(1);
190
+ expect(pbrF32[58]).toBe(1);
191
+ expect(pbrF32[66]).toBe(1);
192
+
193
+ const spritePayload = new ArrayBuffer(128);
194
+ apply(
195
+ spritePayload,
196
+ { ...makePbrSnapshot({}), materialShaderId: 'forgeax::sprite' } as MaterialSnapshot,
197
+ world,
198
+ );
199
+ const spriteF32 = new Float32Array(spritePayload);
200
+ expect(Array.from(spriteF32.slice(16, 24))).toEqual([0, 0, 1, 1, 0, 0, 1, 1]);
201
+ });
202
+
203
+ it('byte-stable across two equivalent PBR snapshots (idempotent write)', () => {
204
+ if (typeof mod.buildPbrMaterialUboPayload !== 'function') {
205
+ throw new Error('helper not exported yet');
206
+ }
207
+ const snap = makePbrSnapshot({
208
+ baseColor: [0.2, 0.3, 0.4, 1],
209
+ metallic: 0.5,
210
+ roughness: 0.5,
211
+ });
212
+ const a = mod.buildPbrMaterialUboPayload(snap);
213
+ const b = mod.buildPbrMaterialUboPayload(snap);
214
+ expect(new Uint8Array(a)).toEqual(new Uint8Array(b));
67
215
  });
68
216
  });
69
- });
217
+ }
70
218
 
71
219
  // ─── from render-system-record-scale-too-small.test.ts ───
72
220
  {
@@ -74,7 +222,7 @@ describe('derived material record stop-draw (w28)', () => {
74
222
  //
75
223
  // AC-16 end-to-end: when a 9-slice sprite entity carries a Transform.scale
76
224
  // below the four corner anchors, the detection path bumps
77
- // `renderer.metrics.snapshot()['nineslice.scale-too-small']` once per offending
225
+ // the owner metrics snapshot's `nineslice.scale-too-small` key once per offending
78
226
  // renderableIndex per RenderSystem lifetime. AI users observe the breach
79
227
  // through the EngineMetrics counter rather than parsing console.warn text
80
228
  // (charter P3 machine-readable signals).
@@ -290,7 +438,7 @@ describe('derived material record stop-draw (w28)', () => {
290
438
  describe('SpriteRegionOverride compose 9-slice (M4 / w17b, AC-14)', () => {
291
439
  it('(1) entity without override uses asset-side region', () => {
292
440
  const world = new World();
293
- const assets = createTestRenderAssetOwner(makeShaderRegistryWithSprite());
441
+ const assets = new AssetRegistry(makeShaderRegistryWithSprite());
294
442
  const mesh = registerSpriteMesh(world);
295
443
  const matHandle = world.allocSharedRef<'MaterialAsset', MaterialAsset>('MaterialAsset', {
296
444
  kind: 'material',
@@ -318,7 +466,7 @@ describe('derived material record stop-draw (w28)', () => {
318
466
 
319
467
  it('(2) entity with override uses the override region in the snapshot', () => {
320
468
  const world = new World();
321
- const assets = createTestRenderAssetOwner(makeShaderRegistryWithSprite());
469
+ const assets = new AssetRegistry(makeShaderRegistryWithSprite());
322
470
  const mesh = registerSpriteMesh(world);
323
471
  const matHandle = world.allocSharedRef<'MaterialAsset', MaterialAsset>('MaterialAsset', {
324
472
  kind: 'material',
@@ -352,7 +500,7 @@ describe('derived material record stop-draw (w28)', () => {
352
500
 
353
501
  it('(3) two entities sharing one material diverge on effective region (compose with 9-slice)', () => {
354
502
  const world = new World();
355
- const assets = createTestRenderAssetOwner(makeShaderRegistryWithSprite());
503
+ const assets = new AssetRegistry(makeShaderRegistryWithSprite());
356
504
  const mesh = registerSpriteMesh(world);
357
505
  const matHandle = world.allocSharedRef<'MaterialAsset', MaterialAsset>('MaterialAsset', {
358
506
  kind: 'material',
@@ -583,15 +731,6 @@ describe('derived material record stop-draw (w28)', () => {
583
731
  //
584
732
  // Anchors: plan-strategy section 5.3 key tests; requirements AC-03/AC-04/AC-18.
585
733
 
586
- const filterDispatchBySelector = (
587
- recordModule as unknown as {
588
- filterDispatchBySelector?: (
589
- dispatch: readonly DispatchEntry[],
590
- selector: PassSelector,
591
- ) => readonly DispatchEntry[];
592
- }
593
- ).filterDispatchBySelector;
594
-
595
734
  function makeDispatchEntry(
596
735
  renderableIndex: number,
597
736
  passIndex: number,
@@ -890,6 +1029,191 @@ describe('derived material record stop-draw (w28)', () => {
890
1029
  });
891
1030
  }
892
1031
 
1032
+ // --- from feat-20260625-refactor-sprite-as-transparent-mesh M1 / w2 ---
1033
+ {
1034
+ // standard-pbr regression: the generic writer over the engine-shipped
1035
+ // default-standard-pbr.material.json paramSchema (15 numeric entries
1036
+ // std140-packed into 96 B) must produce byte-identical output to
1037
+ // buildPbrMaterialUboPayload. This is the gate plan-strategy section 2
1038
+ // D-2 sets so the generic writer can replace the inline overlay without
1039
+ // perturbing PBR rendering. RED until w3 lands the helper.
1040
+
1041
+ const mod = recordModule as unknown as {
1042
+ applyParamSnapshotToUbo?: (
1043
+ payload: ArrayBuffer | Uint8Array,
1044
+ paramSchema: readonly ParamSchemaEntry[] | undefined,
1045
+ paramSnapshot:
1046
+ | Readonly<Record<string, number | readonly number[] | string | undefined>>
1047
+ | undefined,
1048
+ ) => void;
1049
+ buildPbrMaterialUboPayload?: (material: MaterialSnapshot) => Uint8Array;
1050
+ };
1051
+
1052
+ // Mirror the engine-shipped default-standard-pbr.material.json schema
1053
+ // (the on-disk SSOT; inline here to keep the unit suite free of asset
1054
+ // loads).
1055
+ const STANDARD_PBR_SCHEMA: readonly ParamSchemaEntry[] = [
1056
+ { name: 'baseColor', type: 'color', default: [1, 1, 1, 1] },
1057
+ { name: 'metallic', type: 'f32', default: 0 },
1058
+ { name: 'roughness', type: 'f32', default: 0.5 },
1059
+ { name: 'metallicChannel', type: 'f32', default: 2 },
1060
+ { name: 'roughnessChannel', type: 'f32', default: 1 },
1061
+ { name: 'aoChannel', type: 'f32', default: 0 },
1062
+ { name: 'extraChannel', type: 'f32', default: 0 },
1063
+ { name: 'emissive', type: 'vec3', default: [0, 0, 0] },
1064
+ { name: 'emissiveIntensity', type: 'f32', default: 0 },
1065
+ { name: 'occlusionStrength', type: 'f32', default: 1 },
1066
+ { name: 'alphaCutoff', type: 'f32', default: 0 },
1067
+ { name: 'clearcoat', type: 'f32', default: 0 },
1068
+ { name: 'clearcoatRoughness', type: 'f32', default: 0.5 },
1069
+ { name: 'specularTint', type: 'vec3', default: [1, 1, 1] },
1070
+ ];
1071
+
1072
+ describe('applyParamSnapshotToUbo: standard-pbr byte-identical via derive (M1 / w2)', () => {
1073
+ it('derive(standard-pbr).uboLayout matches the 96 B authored numeric layout', () => {
1074
+ const { uboLayout } = derive(STANDARD_PBR_SCHEMA);
1075
+ expect(uboLayout.totalBytes).toBe(96);
1076
+ const byName = new Map(uboLayout.entries.map((e) => [e.name, e]));
1077
+ expect(byName.get('baseColor')?.offset).toBe(0);
1078
+ expect(byName.get('metallic')?.offset).toBe(16);
1079
+ expect(byName.get('roughness')?.offset).toBe(20);
1080
+ expect(byName.get('metallicChannel')?.offset).toBe(24);
1081
+ expect(byName.get('roughnessChannel')?.offset).toBe(28);
1082
+ expect(byName.get('aoChannel')?.offset).toBe(32);
1083
+ expect(byName.get('extraChannel')?.offset).toBe(36);
1084
+ // vec3 aligns to 16: cursor at 40 rounds up to 48.
1085
+ expect(byName.get('emissive')?.offset).toBe(48);
1086
+ expect(byName.get('emissiveIntensity')?.offset).toBe(60);
1087
+ expect(byName.get('occlusionStrength')?.offset).toBe(64);
1088
+ expect(byName.get('alphaCutoff')?.offset).toBe(68);
1089
+ expect(byName.get('clearcoat')?.offset).toBe(72);
1090
+ expect(byName.get('clearcoatRoughness')?.offset).toBe(76);
1091
+ expect(byName.get('specularTint')?.offset).toBe(80);
1092
+ });
1093
+
1094
+ it('generic writer over standard-pbr snapshot equals buildPbrMaterialUboPayload bytes', () => {
1095
+ if (typeof mod.applyParamSnapshotToUbo !== 'function') {
1096
+ throw new Error('helper not exported yet (red phase)');
1097
+ }
1098
+ if (typeof mod.buildPbrMaterialUboPayload !== 'function') {
1099
+ throw new Error('buildPbrMaterialUboPayload missing -- baseline broken');
1100
+ }
1101
+ // Construct a snapshot equivalent to the explicit material fields the
1102
+ // legacy helper consumes (baseColor / metallic / roughness / emissive /
1103
+ // emissiveIntensity / occlusionStrength + the channelMap defaults the
1104
+ // helper hard-codes).
1105
+ const baseColor = [0.5, 0.6, 0.7, 1] as readonly number[];
1106
+ const metallic = 0.1;
1107
+ const roughness = 0.4;
1108
+ const emissive = [0, 0, 0] as readonly number[];
1109
+ const emissiveIntensity = 0;
1110
+ const occlusionStrength = 1;
1111
+ const material = {
1112
+ baseColor,
1113
+ metallic,
1114
+ roughness,
1115
+ materialShaderId: 'forgeax::default-standard-pbr',
1116
+ paramSnapshot: undefined,
1117
+ emissive,
1118
+ emissiveIntensity,
1119
+ occlusionStrength,
1120
+ alphaCutoff: 0,
1121
+ clearcoat: 0,
1122
+ clearcoatRoughness: 0.5,
1123
+ specularTint: [1, 1, 1],
1124
+ } as unknown as MaterialSnapshot;
1125
+ const baseline = mod.buildPbrMaterialUboPayload(material);
1126
+ // Construct the generic-writer output: start from the same explicit
1127
+ // PBR baseline, then apply the generic overlay over a paramSnapshot
1128
+ // carrying the same values. The overlay must not perturb any byte
1129
+ // the explicit baseline already wrote (charter P4 -- one writer, one
1130
+ // byte layout).
1131
+ const candidate = mod.buildPbrMaterialUboPayload(material);
1132
+ const snapshot = {
1133
+ baseColor,
1134
+ metallic,
1135
+ roughness,
1136
+ metallicChannel: 2,
1137
+ roughnessChannel: 1,
1138
+ aoChannel: 0,
1139
+ extraChannel: 0,
1140
+ emissive,
1141
+ emissiveIntensity,
1142
+ occlusionStrength,
1143
+ specularTint: [1, 1, 1],
1144
+ };
1145
+ mod.applyParamSnapshotToUbo(candidate, STANDARD_PBR_SCHEMA, snapshot);
1146
+ expect(new Uint8Array(candidate)).toEqual(new Uint8Array(baseline));
1147
+ });
1148
+
1149
+ it('overlays non-opaque standard-PBR baseColor alpha over the opaque baseline', () => {
1150
+ if (typeof mod.applyParamSnapshotToUbo !== 'function') {
1151
+ throw new Error('helper not exported yet (red phase)');
1152
+ }
1153
+ if (typeof mod.buildPbrMaterialUboPayload !== 'function') {
1154
+ throw new Error('buildPbrMaterialUboPayload missing -- baseline broken');
1155
+ }
1156
+ const material = {
1157
+ baseColor: [0.5, 0.6, 0.7, 0.5],
1158
+ metallic: 0,
1159
+ roughness: 0.5,
1160
+ materialShaderId: 'forgeax::default-standard-pbr',
1161
+ paramSnapshot: undefined,
1162
+ } as unknown as MaterialSnapshot;
1163
+ const payload = mod.buildPbrMaterialUboPayload(material);
1164
+ // The explicit baseline is intentionally opaque; importer-supplied
1165
+ // paramSnapshot values must overwrite all four baseColor components.
1166
+ expect(new Float32Array(payload.buffer, payload.byteOffset, payload.byteLength / 4)[3]).toBe(
1167
+ 1,
1168
+ );
1169
+ mod.applyParamSnapshotToUbo(payload, STANDARD_PBR_SCHEMA, {
1170
+ baseColor: [0.5, 0.6, 0.7, 0.5],
1171
+ });
1172
+ expect(new Float32Array(payload.buffer, payload.byteOffset, payload.byteLength / 4)[3]).toBe(
1173
+ 0.5,
1174
+ );
1175
+ });
1176
+
1177
+ it('honours f32 slot offsets independently (slot 1 width = 4 floats from metallic..extraChannel)', () => {
1178
+ if (typeof mod.applyParamSnapshotToUbo !== 'function') {
1179
+ throw new Error('helper not exported yet (red phase)');
1180
+ }
1181
+ const buf = new ArrayBuffer(80);
1182
+ // f32-exact values (powers of 2 / sums) so we can assert toEqual on
1183
+ // every slot; toBeCloseTo would let off-by-one-bit drifts hide.
1184
+ const snapshot = {
1185
+ baseColor: [0.125, 0.25, 0.5, 1] as readonly number[],
1186
+ metallic: 0.5,
1187
+ roughness: 0.25,
1188
+ metallicChannel: 2,
1189
+ roughnessChannel: 1,
1190
+ aoChannel: 0,
1191
+ extraChannel: 0,
1192
+ emissive: [0.5, 0.5, 0.5] as readonly number[],
1193
+ emissiveIntensity: 1.5,
1194
+ occlusionStrength: 0.75,
1195
+ };
1196
+ mod.applyParamSnapshotToUbo(buf, STANDARD_PBR_SCHEMA, snapshot);
1197
+ const f32 = new Float32Array(buf);
1198
+ // baseColor occupies slot 0 (offset 0).
1199
+ expect(Array.from(f32.slice(0, 4))).toEqual([0.125, 0.25, 0.5, 1]);
1200
+ // 4 f32 channels packed at offset 16..36 -- distinct slots, not folded
1201
+ // into one vec4 (regression against legacy "first two f32 only"
1202
+ // overlay at render-system-record.ts:4334-4374).
1203
+ expect(f32[4]).toBe(0.5);
1204
+ expect(f32[5]).toBe(0.25);
1205
+ expect(f32[6]).toBe(2);
1206
+ expect(f32[7]).toBe(1);
1207
+ expect(f32[8]).toBe(0);
1208
+ expect(f32[9]).toBe(0);
1209
+ // emissive vec3 at offset 48 (f32 index 12).
1210
+ expect(Array.from(f32.slice(12, 15))).toEqual([0.5, 0.5, 0.5]);
1211
+ expect(f32[15]).toBe(1.5);
1212
+ expect(f32[16]).toBe(0.75);
1213
+ });
1214
+ });
1215
+ }
1216
+
893
1217
  // --- from feat-20260625-refactor-sprite-as-transparent-mesh M2 / w4 ---
894
1218
  {
895
1219
  // AC-05: a MaterialSnapshot carrying transparent:true on its source pass
@@ -927,11 +1251,13 @@ describe('derived material record stop-draw (w28)', () => {
927
1251
  };
928
1252
  };
929
1253
 
930
- const mod = recordModule as unknown as {
1254
+ const spriteMod = spriteRecordModule as unknown as {
931
1255
  computeSplitLdrSprite?: (
932
1256
  validatedOrdered: readonly (DispatchEntryLike | undefined)[],
933
1257
  tonemapActive: boolean,
934
1258
  ) => boolean;
1259
+ };
1260
+ const mod = recordModule as unknown as {
935
1261
  isEntityFullyTransparent?: (source: {
936
1262
  material: MaterialSnapshot;
937
1263
  materials?: readonly MaterialSnapshot[];
@@ -962,11 +1288,11 @@ describe('derived material record stop-draw (w28)', () => {
962
1288
 
963
1289
  describe('transparent decouples from sprite shader (M2 / w4, AC-05)', () => {
964
1290
  it('export: computeSplitLdrSprite helper is exported from render-system-record', () => {
965
- expect(typeof mod.computeSplitLdrSprite).toBe('function');
1291
+ expect(typeof spriteMod.computeSplitLdrSprite).toBe('function');
966
1292
  });
967
1293
 
968
1294
  it('non-sprite shader with transparent:true triggers LDR split', () => {
969
- if (typeof mod.computeSplitLdrSprite !== 'function') {
1295
+ if (typeof spriteMod.computeSplitLdrSprite !== 'function') {
970
1296
  throw new Error('computeSplitLdrSprite helper not exported yet (red phase)');
971
1297
  }
972
1298
  const transparentSnap = makeTransparentSnap({
@@ -980,7 +1306,7 @@ describe('derived material record stop-draw (w28)', () => {
980
1306
  // tonemapActive=false (LDR path) + a transparent entry in the
981
1307
  // validated list -- the split decision must trip even though the
982
1308
  // shader is not forgeax::sprite (AC-05 proves the decoupling).
983
- const split = mod.computeSplitLdrSprite(
1309
+ const split = spriteMod.computeSplitLdrSprite(
984
1310
  [makeValidatedEntry(opaqueSnap), makeValidatedEntry(transparentSnap)],
985
1311
  false,
986
1312
  );
@@ -988,7 +1314,7 @@ describe('derived material record stop-draw (w28)', () => {
988
1314
  });
989
1315
 
990
1316
  it('LDR split stays false on pure-opaque non-sprite list', () => {
991
- if (typeof mod.computeSplitLdrSprite !== 'function') {
1317
+ if (typeof spriteMod.computeSplitLdrSprite !== 'function') {
992
1318
  throw new Error('computeSplitLdrSprite helper not exported yet (red phase)');
993
1319
  }
994
1320
  const opaqueA = makeTransparentSnap({
@@ -999,7 +1325,7 @@ describe('derived material record stop-draw (w28)', () => {
999
1325
  transparent: false,
1000
1326
  materialShaderId: 'forgeax::default-standard-pbr',
1001
1327
  });
1002
- const split = mod.computeSplitLdrSprite(
1328
+ const split = spriteMod.computeSplitLdrSprite(
1003
1329
  [makeValidatedEntry(opaqueA), makeValidatedEntry(opaqueB)],
1004
1330
  false,
1005
1331
  );
@@ -1007,19 +1333,19 @@ describe('derived material record stop-draw (w28)', () => {
1007
1333
  });
1008
1334
 
1009
1335
  it('HDR path (tonemapActive=true) suppresses split even with transparent entries', () => {
1010
- if (typeof mod.computeSplitLdrSprite !== 'function') {
1336
+ if (typeof spriteMod.computeSplitLdrSprite !== 'function') {
1011
1337
  throw new Error('computeSplitLdrSprite helper not exported yet (red phase)');
1012
1338
  }
1013
1339
  const transparentSnap = makeTransparentSnap({
1014
1340
  transparent: true,
1015
1341
  materialShaderId: 'forgeax::unlit-test',
1016
1342
  });
1017
- const split = mod.computeSplitLdrSprite([makeValidatedEntry(transparentSnap)], true);
1343
+ const split = spriteMod.computeSplitLdrSprite([makeValidatedEntry(transparentSnap)], true);
1018
1344
  expect(split).toBe(false);
1019
1345
  });
1020
1346
 
1021
1347
  it('M3 / w13: legacy sprite material without transparent:true does NOT trigger split (union arm deleted)', () => {
1022
- if (typeof mod.computeSplitLdrSprite !== 'function') {
1348
+ if (typeof spriteMod.computeSplitLdrSprite !== 'function') {
1023
1349
  throw new Error('computeSplitLdrSprite helper not exported yet (red phase)');
1024
1350
  }
1025
1351
  // feat-20260625-refactor-sprite-as-transparent-mesh M3 / w13 (D-3):
@@ -1035,7 +1361,7 @@ describe('derived material record stop-draw (w28)', () => {
1035
1361
  materialShaderId: 'forgeax::sprite',
1036
1362
  paramSnapshot: {},
1037
1363
  } as unknown as MaterialSnapshot;
1038
- const splitWithoutTransparent = mod.computeSplitLdrSprite(
1364
+ const splitWithoutTransparent = spriteMod.computeSplitLdrSprite(
1039
1365
  [makeValidatedEntry(legacySpriteNoTransparent)],
1040
1366
  false,
1041
1367
  );
@@ -1047,7 +1373,7 @@ describe('derived material record stop-draw (w28)', () => {
1047
1373
  ...legacySpriteNoTransparent,
1048
1374
  transparent: true,
1049
1375
  } as unknown as MaterialSnapshot;
1050
- const splitWithTransparent = mod.computeSplitLdrSprite(
1376
+ const splitWithTransparent = spriteMod.computeSplitLdrSprite(
1051
1377
  [makeValidatedEntry(spriteTransparent)],
1052
1378
  false,
1053
1379
  );
@@ -1074,7 +1400,7 @@ describe('derived material record stop-draw (w28)', () => {
1074
1400
  // material[0] is opaque (the crosswalk case: opaque road submesh[0] +
1075
1401
  // BLEND decal submesh[1] on one multi-material mesh).
1076
1402
  it('per-submesh: split trips when only a non-zero submesh is transparent', () => {
1077
- if (typeof mod.computeSplitLdrSprite !== 'function') {
1403
+ if (typeof spriteMod.computeSplitLdrSprite !== 'function') {
1078
1404
  throw new Error('computeSplitLdrSprite helper not exported yet');
1079
1405
  }
1080
1406
  const opaque0 = makeTransparentSnap({
@@ -1089,11 +1415,11 @@ describe('derived material record stop-draw (w28)', () => {
1089
1415
  const mixedEntry: DispatchEntryLike = {
1090
1416
  source: { material: opaque0, materials: [opaque0, transparent1] },
1091
1417
  };
1092
- expect(mod.computeSplitLdrSprite([mixedEntry], false)).toBe(true);
1418
+ expect(spriteMod.computeSplitLdrSprite([mixedEntry], false)).toBe(true);
1093
1419
  });
1094
1420
 
1095
1421
  it('per-submesh: split stays false when every submesh material is opaque', () => {
1096
- if (typeof mod.computeSplitLdrSprite !== 'function') {
1422
+ if (typeof spriteMod.computeSplitLdrSprite !== 'function') {
1097
1423
  throw new Error('computeSplitLdrSprite helper not exported yet');
1098
1424
  }
1099
1425
  const opaque0 = makeTransparentSnap({
@@ -1107,7 +1433,7 @@ describe('derived material record stop-draw (w28)', () => {
1107
1433
  const opaqueMixed: DispatchEntryLike = {
1108
1434
  source: { material: opaque0, materials: [opaque0, opaque1] },
1109
1435
  };
1110
- expect(mod.computeSplitLdrSprite([opaqueMixed], false)).toBe(false);
1436
+ expect(spriteMod.computeSplitLdrSprite([opaqueMixed], false)).toBe(false);
1111
1437
  });
1112
1438
 
1113
1439
  it('isEntityFullyTransparent / entityHasTransparentSubmesh classify mixed meshes', () => {
@@ -1136,169 +1462,6 @@ describe('derived material record stop-draw (w28)', () => {
1136
1462
  });
1137
1463
  }
1138
1464
 
1139
- // --- from feat-20260625-refactor-sprite-as-transparent-mesh M2 / w5 ---
1140
- {
1141
- // AC-14: a transparent material whose target shader pipeline is not yet
1142
- // cached must surface a structured RhiError (.code / .expected / .hint),
1143
- // NOT silently fall back to the debug-pink placeholder. The generic
1144
- // materialShaderId path is the only resolver -- post feat-20260625 M3 / w14
1145
- // the dedicated sprite PSO fields are gone; sprite uses the same generic
1146
- // getMaterialShaderPipeline path every transparent material consumes.
1147
- //
1148
- // The helper signature added by w7:
1149
- //
1150
- // selectMaterialPipelineForRender({
1151
- // materialShaderId, isHdr, renderState, topology, indexFormat,
1152
- // variantSet, sampleCount,
1153
- // getMaterialShaderPipeline, // injected at call site (runtime.getMaterialShaderPipeline)
1154
- // }): Result<RenderPipeline, RhiError>
1155
- //
1156
- // Plan anchors:
1157
- // - requirements AC-14 (structured RhiError, no debug-pink fall-through)
1158
- // - plan-strategy section 8.3 (error info AI users consume via property
1159
- // access: .code / .expected / .hint; charter P3 explicit failure)
1160
- // - plan-strategy section 2 D-3 (transparent flows through the generic
1161
- // materialShaderId path; the resolver therefore never branches on
1162
- // 'forgeax::sprite' to recover)
1163
-
1164
- type SelectArgs = {
1165
- readonly materialShaderId: string;
1166
- readonly isHdr: boolean;
1167
- readonly renderState: {
1168
- readonly blend?: {
1169
- readonly color: { readonly srcFactor: string; readonly dstFactor: string };
1170
- readonly alpha: { readonly srcFactor: string; readonly dstFactor: string };
1171
- };
1172
- };
1173
- readonly topology: 'triangle-list' | 'triangle-strip';
1174
- readonly indexFormat: 'uint16' | 'uint32';
1175
- readonly variantSet: string;
1176
- readonly sampleCount: number;
1177
- readonly getMaterialShaderPipeline: (
1178
- materialShaderId: string,
1179
- isHdr: boolean,
1180
- ) => unknown | null;
1181
- };
1182
-
1183
- const mod = recordModule as unknown as {
1184
- selectMaterialPipelineForRender?: (
1185
- args: SelectArgs,
1186
- ) =>
1187
- | { readonly ok: true; readonly value: unknown }
1188
- | { readonly ok: false; readonly error: { code: string; expected: string; hint: string } };
1189
- };
1190
-
1191
- function makeSelectArgs(overrides: {
1192
- materialShaderId?: string;
1193
- getter?: SelectArgs['getMaterialShaderPipeline'];
1194
- }): SelectArgs {
1195
- const pipelineStub = { __pipeline: true };
1196
- return {
1197
- materialShaderId: overrides.materialShaderId ?? 'forgeax::unlit-test',
1198
- isHdr: false,
1199
- renderState: {
1200
- blend: {
1201
- color: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },
1202
- alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },
1203
- },
1204
- },
1205
- topology: 'triangle-list',
1206
- indexFormat: 'uint16',
1207
- variantSet: '',
1208
- sampleCount: 1,
1209
- getMaterialShaderPipeline: overrides.getter ?? (() => pipelineStub),
1210
- };
1211
- }
1212
-
1213
- describe('selectMaterialPipelineForRender pipeline-miss surfaces RhiError (M2 / w5, AC-14)', () => {
1214
- it('export: selectMaterialPipelineForRender helper is exported from render-system-record', () => {
1215
- expect(typeof mod.selectMaterialPipelineForRender).toBe('function');
1216
- });
1217
-
1218
- it('cache miss returns ok=false with structured RhiError (.code/.expected/.hint)', () => {
1219
- if (typeof mod.selectMaterialPipelineForRender !== 'function') {
1220
- throw new Error('selectMaterialPipelineForRender helper not exported yet (red phase)');
1221
- }
1222
- const result = mod.selectMaterialPipelineForRender(
1223
- makeSelectArgs({
1224
- materialShaderId: 'forgeax::unlit-test',
1225
- getter: () => null, // simulate cache miss / async build pending
1226
- }),
1227
- );
1228
- expect(result.ok).toBe(false);
1229
- if (result.ok) throw new Error('unreachable -- result.ok asserted false above');
1230
- const err = result.error;
1231
- // charter P3 -- AI users branch on .code (string union member from
1232
- // RhiErrorCode) and consume .expected / .hint as property reads;
1233
- // they do NOT parse the human-facing .message string.
1234
- expect(typeof err.code).toBe('string');
1235
- expect(err.code.length).toBeGreaterThan(0);
1236
- expect(typeof err.expected).toBe('string');
1237
- expect(err.expected.length).toBeGreaterThan(0);
1238
- expect(typeof err.hint).toBe('string');
1239
- expect(err.hint.length).toBeGreaterThan(0);
1240
- });
1241
-
1242
- it('cache miss .hint references the missing materialShaderId (AI users locate the cache key)', () => {
1243
- if (typeof mod.selectMaterialPipelineForRender !== 'function') {
1244
- throw new Error('selectMaterialPipelineForRender helper not exported yet (red phase)');
1245
- }
1246
- const result = mod.selectMaterialPipelineForRender(
1247
- makeSelectArgs({
1248
- materialShaderId: 'forgeax::missing-shader-id',
1249
- getter: () => null,
1250
- }),
1251
- );
1252
- expect(result.ok).toBe(false);
1253
- if (result.ok) throw new Error('unreachable -- result.ok asserted false above');
1254
- // The shader id must appear in .hint (or .expected) so AI users can
1255
- // grep the registry / pipeline cache straight from the structured
1256
- // error -- not from a human-prose substring of .message.
1257
- const exposed = `${result.error.hint} ${result.error.expected}`;
1258
- expect(exposed).toContain('forgeax::missing-shader-id');
1259
- });
1260
-
1261
- it('cache hit returns ok=true with the pipeline (no error path on success)', () => {
1262
- if (typeof mod.selectMaterialPipelineForRender !== 'function') {
1263
- throw new Error('selectMaterialPipelineForRender helper not exported yet (red phase)');
1264
- }
1265
- const pipeline = { __pipeline: 'forgeax::unlit-test-pso' };
1266
- const result = mod.selectMaterialPipelineForRender(
1267
- makeSelectArgs({
1268
- materialShaderId: 'forgeax::unlit-test',
1269
- getter: () => pipeline,
1270
- }),
1271
- );
1272
- expect(result.ok).toBe(true);
1273
- if (!result.ok) throw new Error('unreachable -- result.ok asserted true above');
1274
- expect(result.value).toBe(pipeline);
1275
- });
1276
-
1277
- it('cache miss does NOT silently substitute a debug-pink fallback pipeline', () => {
1278
- if (typeof mod.selectMaterialPipelineForRender !== 'function') {
1279
- throw new Error('selectMaterialPipelineForRender helper not exported yet (red phase)');
1280
- }
1281
- // Probe: the only branch the getter ever returns is the one passed in.
1282
- // A cache miss must surface ok=false, NOT a synthesized pipeline value
1283
- // that hides the miss (charter P3 -- the pre-M6 silent fallback to
1284
- // pipelineState.standardPipeline* was exactly this anti-pattern, see
1285
- // render-system-record.ts:5188-5198 commentary).
1286
- let getterCallCount = 0;
1287
- const result = mod.selectMaterialPipelineForRender(
1288
- makeSelectArgs({
1289
- materialShaderId: 'forgeax::unlit-test',
1290
- getter: () => {
1291
- getterCallCount += 1;
1292
- return null;
1293
- },
1294
- }),
1295
- );
1296
- expect(getterCallCount).toBeGreaterThanOrEqual(1);
1297
- expect(result.ok).toBe(false);
1298
- });
1299
- });
1300
- }
1301
-
1302
1465
  // ─── bug-20260622-tilemap-ysort-transparent-sort-modes-followup M2 m2-1 ───
1303
1466
  //
1304
1467
  // AC-04 (error signal SSOT) + AC-05 (LAYER_Y footY ordering) + R-2
@@ -1316,7 +1479,7 @@ describe('derived material record stop-draw (w28)', () => {
1316
1479
  describe('AC-04 setTransparentSortConfig mode=99 returns Result.err (KV untouched)', () => {
1317
1480
  it('Result.err carries code/expected/hint/detail + KV resource is NOT inserted', async () => {
1318
1481
  const { setTransparentSortConfig, TRANSPARENT_SORT_CONFIG_KEY } = await import(
1319
- '@forgeax/engine-render/internal'
1482
+ '../../../render/src/systems/transparent-sort-config'
1320
1483
  );
1321
1484
  const world = new World();
1322
1485
  // Pre-check: resource MUST be absent before the rejected call.
@@ -1343,7 +1506,7 @@ describe('derived material record stop-draw (w28)', () => {
1343
1506
  describe('AC-05 LAYER_Y footY ordering (same layer, deeper foot draws later)', () => {
1344
1507
  it('footY=10/20/30 same layer -> output order footY=30/20/10 (back-to-front)', async () => {
1345
1508
  const { setTransparentSortConfig, TRANSPARENT_SORT_MODE_LAYER_Y } = await import(
1346
- '@forgeax/engine-render/internal'
1509
+ '../../../render/src/systems/transparent-sort-config'
1347
1510
  );
1348
1511
  const { transparentSortEntries } = await import('../systems/transparent-sort');
1349
1512
  const world = new World();
@@ -1403,7 +1566,7 @@ describe('derived material record stop-draw (w28)', () => {
1403
1566
  describe('R-2 mode=DISTANCE + cameraPos absent preserves insertion order', () => {
1404
1567
  it('transparentSortEntries(entries, world) with mode=3 + no cameraPos = insertion order', async () => {
1405
1568
  const { setTransparentSortConfig, TRANSPARENT_SORT_MODE_DISTANCE } = await import(
1406
- '@forgeax/engine-render/internal'
1569
+ '../../../render/src/systems/transparent-sort-config'
1407
1570
  );
1408
1571
  const { transparentSortEntries } = await import('../systems/transparent-sort');
1409
1572
  const world = new World();