@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,5 +1,8 @@
1
1
  import { assert } from "../../../../core/assert.js";
2
+ import { array_compute_max } from "../../../../core/collection/array/array_compute_max.js";
3
+ import { clamp01 } from "../../../../core/math/clamp01.js";
2
4
  import { cloth_collider_pose_at } from "../collider/cloth_collider_sdf.js";
5
+ import { CLOTH_HOLD_LINE_WORDS, cloth_hold_line_fit, cloth_hold_line_turn } from "./cloth_hold_line.js";
3
6
  import { cloth_solve_vertex } from "./cloth_solve_vertex.js";
4
7
  import {
5
8
  CLOTH_CONTACT_K_MIN_RATIO,
@@ -42,6 +45,7 @@ import { find_non_finite_cloth_state } from "./find_non_finite_cloth_state.js";
42
45
  * warm start λ ← λ·α·γ ; k ← clamp(k·γ, k_min, k_max) (hard rows only)
43
46
  * iterate × iterations:
44
47
  * for each colour: for each particle: vertex update
48
+ * last iteration, held particles on one line: turn about it
45
49
  * dual update: λ ← clamp(k·C + λ, f_min, f_max)
46
50
  * k ← min(k + β·|C|, min(k_max, stiffness))
47
51
  * integrate v = (x − x_prev)/h
@@ -85,6 +89,21 @@ import { find_non_finite_cloth_state } from "./find_non_finite_cloth_state.js";
85
89
  * which is what makes "no wind produces the bytes M5 measured" a fact about the
86
90
  * code rather than a claim about floating point.
87
91
  *
92
+ * ## One more block when the holds are a line
93
+ *
94
+ * Every vertex update is a 3×3 block of the descent, and a cloth held along one
95
+ * line has a motion no such block can make: turning about the line as a rigid
96
+ * body. About a vertical line nothing restores that turn, and the step stopped
97
+ * at a fabric's iteration count left a moment about it every substep — a flag
98
+ * turned on its pole for as long as it was run. So the turn is a block of its
99
+ * own, `cloth_hold_line.js`: one Newton step along it, in the last iteration,
100
+ * after the sweep and before the dual update.
101
+ *
102
+ * Whether the held particles are on a line is decided at every substep, from
103
+ * where the predict has just carried them. The predict lists them as it goes,
104
+ * so the question costs a pass over the held particles rather than over the
105
+ * cloth.
106
+ *
88
107
  * ## What each piece is for
89
108
  *
90
109
  * **Warm start** carries the multipliers into the next substep so a hard row
@@ -203,13 +222,37 @@ export function cloth_step(
203
222
 
204
223
  const contacts = collider_table !== null && collider_count > 0 ? collider_table : null;
205
224
 
225
+ if (HELD.length < state.particle_count) {
226
+ HELD = new Int32Array(state.particle_count);
227
+ }
228
+
229
+ const held = HELD;
230
+ const line = HOLD_LINE;
231
+
232
+ const last_iteration = iterations - 1;
233
+
206
234
  for (let substep = 0; substep < substeps; substep++) {
235
+ // How many substeps are left, this one included: a held particle covers
236
+ // an equal share of what remains of its way at each of them.
237
+ const remaining = substeps - substep;
238
+
239
+ let held_count;
240
+
207
241
  if (external === null) {
208
- cloth_predict(state, h, acceleration_x, acceleration_y, acceleration_z);
242
+ held_count = cloth_predict(state, h, acceleration_x, acceleration_y, acceleration_z, remaining, held);
209
243
  } else {
210
- cloth_predict_varying(state, h, external);
244
+ held_count = cloth_predict_varying(state, h, external, remaining, held);
211
245
  }
212
246
 
247
+ // Where the held particles are for the rest of the substep: nothing
248
+ // below moves one.
249
+ const turn = cloth_hold_line_fit(line, state.position, held, held_count);
250
+
251
+ // After the held particles have moved, so a centre measured from one
252
+ // sits where it is at this substep rather than where it was at the
253
+ // start of the step.
254
+ cloth_leash_follow(state);
255
+
213
256
  if (contacts !== null) {
214
257
  cloth_collider_pose_at(contacts, collider_count, (substep + 1) / substeps);
215
258
  }
@@ -239,6 +282,10 @@ export function cloth_step(
239
282
  }
240
283
  }
241
284
 
285
+ if (turn && iteration === last_iteration) {
286
+ cloth_hold_line_turn(state, line, inverse_h_squared, contacts);
287
+ }
288
+
242
289
  cloth_stretch_dual_update(state, beta, k_max_ratio, inverse_h_squared);
243
290
  cloth_bend_dual_update(state, beta, k_max_ratio, inverse_h_squared);
244
291
  cloth_leash_dual_update(state, beta, k_max_ratio, inverse_h_squared);
@@ -262,6 +309,91 @@ export function cloth_step(
262
309
  );
263
310
  }
264
311
 
312
+ /**
313
+ * Carry one held particle an equal share of the remaining way to its kinematic
314
+ * target, and make that its inertial target too.
315
+ *
316
+ * Equal shares of what *remains* rather than `(substep + 1)/substeps` of the
317
+ * whole: the particle is not moved by anything else in between, so the two put
318
+ * it in the same places, and this form needs no record of where the step began.
319
+ * It lands on the target exactly at the last substep, and a target equal to the
320
+ * position moves nothing by exactly nothing — which is what keeps a holder that
321
+ * rides the frame bit-identical to the fixed anchor it replaced.
322
+ *
323
+ * @param {ClothState} state
324
+ * @param {number} p particle index times three
325
+ * @param {number} remaining substeps left in the step, this one included
326
+ * @private
327
+ */
328
+ function cloth_carry_held(state, p, remaining) {
329
+ const position = state.position;
330
+ const inertial = state.inertial;
331
+ const target = state.kinematic_target;
332
+
333
+ const x = position[p] + (target[p] - position[p]) / remaining;
334
+ const y = position[p + 1] + (target[p + 1] - position[p + 1]) / remaining;
335
+ const z = position[p + 2] + (target[p + 2] - position[p + 2]) / remaining;
336
+
337
+ position[p] = x;
338
+ position[p + 1] = y;
339
+ position[p + 2] = z;
340
+
341
+ inertial[p] = x;
342
+ inertial[p + 1] = y;
343
+ inertial[p + 2] = z;
344
+ }
345
+
346
+ /**
347
+ * Re-centre every leash row that is measured from a particle: `position[source]
348
+ * + offset`, at the substep's own positions.
349
+ *
350
+ * @param {ClothState} state
351
+ * @private
352
+ */
353
+ function cloth_leash_follow(state) {
354
+ const count = state.leash_count;
355
+
356
+ const source = state.leash_source;
357
+ const offset = state.leash_offset;
358
+ const target = state.leash_target;
359
+ const position = state.position;
360
+
361
+ for (let row = 0; row < count; row++) {
362
+ const s = source[row];
363
+
364
+ if (s < 0) {
365
+ continue;
366
+ }
367
+
368
+ const r = row * 3;
369
+ const p = s * 3;
370
+
371
+ target[r] = position[p] + offset[r];
372
+ target[r + 1] = position[p + 1] + offset[r + 1];
373
+ target[r + 2] = position[p + 2] + offset[r + 2];
374
+ }
375
+ }
376
+
377
+ /**
378
+ * A held particle's velocity is the one its holder is moving it at. Nothing in
379
+ * the step reads it while the hold lasts — it has no inertia and no acceleration
380
+ * to seed — and it is exactly what the particle carries when it is let go.
381
+ *
382
+ * @param {ClothState} state
383
+ * @param {number} p particle index times three
384
+ * @param {number} inverse_h
385
+ * @private
386
+ */
387
+ function cloth_held_velocity(state, p, inverse_h) {
388
+ const position = state.position;
389
+ const position_previous = state.position_previous;
390
+ const velocity = state.velocity;
391
+
392
+ velocity[p] = (position[p] - position_previous[p]) * inverse_h;
393
+ velocity[p + 1] = (position[p + 1] - position_previous[p + 1]) * inverse_h;
394
+ velocity[p + 2] = (position[p + 2] - position_previous[p + 2]) * inverse_h;
395
+ }
396
+
265
397
  /**
266
398
  * The largest inverse mass in the cloth — the lightest particle, which is the
267
399
  * one a shared penalty has to be safe for.
@@ -278,17 +410,9 @@ export function cloth_step(
278
410
  * @private
279
411
  */
280
412
  function max_inverse_mass(state) {
281
- const mass_inverse = state.mass_inverse;
282
-
283
- let worst = 0;
413
+ const worst = array_compute_max(state.mass_inverse, 0, state.particle_count);
284
414
 
285
- for (let i = 0; i < state.particle_count; i++) {
286
- if (mass_inverse[i] > worst) {
287
- worst = mass_inverse[i];
288
- }
289
- }
290
-
291
- // Every particle pinned: nothing can move, so the stiffness is unused and
415
+ // Every particle pinned, or no particles at all: nothing can move, so the stiffness is unused and
292
416
  // any finite value is as good as another.
293
417
  return worst > 0 ? worst : 1;
294
418
  }
@@ -297,18 +421,22 @@ function max_inverse_mass(state) {
297
421
  * Predict: record where the substep started, build the inertial target every
298
422
  * vertex update pulls towards, and seed the descent.
299
423
  *
300
- * A pinned particle (zero inverse mass) is held exactly: it does not fall, it
301
- * does not carry velocity, and its inertial target is its own position, so a
302
- * row that reaches it sees a fixed anchor rather than a very heavy particle.
424
+ * A held particle (zero inverse mass) is kinematic: it does not fall, it is
425
+ * carried towards its {@link ClothState#kinematic_target} by an equal share of
426
+ * the remaining way, and its inertial target is wherever that puts it, so a row
427
+ * that reaches it sees a fixed anchor rather than a very heavy particle.
303
428
  *
304
429
  * @param {ClothState} state
305
430
  * @param {number} h
306
431
  * @param {number} acceleration_x
307
432
  * @param {number} acceleration_y
308
433
  * @param {number} acceleration_z
434
+ * @param {number} remaining substeps left in the step, this one included
435
+ * @param {Int32Array} held out, every held particle's index, in order
436
+ * @returns {number} how many particles are held
309
437
  * @private
310
438
  */
311
- function cloth_predict(state, h, acceleration_x, acceleration_y, acceleration_z) {
439
+ function cloth_predict(state, h, acceleration_x, acceleration_y, acceleration_z, remaining, held) {
312
440
  const particle_count = state.particle_count;
313
441
 
314
442
  const position = state.position;
@@ -324,6 +452,8 @@ function cloth_predict(state, h, acceleration_x, acceleration_y, acceleration_z)
324
452
  const gravity_y = h_squared * acceleration_y;
325
453
  const gravity_z = h_squared * acceleration_z;
326
454
 
455
+ let held_count = 0;
456
+
327
457
  for (let i = 0; i < particle_count; i++) {
328
458
  const p = i * 3;
329
459
 
@@ -336,9 +466,9 @@ function cloth_predict(state, h, acceleration_x, acceleration_y, acceleration_z)
336
466
  position_previous[p + 2] = z;
337
467
 
338
468
  if (mass_inverse[i] === 0) {
339
- inertial[p] = x;
340
- inertial[p + 1] = y;
341
- inertial[p + 2] = z;
469
+ cloth_carry_held(state, p, remaining);
470
+
471
+ held[held_count++] = i;
342
472
 
343
473
  continue;
344
474
  }
@@ -357,22 +487,26 @@ function cloth_predict(state, h, acceleration_x, acceleration_y, acceleration_z)
357
487
  position[p + 1] = y + drift_y + blend * gravity_y;
358
488
  position[p + 2] = z + drift_z + blend * gravity_z;
359
489
  }
490
+
491
+ return held_count;
360
492
  }
361
493
 
362
494
  /**
363
495
  * {@link cloth_predict} with a per-particle external acceleration — §10's wind,
364
496
  * with gravity already folded in by `cloth_wind_accelerate`.
365
497
  *
366
- * Identical in every other respect, including the pinned-particle rule: a pin is
367
- * held exactly, so the air does not move it and its inertial target is its own
368
- * position.
498
+ * Identical in every other respect, including the held-particle rule: the air
499
+ * does not move a held particle, its holder does.
369
500
  *
370
501
  * @param {ClothState} state
371
502
  * @param {number} h
372
503
  * @param {Float32Array} external 3 per particle, cloth-local, m/s²
504
+ * @param {number} remaining substeps left in the step, this one included
505
+ * @param {Int32Array} held out, every held particle's index, in order
506
+ * @returns {number} how many particles are held
373
507
  * @private
374
508
  */
375
- function cloth_predict_varying(state, h, external) {
509
+ function cloth_predict_varying(state, h, external, remaining, held) {
376
510
  const particle_count = state.particle_count;
377
511
 
378
512
  const position = state.position;
@@ -384,6 +518,8 @@ function cloth_predict_varying(state, h, external) {
384
518
 
385
519
  const h_squared = h * h;
386
520
 
521
+ let held_count = 0;
522
+
387
523
  for (let i = 0; i < particle_count; i++) {
388
524
  const p = i * 3;
389
525
 
@@ -396,9 +532,9 @@ function cloth_predict_varying(state, h, external) {
396
532
  position_previous[p + 2] = z;
397
533
 
398
534
  if (mass_inverse[i] === 0) {
399
- inertial[p] = x;
400
- inertial[p + 1] = y;
401
- inertial[p + 2] = z;
535
+ cloth_carry_held(state, p, remaining);
536
+
537
+ held[held_count++] = i;
402
538
 
403
539
  continue;
404
540
  }
@@ -421,6 +557,8 @@ function cloth_predict_varying(state, h, external) {
421
557
  position[p + 1] = y + drift_y + blend * push_y;
422
558
  position[p + 2] = z + drift_z + blend * push_z;
423
559
  }
560
+
561
+ return held_count;
424
562
  }
425
563
 
426
564
  /**
@@ -461,12 +599,14 @@ function cloth_integrate(state, inverse_h, acceleration_x, acceleration_y, accel
461
599
  const inverse_acceleration_squared = acceleration_squared > 0 ? 1 / acceleration_squared : 0;
462
600
 
463
601
  for (let i = 0; i < particle_count; i++) {
602
+ const p = i * 3;
603
+
464
604
  if (mass_inverse[i] === 0) {
605
+ cloth_held_velocity(state, p, inverse_h);
606
+
465
607
  continue;
466
608
  }
467
609
 
468
- const p = i * 3;
469
-
470
610
  const next_x = (position[p] - position_previous[p]) * inverse_h;
471
611
  const next_y = (position[p + 1] - position_previous[p + 1]) * inverse_h;
472
612
  const next_z = (position[p + 2] - position_previous[p + 2]) * inverse_h;
@@ -476,15 +616,7 @@ function cloth_integrate(state, inverse_h, acceleration_x, acceleration_y, accel
476
616
  (next_y - velocity[p + 1]) * acceleration_y +
477
617
  (next_z - velocity[p + 2]) * acceleration_z;
478
618
 
479
- let blend = realised * inverse_h * inverse_acceleration_squared;
480
-
481
- if (blend < 0) {
482
- blend = 0;
483
- } else if (blend > 1) {
484
- blend = 1;
485
- }
486
-
487
- inertia_blend[i] = blend;
619
+ inertia_blend[i] = clamp01(realised * inverse_h * inverse_acceleration_squared);
488
620
 
489
621
  velocity[p] = next_x;
490
622
  velocity[p + 1] = next_y;
@@ -517,12 +649,14 @@ function cloth_integrate_varying(state, inverse_h, external) {
517
649
  const inertia_blend = state.inertia_blend;
518
650
 
519
651
  for (let i = 0; i < particle_count; i++) {
652
+ const p = i * 3;
653
+
520
654
  if (mass_inverse[i] === 0) {
655
+ cloth_held_velocity(state, p, inverse_h);
656
+
521
657
  continue;
522
658
  }
523
659
 
524
- const p = i * 3;
525
-
526
660
  const acceleration_x = external[p];
527
661
  const acceleration_y = external[p + 1];
528
662
  const acceleration_z = external[p + 2];
@@ -546,15 +680,7 @@ function cloth_integrate_varying(state, inverse_h, external) {
546
680
  // {@link cloth_integrate} uses — the two differ in the last bit, and
547
681
  // a cloth whose external acceleration happens to be exactly gravity
548
682
  // should follow the same trajectory whichever loop stepped it.
549
- let blend = realised * inverse_h * (1 / acceleration_squared);
550
-
551
- if (blend < 0) {
552
- blend = 0;
553
- } else if (blend > 1) {
554
- blend = 1;
555
- }
556
-
557
- inertia_blend[i] = blend;
683
+ inertia_blend[i] = clamp01(realised * inverse_h * (1 / acceleration_squared));
558
684
  } else {
559
685
  // No direction to project onto, so nothing to seed. The uniform
560
686
  // path reaches this for the whole cloth at once; here it is a
@@ -568,3 +694,18 @@ function cloth_integrate_varying(state, inverse_h, external) {
568
694
  velocity[p + 2] = next_z;
569
695
  }
570
696
  }
697
+
698
+ /**
699
+ * The held particles' indices, as the predict carries them — grown to the
700
+ * largest cloth stepped, and only ever read up to the count the predict returns.
701
+ * @type {Int32Array}
702
+ * @private
703
+ */
704
+ let HELD = new Int32Array(0);
705
+
706
+ /**
707
+ * The hold line of the substep in progress, from `cloth_hold_line_fit`.
708
+ * @type {Float64Array}
709
+ * @private
710
+ */
711
+ const HOLD_LINE = new Float64Array(CLOTH_HOLD_LINE_WORDS);
@@ -31,6 +31,7 @@ export namespace ClothStepParam {
31
31
  let COLLIDER_COUNT: number;
32
32
  let SELF_COLLISION: number;
33
33
  let DRAG_RESPONSE: number;
34
+ let KINEMATIC_TRAVEL: number;
34
35
  }
35
36
  /**
36
37
  * `Float64` words one cloth's parameter block occupies.
@@ -1 +1 @@
1
- {"version":3,"file":"cloth_step_instance.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_step_instance.js"],"names":[],"mappings":"AAsIA;;;;;;;;;GASG;AACH,wEANW;IAAC,MAAM,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAC,GAAC,IAAI,UAE9C,YAAY,UACZ,MAAM,GACJ,IAAI,CA4DhB;;;;6BA/IS,MAAM;;;;;;;;;;;;;;;;;AAqEhB;;;GAGG;AACH,sCAFU,MAAM,CAE0B"}
1
+ {"version":3,"file":"cloth_step_instance.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_step_instance.js"],"names":[],"mappings":"AA6IA;;;;;;;;;GASG;AACH,wEANW;IAAC,MAAM,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAC,GAAC,IAAI,UAE9C,YAAY,UACZ,MAAM,GACJ,IAAI,CA6DhB;;;;6BAtJS,MAAM;;;;;;;;;;;;;;;;;;AA2EhB;;;GAGG;AACH,sCAFU,MAAM,CAE0B"}
@@ -1,3 +1,4 @@
1
+ import { vector_scale_offset } from "../../../../core/geom/vec/vector_scale_offset.js";
1
2
  import { cloth_contact_find } from "./cloth_contact_find.js";
2
3
  import { cloth_self_find } from "./cloth_self_find.js";
3
4
  import { cloth_step } from "./cloth_step.js";
@@ -123,14 +124,20 @@ export const ClothStepParam = {
123
124
  * takes `cloth_step`'s uniform-gravity path, which is the path M0 through
124
125
  * M5 measured.
125
126
  */
126
- DRAG_RESPONSE: 13
127
+ DRAG_RESPONSE: 13,
128
+ /**
129
+ * The furthest any held particle is carried this step, metres — how far a
130
+ * cloth its holders are dragging moves without a velocity to show for it.
131
+ * Contact discovery reaches this much further for every free particle.
132
+ */
133
+ KINEMATIC_TRAVEL: 14
127
134
  };
128
135
 
129
136
  /**
130
137
  * `Float64` words one cloth's parameter block occupies.
131
138
  * @type {number}
132
139
  */
133
- export const CLOTH_STEP_PARAM_STRIDE = 14;
140
+ export const CLOTH_STEP_PARAM_STRIDE = 15;
134
141
 
135
142
  /**
136
143
  * Step one cloth.
@@ -159,7 +166,8 @@ export function cloth_step_instance(state, self_exclusions, params, offset) {
159
166
  damp(state, params[offset + ClothStepParam.RETENTION]);
160
167
 
161
168
  const contact_count = cloth_contact_find(
162
- state, state.collider_table, state.collider_key, collider_count, dt
169
+ state, state.collider_table, state.collider_key, collider_count, dt,
170
+ params[offset + ClothStepParam.KINEMATIC_TRAVEL]
163
171
  );
164
172
 
165
173
  let self_pairs = 0;
@@ -222,9 +230,7 @@ function damp(state, retention) {
222
230
 
223
231
  const velocity = state.velocity;
224
232
 
225
- for (let i = 0; i < velocity.length; i++) {
226
- velocity[i] *= retention;
227
- }
233
+ vector_scale_offset(velocity, 0, velocity, 0, velocity.length, retention);
228
234
  }
229
235
 
230
236
  /**
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The worst relative error over a cloth's stretch rows, `max |C|/L₀` with
3
+ * `C = ‖x_a − x_b‖ − L₀` — §7 P2's rubber number. Zero when every row sits at
4
+ * its rest length; `0.1` when the worst one is ten percent off, long or short.
5
+ *
6
+ * A row of zero rest length has no relative error to speak of and is skipped,
7
+ * so a cloth with no rows, or only such rows, reads zero. A row with a NaN end
8
+ * reads NaN and so does the answer, whatever the other rows say: the callers
9
+ * gate on `Number.isFinite`, and a broken state must not read as converged.
10
+ *
11
+ * A diagnostic for specs, measurements and the playgrounds; nothing in the
12
+ * step reads it.
13
+ *
14
+ * @param {ClothState} state
15
+ * @returns {number} dimensionless
16
+ *
17
+ * @author Alex Goldring
18
+ * @copyright Company Named Limited (c) 2026
19
+ */
20
+ export function cloth_stretch_residual(state: ClothState): number;
21
+ //# sourceMappingURL=cloth_stretch_residual.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloth_stretch_residual.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_stretch_residual.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;GAkBG;AACH,2DALa,MAAM,CAoClB"}
@@ -0,0 +1,54 @@
1
+ import { v3_length } from "../../../../core/geom/vec3/v3_length.js";
2
+ import { max2_exact } from "../../../../core/math/max2_exact.js";
3
+
4
+ /**
5
+ * The worst relative error over a cloth's stretch rows, `max |C|/L₀` with
6
+ * `C = ‖x_a − x_b‖ − L₀` — §7 P2's rubber number. Zero when every row sits at
7
+ * its rest length; `0.1` when the worst one is ten percent off, long or short.
8
+ *
9
+ * A row of zero rest length has no relative error to speak of and is skipped,
10
+ * so a cloth with no rows, or only such rows, reads zero. A row with a NaN end
11
+ * reads NaN and so does the answer, whatever the other rows say: the callers
12
+ * gate on `Number.isFinite`, and a broken state must not read as converged.
13
+ *
14
+ * A diagnostic for specs, measurements and the playgrounds; nothing in the
15
+ * step reads it.
16
+ *
17
+ * @param {ClothState} state
18
+ * @returns {number} dimensionless
19
+ *
20
+ * @author Alex Goldring
21
+ * @copyright Company Named Limited (c) 2026
22
+ */
23
+ export function cloth_stretch_residual(state) {
24
+ const stretch_count = state.stretch_count;
25
+
26
+ const stretch_particle = state.stretch_particle;
27
+ const stretch_rest = state.stretch_rest;
28
+ const position = state.position;
29
+
30
+ let worst = 0;
31
+
32
+ for (let row = 0; row < stretch_count; row++) {
33
+ const rest = stretch_rest[row];
34
+
35
+ if (!(rest > 0)) {
36
+ continue;
37
+ }
38
+
39
+ const a = stretch_particle[row * 2] * 3;
40
+ const b = stretch_particle[row * 2 + 1] * 3;
41
+
42
+ const length = v3_length(
43
+ position[a] - position[b],
44
+ position[a + 1] - position[b + 1],
45
+ position[a + 2] - position[b + 2]
46
+ );
47
+
48
+ const residual = Math.abs(length - rest) / rest;
49
+
50
+ worst = max2_exact(worst, residual);
51
+ }
52
+
53
+ return worst;
54
+ }
@@ -1,3 +1,18 @@
1
+ /**
2
+ * Seed an accumulator with the inertial term alone, before any row adds to it:
3
+ * the force `−(m/h²)(x − y)`, the Hessian `(m/h²)·I`, and no trust bound yet.
4
+ *
5
+ * `m/h²` is positive and finite whenever the particle has a mass at all, which
6
+ * is what makes the assembled `H` positive definite rather than merely
7
+ * semidefinite.
8
+ *
9
+ * @param {Float64Array} accumulator {@link CVA_STRIDE} slots, overwritten
10
+ * @param {Float32Array} position particle positions, 3 per particle
11
+ * @param {Float32Array} inertial predicted positions `y`, 3 per particle
12
+ * @param {number} p the particle's first component index, `particle · 3`
13
+ * @param {number} mass_over_h_squared `m/h²`
14
+ */
15
+ export function cloth_vertex_accumulator_seed(accumulator: Float64Array, position: Float32Array, inertial: Float32Array, p: number, mass_over_h_squared: number): void;
1
16
  /**
2
17
  * # The per-vertex `(f, H)` accumulator
3
18
  *
@@ -1 +1 @@
1
- {"version":3,"file":"cloth_vertex_accumulator.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_vertex_accumulator.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,gBAAgB;AAChB,wBAAyB;AACzB,gBAAgB;AAChB,wBAAyB;AACzB,gBAAgB;AAChB,wBAAyB;AACzB,yBAAyB;AACzB,yBAA0B;AAC1B,yBAAyB;AACzB,yBAA0B;AAC1B,yBAAyB;AACzB,yBAA0B;AAC1B,mCAAmC;AACnC,yBAA0B;AAC1B,mCAAmC;AACnC,yBAA0B;AAC1B,mCAAmC;AACnC,yBAA0B;AAE1B;;;;;;;;;;GAUG;AACH,0BAA2B;AAE3B,gCAAgC;AAChC,4BAA6B"}
1
+ {"version":3,"file":"cloth_vertex_accumulator.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_vertex_accumulator.js"],"names":[],"mappings":"AAyDA;;;;;;;;;;;;;GAaG;AACH,2DANW,YAAY,YACZ,YAAY,YACZ,YAAY,KACZ,MAAM,uBACN,MAAM,QAchB;AAnFD;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,gBAAgB;AAChB,wBAAyB;AACzB,gBAAgB;AAChB,wBAAyB;AACzB,gBAAgB;AAChB,wBAAyB;AACzB,yBAAyB;AACzB,yBAA0B;AAC1B,yBAAyB;AACzB,yBAA0B;AAC1B,yBAAyB;AACzB,yBAA0B;AAC1B,mCAAmC;AACnC,yBAA0B;AAC1B,mCAAmC;AACnC,yBAA0B;AAC1B,mCAAmC;AACnC,yBAA0B;AAE1B;;;;;;;;;;GAUG;AACH,0BAA2B;AAE3B,gCAAgC;AAChC,4BAA6B"}
@@ -54,3 +54,31 @@ export const CVA_TRUST = 9;
54
54
 
55
55
  /** Slots in one accumulator. */
56
56
  export const CVA_STRIDE = 10;
57
+
58
+ /**
59
+ * Seed an accumulator with the inertial term alone, before any row adds to it:
60
+ * the force `−(m/h²)(x − y)`, the Hessian `(m/h²)·I`, and no trust bound yet.
61
+ *
62
+ * `m/h²` is positive and finite whenever the particle has a mass at all, which
63
+ * is what makes the assembled `H` positive definite rather than merely
64
+ * semidefinite.
65
+ *
66
+ * @param {Float64Array} accumulator {@link CVA_STRIDE} slots, overwritten
67
+ * @param {Float32Array} position particle positions, 3 per particle
68
+ * @param {Float32Array} inertial predicted positions `y`, 3 per particle
69
+ * @param {number} p the particle's first component index, `particle · 3`
70
+ * @param {number} mass_over_h_squared `m/h²`
71
+ */
72
+ export function cloth_vertex_accumulator_seed(accumulator, position, inertial, p, mass_over_h_squared) {
73
+ accumulator[CVA_F_X] = -mass_over_h_squared * (position[p] - inertial[p]);
74
+ accumulator[CVA_F_Y] = -mass_over_h_squared * (position[p + 1] - inertial[p + 1]);
75
+ accumulator[CVA_F_Z] = -mass_over_h_squared * (position[p + 2] - inertial[p + 2]);
76
+
77
+ accumulator[CVA_H_XX] = mass_over_h_squared;
78
+ accumulator[CVA_H_YY] = mass_over_h_squared;
79
+ accumulator[CVA_H_ZZ] = mass_over_h_squared;
80
+ accumulator[CVA_H_XY] = 0;
81
+ accumulator[CVA_H_XZ] = 0;
82
+ accumulator[CVA_H_YZ] = 0;
83
+ accumulator[CVA_TRUST] = Infinity;
84
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * How far the cloth has stretched away from its root, as the worst ratio over
3
+ * nodes of straight-line distance from node 0 to the fabric between them:
4
+ * `max ‖x_node − x_0‖ / d_geo(node)` over nodes `1 .. node_count − 1` — §7 P2's
5
+ * measure. At most 1 for a cloth that has not over-stretched anywhere, since no
6
+ * straight line is longer than the fabric it spans; `1.05` is a node five
7
+ * percent further out than the cloth reaches.
8
+ *
9
+ * Everything is measured from node 0, the root of the seeder's tree, which is
10
+ * where the rigs this was written for are held. A cloth held in several places
11
+ * wants each node measured from its own hold instead, and this is not that
12
+ * measure.
13
+ *
14
+ * A node at a NaN position reads NaN and so does the answer, whatever the other
15
+ * nodes say, so a broken state cannot pass for a well-behaved one.
16
+ *
17
+ * Takes the arrays rather than a `ClothInstance` so the solver side does not
18
+ * depend on the ECS one.
19
+ *
20
+ * @param {Float32Array|Float64Array} position 3 per particle
21
+ * @param {Int32Array|Uint32Array|number[]} particle_of_node particle index per node
22
+ * @param {Float32Array|Float64Array|number[]} geodesic fabric distance from node 0 per node, metres
23
+ * @param {number} node_count
24
+ * @returns {number} dimensionless; 0 for a cloth of fewer than two nodes
25
+ *
26
+ * @author Alex Goldring
27
+ * @copyright Company Named Limited (c) 2026
28
+ */
29
+ export function cloth_worst_tether_ratio(position: Float32Array | Float64Array, particle_of_node: Int32Array | Uint32Array | number[], geodesic: Float32Array | Float64Array | number[], node_count: number): number;
30
+ //# sourceMappingURL=cloth_worst_tether_ratio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloth_worst_tether_ratio.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_worst_tether_ratio.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,mDATW,YAAY,GAAC,YAAY,oBACzB,UAAU,GAAC,WAAW,GAAC,MAAM,EAAE,YAC/B,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,cAClC,MAAM,GACJ,MAAM,CA6BlB"}