@adobe/data-gpu 0.9.69

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 (584) hide show
  1. package/CLAUDE.md +98 -0
  2. package/LICENSE +21 -0
  3. package/dist/core/core-plugin.d.ts +44 -0
  4. package/dist/core/core-plugin.js +90 -0
  5. package/dist/core/core-plugin.js.map +1 -0
  6. package/dist/core/frame-time/frame-time-plugin.d.ts +25 -0
  7. package/dist/core/frame-time/frame-time-plugin.js +41 -0
  8. package/dist/core/frame-time/frame-time-plugin.js.map +1 -0
  9. package/dist/core/frame-time/frame-time.d.ts +18 -0
  10. package/dist/core/frame-time/frame-time.js +3 -0
  11. package/dist/core/frame-time/frame-time.js.map +1 -0
  12. package/dist/core/frame-time/public.d.ts +1 -0
  13. package/dist/core/frame-time/public.js +3 -0
  14. package/dist/core/frame-time/public.js.map +1 -0
  15. package/dist/graphics/animation/animation-data-plugin.d.ts +216 -0
  16. package/dist/graphics/animation/animation-data-plugin.js +110 -0
  17. package/dist/graphics/animation/animation-data-plugin.js.map +1 -0
  18. package/dist/graphics/animation/animation-plugin.d.ts +214 -0
  19. package/dist/graphics/animation/animation-plugin.js +26 -0
  20. package/dist/graphics/animation/animation-plugin.js.map +1 -0
  21. package/dist/graphics/animation/animation-plugin.test.d.ts +1 -0
  22. package/dist/graphics/animation/animation-plugin.test.js +142 -0
  23. package/dist/graphics/animation/animation-plugin.test.js.map +1 -0
  24. package/dist/graphics/animation/animation-track/animation-track.d.ts +13 -0
  25. package/dist/graphics/animation/animation-track/animation-track.js +3 -0
  26. package/dist/graphics/animation/animation-track/animation-track.js.map +1 -0
  27. package/dist/graphics/animation/animation-track/componentwise-lerp.d.ts +7 -0
  28. package/dist/graphics/animation/animation-track/componentwise-lerp.js +22 -0
  29. package/dist/graphics/animation/animation-track/componentwise-lerp.js.map +1 -0
  30. package/dist/graphics/animation/animation-track/interpolate.d.ts +8 -0
  31. package/dist/graphics/animation/animation-track/interpolate.js +18 -0
  32. package/dist/graphics/animation/animation-track/interpolate.js.map +1 -0
  33. package/dist/graphics/animation/animation-track/public.d.ts +1 -0
  34. package/dist/graphics/animation/animation-track/public.js +3 -0
  35. package/dist/graphics/animation/animation-track/public.js.map +1 -0
  36. package/dist/graphics/animation/animation-track/sample.d.ts +7 -0
  37. package/dist/graphics/animation/animation-track/sample.js +44 -0
  38. package/dist/graphics/animation/animation-track/sample.js.map +1 -0
  39. package/dist/graphics/animation/interpolation-mode/interpolation-mode.d.ts +4 -0
  40. package/dist/graphics/animation/interpolation-mode/interpolation-mode.js +3 -0
  41. package/dist/graphics/animation/interpolation-mode/interpolation-mode.js.map +1 -0
  42. package/dist/graphics/animation/interpolation-mode/public.d.ts +1 -0
  43. package/dist/graphics/animation/interpolation-mode/public.js +3 -0
  44. package/dist/graphics/animation/interpolation-mode/public.js.map +1 -0
  45. package/dist/graphics/animation/interpolation-mode/schema.d.ts +4 -0
  46. package/dist/graphics/animation/interpolation-mode/schema.js +3 -0
  47. package/dist/graphics/animation/interpolation-mode/schema.js.map +1 -0
  48. package/dist/graphics/camera/camera-plugin.d.ts +112 -0
  49. package/dist/graphics/camera/camera-plugin.js +36 -0
  50. package/dist/graphics/camera/camera-plugin.js.map +1 -0
  51. package/dist/graphics/camera/camera.d.ts +4 -0
  52. package/dist/graphics/camera/camera.js +3 -0
  53. package/dist/graphics/camera/camera.js.map +1 -0
  54. package/dist/graphics/camera/orbit/attach-orbit-drag.d.ts +31 -0
  55. package/dist/graphics/camera/orbit/attach-orbit-drag.js +44 -0
  56. package/dist/graphics/camera/orbit/attach-orbit-drag.js.map +1 -0
  57. package/dist/graphics/camera/orbit/orbit-data-plugin.d.ts +290 -0
  58. package/dist/graphics/camera/orbit/orbit-data-plugin.js +42 -0
  59. package/dist/graphics/camera/orbit/orbit-data-plugin.js.map +1 -0
  60. package/dist/graphics/camera/orbit/orbit-plugin.d.ts +281 -0
  61. package/dist/graphics/camera/orbit/orbit-plugin.js +12 -0
  62. package/dist/graphics/camera/orbit/orbit-plugin.js.map +1 -0
  63. package/dist/graphics/camera/orbit/orbit-system-plugin.d.ts +292 -0
  64. package/dist/graphics/camera/orbit/orbit-system-plugin.js +71 -0
  65. package/dist/graphics/camera/orbit/orbit-system-plugin.js.map +1 -0
  66. package/dist/graphics/camera/orbit/orbit.d.ts +32 -0
  67. package/dist/graphics/camera/orbit/orbit.js +3 -0
  68. package/dist/graphics/camera/orbit/orbit.js.map +1 -0
  69. package/dist/graphics/camera/orbit/public.d.ts +5 -0
  70. package/dist/graphics/camera/orbit/public.js +6 -0
  71. package/dist/graphics/camera/orbit/public.js.map +1 -0
  72. package/dist/graphics/camera/public.d.ts +4 -0
  73. package/dist/graphics/camera/public.js +6 -0
  74. package/dist/graphics/camera/public.js.map +1 -0
  75. package/dist/graphics/camera/schema.d.ts +65 -0
  76. package/dist/graphics/camera/schema.js +19 -0
  77. package/dist/graphics/camera/schema.js.map +1 -0
  78. package/dist/graphics/camera/screen-to-world-ray.d.ts +10 -0
  79. package/dist/graphics/camera/screen-to-world-ray.js +31 -0
  80. package/dist/graphics/camera/screen-to-world-ray.js.map +1 -0
  81. package/dist/graphics/camera/to-view-projection.d.ts +3 -0
  82. package/dist/graphics/camera/to-view-projection.js +23 -0
  83. package/dist/graphics/camera/to-view-projection.js.map +1 -0
  84. package/dist/graphics/graphics-plugin.d.ts +121 -0
  85. package/dist/graphics/graphics-plugin.js +106 -0
  86. package/dist/graphics/graphics-plugin.js.map +1 -0
  87. package/dist/graphics/picking/pick-hit.d.ts +10 -0
  88. package/dist/graphics/picking/pick-hit.js +3 -0
  89. package/dist/graphics/picking/pick-hit.js.map +1 -0
  90. package/dist/graphics/picking/picking-plugin.d.ts +3819 -0
  91. package/dist/graphics/picking/picking-plugin.js +88 -0
  92. package/dist/graphics/picking/picking-plugin.js.map +1 -0
  93. package/dist/graphics/rendering/bone-collider-plugin.d.ts +1619 -0
  94. package/dist/graphics/rendering/bone-collider-plugin.js +207 -0
  95. package/dist/graphics/rendering/bone-collider-plugin.js.map +1 -0
  96. package/dist/graphics/rendering/display-transform-plugin.d.ts +52 -0
  97. package/dist/graphics/rendering/display-transform-plugin.js +25 -0
  98. package/dist/graphics/rendering/display-transform-plugin.js.map +1 -0
  99. package/dist/graphics/rendering/ibl-render/brdf.wgsl.d.ts +2 -0
  100. package/dist/graphics/rendering/ibl-render/brdf.wgsl.js +42 -0
  101. package/dist/graphics/rendering/ibl-render/brdf.wgsl.js.map +1 -0
  102. package/dist/graphics/rendering/ibl-render/ibl/brdf-lut.d.ts +1 -0
  103. package/dist/graphics/rendering/ibl-render/ibl/brdf-lut.js +91 -0
  104. package/dist/graphics/rendering/ibl-render/ibl/brdf-lut.js.map +1 -0
  105. package/dist/graphics/rendering/ibl-render/ibl/build-ibl-resources.d.ts +24 -0
  106. package/dist/graphics/rendering/ibl-render/ibl/build-ibl-resources.js +34 -0
  107. package/dist/graphics/rendering/ibl-render/ibl/build-ibl-resources.js.map +1 -0
  108. package/dist/graphics/rendering/ibl-render/ibl/create-cubemap.d.ts +1 -0
  109. package/dist/graphics/rendering/ibl-render/ibl/create-cubemap.js +12 -0
  110. package/dist/graphics/rendering/ibl-render/ibl/create-cubemap.js.map +1 -0
  111. package/dist/graphics/rendering/ibl-render/ibl/cube-face-view.d.ts +1 -0
  112. package/dist/graphics/rendering/ibl-render/ibl/cube-face-view.js +11 -0
  113. package/dist/graphics/rendering/ibl-render/ibl/cube-face-view.js.map +1 -0
  114. package/dist/graphics/rendering/ibl-render/ibl/cubemap-sample-view.d.ts +1 -0
  115. package/dist/graphics/rendering/ibl-render/ibl/cubemap-sample-view.js +9 -0
  116. package/dist/graphics/rendering/ibl-render/ibl/cubemap-sample-view.js.map +1 -0
  117. package/dist/graphics/rendering/ibl-render/ibl/environment.d.ts +8 -0
  118. package/dist/graphics/rendering/ibl-render/ibl/environment.js +170 -0
  119. package/dist/graphics/rendering/ibl-render/ibl/environment.js.map +1 -0
  120. package/dist/graphics/rendering/ibl-render/ibl/float-to-half.d.ts +2 -0
  121. package/dist/graphics/rendering/ibl-render/ibl/float-to-half.js +32 -0
  122. package/dist/graphics/rendering/ibl-render/ibl/float-to-half.js.map +1 -0
  123. package/dist/graphics/rendering/ibl-render/ibl/ibl-math.wgsl.d.ts +2 -0
  124. package/dist/graphics/rendering/ibl-render/ibl/ibl-math.wgsl.js +59 -0
  125. package/dist/graphics/rendering/ibl-render/ibl/ibl-math.wgsl.js.map +1 -0
  126. package/dist/graphics/rendering/ibl-render/ibl/irradiance.d.ts +1 -0
  127. package/dist/graphics/rendering/ibl-render/ibl/irradiance.js +94 -0
  128. package/dist/graphics/rendering/ibl-render/ibl/irradiance.js.map +1 -0
  129. package/dist/graphics/rendering/ibl-render/ibl/parse-hdr.d.ts +6 -0
  130. package/dist/graphics/rendering/ibl-render/ibl/parse-hdr.js +106 -0
  131. package/dist/graphics/rendering/ibl-render/ibl/parse-hdr.js.map +1 -0
  132. package/dist/graphics/rendering/ibl-render/ibl/prefilter.d.ts +5 -0
  133. package/dist/graphics/rendering/ibl-render/ibl/prefilter.js +103 -0
  134. package/dist/graphics/rendering/ibl-render/ibl/prefilter.js.map +1 -0
  135. package/dist/graphics/rendering/ibl-render/ibl/render-helpers.d.ts +4 -0
  136. package/dist/graphics/rendering/ibl-render/ibl/render-helpers.js +16 -0
  137. package/dist/graphics/rendering/ibl-render/ibl/render-helpers.js.map +1 -0
  138. package/dist/graphics/rendering/ibl-render/ibl-render-plugin.d.ts +1028 -0
  139. package/dist/graphics/rendering/ibl-render/ibl-render-plugin.js +409 -0
  140. package/dist/graphics/rendering/ibl-render/ibl-render-plugin.js.map +1 -0
  141. package/dist/graphics/rendering/ibl-render/ibl-shader.wgsl.d.ts +8 -0
  142. package/dist/graphics/rendering/ibl-render/ibl-shader.wgsl.js +173 -0
  143. package/dist/graphics/rendering/ibl-render/ibl-shader.wgsl.js.map +1 -0
  144. package/dist/graphics/rendering/ibl-render/skybox-shader.wgsl.d.ts +2 -0
  145. package/dist/graphics/rendering/ibl-render/skybox-shader.wgsl.js +50 -0
  146. package/dist/graphics/rendering/ibl-render/skybox-shader.wgsl.js.map +1 -0
  147. package/dist/graphics/rendering/interpolation-plugin.d.ts +485 -0
  148. package/dist/graphics/rendering/interpolation-plugin.js +98 -0
  149. package/dist/graphics/rendering/interpolation-plugin.js.map +1 -0
  150. package/dist/graphics/rendering/interpolation.test.d.ts +1 -0
  151. package/dist/graphics/rendering/interpolation.test.js +38 -0
  152. package/dist/graphics/rendering/interpolation.test.js.map +1 -0
  153. package/dist/graphics/rendering/jolt-ragdoll-plugin.d.ts +1628 -0
  154. package/dist/graphics/rendering/jolt-ragdoll-plugin.js +218 -0
  155. package/dist/graphics/rendering/jolt-ragdoll-plugin.js.map +1 -0
  156. package/dist/graphics/rendering/material-gpu/material-arrays.d.ts +47 -0
  157. package/dist/graphics/rendering/material-gpu/material-arrays.js +83 -0
  158. package/dist/graphics/rendering/material-gpu/material-arrays.js.map +1 -0
  159. package/dist/graphics/rendering/material-gpu/material-bind-group.d.ts +9 -0
  160. package/dist/graphics/rendering/material-gpu/material-bind-group.js +52 -0
  161. package/dist/graphics/rendering/material-gpu/material-bind-group.js.map +1 -0
  162. package/dist/graphics/rendering/material-gpu/material-gpu-plugin.d.ts +259 -0
  163. package/dist/graphics/rendering/material-gpu/material-gpu-plugin.js +90 -0
  164. package/dist/graphics/rendering/material-gpu/material-gpu-plugin.js.map +1 -0
  165. package/dist/graphics/rendering/model-collider-plugin.d.ts +1232 -0
  166. package/dist/graphics/rendering/model-collider-plugin.js +81 -0
  167. package/dist/graphics/rendering/model-collider-plugin.js.map +1 -0
  168. package/dist/graphics/rendering/pbr-core-plugin.d.ts +75 -0
  169. package/dist/graphics/rendering/pbr-core-plugin.js +39 -0
  170. package/dist/graphics/rendering/pbr-core-plugin.js.map +1 -0
  171. package/dist/graphics/rendering/pbr-render/pbr-array-shader.wgsl.d.ts +10 -0
  172. package/dist/graphics/rendering/pbr-render/pbr-array-shader.wgsl.js +145 -0
  173. package/dist/graphics/rendering/pbr-render/pbr-array-shader.wgsl.js.map +1 -0
  174. package/dist/graphics/rendering/pbr-render/pbr-render-plugin.d.ts +1266 -0
  175. package/dist/graphics/rendering/pbr-render/pbr-render-plugin.js +254 -0
  176. package/dist/graphics/rendering/pbr-render/pbr-render-plugin.js.map +1 -0
  177. package/dist/graphics/rendering/pbr-render/physics-bridge-plugin.d.ts +1004 -0
  178. package/dist/graphics/rendering/pbr-render/physics-bridge-plugin.js +116 -0
  179. package/dist/graphics/rendering/pbr-render/physics-bridge-plugin.js.map +1 -0
  180. package/dist/graphics/rendering/ragdoll-trigger-plugin.d.ts +31 -0
  181. package/dist/graphics/rendering/ragdoll-trigger-plugin.js +20 -0
  182. package/dist/graphics/rendering/ragdoll-trigger-plugin.js.map +1 -0
  183. package/dist/graphics/rendering/rendering-plugin.d.ts +1 -0
  184. package/dist/graphics/rendering/rendering-plugin.js +3 -0
  185. package/dist/graphics/rendering/rendering-plugin.js.map +1 -0
  186. package/dist/graphics/rendering/skinning/skinning-attributes/layout.d.ts +2 -0
  187. package/dist/graphics/rendering/skinning/skinning-attributes/layout.js +18 -0
  188. package/dist/graphics/rendering/skinning/skinning-attributes/layout.js.map +1 -0
  189. package/dist/graphics/rendering/skinning/skinning-attributes/public.d.ts +1 -0
  190. package/dist/graphics/rendering/skinning/skinning-attributes/public.js +3 -0
  191. package/dist/graphics/rendering/skinning/skinning-attributes/public.js.map +1 -0
  192. package/dist/graphics/rendering/skinning/skinning-attributes/skinning-attributes.d.ts +1 -0
  193. package/dist/graphics/rendering/skinning/skinning-attributes/skinning-attributes.js +3 -0
  194. package/dist/graphics/rendering/skinning/skinning-attributes/skinning-attributes.js.map +1 -0
  195. package/dist/graphics/rendering/skinning/skinning-plugin.d.ts +1212 -0
  196. package/dist/graphics/rendering/skinning/skinning-plugin.js +207 -0
  197. package/dist/graphics/rendering/skinning/skinning-plugin.js.map +1 -0
  198. package/dist/graphics/rendering/standard-vertex/layout.d.ts +2 -0
  199. package/dist/graphics/rendering/standard-vertex/layout.js +16 -0
  200. package/dist/graphics/rendering/standard-vertex/layout.js.map +1 -0
  201. package/dist/graphics/rendering/standard-vertex/public.d.ts +2 -0
  202. package/dist/graphics/rendering/standard-vertex/public.js +4 -0
  203. package/dist/graphics/rendering/standard-vertex/public.js.map +1 -0
  204. package/dist/graphics/rendering/standard-vertex/schema.d.ts +52 -0
  205. package/dist/graphics/rendering/standard-vertex/schema.js +15 -0
  206. package/dist/graphics/rendering/standard-vertex/schema.js.map +1 -0
  207. package/dist/graphics/rendering/standard-vertex/standard-vertex.d.ts +4 -0
  208. package/dist/graphics/rendering/standard-vertex/standard-vertex.js +3 -0
  209. package/dist/graphics/rendering/standard-vertex/standard-vertex.js.map +1 -0
  210. package/dist/graphics/rendering/visible-material/color-material-options.d.ts +7 -0
  211. package/dist/graphics/rendering/visible-material/color-material-options.js +3 -0
  212. package/dist/graphics/rendering/visible-material/color-material-options.js.map +1 -0
  213. package/dist/graphics/rendering/visible-material/create-bind-group-layout.d.ts +8 -0
  214. package/dist/graphics/rendering/visible-material/create-bind-group-layout.js +35 -0
  215. package/dist/graphics/rendering/visible-material/create-bind-group-layout.js.map +1 -0
  216. package/dist/graphics/rendering/visible-material/create-color-bind-group.d.ts +10 -0
  217. package/dist/graphics/rendering/visible-material/create-color-bind-group.js +26 -0
  218. package/dist/graphics/rendering/visible-material/create-color-bind-group.js.map +1 -0
  219. package/dist/graphics/rendering/visible-material/public.d.ts +4 -0
  220. package/dist/graphics/rendering/visible-material/public.js +5 -0
  221. package/dist/graphics/rendering/visible-material/public.js.map +1 -0
  222. package/dist/graphics/rendering/visible-material/schema.d.ts +49 -0
  223. package/dist/graphics/rendering/visible-material/schema.js +23 -0
  224. package/dist/graphics/rendering/visible-material/schema.js.map +1 -0
  225. package/dist/graphics/rendering/visible-material/visible-material.d.ts +4 -0
  226. package/dist/graphics/rendering/visible-material/visible-material.js +3 -0
  227. package/dist/graphics/rendering/visible-material/visible-material.js.map +1 -0
  228. package/dist/graphics/scene/light/light-plugin.d.ts +30 -0
  229. package/dist/graphics/scene/light/light-plugin.js +35 -0
  230. package/dist/graphics/scene/light/light-plugin.js.map +1 -0
  231. package/dist/graphics/scene/light/light.d.ts +14 -0
  232. package/dist/graphics/scene/light/light.js +3 -0
  233. package/dist/graphics/scene/light/light.js.map +1 -0
  234. package/dist/graphics/scene/light/public.d.ts +1 -0
  235. package/dist/graphics/scene/light/public.js +2 -0
  236. package/dist/graphics/scene/light/public.js.map +1 -0
  237. package/dist/graphics/scene/model/geometry/geometry.d.ts +9 -0
  238. package/dist/graphics/scene/model/geometry/geometry.js +3 -0
  239. package/dist/graphics/scene/model/geometry/geometry.js.map +1 -0
  240. package/dist/graphics/scene/model/geometry/public.d.ts +1 -0
  241. package/dist/graphics/scene/model/geometry/public.js +3 -0
  242. package/dist/graphics/scene/model/geometry/public.js.map +1 -0
  243. package/dist/graphics/scene/model/gltf/accessor-view.d.ts +9 -0
  244. package/dist/graphics/scene/model/gltf/accessor-view.js +44 -0
  245. package/dist/graphics/scene/model/gltf/accessor-view.js.map +1 -0
  246. package/dist/graphics/scene/model/gltf/build-material-bind-group.d.ts +22 -0
  247. package/dist/graphics/scene/model/gltf/build-material-bind-group.js +75 -0
  248. package/dist/graphics/scene/model/gltf/build-material-bind-group.js.map +1 -0
  249. package/dist/graphics/scene/model/gltf/compute-world-matrices.d.ts +7 -0
  250. package/dist/graphics/scene/model/gltf/compute-world-matrices.js +38 -0
  251. package/dist/graphics/scene/model/gltf/compute-world-matrices.js.map +1 -0
  252. package/dist/graphics/scene/model/gltf/create-color-material.d.ts +3 -0
  253. package/dist/graphics/scene/model/gltf/create-color-material.js +34 -0
  254. package/dist/graphics/scene/model/gltf/create-color-material.js.map +1 -0
  255. package/dist/graphics/scene/model/gltf/decode-images.d.ts +12 -0
  256. package/dist/graphics/scene/model/gltf/decode-images.js +68 -0
  257. package/dist/graphics/scene/model/gltf/decode-images.js.map +1 -0
  258. package/dist/graphics/scene/model/gltf/gltf-schema.d.ts +152 -0
  259. package/dist/graphics/scene/model/gltf/gltf-schema.js +20 -0
  260. package/dist/graphics/scene/model/gltf/gltf-schema.js.map +1 -0
  261. package/dist/graphics/scene/model/gltf/load-gltf-model.d.ts +42 -0
  262. package/dist/graphics/scene/model/gltf/load-gltf-model.js +175 -0
  263. package/dist/graphics/scene/model/gltf/load-gltf-model.js.map +1 -0
  264. package/dist/graphics/scene/model/gltf/pack-vertex-buffer.d.ts +21 -0
  265. package/dist/graphics/scene/model/gltf/pack-vertex-buffer.js +106 -0
  266. package/dist/graphics/scene/model/gltf/pack-vertex-buffer.js.map +1 -0
  267. package/dist/graphics/scene/model/gltf/parse-animations.d.ts +18 -0
  268. package/dist/graphics/scene/model/gltf/parse-animations.js +51 -0
  269. package/dist/graphics/scene/model/gltf/parse-animations.js.map +1 -0
  270. package/dist/graphics/scene/model/gltf/parse-glb.d.ts +6 -0
  271. package/dist/graphics/scene/model/gltf/parse-glb.js +40 -0
  272. package/dist/graphics/scene/model/gltf/parse-glb.js.map +1 -0
  273. package/dist/graphics/scene/model/gltf/parse-skin.d.ts +19 -0
  274. package/dist/graphics/scene/model/gltf/parse-skin.js +43 -0
  275. package/dist/graphics/scene/model/gltf/parse-skin.js.map +1 -0
  276. package/dist/graphics/scene/model/model-loader-plugin.d.ts +922 -0
  277. package/dist/graphics/scene/model/model-loader-plugin.js +120 -0
  278. package/dist/graphics/scene/model/model-loader-plugin.js.map +1 -0
  279. package/dist/graphics/scene/model/model-plugin.d.ts +352 -0
  280. package/dist/graphics/scene/model/model-plugin.js +39 -0
  281. package/dist/graphics/scene/model/model-plugin.js.map +1 -0
  282. package/dist/graphics/scene/model/model.d.ts +11 -0
  283. package/dist/graphics/scene/model/model.js +3 -0
  284. package/dist/graphics/scene/model/model.js.map +1 -0
  285. package/dist/graphics/scene/model/public.d.ts +1 -0
  286. package/dist/graphics/scene/model/public.js +2 -0
  287. package/dist/graphics/scene/model/public.js.map +1 -0
  288. package/dist/graphics/scene/model/shape/convex-hull.d.ts +36 -0
  289. package/dist/graphics/scene/model/shape/convex-hull.js +152 -0
  290. package/dist/graphics/scene/model/shape/convex-hull.js.map +1 -0
  291. package/dist/graphics/scene/model/shape/convex-hull.test.d.ts +1 -0
  292. package/dist/graphics/scene/model/shape/convex-hull.test.js +78 -0
  293. package/dist/graphics/scene/model/shape/convex-hull.test.js.map +1 -0
  294. package/dist/graphics/scene/model/shape/shape-geometry-plugin.d.ts +631 -0
  295. package/dist/graphics/scene/model/shape/shape-geometry-plugin.js +61 -0
  296. package/dist/graphics/scene/model/shape/shape-geometry-plugin.js.map +1 -0
  297. package/dist/graphics/scene/model/shape/shape-mesh.d.ts +34 -0
  298. package/dist/graphics/scene/model/shape/shape-mesh.js +142 -0
  299. package/dist/graphics/scene/model/shape/shape-mesh.js.map +1 -0
  300. package/dist/graphics/scene/model/shape/upload-shape-mesh.d.ts +9 -0
  301. package/dist/graphics/scene/model/shape/upload-shape-mesh.js +12 -0
  302. package/dist/graphics/scene/model/shape/upload-shape-mesh.js.map +1 -0
  303. package/dist/graphics/scene/model/world-bounds-plugin.d.ts +909 -0
  304. package/dist/graphics/scene/model/world-bounds-plugin.js +93 -0
  305. package/dist/graphics/scene/model/world-bounds-plugin.js.map +1 -0
  306. package/dist/graphics/scene/node/node-data-plugin.d.ts +113 -0
  307. package/dist/graphics/scene/node/node-data-plugin.js +27 -0
  308. package/dist/graphics/scene/node/node-data-plugin.js.map +1 -0
  309. package/dist/graphics/scene/node/node-plugin.d.ts +102 -0
  310. package/dist/graphics/scene/node/node-plugin.js +12 -0
  311. package/dist/graphics/scene/node/node-plugin.js.map +1 -0
  312. package/dist/graphics/scene/node/node.d.ts +19 -0
  313. package/dist/graphics/scene/node/node.js +3 -0
  314. package/dist/graphics/scene/node/node.js.map +1 -0
  315. package/dist/graphics/scene/node/public.d.ts +1 -0
  316. package/dist/graphics/scene/node/public.js +2 -0
  317. package/dist/graphics/scene/node/public.js.map +1 -0
  318. package/dist/graphics/scene/node/transform-plugin.d.ts +123 -0
  319. package/dist/graphics/scene/node/transform-plugin.js +65 -0
  320. package/dist/graphics/scene/node/transform-plugin.js.map +1 -0
  321. package/dist/graphics/scene/scene-plugin.d.ts +461 -0
  322. package/dist/graphics/scene/scene-plugin.js +19 -0
  323. package/dist/graphics/scene/scene-plugin.js.map +1 -0
  324. package/dist/graphics/scene/scene-uniforms/create-bind-group-layout.d.ts +7 -0
  325. package/dist/graphics/scene/scene-uniforms/create-bind-group-layout.js +19 -0
  326. package/dist/graphics/scene/scene-uniforms/create-bind-group-layout.js.map +1 -0
  327. package/dist/graphics/scene/scene-uniforms/public.d.ts +3 -0
  328. package/dist/graphics/scene/scene-uniforms/public.js +5 -0
  329. package/dist/graphics/scene/scene-uniforms/public.js.map +1 -0
  330. package/dist/graphics/scene/scene-uniforms/scene-uniforms-plugin.d.ts +137 -0
  331. package/dist/graphics/scene/scene-uniforms/scene-uniforms-plugin.js +59 -0
  332. package/dist/graphics/scene/scene-uniforms/scene-uniforms-plugin.js.map +1 -0
  333. package/dist/graphics/scene/scene-uniforms/scene-uniforms.d.ts +11 -0
  334. package/dist/graphics/scene/scene-uniforms/scene-uniforms.js +3 -0
  335. package/dist/graphics/scene/scene-uniforms/scene-uniforms.js.map +1 -0
  336. package/dist/graphics/scene/scene-uniforms/schema.d.ts +56 -0
  337. package/dist/graphics/scene/scene-uniforms/schema.js +15 -0
  338. package/dist/graphics/scene/scene-uniforms/schema.js.map +1 -0
  339. package/dist/index.d.ts +53 -0
  340. package/dist/index.js +56 -0
  341. package/dist/index.js.map +1 -0
  342. package/dist/material/material-plugin.d.ts +221 -0
  343. package/dist/material/material-plugin.js +60 -0
  344. package/dist/material/material-plugin.js.map +1 -0
  345. package/dist/material/material.d.ts +31 -0
  346. package/dist/material/material.js +3 -0
  347. package/dist/material/material.js.map +1 -0
  348. package/dist/material/public.d.ts +2 -0
  349. package/dist/material/public.js +4 -0
  350. package/dist/material/public.js.map +1 -0
  351. package/dist/material/standard-materials.d.ts +3 -0
  352. package/dist/material/standard-materials.js +35 -0
  353. package/dist/material/standard-materials.js.map +1 -0
  354. package/dist/physics/body/body-type/body-type.d.ts +10 -0
  355. package/dist/physics/body/body-type/body-type.js +3 -0
  356. package/dist/physics/body/body-type/body-type.js.map +1 -0
  357. package/dist/physics/body/body-type/is-dynamic.d.ts +3 -0
  358. package/dist/physics/body/body-type/is-dynamic.js +6 -0
  359. package/dist/physics/body/body-type/is-dynamic.js.map +1 -0
  360. package/dist/physics/body/body-type/public.d.ts +2 -0
  361. package/dist/physics/body/body-type/public.js +4 -0
  362. package/dist/physics/body/body-type/public.js.map +1 -0
  363. package/dist/physics/body/body-type/schema.d.ts +4 -0
  364. package/dist/physics/body/body-type/schema.js +3 -0
  365. package/dist/physics/body/body-type/schema.js.map +1 -0
  366. package/dist/physics/body/collider-mesh.d.ts +11 -0
  367. package/dist/physics/body/collider-mesh.js +3 -0
  368. package/dist/physics/body/collider-mesh.js.map +1 -0
  369. package/dist/physics/body/collider-shape/collider-shape.d.ts +15 -0
  370. package/dist/physics/body/collider-shape/collider-shape.js +3 -0
  371. package/dist/physics/body/collider-shape/collider-shape.js.map +1 -0
  372. package/dist/physics/body/collider-shape/list.d.ts +3 -0
  373. package/dist/physics/body/collider-shape/list.js +5 -0
  374. package/dist/physics/body/collider-shape/list.js.map +1 -0
  375. package/dist/physics/body/collider-shape/mass-properties.d.ts +10 -0
  376. package/dist/physics/body/collider-shape/mass-properties.js +48 -0
  377. package/dist/physics/body/collider-shape/mass-properties.js.map +1 -0
  378. package/dist/physics/body/collider-shape/public.d.ts +4 -0
  379. package/dist/physics/body/collider-shape/public.js +6 -0
  380. package/dist/physics/body/collider-shape/public.js.map +1 -0
  381. package/dist/physics/body/collider-shape/schema.d.ts +4 -0
  382. package/dist/physics/body/collider-shape/schema.js +3 -0
  383. package/dist/physics/body/collider-shape/schema.js.map +1 -0
  384. package/dist/physics/body/collider-shape/to-index.d.ts +3 -0
  385. package/dist/physics/body/collider-shape/to-index.js +6 -0
  386. package/dist/physics/body/collider-shape/to-index.js.map +1 -0
  387. package/dist/physics/body/rigid-body.d.ts +23 -0
  388. package/dist/physics/body/rigid-body.js +3 -0
  389. package/dist/physics/body/rigid-body.js.map +1 -0
  390. package/dist/physics/body/static-collider.d.ts +25 -0
  391. package/dist/physics/body/static-collider.js +3 -0
  392. package/dist/physics/body/static-collider.js.map +1 -0
  393. package/dist/physics/joint/joint-plugin.d.ts +88 -0
  394. package/dist/physics/joint/joint-plugin.js +32 -0
  395. package/dist/physics/joint/joint-plugin.js.map +1 -0
  396. package/dist/physics/joint/joint-type/joint-type.d.ts +15 -0
  397. package/dist/physics/joint/joint-type/joint-type.js +3 -0
  398. package/dist/physics/joint/joint-type/joint-type.js.map +1 -0
  399. package/dist/physics/joint/joint-type/public.d.ts +1 -0
  400. package/dist/physics/joint/joint-type/public.js +3 -0
  401. package/dist/physics/joint/joint-type/public.js.map +1 -0
  402. package/dist/physics/joint/joint-type/schema.d.ts +4 -0
  403. package/dist/physics/joint/joint-type/schema.js +3 -0
  404. package/dist/physics/joint/joint-type/schema.js.map +1 -0
  405. package/dist/physics/joint/joint.d.ts +24 -0
  406. package/dist/physics/joint/joint.js +3 -0
  407. package/dist/physics/joint/joint.js.map +1 -0
  408. package/dist/physics/physics-clock-plugin.d.ts +86 -0
  409. package/dist/physics/physics-clock-plugin.js +37 -0
  410. package/dist/physics/physics-clock-plugin.js.map +1 -0
  411. package/dist/physics/physics-clock.test.d.ts +1 -0
  412. package/dist/physics/physics-clock.test.js +45 -0
  413. package/dist/physics/physics-clock.test.js.map +1 -0
  414. package/dist/physics/physics-data-plugin.d.ts +348 -0
  415. package/dist/physics/physics-data-plugin.js +71 -0
  416. package/dist/physics/physics-data-plugin.js.map +1 -0
  417. package/dist/physics/ragdoll/fit-bone-capsules.d.ts +39 -0
  418. package/dist/physics/ragdoll/fit-bone-capsules.js +87 -0
  419. package/dist/physics/ragdoll/fit-bone-capsules.js.map +1 -0
  420. package/dist/physics/ragdoll/fit-bone-capsules.test.d.ts +1 -0
  421. package/dist/physics/ragdoll/fit-bone-capsules.test.js +67 -0
  422. package/dist/physics/ragdoll/fit-bone-capsules.test.js.map +1 -0
  423. package/dist/physics/solvers/jolt-solver-plugin.d.ts +465 -0
  424. package/dist/physics/solvers/jolt-solver-plugin.js +440 -0
  425. package/dist/physics/solvers/jolt-solver-plugin.js.map +1 -0
  426. package/dist/physics/solvers/rapier-jolt.benchmark.test.d.ts +1 -0
  427. package/dist/physics/solvers/rapier-jolt.benchmark.test.js +35 -0
  428. package/dist/physics/solvers/rapier-jolt.benchmark.test.js.map +1 -0
  429. package/dist/physics/solvers/rapier-solver-plugin.d.ts +444 -0
  430. package/dist/physics/solvers/rapier-solver-plugin.js +284 -0
  431. package/dist/physics/solvers/rapier-solver-plugin.js.map +1 -0
  432. package/dist/physics/solvers/solver-benchmark.d.ts +45 -0
  433. package/dist/physics/solvers/solver-benchmark.js +115 -0
  434. package/dist/physics/solvers/solver-benchmark.js.map +1 -0
  435. package/package.json +34 -0
  436. package/src/core/core-plugin.ts +92 -0
  437. package/src/core/frame-time/frame-time-plugin.ts +44 -0
  438. package/src/core/frame-time/frame-time.ts +21 -0
  439. package/src/core/frame-time/public.ts +3 -0
  440. package/src/graphics/animation/animation-data-plugin.ts +119 -0
  441. package/src/graphics/animation/animation-plugin.test.ts +161 -0
  442. package/src/graphics/animation/animation-plugin.ts +26 -0
  443. package/src/graphics/animation/animation-track/animation-track.ts +17 -0
  444. package/src/graphics/animation/animation-track/componentwise-lerp.ts +24 -0
  445. package/src/graphics/animation/animation-track/interpolate.ts +24 -0
  446. package/src/graphics/animation/animation-track/public.ts +3 -0
  447. package/src/graphics/animation/animation-track/sample.ts +48 -0
  448. package/src/graphics/animation/interpolation-mode/interpolation-mode.ts +8 -0
  449. package/src/graphics/animation/interpolation-mode/public.ts +3 -0
  450. package/src/graphics/animation/interpolation-mode/schema.ts +5 -0
  451. package/src/graphics/camera/camera-plugin.ts +37 -0
  452. package/src/graphics/camera/camera.ts +8 -0
  453. package/src/graphics/camera/orbit/attach-orbit-drag.ts +62 -0
  454. package/src/graphics/camera/orbit/orbit-data-plugin.ts +44 -0
  455. package/src/graphics/camera/orbit/orbit-plugin.ts +13 -0
  456. package/src/graphics/camera/orbit/orbit-system-plugin.ts +74 -0
  457. package/src/graphics/camera/orbit/orbit.ts +36 -0
  458. package/src/graphics/camera/orbit/public.ts +7 -0
  459. package/src/graphics/camera/public.ts +6 -0
  460. package/src/graphics/camera/schema.ts +21 -0
  461. package/src/graphics/camera/screen-to-world-ray.ts +47 -0
  462. package/src/graphics/camera/to-view-projection.ts +29 -0
  463. package/src/graphics/graphics-plugin.ts +108 -0
  464. package/src/graphics/picking/pick-hit.ts +13 -0
  465. package/src/graphics/picking/picking-plugin.ts +101 -0
  466. package/src/graphics/plugins.md +120 -0
  467. package/src/graphics/rendering/bone-collider-plugin.ts +182 -0
  468. package/src/graphics/rendering/display-transform-plugin.ts +26 -0
  469. package/src/graphics/rendering/ibl-render/brdf.wgsl.ts +43 -0
  470. package/src/graphics/rendering/ibl-render/ibl/brdf-lut.ts +101 -0
  471. package/src/graphics/rendering/ibl-render/ibl/build-ibl-resources.ts +57 -0
  472. package/src/graphics/rendering/ibl-render/ibl/create-cubemap.ts +17 -0
  473. package/src/graphics/rendering/ibl-render/ibl/cube-face-view.ts +11 -0
  474. package/src/graphics/rendering/ibl-render/ibl/cubemap-sample-view.ts +9 -0
  475. package/src/graphics/rendering/ibl-render/ibl/environment.ts +190 -0
  476. package/src/graphics/rendering/ibl-render/ibl/float-to-half.ts +35 -0
  477. package/src/graphics/rendering/ibl-render/ibl/ibl-math.wgsl.ts +60 -0
  478. package/src/graphics/rendering/ibl-render/ibl/irradiance.ts +105 -0
  479. package/src/graphics/rendering/ibl-render/ibl/parse-hdr.ts +108 -0
  480. package/src/graphics/rendering/ibl-render/ibl/prefilter.ts +121 -0
  481. package/src/graphics/rendering/ibl-render/ibl/render-helpers.ts +17 -0
  482. package/src/graphics/rendering/ibl-render/ibl-render-plugin.ts +415 -0
  483. package/src/graphics/rendering/ibl-render/ibl-shader.wgsl.ts +185 -0
  484. package/src/graphics/rendering/ibl-render/skybox-shader.wgsl.ts +51 -0
  485. package/src/graphics/rendering/interpolation-plugin.ts +97 -0
  486. package/src/graphics/rendering/interpolation.test.ts +52 -0
  487. package/src/graphics/rendering/jolt-ragdoll-plugin.ts +174 -0
  488. package/src/graphics/rendering/material-gpu/material-arrays.ts +113 -0
  489. package/src/graphics/rendering/material-gpu/material-bind-group.ts +61 -0
  490. package/src/graphics/rendering/material-gpu/material-gpu-plugin.ts +95 -0
  491. package/src/graphics/rendering/model-collider-plugin.ts +77 -0
  492. package/src/graphics/rendering/pbr-core-plugin.ts +40 -0
  493. package/src/graphics/rendering/pbr-render/pbr-array-shader.wgsl.ts +146 -0
  494. package/src/graphics/rendering/pbr-render/pbr-render-plugin.ts +247 -0
  495. package/src/graphics/rendering/pbr-render/physics-bridge-plugin.ts +106 -0
  496. package/src/graphics/rendering/ragdoll-trigger-plugin.ts +21 -0
  497. package/src/graphics/rendering/rendering-plugin.ts +3 -0
  498. package/src/graphics/rendering/skinning/skinning-attributes/layout.ts +20 -0
  499. package/src/graphics/rendering/skinning/skinning-attributes/public.ts +3 -0
  500. package/src/graphics/rendering/skinning/skinning-attributes/skinning-attributes.ts +3 -0
  501. package/src/graphics/rendering/skinning/skinning-plugin.ts +213 -0
  502. package/src/graphics/rendering/standard-vertex/layout.ts +19 -0
  503. package/src/graphics/rendering/standard-vertex/public.ts +4 -0
  504. package/src/graphics/rendering/standard-vertex/schema.ts +17 -0
  505. package/src/graphics/rendering/standard-vertex/standard-vertex.ts +8 -0
  506. package/src/graphics/rendering/visible-material/color-material-options.ts +10 -0
  507. package/src/graphics/rendering/visible-material/create-bind-group-layout.ts +35 -0
  508. package/src/graphics/rendering/visible-material/create-color-bind-group.ts +40 -0
  509. package/src/graphics/rendering/visible-material/public.ts +6 -0
  510. package/src/graphics/rendering/visible-material/schema.ts +25 -0
  511. package/src/graphics/rendering/visible-material/visible-material.ts +8 -0
  512. package/src/graphics/scene/light/light-plugin.ts +37 -0
  513. package/src/graphics/scene/light/light.ts +18 -0
  514. package/src/graphics/scene/light/public.ts +1 -0
  515. package/src/graphics/scene/model/geometry/geometry.ts +12 -0
  516. package/src/graphics/scene/model/geometry/public.ts +4 -0
  517. package/src/graphics/scene/model/gltf/accessor-view.ts +53 -0
  518. package/src/graphics/scene/model/gltf/build-material-bind-group.ts +110 -0
  519. package/src/graphics/scene/model/gltf/compute-world-matrices.ts +43 -0
  520. package/src/graphics/scene/model/gltf/create-color-material.ts +47 -0
  521. package/src/graphics/scene/model/gltf/decode-images.ts +93 -0
  522. package/src/graphics/scene/model/gltf/gltf-schema.ts +161 -0
  523. package/src/graphics/scene/model/gltf/load-gltf-model.ts +220 -0
  524. package/src/graphics/scene/model/gltf/pack-vertex-buffer.ts +116 -0
  525. package/src/graphics/scene/model/gltf/parse-animations.ts +66 -0
  526. package/src/graphics/scene/model/gltf/parse-glb.ts +51 -0
  527. package/src/graphics/scene/model/gltf/parse-skin.ts +67 -0
  528. package/src/graphics/scene/model/model-loader-plugin.ts +131 -0
  529. package/src/graphics/scene/model/model-plugin.ts +46 -0
  530. package/src/graphics/scene/model/model.ts +15 -0
  531. package/src/graphics/scene/model/public.ts +1 -0
  532. package/src/graphics/scene/model/shape/convex-hull.test.ts +72 -0
  533. package/src/graphics/scene/model/shape/convex-hull.ts +141 -0
  534. package/src/graphics/scene/model/shape/shape-geometry-plugin.ts +61 -0
  535. package/src/graphics/scene/model/shape/shape-mesh.ts +150 -0
  536. package/src/graphics/scene/model/shape/upload-shape-mesh.ts +14 -0
  537. package/src/graphics/scene/model/world-bounds-plugin.ts +88 -0
  538. package/src/graphics/scene/node/node-data-plugin.ts +28 -0
  539. package/src/graphics/scene/node/node-plugin.ts +13 -0
  540. package/src/graphics/scene/node/node.ts +23 -0
  541. package/src/graphics/scene/node/public.ts +1 -0
  542. package/src/graphics/scene/node/transform-plugin.ts +72 -0
  543. package/src/graphics/scene/scene-plugin.ts +20 -0
  544. package/src/graphics/scene/scene-uniforms/create-bind-group-layout.ts +19 -0
  545. package/src/graphics/scene/scene-uniforms/public.ts +5 -0
  546. package/src/graphics/scene/scene-uniforms/scene-uniforms-plugin.ts +64 -0
  547. package/src/graphics/scene/scene-uniforms/scene-uniforms.ts +15 -0
  548. package/src/graphics/scene/scene-uniforms/schema.ts +17 -0
  549. package/src/index.ts +72 -0
  550. package/src/material/material-plugin.ts +61 -0
  551. package/src/material/material.ts +38 -0
  552. package/src/material/public.ts +4 -0
  553. package/src/material/standard-materials.ts +43 -0
  554. package/src/physics/README.md +71 -0
  555. package/src/physics/body/body-type/body-type.ts +14 -0
  556. package/src/physics/body/body-type/is-dynamic.ts +8 -0
  557. package/src/physics/body/body-type/public.ts +4 -0
  558. package/src/physics/body/body-type/schema.ts +5 -0
  559. package/src/physics/body/collider-mesh.ts +13 -0
  560. package/src/physics/body/collider-shape/collider-shape.ts +19 -0
  561. package/src/physics/body/collider-shape/list.ts +7 -0
  562. package/src/physics/body/collider-shape/mass-properties.ts +47 -0
  563. package/src/physics/body/collider-shape/public.ts +6 -0
  564. package/src/physics/body/collider-shape/schema.ts +5 -0
  565. package/src/physics/body/collider-shape/to-index.ts +8 -0
  566. package/src/physics/body/rigid-body.ts +26 -0
  567. package/src/physics/body/static-collider.ts +28 -0
  568. package/src/physics/joint/joint-plugin.ts +33 -0
  569. package/src/physics/joint/joint-type/joint-type.ts +19 -0
  570. package/src/physics/joint/joint-type/public.ts +3 -0
  571. package/src/physics/joint/joint-type/schema.ts +5 -0
  572. package/src/physics/joint/joint.ts +27 -0
  573. package/src/physics/physics-clock-plugin.ts +61 -0
  574. package/src/physics/physics-clock.test.ts +55 -0
  575. package/src/physics/physics-data-plugin.ts +73 -0
  576. package/src/physics/ragdoll/fit-bone-capsules.test.ts +66 -0
  577. package/src/physics/ragdoll/fit-bone-capsules.ts +106 -0
  578. package/src/physics/solvers/README.md +63 -0
  579. package/src/physics/solvers/jolt-solver-plugin.ts +382 -0
  580. package/src/physics/solvers/rapier-jolt.benchmark.test.ts +39 -0
  581. package/src/physics/solvers/rapier-solver-plugin.ts +251 -0
  582. package/src/physics/solvers/solver-benchmark.ts +172 -0
  583. package/tsconfig.json +25 -0
  584. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,97 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { Database } from "@adobe/data/ecs";
4
+ import { Mat4x4, Quat } from "@adobe/data/math";
5
+ import { physicsData } from "../../physics/physics-data-plugin.js";
6
+ import { physicsClock } from "../../physics/physics-clock-plugin.js";
7
+ import { transform } from "../scene/node/transform-plugin.js";
8
+ import { displayTransform } from "./display-transform-plugin.js";
9
+
10
+ /**
11
+ * interpolation — the single pre-render pass that turns the fixed-step physics
12
+ * state into a smooth display pose. Because the solver steps on `physicsClock`
13
+ * (0..N steps/frame), the canonical `position`/`rotation` jump in fixed
14
+ * increments; rendering them raw judders when the render rate ≠ the sim rate.
15
+ *
16
+ * Each render frame this blends `_prevPosition`→`position` (and the rotations)
17
+ * by `physicsClock.alpha` into `_renderPosition`/`_renderRotation`, which the
18
+ * renderer draws. Doing it once here (not in each renderer) keeps render systems
19
+ * free of physics knowledge — they only read the display transform.
20
+ *
21
+ * Bodies gain `_renderPosition`/`_renderRotation` the first frame after the
22
+ * solver has mirrored them (i.e. once `_prevPosition` exists); the tag-exclude
23
+ * query means steady state never re-scans already-equipped bodies.
24
+ */
25
+
26
+ // Dynamic bodies that have been mirrored (so `_prevPosition` exists) but don't
27
+ // yet carry the display-pose columns — give them those columns once.
28
+ const NEEDS_RENDER_POSE = ["position", "rotation", "_prevPosition"] as const;
29
+ const WITHOUT_RENDER_POSE = { exclude: ["_renderPosition"] } as const;
30
+ // Fully-equipped bodies: blend prev→current into the display pose every frame.
31
+ const INTERPOLATED = ["position", "rotation", "_prevPosition", "_prevRotation", "_renderPosition", "_renderRotation"] as const;
32
+ // Interpolated bodies that render through the world-matrix path (models, which have
33
+ // a `parent`/`_worldMatrix`) rather than the flat instanced path.
34
+ const INTERPOLATED_MODEL = ["_renderPosition", "_renderRotation", "scale", "parent", "_worldMatrix"] as const;
35
+
36
+ export const interpolation = Database.Plugin.create({
37
+ extends: Database.Plugin.combine(physicsData, physicsClock, displayTransform, transform),
38
+ systems: {
39
+ interpolateDisplayPose: {
40
+ schedule: { during: ["preRender"] },
41
+ create: db => () => {
42
+ // 1) Equip newly-mirrored bodies with display-pose columns (seed = current
43
+ // pose). Tail→head: every visited row migrates out on gaining the columns.
44
+ for (const arch of db.store.queryArchetypes(NEEDS_RENDER_POSE, WITHOUT_RENDER_POSE)) {
45
+ const ids = arch.columns.id, pos = arch.columns.position, ori = arch.columns.rotation;
46
+ for (let r = arch.rowCount - 1; r >= 0; r--) {
47
+ db.store.update(ids.get(r), { _renderPosition: pos.get(r), _renderRotation: ori.get(r) });
48
+ }
49
+ }
50
+
51
+ // 2) Blend prev→current by alpha into the display pose — every frame, in
52
+ // place (no migration), straight on the backing typed arrays.
53
+ const alpha = db.store.resources.physicsClock.alpha;
54
+ for (const arch of db.store.queryArchetypes(INTERPOLATED)) {
55
+ const pos = arch.columns.position.getTypedArray(), ori = arch.columns.rotation.getTypedArray();
56
+ const pp = arch.columns._prevPosition.getTypedArray(), pr = arch.columns._prevRotation.getTypedArray();
57
+ const rp = arch.columns._renderPosition.getTypedArray(), rr = arch.columns._renderRotation.getTypedArray();
58
+ for (let r = 0; r < arch.rowCount; r++) {
59
+ const r3 = r * 3, r4 = r * 4;
60
+ rp[r3] = pp[r3] + (pos[r3] - pp[r3]) * alpha;
61
+ rp[r3 + 1] = pp[r3 + 1] + (pos[r3 + 1] - pp[r3 + 1]) * alpha;
62
+ rp[r3 + 2] = pp[r3 + 2] + (pos[r3 + 2] - pp[r3 + 2]) * alpha;
63
+ // nlerp with shortest-path sign flip — cheap, allocation-free, and
64
+ // visually exact for the small per-step rotations of interpolation.
65
+ let ax = pr[r4], ay = pr[r4 + 1], az = pr[r4 + 2], aw = pr[r4 + 3];
66
+ const bx = ori[r4], by = ori[r4 + 1], bz = ori[r4 + 2], bw = ori[r4 + 3];
67
+ if (ax * bx + ay * by + az * bz + aw * bw < 0) { ax = -ax; ay = -ay; az = -az; aw = -aw; }
68
+ const x = ax + (bx - ax) * alpha, y = ay + (by - ay) * alpha, z = az + (bz - az) * alpha, w = aw + (bw - aw) * alpha;
69
+ const inv = 1 / Math.hypot(x, y, z, w);
70
+ rr[r4] = x * inv; rr[r4 + 1] = y * inv; rr[r4 + 2] = z * inv; rr[r4 + 3] = w * inv;
71
+ }
72
+ }
73
+ },
74
+ },
75
+ // Models render from `_worldMatrix` (the transform path), not the flat display
76
+ // pose — so recompose their world matrix from the interpolated pose, after the
77
+ // blend above and after `transformSystem` (which wrote the raw, juddering pose).
78
+ interpolateWorldMatrix: {
79
+ schedule: { during: ["preRender"], after: ["interpolateDisplayPose", "transformSystem"] },
80
+ create: db => () => {
81
+ for (const arch of db.store.queryArchetypes(INTERPOLATED_MODEL)) {
82
+ const rp = arch.columns._renderPosition.getTypedArray(), rr = arch.columns._renderRotation.getTypedArray();
83
+ const scl = arch.columns.scale, parents = arch.columns.parent, world = arch.columns._worldMatrix;
84
+ for (let i = 0; i < arch.rowCount; i++) {
85
+ const r3 = i * 3, r4 = i * 4, s = scl.get(i), parentId = parents.get(i);
86
+ const local = Mat4x4.multiply(
87
+ Mat4x4.translation(rp[r3], rp[r3 + 1], rp[r3 + 2]),
88
+ Mat4x4.multiply(Quat.toMat4([rr[r4], rr[r4 + 1], rr[r4 + 2], rr[r4 + 3]]), Mat4x4.scaling(s[0], s[1], s[2])),
89
+ );
90
+ const parentWorld = parentId === 0 ? Mat4x4.identity : db.store.get(parentId, "_worldMatrix") ?? Mat4x4.identity;
91
+ world.set(i, parentId === 0 ? local : Mat4x4.multiply(parentWorld, local));
92
+ }
93
+ }
94
+ },
95
+ },
96
+ },
97
+ });
@@ -0,0 +1,52 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { describe, it, expect } from "vitest";
4
+ import { Database } from "@adobe/data/ecs";
5
+ import { interpolation } from "./interpolation-plugin.js";
6
+ import type { PhysicsClock } from "../../physics/physics-clock-plugin.js";
7
+
8
+ /**
9
+ * The interpolation pass turns the fixed-step sim state into a smooth render pose.
10
+ * No solver here — we hand-seed the prev snapshot a solver would write, then assert
11
+ * the display pose is the alpha-blend of prev → current. Pure + deterministic
12
+ * (no WASM, no GPU), so it runs headless.
13
+ */
14
+ describe("interpolation", () => {
15
+ // A created database carries a writable `store` (runtime invariant; not on the
16
+ // public type — the same loose access the solver benchmark uses).
17
+ interface InterpStore {
18
+ resources: { physicsClock: PhysicsClock };
19
+ archetypes: { RigidBody: { insert(v: object): number } };
20
+ read(id: number): { _renderPosition: readonly number[] };
21
+ update(id: number, v: object): void;
22
+ }
23
+
24
+ const make = () => {
25
+ const db = Database.create(interpolation);
26
+ const store = (db as unknown as { store: InterpStore }).store;
27
+ // a body the solver has already mirrored (so it carries a prev snapshot)
28
+ const id = store.archetypes.RigidBody.insert({
29
+ bodyType: "dynamic", colliderShape: "box", halfExtents: [0.5, 0.5, 0.5], material: 0,
30
+ position: [0, 10, 0], rotation: [0, 0, 0, 1], linearVelocity: [0, 0, 0], angularVelocity: [0, 0, 0],
31
+ });
32
+ store.update(id, { _prevPosition: [0, 10, 0], _prevRotation: [0, 0, 0, 1] });
33
+ store.update(id, { position: [0, 6, 0] }); // a step landed: prev y=10, current y=6
34
+
35
+ const interpolateAt = (alpha: number): number => {
36
+ store.resources.physicsClock = { ...store.resources.physicsClock, alpha, steps: 0 };
37
+ db.system.functions.interpolateDisplayPose?.();
38
+ return store.read(id)._renderPosition[1];
39
+ };
40
+ return { interpolateAt };
41
+ };
42
+
43
+ it("blends prev → current by the clock's alpha into the display pose", () => {
44
+ expect(make().interpolateAt(0.25)).toBeCloseTo(9); // 10 + (6 - 10) * 0.25
45
+ });
46
+
47
+ it("at alpha→0 the display pose equals prev; at alpha→1 it equals current", () => {
48
+ const { interpolateAt } = make();
49
+ expect(interpolateAt(0)).toBeCloseTo(10); // prev
50
+ expect(interpolateAt(1)).toBeCloseTo(6); // current
51
+ });
52
+ });
@@ -0,0 +1,174 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { Database, type Entity } from "@adobe/data/ecs";
4
+ import { Mat4x4, Quat } from "@adobe/data/math";
5
+ import { joltSolver, type JoltContext } from "../../physics/solvers/jolt-solver-plugin.js";
6
+ import { fitBoneCapsules } from "../../physics/ragdoll/fit-bone-capsules.js";
7
+ import { ragdollTrigger } from "./ragdoll-trigger-plugin.js";
8
+ import { pbrSkinning } from "./skinning/skinning-plugin.js";
9
+ import { modelLoader } from "../scene/model/model-loader-plugin.js";
10
+ import { transform } from "../scene/node/transform-plugin.js";
11
+ import type { JointTemplate } from "../scene/model/gltf/parse-skin.js";
12
+
13
+ /**
14
+ * joltRagdoll — a **Jolt-native** ragdoll backend (the alternative to our generic
15
+ * `boneColliders`), using Jolt's `Skeleton` / `RagdollSettings` / `Ragdoll`.
16
+ *
17
+ * Once the skin loads, it builds a `Ragdoll` in the *solver's* physics system: one
18
+ * dynamic body per bone (capsule fitted by `fitBoneCapsules`, tiny sphere for
19
+ * capsule-less joints), a swing-twist constraint to each parent, and
20
+ * `DisableParentChildCollisions`. While alive it `DriveToPoseUsingKinematics`
21
+ * toward the animated pose each frame; on `triggerRagdoll` it stops driving (the
22
+ * bodies fall) and reads the pose back onto the skeleton so the skin flops.
23
+ *
24
+ * Jolt-only by construction — it needs the solver's `PhysicsSystem` (exposed as
25
+ * `_joltContext`). Pair it with `joltSolver`; use `boneColliders` for other solvers.
26
+ */
27
+
28
+ type Jolt = JoltContext["jolt"];
29
+ interface SkinGeo { _cpuSkin?: { positions: Float32Array; joints: Uint32Array; weights: Float32Array } | null; _skinInverseBindMatrices?: Float32Array | null; _skinJointTemplate?: JointTemplate[] }
30
+
31
+ /** Column-major rigid transform from a position + unit quaternion. */
32
+ const compose = (px: number, py: number, pz: number, q: ArrayLike<number>): Mat4x4 =>
33
+ Mat4x4.multiply(Mat4x4.translation(px, py, pz), Quat.toMat4([q[0], q[1], q[2], q[3]]));
34
+
35
+ /** Orthonormalised rotation of a column-major matrix → quaternion. */
36
+ function rotationOf(m: Mat4x4): Quat {
37
+ let m00 = m[0], m10 = m[1], m20 = m[2], m01 = m[4], m11 = m[5], m21 = m[6], m02 = m[8], m12 = m[9], m22 = m[10];
38
+ const sx = Math.hypot(m00, m10, m20) || 1, sy = Math.hypot(m01, m11, m21) || 1, sz = Math.hypot(m02, m12, m22) || 1;
39
+ m00 /= sx; m10 /= sx; m20 /= sx; m01 /= sy; m11 /= sy; m21 /= sy; m02 /= sz; m12 /= sz; m22 /= sz;
40
+ const tr = m00 + m11 + m22;
41
+ if (tr > 0) { const s = Math.sqrt(tr + 1) * 2; return [(m21 - m12) / s, (m02 - m20) / s, (m10 - m01) / s, 0.25 * s]; }
42
+ if (m00 > m11 && m00 > m22) { const s = Math.sqrt(1 + m00 - m11 - m22) * 2; return [0.25 * s, (m01 + m10) / s, (m02 + m20) / s, (m21 - m12) / s]; }
43
+ if (m11 > m22) { const s = Math.sqrt(1 + m11 - m00 - m22) * 2; return [(m01 + m10) / s, 0.25 * s, (m12 + m21) / s, (m02 - m20) / s]; }
44
+ const s = Math.sqrt(1 + m22 - m00 - m11) * 2; return [(m02 + m20) / s, (m12 + m21) / s, 0.25 * s, (m10 - m01) / s];
45
+ }
46
+
47
+ const SWING = 0.9, TWIST = 0.5; // ~52° swing cone, ~±29° twist
48
+
49
+ export const joltRagdoll = Database.Plugin.create({
50
+ extends: Database.Plugin.combine(joltSolver, ragdollTrigger, pbrSkinning, modelLoader, transform),
51
+ systems: {
52
+ joltRagdollSystem: {
53
+ schedule: { during: ["postUpdate"], after: ["transformSystem"] },
54
+ create: db => {
55
+ let built = false, dead = false;
56
+ // Jolt objects (created at build): the ragdoll, a reusable pose, scratch.
57
+ let ragdoll: InstanceType<Jolt["Ragdoll"]> | null = null;
58
+ let pose: InstanceType<Jolt["SkeletonPose"]> | null = null;
59
+ let joints: readonly Entity[] = [];
60
+ let modelEntity: Entity = 0 as Entity; // the skeleton's root parent (the Model); moved to follow the ragdoll root when limp
61
+ let tv: InstanceType<Jolt["Vec3"]> | null = null, tq: InstanceType<Jolt["Quat"]> | null = null, troot: InstanceType<Jolt["RVec3"]> | null = null;
62
+
63
+ const jointWorld = (j: Entity): Mat4x4 => (db.store.get(j, "_worldMatrix") as Mat4x4 | undefined) ?? Mat4x4.identity;
64
+
65
+ const build = (ctx: JoltContext, jointIds: readonly Entity[], g: SkinGeo): void => {
66
+ const jolt = ctx.jolt, template = g._skinJointTemplate!;
67
+ const caps = new Map<number, { radius: number; halfHeight: number; offPos: readonly number[]; offRot: readonly number[] }>();
68
+ for (const c of fitBoneCapsules({ jointCount: jointIds.length, inverseBindMatrices: g._skinInverseBindMatrices!, skin: g._cpuSkin! }))
69
+ caps.set(c.jointIndex, { radius: c.radius, halfHeight: c.halfHeight, offPos: c.offsetPosition, offRot: c.offsetRotation });
70
+
71
+ const skel = new jolt.Skeleton();
72
+ for (let i = 0; i < jointIds.length; i++) { const s = new jolt.JPHString(template[i]?.name ?? `j${i}`, (template[i]?.name ?? `j${i}`).length); skel.AddJoint(s, template[i]?.parentJointIndex ?? -1); jolt.destroy(s); }
73
+
74
+ const settings = new jolt.RagdollSettings();
75
+ settings.mSkeleton = skel;
76
+ // RagdollPart has no constructor in the IDL — resize the parts vector and
77
+ // configure each element in place, then write the vector back.
78
+ const parts = settings.mParts;
79
+ parts.resize(jointIds.length);
80
+ for (let i = 0; i < jointIds.length; i++) {
81
+ const jw = jointWorld(jointIds[i]), cap = caps.get(i);
82
+ const part = parts.at(i);
83
+ // body bind pose: capsule sits at jointWorld · offset; sphere at the joint
84
+ const bodyW = cap ? Mat4x4.multiply(jw, compose(cap.offPos[0], cap.offPos[1], cap.offPos[2], cap.offRot)) : jw;
85
+ const shp = cap ? new jolt.CapsuleShape(Math.max(cap.halfHeight, 1e-3), cap.radius) : new jolt.SphereShape(0.03);
86
+ part.SetShape(shp);
87
+ const bp = new jolt.RVec3(bodyW[12], bodyW[13], bodyW[14]); const br = rotationOf(bodyW); const bq = new jolt.Quat(br[0], br[1], br[2], br[3]);
88
+ part.set_mPosition(bp); part.set_mRotation(bq);
89
+ part.set_mMotionType(jolt.EMotionType_Dynamic); part.set_mObjectLayer(ctx.ragdollLayer);
90
+ const pj = template[i]?.parentJointIndex ?? -1;
91
+ if (pj >= 0) {
92
+ // swing-twist to the parent, anchored at this joint, bone axis = parent→this
93
+ const pw = jointWorld(jointIds[pj]);
94
+ let ax = jw[12] - pw[12], ay = jw[13] - pw[13], az = jw[14] - pw[14];
95
+ const al = Math.hypot(ax, ay, az) || 1; ax /= al; ay /= al; az /= al;
96
+ let nx = 0, ny = 0, nz = 0; if (Math.abs(ax) <= Math.abs(ay) && Math.abs(ax) <= Math.abs(az)) { ny = az; nz = -ay; } else { nx = -az; nz = ax; }
97
+ const nl = Math.hypot(nx, ny, nz) || 1; nx /= nl; ny /= nl; nz /= nl;
98
+ const st = new jolt.SwingTwistConstraintSettings();
99
+ st.mSpace = jolt.EConstraintSpace_WorldSpace;
100
+ const p1 = new jolt.RVec3(jw[12], jw[13], jw[14]), p2 = new jolt.RVec3(jw[12], jw[13], jw[14]);
101
+ const t1 = new jolt.Vec3(ax, ay, az), t2 = new jolt.Vec3(ax, ay, az), n1 = new jolt.Vec3(nx, ny, nz), n2 = new jolt.Vec3(nx, ny, nz);
102
+ st.mPosition1 = p1; st.mPosition2 = p2; st.mTwistAxis1 = t1; st.mTwistAxis2 = t2; st.mPlaneAxis1 = n1; st.mPlaneAxis2 = n2;
103
+ st.mSwingType = jolt.ESwingType_Cone; st.mNormalHalfConeAngle = SWING; st.mPlaneHalfConeAngle = SWING; st.mTwistMinAngle = -TWIST; st.mTwistMaxAngle = TWIST;
104
+ part.set_mToParent(st);
105
+ jolt.destroy(p1); jolt.destroy(p2); jolt.destroy(t1); jolt.destroy(t2); jolt.destroy(n1); jolt.destroy(n2);
106
+ }
107
+ jolt.destroy(bp); jolt.destroy(bq);
108
+ }
109
+ settings.mParts = parts;
110
+ settings.DisableParentChildCollisions();
111
+ settings.Stabilize();
112
+ ragdoll = settings.CreateRagdoll(0, 0, ctx.physicsSystem) as typeof ragdoll;
113
+ ragdoll!.AddToPhysicsSystem(jolt.EActivation_Activate);
114
+ pose = new jolt.SkeletonPose(); pose.SetSkeleton(skel);
115
+ tv = new jolt.Vec3(0, 0, 0); tq = new jolt.Quat(0, 0, 0, 1); troot = new jolt.RVec3(0, 0, 0);
116
+ joints = jointIds;
117
+ let rootIdx = template.findIndex(t => (t.parentJointIndex ?? -1) < 0); if (rootIdx < 0) rootIdx = 0;
118
+ modelEntity = (db.store.get(jointIds[rootIdx], "parent") as Entity | undefined) ?? (0 as Entity);
119
+ jolt.destroy(settings);
120
+ };
121
+
122
+ return () => {
123
+ const ctx = db.store.resources._joltContext;
124
+ if (!ctx) return;
125
+ if (!built) {
126
+ for (const arch of db.store.queryArchetypes(["_skeletonJoints", "_skeletonGeometry"])) {
127
+ const jc = arch.columns._skeletonJoints, gc = arch.columns._skeletonGeometry;
128
+ for (let i = 0; i < arch.rowCount; i++) {
129
+ const g = db.store.read(gc.get(i)) as SkinGeo | null;
130
+ if (!g?._cpuSkin || !g._skinInverseBindMatrices || !g._skinJointTemplate?.length) continue;
131
+ build(ctx, jc.get(i), g); built = true; break;
132
+ }
133
+ if (built) break;
134
+ }
135
+ if (!built) return;
136
+ }
137
+ const jolt = ctx.jolt, rd = ragdoll!, p = pose!;
138
+ if (!dead && db.store.resources._ragdollTrigger) {
139
+ dead = true;
140
+ for (const a of db.store.queryArchetypes(["animationPlaying"])) for (let i = 0; i < a.rowCount; i++) db.store.update(a.columns.id.get(i), { animationPlaying: false });
141
+ }
142
+ if (!dead) {
143
+ // alive: drive the ragdoll toward the animated pose. Root offset =
144
+ // the model's world translation; joint states = the animated locals.
145
+ const rm = jointWorld(modelEntity);
146
+ troot!.Set(rm[12], rm[13], rm[14]); p.SetRootOffset(troot!);
147
+ for (let i = 0; i < joints.length; i++) {
148
+ const pos = db.store.get(joints[i], "position") as readonly number[] | undefined;
149
+ const rot = db.store.get(joints[i], "rotation") as readonly number[] | undefined;
150
+ if (!pos || !rot) continue;
151
+ const st = p.GetJoint(i);
152
+ tv!.Set(pos[0], pos[1], pos[2]); tq!.Set(rot[0], rot[1], rot[2], rot[3]);
153
+ st.set_mTranslation(tv!); st.set_mRotation(tq!);
154
+ }
155
+ p.CalculateJointMatrices();
156
+ rd.DriveToPoseUsingKinematics(p, db.store.resources.physicsClock.fixedDt * Math.max(1, db.store.resources.physicsClock.steps));
157
+ } else {
158
+ // limp: read the physics pose back. The ragdoll's root has fallen, so move
159
+ // the model to the pose's root offset and apply the local joint states —
160
+ // the whole skin follows the fall, the limbs flop.
161
+ rd.GetPose(p, false);
162
+ p.CalculateJointStates();
163
+ const ro = p.GetRootOffset();
164
+ db.store.update(modelEntity, { position: [ro.GetX(), ro.GetY(), ro.GetZ()] });
165
+ for (let i = 0; i < joints.length; i++) {
166
+ const st = p.GetJoint(i), t = st.get_mTranslation(), r = st.get_mRotation();
167
+ db.store.update(joints[i], { position: [t.GetX(), t.GetY(), t.GetZ()], rotation: [r.GetX(), r.GetY(), r.GetZ(), r.GetW()] });
168
+ }
169
+ }
170
+ };
171
+ },
172
+ },
173
+ },
174
+ });
@@ -0,0 +1,113 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ /**
4
+ * The shared GPU material set: five `texture_2d_array`s (one per PBR map) plus
5
+ * a palette storage buffer of per-layer factors. Every material occupies one
6
+ * layer across all five arrays; a drawable selects its material with a single
7
+ * per-instance layer index. Built once and grown by layer — materials are
8
+ * added rarely and edited never, so nothing here is rebuilt per frame.
9
+ */
10
+ export interface MaterialArrays {
11
+ baseColor: GPUTexture; // rgba8unorm-srgb
12
+ metallicRoughness: GPUTexture; // rgba8unorm (G = roughness, B = metalness)
13
+ normal: GPUTexture; // rgba8unorm
14
+ occlusion: GPUTexture; // rgba8unorm (R = AO)
15
+ emissive: GPUTexture; // rgba8unorm-srgb
16
+ }
17
+
18
+ /** Fixed layer size every material map is resampled to. */
19
+ export const MATERIAL_TEXTURE_SIZE = 512;
20
+ /** Maximum distinct materials (array layers). 16 × 512² × 5 maps ≈ 80 MB. */
21
+ export const MAX_MATERIAL_LAYERS = 16;
22
+ /** Bytes per palette entry: baseColor(vec4) + emissive/metallic(vec4) + rough/normal/occlusion(vec4). */
23
+ export const PALETTE_STRIDE = 48;
24
+
25
+ export function createMaterialArrays(device: GPUDevice): MaterialArrays {
26
+ const make = (format: GPUTextureFormat): GPUTexture =>
27
+ device.createTexture({
28
+ size: [MATERIAL_TEXTURE_SIZE, MATERIAL_TEXTURE_SIZE, MAX_MATERIAL_LAYERS],
29
+ dimension: "2d",
30
+ format,
31
+ // RENDER_ATTACHMENT is required by copyExternalImageToTexture.
32
+ usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
33
+ });
34
+ return {
35
+ baseColor: make("rgba8unorm-srgb"),
36
+ metallicRoughness: make("rgba8unorm"),
37
+ normal: make("rgba8unorm"),
38
+ occlusion: make("rgba8unorm"),
39
+ emissive: make("rgba8unorm-srgb"),
40
+ };
41
+ }
42
+
43
+ /** Per-material visible factors written into one palette layer. */
44
+ export interface MaterialFactors {
45
+ baseColorFactor: readonly number[];
46
+ emissiveFactor: readonly number[];
47
+ metallicFactor: number;
48
+ roughnessFactor: number;
49
+ normalScale: number;
50
+ occlusionStrength: number;
51
+ }
52
+
53
+ const _palette = new Float32Array(PALETTE_STRIDE / 4);
54
+
55
+ export function writePaletteLayer(device: GPUDevice, palette: GPUBuffer, layer: number, f: MaterialFactors): void {
56
+ _palette[0] = f.baseColorFactor[0]; _palette[1] = f.baseColorFactor[1]; _palette[2] = f.baseColorFactor[2]; _palette[3] = f.baseColorFactor[3];
57
+ _palette[4] = f.emissiveFactor[0]; _palette[5] = f.emissiveFactor[1]; _palette[6] = f.emissiveFactor[2]; _palette[7] = f.metallicFactor;
58
+ _palette[8] = f.roughnessFactor; _palette[9] = f.normalScale; _palette[10] = f.occlusionStrength; _palette[11] = 0;
59
+ device.queue.writeBuffer(palette, layer * PALETTE_STRIDE, _palette);
60
+ }
61
+
62
+ /** The five map source URLs for one material ("" = leave the neutral layer). */
63
+ export interface MaterialMapUrls {
64
+ baseColorUrl: string;
65
+ metallicRoughnessUrl: string;
66
+ normalUrl: string;
67
+ occlusionUrl: string;
68
+ emissiveUrl: string;
69
+ }
70
+
71
+ /**
72
+ * Fetches a material's maps and blits them (resampled to the layer size) into
73
+ * its array layer. Fire-and-forget: each map resolves independently, so a body
74
+ * renders (neutral) immediately and sharpens as textures arrive. URLs shared
75
+ * across maps (e.g. an ARM image used for both metallicRoughness and occlusion)
76
+ * are fetched once and copied to each target.
77
+ */
78
+ export function loadMaterialMaps(device: GPUDevice, arrays: MaterialArrays, layer: number, urls: MaterialMapUrls): void {
79
+ const targets: { url: string; tex: GPUTexture }[] = [
80
+ { url: urls.baseColorUrl, tex: arrays.baseColor },
81
+ { url: urls.metallicRoughnessUrl, tex: arrays.metallicRoughness },
82
+ { url: urls.normalUrl, tex: arrays.normal },
83
+ { url: urls.occlusionUrl, tex: arrays.occlusion },
84
+ { url: urls.emissiveUrl, tex: arrays.emissive },
85
+ ];
86
+ const byUrl = new Map<string, GPUTexture[]>();
87
+ for (const t of targets) {
88
+ if (!t.url) continue;
89
+ const list = byUrl.get(t.url);
90
+ if (list) list.push(t.tex);
91
+ else byUrl.set(t.url, [t.tex]);
92
+ }
93
+ for (const [url, texes] of byUrl) {
94
+ fetch(url)
95
+ .then(r => { if (!r.ok) throw new Error(`material map ${r.status}: ${url}`); return r.blob(); })
96
+ .then(blob => createImageBitmap(blob, {
97
+ resizeWidth: MATERIAL_TEXTURE_SIZE,
98
+ resizeHeight: MATERIAL_TEXTURE_SIZE,
99
+ colorSpaceConversion: "none",
100
+ }))
101
+ .then(bitmap => {
102
+ for (const tex of texes) {
103
+ device.queue.copyExternalImageToTexture(
104
+ { source: bitmap },
105
+ { texture: tex, origin: [0, 0, layer] },
106
+ [MATERIAL_TEXTURE_SIZE, MATERIAL_TEXTURE_SIZE, 1],
107
+ );
108
+ }
109
+ bitmap.close();
110
+ })
111
+ .catch(err => console.warn("[materialGpu] map load failed", err));
112
+ }
113
+ }
@@ -0,0 +1,61 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import type { MaterialArrays } from "./material-arrays.js";
4
+
5
+ interface DeviceCache {
6
+ layout: GPUBindGroupLayout;
7
+ sampler: GPUSampler;
8
+ }
9
+ const cacheByDevice = new WeakMap<GPUDevice, DeviceCache>();
10
+
11
+ function deviceCache(device: GPUDevice): DeviceCache {
12
+ let c = cacheByDevice.get(device);
13
+ if (!c) {
14
+ const tex = (binding: number): GPUBindGroupLayoutEntry => ({
15
+ binding, visibility: GPUShaderStage.FRAGMENT,
16
+ texture: { sampleType: "float", viewDimension: "2d-array" },
17
+ });
18
+ c = {
19
+ layout: device.createBindGroupLayout({
20
+ entries: [
21
+ { binding: 0, visibility: GPUShaderStage.FRAGMENT, buffer: { type: "read-only-storage" } },
22
+ tex(1), tex(2), tex(3), tex(4), tex(5),
23
+ { binding: 6, visibility: GPUShaderStage.FRAGMENT, sampler: { type: "filtering" } },
24
+ ],
25
+ }),
26
+ sampler: device.createSampler({
27
+ magFilter: "linear", minFilter: "linear", mipmapFilter: "linear",
28
+ addressModeU: "repeat", addressModeV: "repeat",
29
+ }),
30
+ };
31
+ cacheByDevice.set(device, c);
32
+ }
33
+ return c;
34
+ }
35
+
36
+ /**
37
+ * Bind-group layout for the shared material set: palette storage buffer +
38
+ * five `texture_2d_array`s + a filtering sampler. The renderer's primitive
39
+ * pipeline builds its pipeline layout from this; `createMaterialBindGroup`
40
+ * builds the matching bind group. Cached per device.
41
+ */
42
+ export function createMaterialBindGroupLayout(device: GPUDevice): GPUBindGroupLayout {
43
+ return deviceCache(device).layout;
44
+ }
45
+
46
+ export function createMaterialBindGroup(device: GPUDevice, arrays: MaterialArrays, palette: GPUBuffer): GPUBindGroup {
47
+ const { layout, sampler } = deviceCache(device);
48
+ const view = (t: GPUTexture): GPUTextureView => t.createView({ dimension: "2d-array" });
49
+ return device.createBindGroup({
50
+ layout,
51
+ entries: [
52
+ { binding: 0, resource: { buffer: palette } },
53
+ { binding: 1, resource: view(arrays.baseColor) },
54
+ { binding: 2, resource: view(arrays.metallicRoughness) },
55
+ { binding: 3, resource: view(arrays.normal) },
56
+ { binding: 4, resource: view(arrays.occlusion) },
57
+ { binding: 5, resource: view(arrays.emissive) },
58
+ { binding: 6, resource: sampler },
59
+ ],
60
+ });
61
+ }
@@ -0,0 +1,95 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { Database } from "@adobe/data/ecs";
4
+ import { U32 } from "@adobe/data/math";
5
+ import { core } from "../../../core/core-plugin.js";
6
+ import { Material } from "../../../material/material.js";
7
+ import {
8
+ type MaterialArrays,
9
+ MAX_MATERIAL_LAYERS, PALETTE_STRIDE,
10
+ createMaterialArrays, writePaletteLayer, loadMaterialMaps,
11
+ } from "./material-arrays.js";
12
+ import { createMaterialBindGroup } from "./material-bind-group.js";
13
+
14
+ /** Material rows the builder reads to fill a layer (factors + map URLs). */
15
+ const MATERIAL_COMPONENTS = [
16
+ "baseColorFactor", "emissiveFactor", "metallicFactor", "roughnessFactor", "normalScale", "occlusionStrength",
17
+ "baseColorUrl", "metallicRoughnessUrl", "normalUrl", "occlusionUrl", "emissiveUrl",
18
+ ] as const;
19
+
20
+ /**
21
+ * materialGpu — derives the shared GPU material set from the `Material`
22
+ * registry. Each authored material is assigned one array layer; its factors go
23
+ * into the palette buffer and its maps are fetched + blitted into that layer.
24
+ *
25
+ * Incremental and cached: the arrays / palette / bind group are built once, and
26
+ * a layer is assigned only to a material that doesn't have one yet (`_layerIndex`
27
+ * excluded). Materials are added rarely and edited never, so steady state does
28
+ * no work. The renderer (P3) binds `_materialBindGroup` once and selects a
29
+ * material per instance by `_layerIndex`.
30
+ */
31
+ export const materialGpu = Database.Plugin.create({
32
+ extends: Database.Plugin.combine(Material.plugin, core),
33
+ components: {
34
+ _layerIndex: U32.schema,
35
+ },
36
+ resources: {
37
+ _materialArrays: { default: null as MaterialArrays | null, transient: true },
38
+ _materialPalette: { default: null as GPUBuffer | null, transient: true },
39
+ _materialBindGroup: { default: null as GPUBindGroup | null, transient: true },
40
+ },
41
+ systems: {
42
+ materialGpuBuilder: {
43
+ schedule: { during: ["preRender"] },
44
+ create: db => {
45
+ let arrays: MaterialArrays | null = null;
46
+ let palette: GPUBuffer | null = null;
47
+ let nextLayer = 0;
48
+ return () => {
49
+ const { device } = db.store.resources;
50
+ if (!device) return;
51
+
52
+ // Assign a layer to each material that lacks one. Tail→head:
53
+ // every visited row migrates out (gains _layerIndex), so the
54
+ // removal is always from the tail — no hole-fill shift. The GPU
55
+ // arrays are created lazily on the first material, so glTF-only
56
+ // scenes (no materials) allocate nothing.
57
+ for (const arch of db.store.queryArchetypes(["name", ...MATERIAL_COMPONENTS], { exclude: ["_layerIndex"] })) {
58
+ const c = arch.columns;
59
+ for (let i = arch.rowCount - 1; i >= 0; i--) {
60
+ if (nextLayer >= MAX_MATERIAL_LAYERS) break;
61
+ if (!arrays || !palette) {
62
+ arrays = createMaterialArrays(device);
63
+ palette = device.createBuffer({
64
+ size: MAX_MATERIAL_LAYERS * PALETTE_STRIDE,
65
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
66
+ });
67
+ db.store.resources._materialArrays = arrays;
68
+ db.store.resources._materialPalette = palette;
69
+ db.store.resources._materialBindGroup = createMaterialBindGroup(device, arrays, palette);
70
+ }
71
+ const id = c.id.get(i);
72
+ const layer = nextLayer++;
73
+ writePaletteLayer(device, palette, layer, {
74
+ baseColorFactor: c.baseColorFactor.get(i),
75
+ emissiveFactor: c.emissiveFactor.get(i),
76
+ metallicFactor: c.metallicFactor.get(i),
77
+ roughnessFactor: c.roughnessFactor.get(i),
78
+ normalScale: c.normalScale.get(i),
79
+ occlusionStrength: c.occlusionStrength.get(i),
80
+ });
81
+ loadMaterialMaps(device, arrays, layer, {
82
+ baseColorUrl: c.baseColorUrl.get(i),
83
+ metallicRoughnessUrl: c.metallicRoughnessUrl.get(i),
84
+ normalUrl: c.normalUrl.get(i),
85
+ occlusionUrl: c.occlusionUrl.get(i),
86
+ emissiveUrl: c.emissiveUrl.get(i),
87
+ });
88
+ db.store.update(id, { _layerIndex: layer });
89
+ }
90
+ }
91
+ };
92
+ },
93
+ },
94
+ },
95
+ });