@woosh/meep-engine 3.44.0 → 3.46.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 (447) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/core/assert.d.ts.map +1 -1
  4. package/src/core/assert.js +5 -1
  5. package/src/core/binary/hash/XXH128Hash.d.ts +1 -37
  6. package/src/core/binary/hash/XXH128Hash.d.ts.map +1 -1
  7. package/src/core/binary/hash/XXH128Hash.js +4 -55
  8. package/src/core/binary/hash/XXH3_SECRET.d.ts +1 -12
  9. package/src/core/binary/hash/XXH3_SECRET.d.ts.map +1 -1
  10. package/src/core/binary/hash/XXH3_SECRET.js +4 -25
  11. package/src/core/binary/hash/crc32.d.ts +1 -15
  12. package/src/core/binary/hash/crc32.d.ts.map +1 -1
  13. package/src/core/binary/hash/crc32.js +4 -96
  14. package/src/core/binary/hash/xxh3_128.d.ts +1 -9
  15. package/src/core/binary/hash/xxh3_128.d.ts.map +1 -1
  16. package/src/core/binary/hash/xxh3_128.js +4 -341
  17. package/src/core/binary/hash/xxh3_64.d.ts +1 -8
  18. package/src/core/binary/hash/xxh3_64.d.ts.map +1 -1
  19. package/src/core/binary/hash/xxh3_64.js +4 -241
  20. package/src/core/binary/hash/xxh3_common.d.ts +1 -223
  21. package/src/core/binary/hash/xxh3_common.d.ts.map +1 -1
  22. package/src/core/binary/hash/xxh3_common.js +90 -476
  23. package/src/core/collection/array/array_sort_insertion_ascending.d.ts +19 -0
  24. package/src/core/collection/array/array_sort_insertion_ascending.d.ts.map +1 -0
  25. package/src/core/collection/array/array_sort_insertion_ascending.js +31 -0
  26. package/src/core/collection/array/combine_hash.d.ts +6 -0
  27. package/src/core/collection/array/combine_hash.d.ts.map +1 -1
  28. package/src/core/collection/array/combine_hash.js +6 -0
  29. package/src/core/function/FunctionCompiler.js +2 -2
  30. package/src/core/geom/3d/aabb/aabb3_array_round_outward_f32.d.ts +27 -0
  31. package/src/core/geom/3d/aabb/aabb3_array_round_outward_f32.d.ts.map +1 -0
  32. package/src/core/geom/3d/aabb/aabb3_array_round_outward_f32.js +39 -0
  33. package/src/core/geom/3d/aabb/aabb3_from_v3_array.d.ts.map +1 -1
  34. package/src/core/geom/3d/aabb/aabb3_from_v3_array.js +4 -1
  35. package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts +2 -2
  36. package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts.map +1 -1
  37. package/src/core/geom/3d/aabb/aabb3_transform_oriented.js +1 -1
  38. package/src/core/geom/3d/mat4/m4_multiply.d.ts +3 -0
  39. package/src/core/geom/3d/mat4/m4_multiply.d.ts.map +1 -1
  40. package/src/core/geom/3d/mat4/m4_multiply.js +3 -0
  41. package/src/core/geom/3d/mat4/m4_multiply_f64.d.ts +30 -0
  42. package/src/core/geom/3d/mat4/m4_multiply_f64.d.ts.map +1 -0
  43. package/src/core/geom/3d/mat4/m4_multiply_f64.js +106 -0
  44. package/src/core/geom/3d/pose/pose3_apply_inverse_point_array.d.ts +21 -0
  45. package/src/core/geom/3d/pose/pose3_apply_inverse_point_array.d.ts.map +1 -0
  46. package/src/core/geom/3d/pose/pose3_apply_inverse_point_array.js +36 -0
  47. package/src/core/geom/3d/pose/pose3_apply_point_array.d.ts +25 -0
  48. package/src/core/geom/3d/pose/pose3_apply_point_array.d.ts.map +1 -0
  49. package/src/core/geom/3d/pose/pose3_apply_point_array.js +40 -0
  50. package/src/core/geom/3d/pose/pose3_compose_array.d.ts +28 -0
  51. package/src/core/geom/3d/pose/pose3_compose_array.d.ts.map +1 -0
  52. package/src/core/geom/3d/pose/pose3_compose_array.js +41 -0
  53. package/src/core/geom/3d/pose/pose3_to_local_array.d.ts +29 -0
  54. package/src/core/geom/3d/pose/pose3_to_local_array.d.ts.map +1 -0
  55. package/src/core/geom/3d/pose/pose3_to_local_array.js +42 -0
  56. package/src/core/geom/3d/quaternion/quat3_clamp_angle_array.d.ts +28 -0
  57. package/src/core/geom/3d/quaternion/quat3_clamp_angle_array.d.ts.map +1 -0
  58. package/src/core/geom/3d/quaternion/quat3_clamp_angle_array.js +66 -0
  59. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_left_array.d.ts +22 -0
  60. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_left_array.d.ts.map +1 -0
  61. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_left_array.js +30 -0
  62. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_right_array.d.ts +23 -0
  63. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_right_array.d.ts.map +1 -0
  64. package/src/core/geom/3d/quaternion/quat3_multiply_conjugate_right_array.js +31 -0
  65. package/src/core/geom/3d/triangle/tri3_compute_normal_area_weighted_array.d.ts +26 -0
  66. package/src/core/geom/3d/triangle/tri3_compute_normal_area_weighted_array.d.ts.map +1 -0
  67. package/src/core/geom/3d/triangle/tri3_compute_normal_area_weighted_array.js +46 -0
  68. package/src/core/geom/ConicRay.js +2 -2
  69. package/src/core/geom/Vector4.d.ts.map +1 -1
  70. package/src/core/geom/Vector4.js +8 -5
  71. package/src/core/geom/vec3/v3_distance_array.d.ts +11 -0
  72. package/src/core/geom/vec3/v3_distance_array.d.ts.map +1 -0
  73. package/src/core/geom/vec3/v3_distance_array.js +19 -0
  74. package/src/core/geom/vec3/v3_normalize_array_checked.d.ts +23 -0
  75. package/src/core/geom/vec3/v3_normalize_array_checked.d.ts.map +1 -0
  76. package/src/core/geom/vec3/v3_normalize_array_checked.js +49 -0
  77. package/src/core/geom/vec3/v3_reject_array.d.ts +15 -0
  78. package/src/core/geom/vec3/v3_reject_array.d.ts.map +1 -0
  79. package/src/core/geom/vec3/v3_reject_array.js +32 -0
  80. package/src/core/graph/csr/csr_build_incidence.d.ts +26 -0
  81. package/src/core/graph/csr/csr_build_incidence.d.ts.map +1 -0
  82. package/src/core/graph/csr/csr_build_incidence.js +71 -0
  83. package/src/core/graph/csr/csr_graph_color_greedy.d.ts +25 -0
  84. package/src/core/graph/csr/csr_graph_color_greedy.d.ts.map +1 -0
  85. package/src/core/graph/csr/csr_graph_color_greedy.js +83 -0
  86. package/src/core/graph/csr/csr_graph_validate_coloring.d.ts +15 -0
  87. package/src/core/graph/csr/csr_graph_validate_coloring.d.ts.map +1 -0
  88. package/src/core/graph/csr/csr_graph_validate_coloring.js +33 -0
  89. package/src/core/math/hash/XXH128Hash.d.ts +38 -0
  90. package/src/core/math/hash/XXH128Hash.d.ts.map +1 -0
  91. package/src/core/math/hash/XXH128Hash.js +55 -0
  92. package/src/core/math/hash/XXH3_SECRET.d.ts +13 -0
  93. package/src/core/math/hash/XXH3_SECRET.d.ts.map +1 -0
  94. package/src/core/math/hash/XXH3_SECRET.js +25 -0
  95. package/src/core/math/hash/crc32.d.ts +16 -0
  96. package/src/core/math/hash/crc32.d.ts.map +1 -0
  97. package/src/core/math/hash/crc32.js +96 -0
  98. package/src/core/math/hash/xxh3_128.d.ts +10 -0
  99. package/src/core/math/hash/xxh3_128.d.ts.map +1 -0
  100. package/src/core/math/hash/xxh3_128.js +341 -0
  101. package/src/core/math/hash/xxh3_64.d.ts +9 -0
  102. package/src/core/math/hash/xxh3_64.d.ts.map +1 -0
  103. package/src/core/math/hash/xxh3_64.js +241 -0
  104. package/src/core/math/hash/xxh3_common.d.ts +224 -0
  105. package/src/core/math/hash/xxh3_common.d.ts.map +1 -0
  106. package/src/core/math/hash/xxh3_common.js +476 -0
  107. package/src/core/math/linalg/matrix_symmetric_3x3_solve_ldlt.d.ts +26 -0
  108. package/src/core/math/linalg/matrix_symmetric_3x3_solve_ldlt.d.ts.map +1 -0
  109. package/src/core/math/linalg/matrix_symmetric_3x3_solve_ldlt.js +71 -0
  110. package/src/core/math/lookup/ParameterLookupTable.js +2 -2
  111. package/src/core/math/max2_exact.d.ts +15 -0
  112. package/src/core/math/max2_exact.d.ts.map +1 -0
  113. package/src/core/math/max2_exact.js +30 -0
  114. package/src/core/math/min2_exact.d.ts +20 -0
  115. package/src/core/math/min2_exact.d.ts.map +1 -0
  116. package/src/core/math/min2_exact.js +35 -0
  117. package/src/core/model/node-graph/node/NodeInstancePortReference.js +2 -2
  118. package/src/core/model/reactive/model/ReactiveBinaryExpression.js +2 -2
  119. package/src/core/model/reactive/model/terminal/ReactiveReference.js +2 -2
  120. package/src/engine/asset/AssetDescription.js +2 -2
  121. package/src/engine/ecs/animation/Animation.js +2 -2
  122. package/src/engine/ecs/animation/AnimationClip.d.ts.map +1 -1
  123. package/src/engine/ecs/animation/AnimationClip.js +7 -5
  124. package/src/engine/ecs/gui/GUIElement.d.ts.map +1 -1
  125. package/src/engine/ecs/gui/GUIElement.js +7 -5
  126. package/src/engine/ecs/gui/hud/HeadsUpDisplay.js +2 -2
  127. package/src/engine/ecs/gui/position/ViewportPosition.d.ts.map +1 -1
  128. package/src/engine/ecs/gui/position/ViewportPosition.js +11 -7
  129. package/src/engine/ecs/ik/IKGoalSystem.d.ts.map +1 -1
  130. package/src/engine/ecs/ik/IKGoalSystem.js +3 -19
  131. package/src/engine/ecs/parent/parent_entity_model_of.d.ts +17 -0
  132. package/src/engine/ecs/parent/parent_entity_model_of.d.ts.map +1 -0
  133. package/src/engine/ecs/parent/parent_entity_model_of.js +26 -0
  134. package/src/engine/ecs/transform/Transform64.d.ts +1 -1
  135. package/src/engine/ecs/transform/Transform64.d.ts.map +1 -1
  136. package/src/engine/ecs/transform/Transform64.js +5 -4
  137. package/src/engine/ecs/transform/t64_read_pose_array.d.ts +15 -0
  138. package/src/engine/ecs/transform/t64_read_pose_array.d.ts.map +1 -0
  139. package/src/engine/ecs/transform/t64_read_pose_array.js +24 -0
  140. package/src/engine/graphics/ecs/animation/animator/AnimationClip.d.ts.map +1 -1
  141. package/src/engine/graphics/ecs/animation/animator/AnimationClip.js +8 -5
  142. package/src/engine/graphics/ecs/animation/animator/AnimationClipDefinition.js +2 -2
  143. package/src/engine/graphics/ecs/animation/animator/AnimationNotification.js +2 -2
  144. package/src/engine/graphics/ecs/animation/animator/AnimationNotificationDefinition.js +2 -2
  145. package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationGraphDefinition.js +2 -2
  146. package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationStateDefinition.js +2 -2
  147. package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationTransitionDefinition.d.ts.map +1 -1
  148. package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationTransitionDefinition.js +8 -5
  149. package/src/engine/graphics/ecs/decal/v2/Decal.d.ts.map +1 -1
  150. package/src/engine/graphics/ecs/decal/v2/Decal.js +9 -8
  151. package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.d.ts +2 -0
  152. package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.d.ts.map +1 -1
  153. package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.js +10 -21
  154. package/src/engine/graphics/render/frame_graph/resource/TextureResourceDescriptor.d.ts.map +1 -1
  155. package/src/engine/graphics/render/frame_graph/resource/TextureResourceDescriptor.js +9 -6
  156. package/src/engine/graphics3/AnimationGraphSystem.d.ts +5 -0
  157. package/src/engine/graphics3/AnimationGraphSystem.d.ts.map +1 -1
  158. package/src/engine/graphics3/AnimationGraphSystem.js +48 -2
  159. package/src/engine/graphics3/AnimationSystem.d.ts +5 -0
  160. package/src/engine/graphics3/AnimationSystem.d.ts.map +1 -1
  161. package/src/engine/graphics3/AnimationSystem.js +47 -2
  162. package/src/engine/graphics3/ParticipatingMedia.js +204 -204
  163. package/src/engine/graphics3/animation/AnimationClips.d.ts +5 -0
  164. package/src/engine/graphics3/animation/AnimationClips.d.ts.map +1 -1
  165. package/src/engine/graphics3/animation/AnimationClips.js +5 -0
  166. package/src/engine/graphics3/register_clips.d.ts +29 -0
  167. package/src/engine/graphics3/register_clips.d.ts.map +1 -1
  168. package/src/engine/graphics3/register_clips.js +52 -0
  169. package/src/engine/grid/obstacle/GridObstacle.js +2 -2
  170. package/src/engine/intelligence/behavior/selector/WeightedElement.js +2 -2
  171. package/src/engine/interpolation/Interpolated.js +2 -2
  172. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts +9 -0
  173. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts.map +1 -1
  174. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +3 -1
  175. package/src/engine/physics/cloth/PLAN.md +10 -8
  176. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts +22 -0
  177. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts.map +1 -1
  178. package/src/engine/physics/cloth/build/cloth_bind_in_frame.js +51 -19
  179. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  180. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +16 -2
  181. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts.map +1 -1
  182. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.js +19 -24
  183. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +7 -0
  184. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
  185. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +85 -67
  186. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts.map +1 -1
  187. package/src/engine/physics/cloth/collider/cloth_collider_bounds.js +19 -101
  188. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts +2 -5
  189. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts.map +1 -1
  190. package/src/engine/physics/cloth/collider/cloth_collider_pack.js +7 -15
  191. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts.map +1 -1
  192. package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +16 -61
  193. package/src/engine/physics/cloth/ecs/Cloth.d.ts.map +1 -1
  194. package/src/engine/physics/cloth/ecs/Cloth.js +7 -5
  195. package/src/engine/physics/cloth/ecs/ClothCollider.d.ts.map +1 -1
  196. package/src/engine/physics/cloth/ecs/ClothCollider.js +7 -5
  197. package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts +0 -1
  198. package/src/engine/physics/cloth/ecs/ClothColliderFlags.js +6 -19
  199. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +1 -2
  200. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -1
  201. package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +3 -12
  202. package/src/engine/physics/cloth/ecs/ClothDynamics.d.ts.map +1 -1
  203. package/src/engine/physics/cloth/ecs/ClothDynamics.js +20 -11
  204. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  205. package/src/engine/physics/cloth/ecs/ClothWorld.js +40 -130
  206. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  207. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +17 -58
  208. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  209. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +3 -3
  210. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
  211. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +44 -104
  212. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts.map +1 -1
  213. package/src/engine/physics/cloth/ecs/cloth_geodesic.js +6 -13
  214. package/src/engine/physics/cloth/ecs/cloth_holds.d.ts.map +1 -1
  215. package/src/engine/physics/cloth/ecs/cloth_holds.js +15 -40
  216. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -1
  217. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +45 -79
  218. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  219. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +7 -27
  220. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  221. package/src/engine/physics/cloth/ecs/cloth_write_back.js +30 -62
  222. package/src/engine/physics/cloth/playground/cloth_playground_build.d.ts.map +1 -1
  223. package/src/engine/physics/cloth/playground/cloth_playground_build.js +2 -3
  224. package/src/engine/physics/cloth/playground/collide_main.js +2 -28
  225. package/src/engine/physics/cloth/playground/garment_main.js +4 -19
  226. package/src/engine/physics/cloth/playground/main.js +6 -48
  227. package/src/engine/physics/cloth/playground/rig_main.js +947 -955
  228. package/src/engine/physics/cloth/playground/wind_main.js +8 -7
  229. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  230. package/src/engine/physics/cloth/solver/ClothState.js +16 -76
  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.map +1 -1
  235. package/src/engine/physics/cloth/solver/cloth_contact_find.js +3 -2
  236. package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts.map +1 -1
  237. package/src/engine/physics/cloth/solver/cloth_hold_line.js +2 -14
  238. package/src/engine/physics/cloth/solver/cloth_kinetic_energy.d.ts +21 -0
  239. package/src/engine/physics/cloth/solver/cloth_kinetic_energy.d.ts.map +1 -0
  240. package/src/engine/physics/cloth/solver/cloth_kinetic_energy.js +45 -0
  241. package/src/engine/physics/cloth/solver/cloth_particle_coupling.d.ts +32 -0
  242. package/src/engine/physics/cloth/solver/cloth_particle_coupling.d.ts.map +1 -0
  243. package/src/engine/physics/cloth/solver/cloth_particle_coupling.js +133 -0
  244. package/src/engine/physics/cloth/solver/cloth_particle_of_source.d.ts +16 -0
  245. package/src/engine/physics/cloth/solver/cloth_particle_of_source.d.ts.map +1 -0
  246. package/src/engine/physics/cloth/solver/cloth_particle_of_source.js +19 -0
  247. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -1
  248. package/src/engine/physics/cloth/solver/cloth_self_find.js +6 -55
  249. package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts.map +1 -1
  250. package/src/engine/physics/cloth/solver/cloth_solve_vertex.js +30 -65
  251. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  252. package/src/engine/physics/cloth/solver/cloth_step.js +6 -28
  253. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -1
  254. package/src/engine/physics/cloth/solver/cloth_step_instance.js +2 -3
  255. package/src/engine/physics/cloth/solver/cloth_stretch_residual.d.ts +21 -0
  256. package/src/engine/physics/cloth/solver/cloth_stretch_residual.d.ts.map +1 -0
  257. package/src/engine/physics/cloth/solver/cloth_stretch_residual.js +54 -0
  258. package/src/engine/physics/cloth/solver/cloth_vertex_accumulator.d.ts +15 -0
  259. package/src/engine/physics/cloth/solver/cloth_vertex_accumulator.d.ts.map +1 -1
  260. package/src/engine/physics/cloth/solver/cloth_vertex_accumulator.js +28 -0
  261. package/src/engine/physics/cloth/solver/cloth_worst_tether_ratio.d.ts +30 -0
  262. package/src/engine/physics/cloth/solver/cloth_worst_tether_ratio.d.ts.map +1 -0
  263. package/src/engine/physics/cloth/solver/cloth_worst_tether_ratio.js +56 -0
  264. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts.map +1 -1
  265. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.js +3 -17
  266. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts +2 -1
  267. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -1
  268. package/src/engine/physics/cloth/wind/ClothFluidWind.js +7 -25
  269. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +3 -1
  270. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
  271. package/src/engine/physics/cloth/wind/cloth_sample_air.js +40 -62
  272. package/src/engine/physics/ecs/ContactProbeSystem.d.ts.map +1 -1
  273. package/src/engine/physics/ecs/ContactProbeSystem.js +2 -18
  274. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  275. package/src/engine/physics/ecs/PhysicsSystem.js +9 -50
  276. package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
  277. package/src/engine/physics/fluid/FluidField.js +7 -5
  278. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -1
  279. package/src/engine/physics/fluid/ecs/FluidComponent.js +19 -11
  280. package/src/engine/physics/fluid/ecs/fluid_sample_domain_bounds.d.ts +24 -0
  281. package/src/engine/physics/fluid/ecs/fluid_sample_domain_bounds.d.ts.map +1 -0
  282. package/src/engine/physics/fluid/ecs/fluid_sample_domain_bounds.js +42 -0
  283. package/src/engine/physics/fluid/ecs/fluid_sample_velocity_world_mps.d.ts +25 -0
  284. package/src/engine/physics/fluid/ecs/fluid_sample_velocity_world_mps.d.ts.map +1 -0
  285. package/src/engine/physics/fluid/ecs/fluid_sample_velocity_world_mps.js +40 -0
  286. package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts +2 -2
  287. package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +2 -2
  288. package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts.map +1 -1
  289. package/src/engine/physics/fluid/effector/GlobalFluidEffector.js +11 -7
  290. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.d.ts.map +1 -1
  291. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.js +11 -7
  292. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts.map +1 -1
  293. package/src/engine/physics/fluid/effector/WakeFluidEffector.js +16 -9
  294. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_solve.d.ts.map +1 -1
  295. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_solve.js +40 -90
  296. package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -1
  297. package/src/engine/physics/narrowphase/capsule_contacts.js +3 -5
  298. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts.map +1 -1
  299. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.js +2 -14
  300. package/src/engine/physics/narrowphase/hull_sphere_contact.d.ts.map +1 -1
  301. package/src/engine/physics/narrowphase/hull_sphere_contact.js +2 -5
  302. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  303. package/src/engine/physics/narrowphase/narrowphase_step.js +13 -32
  304. package/src/engine/physics/narrowphase/sphere_box_contact.d.ts.map +1 -1
  305. package/src/engine/physics/narrowphase/sphere_box_contact.js +2 -5
  306. package/src/engine/sound/ecs/audio/AudioEmitter.d.ts.map +1 -1
  307. package/src/engine/sound/ecs/audio/AudioEmitter.js +12 -7
  308. package/src/engine/sound/ecs/trigger/AudioEventTrigger.d.ts.map +1 -1
  309. package/src/engine/sound/ecs/trigger/AudioEventTrigger.js +192 -191
  310. package/src/engine/sound/simulation/core/AcousticMedium.js +2 -2
  311. package/src/engine/sound/simulation/definition/AcousticDirectivity.js +2 -2
  312. package/src/engine/sound/simulation/definition/AcousticMaterial.d.ts.map +1 -1
  313. package/src/engine/sound/simulation/definition/AcousticMaterial.js +11 -7
  314. package/src/engine/sound/sopra/definition/BusDefinition.d.ts.map +1 -1
  315. package/src/engine/sound/sopra/definition/BusDefinition.js +5 -4
  316. package/src/engine/sound/sopra/definition/DuckingRule.d.ts.map +1 -1
  317. package/src/engine/sound/sopra/definition/DuckingRule.js +7 -5
  318. package/src/engine/sound/sopra/definition/EventDescription.d.ts.map +1 -1
  319. package/src/engine/sound/sopra/definition/EventDescription.js +23 -13
  320. package/src/engine/sound/sopra/definition/MixerSnapshot.js +2 -2
  321. package/src/engine/sound/sopra/definition/ParameterDefinition.d.ts.map +1 -1
  322. package/src/engine/sound/sopra/definition/ParameterDefinition.js +7 -5
  323. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +2 -2
  324. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts.map +1 -1
  325. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.js +4 -3
  326. package/src/engine/sound/sopra/definition/clip/ContainerAudioClip.js +2 -2
  327. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.js +3 -3
  328. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts.map +1 -1
  329. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +16 -9
  330. package/src/engine/sound/sopra/definition/clip/SilenceAudioClip.js +2 -2
  331. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +1 -1
  332. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
  333. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.js +2 -2
  334. package/src/engine/sound/sopra/definition/effect/CompressorEffect.d.ts.map +1 -1
  335. package/src/engine/sound/sopra/definition/effect/CompressorEffect.js +7 -5
  336. package/src/engine/sound/sopra/definition/effect/EqEffect.d.ts.map +1 -1
  337. package/src/engine/sound/sopra/definition/effect/EqEffect.js +8 -5
  338. package/src/engine/sound/sopra/definition/effect/ReverbEffect.js +2 -2
  339. package/src/engine/sound/sopra/legacy/SoundEmitter.d.ts.map +1 -1
  340. package/src/engine/sound/sopra/legacy/SoundEmitter.js +357 -352
  341. package/src/engine/sound/sopra/legacy/SoundTrack.d.ts.map +1 -1
  342. package/src/engine/sound/sopra/legacy/SoundTrack.js +281 -278
  343. package/src/format/image/png/PNGReader.js +644 -644
  344. package/src/format/image/png/crc32.d.ts +1 -1
  345. package/src/format/image/png/crc32.js +7 -8
  346. package/src/format/texture/basis/transcode/etc1s_to_astc.d.ts.map +1 -1
  347. package/src/format/texture/basis/transcode/etc1s_to_astc.js +2 -1
  348. package/src/shade/descriptor/binding/BindGroupLayoutDescriptor.js +2 -2
  349. package/src/shade/descriptor/binding/BindGroupLayoutEntry.d.ts.map +1 -1
  350. package/src/shade/descriptor/binding/BindGroupLayoutEntry.js +12 -8
  351. package/src/shade/descriptor/binding/StorageTextureBindingLayout.js +2 -2
  352. package/src/shade/descriptor/binding/TextureBindingLayout.js +2 -2
  353. package/src/shade/descriptor/blend/BlendComponent.js +2 -2
  354. package/src/shade/descriptor/pipeline/PipelineDescriptorBase.js +2 -2
  355. package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.js +2 -2
  356. package/src/shade/descriptor/pipeline/ProgrammableStage.js +2 -2
  357. package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.js +2 -2
  358. package/src/shade/descriptor/pipeline/render/ColorTargetState.js +2 -2
  359. package/src/shade/descriptor/pipeline/render/FragmentState.js +2 -2
  360. package/src/shade/descriptor/pipeline/render/PrimitiveState.js +2 -2
  361. package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.d.ts.map +1 -1
  362. package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.js +8 -5
  363. package/src/shade/descriptor/pipeline/render/VertexAttribute.js +2 -2
  364. package/src/shade/descriptor/texture/SamplerDescriptor.d.ts.map +1 -1
  365. package/src/shade/descriptor/texture/SamplerDescriptor.js +20 -12
  366. package/src/shade/descriptor/texture/TextureDescriptor.d.ts.map +1 -1
  367. package/src/shade/descriptor/texture/TextureDescriptor.js +11 -7
  368. package/src/shade/device/graph/BufferResourceDescriptor.d.ts.map +1 -1
  369. package/src/shade/device/graph/BufferResourceDescriptor.js +196 -193
  370. package/src/shade/device/graph/TextureResourceDescriptor.d.ts.map +1 -1
  371. package/src/shade/device/graph/TextureResourceDescriptor.js +178 -173
  372. package/src/shade/device/timing/profile/sgpt_read_header.js +1 -1
  373. package/src/shade/device/timing/profile/sgpt_read_records.js +1 -1
  374. package/src/shade/device/timing/profile/sgpt_write_header.js +1 -1
  375. package/src/shade/device/timing/profile/sgpt_write_record.js +1 -1
  376. package/src/shade/playground/image_decode_bench/main.js +2 -1
  377. package/src/shade/playground/skinned_blas_refit/diff_traced_against_rasterized.d.ts.map +1 -1
  378. package/src/shade/playground/skinned_blas_refit/diff_traced_against_rasterized.js +2 -1
  379. package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts.map +1 -1
  380. package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.js +2 -1
  381. package/src/shade/playground/ssr_variance/statistics.d.ts.map +1 -1
  382. package/src/shade/playground/ssr_variance/statistics.js +2 -1
  383. package/src/shade/playground/texture_encode/main.d.ts.map +1 -1
  384. package/src/shade/playground/texture_encode/main.js +2 -1
  385. package/src/shade/playground/volumetrics_froxel/measure.d.ts.map +1 -1
  386. package/src/shade/playground/volumetrics_froxel/measure.js +2 -1
  387. package/src/shade/renderer/binding/BufferBinding.js +2 -2
  388. package/src/shade/renderer/buffer/table/gpu_database_check_links.d.ts.map +1 -1
  389. package/src/shade/renderer/buffer/table/gpu_database_check_links.js +2 -1
  390. package/src/shade/renderer/camera/Camera.js +2 -2
  391. package/src/shade/renderer/geometry/Attribute.js +2 -2
  392. package/src/shade/renderer/geometry/Geometry.js +2 -2
  393. package/src/shade/renderer/geometry/geometry_deduplicate_vertices.js +2 -2
  394. package/src/shade/renderer/geometry/meshlet/MeshletBatch.js +2 -2
  395. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.d.ts.map +1 -1
  396. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +3 -2
  397. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.d.ts.map +1 -1
  398. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.js +2 -1
  399. package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.d.ts.map +1 -1
  400. package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.js +2 -1
  401. package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.d.ts.map +1 -1
  402. package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.js +2 -1
  403. package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.d.ts.map +1 -1
  404. package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.js +3 -2
  405. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_graph_components.d.ts.map +1 -1
  406. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_graph_components.js +2 -1
  407. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.d.ts.map +1 -1
  408. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.js +2 -1
  409. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_asset_id.js +13 -13
  410. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_directory_block_checksum.js +41 -41
  411. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_frame_checksum.js +41 -41
  412. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_header_checksum.js +25 -25
  413. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  414. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +3 -2
  415. package/src/shade/renderer/material/StandardShadeMaterial.d.ts.map +1 -1
  416. package/src/shade/renderer/material/StandardShadeMaterial.js +13 -8
  417. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.d.ts.map +1 -1
  418. package/src/shade/renderer/particles/optimizer/dag/particle_vector_extract.js +3 -2
  419. package/src/shade/renderer/scene/optimization/geometry/internal/triangle_fingerprint_stream.d.ts.map +1 -1
  420. package/src/shade/renderer/scene/optimization/geometry/internal/triangle_fingerprint_stream.js +14 -5
  421. package/src/shade/renderer/scene/optimization/sampler2d_from_image_bitmap.js +1 -1
  422. package/src/shade/renderer/shader/type/WGSLStructField.js +2 -2
  423. package/src/shade/renderer/shader/type/WebGPUArray.js +2 -2
  424. package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
  425. package/src/shade/renderer/shader/type/WebGPUStruct.js +9 -6
  426. package/src/shade/renderer/texture/ShadeTexture.d.ts.map +1 -1
  427. package/src/shade/renderer/texture/ShadeTexture.js +17 -10
  428. package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +2 -2
  429. package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts +4 -4
  430. package/src/shade/renderer/water/surface/chunk_water_surface_sample.js +6 -6
  431. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -1
  432. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +46 -55
  433. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts +3 -3
  434. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts.map +1 -1
  435. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.js +14 -4
  436. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts +10 -1
  437. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts.map +1 -1
  438. package/src/shade/renderer/water/surface/particles/chunk_water_particle.js +82 -40
  439. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts +4 -1
  440. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts.map +1 -1
  441. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.js +8 -4
  442. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts +98 -86
  443. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts.map +1 -1
  444. package/src/shade/renderer/water/surface/particles/shader_water_particles.js +440 -298
  445. package/src/view/common/HTMLElementCacheKey.d.ts.map +1 -1
  446. package/src/view/common/HTMLElementCacheKey.js +4 -3
  447. package/src/view/minimap/MinimapMarker.js +2 -2
@@ -270,7 +270,7 @@ export class ClothCollider {
270
270
  friction_scale = 1; // multiplies the entity's Collider#friction
271
271
  layer = 1; // RigidBody semantics, and see below
272
272
  mask = 0xFFFFFFFF;
273
- flags = 0; // ClothColliderFlags.Static
273
+ flags = 0; // ClothColliderFlags: none defined; bit 0 was Static, retired
274
274
  }
275
275
  ```
276
276
 
@@ -675,10 +675,12 @@ bundles — the engine ships raw source, and a check moved out of `assert.*` sto
675
675
  ### 5.4 Colouring
676
676
 
677
677
  The particle graph is coloured so no constraint touches two particles of the same colour, using the
678
- existing `core/graph/coloring/colorizeGraphGreedy.js` and checked by the existing
679
- `validateGraphColoring.js`. Bending stencils span four particles, so the graph is the mesh graph plus
680
- the bend diagonals — around 8–10 colours for typical garment topology. Colouring runs once, on a
681
- `Graph` object, and is baked into the `ClothProxy` as colour ranges over a permuted particle order;
678
+ greedy colouring in `core/graph/csr/csr_graph_color_greedy.js` and checked by
679
+ `csr_graph_validate_coloring.js`, over the deduplicated particle-coupling CSR that
680
+ `solver/cloth_particle_coupling.js` builds (the object `Graph` route was O(n²·degree): 134 ms → 3.5 ms
681
+ on a 64×64 sheet, same colours). Bending stencils span four particles, so the graph is the mesh graph plus
682
+ the bend diagonals — around 8–10 colours for typical garment topology. Colouring runs once, on that
683
+ CSR, and is baked into the `ClothProxy` as colour ranges over a permuted particle order;
682
684
  for a chain it runs at link time on a graph of a few dozen nodes. Nothing colours per step and the
683
685
  runtime never sees a graph object.
684
686
 
@@ -1620,7 +1622,7 @@ For a **rigged** garment, only steps 5–8 run, over the joint graph rather than
1620
1622
  (`cloth_rig.spec.js`).
1621
1623
  6. Bake `d_geo` — geodesic distance from every particle to the fixed set. This one array drives the
1622
1624
  tether row, the slack profile, and the pinning, so the three cannot disagree.
1623
- 7. Colour the particle graph (`colorizeGraphGreedy`, checked by `validateGraphColoring`), and permute
1625
+ 7. Colour the particle graph (`csr_graph_color_greedy`, checked by `csr_graph_validate_coloring`), and permute
1624
1626
  the particle order so each colour is a contiguous range.
1625
1627
  8. Resolve joint **names to indices** into `Skin#joints`, using `SceneBundleInstance#nodes`. This is
1626
1628
  the only place a name appears anywhere in the system.
@@ -1803,9 +1805,9 @@ What this design takes from the engine rather than building:
1803
1805
  | Mesh topology, adjacency, bending stencils | `core/geom/3d/topology/struct/binary/` — `BinaryTopology`, `bt_edge_read_diamond`, `bt_edge_is_boundary`, `bt_collect_boundary_segments` |
1804
1806
  | Proxy decimation | `bt_mesh_simplify_by_error`, `bt_mesh_compute_vertex_quadrics` |
1805
1807
  | Mesh cleanup | `geometry_deduplicate_vertices` |
1806
- | Graph colouring | `core/graph/coloring/colorizeGraphGreedy.js`, `validateGraphColoring.js` |
1808
+ | Graph colouring | `core/graph/csr/csr_graph_color_greedy.js`, `csr_graph_validate_coloring.js` |
1807
1809
  | Collider shapes and their SDFs | `core/geom/3d/shape/*` — closed-form `signed_distance_at_point` on every primitive |
1808
- | Collider AABBs, pose caching | `core/geom/3d/aabb/*`, `aabb3_matrix4_project` |
1810
+ | Collider AABBs, pose caching | `core/geom/3d/aabb/*`, `aabb3_transform_oriented_array` |
1809
1811
  | Collider ECS wiring | `Collider`, `ColliderFlags`, `ColliderObserverSystem` (as the pattern) |
1810
1812
  | "Opt a collider into a second simulation" | `FluidObstacle` + `FluidObstacleSystem`, `AcousticBody` |
1811
1813
  | Collider index shape | `AcousticOccluderIndex` + `OccluderBody` |
@@ -10,6 +10,12 @@
10
10
  * bind pose — so that a re-seed reads what was authored rather than what the
11
11
  * solver left on the joints.
12
12
  *
13
+ * Rigid, as every pose cloth holds is: a local scale is not applied. That is
14
+ * not a convention this can opt out of alone — the write-back is rigid too,
15
+ * and the GPU applies a parent's scale on top of what cloth writes, so a
16
+ * scaled bake would draw a scaled link twice over. A builder refuses a rig
17
+ * where it would matter, with {@link cloth_bind_scaled_above}.
18
+ *
13
19
  * @author Alex Goldring
14
20
  * @copyright Company Named Limited (c) 2026
15
21
  *
@@ -18,5 +24,21 @@
18
24
  * @returns {function(number): Float64Array}
19
25
  */
20
26
  export function cloth_bind_in_frame(prefab: Prefab, frame: number): (arg0: number) => Float64Array;
27
+ /**
28
+ * The nearest node above `node`, up to and including the prefab's root, whose
29
+ * rest scale is not one; or -1.
30
+ *
31
+ * Cloth simulates and writes back rigid poses, and everything under a scaled
32
+ * node is drawn scaled: a link below one is simulated at its authored length and
33
+ * drawn at that times the scale, and a scale above the frame draws the whole
34
+ * garment at another size than the one its colliders meet. Measured, a 10 cm
35
+ * chain under a joint scaled by 2: simulated links 0.1, drawn 0.2. A node's own
36
+ * scale moves nothing cloth places, so it is not asked about.
37
+ *
38
+ * @param {Prefab} prefab
39
+ * @param {number} node
40
+ * @returns {number}
41
+ */
42
+ export function cloth_bind_scaled_above(prefab: Prefab, node: number): number;
21
43
  export type Prefab = import("../../../graphics3/prefab/Prefab.js").Prefab;
22
44
  //# sourceMappingURL=cloth_bind_in_frame.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cloth_bind_in_frame.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/build/cloth_bind_in_frame.js"],"names":[],"mappings":"AAOA;;GAEG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,4CAJW,MAAM,SACN,MAAM,UACK,MAAM,KAAG,YAAY,CAiD1C;qBAlEY,OAAO,qCAAqC,EAAE,MAAM"}
1
+ {"version":3,"file":"cloth_bind_in_frame.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/build/cloth_bind_in_frame.js"],"names":[],"mappings":"AAOA;;GAEG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,4CAJW,MAAM,SACN,MAAM,UACK,MAAM,KAAG,YAAY,CAqC1C;AASD;;;;;;;;;;;;;;GAcG;AACH,gDAJW,MAAM,QACN,MAAM,GACJ,MAAM,CAgBlB;qBAlGY,OAAO,qCAAqC,EAAE,MAAM"}
@@ -1,7 +1,7 @@
1
- import { quat3_multiply } from "../../../../core/geom/3d/quaternion/quat3_multiply.js";
2
- import { v3_quaternion_apply } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
1
+ import { pose3_compose_array } from "../../../../core/geom/3d/pose/pose3_compose_array.js";
3
2
  import {
4
3
  TRANSFORM64_ROTATION_OFFSET,
4
+ TRANSFORM64_SCALE_OFFSET,
5
5
  TRANSFORM64_TRANSLATION_OFFSET
6
6
  } from "../../../ecs/transform/Transform64.js";
7
7
 
@@ -18,6 +18,12 @@ import {
18
18
  * bind pose — so that a re-seed reads what was authored rather than what the
19
19
  * solver left on the joints.
20
20
  *
21
+ * Rigid, as every pose cloth holds is: a local scale is not applied. That is
22
+ * not a convention this can opt out of alone — the write-back is rigid too,
23
+ * and the GPU applies a parent's scale on top of what cloth writes, so a
24
+ * scaled bake would draw a scaled link twice over. A builder refuses a rig
25
+ * where it would matter, with {@link cloth_bind_scaled_above}.
26
+ *
21
27
  * @author Alex Goldring
22
28
  * @copyright Company Named Limited (c) 2026
23
29
  *
@@ -45,25 +51,13 @@ export function cloth_bind_in_frame(prefab, frame) {
45
51
 
46
52
  answer = new Float64Array(7);
47
53
 
48
- v3_quaternion_apply(
54
+ pose3_compose_array(
49
55
  answer, 0,
50
- local[TRANSFORM64_TRANSLATION_OFFSET],
51
- local[TRANSFORM64_TRANSLATION_OFFSET + 1],
52
- local[TRANSFORM64_TRANSLATION_OFFSET + 2],
53
- above[3], above[4], above[5], above[6]
54
- );
55
-
56
- answer[0] += above[0];
57
- answer[1] += above[1];
58
- answer[2] += above[2];
59
-
60
- quat3_multiply(
61
56
  answer, 3,
62
- above[3], above[4], above[5], above[6],
63
- local[TRANSFORM64_ROTATION_OFFSET],
64
- local[TRANSFORM64_ROTATION_OFFSET + 1],
65
- local[TRANSFORM64_ROTATION_OFFSET + 2],
66
- local[TRANSFORM64_ROTATION_OFFSET + 3]
57
+ above, 0,
58
+ above, 3,
59
+ local, TRANSFORM64_TRANSLATION_OFFSET,
60
+ local, TRANSFORM64_ROTATION_OFFSET
67
61
  );
68
62
 
69
63
  known.set(node, answer);
@@ -73,3 +67,41 @@ export function cloth_bind_in_frame(prefab, frame) {
73
67
 
74
68
  return pose;
75
69
  }
70
+
71
+ /**
72
+ * How far a rest scale may be from one before it is a scale: the tolerance
73
+ * `prefab_normalize_skin_frames` holds a skin's frame to, for the same reason.
74
+ * @type {number}
75
+ */
76
+ const SCALE_TOLERANCE = 1e-4;
77
+
78
+ /**
79
+ * The nearest node above `node`, up to and including the prefab's root, whose
80
+ * rest scale is not one; or -1.
81
+ *
82
+ * Cloth simulates and writes back rigid poses, and everything under a scaled
83
+ * node is drawn scaled: a link below one is simulated at its authored length and
84
+ * drawn at that times the scale, and a scale above the frame draws the whole
85
+ * garment at another size than the one its colliders meet. Measured, a 10 cm
86
+ * chain under a joint scaled by 2: simulated links 0.1, drawn 0.2. A node's own
87
+ * scale moves nothing cloth places, so it is not asked about.
88
+ *
89
+ * @param {Prefab} prefab
90
+ * @param {number} node
91
+ * @returns {number}
92
+ */
93
+ export function cloth_bind_scaled_above(prefab, node) {
94
+ const parent = prefab.parent;
95
+
96
+ for (let above = parent[node]; above >= 0; above = parent[above]) {
97
+ const local = prefab.local[above];
98
+
99
+ if (Math.abs(local[TRANSFORM64_SCALE_OFFSET] - 1) > SCALE_TOLERANCE
100
+ || Math.abs(local[TRANSFORM64_SCALE_OFFSET + 1] - 1) > SCALE_TOLERANCE
101
+ || Math.abs(local[TRANSFORM64_SCALE_OFFSET + 2] - 1) > SCALE_TOLERANCE) {
102
+ return above;
103
+ }
104
+ }
105
+
106
+ return -1;
107
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"cloth_proxy_from_joints.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/build/cloth_proxy_from_joints.js"],"names":[],"mappings":"AAGA;;;GAGG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH;;;;;GAKG;AAEH;;;;;GAKG;AAEH;;;;;;;;;;;;;;GAcG;AACH,gDARW,MAAM,QACN,IAAI,eAEJ,MAAM,EAAE;IAES,IAAI,GAArB,MAAM;IACJ,qBAAqB,CAgQjC;qBAjUY,OAAO,qCAAqC,EAAE,MAAM;mBACpD,OAAO,8CAA8C,EAAE,IAAI;;;;;;;;WAwC1D,MAAM;;;;eACN,UAAU;;;;;;WAKV,UAAU,GAAC,IAAI;;;;YACf,eAAe,EAAE;;;;WACjB,MAAM;;2BArDO,iBAAiB"}
1
+ {"version":3,"file":"cloth_proxy_from_joints.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/build/cloth_proxy_from_joints.js"],"names":[],"mappings":"AAIA;;;GAGG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH;;;;;GAKG;AAEH;;;;;GAKG;AAEH;;;;;;;;;;;;;;GAcG;AACH,gDARW,MAAM,QACN,IAAI,eAEJ,MAAM,EAAE;IAES,IAAI,GAArB,MAAM;IACJ,qBAAqB,CA6QjC;qBA9UY,OAAO,qCAAqC,EAAE,MAAM;mBACpD,OAAO,8CAA8C,EAAE,IAAI;;;;;;;;WAwC1D,MAAM;;;;eACN,UAAU;;;;;;WAKV,UAAU,GAAC,IAAI;;;;YACf,eAAe,EAAE;;;;WACjB,MAAM;;2BAtDO,iBAAiB"}
@@ -1,5 +1,6 @@
1
1
  import { ClothProxy } from "./ClothProxy.js";
2
- import { cloth_bind_in_frame } from "./cloth_bind_in_frame.js";
2
+ import { cloth_bind_in_frame, cloth_bind_scaled_above } from "./cloth_bind_in_frame.js";
3
+ import { number_compare_ascending } from "../../../../core/primitives/numbers/number_compare_ascending.js";
3
4
 
4
5
  /**
5
6
  * @typedef {import("../../../graphics3/prefab/Prefab.js").Prefab} Prefab
@@ -161,7 +162,7 @@ export function cloth_proxy_from_joints(prefab, skin, joint_names, { name = "" }
161
162
  }
162
163
  }
163
164
 
164
- hung_from.sort((a, b) => a - b);
165
+ hung_from.sort(number_compare_ascending);
165
166
 
166
167
  // The frame: the nearest skin joint above every bone the garment hangs from
167
168
  // — for one bone, the bone itself.
@@ -236,6 +237,19 @@ export function cloth_proxy_from_joints(prefab, skin, joint_names, { name = "" }
236
237
 
237
238
  const particle_name = [];
238
239
 
240
+ for (let i = 0; i < particle_count; i++) {
241
+ const scaled = cloth_bind_scaled_above(prefab, ordered[i]);
242
+
243
+ if (scaled >= 0) {
244
+ const local = prefab.local[scaled];
245
+
246
+ return refuse(
247
+ `${name}: "${name_of[scaled]}", above "${name_of[ordered[i]]}", is scaled by (${local.scale_x}, ${local.scale_y}, ${local.scale_z}) at rest;`
248
+ + ` cloth poses its joints rigidly, so it would simulate a different garment from the one drawn`
249
+ );
250
+ }
251
+ }
252
+
239
253
  const pose = cloth_bind_in_frame(prefab, frame_node);
240
254
 
241
255
  for (let i = 0; i < particle_count; i++) {
@@ -1 +1 @@
1
- {"version":3,"file":"cloth_proxy_from_mesh.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/build/cloth_proxy_from_mesh.js"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH;;;;;;;;;;GAUG;AACH,8CARW,MAAM,QACN,IAAI,eACJ,MAAM,EAAE,aACR,UAAU,GAAC,MAAM,EAAE;IAEF,IAAI,GAArB,MAAM;IACJ,qBAAqB,CA8LjC;qBApPY,OAAO,qCAAqC,EAAE,MAAM;mBACpD,OAAO,8CAA8C,EAAE,IAAI;oCAC3D,OAAO,8BAA8B,EAAE,qBAAqB"}
1
+ {"version":3,"file":"cloth_proxy_from_mesh.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/build/cloth_proxy_from_mesh.js"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH;;;;;;;;;;GAUG;AACH,8CARW,MAAM,QACN,IAAI,eACJ,MAAM,EAAE,aACR,UAAU,GAAC,MAAM,EAAE;IAEF,IAAI,GAArB,MAAM;IACJ,qBAAqB,CA8MjC;qBApQY,OAAO,qCAAqC,EAAE,MAAM;mBACpD,OAAO,8CAA8C,EAAE,IAAI;oCAC3D,OAAO,8BAA8B,EAAE,qBAAqB"}
@@ -1,5 +1,6 @@
1
+ import { tri3_area } from "../../../../core/geom/3d/triangle/tri3_area.js";
1
2
  import { ClothProxy } from "./ClothProxy.js";
2
- import { cloth_bind_in_frame } from "./cloth_bind_in_frame.js";
3
+ import { cloth_bind_in_frame, cloth_bind_scaled_above } from "./cloth_bind_in_frame.js";
3
4
 
4
5
  /**
5
6
  * @typedef {import("../../../graphics3/prefab/Prefab.js").Prefab} Prefab
@@ -140,6 +141,18 @@ export function cloth_proxy_from_mesh(prefab, skin, joint_names, triangles, { na
140
141
  return refuse(`${name}: ${triangles.length} triangle indices is not a whole number of triangles`);
141
142
  }
142
143
 
144
+ // Every vertex joint hangs from the frame, so one walk up from any of them asks the lot.
145
+ const scaled = cloth_bind_scaled_above(prefab, node[0]);
146
+
147
+ if (scaled >= 0) {
148
+ const local = prefab.local[scaled];
149
+
150
+ return refuse(
151
+ `${name}: "${name_of[scaled]}", above "${name_of[node[0]]}", is scaled by (${local.scale_x}, ${local.scale_y}, ${local.scale_z}) at rest;`
152
+ + ` cloth poses its joints rigidly, so it would simulate a different garment from the one drawn`
153
+ );
154
+ }
155
+
143
156
  const pose = cloth_bind_in_frame(prefab, frame_node);
144
157
 
145
158
  const rest_position = new Float32Array(particle_count * 3);
@@ -176,7 +189,11 @@ export function cloth_proxy_from_mesh(prefab, skin, joint_names, triangles, { na
176
189
  }
177
190
  }
178
191
 
179
- if (twice_area(rest_position, i0, i1, i2) <= 0) {
192
+ if (tri3_area(
193
+ rest_position[i0 * 3], rest_position[i0 * 3 + 1], rest_position[i0 * 3 + 2],
194
+ rest_position[i1 * 3], rest_position[i1 * 3 + 1], rest_position[i1 * 3 + 2],
195
+ rest_position[i2 * 3], rest_position[i2 * 3 + 1], rest_position[i2 * 3 + 2]
196
+ ) <= 0) {
180
197
  return refuse(
181
198
  `${name}: triangle ${t} ("${joint_names[i0]}", "${joint_names[i1]}", "${joint_names[i2]}") has no area,`
182
199
  + ` so no normal and no hinge across it`
@@ -248,28 +265,6 @@ export function cloth_proxy_from_mesh(prefab, skin, joint_names, triangles, { na
248
265
  };
249
266
  }
250
267
 
251
- /**
252
- * Twice the area of a triangle of the rest pose.
253
- *
254
- * @param {Float32Array} position
255
- * @param {number} a
256
- * @param {number} b
257
- * @param {number} c
258
- * @returns {number}
259
- * @private
260
- */
261
- function twice_area(position, a, b, c) {
262
- const ux = position[b * 3] - position[a * 3];
263
- const uy = position[b * 3 + 1] - position[a * 3 + 1];
264
- const uz = position[b * 3 + 2] - position[a * 3 + 2];
265
-
266
- const vx = position[c * 3] - position[a * 3];
267
- const vy = position[c * 3 + 1] - position[a * 3 + 1];
268
- const vz = position[c * 3 + 2] - position[a * 3 + 2];
269
-
270
- return Math.hypot(uy * vz - uz * vy, uz * vx - ux * vz, ux * vy - uy * vx);
271
- }
272
-
273
268
  /**
274
269
  * @param {string} error
275
270
  * @returns {ClothProxyBuildResult}
@@ -164,6 +164,13 @@ export class ClothColliderIndex {
164
164
  * ignores it, so a distance in the shape's local frame is a distance in
165
165
  * world space.
166
166
  *
167
+ * A pose equal to the one the record already holds is not refit: its
168
+ * bounds were fit to exactly this pair of poses when either last changed —
169
+ * here, in {@link placePose}, or in {@link advance} — so the refit would
170
+ * write what is there. That is what a collider that never moves costs, and
171
+ * why nothing has to say it will not: 1.43 µs per collider per step
172
+ * refitting, 0.42 µs skipping, of which {@link advance} is 0.32.
173
+ *
167
174
  * @param {number} handle
168
175
  * @param {number} tx
169
176
  * @param {number} ty
@@ -1 +1 @@
1
- {"version":3,"file":"ClothColliderIndex.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/collider/ClothColliderIndex.js"],"names":[],"mappings":"AA2CA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgFG;AACH;IAEI;;;;;;OAMG;IACH,OAFU,YAAY,CAEM;IAE5B;;;;;OAKG;IACH,MAFU,UAAU,CAEK;IAEzB;;;;OAIG;IACH,OAFU,MAAM,CAEN;IAEV;;;;;;OAMG;IACH,eAFU,MAAM,CAEE;IAElB;;;;;;OAMG;IACH,qBAFU,MAAM,CAEQ;IAoFxB;;;;;;;;;;;OAWG;IACH,sCAPW,MAAM,aACN,MAAM,SACN,MAAM,QACN,MAAM,UACN,MAAM,GACJ,MAAM,CA8DlB;IAED;;;;;;;OAOG;IACH,eAHW,MAAM,GACJ,IAAI,CAoChB;IAED;;;;OAIG;IACH,eAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;OAGG;IACH,mBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;;OAIG;IACH,WAFa,IAAI,CAuDhB;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,gBAVW,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,GACJ,IAAI,CA8BhB;IAwID;;;;;;;;;;;;;;;OAeG;IACH,kBAVW,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,GACJ,IAAI,CAmBhB;IAED;;;;;;;;OAQG;IACH,mBALW,MAAM,YACN,MAAM,aACN,MAAM,GACJ,IAAI,CAoBhB;IAED;;;;;OAKG;IACH,kBALW,MAAM,SACN,MAAM,QACN,MAAM,GACJ,IAAI,CAWhB;IAED;;;OAGG;IACH,iBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,WAdW,MAAM,EAAE,SACR,MAAM,SACN,MAAM,SACN,MAAM,SACN,MAAM,SACN,MAAM,SACN,MAAM,SACN,MAAM,QACN,MAAM,YACN,OAAO,GAGL,MAAM,CAWlB;IAED;;;;;;;;;;;OAWG;IACH,gBARW,MAAM,EAAE,OACR,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,cAClC,MAAM,SACN,MAAM,QACN,MAAM,WACN,OAAO,GACL,MAAM,CA6DlB;;CAyGJ"}
1
+ {"version":3,"file":"ClothColliderIndex.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/collider/ClothColliderIndex.js"],"names":[],"mappings":"AAkDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgFG;AACH;IAEI;;;;;;OAMG;IACH,OAFU,YAAY,CAEM;IAE5B;;;;;OAKG;IACH,MAFU,UAAU,CAEK;IAEzB;;;;OAIG;IACH,OAFU,MAAM,CAEN;IAEV;;;;;;OAMG;IACH,eAFU,MAAM,CAEE;IAElB;;;;;;OAMG;IACH,qBAFU,MAAM,CAEQ;IAoFxB;;;;;;;;;;;OAWG;IACH,sCAPW,MAAM,aACN,MAAM,SACN,MAAM,QACN,MAAM,UACN,MAAM,GACJ,MAAM,CA8DlB;IAED;;;;;;;OAOG;IACH,eAHW,MAAM,GACJ,IAAI,CAkChB;IAED;;;;OAIG;IACH,eAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;OAGG;IACH,mBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;;OAIG;IACH,WAFa,IAAI,CA4ChB;IAED;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,gBAVW,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,GACJ,IAAI,CAqBhB;IAsLD;;;;;;;;;;;;;;;OAeG;IACH,kBAVW,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,GACJ,IAAI,CAqBhB;IAED;;;;;;;;OAQG;IACH,mBALW,MAAM,YACN,MAAM,aACN,MAAM,GACJ,IAAI,CAoBhB;IAED;;;;;OAKG;IACH,kBALW,MAAM,SACN,MAAM,QACN,MAAM,GACJ,IAAI,CAWhB;IAED;;;OAGG;IACH,iBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,WAdW,MAAM,EAAE,SACR,MAAM,SACN,MAAM,SACN,MAAM,SACN,MAAM,SACN,MAAM,SACN,MAAM,SACN,MAAM,QACN,MAAM,YACN,OAAO,GAGL,MAAM,CAWlB;IAED;;;;;;;;;;;OAWG;IACH,gBARW,MAAM,EAAE,OACR,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,cAClC,MAAM,SACN,MAAM,QACN,MAAM,WACN,OAAO,GACL,MAAM,CA6DlB;;CAyGJ"}
@@ -1,8 +1,15 @@
1
1
  import { assert } from "../../../../core/assert.js";
2
2
  import { BVH, NULL_NODE } from "../../../../core/bvh2/bvh3/BVH.js";
3
+ import { number_compare_ascending } from "../../../../core/primitives/numbers/number_compare_ascending.js";
3
4
  import {
4
5
  bvh_query_user_data_intersects_aabb
5
6
  } from "../../../../core/bvh2/bvh3/query/bvh_query_user_data_intersects_aabb.js";
7
+ import { array_copy } from "../../../../core/collection/array/array_copy.js";
8
+ import { array_range_equal_strict } from "../../../../core/collection/array/array_range_equal_strict.js";
9
+ import { array_remove_first } from "../../../../core/collection/array/array_remove_first.js";
10
+ import { array_sort_insertion_ascending } from "../../../../core/collection/array/array_sort_insertion_ascending.js";
11
+ import { aabb3_array_round_outward_f32 } from "../../../../core/geom/3d/aabb/aabb3_array_round_outward_f32.js";
12
+ import { FAT_LINEAR } from "../../broadphase/compute_fat_world_aabb.js";
6
13
  import {
7
14
  CCR_AABB_MAX_X,
8
15
  CCR_AABB_MAX_Y,
@@ -341,11 +348,9 @@ export class ClothColliderIndex {
341
348
  const node = this.#node[handle];
342
349
 
343
350
  if (node === NULL_NODE) {
344
- const at = this.#planes.indexOf(handle);
351
+ const planes = this.#planes;
345
352
 
346
- if (at >= 0) {
347
- this.#planes.splice(at, 1);
348
- }
353
+ array_remove_first(planes, handle, 0, planes.length);
349
354
  } else {
350
355
  this.#bvh.remove_leaf(node);
351
356
  this.#bvh.release_node(node);
@@ -419,22 +424,11 @@ export class ClothColliderIndex {
419
424
  this.max_inflation = table[r + CCR_INFLATION];
420
425
  }
421
426
 
422
- const moved = table[r + CCR_PREV_TX] !== table[r + CCR_TX]
423
- || table[r + CCR_PREV_TY] !== table[r + CCR_TY]
424
- || table[r + CCR_PREV_TZ] !== table[r + CCR_TZ]
425
- || table[r + CCR_PREV_QX] !== table[r + CCR_QX]
426
- || table[r + CCR_PREV_QY] !== table[r + CCR_QY]
427
- || table[r + CCR_PREV_QZ] !== table[r + CCR_QZ]
428
- || table[r + CCR_PREV_QW] !== table[r + CCR_QW];
429
-
430
- table[r + CCR_PREV_TX] = table[r + CCR_TX];
431
- table[r + CCR_PREV_TY] = table[r + CCR_TY];
432
- table[r + CCR_PREV_TZ] = table[r + CCR_TZ];
427
+ // A pose is seven contiguous slots, translation then rotation, in
428
+ // both the current and the previous half of the record.
429
+ const moved = !array_range_equal_strict(table, r + CCR_PREV_TX, table, r + CCR_TX, POSE_SLOTS);
433
430
 
434
- table[r + CCR_PREV_QX] = table[r + CCR_QX];
435
- table[r + CCR_PREV_QY] = table[r + CCR_QY];
436
- table[r + CCR_PREV_QZ] = table[r + CCR_QZ];
437
- table[r + CCR_PREV_QW] = table[r + CCR_QW];
431
+ array_copy(table, r + CCR_TX, table, r + CCR_PREV_TX, POSE_SLOTS);
438
432
 
439
433
  if (moved) {
440
434
  cloth_collider_refit_bounds(table, handle, CCR_STRIDE);
@@ -451,6 +445,13 @@ export class ClothColliderIndex {
451
445
  * ignores it, so a distance in the shape's local frame is a distance in
452
446
  * world space.
453
447
  *
448
+ * A pose equal to the one the record already holds is not refit: its
449
+ * bounds were fit to exactly this pair of poses when either last changed —
450
+ * here, in {@link placePose}, or in {@link advance} — so the refit would
451
+ * write what is there. That is what a collider that never moves costs, and
452
+ * why nothing has to say it will not: 1.43 µs per collider per step
453
+ * refitting, 0.42 µs skipping, of which {@link advance} is 0.32.
454
+ *
454
455
  * @param {number} handle
455
456
  * @param {number} tx
456
457
  * @param {number} ty
@@ -471,6 +472,35 @@ export class ClothColliderIndex {
471
472
 
472
473
  const r = handle * CCR_STRIDE;
473
474
 
475
+ if (table[r + CCR_TX] === tx && table[r + CCR_TY] === ty && table[r + CCR_TZ] === tz
476
+ && table[r + CCR_QX] === qx && table[r + CCR_QY] === qy
477
+ && table[r + CCR_QZ] === qz && table[r + CCR_QW] === qw
478
+ // no leaf — never posed, or a plane, which is never in the tree — refits regardless
479
+ && this.#node[handle] !== NULL_NODE) {
480
+ return;
481
+ }
482
+
483
+ this.#pose(handle, tx, ty, tz, qx, qy, qz, qw);
484
+ }
485
+
486
+ /**
487
+ * Write the current pose and refit, unconditionally.
488
+ *
489
+ * @param {number} handle
490
+ * @param {number} tx
491
+ * @param {number} ty
492
+ * @param {number} tz
493
+ * @param {number} qx
494
+ * @param {number} qy
495
+ * @param {number} qz
496
+ * @param {number} qw
497
+ * @private
498
+ */
499
+ #pose(handle, tx, ty, tz, qx, qy, qz, qw) {
500
+ const table = this.table;
501
+
502
+ const r = handle * CCR_STRIDE;
503
+
474
504
  if (table[r + CCR_TX] !== tx || table[r + CCR_TY] !== ty || table[r + CCR_TZ] !== tz
475
505
  || table[r + CCR_QX] !== qx || table[r + CCR_QY] !== qy
476
506
  || table[r + CCR_QZ] !== qz || table[r + CCR_QW] !== qw) {
@@ -561,9 +591,15 @@ export class ClothColliderIndex {
561
591
  if (lower < STORED_AABB[axis] || upper > STORED_AABB[axis + 3]) contained = false;
562
592
  // A one-step outlier must not leave a scene-sized leaf behind once
563
593
  // motion stops. Allow ordinary jitter to keep spending the slack.
594
+ // The yardstick is twice what a store would write now: the slack
595
+ // on both sides plus the outward rounding, which grows each side by
596
+ // under one float32 step of its magnitude. Without that term a leaf
597
+ // far enough out that a step outgrows the slack — past about four
598
+ // hundred kilometres — would read as oversized straight after being
599
+ // stored, and be re-homed every step.
564
600
  if (STORED_AABB[axis + 3] - STORED_AABB[axis]
565
- > 2 * (upper - lower + 2 * BVH_LEAF_SLACK
566
- + (Math.abs(lower) + Math.abs(upper)) * FLOAT32_ROUNDING)) oversized = true;
601
+ > 2 * (upper - lower + 2 * FAT_LINEAR
602
+ + (Math.abs(lower) + Math.abs(upper) + 2 * FAT_LINEAR) * FLOAT32_STEP)) oversized = true;
567
603
  }
568
604
 
569
605
  if (contained && !oversized) {
@@ -589,18 +625,18 @@ export class ClothColliderIndex {
589
625
  * Write a record's swept bounds plus its contact reach into {@link FAT_AABB}
590
626
  * with the slack the refit skip spends, and store them on the leaf.
591
627
  *
592
- * The slack is also what makes the tree's `Float32` nodes safe to hold a
593
- * `Float64` world, and it has two terms because one is not enough. The
594
- * constant covers jitter. The relative term covers the rounding
595
- * {@link BVH#node_set_aabb} does on the way in: a bound can move by an ulp,
596
- * and `Float32`'s ulp is a *proportion* of the magnitude — a millimetre at
597
- * ten kilometres out, but **a whole metre at ten thousand**, which is well
598
- * past the constant: measured, a leaf there comes back 45 cm inside its own
599
- * record. A bound that rounds inward past its slack is a leaf
600
- * smaller than the record it stands for, and that is a collider the tree
601
- * stops answering with — silently, and only far from the origin, which is
602
- * the worst shape a bug can have. Two ulps of the magnitude puts it back
603
- * outside at every scale the `Float64` table is kept for.
628
+ * The slack covers jitter; it does not cover the tree's `Float32` nodes
629
+ * holding a `Float64` world. {@link BVH#node_set_aabb} rounds each bound to
630
+ * the nearest `Float32`, and `Float32`'s step is a *proportion* of the
631
+ * magnitude — a millimetre at ten kilometres out, but **a whole metre at
632
+ * ten thousand**, which is well past any constant: measured, a leaf there
633
+ * fattened by 5 cm came back 45 cm inside its own record. A bound that
634
+ * rounds inward past its slack is a leaf smaller than the record it stands
635
+ * for, and that is a collider the tree stops answering with — silently,
636
+ * and only far from the origin, which is the worst shape a bug can have.
637
+ * So the fattened box is rounded outward to `Float32` before it is stored,
638
+ * which makes the store exact at every scale and leaves the constant to do
639
+ * only its own job.
604
640
  *
605
641
  * The exact test in {@link query} reads the `Float64` record, so the tree
606
642
  * only ever has to avoid a false **negative**; being generous here costs a
@@ -618,10 +654,12 @@ export class ClothColliderIndex {
618
654
  const lower = table[r + CCR_AABB_MIN_X + axis] - reach;
619
655
  const upper = table[r + CCR_AABB_MAX_X + axis] + reach;
620
656
 
621
- FAT_AABB[axis] = lower - BVH_LEAF_SLACK - Math.abs(lower) * FLOAT32_ROUNDING;
622
- FAT_AABB[axis + 3] = upper + BVH_LEAF_SLACK + Math.abs(upper) * FLOAT32_ROUNDING;
657
+ FAT_AABB[axis] = lower - FAT_LINEAR;
658
+ FAT_AABB[axis + 3] = upper + FAT_LINEAR;
623
659
  }
624
660
 
661
+ aabb3_array_round_outward_f32(FAT_AABB, 0, FAT_AABB, 0);
662
+
625
663
  this.#bvh.node_set_aabb(node, FAT_AABB);
626
664
  }
627
665
 
@@ -657,7 +695,9 @@ export class ClothColliderIndex {
657
695
  this.table[r + CCR_PREV_QZ] = qz;
658
696
  this.table[r + CCR_PREV_QW] = qw;
659
697
 
660
- this.setPose(handle, tx, ty, tz, qx, qy, qz, qw);
698
+ // Not {@link setPose}: the previous pose has just changed, so the
699
+ // bounds are stale even when the current one has not.
700
+ this.#pose(handle, tx, ty, tz, qx, qy, qz, qw);
661
701
  }
662
702
 
663
703
  /**
@@ -926,21 +966,19 @@ export class ClothColliderIndex {
926
966
  }
927
967
 
928
968
  /**
929
- * How far past a record's swept bounds its leaf is stored, metres. The same
930
- * constant `compute_fat_world_aabb` spends on a rigid body, and for the same
931
- * reason: a collider jittering inside its own slack must not cost a refit.
969
+ * One `Float32` step as a proportion of a value's magnitude, an upper bound
970
+ * for every normal `Float32`: 23 fraction bits, so a step is at most `2^-23`
971
+ * of the magnitude. The most an outward rounding can widen a bound by.
932
972
  * @type {number}
933
973
  */
934
- const BVH_LEAF_SLACK = 0.05;
974
+ const FLOAT32_STEP = 2 ** -23;
935
975
 
936
976
  /**
937
- * Two `Float32` ulps as a proportion of a value's magnitude — what a bound has
938
- * to be widened by to survive being stored in a `Float32` leaf whatever the
939
- * rounding does. `Float32` carries 23 fraction bits, so one ulp is `2^-23` of
940
- * the magnitude and two is the first multiple that is unconditionally outside.
977
+ * Slots in one pose, `[tx, ty, tz, qx, qy, qz, qw]`: {@link CCR_TX} to {@link CCR_QW}, and the same
978
+ * from {@link CCR_PREV_TX}.
941
979
  * @type {number}
942
980
  */
943
- const FLOAT32_ROUNDING = 2 ** -22;
981
+ const POSE_SLOTS = 7;
944
982
 
945
983
  /**
946
984
  * The box being queried, `[min_x, min_y, min_z, max_x, max_y, max_z]`: what the tree is walked with
@@ -972,23 +1010,12 @@ function sort_handles(handles) {
972
1010
  const n = handles.length;
973
1011
 
974
1012
  if (n > INSERTION_SORT_LIMIT) {
975
- handles.sort(ASCENDING);
1013
+ handles.sort(number_compare_ascending);
976
1014
 
977
1015
  return;
978
1016
  }
979
1017
 
980
- for (let i = 1; i < n; i++) {
981
- const handle = handles[i];
982
-
983
- let j = i - 1;
984
-
985
- while (j >= 0 && handles[j] > handle) {
986
- handles[j + 1] = handles[j];
987
- j--;
988
- }
989
-
990
- handles[j + 1] = handle;
991
- }
1018
+ array_sort_insertion_ascending(handles, 0, n);
992
1019
  }
993
1020
 
994
1021
  /**
@@ -1002,12 +1029,3 @@ const FAT_AABB = new Float64Array(6);
1002
1029
  * @type {Float32Array}
1003
1030
  */
1004
1031
  const STORED_AABB = new Float32Array(6);
1005
-
1006
- /**
1007
- * @param {number} a
1008
- * @param {number} b
1009
- * @returns {number}
1010
- */
1011
- function ASCENDING(a, b) {
1012
- return a - b;
1013
- }
@@ -1 +1 @@
1
- {"version":3,"file":"cloth_collider_bounds.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/collider/cloth_collider_bounds.js"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,oDAJW,MAAM,eACN,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;GAOG;AACH,mDALW,YAAY,GAAC,YAAY,UACzB,MAAM,UACN,MAAM,GACJ,IAAI,CAoBhB"}
1
+ {"version":3,"file":"cloth_collider_bounds.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/collider/cloth_collider_bounds.js"],"names":[],"mappings":"AAkBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,oDAJW,MAAM,eACN,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;GAOG;AACH,mDALW,YAAY,GAAC,YAAY,UACzB,MAAM,UACN,MAAM,GACJ,IAAI,CA2BhB"}