@woosh/meep-engine 3.43.0 → 3.45.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 (466) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/editor/prototypeEditorShell.d.ts.map +1 -1
  3. package/editor/prototypeEditorShell.js +4 -2
  4. package/package.json +1 -1
  5. package/src/core/collection/array/array_sort_insertion_ascending.d.ts +19 -0
  6. package/src/core/collection/array/array_sort_insertion_ascending.d.ts.map +1 -0
  7. package/src/core/collection/array/array_sort_insertion_ascending.js +31 -0
  8. package/src/core/geom/3d/aabb/aabb3_array_round_outward_f32.d.ts +27 -0
  9. package/src/core/geom/3d/aabb/aabb3_array_round_outward_f32.d.ts.map +1 -0
  10. package/src/core/geom/3d/aabb/aabb3_array_round_outward_f32.js +39 -0
  11. package/src/core/geom/3d/aabb/aabb3_from_v3_array.d.ts.map +1 -1
  12. package/src/core/geom/3d/aabb/aabb3_from_v3_array.js +4 -1
  13. package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts +2 -2
  14. package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts.map +1 -1
  15. package/src/core/geom/3d/aabb/aabb3_transform_oriented.js +1 -1
  16. package/src/core/geom/3d/pose/pose3_apply_inverse_point_array.d.ts +21 -0
  17. package/src/core/geom/3d/pose/pose3_apply_inverse_point_array.d.ts.map +1 -0
  18. package/src/core/geom/3d/pose/pose3_apply_inverse_point_array.js +36 -0
  19. package/src/core/geom/3d/pose/pose3_apply_point_array.d.ts +25 -0
  20. package/src/core/geom/3d/pose/pose3_apply_point_array.d.ts.map +1 -0
  21. package/src/core/geom/3d/pose/pose3_apply_point_array.js +40 -0
  22. package/src/core/geom/3d/pose/pose3_compose_array.d.ts +28 -0
  23. package/src/core/geom/3d/pose/pose3_compose_array.d.ts.map +1 -0
  24. package/src/core/geom/3d/pose/pose3_compose_array.js +41 -0
  25. package/src/core/geom/3d/pose/pose3_to_local_array.d.ts +29 -0
  26. package/src/core/geom/3d/pose/pose3_to_local_array.d.ts.map +1 -0
  27. package/src/core/geom/3d/pose/pose3_to_local_array.js +42 -0
  28. package/src/core/geom/3d/quaternion/quat3_clamp_angle_array.d.ts +28 -0
  29. package/src/core/geom/3d/quaternion/quat3_clamp_angle_array.d.ts.map +1 -0
  30. package/src/core/geom/3d/quaternion/quat3_clamp_angle_array.js +66 -0
  31. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_left_array.d.ts +22 -0
  32. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_left_array.d.ts.map +1 -0
  33. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_left_array.js +30 -0
  34. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_right_array.d.ts +23 -0
  35. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_right_array.d.ts.map +1 -0
  36. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_right_array.js +31 -0
  37. package/src/core/geom/3d/triangle/tri3_compute_normal_area_weighted_array.d.ts +26 -0
  38. package/src/core/geom/3d/triangle/tri3_compute_normal_area_weighted_array.d.ts.map +1 -0
  39. package/src/core/geom/3d/triangle/tri3_compute_normal_area_weighted_array.js +46 -0
  40. package/src/core/geom/vec3/v3_distance_array.d.ts +11 -0
  41. package/src/core/geom/vec3/v3_distance_array.d.ts.map +1 -0
  42. package/src/core/geom/vec3/v3_distance_array.js +19 -0
  43. package/src/core/geom/vec3/v3_normalize_array_checked.d.ts +23 -0
  44. package/src/core/geom/vec3/v3_normalize_array_checked.d.ts.map +1 -0
  45. package/src/core/geom/vec3/v3_normalize_array_checked.js +49 -0
  46. package/src/core/geom/vec3/v3_reject_array.d.ts +15 -0
  47. package/src/core/geom/vec3/v3_reject_array.d.ts.map +1 -0
  48. package/src/core/geom/vec3/v3_reject_array.js +32 -0
  49. package/src/core/graph/csr/csr_build_incidence.d.ts +26 -0
  50. package/src/core/graph/csr/csr_build_incidence.d.ts.map +1 -0
  51. package/src/core/graph/csr/csr_build_incidence.js +71 -0
  52. package/src/core/graph/csr/csr_graph_color_greedy.d.ts +25 -0
  53. package/src/core/graph/csr/csr_graph_color_greedy.d.ts.map +1 -0
  54. package/src/core/graph/csr/csr_graph_color_greedy.js +83 -0
  55. package/src/core/graph/csr/csr_graph_validate_coloring.d.ts +15 -0
  56. package/src/core/graph/csr/csr_graph_validate_coloring.d.ts.map +1 -0
  57. package/src/core/graph/csr/csr_graph_validate_coloring.js +33 -0
  58. package/src/core/math/linalg/matrix_symmetric_3x3_solve_ldlt.d.ts +26 -0
  59. package/src/core/math/linalg/matrix_symmetric_3x3_solve_ldlt.d.ts.map +1 -0
  60. package/src/core/math/linalg/matrix_symmetric_3x3_solve_ldlt.js +71 -0
  61. package/src/core/math/max2_exact.d.ts +15 -0
  62. package/src/core/math/max2_exact.d.ts.map +1 -0
  63. package/src/core/math/max2_exact.js +30 -0
  64. package/src/core/math/min2_exact.d.ts +20 -0
  65. package/src/core/math/min2_exact.d.ts.map +1 -0
  66. package/src/core/math/min2_exact.js +35 -0
  67. package/src/engine/Clock.d.ts +15 -0
  68. package/src/engine/Clock.d.ts.map +1 -1
  69. package/src/engine/Clock.js +29 -5
  70. package/src/engine/Engine.d.ts.map +1 -1
  71. package/src/engine/Engine.js +11 -19
  72. package/src/engine/ecs/ik/IKGoalSystem.d.ts.map +1 -1
  73. package/src/engine/ecs/ik/IKGoalSystem.js +3 -19
  74. package/src/engine/ecs/parent/parent_entity_model_of.d.ts +17 -0
  75. package/src/engine/ecs/parent/parent_entity_model_of.d.ts.map +1 -0
  76. package/src/engine/ecs/parent/parent_entity_model_of.js +26 -0
  77. package/src/engine/ecs/transform/t64_read_pose_array.d.ts +15 -0
  78. package/src/engine/ecs/transform/t64_read_pose_array.d.ts.map +1 -0
  79. package/src/engine/ecs/transform/t64_read_pose_array.js +24 -0
  80. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.d.ts +57 -0
  81. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.d.ts.map +1 -0
  82. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.js +84 -0
  83. package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.d.ts +2 -0
  84. package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.d.ts.map +1 -1
  85. package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.js +10 -21
  86. package/src/engine/graphics3/AnimationGraphSystem.d.ts +28 -13
  87. package/src/engine/graphics3/AnimationGraphSystem.d.ts.map +1 -1
  88. package/src/engine/graphics3/AnimationGraphSystem.js +107 -64
  89. package/src/engine/graphics3/AnimationSystem.d.ts +29 -15
  90. package/src/engine/graphics3/AnimationSystem.d.ts.map +1 -1
  91. package/src/engine/graphics3/AnimationSystem.js +112 -61
  92. package/src/engine/graphics3/MeshSkinSystem.d.ts +56 -0
  93. package/src/engine/graphics3/MeshSkinSystem.d.ts.map +1 -0
  94. package/src/engine/graphics3/MeshSkinSystem.js +317 -0
  95. package/src/engine/graphics3/MeshSystem.d.ts +15 -35
  96. package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
  97. package/src/engine/graphics3/MeshSystem.js +21 -298
  98. package/src/engine/graphics3/RowChains.d.ts +76 -0
  99. package/src/engine/graphics3/RowChains.d.ts.map +1 -0
  100. package/src/engine/graphics3/RowChains.js +347 -0
  101. package/src/engine/graphics3/ShadedGeometrySystem.d.ts +6 -0
  102. package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
  103. package/src/engine/graphics3/ShadedGeometrySystem.js +329 -309
  104. package/src/engine/graphics3/animation/AnimationClips.d.ts +56 -0
  105. package/src/engine/graphics3/animation/AnimationClips.d.ts.map +1 -0
  106. package/src/engine/graphics3/animation/AnimationClips.js +79 -0
  107. package/src/engine/graphics3/animation/ClipListPlayer.d.ts +13 -14
  108. package/src/engine/graphics3/animation/ClipListPlayer.d.ts.map +1 -1
  109. package/src/engine/graphics3/animation/ClipListPlayer.js +262 -263
  110. package/src/engine/graphics3/animation/write_clip_playback.d.ts +3 -3
  111. package/src/engine/graphics3/animation/write_clip_playback.js +4 -4
  112. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts +5 -0
  113. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts.map +1 -1
  114. package/src/engine/graphics3/pose/query_entity_node_world_pose.js +80 -75
  115. package/src/engine/graphics3/prefab/PrefabInstance.d.ts +4 -24
  116. package/src/engine/graphics3/prefab/PrefabInstance.d.ts.map +1 -1
  117. package/src/engine/graphics3/prefab/PrefabInstance.js +60 -80
  118. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts +16 -3
  119. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts.map +1 -1
  120. package/src/engine/graphics3/prefab/prefab_instantiate.js +49 -12
  121. package/src/engine/graphics3/prefab/prefab_place.d.ts +31 -17
  122. package/src/engine/graphics3/prefab/prefab_place.d.ts.map +1 -1
  123. package/src/engine/graphics3/prefab/prefab_place.js +175 -130
  124. package/src/engine/graphics3/register_clips.d.ts +93 -0
  125. package/src/engine/graphics3/register_clips.d.ts.map +1 -0
  126. package/src/engine/graphics3/register_clips.js +166 -0
  127. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts +9 -0
  128. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts.map +1 -1
  129. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +3 -1
  130. package/src/engine/physics/cloth/MEASUREMENTS.md +795 -0
  131. package/src/engine/physics/cloth/PLAN.md +349 -17
  132. package/src/engine/physics/cloth/build/ClothProxy.d.ts +113 -61
  133. package/src/engine/physics/cloth/build/ClothProxy.d.ts.map +1 -1
  134. package/src/engine/physics/cloth/build/ClothProxy.js +142 -77
  135. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts +44 -0
  136. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts.map +1 -0
  137. package/src/engine/physics/cloth/build/cloth_bind_in_frame.js +107 -0
  138. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +43 -30
  139. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  140. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +371 -284
  141. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts +62 -0
  142. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts.map +1 -0
  143. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.js +275 -0
  144. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +7 -0
  145. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
  146. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +85 -67
  147. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts.map +1 -1
  148. package/src/engine/physics/cloth/collider/cloth_collider_bounds.js +19 -101
  149. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts +2 -5
  150. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts.map +1 -1
  151. package/src/engine/physics/cloth/collider/cloth_collider_pack.js +7 -15
  152. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts +1 -1
  153. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts.map +1 -1
  154. package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +17 -62
  155. package/src/engine/physics/cloth/ecs/Cloth.d.ts +17 -9
  156. package/src/engine/physics/cloth/ecs/Cloth.d.ts.map +1 -1
  157. package/src/engine/physics/cloth/ecs/Cloth.js +220 -212
  158. package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts +0 -1
  159. package/src/engine/physics/cloth/ecs/ClothColliderFlags.js +6 -19
  160. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +1 -2
  161. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -1
  162. package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +3 -12
  163. package/src/engine/physics/cloth/ecs/ClothDynamicsFlags.js +6 -0
  164. package/src/engine/physics/cloth/ecs/ClothHold.d.ts +91 -0
  165. package/src/engine/physics/cloth/ecs/ClothHold.d.ts.map +1 -0
  166. package/src/engine/physics/cloth/ecs/ClothHold.js +103 -0
  167. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +254 -48
  168. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  169. package/src/engine/physics/cloth/ecs/ClothInstance.js +277 -47
  170. package/src/engine/physics/cloth/ecs/ClothPin.d.ts +73 -0
  171. package/src/engine/physics/cloth/ecs/ClothPin.d.ts.map +1 -0
  172. package/src/engine/physics/cloth/ecs/ClothPin.js +92 -0
  173. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.d.ts +36 -0
  174. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.d.ts.map +1 -0
  175. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.js +61 -0
  176. package/src/engine/physics/cloth/ecs/ClothRig.d.ts +23 -17
  177. package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -1
  178. package/src/engine/physics/cloth/ecs/ClothRig.js +29 -27
  179. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +12 -14
  180. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  181. package/src/engine/physics/cloth/ecs/ClothSystem.js +20 -15
  182. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +57 -36
  183. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  184. package/src/engine/physics/cloth/ecs/ClothWorld.js +754 -207
  185. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +12 -13
  186. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -1
  187. package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +20 -14
  188. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +63 -11
  189. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  190. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +297 -101
  191. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +9 -7
  192. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  193. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +12 -10
  194. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +3 -3
  195. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
  196. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +60 -120
  197. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts +37 -0
  198. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts.map +1 -0
  199. package/src/engine/physics/cloth/ecs/cloth_geodesic.js +135 -0
  200. package/src/engine/physics/cloth/ecs/cloth_holds.d.ts +97 -0
  201. package/src/engine/physics/cloth/ecs/cloth_holds.d.ts.map +1 -0
  202. package/src/engine/physics/cloth/ecs/cloth_holds.js +583 -0
  203. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts +2 -2
  204. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -1
  205. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +168 -51
  206. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +17 -22
  207. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  208. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +55 -117
  209. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -6
  210. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  211. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +51 -42
  212. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +5 -0
  213. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  214. package/src/engine/physics/cloth/ecs/cloth_write_back.js +62 -50
  215. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -1
  216. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +65 -58
  217. package/src/engine/physics/cloth/playground/cloth_playground_build.d.ts.map +1 -1
  218. package/src/engine/physics/cloth/playground/cloth_playground_build.js +2 -3
  219. package/src/engine/physics/cloth/playground/collide_main.js +3 -29
  220. package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -1
  221. package/src/engine/physics/cloth/playground/garment_build.js +17 -5
  222. package/src/engine/physics/cloth/playground/garment_main.js +5 -20
  223. package/src/engine/physics/cloth/playground/main.js +6 -48
  224. package/src/engine/physics/cloth/playground/rig_build.d.ts.map +1 -1
  225. package/src/engine/physics/cloth/playground/rig_build.js +302 -296
  226. package/src/engine/physics/cloth/playground/rig_main.js +947 -955
  227. package/src/engine/physics/cloth/playground/wind_main.js +8 -7
  228. package/src/engine/physics/cloth/solver/ClothState.d.ts +45 -7
  229. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  230. package/src/engine/physics/cloth/solver/ClothState.js +79 -83
  231. package/src/engine/physics/cloth/solver/cloth_color_particles.d.ts +10 -8
  232. package/src/engine/physics/cloth/solver/cloth_color_particles.d.ts.map +1 -1
  233. package/src/engine/physics/cloth/solver/cloth_color_particles.js +30 -102
  234. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +6 -1
  235. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
  236. package/src/engine/physics/cloth/solver/cloth_contact_find.js +9 -3
  237. package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts +114 -0
  238. package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts.map +1 -0
  239. package/src/engine/physics/cloth/solver/cloth_hold_line.js +350 -0
  240. package/src/engine/physics/cloth/solver/cloth_kinetic_energy.d.ts +21 -0
  241. package/src/engine/physics/cloth/solver/cloth_kinetic_energy.d.ts.map +1 -0
  242. package/src/engine/physics/cloth/solver/cloth_kinetic_energy.js +45 -0
  243. package/src/engine/physics/cloth/solver/cloth_particle_coupling.d.ts +32 -0
  244. package/src/engine/physics/cloth/solver/cloth_particle_coupling.d.ts.map +1 -0
  245. package/src/engine/physics/cloth/solver/cloth_particle_coupling.js +133 -0
  246. package/src/engine/physics/cloth/solver/cloth_particle_of_source.d.ts +16 -0
  247. package/src/engine/physics/cloth/solver/cloth_particle_of_source.d.ts.map +1 -0
  248. package/src/engine/physics/cloth/solver/cloth_particle_of_source.js +19 -0
  249. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts +6 -2
  250. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -1
  251. package/src/engine/physics/cloth/solver/cloth_self_find.js +19 -68
  252. package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts.map +1 -1
  253. package/src/engine/physics/cloth/solver/cloth_solve_vertex.js +30 -65
  254. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +24 -12
  255. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  256. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +24 -12
  257. package/src/engine/physics/cloth/solver/cloth_step.d.ts +16 -0
  258. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  259. package/src/engine/physics/cloth/solver/cloth_step.js +189 -48
  260. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts +1 -0
  261. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -1
  262. package/src/engine/physics/cloth/solver/cloth_step_instance.js +12 -6
  263. package/src/engine/physics/cloth/solver/cloth_stretch_residual.d.ts +21 -0
  264. package/src/engine/physics/cloth/solver/cloth_stretch_residual.d.ts.map +1 -0
  265. package/src/engine/physics/cloth/solver/cloth_stretch_residual.js +54 -0
  266. package/src/engine/physics/cloth/solver/cloth_vertex_accumulator.d.ts +15 -0
  267. package/src/engine/physics/cloth/solver/cloth_vertex_accumulator.d.ts.map +1 -1
  268. package/src/engine/physics/cloth/solver/cloth_vertex_accumulator.js +28 -0
  269. package/src/engine/physics/cloth/solver/cloth_worst_tether_ratio.d.ts +30 -0
  270. package/src/engine/physics/cloth/solver/cloth_worst_tether_ratio.d.ts.map +1 -0
  271. package/src/engine/physics/cloth/solver/cloth_worst_tether_ratio.js +56 -0
  272. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts.map +1 -1
  273. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.js +3 -17
  274. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.d.ts +1 -1
  275. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.d.ts.map +1 -1
  276. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.js +353 -346
  277. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts +7 -5
  278. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -1
  279. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +7 -5
  280. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts +2 -1
  281. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -1
  282. package/src/engine/physics/cloth/wind/ClothFluidWind.js +7 -25
  283. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +12 -10
  284. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
  285. package/src/engine/physics/cloth/wind/cloth_sample_air.js +60 -82
  286. package/src/engine/physics/ecs/ContactProbeSystem.d.ts.map +1 -1
  287. package/src/engine/physics/ecs/ContactProbeSystem.js +2 -18
  288. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  289. package/src/engine/physics/ecs/PhysicsSystem.js +9 -50
  290. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  291. package/src/engine/physics/fluid/ecs/fluid_sample_domain_bounds.d.ts +24 -0
  292. package/src/engine/physics/fluid/ecs/fluid_sample_domain_bounds.d.ts.map +1 -0
  293. package/src/engine/physics/fluid/ecs/fluid_sample_domain_bounds.js +42 -0
  294. package/src/engine/physics/fluid/ecs/fluid_sample_velocity_world_mps.d.ts +25 -0
  295. package/src/engine/physics/fluid/ecs/fluid_sample_velocity_world_mps.d.ts.map +1 -0
  296. package/src/engine/physics/fluid/ecs/fluid_sample_velocity_world_mps.js +40 -0
  297. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_solve.d.ts.map +1 -1
  298. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_solve.js +40 -90
  299. package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -1
  300. package/src/engine/physics/narrowphase/capsule_contacts.js +3 -5
  301. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts.map +1 -1
  302. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.js +2 -14
  303. package/src/engine/physics/narrowphase/hull_sphere_contact.d.ts.map +1 -1
  304. package/src/engine/physics/narrowphase/hull_sphere_contact.js +2 -5
  305. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  306. package/src/engine/physics/narrowphase/narrowphase_step.js +13 -32
  307. package/src/engine/physics/narrowphase/sphere_box_contact.d.ts.map +1 -1
  308. package/src/engine/physics/narrowphase/sphere_box_contact.js +2 -5
  309. package/src/engine/simulation/Ticker.d.ts +13 -0
  310. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  311. package/src/engine/simulation/Ticker.js +43 -8
  312. package/src/format/texture/basis/transcode/etc1s_to_astc.d.ts.map +1 -1
  313. package/src/format/texture/basis/transcode/etc1s_to_astc.js +2 -1
  314. package/src/shade/RENDERER_CONTRACT.md +8 -2
  315. package/src/shade/playground/image_decode_bench/main.js +2 -1
  316. package/src/shade/playground/mesh_row_ceiling/main.js +2 -1
  317. package/src/shade/playground/skinned_blas_refit/diff_traced_against_rasterized.d.ts.map +1 -1
  318. package/src/shade/playground/skinned_blas_refit/diff_traced_against_rasterized.js +2 -1
  319. package/src/shade/playground/skinned_blas_refit/main.d.ts.map +1 -1
  320. package/src/shade/playground/skinned_blas_refit/main.js +11 -19
  321. package/src/shade/playground/skinned_blas_refit/place_character.d.ts +6 -3
  322. package/src/shade/playground/skinned_blas_refit/place_character.d.ts.map +1 -1
  323. package/src/shade/playground/skinned_blas_refit/place_character.js +90 -90
  324. package/src/shade/playground/skinned_mesh_soup/main.d.ts.map +1 -1
  325. package/src/shade/playground/skinned_mesh_soup/main.js +502 -509
  326. package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts.map +1 -1
  327. package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.js +2 -1
  328. package/src/shade/playground/ssr_variance/statistics.d.ts.map +1 -1
  329. package/src/shade/playground/ssr_variance/statistics.js +2 -1
  330. package/src/shade/playground/texture_encode/README.md +129 -109
  331. package/src/shade/playground/texture_encode/main.d.ts.map +1 -1
  332. package/src/shade/playground/texture_encode/main.js +1431 -1430
  333. package/src/shade/playground/volumetrics_froxel/measure.d.ts.map +1 -1
  334. package/src/shade/playground/volumetrics_froxel/measure.js +2 -1
  335. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +45 -14
  336. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  337. package/src/shade/renderer/animation/GPUAnimationManager.js +316 -64
  338. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts +5 -0
  339. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  340. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +11 -1
  341. package/src/shade/renderer/buffer/table/gpu_database_check_links.d.ts.map +1 -1
  342. package/src/shade/renderer/buffer/table/gpu_database_check_links.js +2 -1
  343. package/src/shade/renderer/geometry/BoxGeometry.d.ts +1 -11
  344. package/src/shade/renderer/geometry/BoxGeometry.d.ts.map +1 -1
  345. package/src/shade/renderer/geometry/BoxGeometry.js +6 -13
  346. package/src/shade/renderer/geometry/CapsuleGeometry.d.ts +19 -0
  347. package/src/shade/renderer/geometry/CapsuleGeometry.d.ts.map +1 -0
  348. package/src/shade/renderer/geometry/CapsuleGeometry.js +24 -0
  349. package/src/shade/renderer/geometry/ConeGeometry.d.ts +20 -0
  350. package/src/shade/renderer/geometry/ConeGeometry.d.ts.map +1 -0
  351. package/src/shade/renderer/geometry/ConeGeometry.js +33 -0
  352. package/src/shade/renderer/geometry/CylinderGeometry.d.ts +21 -0
  353. package/src/shade/renderer/geometry/CylinderGeometry.d.ts.map +1 -0
  354. package/src/shade/renderer/geometry/CylinderGeometry.js +35 -0
  355. package/src/shade/renderer/geometry/PlaneGeometry.d.ts +17 -0
  356. package/src/shade/renderer/geometry/PlaneGeometry.d.ts.map +1 -0
  357. package/src/shade/renderer/geometry/PlaneGeometry.js +22 -0
  358. package/src/shade/renderer/geometry/TorusGeometry.d.ts +18 -0
  359. package/src/shade/renderer/geometry/TorusGeometry.d.ts.map +1 -0
  360. package/src/shade/renderer/geometry/TorusGeometry.js +23 -0
  361. package/src/shade/renderer/geometry/UVSphereGeometry.d.ts +21 -0
  362. package/src/shade/renderer/geometry/UVSphereGeometry.d.ts.map +1 -0
  363. package/src/shade/renderer/geometry/UVSphereGeometry.js +34 -0
  364. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts +19 -0
  365. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts.map +1 -0
  366. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.js +205 -0
  367. package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts +21 -0
  368. package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts.map +1 -0
  369. package/src/shade/renderer/geometry/primitives/make_cone_geometry.js +36 -0
  370. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts +1 -1
  371. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts.map +1 -1
  372. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.js +44 -9
  373. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts +20 -0
  374. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts.map +1 -0
  375. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.js +190 -0
  376. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.d.ts.map +1 -1
  377. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +3 -2
  378. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.d.ts.map +1 -1
  379. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.js +2 -1
  380. package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.d.ts.map +1 -1
  381. package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.js +2 -1
  382. package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.d.ts.map +1 -1
  383. package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.js +2 -1
  384. package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.d.ts.map +1 -1
  385. package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.js +3 -2
  386. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_graph_components.d.ts.map +1 -1
  387. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_graph_components.js +2 -1
  388. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.d.ts.map +1 -1
  389. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.js +2 -1
  390. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  391. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +3 -2
  392. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  393. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +7 -2
  394. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts +26 -8
  395. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts.map +1 -1
  396. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js +56 -39
  397. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts +7 -0
  398. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts.map +1 -1
  399. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.js +46 -4
  400. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.d.ts.map +1 -1
  401. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.js +4 -2
  402. package/src/shade/renderer/gpu_primitive/sort/defs.d.ts +2 -2
  403. package/src/shade/renderer/gpu_primitive/sort/defs.js +79 -79
  404. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts +1 -1
  405. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts.map +1 -1
  406. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.js +7 -3
  407. package/src/shade/renderer/particles/GPUParticleSystem.js +1 -1
  408. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts +4 -3
  409. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts.map +1 -1
  410. package/src/shade/renderer/particles/coherence/graph_particle_bucket.js +200 -194
  411. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  412. package/src/shade/renderer/particles/graph_particles.js +6 -2
  413. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts.map +1 -1
  414. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.js +3 -2
  415. package/src/shade/renderer/particles/warmup/graph_particle_warmup.d.ts.map +1 -1
  416. package/src/shade/renderer/particles/warmup/graph_particle_warmup.js +334 -329
  417. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  418. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +7 -2
  419. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.d.ts.map +1 -1
  420. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.js +16 -4
  421. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +2444 -2345
  422. package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.d.ts.map +1 -1
  423. package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.js +312 -310
  424. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts +3 -3
  425. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts.map +1 -1
  426. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.js +383 -375
  427. package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.d.ts.map +1 -1
  428. package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.js +349 -346
  429. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts +58 -0
  430. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts.map +1 -0
  431. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.js +536 -0
  432. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts +21 -7
  433. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts.map +1 -1
  434. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.js +291 -327
  435. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts +25 -0
  436. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts.map +1 -0
  437. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.js +99 -0
  438. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts +5 -3
  439. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts.map +1 -1
  440. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.js +47 -71
  441. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts +10 -0
  442. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts.map +1 -0
  443. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.js +50 -0
  444. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts +4 -5
  445. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts.map +1 -1
  446. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.js +7 -8
  447. package/src/shade/renderer/water/chunk_water_transport.d.ts.map +1 -1
  448. package/src/shade/renderer/water/chunk_water_transport.js +7 -5
  449. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +1 -1
  450. package/src/shade/renderer/water/medium/GPUWaterBodies.js +8 -2
  451. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts +3 -2
  452. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts.map +1 -1
  453. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.js +3 -2
  454. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  455. package/src/shade/renderer/water/shader_water.js +3 -1
  456. package/src/shade/renderer/water/surface/GPUWaterSurface.d.ts.map +1 -1
  457. package/src/shade/renderer/water/surface/GPUWaterSurface.js +3 -1
  458. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts.map +1 -1
  459. package/src/shade/renderer/water/surface/graph_water_tessellation.js +11 -4
  460. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -1
  461. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +37 -20
  462. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  463. package/src/shade/wgsl/validate_wgsl_source.js +74 -3
  464. package/src/engine/graphics3/register_instance_animation.d.ts +0 -114
  465. package/src/engine/graphics3/register_instance_animation.d.ts.map +0 -1
  466. package/src/engine/graphics3/register_instance_animation.js +0 -201
@@ -1,6 +1,7 @@
1
1
  import { EntityComponentDataset } from "../../../ecs/EntityComponentDataset.js";
2
2
  import { FluidComponent } from "../../fluid/ecs/FluidComponent.js";
3
3
  import { fluid_build_world_to_grid } from "../../fluid/ecs/fluid_build_world_to_grid.js";
4
+ import { fluid_sample_velocity_world_mps } from "../../fluid/ecs/fluid_sample_velocity_world_mps.js";
4
5
  import { CLOTH_DYNAMICS_BY_NAME } from "../ecs/cloth_dynamics_library.js";
5
6
  import { cloth_bend_ratio, cloth_drag_response } from "../ecs/cloth_dynamics_map.js";
6
7
  import { cloth_step } from "../solver/cloth_step.js";
@@ -389,14 +390,14 @@ function draw_field() {
389
390
  continue;
390
391
  }
391
392
 
392
- component.sampleVelocityAtWorld(sample, x, y, z);
393
+ // In metres a second, as `ClothFluidWind` reads it.
394
+ fluid_sample_velocity_world_mps(sample, 0, component, x, y, z);
393
395
 
394
- // Cells a second to metres a second, the same conversion
395
- // `ClothFluidWind` makes and for the same reason.
396
- const vx = sample[0] * cell_size;
397
- const vz = sample[2] * cell_size;
396
+ const vx = sample[0];
397
+ const vy = sample[1];
398
+ const vz = sample[2];
398
399
 
399
- const speed = Math.hypot(vx, sample[1] * cell_size, vz);
400
+ const speed = Math.hypot(vx, vy, vz);
400
401
 
401
402
  if (speed < 1e-3) {
402
403
  continue;
@@ -406,7 +407,7 @@ function draw_field() {
406
407
 
407
408
  const depth = project(from, camera, x, y, z, width, height);
408
409
 
409
- project(to, camera, x + vx * scale, y + sample[1] * cell_size * scale, z + vz * scale, width, height);
410
+ project(to, camera, x + vx * scale, y + vy * scale, z + vz * scale, width, height);
410
411
 
411
412
  if (depth <= 0) {
412
413
  continue;
@@ -39,6 +39,8 @@ export class ClothState {
39
39
  * @param {Int32Array|number[]} [description.leash_particle] the particle each leash row holds
40
40
  * @param {Float32Array|number[]} [description.leash_radius] leash radius per row; its length is
41
41
  * the row count, and the leash centres are written per step rather than here
42
+ * @param {Int32Array|number[]} [description.leash_source] source particle per leash row, `−1`
43
+ * for a row whose centre the caller writes outright; default all `−1`
42
44
  * @param {Int32Array|number[]} [description.backstop_particle] the particle each backstop row holds
43
45
  * @param {Float32Array|number[]} [description.backstop_radius] backstop radius per row; the planes
44
46
  * themselves are written per step rather than here
@@ -49,7 +51,7 @@ export class ClothState {
49
51
  * back private memory would make both threads mutate copies of it.
50
52
  * @returns {ClothState}
51
53
  */
52
- static from({ position, mass_inverse, stretch_particle, stretch_rest, stretch_stiffness, stretch_force_min, stretch_force_max, bend_particle, bend_weight, bend_stiffness, leash_particle, leash_radius, backstop_particle, backstop_radius, shared }: {
54
+ static from({ position, mass_inverse, stretch_particle, stretch_rest, stretch_stiffness, stretch_force_min, stretch_force_max, bend_particle, bend_weight, bend_stiffness, leash_particle, leash_radius, leash_source, backstop_particle, backstop_radius, shared }: {
53
55
  position: Float32Array | number[];
54
56
  mass_inverse: Float32Array | number[];
55
57
  stretch_particle?: Int32Array | number[];
@@ -62,6 +64,7 @@ export class ClothState {
62
64
  bend_stiffness?: Float32Array | number[];
63
65
  leash_particle?: Int32Array | number[];
64
66
  leash_radius?: Float32Array | number[];
67
+ leash_source?: Int32Array | number[];
65
68
  backstop_particle?: Int32Array | number[];
66
69
  backstop_radius?: Float32Array | number[];
67
70
  shared?: boolean;
@@ -278,15 +281,36 @@ export class ClothState {
278
281
  * The point each leash row is measured from, 3 per row, in the cloth's own
279
282
  * local frame.
280
283
  *
281
- * **Written per step by the caller, not baked.** A slack row's centre is
282
- * the particle's animated position and a tether row's is the anchor's, and
283
- * neither is a property of the rest shape. Storing a point per row rather
284
- * than an index into a shared table costs three floats a row and removes an
285
- * indirection from the inner loop, which is the trade this structure makes
286
- * everywhere else too.
284
+ * **Written per step by the caller, not baked** — or, for a row with a
285
+ * {@link leash_source}, per substep by the step itself. A slack row's centre
286
+ * is the particle's animated position and a tether row's is the held
287
+ * particle it hangs from, and neither is a property of the rest shape.
288
+ * Storing a point per row rather than an index into a shared table costs
289
+ * three floats a row and removes an indirection from the inner loop, which
290
+ * is the trade this structure makes everywhere else too.
287
291
  * @type {Float32Array}
288
292
  */
289
293
  leash_target: Float32Array;
294
+ /**
295
+ * The particle each leash row is measured from, or `−1` for a row whose
296
+ * centre the caller writes outright.
297
+ *
298
+ * **A held particle moves inside a step** — it is carried an equal share of
299
+ * the way to where its holder will have it at each substep — so a centre
300
+ * written once per step is a step behind the particle it is supposed to sit
301
+ * on, and a hard row measured from a stale point fights the hold it hangs
302
+ * from. A row with a source is re-centred at every substep, after the held
303
+ * particles have moved, at `position[source] + leash_offset`.
304
+ * @type {Int32Array}
305
+ */
306
+ leash_source: Int32Array;
307
+ /**
308
+ * Where a sourced leash row's centre sits relative to its source particle,
309
+ * 3 per row, cloth-local. Zero for a tether; the animated pose's offset from
310
+ * the held particle for a slack row. Written by the caller per step.
311
+ * @type {Float32Array}
312
+ */
313
+ leash_offset: Float32Array;
290
314
  /**
291
315
  * Leash radius, one per row: `slack·d_geo,i` for a slack row, `d_geo,i` for
292
316
  * a tether. Zero is a weld (§3.4 — the pin is a leash of no radius, not a
@@ -541,6 +565,20 @@ export class ClothState {
541
565
  * @type {Float32Array}
542
566
  */
543
567
  air_velocity: Float32Array;
568
+ /**
569
+ * Where each **held** particle — inverse mass zero — is to be at the end of
570
+ * the step, 3 per particle, cloth-local.
571
+ *
572
+ * Written by the caller; read by the predict, which carries a held particle
573
+ * an equal share of the remaining way at every substep so that it arrives
574
+ * here exactly at the last one. That is how a holder that moves relative to
575
+ * the cloth's frame moves its particles *through* the step rather than at
576
+ * its start, which is the same thing §8.2 does for colliders — and Chaos
577
+ * Cloth does for its kinematic particles. Seeded at the rest position, so a
578
+ * held particle nobody writes a target for stays where it is, bit for bit.
579
+ * @type {Float32Array}
580
+ */
581
+ kinematic_target: Float32Array;
544
582
  /**
545
583
  * Gravity plus §10's aerodynamic drag, 3 per particle, cloth-local, m/s².
546
584
  *
@@ -1 +1 @@
1
- {"version":3,"file":"ClothState.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/ClothState.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ClothState.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/ClothState.js"],"names":[],"mappings":";;;8BAoHU,MAAM;;;;;;AAkBhB;;;GAGG;AACH,sCAFU,MAAM,CAEyB;AAEzC;IAyjBI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqCG;IACH;QAzB8C,QAAQ,EAA3C,YAAY,GAAC,MAAM,EAAE;QACc,YAAY,EAA/C,YAAY,GAAC,MAAM,EAAE;QACa,gBAAgB,GAAlD,UAAU,GAAC,MAAM,EAAE;QACiB,YAAY,GAAhD,YAAY,GAAC,MAAM,EAAE;QACe,iBAAiB,GAArD,YAAY,GAAC,MAAM,EAAE;QACe,iBAAiB,GAArD,YAAY,GAAC,MAAM,EAAE;QACe,iBAAiB,GAArD,YAAY,GAAC,MAAM,EAAE;QACa,aAAa,GAA/C,UAAU,GAAC,MAAM,EAAE;QACiB,WAAW,GAA/C,YAAY,GAAC,MAAM,EAAE;QACe,cAAc,GAAlD,YAAY,GAAC,MAAM,EAAE;QACa,cAAc,GAAhD,UAAU,GAAC,MAAM,EAAE;QACiB,YAAY,GAAhD,YAAY,GAAC,MAAM,EAAE;QAEa,YAAY,GAA9C,UAAU,GAAC,MAAM,EAAE;QAEe,iBAAiB,GAAnD,UAAU,GAAC,MAAM,EAAE;QACiB,eAAe,GAAnD,YAAY,GAAC,MAAM,EAAE;QAEC,MAAM,GAA5B,OAAO;QAKL,UAAU,CAiLtB;IAkCD;;;;;;;;;;;;OAYG;IACH,wCAJW;QAAC,MAAM,EAAE,iBAAiB,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QACpF,UAAc,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAC,GAC9E,UAAU,CAiBtB;IA10BD;;;;;;OAMG;IACH,QAFU,WAAW,GAAC,iBAAiB,CAEzB;IAEd;;;OAGG;IACH,QAFU,YAAY,CAER;IAEd;;OAEG;IACH,gBAFU,MAAM,CAEG;IAEnB;;OAEG;IACH,eAFU,MAAM,CAEE;IAElB;;OAEG;IACH,YAFU,MAAM,CAED;IAEf;;OAEG;IACH,aAFU,MAAM,CAEA;IAEhB;;OAEG;IACH,cAFU,MAAM,CAEC;IAEjB;;;;OAIG;IACH,UAFU,YAAY,CAEN;IAEhB;;;;;OAKG;IACH,mBAFU,YAAY,CAEG;IAEzB;;OAEG;IACH,UAFU,YAAY,CAEN;IAEhB;;;;;OAKG;IACH,UAFU,YAAY,CAEN;IAEhB;;;;;OAKG;IACH,cAFU,YAAY,CAEF;IAEpB;;;;;;;;OAQG;IACH,eAFU,YAAY,CAED;IAErB;;;;OAIG;IACH,eAFU,UAAU,CAEC;IAErB;;;;OAIG;IACH,oBAFU,UAAU,CAEM;IAE1B;;;OAGG;IACH,kBAFU,UAAU,CAEI;IAExB;;;OAGG;IACH,cAFU,YAAY,CAEF;IAEpB;;;;OAIG;IACH,mBAFU,YAAY,CAEG;IAEzB;;;;OAIG;IACH,mBAFU,YAAY,CAEG;IAEzB;;;;;OAKG;IACH,mBAFU,YAAY,CAEG;IAEzB;;;;OAIG;IACH,gBAFU,YAAY,CAEA;IAEtB;;;;OAIG;IACH,iBAFU,YAAY,CAEC;IAEvB;;;OAGG;IACH,0BAFU,UAAU,CAEY;IAEhC;;;;OAIG;IACH,mBAFU,UAAU,CAEK;IAEzB;;;;OAIG;IACH,eAFU,UAAU,CAEC;IAErB;;;;;OAKG;IACH,aAFU,YAAY,CAEH;IAEnB;;;OAGG;IACH,gBAFU,YAAY,CAEA;IAEtB;;;;;;OAMG;IACH,aAFU,YAAY,CAEH;IAEnB;;;;OAIG;IACH,cAFU,YAAY,CAEF;IAEpB;;;OAGG;IACH,uBAFU,UAAU,CAES;IAE7B;;;;OAIG;IACH,gBAFU,UAAU,CAEE;IAEtB;;;OAGG;IACH,gBAFU,UAAU,CAEE;IAEtB;;;;;;;;;;;;OAYG;IACH,cAFU,YAAY,CAEF;IAEpB;;;;;;;;;;;OAWG;IACH,cAFU,UAAU,CAEA;IAEpB;;;;;OAKG;IACH,cAFU,YAAY,CAEF;IAEpB;;;;;OAKG;IACH,cAFU,YAAY,CAEF;IAEpB;;;;;;OAMG;IACH,cAFU,YAAY,CAEF;IAEpB;;;OAGG;IACH,eAFU,YAAY,CAED;IAErB;;;OAGG;IACH,wBAFU,UAAU,CAEU;IAE9B;;;OAGG;IACH,iBAFU,UAAU,CAEG;IAEvB;;OAEG;IACH,gBAFU,MAAM,CAEG;IAEnB;;;OAGG;IACH,mBAFU,UAAU,CAEK;IAEzB;;;;;;;;;;;;;OAaG;IACH,gBAFU,YAAY,CAEA;IAEtB;;;OAGG;IACH,iBAFU,YAAY,CAEC;IAEvB;;;OAGG;IACH,iBAFU,YAAY,CAEC;IAEvB;;;OAGG;IACH,kBAFU,YAAY,CAEE;IAExB;;;OAGG;IACH,2BAFU,UAAU,CAEa;IAEjC;;;OAGG;IACH,oBAFU,UAAU,CAEM;IAE1B;;;;;;;;;;;;;;;OAeG;IACH,gBAFU,MAAM,CAEG;IAEnB;;;;;;;;;;;;OAYG;IACH,gBAFU,YAAY,CAEA;IAEtB;;;;;OAKG;IACH,cAFU,UAAU,CAEA;IAEpB;;;;OAIG;IACH,gBAFU,MAAM,CAEG;IAEnB;;;;;OAKG;IACH,kBAFU,UAAU,CAEI;IAExB;;;;;;;OAOG;IACH,aAFU,UAAU,CAED;IAEnB;;;OAGG;IACH,gBAFU,YAAY,CAEA;IAEtB;;;OAGG;IACH,iBAFU,YAAY,CAEC;IAEvB;;;;;OAKG;IACH,yBAFU,YAAY,CAES;IAE/B;;;OAGG;IACH,0BAFU,YAAY,CAEU;IAEhC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,aAFU,MAAM,CAEA;IAEhB;;;;;;;;;;;;;;OAcG;IACH,WAFU,UAAU,CAEH;IAEjB;;;OAGG;IACH,YAFU,MAAM,CAED;IAEf;;;;;;;;;;OAUG;IACH,YAFU,YAAY,CAEJ;IAElB;;;;OAIG;IACH,cAFU,YAAY,CAEF;IAEpB;;;;;;;;;;OAUG;IACH,gBAFU,YAAY,CAEA;IAEtB;;;;;;;;;;;;;;;;;OAiBG;IACH,cAFU,YAAY,CAEF;IAEpB;;;;;;;;;;;;OAYG;IACH,kBAFU,YAAY,CAEE;IAExB;;;;;;;;;;OAUG;IACH,uBAFU,YAAY,CAEO;IAyN7B;;OAEG;IACH,kBAFa,OAAO,CAInB;IAED;;;;;;;;;;OAUG;IACH,uBAHa;QAAC,MAAM,EAAE,iBAAiB,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QACtF,UAAc,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAC,CAc1F;CA+BJ"}
@@ -1,6 +1,8 @@
1
1
  import { assert } from "../../../../core/assert.js";
2
+ import { csr_build_incidence } from "../../../../core/graph/csr/csr_build_incidence.js";
2
3
  import { CCR_STRIDE } from "../collider/ClothColliderRecord.js";
3
4
  import { cloth_color_order, cloth_color_particles } from "./cloth_color_particles.js";
5
+ import { cloth_particle_of_source } from "./cloth_particle_of_source.js";
4
6
  import { CLOTH_COLLIDER_SLOTS } from "./cloth_solver_constants.js";
5
7
  import { CLOTH_SELF_PAIRS_PER_PARTICLE } from "./cloth_self_find.js";
6
8
  import { CLOTH_CONTACT_SLOTS } from "./constraint/cloth_contact_row.js";
@@ -360,16 +362,39 @@ export class ClothState {
360
362
  * The point each leash row is measured from, 3 per row, in the cloth's own
361
363
  * local frame.
362
364
  *
363
- * **Written per step by the caller, not baked.** A slack row's centre is
364
- * the particle's animated position and a tether row's is the anchor's, and
365
- * neither is a property of the rest shape. Storing a point per row rather
366
- * than an index into a shared table costs three floats a row and removes an
367
- * indirection from the inner loop, which is the trade this structure makes
368
- * everywhere else too.
365
+ * **Written per step by the caller, not baked** — or, for a row with a
366
+ * {@link leash_source}, per substep by the step itself. A slack row's centre
367
+ * is the particle's animated position and a tether row's is the held
368
+ * particle it hangs from, and neither is a property of the rest shape.
369
+ * Storing a point per row rather than an index into a shared table costs
370
+ * three floats a row and removes an indirection from the inner loop, which
371
+ * is the trade this structure makes everywhere else too.
369
372
  * @type {Float32Array}
370
373
  */
371
374
  leash_target = null;
372
375
 
376
+ /**
377
+ * The particle each leash row is measured from, or `−1` for a row whose
378
+ * centre the caller writes outright.
379
+ *
380
+ * **A held particle moves inside a step** — it is carried an equal share of
381
+ * the way to where its holder will have it at each substep — so a centre
382
+ * written once per step is a step behind the particle it is supposed to sit
383
+ * on, and a hard row measured from a stale point fights the hold it hangs
384
+ * from. A row with a source is re-centred at every substep, after the held
385
+ * particles have moved, at `position[source] + leash_offset`.
386
+ * @type {Int32Array}
387
+ */
388
+ leash_source = null;
389
+
390
+ /**
391
+ * Where a sourced leash row's centre sits relative to its source particle,
392
+ * 3 per row, cloth-local. Zero for a tether; the animated pose's offset from
393
+ * the held particle for a slack row. Written by the caller per step.
394
+ * @type {Float32Array}
395
+ */
396
+ leash_offset = null;
397
+
373
398
  /**
374
399
  * Leash radius, one per row: `slack·d_geo,i` for a slack row, `d_geo,i` for
375
400
  * a tether. Zero is a weld (§3.4 — the pin is a leash of no radius, not a
@@ -654,6 +679,21 @@ export class ClothState {
654
679
  */
655
680
  air_velocity = null;
656
681
 
682
+ /**
683
+ * Where each **held** particle — inverse mass zero — is to be at the end of
684
+ * the step, 3 per particle, cloth-local.
685
+ *
686
+ * Written by the caller; read by the predict, which carries a held particle
687
+ * an equal share of the remaining way at every substep so that it arrives
688
+ * here exactly at the last one. That is how a holder that moves relative to
689
+ * the cloth's frame moves its particles *through* the step rather than at
690
+ * its start, which is the same thing §8.2 does for colliders — and Chaos
691
+ * Cloth does for its kinematic particles. Seeded at the rest position, so a
692
+ * held particle nobody writes a target for stays where it is, bit for bit.
693
+ * @type {Float32Array}
694
+ */
695
+ kinematic_target = null;
696
+
657
697
  /**
658
698
  * Gravity plus §10's aerodynamic drag, 3 per particle, cloth-local, m/s².
659
699
  *
@@ -693,6 +733,8 @@ export class ClothState {
693
733
  * @param {Int32Array|number[]} [description.leash_particle] the particle each leash row holds
694
734
  * @param {Float32Array|number[]} [description.leash_radius] leash radius per row; its length is
695
735
  * the row count, and the leash centres are written per step rather than here
736
+ * @param {Int32Array|number[]} [description.leash_source] source particle per leash row, `−1`
737
+ * for a row whose centre the caller writes outright; default all `−1`
696
738
  * @param {Int32Array|number[]} [description.backstop_particle] the particle each backstop row holds
697
739
  * @param {Float32Array|number[]} [description.backstop_radius] backstop radius per row; the planes
698
740
  * themselves are written per step rather than here
@@ -716,6 +758,7 @@ export class ClothState {
716
758
  bend_stiffness = EMPTY_FLOAT32,
717
759
  leash_particle = EMPTY_INT32,
718
760
  leash_radius = EMPTY_FLOAT32,
761
+ leash_source = undefined,
719
762
  backstop_particle = EMPTY_INT32,
720
763
  backstop_radius = EMPTY_FLOAT32,
721
764
  shared = false
@@ -732,6 +775,7 @@ export class ClothState {
732
775
  assert.equal(bend_particle.length, bend_count * 4, 'bend_particle.length');
733
776
  assert.equal(bend_weight.length, bend_count * 4, 'bend_weight.length');
734
777
  assert.equal(leash_particle.length, leash_count, 'leash_particle.length');
778
+ assert.ok(leash_source === undefined || leash_source.length === leash_count, 'leash_source.length');
735
779
  assert.equal(backstop_particle.length, backstop_count, 'backstop_particle.length');
736
780
 
737
781
  const colors = cloth_color_particles(
@@ -745,9 +789,7 @@ export class ClothState {
745
789
  // `order` maps permuted → source; the rows need source → permuted.
746
790
  const particle_of_source = new Int32Array(particle_count);
747
791
 
748
- for (let i = 0; i < particle_count; i++) {
749
- particle_of_source[order[i]] = i;
750
- }
792
+ cloth_particle_of_source(particle_of_source, order, particle_count);
751
793
 
752
794
  const state = new ClothState();
753
795
 
@@ -774,6 +816,7 @@ export class ClothState {
774
816
  // and the first step's `v = (x − x_prev)/h` reads zero.
775
817
  state.position_previous.set(state.position);
776
818
  state.inertial.set(state.position);
819
+ state.kinematic_target.set(state.position);
777
820
 
778
821
  for (let row = 0; row < stretch_count; row++) {
779
822
  state.stretch_particle[row * 2] = particle_of_source[stretch_particle[row * 2]];
@@ -809,9 +852,15 @@ export class ClothState {
809
852
  state.bend_penalty[row] = stiffness < Infinity ? stiffness : 0;
810
853
  }
811
854
 
812
- build_adjacency(
855
+ // Grouping the flat particle table gives the flat index `row·2 + slot`,
856
+ // which is the packed `(row << 1) | slot` the stretch accumulation
857
+ // decodes, already in ascending row order within each particle — so the
858
+ // row tables are walked forwards during a sweep even though the
859
+ // particles are in colour order. The bend table below is the same with
860
+ // `(row << 2) | slot`.
861
+ csr_build_incidence(
813
862
  state.stretch_adjacency_offset, state.stretch_adjacency,
814
- state.stretch_particle, stretch_count, 2, particle_count
863
+ state.stretch_particle, stretch_count * 2, particle_count
815
864
  );
816
865
 
817
866
  for (let row = 0; row < leash_count; row++) {
@@ -828,14 +877,19 @@ export class ClothState {
828
877
  state.leash_target[row * 3] = state.position[particle * 3];
829
878
  state.leash_target[row * 3 + 1] = state.position[particle * 3 + 1];
830
879
  state.leash_target[row * 3 + 2] = state.position[particle * 3 + 2];
880
+
881
+ state.leash_source[row] = leash_source === undefined || leash_source[row] < 0
882
+ ? -1
883
+ : particle_of_source[leash_source[row]];
831
884
  }
832
885
 
833
- build_adjacency(
886
+ csr_build_incidence(
834
887
  state.bend_adjacency_offset, state.bend_adjacency,
835
- state.bend_particle, bend_count, 4, particle_count
888
+ state.bend_particle, bend_count * 4, particle_count
836
889
  );
837
890
 
838
- build_unary_adjacency(
891
+ // A unary row kind's flat index is its row index: nothing to unpack.
892
+ csr_build_incidence(
839
893
  state.leash_adjacency_offset, state.leash_adjacency,
840
894
  state.leash_particle, leash_count, particle_count
841
895
  );
@@ -857,7 +911,7 @@ export class ClothState {
857
911
  state.backstop_plane[row * 6 + 4] = 1;
858
912
  }
859
913
 
860
- build_unary_adjacency(
914
+ csr_build_incidence(
861
915
  state.backstop_adjacency_offset, state.backstop_adjacency,
862
916
  state.backstop_particle, backstop_count, particle_count
863
917
  );
@@ -1028,6 +1082,8 @@ function allocate(
1028
1082
  bend_count * 4, // bend_adjacency
1029
1083
  leash_count, // leash_particle
1030
1084
  leash_count * 3, // leash_target
1085
+ leash_count, // leash_source
1086
+ leash_count * 3, // leash_offset
1031
1087
  leash_count, // leash_radius
1032
1088
  leash_count, // leash_lambda
1033
1089
  leash_count, // leash_penalty
@@ -1053,7 +1109,8 @@ function allocate(
1053
1109
  particle_count * 3, // self_force
1054
1110
  particle_count * 6, // self_hessian
1055
1111
  particle_count * 3, // air_velocity
1056
- particle_count * 3 // external_acceleration
1112
+ particle_count * 3, // external_acceleration
1113
+ particle_count * 3 // kinematic_target
1057
1114
  ];
1058
1115
 
1059
1116
  let total = 0;
@@ -1119,6 +1176,8 @@ function allocate(
1119
1176
 
1120
1177
  state.leash_particle = cut(Int32Array, leash_count);
1121
1178
  state.leash_target = cut(Float32Array, leash_count * 3);
1179
+ state.leash_source = cut(Int32Array, leash_count);
1180
+ state.leash_offset = cut(Float32Array, leash_count * 3);
1122
1181
  state.leash_radius = cut(Float32Array, leash_count);
1123
1182
  state.leash_lambda = cut(Float32Array, leash_count);
1124
1183
  state.leash_penalty = cut(Float32Array, leash_count);
@@ -1157,72 +1216,9 @@ function allocate(
1157
1216
  state.air_velocity = cut(Float32Array, particle_count * 3);
1158
1217
  state.external_acceleration = cut(Float32Array, particle_count * 3);
1159
1218
 
1160
- assert.equal(cursor, total, 'buffer cursor at end of allocation');
1161
- }
1162
-
1163
- /**
1164
- * The {@link build_adjacency} of a **unary** row kind: one particle per row, so
1165
- * an entry is a bare row index rather than a packed `(row, slot)` pair and
1166
- * there is nothing to shift.
1167
- *
1168
- * @param {Int32Array} offset out, `particle_count + 1`
1169
- * @param {Int32Array} adjacency out, `row_count`
1170
- * @param {Int32Array} row_particle particle index per row
1171
- * @param {number} row_count
1172
- * @param {number} particle_count
1173
- * @private
1174
- */
1175
- function build_unary_adjacency(offset, adjacency, row_particle, row_count, particle_count) {
1176
- for (let row = 0; row < row_count; row++) {
1177
- offset[row_particle[row] + 1]++;
1178
- }
1179
-
1180
- for (let i = 0; i < particle_count; i++) {
1181
- offset[i + 1] += offset[i];
1182
- }
1183
-
1184
- const cursor = offset.slice(0, particle_count);
1185
-
1186
- for (let row = 0; row < row_count; row++) {
1187
- adjacency[cursor[row_particle[row]]++] = row;
1188
- }
1189
- }
1190
-
1191
- /**
1192
- * Counting sort of `(particle, row, slot)` incidences into CSR, with the slot
1193
- * folded into the low bits of each entry so the accumulation loop reads one
1194
- * word per row it touches.
1195
- *
1196
- * Entries within a particle come out in ascending row order, which keeps the
1197
- * row tables walked forwards during a sweep even though the particles are in
1198
- * colour order.
1199
- *
1200
- * @param {Int32Array} offset out, `particle_count + 1`
1201
- * @param {Int32Array} adjacency out, `row_count * arity`
1202
- * @param {Int32Array} row_particle particle indices, `arity` per row
1203
- * @param {number} row_count
1204
- * @param {number} arity 2 for stretch, 4 for bend
1205
- * @param {number} particle_count
1206
- * @private
1207
- */
1208
- function build_adjacency(offset, adjacency, row_particle, row_count, arity, particle_count) {
1209
- const shift = arity === 2 ? 1 : 2;
1210
-
1211
- for (let i = 0; i < row_count * arity; i++) {
1212
- offset[row_particle[i] + 1]++;
1213
- }
1214
-
1215
- for (let i = 0; i < particle_count; i++) {
1216
- offset[i + 1] += offset[i];
1217
- }
1218
-
1219
- const cursor = offset.slice(0, particle_count);
1220
-
1221
- for (let row = 0; row < row_count; row++) {
1222
- for (let slot = 0; slot < arity; slot++) {
1223
- const particle = row_particle[row * arity + slot];
1219
+ // Held particles only, and a cloth whose holders ride its frame never
1220
+ // changes it: the cold end.
1221
+ state.kinematic_target = cut(Float32Array, particle_count * 3);
1224
1222
 
1225
- adjacency[cursor[particle]++] = (row << shift) | slot;
1226
- }
1227
- }
1223
+ assert.equal(cursor, total, 'buffer cursor at end of allocation');
1228
1224
  }
@@ -19,17 +19,19 @@
19
19
  * against 76 for its 14,802 tetrahedra — the same asymmetry, and the reason
20
20
  * this design colours vertices rather than constraints.
21
21
  *
22
- * This runs **once**, at build time, on a `Graph` object. The runtime never
23
- * sees a graph: {@link ClothState} bakes the result into a permuted particle
24
- * order plus a range per colour, so the sweep is a pair of nested counted
25
- * loops over contiguous indices.
22
+ * This runs **once**, at build time, on the sorted CSR adjacency
23
+ * {@link cloth_particle_coupling} builds — the same edge set the
24
+ * self-collision exclusions are. The runtime never sees a graph:
25
+ * {@link ClothState} bakes the result into a permuted particle order plus a
26
+ * range per colour, so the sweep is a pair of nested counted loops over
27
+ * contiguous indices.
26
28
  *
27
29
  * The greedy colouriser is fed a largest-degree-first order (Welsh–Powell),
28
30
  * which is the cheap heuristic that gets a regular triangulated sheet down to
29
- * the 8–10 colours §5.4 predicts. The result is checked with the engine's own
30
- * {@link validateGraphColoring} behind `assert.*`, so a colouring that would
31
- * let two coupled particles race is caught in a dev build and compiles out of
32
- * a shipped one.
31
+ * the 8–10 colours §5.4 predicts. The result is checked with
32
+ * {@link csr_graph_validate_coloring} behind `assert.*`, so a colouring that
33
+ * would let two coupled particles race is caught in a dev build and compiles
34
+ * out of a shipped one.
33
35
  *
34
36
  * @author Alex Goldring
35
37
  * @copyright Company Named Limited (c) 2026
@@ -1 +1 @@
1
- {"version":3,"file":"cloth_color_particles.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_color_particles.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH;;;;;;;;;GASG;AACH,sDAPW,MAAM,oBACN,UAAU,GAAC,MAAM,EAAE,iBACnB,MAAM,iBACN,UAAU,GAAC,MAAM,EAAE,cACnB,MAAM,GACJ,WAAW,CAyFvB;AAmCD;;;;;;;;;;;;;GAaG;AACH,0CANW,WAAW,kBACX,MAAM,GACJ;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAC,CAmChF"}
1
+ {"version":3,"file":"cloth_color_particles.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_color_particles.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH;;;;;;;;;GASG;AACH,sDAPW,MAAM,oBACN,UAAU,GAAC,MAAM,EAAE,iBACnB,MAAM,iBACN,UAAU,GAAC,MAAM,EAAE,cACnB,MAAM,GACJ,WAAW,CA+BvB;AA8BD;;;;;;;;;;;;;GAaG;AACH,0CANW,WAAW,kBACX,MAAM,GACJ;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAC,CAuBhF"}
@@ -1,7 +1,8 @@
1
1
  import { assert } from "../../../../core/assert.js";
2
- import { colorizeGraphGreedy } from "../../../../core/graph/coloring/colorizeGraphGreedy.js";
3
- import { validateGraphColoring } from "../../../../core/graph/coloring/validateGraphColoring.js";
4
- import { Graph } from "../../../../core/graph/v2/Graph.js";
2
+ import { csr_build_incidence } from "../../../../core/graph/csr/csr_build_incidence.js";
3
+ import { csr_graph_color_greedy } from "../../../../core/graph/csr/csr_graph_color_greedy.js";
4
+ import { csr_graph_validate_coloring } from "../../../../core/graph/csr/csr_graph_validate_coloring.js";
5
+ import { cloth_particle_coupling } from "./cloth_particle_coupling.js";
5
6
 
6
7
  /**
7
8
  * # Particle-graph colouring for the cloth solver
@@ -24,17 +25,19 @@ import { Graph } from "../../../../core/graph/v2/Graph.js";
24
25
  * against 76 for its 14,802 tetrahedra — the same asymmetry, and the reason
25
26
  * this design colours vertices rather than constraints.
26
27
  *
27
- * This runs **once**, at build time, on a `Graph` object. The runtime never
28
- * sees a graph: {@link ClothState} bakes the result into a permuted particle
29
- * order plus a range per colour, so the sweep is a pair of nested counted
30
- * loops over contiguous indices.
28
+ * This runs **once**, at build time, on the sorted CSR adjacency
29
+ * {@link cloth_particle_coupling} builds — the same edge set the
30
+ * self-collision exclusions are. The runtime never sees a graph:
31
+ * {@link ClothState} bakes the result into a permuted particle order plus a
32
+ * range per colour, so the sweep is a pair of nested counted loops over
33
+ * contiguous indices.
31
34
  *
32
35
  * The greedy colouriser is fed a largest-degree-first order (Welsh–Powell),
33
36
  * which is the cheap heuristic that gets a regular triangulated sheet down to
34
- * the 8–10 colours §5.4 predicts. The result is checked with the engine's own
35
- * {@link validateGraphColoring} behind `assert.*`, so a colouring that would
36
- * let two coupled particles race is caught in a dev build and compiles out of
37
- * a shipped one.
37
+ * the 8–10 colours §5.4 predicts. The result is checked with
38
+ * {@link csr_graph_validate_coloring} behind `assert.*`, so a colouring that
39
+ * would let two coupled particles race is caught in a dev build and compiles
40
+ * out of a shipped one.
38
41
  *
39
42
  * @author Alex Goldring
40
43
  * @copyright Company Named Limited (c) 2026
@@ -56,83 +59,25 @@ export function cloth_color_particles(
56
59
  bend_particle, bend_count
57
60
  ) {
58
61
  assert.isNonNegativeInteger(particle_count, 'particle_count');
59
- assert.isNonNegativeInteger(stretch_count, 'stretch_count');
60
- assert.isNonNegativeInteger(bend_count, 'bend_count');
61
62
 
62
- if (particle_count === 0) {
63
- return new Uint32Array(0);
64
- }
65
-
66
- const graph = new Graph();
67
-
68
- // Nodes are the particle indices themselves, inserted in order, so the
69
- // colouriser's node array is the identity permutation and `colors[i]` is
70
- // the colour of particle `i` without a second lookup.
71
- for (let i = 0; i < particle_count; i++) {
72
- graph.addNode(i);
73
- }
74
-
75
- // `Graph#hasEdge` is identity-based, so the same pair added twice becomes
76
- // two edges and shows up twice in a neighbour list. A garment adds every
77
- // hinge's shared edge once as a stretch row and again as a bend pair, so
78
- // the duplicates are the common case rather than the exception; they cost
79
- // the colouriser a linear `indexOf` each. Fold them here instead.
80
- const seen = new Set();
81
-
82
- /**
83
- * @param {number} a
84
- * @param {number} b
85
- */
86
- const couple = (a, b) => {
87
- if (a === b) {
88
- return;
89
- }
90
-
91
- const key = a < b ? a * particle_count + b : b * particle_count + a;
63
+ const colors = new Uint32Array(particle_count);
92
64
 
93
- if (seen.has(key)) {
94
- return;
95
- }
96
-
97
- seen.add(key);
98
-
99
- graph.createEdge(a, b);
100
- };
101
-
102
- // A stretch row couples its two endpoints.
103
- for (let row = 0; row < stretch_count; row++) {
104
- const a = stretch_particle[row * 2];
105
- const b = stretch_particle[row * 2 + 1];
106
-
107
- assert.ok(a >= 0 && a < particle_count, `stretch row ${row} particle 0 (=${a}) out of range`);
108
- assert.ok(b >= 0 && b < particle_count, `stretch row ${row} particle 1 (=${b}) out of range`);
109
-
110
- couple(a, b);
65
+ if (particle_count === 0) {
66
+ return colors;
111
67
  }
112
68
 
113
- // A bend stencil couples all six pairs of its four particles — every one
114
- // of them appears in the same row, so any two of them writing at once is
115
- // the race the colouring exists to prevent.
116
- for (let row = 0; row < bend_count; row++) {
117
- const base = row * 4;
118
-
119
- for (let i = 0; i < 4; i++) {
120
- const a = bend_particle[base + i];
121
-
122
- assert.ok(a >= 0 && a < particle_count, `bend row ${row} particle ${i} (=${a}) out of range`);
123
-
124
- for (let j = i + 1; j < 4; j++) {
125
- couple(a, bend_particle[base + j]);
126
- }
127
- }
128
- }
69
+ const { offset, partner } = cloth_particle_coupling(
70
+ particle_count,
71
+ stretch_particle, stretch_count,
72
+ bend_particle, bend_count
73
+ );
129
74
 
130
- const order = order_by_descending_degree(graph, particle_count);
75
+ const order = order_by_descending_degree(offset, particle_count);
131
76
 
132
- const colors = colorizeGraphGreedy(graph, order);
77
+ csr_graph_color_greedy(colors, offset, partner, order, particle_count);
133
78
 
134
79
  assert.ok(
135
- validateGraphColoring(colors, graph),
80
+ csr_graph_validate_coloring(colors, offset, partner, particle_count),
136
81
  'cloth particle colouring is invalid — two coupled particles share a colour'
137
82
  );
138
83
 
@@ -147,18 +92,13 @@ export function cloth_color_particles(
147
92
  * Ties are broken by particle index so the ordering — and therefore the whole
148
93
  * baked layout — is a deterministic function of the topology alone.
149
94
  *
150
- * @param {Graph<number>} graph
95
+ * @param {Int32Array} offset CSR offsets of the deduplicated particle graph, so
96
+ * a row's length is the particle's degree
151
97
  * @param {number} particle_count
152
98
  * @returns {Uint32Array}
153
99
  * @private
154
100
  */
155
- function order_by_descending_degree(graph, particle_count) {
156
- const degree = new Int32Array(particle_count);
157
-
158
- for (let i = 0; i < particle_count; i++) {
159
- degree[i] = graph.getNeighbours(i).length;
160
- }
161
-
101
+ function order_by_descending_degree(offset, particle_count) {
162
102
  const order = new Uint32Array(particle_count);
163
103
 
164
104
  for (let i = 0; i < particle_count; i++) {
@@ -167,7 +107,7 @@ function order_by_descending_degree(graph, particle_count) {
167
107
 
168
108
  // `Array#sort` over a typed array is a numeric sort already; the comparator
169
109
  // is here for the tie-break, not for the ordering of the degrees.
170
- order.sort((a, b) => (degree[b] - degree[a]) || (a - b));
110
+ order.sort((a, b) => ((offset[b + 1] - offset[b]) - (offset[a + 1] - offset[a])) || (a - b));
171
111
 
172
112
  return order;
173
113
  }
@@ -200,21 +140,9 @@ export function cloth_color_order(colors, particle_count) {
200
140
  }
201
141
 
202
142
  const colour_offset = new Int32Array(colour_count + 1);
203
-
204
- for (let i = 0; i < particle_count; i++) {
205
- colour_offset[colors[i] + 1]++;
206
- }
207
-
208
- for (let c = 0; c < colour_count; c++) {
209
- colour_offset[c + 1] += colour_offset[c];
210
- }
211
-
212
- const cursor = colour_offset.slice(0, colour_count);
213
143
  const order = new Int32Array(particle_count);
214
144
 
215
- for (let i = 0; i < particle_count; i++) {
216
- order[cursor[colors[i]]++] = i;
217
- }
145
+ csr_build_incidence(colour_offset, order, colors, particle_count, colour_count);
218
146
 
219
147
  return { colour_count, colour_offset, order };
220
148
  }