@woosh/meep-engine 3.24.0 → 3.26.0

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 (349) hide show
  1. package/package.json +1 -1
  2. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +59 -0
  3. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
  4. package/src/core/geom/3d/shape/HeightMapShape3D.js +285 -0
  5. package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
  6. package/src/core/geom/3d/shape/PosedShape3D.js +57 -0
  7. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  8. package/src/core/geom/3d/shape/TransformedShape3D.js +102 -0
  9. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  10. package/src/core/geom/3d/shape/UnionShape3D.js +64 -0
  11. package/src/engine/graphics3/PickingSystem.d.ts +3 -3
  12. package/src/engine/graphics3/PickingSystem.d.ts.map +1 -1
  13. package/src/engine/graphics3/PickingSystem.js +52 -55
  14. package/src/engine/graphics3/shader_picking_gather.d.ts +40 -0
  15. package/src/engine/graphics3/shader_picking_gather.d.ts.map +1 -0
  16. package/src/engine/graphics3/shader_picking_gather.js +120 -0
  17. package/src/engine/physics/cloth/MEASUREMENTS.md +1632 -0
  18. package/src/engine/physics/cloth/PLAN.md +738 -95
  19. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +84 -17
  20. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
  21. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +451 -42
  22. package/src/engine/physics/cloth/ecs/ClothColliderSerializationAdapter.d.ts +52 -0
  23. package/src/engine/physics/cloth/ecs/ClothColliderSerializationAdapter.d.ts.map +1 -0
  24. package/src/engine/physics/cloth/ecs/ClothColliderSerializationAdapter.js +70 -0
  25. package/src/engine/physics/cloth/ecs/ClothDynamics.d.ts +12 -3
  26. package/src/engine/physics/cloth/ecs/ClothDynamics.d.ts.map +1 -1
  27. package/src/engine/physics/cloth/ecs/ClothDynamics.js +340 -331
  28. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +101 -29
  29. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  30. package/src/engine/physics/cloth/ecs/ClothInstance.js +110 -31
  31. package/src/engine/physics/cloth/ecs/ClothSerializationAdapter.d.ts +84 -0
  32. package/src/engine/physics/cloth/ecs/ClothSerializationAdapter.d.ts.map +1 -0
  33. package/src/engine/physics/cloth/ecs/ClothSerializationAdapter.js +141 -0
  34. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +71 -81
  35. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  36. package/src/engine/physics/cloth/ecs/ClothSystem.js +135 -856
  37. package/src/engine/physics/cloth/ecs/ClothWorkerCore.d.ts +48 -0
  38. package/src/engine/physics/cloth/ecs/ClothWorkerCore.d.ts.map +1 -0
  39. package/src/engine/physics/cloth/ecs/ClothWorkerCore.js +107 -0
  40. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +323 -0
  41. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -0
  42. package/src/engine/physics/cloth/ecs/ClothWorld.js +1248 -0
  43. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +192 -0
  44. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -0
  45. package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +578 -0
  46. package/src/engine/physics/cloth/ecs/cloth.worker.d.ts +2 -0
  47. package/src/engine/physics/cloth/ecs/cloth.worker.d.ts.map +1 -0
  48. package/src/engine/physics/cloth/ecs/cloth.worker.js +12 -0
  49. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  50. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +2 -1
  51. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +85 -3
  52. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  53. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +366 -271
  54. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +95 -12
  55. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
  56. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +170 -27
  57. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +19 -0
  58. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  59. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +249 -201
  60. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -0
  61. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  62. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +62 -1
  63. package/src/engine/physics/cloth/ecs/cloth_worker_protocol.d.ts +29 -0
  64. package/src/engine/physics/cloth/ecs/cloth_worker_protocol.d.ts.map +1 -0
  65. package/src/engine/physics/cloth/ecs/cloth_worker_protocol.js +78 -0
  66. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  67. package/src/engine/physics/cloth/ecs/cloth_write_back.js +18 -10
  68. package/src/engine/physics/cloth/ecs/makeClothWorker.d.ts +17 -0
  69. package/src/engine/physics/cloth/ecs/makeClothWorker.d.ts.map +1 -0
  70. package/src/engine/physics/cloth/ecs/makeClothWorker.js +18 -0
  71. package/src/engine/physics/cloth/playground/README.md +73 -2
  72. package/src/engine/physics/cloth/playground/collide_main.js +1 -1
  73. package/src/engine/physics/cloth/playground/wind.html +166 -0
  74. package/src/engine/physics/cloth/playground/wind_build.d.ts +81 -0
  75. package/src/engine/physics/cloth/playground/wind_build.d.ts.map +1 -0
  76. package/src/engine/physics/cloth/playground/wind_build.js +141 -0
  77. package/src/engine/physics/cloth/playground/wind_main.d.ts +2 -0
  78. package/src/engine/physics/cloth/playground/wind_main.d.ts.map +1 -0
  79. package/src/engine/physics/cloth/playground/wind_main.js +681 -0
  80. package/src/engine/physics/cloth/solver/ClothState.d.ts +134 -79
  81. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  82. package/src/engine/physics/cloth/solver/ClothState.js +273 -12
  83. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +29 -8
  84. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
  85. package/src/engine/physics/cloth/solver/cloth_contact_find.js +37 -9
  86. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +45 -2
  87. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  88. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +46 -2
  89. package/src/engine/physics/cloth/solver/cloth_step.d.ts +21 -2
  90. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  91. package/src/engine/physics/cloth/solver/cloth_step.js +173 -4
  92. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts +40 -0
  93. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -0
  94. package/src/engine/physics/cloth/solver/cloth_step_instance.js +284 -0
  95. package/src/engine/physics/cloth/solver/cloth_wind_accelerate.d.ts +107 -0
  96. package/src/engine/physics/cloth/solver/cloth_wind_accelerate.d.ts.map +1 -0
  97. package/src/engine/physics/cloth/solver/cloth_wind_accelerate.js +263 -0
  98. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +9 -2
  99. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -1
  100. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +9 -2
  101. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts +102 -0
  102. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts.map +1 -0
  103. package/src/engine/physics/cloth/wind/AbstractClothWind.js +114 -0
  104. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts +87 -0
  105. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts.map +1 -0
  106. package/src/engine/physics/cloth/wind/ClothAmbientWind.js +185 -0
  107. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts +79 -0
  108. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -0
  109. package/src/engine/physics/cloth/wind/ClothFluidWind.js +213 -0
  110. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +106 -0
  111. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -0
  112. package/src/engine/physics/cloth/wind/cloth_sample_air.js +297 -0
  113. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  114. package/src/shade/device/mock/texture_copy.d.ts.map +1 -1
  115. package/src/shade/device/mock/texture_copy.js +28 -0
  116. package/src/shade/playground/vgeo_runtime/README.md +94 -0
  117. package/src/shade/playground/vgeo_runtime/index.html +62 -0
  118. package/src/shade/playground/vgeo_runtime/main.d.ts +2 -0
  119. package/src/shade/playground/vgeo_runtime/main.d.ts.map +1 -0
  120. package/src/shade/playground/vgeo_runtime/main.js +399 -0
  121. package/src/shade/playground/vgeo_viewer/sample_asset.js +1 -1
  122. package/src/shade/renderer/camera/Camera.d.ts +14 -0
  123. package/src/shade/renderer/camera/Camera.d.ts.map +1 -1
  124. package/src/shade/renderer/camera/Camera.js +7 -1
  125. package/src/shade/renderer/geometry/GEOMETRY_METADATA_STRUCT.d.ts.map +1 -1
  126. package/src/shade/renderer/geometry/GEOMETRY_METADATA_STRUCT.js +16 -1
  127. package/src/shade/renderer/geometry/GPUGeometryManager.d.ts.map +1 -1
  128. package/src/shade/renderer/geometry/GPUGeometryManager.js +29 -9
  129. package/src/shade/renderer/geometry/GPUGeometryMetadata.d.ts +10 -0
  130. package/src/shade/renderer/geometry/GPUGeometryMetadata.d.ts.map +1 -1
  131. package/src/shade/renderer/geometry/GPUGeometryMetadata.js +13 -0
  132. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +46 -18
  133. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +70 -22
  134. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +97 -19
  135. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +12 -2
  136. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
  137. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +14 -3
  138. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts +2 -2
  139. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +1 -1
  140. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js +124 -6
  141. package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.d.ts +22 -0
  142. package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.d.ts.map +1 -0
  143. package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.js +53 -0
  144. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +8 -1
  145. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
  146. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +8 -1
  147. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.d.ts +16 -0
  148. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.d.ts.map +1 -0
  149. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.js +15 -0
  150. package/src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.d.ts +54 -0
  151. package/src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.d.ts.map +1 -0
  152. package/src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.js +53 -0
  153. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts +13 -2
  154. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts.map +1 -1
  155. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js +14 -2
  156. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +100 -0
  157. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
  158. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +113 -0
  159. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_header.d.ts.map +1 -1
  160. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_header.js +5 -0
  161. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts.map +1 -1
  162. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +108 -0
  163. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
  164. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +23 -0
  165. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  166. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +40 -0
  167. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts +228 -0
  168. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts.map +1 -0
  169. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.js +932 -0
  170. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +176 -0
  171. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -0
  172. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +425 -0
  173. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +241 -0
  174. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +574 -0
  175. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +120 -0
  176. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -0
  177. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +674 -0
  178. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts +287 -0
  179. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -0
  180. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +976 -0
  181. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +42 -0
  182. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts.map +1 -0
  183. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +96 -0
  184. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_CULL.d.ts +16 -0
  185. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_CULL.d.ts.map +1 -0
  186. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_CULL.js +15 -0
  187. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts +19 -0
  188. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts.map +1 -0
  189. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js +83 -0
  190. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_WORKGROUP_SIZE.d.ts +9 -0
  191. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_WORKGROUP_SIZE.d.ts.map +1 -0
  192. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_WORKGROUP_SIZE.js +8 -0
  193. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts +19 -0
  194. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -0
  195. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +160 -0
  196. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts +3 -0
  197. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -0
  198. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +255 -0
  199. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts +3 -0
  200. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts.map +1 -0
  201. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js +80 -0
  202. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts +3 -0
  203. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts.map +1 -0
  204. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js +144 -0
  205. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts +3 -0
  206. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -0
  207. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +530 -0
  208. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts +39 -0
  209. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts.map +1 -0
  210. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.js +54 -0
  211. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.d.ts +41 -0
  212. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.d.ts.map +1 -0
  213. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.js +56 -0
  214. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts +49 -0
  215. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -0
  216. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +328 -0
  217. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.d.ts +10 -0
  218. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.d.ts.map +1 -0
  219. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.js +51 -0
  220. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts +13 -0
  221. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts.map +1 -0
  222. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.js +12 -0
  223. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +17 -0
  224. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts.map +1 -0
  225. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +99 -0
  226. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.d.ts +9 -0
  227. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.d.ts.map +1 -0
  228. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +8 -0
  229. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts +7 -0
  230. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts.map +1 -0
  231. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.js +27 -0
  232. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.d.ts +14 -0
  233. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.d.ts.map +1 -0
  234. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.js +13 -0
  235. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_OFFSET.d.ts +7 -0
  236. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_OFFSET.d.ts.map +1 -0
  237. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_OFFSET.js +35 -0
  238. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_WORDS.d.ts +9 -0
  239. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_WORDS.d.ts.map +1 -0
  240. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_WORDS.js +8 -0
  241. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_FLAG_SELECTABLE.d.ts +15 -0
  242. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_FLAG_SELECTABLE.d.ts.map +1 -0
  243. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_FLAG_SELECTABLE.js +14 -0
  244. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts +7 -0
  245. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts.map +1 -0
  246. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.js +36 -0
  247. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts +10 -0
  248. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts.map +1 -0
  249. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.js +9 -0
  250. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_OFFSET.d.ts +11 -0
  251. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_OFFSET.d.ts.map +1 -0
  252. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_OFFSET.js +54 -0
  253. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_WORDS.d.ts +9 -0
  254. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_WORDS.d.ts.map +1 -0
  255. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_WORDS.js +8 -0
  256. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_LEAF_BIT.d.ts +11 -0
  257. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_LEAF_BIT.d.ts.map +1 -0
  258. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_LEAF_BIT.js +10 -0
  259. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_OFFSET.d.ts +7 -0
  260. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_OFFSET.d.ts.map +1 -0
  261. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_OFFSET.js +30 -0
  262. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_WORDS.d.ts +9 -0
  263. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_WORDS.d.ts.map +1 -0
  264. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_WORDS.js +8 -0
  265. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NO_CHILD_PAGE.d.ts +13 -0
  266. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NO_CHILD_PAGE.d.ts.map +1 -0
  267. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NO_CHILD_PAGE.js +12 -0
  268. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_NONE.d.ts +14 -0
  269. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_NONE.d.ts.map +1 -0
  270. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_NONE.js +13 -0
  271. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts +11 -0
  272. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts.map +1 -0
  273. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.js +61 -0
  274. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts +9 -0
  275. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts.map +1 -0
  276. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.js +8 -0
  277. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_ITEM_WORDS.d.ts +13 -0
  278. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_ITEM_WORDS.d.ts.map +1 -0
  279. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_ITEM_WORDS.js +12 -0
  280. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_GROUP_BIT.d.ts +9 -0
  281. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_GROUP_BIT.d.ts.map +1 -0
  282. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_GROUP_BIT.js +8 -0
  283. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_WANT_WORDS.d.ts +20 -0
  284. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_WANT_WORDS.d.ts.map +1 -0
  285. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_WANT_WORDS.js +19 -0
  286. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts +23 -0
  287. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -0
  288. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +70 -0
  289. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts +18 -0
  290. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts.map +1 -0
  291. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.js +25 -0
  292. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts +35 -0
  293. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts.map +1 -0
  294. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.js +41 -0
  295. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts +32 -0
  296. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -0
  297. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +138 -0
  298. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  299. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  300. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  301. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +9 -0
  302. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
  303. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +12 -1
  304. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  305. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +12 -1
  306. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
  307. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +10 -0
  308. package/src/shade/renderer/scene/GPUSceneContext.d.ts +18 -0
  309. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  310. package/src/shade/renderer/scene/GPUSceneContext.js +647 -594
  311. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -1
  312. package/src/shade/renderer/scene/rows/GPUSceneRows.js +22 -0
  313. package/src/shade/renderer/shader/chunk/geometry/mat3/chunk_mat3_singular_values.d.ts +35 -0
  314. package/src/shade/renderer/shader/chunk/geometry/mat3/chunk_mat3_singular_values.d.ts.map +1 -0
  315. package/src/shade/renderer/shader/chunk/geometry/mat3/chunk_mat3_singular_values.js +91 -0
  316. package/src/engine/graphics3/instantiate_scene_bundle.d.ts +0 -54
  317. package/src/engine/graphics3/instantiate_scene_bundle.d.ts.map +0 -1
  318. package/src/engine/graphics3/shade_node_to_entity_composition.d.ts +0 -39
  319. package/src/engine/graphics3/shade_node_to_entity_composition.d.ts.map +0 -1
  320. package/src/shade/renderer/animation/compute_skin_world_bounds.d.ts +0 -35
  321. package/src/shade/renderer/animation/compute_skin_world_bounds.d.ts.map +0 -1
  322. package/src/shade/renderer/animation/compute_skinned_mesh_clip_bounding_sphere.d.ts +0 -96
  323. package/src/shade/renderer/animation/compute_skinned_mesh_clip_bounding_sphere.d.ts.map +0 -1
  324. package/src/shade/renderer/animation/pose/pose_evaluate_world.d.ts +0 -20
  325. package/src/shade/renderer/animation/pose/pose_evaluate_world.d.ts.map +0 -1
  326. package/src/shade/renderer/animation/skin_bind_transform.d.ts +0 -25
  327. package/src/shade/renderer/animation/skin_bind_transform.d.ts.map +0 -1
  328. package/src/shade/renderer/animation/skin_frame_defect.d.ts +0 -34
  329. package/src/shade/renderer/animation/skin_frame_defect.d.ts.map +0 -1
  330. package/src/shade/renderer/animation/skin_joint_matrix.d.ts +0 -24
  331. package/src/shade/renderer/animation/skin_joint_matrix.d.ts.map +0 -1
  332. package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts +0 -70
  333. package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts.map +0 -1
  334. package/src/shade/renderer/buffer/table/GPUReadbackStagingRing.d.ts +0 -96
  335. package/src/shade/renderer/buffer/table/GPUReadbackStagingRing.d.ts.map +0 -1
  336. package/src/shade/renderer/scene/InstanceBatch.d.ts +0 -92
  337. package/src/shade/renderer/scene/InstanceBatch.d.ts.map +0 -1
  338. package/src/shade/renderer/scene/Mesh.d.ts +0 -55
  339. package/src/shade/renderer/scene/Mesh.d.ts.map +0 -1
  340. package/src/shade/renderer/scene/Node3D.d.ts +0 -159
  341. package/src/shade/renderer/scene/Node3D.d.ts.map +0 -1
  342. package/src/shade/renderer/scene/Node3DDirtyList.d.ts +0 -59
  343. package/src/shade/renderer/scene/Node3DDirtyList.d.ts.map +0 -1
  344. package/src/shade/renderer/scene/SceneNodeBinding.d.ts +0 -52
  345. package/src/shade/renderer/scene/SceneNodeBinding.d.ts.map +0 -1
  346. package/src/shade/renderer/scene/SkinnedMesh.d.ts +0 -27
  347. package/src/shade/renderer/scene/SkinnedMesh.d.ts.map +0 -1
  348. package/src/shade/renderer/scene/TransformAuthority.d.ts +0 -19
  349. package/src/shade/renderer/scene/TransformAuthority.d.ts.map +0 -1
@@ -0,0 +1,213 @@
1
+ import { FluidComponent } from "../../fluid/ecs/FluidComponent.js";
2
+ import { AbstractClothWind } from "./AbstractClothWind.js";
3
+ import { ClothAmbientWind } from "./ClothAmbientWind.js";
4
+
5
+ /**
6
+ * # The air, read out of the fluid simulation that is already running
7
+ *
8
+ * §10's whole argument: this engine has a fluid simulator, `FluidObstacle`
9
+ * already voxelises physics colliders into it, so a character running past a
10
+ * cape gets a **wake** without anything cloth-specific being authored. This is
11
+ * the source that reads it — every enabled {@link FluidComponent} in the scene,
12
+ * sampled trilinearly where a particle actually is.
13
+ *
14
+ * Where no field reaches, {@link ambient} answers instead, so this is the one
15
+ * source a scene needs rather than a thing to switch between: a banner inside a
16
+ * wind tunnel volume reads the tunnel, the same banner carried outside reads the
17
+ * prevailing weather, and the cloth never learns which happened.
18
+ *
19
+ * ## Two units problems, and they are the reason this class exists at all
20
+ *
21
+ * A caller cannot simply forward `FluidComponent#sampleVelocityAtWorld`:
22
+ *
23
+ * - **Cells, not metres.** `FluidField#sampleVelocity` answers in *grid cells*
24
+ * per second and says so — it "does NOT rescale them, on the assumption that
25
+ * callers (vegetation sway, dust drift) interpret the field as a direction ×
26
+ * magnitude wind". Cloth's drag row is a relaxation toward a **velocity**, so
27
+ * the same wind voxelised at 0.25 m instead of 1 m would blow a garment four
28
+ * times as hard. The multiply by `cell_size` is here. `MEASUREMENTS.md` §45.
29
+ * - **Unbuilt fields read as null.** A `FluidComponent` exists from the moment
30
+ * the entity is spawned and its field's buffers arrive at `build()`. Sampling
31
+ * before that is a null dereference rather than a zero, so an unbuilt field is
32
+ * skipped exactly like a disabled one.
33
+ *
34
+ * ## The field list is rebuilt once a step, not once a cloth
35
+ *
36
+ * {@link begin} walks the dataset and caches each live field with its world
37
+ * box. Every cloth's {@link varies} and every particle's {@link sample} then
38
+ * read that cache, so a scene with twenty garments and one wind volume walks the
39
+ * dataset once. `FluidSystem` does the equivalent per field for its effectors
40
+ * and notes the same trade.
41
+ *
42
+ * ## What it does not do
43
+ *
44
+ * **It does not blend at a field's edge.** A point inside a field's box reads
45
+ * the field and a point outside reads the ambient, so a garment straddling the
46
+ * boundary sees a step in the air rather than a ramp. In a scene where the
47
+ * ambient is the far field the volume relaxes toward — `GlobalFluidEffector`'s
48
+ * `wind` — the step is small and mostly the disturbance the volume exists to
49
+ * carry; where it is not, it is visible, and the answer is a volume large enough
50
+ * to hold what moves through it. **Overlapping fields are resolved by order**,
51
+ * first match wins, which is the same arbitrary-but-deterministic rule
52
+ * `FluidSystem` applies when it steps them independently.
53
+ *
54
+ * @author Alex Goldring
55
+ * @copyright Company Named Limited (c) 2026
56
+ */
57
+ export class ClothFluidWind extends AbstractClothWind {
58
+
59
+ /**
60
+ * What the air is where no field reaches. Present rather than optional
61
+ * because "outside every fluid volume" is most of the world.
62
+ * @type {ClothAmbientWind}
63
+ */
64
+ ambient = new ClothAmbientWind();
65
+
66
+ /**
67
+ * Live fields this step: the component and its world box, six words each.
68
+ * @type {FluidComponent[]}
69
+ * @private
70
+ */
71
+ __components = [];
72
+
73
+ /**
74
+ * @type {number[]}
75
+ * @private
76
+ */
77
+ __bounds = [];
78
+
79
+ /**
80
+ * @type {number}
81
+ * @private
82
+ */
83
+ __count = 0;
84
+
85
+ /**
86
+ * @param {number} time
87
+ * @param {EntityComponentDataset} ecd
88
+ * @returns {void}
89
+ */
90
+ begin(time, ecd) {
91
+ this.ambient.begin(time, ecd);
92
+
93
+ const components = this.__components;
94
+ const bounds = this.__bounds;
95
+
96
+ let count = 0;
97
+
98
+ if (ecd !== null && ecd !== undefined) {
99
+ ecd.traverseComponents(FluidComponent, component => {
100
+ if (!component.enabled) {
101
+ return;
102
+ }
103
+
104
+ const field = component.field;
105
+
106
+ if (field.velocity_x === null) {
107
+ // Not built yet — `setResolution`/`build` has not run, so
108
+ // there are no buffers to sample.
109
+ return;
110
+ }
111
+
112
+ const resolution = field.getResolution();
113
+
114
+ const cell_size = component.cell_size;
115
+
116
+ const origin = component.origin;
117
+
118
+ const b = count * 6;
119
+
120
+ bounds[b] = origin[0];
121
+ bounds[b + 1] = origin[1];
122
+ bounds[b + 2] = origin[2];
123
+ bounds[b + 3] = origin[0] + resolution[0] * cell_size;
124
+ bounds[b + 4] = origin[1] + resolution[1] * cell_size;
125
+ bounds[b + 5] = origin[2] + resolution[2] * cell_size;
126
+
127
+ components[count] = component;
128
+
129
+ count++;
130
+ });
131
+ }
132
+
133
+ // Drop references to components that are no longer live, so a despawned
134
+ // fluid volume is not kept alive by this cache.
135
+ for (let i = count; i < components.length; i++) {
136
+ components[i] = null;
137
+ }
138
+
139
+ this.__count = count;
140
+ }
141
+
142
+ /**
143
+ * @param {number} min_x
144
+ * @param {number} min_y
145
+ * @param {number} min_z
146
+ * @param {number} max_x
147
+ * @param {number} max_y
148
+ * @param {number} max_z
149
+ * @returns {boolean} whether a fluid field reaches into this box — and so
150
+ * whether the caller has to sample per particle rather than once
151
+ */
152
+ varies(min_x, min_y, min_z, max_x, max_y, max_z) {
153
+ const count = this.__count;
154
+
155
+ const bounds = this.__bounds;
156
+
157
+ for (let i = 0; i < count; i++) {
158
+ const b = i * 6;
159
+
160
+ if (max_x >= bounds[b]
161
+ && max_y >= bounds[b + 1]
162
+ && max_z >= bounds[b + 2]
163
+ && min_x <= bounds[b + 3]
164
+ && min_y <= bounds[b + 4]
165
+ && min_z <= bounds[b + 5]) {
166
+ return true;
167
+ }
168
+ }
169
+
170
+ return false;
171
+ }
172
+
173
+ /**
174
+ * @param {Float64Array|number[]} out
175
+ * @param {number} x
176
+ * @param {number} y
177
+ * @param {number} z
178
+ * @param {number} time seconds the asking cloth has stepped, for the
179
+ * ambient fallback; a field's own velocities are a snapshot of this tick
180
+ * and are not a function of it
181
+ * @returns {Float64Array|number[]}
182
+ */
183
+ sample(out, x, y, z, time) {
184
+ const count = this.__count;
185
+
186
+ const bounds = this.__bounds;
187
+
188
+ for (let i = 0; i < count; i++) {
189
+ const b = i * 6;
190
+
191
+ if (x < bounds[b] || x > bounds[b + 3]
192
+ || y < bounds[b + 1] || y > bounds[b + 4]
193
+ || z < bounds[b + 2] || z > bounds[b + 5]) {
194
+ continue;
195
+ }
196
+
197
+ const component = this.__components[i];
198
+
199
+ component.sampleVelocityAtWorld(out, x, y, z);
200
+
201
+ // Cells per second to metres per second. See the header.
202
+ const cell_size = component.cell_size;
203
+
204
+ out[0] *= cell_size;
205
+ out[1] *= cell_size;
206
+ out[2] *= cell_size;
207
+
208
+ return out;
209
+ }
210
+
211
+ return this.ambient.sample(out, x, y, z, time);
212
+ }
213
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * # Reading the air into the cloth's own frame
3
+ *
4
+ * The one piece of §10 that has to run on the **main thread**, and the milestone's
5
+ * design decision. M5 moved every number the solver touches onto a worker; a
6
+ * fluid field is not one of those numbers. It is an ECS component holding a
7
+ * hundred thousand floats that the fluid solver rewrites every step, it may
8
+ * itself already live on a *different* worker (`WorkerFluidSystem`), and nothing
9
+ * about it is shaped like a cloth. Sending it across per step would cost more
10
+ * than the whole cloth step it was supposed to feed.
11
+ *
12
+ * So the split is the one §12 already draws — "arbitrary user-facing work —
13
+ * component reads, `Transform64` sync, index queries — stays on the main thread;
14
+ * the pure numeric step crosses" — applied once more. A field query is an index
15
+ * query. What crosses is the **answer**: one air velocity per particle, written
16
+ * into {@link ClothState#air_velocity}, which is a region of the cloth's own
17
+ * buffer and therefore already shared memory. Nothing is copied and nothing is
18
+ * marshalled; the main thread writes exactly where the worker reads. §39's "one
19
+ * buffer per cloth" is what makes that free.
20
+ *
21
+ * The **drag arithmetic** is not here, deliberately. It reads positions and
22
+ * velocities the state already holds, so it belongs with the rest of the
23
+ * arithmetic in `cloth_step_instance` — which keeps §40's property intact:
24
+ * neither system computes a step parameter of its own, the drag response crosses
25
+ * as one more word of the block, and the acceleration is built by the one
26
+ * function both systems call. `MEASUREMENTS.md` §45.
27
+ *
28
+ * ## Two costs, and only one of them scales
29
+ *
30
+ * A source that answers `varies() === false` — {@link ClothAmbientWind}, and
31
+ * {@link ClothFluidWind} anywhere its fields do not reach — is sampled **once**
32
+ * for the whole cloth. What is left is a bounds scan and a fill, both linear in
33
+ * particles with a handful of operations each, and both an order below a
34
+ * trilinear sample. That is the case §10 calls "no fluid field in range", and it
35
+ * is the common one. `MEASUREMENTS.md` §47 is what each costs.
36
+ *
37
+ * @author Alex Goldring
38
+ * @copyright Company Named Limited (c) 2026
39
+ */
40
+ /**
41
+ * Fill {@link ClothState#air_velocity} with the air each particle sits in,
42
+ * rotated into the cloth's local frame.
43
+ *
44
+ * @param {ClothState} state
45
+ * @param {AbstractClothWind} wind
46
+ * @param {Float64Array} anchor_translation the cloth frame's world origin
47
+ * @param {Float64Array} anchor_rotation the cloth frame's world rotation, xyzw
48
+ * @param {Float64Array} [centre] written with the world-space air at the cloth's
49
+ * own centre — what the sleep test compares against next step
50
+ * @param {number} [time] seconds this cloth has stepped, the clock its gust is a
51
+ * function of — see {@link AbstractClothWind}
52
+ * @returns {boolean} whether the source was sampled per particle
53
+ */
54
+ export function cloth_sample_air(state: ClothState, wind: AbstractClothWind, anchor_translation: Float64Array, anchor_rotation: Float64Array, centre?: Float64Array, time?: number): boolean;
55
+ /**
56
+ * Whether the air at the cloth's centre has moved far enough since the last step
57
+ * that actually applied it to be worth waking for — §10's "sleep wakes on a wind
58
+ * change, so a settled banner does not sleep through a gust".
59
+ *
60
+ * The comparison is against the last **applied** air rather than the last
61
+ * sampled one, so a gust that arrives slowly still wakes the cloth: the
62
+ * difference accumulates instead of being reset by every step that declined to
63
+ * act on it.
64
+ *
65
+ * The threshold is the sleep test's own speed ratio, and that is deliberately
66
+ * conservative — the velocity a wind change of `Δu` actually produces in one
67
+ * step is `(1 − e^(−rate·dt))·facing·Δu`, a fraction of it, so this wakes on a
68
+ * change several times smaller than the one that would keep the cloth awake.
69
+ * Erring that way is the point: the failure §10 names is a banner sleeping
70
+ * through a gust, not one waking a few steps early.
71
+ *
72
+ * **Its limit, stated.** One point, at the cloth's centre. A wake that reaches
73
+ * only the hem of a sleeping banner and leaves its middle still will not wake
74
+ * it. The collider wake test next to it has no such gap because a collider's
75
+ * pose is seven exact numbers and a field is a continuum — the honest fix is
76
+ * more sample points, and the measurement is that one is enough for anything
77
+ * that crosses a garment rather than grazing it.
78
+ *
79
+ * @param {ClothState} state
80
+ * @param {AbstractClothWind} wind
81
+ * @param {Float64Array} anchor_translation
82
+ * @param {Float64Array} anchor_rotation
83
+ * @param {Float64Array} previous the air last applied to this cloth, world-space
84
+ * @param {number} threshold m/s
85
+ * @param {number} time seconds the cloth has stepped — the clock its gust is a
86
+ * function of, which for a sleeping cloth is the age its *next* step would
87
+ * have, because it has to be asking about the air that step would feel
88
+ * @returns {boolean}
89
+ */
90
+ export function cloth_air_changed(state: ClothState, wind: AbstractClothWind, anchor_translation: Float64Array, anchor_rotation: Float64Array, previous: Float64Array, threshold: number, time: number): boolean;
91
+ /**
92
+ * The cloth's world-space axis-aligned bounds.
93
+ *
94
+ * The particles are local, so this is the bounds of the **rotated** local box
95
+ * rather than the rotation of its bounds — the same eight-corner argument
96
+ * `cloth_gather_colliders` makes for its own query volume, and the same reason:
97
+ * a rotated box is not a box.
98
+ *
99
+ * @param {ClothState} state
100
+ * @param {Float64Array} anchor_translation
101
+ * @param {Float64Array} anchor_rotation
102
+ * @param {Float64Array} out six words, min then max
103
+ * @returns {void}
104
+ */
105
+ export function cloth_air_bounds(state: ClothState, anchor_translation: Float64Array, anchor_rotation: Float64Array, out: Float64Array): void;
106
+ //# sourceMappingURL=cloth_sample_air.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloth_sample_air.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/wind/cloth_sample_air.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH;;;;;;;;;;;;;GAaG;AACH,iGARW,YAAY,mBACZ,YAAY,WACZ,YAAY,SAEZ,MAAM,GAEJ,OAAO,CA8EnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,kGATW,YAAY,mBACZ,YAAY,YACZ,YAAY,aACZ,MAAM,QACN,MAAM,GAGJ,OAAO,CAsBnB;AAED;;;;;;;;;;;;;GAaG;AACH,wEALW,YAAY,mBACZ,YAAY,OACZ,YAAY,GACV,IAAI,CAoEhB"}
@@ -0,0 +1,297 @@
1
+ import { v3_quaternion_apply } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
2
+ import { v3_quaternion_apply_inverse } from "../../../../core/geom/vec3/v3_quaternion_apply_inverse.js";
3
+
4
+ /**
5
+ * # Reading the air into the cloth's own frame
6
+ *
7
+ * The one piece of §10 that has to run on the **main thread**, and the milestone's
8
+ * design decision. M5 moved every number the solver touches onto a worker; a
9
+ * fluid field is not one of those numbers. It is an ECS component holding a
10
+ * hundred thousand floats that the fluid solver rewrites every step, it may
11
+ * itself already live on a *different* worker (`WorkerFluidSystem`), and nothing
12
+ * about it is shaped like a cloth. Sending it across per step would cost more
13
+ * than the whole cloth step it was supposed to feed.
14
+ *
15
+ * So the split is the one §12 already draws — "arbitrary user-facing work —
16
+ * component reads, `Transform64` sync, index queries — stays on the main thread;
17
+ * the pure numeric step crosses" — applied once more. A field query is an index
18
+ * query. What crosses is the **answer**: one air velocity per particle, written
19
+ * into {@link ClothState#air_velocity}, which is a region of the cloth's own
20
+ * buffer and therefore already shared memory. Nothing is copied and nothing is
21
+ * marshalled; the main thread writes exactly where the worker reads. §39's "one
22
+ * buffer per cloth" is what makes that free.
23
+ *
24
+ * The **drag arithmetic** is not here, deliberately. It reads positions and
25
+ * velocities the state already holds, so it belongs with the rest of the
26
+ * arithmetic in `cloth_step_instance` — which keeps §40's property intact:
27
+ * neither system computes a step parameter of its own, the drag response crosses
28
+ * as one more word of the block, and the acceleration is built by the one
29
+ * function both systems call. `MEASUREMENTS.md` §45.
30
+ *
31
+ * ## Two costs, and only one of them scales
32
+ *
33
+ * A source that answers `varies() === false` — {@link ClothAmbientWind}, and
34
+ * {@link ClothFluidWind} anywhere its fields do not reach — is sampled **once**
35
+ * for the whole cloth. What is left is a bounds scan and a fill, both linear in
36
+ * particles with a handful of operations each, and both an order below a
37
+ * trilinear sample. That is the case §10 calls "no fluid field in range", and it
38
+ * is the common one. `MEASUREMENTS.md` §47 is what each costs.
39
+ *
40
+ * @author Alex Goldring
41
+ * @copyright Company Named Limited (c) 2026
42
+ */
43
+
44
+ /**
45
+ * Fill {@link ClothState#air_velocity} with the air each particle sits in,
46
+ * rotated into the cloth's local frame.
47
+ *
48
+ * @param {ClothState} state
49
+ * @param {AbstractClothWind} wind
50
+ * @param {Float64Array} anchor_translation the cloth frame's world origin
51
+ * @param {Float64Array} anchor_rotation the cloth frame's world rotation, xyzw
52
+ * @param {Float64Array} [centre] written with the world-space air at the cloth's
53
+ * own centre — what the sleep test compares against next step
54
+ * @param {number} [time] seconds this cloth has stepped, the clock its gust is a
55
+ * function of — see {@link AbstractClothWind}
56
+ * @returns {boolean} whether the source was sampled per particle
57
+ */
58
+ export function cloth_sample_air(state, wind, anchor_translation, anchor_rotation, centre = undefined, time = 0) {
59
+ const particle_count = state.particle_count;
60
+
61
+ const air = state.air_velocity;
62
+
63
+ if (particle_count === 0) {
64
+ return false;
65
+ }
66
+
67
+ const position = state.position;
68
+
69
+ const anchor_x = anchor_translation[0];
70
+ const anchor_y = anchor_translation[1];
71
+ const anchor_z = anchor_translation[2];
72
+
73
+ const qx = anchor_rotation[0];
74
+ const qy = anchor_rotation[1];
75
+ const qz = anchor_rotation[2];
76
+ const qw = anchor_rotation[3];
77
+
78
+ cloth_air_bounds(state, anchor_translation, anchor_rotation, BOUNDS);
79
+
80
+ const varies = wind.varies(BOUNDS[0], BOUNDS[1], BOUNDS[2], BOUNDS[3], BOUNDS[4], BOUNDS[5]);
81
+
82
+ // The cloth's own centre: where a uniform source is read, and where the
83
+ // sleep test asks whether the air has changed.
84
+ wind.sample(
85
+ SAMPLE,
86
+ (BOUNDS[0] + BOUNDS[3]) * 0.5,
87
+ (BOUNDS[1] + BOUNDS[4]) * 0.5,
88
+ (BOUNDS[2] + BOUNDS[5]) * 0.5,
89
+ time
90
+ );
91
+
92
+ if (centre !== undefined) {
93
+ centre[0] = SAMPLE[0];
94
+ centre[1] = SAMPLE[1];
95
+ centre[2] = SAMPLE[2];
96
+ }
97
+
98
+ if (!varies) {
99
+ // One vector for the whole cloth. `varies() === false` is a promise
100
+ // rather than a hint, so this is exact rather than an approximation the
101
+ // caller opted into.
102
+ v3_quaternion_apply_inverse(LOCAL, 0, SAMPLE[0], SAMPLE[1], SAMPLE[2], qx, qy, qz, qw);
103
+
104
+ const local_x = LOCAL[0];
105
+ const local_y = LOCAL[1];
106
+ const local_z = LOCAL[2];
107
+
108
+ for (let i = 0; i < particle_count; i++) {
109
+ const p = i * 3;
110
+
111
+ air[p] = local_x;
112
+ air[p + 1] = local_y;
113
+ air[p + 2] = local_z;
114
+ }
115
+
116
+ return false;
117
+ }
118
+
119
+ for (let i = 0; i < particle_count; i++) {
120
+ const p = i * 3;
121
+
122
+ v3_quaternion_apply(WORLD, 0, position[p], position[p + 1], position[p + 2], qx, qy, qz, qw);
123
+
124
+ wind.sample(SAMPLE, WORLD[0] + anchor_x, WORLD[1] + anchor_y, WORLD[2] + anchor_z, time);
125
+
126
+ v3_quaternion_apply_inverse(LOCAL, 0, SAMPLE[0], SAMPLE[1], SAMPLE[2], qx, qy, qz, qw);
127
+
128
+ air[p] = LOCAL[0];
129
+ air[p + 1] = LOCAL[1];
130
+ air[p + 2] = LOCAL[2];
131
+ }
132
+
133
+ return true;
134
+ }
135
+
136
+ /**
137
+ * Whether the air at the cloth's centre has moved far enough since the last step
138
+ * that actually applied it to be worth waking for — §10's "sleep wakes on a wind
139
+ * change, so a settled banner does not sleep through a gust".
140
+ *
141
+ * The comparison is against the last **applied** air rather than the last
142
+ * sampled one, so a gust that arrives slowly still wakes the cloth: the
143
+ * difference accumulates instead of being reset by every step that declined to
144
+ * act on it.
145
+ *
146
+ * The threshold is the sleep test's own speed ratio, and that is deliberately
147
+ * conservative — the velocity a wind change of `Δu` actually produces in one
148
+ * step is `(1 − e^(−rate·dt))·facing·Δu`, a fraction of it, so this wakes on a
149
+ * change several times smaller than the one that would keep the cloth awake.
150
+ * Erring that way is the point: the failure §10 names is a banner sleeping
151
+ * through a gust, not one waking a few steps early.
152
+ *
153
+ * **Its limit, stated.** One point, at the cloth's centre. A wake that reaches
154
+ * only the hem of a sleeping banner and leaves its middle still will not wake
155
+ * it. The collider wake test next to it has no such gap because a collider's
156
+ * pose is seven exact numbers and a field is a continuum — the honest fix is
157
+ * more sample points, and the measurement is that one is enough for anything
158
+ * that crosses a garment rather than grazing it.
159
+ *
160
+ * @param {ClothState} state
161
+ * @param {AbstractClothWind} wind
162
+ * @param {Float64Array} anchor_translation
163
+ * @param {Float64Array} anchor_rotation
164
+ * @param {Float64Array} previous the air last applied to this cloth, world-space
165
+ * @param {number} threshold m/s
166
+ * @param {number} time seconds the cloth has stepped — the clock its gust is a
167
+ * function of, which for a sleeping cloth is the age its *next* step would
168
+ * have, because it has to be asking about the air that step would feel
169
+ * @returns {boolean}
170
+ */
171
+ export function cloth_air_changed(state, wind, anchor_translation, anchor_rotation, previous, threshold, time) {
172
+ if (state.particle_count === 0) {
173
+ return false;
174
+ }
175
+
176
+ cloth_air_bounds(state, anchor_translation, anchor_rotation, BOUNDS);
177
+
178
+ wind.sample(
179
+ SAMPLE,
180
+ (BOUNDS[0] + BOUNDS[3]) * 0.5,
181
+ (BOUNDS[1] + BOUNDS[4]) * 0.5,
182
+ (BOUNDS[2] + BOUNDS[5]) * 0.5,
183
+ time
184
+ );
185
+
186
+ const dx = SAMPLE[0] - previous[0];
187
+ const dy = SAMPLE[1] - previous[1];
188
+ const dz = SAMPLE[2] - previous[2];
189
+
190
+ return dx * dx + dy * dy + dz * dz > threshold * threshold;
191
+ }
192
+
193
+ /**
194
+ * The cloth's world-space axis-aligned bounds.
195
+ *
196
+ * The particles are local, so this is the bounds of the **rotated** local box
197
+ * rather than the rotation of its bounds — the same eight-corner argument
198
+ * `cloth_gather_colliders` makes for its own query volume, and the same reason:
199
+ * a rotated box is not a box.
200
+ *
201
+ * @param {ClothState} state
202
+ * @param {Float64Array} anchor_translation
203
+ * @param {Float64Array} anchor_rotation
204
+ * @param {Float64Array} out six words, min then max
205
+ * @returns {void}
206
+ */
207
+ export function cloth_air_bounds(state, anchor_translation, anchor_rotation, out) {
208
+ const particle_count = state.particle_count;
209
+
210
+ const position = state.position;
211
+
212
+ let min_x = Infinity;
213
+ let min_y = Infinity;
214
+ let min_z = Infinity;
215
+ let max_x = -Infinity;
216
+ let max_y = -Infinity;
217
+ let max_z = -Infinity;
218
+
219
+ for (let i = 0; i < particle_count; i++) {
220
+ const p = i * 3;
221
+
222
+ const x = position[p];
223
+ const y = position[p + 1];
224
+ const z = position[p + 2];
225
+
226
+ if (x < min_x) { min_x = x; }
227
+ if (y < min_y) { min_y = y; }
228
+ if (z < min_z) { min_z = z; }
229
+ if (x > max_x) { max_x = x; }
230
+ if (y > max_y) { max_y = y; }
231
+ if (z > max_z) { max_z = z; }
232
+ }
233
+
234
+ const qx = anchor_rotation[0];
235
+ const qy = anchor_rotation[1];
236
+ const qz = anchor_rotation[2];
237
+ const qw = anchor_rotation[3];
238
+
239
+ let world_min_x = Infinity;
240
+ let world_min_y = Infinity;
241
+ let world_min_z = Infinity;
242
+ let world_max_x = -Infinity;
243
+ let world_max_y = -Infinity;
244
+ let world_max_z = -Infinity;
245
+
246
+ for (let corner = 0; corner < 8; corner++) {
247
+ v3_quaternion_apply(
248
+ WORLD, 0,
249
+ (corner & 1) === 0 ? min_x : max_x,
250
+ (corner & 2) === 0 ? min_y : max_y,
251
+ (corner & 4) === 0 ? min_z : max_z,
252
+ qx, qy, qz, qw
253
+ );
254
+
255
+ const x = WORLD[0] + anchor_translation[0];
256
+ const y = WORLD[1] + anchor_translation[1];
257
+ const z = WORLD[2] + anchor_translation[2];
258
+
259
+ if (x < world_min_x) { world_min_x = x; }
260
+ if (y < world_min_y) { world_min_y = y; }
261
+ if (z < world_min_z) { world_min_z = z; }
262
+ if (x > world_max_x) { world_max_x = x; }
263
+ if (y > world_max_y) { world_max_y = y; }
264
+ if (z > world_max_z) { world_max_z = z; }
265
+ }
266
+
267
+ out[0] = world_min_x;
268
+ out[1] = world_min_y;
269
+ out[2] = world_min_z;
270
+ out[3] = world_max_x;
271
+ out[4] = world_max_y;
272
+ out[5] = world_max_z;
273
+ }
274
+
275
+ /**
276
+ * @type {Float64Array}
277
+ * @private
278
+ */
279
+ const BOUNDS = new Float64Array(6);
280
+
281
+ /**
282
+ * @type {Float64Array}
283
+ * @private
284
+ */
285
+ const WORLD = new Float64Array(3);
286
+
287
+ /**
288
+ * @type {Float64Array}
289
+ * @private
290
+ */
291
+ const LOCAL = new Float64Array(3);
292
+
293
+ /**
294
+ * @type {Float64Array}
295
+ * @private
296
+ */
297
+ const SAMPLE = new Float64Array(3);
@@ -64,11 +64,11 @@ export class FluidObstacleSystem extends System<any> {
64
64
  /**
65
65
  * @param {FluidComponent} fluid
66
66
  */
67
- static "__#391@#refresh_masks"(fluid: FluidComponent): void;
67
+ static "__#396@#refresh_masks"(fluid: FluidComponent): void;
68
68
  /**
69
69
  * @param {FluidComponent} fluid
70
70
  */
71
- static "__#391@#clear_field"(fluid: FluidComponent): void;
71
+ static "__#396@#clear_field"(fluid: FluidComponent): void;
72
72
  /**
73
73
  * Mark every cell of `fluid` whose centre lies within `inflation` of the
74
74
  * posed shape as solid. Iteration is clipped to the shape's world AABB
@@ -80,7 +80,7 @@ export class FluidObstacleSystem extends System<any> {
80
80
  * @param {number} inflation world-units SDF threshold
81
81
  * @param {Float64Array} point length-3 scratch
82
82
  */
83
- static "__#391@#voxelize"(fluid: FluidComponent, posed: PosedShape3D, aabb: Float64Array, inflation: number, point: Float64Array): void;
83
+ static "__#396@#voxelize"(fluid: FluidComponent, posed: PosedShape3D, aabb: Float64Array, inflation: number, point: Float64Array): void;
84
84
  /**
85
85
  * Write the obstacle's translation velocity onto every face of every cell
86
86
  * it voxelized — the moving-wall boundary condition. Runs AFTER the mask
@@ -100,7 +100,7 @@ export class FluidObstacleSystem extends System<any> {
100
100
  * @param {number} wvy
101
101
  * @param {number} wvz
102
102
  */
103
- static "__#391@#stamp_wall_velocity"(fluid: FluidComponent, posed: PosedShape3D, aabb: Float64Array, inflation: number, point: Float64Array, wvx: number, wvy: number, wvz: number): void;
103
+ static "__#396@#stamp_wall_velocity"(fluid: FluidComponent, posed: PosedShape3D, aabb: Float64Array, inflation: number, point: Float64Array, wvx: number, wvy: number, wvz: number): void;
104
104
  constructor();
105
105
  dependencies: (typeof FluidObstacle)[];
106
106
  components_used: (ResourceAccessSpecification<typeof Transform64> | ResourceAccessSpecification<typeof RigidBody> | ResourceAccessSpecification<typeof Collider> | ResourceAccessSpecification<typeof FluidComponent> | ResourceAccessSpecification<typeof FluidObstacle>)[];
@@ -1 +1 @@
1
- {"version":3,"file":"texture_copy.d.ts","sourceRoot":"","sources":["../../../../../src/shade/device/mock/texture_copy.js"],"names":[],"mappings":"AAiLA;;;;;;;;;;;;;GAaG;AACH;IAP0C,cAAc;IACf,aAAa;IACZ,mBAAmB;IACpB,kBAAkB;IAC9B,IAAI;IACpB,MAAM,GAAC,IAAI,CA4DvB;AAiED;;;;;GAKG;AACH,uHAHW,MAAM,GACJ,IAAI,CA8BhB;;;;;;UA5Fa,WAAW;;;;YACX,MAAM;gBACN,MAAM;kBACN,MAAM"}
1
+ {"version":3,"file":"texture_copy.d.ts","sourceRoot":"","sources":["../../../../../src/shade/device/mock/texture_copy.js"],"names":[],"mappings":"AA6MA;;;;;;;;;;;;;GAaG;AACH;IAP0C,cAAc;IACf,aAAa;IACZ,mBAAmB;IACpB,kBAAkB;IAC9B,IAAI;IACpB,MAAM,GAAC,IAAI,CA4DvB;AAiED;;;;;GAKG;AACH,uHAHW,MAAM,GACJ,IAAI,CA8BhB;;;;;;UA5Fa,WAAW;;;;YACX,MAAM;gBACN,MAAM;kBACN,MAAM"}