@woosh/meep-engine 3.43.0 → 3.44.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 (287) hide show
  1. package/editor/prototypeEditorShell.d.ts.map +1 -1
  2. package/editor/prototypeEditorShell.js +4 -2
  3. package/package.json +1 -1
  4. package/src/engine/Clock.d.ts +15 -0
  5. package/src/engine/Clock.d.ts.map +1 -1
  6. package/src/engine/Clock.js +29 -5
  7. package/src/engine/Engine.d.ts.map +1 -1
  8. package/src/engine/Engine.js +11 -19
  9. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.d.ts +57 -0
  10. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.d.ts.map +1 -0
  11. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.js +84 -0
  12. package/src/engine/graphics3/AnimationGraphSystem.d.ts +23 -13
  13. package/src/engine/graphics3/AnimationGraphSystem.d.ts.map +1 -1
  14. package/src/engine/graphics3/AnimationGraphSystem.js +61 -64
  15. package/src/engine/graphics3/AnimationSystem.d.ts +24 -15
  16. package/src/engine/graphics3/AnimationSystem.d.ts.map +1 -1
  17. package/src/engine/graphics3/AnimationSystem.js +67 -61
  18. package/src/engine/graphics3/MeshSkinSystem.d.ts +56 -0
  19. package/src/engine/graphics3/MeshSkinSystem.d.ts.map +1 -0
  20. package/src/engine/graphics3/MeshSkinSystem.js +317 -0
  21. package/src/engine/graphics3/MeshSystem.d.ts +15 -35
  22. package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
  23. package/src/engine/graphics3/MeshSystem.js +21 -298
  24. package/src/engine/graphics3/RowChains.d.ts +76 -0
  25. package/src/engine/graphics3/RowChains.d.ts.map +1 -0
  26. package/src/engine/graphics3/RowChains.js +347 -0
  27. package/src/engine/graphics3/ShadedGeometrySystem.d.ts +6 -0
  28. package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
  29. package/src/engine/graphics3/ShadedGeometrySystem.js +329 -309
  30. package/src/engine/graphics3/animation/AnimationClips.d.ts +56 -0
  31. package/src/engine/graphics3/animation/AnimationClips.d.ts.map +1 -0
  32. package/src/engine/graphics3/animation/AnimationClips.js +79 -0
  33. package/src/engine/graphics3/animation/ClipListPlayer.d.ts +13 -14
  34. package/src/engine/graphics3/animation/ClipListPlayer.d.ts.map +1 -1
  35. package/src/engine/graphics3/animation/ClipListPlayer.js +262 -263
  36. package/src/engine/graphics3/animation/write_clip_playback.d.ts +3 -3
  37. package/src/engine/graphics3/animation/write_clip_playback.js +4 -4
  38. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts +5 -0
  39. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts.map +1 -1
  40. package/src/engine/graphics3/pose/query_entity_node_world_pose.js +80 -75
  41. package/src/engine/graphics3/prefab/PrefabInstance.d.ts +4 -24
  42. package/src/engine/graphics3/prefab/PrefabInstance.d.ts.map +1 -1
  43. package/src/engine/graphics3/prefab/PrefabInstance.js +60 -80
  44. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts +16 -3
  45. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts.map +1 -1
  46. package/src/engine/graphics3/prefab/prefab_instantiate.js +49 -12
  47. package/src/engine/graphics3/prefab/prefab_place.d.ts +31 -17
  48. package/src/engine/graphics3/prefab/prefab_place.d.ts.map +1 -1
  49. package/src/engine/graphics3/prefab/prefab_place.js +175 -130
  50. package/src/engine/graphics3/register_clips.d.ts +64 -0
  51. package/src/engine/graphics3/register_clips.d.ts.map +1 -0
  52. package/src/engine/graphics3/register_clips.js +114 -0
  53. package/src/engine/physics/cloth/MEASUREMENTS.md +795 -0
  54. package/src/engine/physics/cloth/PLAN.md +339 -9
  55. package/src/engine/physics/cloth/build/ClothProxy.d.ts +113 -61
  56. package/src/engine/physics/cloth/build/ClothProxy.d.ts.map +1 -1
  57. package/src/engine/physics/cloth/build/ClothProxy.js +142 -77
  58. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts +22 -0
  59. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts.map +1 -0
  60. package/src/engine/physics/cloth/build/cloth_bind_in_frame.js +75 -0
  61. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +43 -30
  62. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  63. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +357 -284
  64. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts +62 -0
  65. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts.map +1 -0
  66. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.js +280 -0
  67. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts +1 -1
  68. package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +1 -1
  69. package/src/engine/physics/cloth/ecs/Cloth.d.ts +17 -9
  70. package/src/engine/physics/cloth/ecs/Cloth.d.ts.map +1 -1
  71. package/src/engine/physics/cloth/ecs/Cloth.js +220 -212
  72. package/src/engine/physics/cloth/ecs/ClothDynamicsFlags.js +6 -0
  73. package/src/engine/physics/cloth/ecs/ClothHold.d.ts +91 -0
  74. package/src/engine/physics/cloth/ecs/ClothHold.d.ts.map +1 -0
  75. package/src/engine/physics/cloth/ecs/ClothHold.js +103 -0
  76. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +254 -48
  77. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  78. package/src/engine/physics/cloth/ecs/ClothInstance.js +277 -47
  79. package/src/engine/physics/cloth/ecs/ClothPin.d.ts +73 -0
  80. package/src/engine/physics/cloth/ecs/ClothPin.d.ts.map +1 -0
  81. package/src/engine/physics/cloth/ecs/ClothPin.js +92 -0
  82. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.d.ts +36 -0
  83. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.d.ts.map +1 -0
  84. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.js +61 -0
  85. package/src/engine/physics/cloth/ecs/ClothRig.d.ts +23 -17
  86. package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -1
  87. package/src/engine/physics/cloth/ecs/ClothRig.js +29 -27
  88. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +12 -14
  89. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  90. package/src/engine/physics/cloth/ecs/ClothSystem.js +20 -15
  91. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +57 -36
  92. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  93. package/src/engine/physics/cloth/ecs/ClothWorld.js +816 -179
  94. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +12 -13
  95. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -1
  96. package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +20 -14
  97. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +63 -11
  98. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  99. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +321 -84
  100. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +9 -7
  101. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  102. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +9 -7
  103. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +3 -3
  104. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +30 -30
  105. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts +37 -0
  106. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts.map +1 -0
  107. package/src/engine/physics/cloth/ecs/cloth_geodesic.js +142 -0
  108. package/src/engine/physics/cloth/ecs/cloth_holds.d.ts +97 -0
  109. package/src/engine/physics/cloth/ecs/cloth_holds.d.ts.map +1 -0
  110. package/src/engine/physics/cloth/ecs/cloth_holds.js +608 -0
  111. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts +2 -2
  112. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -1
  113. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +160 -9
  114. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +17 -22
  115. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  116. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +55 -117
  117. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -6
  118. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  119. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +44 -15
  120. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +5 -0
  121. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  122. package/src/engine/physics/cloth/ecs/cloth_write_back.js +60 -16
  123. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -1
  124. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +65 -58
  125. package/src/engine/physics/cloth/playground/collide_main.js +1 -1
  126. package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -1
  127. package/src/engine/physics/cloth/playground/garment_build.js +17 -5
  128. package/src/engine/physics/cloth/playground/garment_main.js +1 -1
  129. package/src/engine/physics/cloth/playground/rig_build.d.ts.map +1 -1
  130. package/src/engine/physics/cloth/playground/rig_build.js +302 -296
  131. package/src/engine/physics/cloth/solver/ClothState.d.ts +45 -7
  132. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  133. package/src/engine/physics/cloth/solver/ClothState.js +63 -7
  134. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +6 -1
  135. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
  136. package/src/engine/physics/cloth/solver/cloth_contact_find.js +7 -2
  137. package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts +114 -0
  138. package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts.map +1 -0
  139. package/src/engine/physics/cloth/solver/cloth_hold_line.js +362 -0
  140. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts +6 -2
  141. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -1
  142. package/src/engine/physics/cloth/solver/cloth_self_find.js +13 -13
  143. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +24 -12
  144. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  145. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +24 -12
  146. package/src/engine/physics/cloth/solver/cloth_step.d.ts +16 -0
  147. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  148. package/src/engine/physics/cloth/solver/cloth_step.js +183 -20
  149. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts +1 -0
  150. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -1
  151. package/src/engine/physics/cloth/solver/cloth_step_instance.js +10 -3
  152. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.d.ts +1 -1
  153. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.d.ts.map +1 -1
  154. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.js +353 -346
  155. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts +7 -5
  156. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -1
  157. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +7 -5
  158. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +9 -9
  159. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
  160. package/src/engine/physics/cloth/wind/cloth_sample_air.js +26 -26
  161. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  162. package/src/engine/simulation/Ticker.d.ts +13 -0
  163. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  164. package/src/engine/simulation/Ticker.js +43 -8
  165. package/src/shade/RENDERER_CONTRACT.md +8 -2
  166. package/src/shade/playground/mesh_row_ceiling/main.js +2 -1
  167. package/src/shade/playground/skinned_blas_refit/main.d.ts.map +1 -1
  168. package/src/shade/playground/skinned_blas_refit/main.js +11 -19
  169. package/src/shade/playground/skinned_blas_refit/place_character.d.ts +6 -3
  170. package/src/shade/playground/skinned_blas_refit/place_character.d.ts.map +1 -1
  171. package/src/shade/playground/skinned_blas_refit/place_character.js +90 -90
  172. package/src/shade/playground/skinned_mesh_soup/main.d.ts.map +1 -1
  173. package/src/shade/playground/skinned_mesh_soup/main.js +502 -509
  174. package/src/shade/playground/texture_encode/README.md +129 -109
  175. package/src/shade/playground/texture_encode/main.js +1430 -1430
  176. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +45 -14
  177. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  178. package/src/shade/renderer/animation/GPUAnimationManager.js +316 -64
  179. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts +5 -0
  180. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  181. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +11 -1
  182. package/src/shade/renderer/geometry/BoxGeometry.d.ts +1 -11
  183. package/src/shade/renderer/geometry/BoxGeometry.d.ts.map +1 -1
  184. package/src/shade/renderer/geometry/BoxGeometry.js +6 -13
  185. package/src/shade/renderer/geometry/CapsuleGeometry.d.ts +19 -0
  186. package/src/shade/renderer/geometry/CapsuleGeometry.d.ts.map +1 -0
  187. package/src/shade/renderer/geometry/CapsuleGeometry.js +24 -0
  188. package/src/shade/renderer/geometry/ConeGeometry.d.ts +20 -0
  189. package/src/shade/renderer/geometry/ConeGeometry.d.ts.map +1 -0
  190. package/src/shade/renderer/geometry/ConeGeometry.js +33 -0
  191. package/src/shade/renderer/geometry/CylinderGeometry.d.ts +21 -0
  192. package/src/shade/renderer/geometry/CylinderGeometry.d.ts.map +1 -0
  193. package/src/shade/renderer/geometry/CylinderGeometry.js +35 -0
  194. package/src/shade/renderer/geometry/PlaneGeometry.d.ts +17 -0
  195. package/src/shade/renderer/geometry/PlaneGeometry.d.ts.map +1 -0
  196. package/src/shade/renderer/geometry/PlaneGeometry.js +22 -0
  197. package/src/shade/renderer/geometry/TorusGeometry.d.ts +18 -0
  198. package/src/shade/renderer/geometry/TorusGeometry.d.ts.map +1 -0
  199. package/src/shade/renderer/geometry/TorusGeometry.js +23 -0
  200. package/src/shade/renderer/geometry/UVSphereGeometry.d.ts +21 -0
  201. package/src/shade/renderer/geometry/UVSphereGeometry.d.ts.map +1 -0
  202. package/src/shade/renderer/geometry/UVSphereGeometry.js +34 -0
  203. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts +19 -0
  204. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts.map +1 -0
  205. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.js +205 -0
  206. package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts +21 -0
  207. package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts.map +1 -0
  208. package/src/shade/renderer/geometry/primitives/make_cone_geometry.js +36 -0
  209. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts +1 -1
  210. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts.map +1 -1
  211. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.js +44 -9
  212. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts +20 -0
  213. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts.map +1 -0
  214. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.js +190 -0
  215. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  216. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +7 -2
  217. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts +26 -8
  218. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts.map +1 -1
  219. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js +56 -39
  220. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts +7 -0
  221. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts.map +1 -1
  222. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.js +46 -4
  223. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.d.ts.map +1 -1
  224. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.js +4 -2
  225. package/src/shade/renderer/gpu_primitive/sort/defs.d.ts +2 -2
  226. package/src/shade/renderer/gpu_primitive/sort/defs.js +79 -79
  227. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts +1 -1
  228. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts.map +1 -1
  229. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.js +7 -3
  230. package/src/shade/renderer/particles/GPUParticleSystem.js +1 -1
  231. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts +4 -3
  232. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts.map +1 -1
  233. package/src/shade/renderer/particles/coherence/graph_particle_bucket.js +200 -194
  234. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  235. package/src/shade/renderer/particles/graph_particles.js +6 -2
  236. package/src/shade/renderer/particles/warmup/graph_particle_warmup.d.ts.map +1 -1
  237. package/src/shade/renderer/particles/warmup/graph_particle_warmup.js +334 -329
  238. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  239. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +7 -2
  240. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.d.ts.map +1 -1
  241. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.js +16 -4
  242. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +2444 -2345
  243. package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.d.ts.map +1 -1
  244. package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.js +312 -310
  245. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts +3 -3
  246. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts.map +1 -1
  247. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.js +383 -375
  248. package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.d.ts.map +1 -1
  249. package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.js +349 -346
  250. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts +58 -0
  251. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts.map +1 -0
  252. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.js +536 -0
  253. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts +21 -7
  254. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts.map +1 -1
  255. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.js +291 -327
  256. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts +25 -0
  257. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts.map +1 -0
  258. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.js +99 -0
  259. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts +5 -3
  260. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts.map +1 -1
  261. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.js +47 -71
  262. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts +10 -0
  263. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts.map +1 -0
  264. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.js +50 -0
  265. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts +4 -5
  266. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts.map +1 -1
  267. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.js +7 -8
  268. package/src/shade/renderer/water/chunk_water_transport.d.ts.map +1 -1
  269. package/src/shade/renderer/water/chunk_water_transport.js +7 -5
  270. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +1 -1
  271. package/src/shade/renderer/water/medium/GPUWaterBodies.js +8 -2
  272. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts +3 -2
  273. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts.map +1 -1
  274. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.js +3 -2
  275. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  276. package/src/shade/renderer/water/shader_water.js +3 -1
  277. package/src/shade/renderer/water/surface/GPUWaterSurface.d.ts.map +1 -1
  278. package/src/shade/renderer/water/surface/GPUWaterSurface.js +3 -1
  279. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts.map +1 -1
  280. package/src/shade/renderer/water/surface/graph_water_tessellation.js +11 -4
  281. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -1
  282. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +37 -20
  283. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  284. package/src/shade/wgsl/validate_wgsl_source.js +74 -3
  285. package/src/engine/graphics3/register_instance_animation.d.ts +0 -114
  286. package/src/engine/graphics3/register_instance_animation.d.ts.map +0 -1
  287. package/src/engine/graphics3/register_instance_animation.js +0 -201
@@ -1,346 +1,353 @@
1
- import {
2
- CVA_F_X,
3
- CVA_F_Y,
4
- CVA_F_Z,
5
- CVA_H_XX,
6
- CVA_H_XY,
7
- CVA_H_XZ,
8
- CVA_H_YY,
9
- CVA_H_YZ,
10
- CVA_H_ZZ,
11
- CVA_TRUST
12
- } from "../cloth_vertex_accumulator.js";
13
- import { CLOTH_STRETCH_EPSILON } from "./cloth_stretch_row.js";
14
-
15
- /**
16
- * # Leash — the distance-to-a-point row
17
- *
18
- * C(x) = ‖x_i − s‖ − r
19
- * ∂C/∂x_i = (x_i − s)/‖x_i − s‖ = n
20
- *
21
- * **This is both of §6's leash rows.** The slack row and the tether row have
22
- * the same `C`, the same clamp and the same stiffness; they differ only in
23
- * where `s` and `r` come from:
24
- *
25
- * | | `s` | `r` |
26
- * |---|---|---|
27
- * | slack | the particle's **animated position** | `slack · d_geo,i` |
28
- * | tether (LRA) | the **anchor's** position | `d_geo,i` |
29
- *
30
- * So they are one module, parameterised by mode, exactly as
31
- * `physics/constraint/solve_constraints.js` does for its 6-DOF joints at the
32
- * velocity level, and exactly as `cloth_stretch_row.js` covers both the fabric
33
- * row and its strain limit. A cape wants both, because they ask different
34
- * questions: slack asks how loosely the cloth is leashed to the animation, the
35
- * tether asks how far the fabric may extend from where it hangs (§6).
36
- *
37
- * §3.4's pin falls out too, with no third row and no branch: a particle whose
38
- * `d_geo` is zero has a slack radius of zero, and `‖x_i − s‖ ≤ 0` under this
39
- * clamp *is* a weld.
40
- *
41
- * ## The row is hard, and one-sided, structurally
42
- *
43
- * Neither a stiffness nor a pair of clamps is stored, because neither varies.
44
- * A leash is `hard` in §6's table — its penalty lives in the measured band and
45
- * its multiplier carries the load — and it is a *bound* rather than a spring,
46
- * so it may only pull inwards. That is why this is the row that survives a low
47
- * iteration budget: it is enforced almost exactly in one iteration, which is
48
- * what §7 P2 means by long-range attachments making low iteration counts
49
- * viable.
50
- *
51
- * ## Which way the clamp goes, and why §6's table has it backwards
52
- *
53
- * The solver applies `f -= fc·g`, so a **positive** `fc` on a distance row
54
- * pulls the two ends together — that is what `cloth_stretch_row.js` means when
55
- * it adds geometric stiffness for a row "in tension" at `fc > 0`. A row that
56
- * bounds a distance from *above* must therefore be allowed positive force and
57
- * no negative force: `f_min = 0, f_max = +∞`.
58
- *
59
- * §6's table gives slack, tether and strain limit `(−∞, 0]` instead, which
60
- * under this convention is the force that pushes them apart — it would drive
61
- * the particle *away* from its leash centre and the row would never bind.
62
- * `cloth_leash_row.spec.js` demonstrates the correct sign directly; the
63
- * table's own collision and self-collision rows are consistent with it once
64
- * you notice that a collision row writes `C` with the opposite sense. The
65
- * precise rule, which the table's "push-only / pull-only" gloss elides, is:
66
- * `[0, +∞)` admits only forces that **reduce** `C`, and `(−∞, 0]` only forces
67
- * that **increase** it.
68
- *
69
- * ## Coincident with the target
70
- *
71
- * `‖x − s‖` is not differentiable at zero. Below {@link CLOTH_STRETCH_EPSILON}
72
- * the row is skipped, which is the standard guard and is also exactly when it
73
- * has nothing to do — a particle sitting on its own leash centre is where the
74
- * row was trying to put it.
75
- *
76
- * @author Alex Goldring
77
- * @copyright Company Named Limited (c) 2026
78
- */
79
-
80
- /**
81
- * Evaluate one leash row's constraint value and its gradient.
82
- *
83
- * This is the definition the accumulation loop below inlines, and the one the
84
- * finite-difference spec checks — there is no second copy of the arithmetic.
85
- *
86
- * @param {Float64Array|number[]} gradient out, `∂C/∂x`
87
- * @param {number} gradient_offset
88
- * @param {ClothState} state
89
- * @param {number} row
90
- * @returns {number} `C`
91
- */
92
- export function cloth_leash_evaluate(gradient, gradient_offset, state, row) {
93
- const self = state.leash_particle[row] * 3;
94
- const target = row * 3;
95
-
96
- const position = state.position;
97
- const leash_target = state.leash_target;
98
-
99
- const dx = position[self] - leash_target[target];
100
- const dy = position[self + 1] - leash_target[target + 1];
101
- const dz = position[self + 2] - leash_target[target + 2];
102
-
103
- const length = Math.sqrt(dx * dx + dy * dy + dz * dz);
104
-
105
- if (length < CLOTH_STRETCH_EPSILON) {
106
- gradient[gradient_offset] = 0;
107
- gradient[gradient_offset + 1] = 0;
108
- gradient[gradient_offset + 2] = 0;
109
-
110
- return length - state.leash_radius[row];
111
- }
112
-
113
- const inverse = 1 / length;
114
-
115
- gradient[gradient_offset] = dx * inverse;
116
- gradient[gradient_offset + 1] = dy * inverse;
117
- gradient[gradient_offset + 2] = dz * inverse;
118
-
119
- return length - state.leash_radius[row];
120
- }
121
-
122
- /**
123
- * Add every leash row touching `particle` into the vertex accumulator.
124
- *
125
- * @param {Float64Array} accumulator
126
- * @param {ClothState} state
127
- * @param {number} particle
128
- */
129
- export function cloth_leash_accumulate(accumulator, state, particle) {
130
- const offset = state.leash_adjacency_offset;
131
-
132
- const start = offset[particle];
133
- const end = offset[particle + 1];
134
-
135
- if (start === end) {
136
- return;
137
- }
138
-
139
- const adjacency = state.leash_adjacency;
140
- const radius = state.leash_radius;
141
- const lambda = state.leash_lambda;
142
- const penalty = state.leash_penalty;
143
- const leash_target = state.leash_target;
144
- const position = state.position;
145
-
146
- const self = particle * 3;
147
-
148
- const x = position[self];
149
- const y = position[self + 1];
150
- const z = position[self + 2];
151
-
152
- let f_x = accumulator[CVA_F_X];
153
- let f_y = accumulator[CVA_F_Y];
154
- let f_z = accumulator[CVA_F_Z];
155
-
156
- let h_xx = accumulator[CVA_H_XX];
157
- let h_yy = accumulator[CVA_H_YY];
158
- let h_zz = accumulator[CVA_H_ZZ];
159
- let h_xy = accumulator[CVA_H_XY];
160
- let h_xz = accumulator[CVA_H_XZ];
161
- let h_yz = accumulator[CVA_H_YZ];
162
-
163
- let trust = accumulator[CVA_TRUST];
164
-
165
- for (let i = start; i < end; i++) {
166
- const row = adjacency[i];
167
-
168
- const target = row * 3;
169
-
170
- const dx = x - leash_target[target];
171
- const dy = y - leash_target[target + 1];
172
- const dz = z - leash_target[target + 2];
173
-
174
- const length_squared = dx * dx + dy * dy + dz * dz;
175
-
176
- if (length_squared < CLOTH_STRETCH_EPSILON * CLOTH_STRETCH_EPSILON) {
177
- continue;
178
- }
179
-
180
- const k = penalty[row];
181
-
182
- const length = Math.sqrt(length_squared);
183
-
184
- const unclamped = k * (length - radius[row]) + lambda[row];
185
-
186
- if (unclamped <= 0) {
187
- // Inside the leash and carrying no accumulated force: the row is
188
- // clamped out, contributes neither force nor curvature, and — this
189
- // is the part that matters — must not narrow the trust region
190
- // either. A particle resting near its own leash centre would
191
- // otherwise cap every step at its distance from that centre and
192
- // freeze for reasons that have nothing to do with the rows doing
193
- // the work.
194
- continue;
195
- }
196
-
197
- const inverse = 1 / length;
198
-
199
- if (length < trust) {
200
- trust = length;
201
- }
202
-
203
- const g_x = dx * inverse;
204
- const g_y = dy * inverse;
205
- const g_z = dz * inverse;
206
-
207
- f_x -= unclamped * g_x;
208
- f_y -= unclamped * g_y;
209
- f_z -= unclamped * g_z;
210
-
211
- // Geometric stiffness, positive part only. The row is in tension
212
- // whenever it is active at all — that is what the clamp above means —
213
- // so the `(fc/L)·(I − ggᵀ)` term is positive semidefinite here without
214
- // a second test. `MEASUREMENTS.md` §5.1 for what dropping it costs.
215
- const s = unclamped * inverse;
216
-
217
- h_xx += s * (1 - g_x * g_x) + k * g_x * g_x;
218
- h_yy += s * (1 - g_y * g_y) + k * g_y * g_y;
219
- h_zz += s * (1 - g_z * g_z) + k * g_z * g_z;
220
- h_xy += (k - s) * g_x * g_y;
221
- h_xz += (k - s) * g_x * g_z;
222
- h_yz += (k - s) * g_y * g_z;
223
- }
224
-
225
- accumulator[CVA_F_X] = f_x;
226
- accumulator[CVA_F_Y] = f_y;
227
- accumulator[CVA_F_Z] = f_z;
228
-
229
- accumulator[CVA_H_XX] = h_xx;
230
- accumulator[CVA_H_YY] = h_yy;
231
- accumulator[CVA_H_ZZ] = h_zz;
232
- accumulator[CVA_H_XY] = h_xy;
233
- accumulator[CVA_H_XZ] = h_xz;
234
- accumulator[CVA_H_YZ] = h_yz;
235
-
236
- accumulator[CVA_TRUST] = trust;
237
- }
238
-
239
- /**
240
- * Warm start every leash row for a substep: regularise the carried multiplier
241
- * and put the penalty in the band. §5.2.
242
- *
243
- * Every leash row is hard, so — unlike the stretch table — there is no soft
244
- * branch here. The row's inertial scale is the particle's own `m/h²`, because
245
- * a leash has one end that can move.
246
- *
247
- * @param {ClothState} state
248
- * @param {number} alpha multiplier regularisation, `[0, 1]`
249
- * @param {number} gamma dual decay, `[0, 1)`
250
- * @param {number} k_min_ratio penalty floor, as a multiple of `m/h²`
251
- * @param {number} k_max_ratio penalty ceiling, as a multiple of `m/h²`
252
- * @param {number} inverse_h_squared
253
- */
254
- export function cloth_leash_warm_start(state, alpha, gamma, k_min_ratio, k_max_ratio, inverse_h_squared) {
255
- const count = state.leash_count;
256
-
257
- const row_particle = state.leash_particle;
258
- const mass_inverse = state.mass_inverse;
259
- const lambda = state.leash_lambda;
260
- const penalty = state.leash_penalty;
261
-
262
- const decay = alpha * gamma;
263
-
264
- for (let row = 0; row < count; row++) {
265
- const compliance = mass_inverse[row_particle[row]];
266
-
267
- if (compliance === 0) {
268
- // A pinned particle cannot move, so the row has nothing to enforce
269
- // and the band it would be clamped into is unbounded. Zeroed rather
270
- // than left holding `Infinity` in live state.
271
- penalty[row] = 0;
272
- lambda[row] = 0;
273
-
274
- continue;
275
- }
276
-
277
- const scale = inverse_h_squared / compliance;
278
-
279
- const lo = k_min_ratio * scale;
280
- const hi = k_max_ratio * scale;
281
-
282
- lambda[row] *= decay;
283
-
284
- let k = penalty[row] * gamma;
285
-
286
- if (k < lo) {
287
- k = lo;
288
- } else if (k > hi) {
289
- k = hi;
290
- }
291
-
292
- penalty[row] = k;
293
- }
294
- }
295
-
296
- /**
297
- * Dual update for every leash row: absorb this iteration's violation into the
298
- * multiplier and ramp the penalty. §5.2.
299
- *
300
- * @param {ClothState} state
301
- * @param {number} beta penalty ramp
302
- * @param {number} k_max_ratio
303
- * @param {number} inverse_h_squared
304
- */
305
- export function cloth_leash_dual_update(state, beta, k_max_ratio, inverse_h_squared) {
306
- const count = state.leash_count;
307
-
308
- const row_particle = state.leash_particle;
309
- const mass_inverse = state.mass_inverse;
310
- const position = state.position;
311
- const leash_target = state.leash_target;
312
- const radius = state.leash_radius;
313
- const lambda = state.leash_lambda;
314
- const penalty = state.leash_penalty;
315
-
316
- for (let row = 0; row < count; row++) {
317
- const particle = row_particle[row];
318
-
319
- const compliance = mass_inverse[particle];
320
-
321
- if (compliance === 0) {
322
- continue;
323
- }
324
-
325
- const k_max = k_max_ratio * inverse_h_squared / compliance;
326
-
327
- const self = particle * 3;
328
- const target = row * 3;
329
-
330
- const dx = position[self] - leash_target[target];
331
- const dy = position[self + 1] - leash_target[target + 1];
332
- const dz = position[self + 2] - leash_target[target + 2];
333
-
334
- const c = Math.sqrt(dx * dx + dy * dy + dz * dz) - radius[row];
335
-
336
- const k = penalty[row];
337
-
338
- const next = k * c + lambda[row];
339
-
340
- lambda[row] = next > 0 ? next : 0;
341
-
342
- const ramped = k + beta * Math.abs(c);
343
-
344
- penalty[row] = ramped < k_max ? ramped : k_max;
345
- }
346
- }
1
+ import {
2
+ CVA_F_X,
3
+ CVA_F_Y,
4
+ CVA_F_Z,
5
+ CVA_H_XX,
6
+ CVA_H_XY,
7
+ CVA_H_XZ,
8
+ CVA_H_YY,
9
+ CVA_H_YZ,
10
+ CVA_H_ZZ,
11
+ CVA_TRUST
12
+ } from "../cloth_vertex_accumulator.js";
13
+ import { CLOTH_STRETCH_EPSILON } from "./cloth_stretch_row.js";
14
+
15
+ /**
16
+ * # Leash — the distance-to-a-point row
17
+ *
18
+ * C(x) = ‖x_i − s‖ − r
19
+ * ∂C/∂x_i = (x_i − s)/‖x_i − s‖ = n
20
+ *
21
+ * **This is both of §6's leash rows.** The slack row and the tether row have
22
+ * the same `C`, the same clamp and the same stiffness; they differ only in
23
+ * where `s` and `r` come from:
24
+ *
25
+ * | | `s` | `r` |
26
+ * |---|---|---|
27
+ * | slack | the particle's **animated position** | `slack · d_geo,i` |
28
+ * | tether (LRA) | the nearest **held particle's** position | `d_geo,i` |
29
+ *
30
+ * So they are one module, parameterised by mode, exactly as
31
+ * `physics/constraint/solve_constraints.js` does for its 6-DOF joints at the
32
+ * velocity level, and exactly as `cloth_stretch_row.js` covers both the fabric
33
+ * row and its strain limit. A cape wants both, because they ask different
34
+ * questions: slack asks how loosely the cloth is leashed to the animation, the
35
+ * tether asks how far the fabric may extend from where it hangs (§6).
36
+ *
37
+ * §3.4's pin falls out too, with no third row and no branch: a particle whose
38
+ * `d_geo` is zero has a slack radius of zero, and `‖x_i − s‖ ≤ 0` under this
39
+ * clamp *is* a weld.
40
+ *
41
+ * ## The row is hard, and one-sided, structurally
42
+ *
43
+ * Neither a stiffness nor a pair of clamps is stored, because neither varies.
44
+ * A leash is `hard` in §6's table — its penalty lives in the measured band and
45
+ * its multiplier carries the load — and it is a *bound* rather than a spring,
46
+ * so it may only pull inwards. That is why this is the row that survives a low
47
+ * iteration budget: it is enforced almost exactly in one iteration, which is
48
+ * what §7 P2 means by long-range attachments making low iteration counts
49
+ * viable.
50
+ *
51
+ * ## Which way the clamp goes, and why §6's table has it backwards
52
+ *
53
+ * The solver applies `f -= fc·g`, so a **positive** `fc` on a distance row
54
+ * pulls the two ends together — that is what `cloth_stretch_row.js` means when
55
+ * it adds geometric stiffness for a row "in tension" at `fc > 0`. A row that
56
+ * bounds a distance from *above* must therefore be allowed positive force and
57
+ * no negative force: `f_min = 0, f_max = +∞`.
58
+ *
59
+ * §6's table gives slack, tether and strain limit `(−∞, 0]` instead, which
60
+ * under this convention is the force that pushes them apart — it would drive
61
+ * the particle *away* from its leash centre and the row would never bind.
62
+ * `cloth_leash_row.spec.js` demonstrates the correct sign directly; the
63
+ * table's own collision and self-collision rows are consistent with it once
64
+ * you notice that a collision row writes `C` with the opposite sense. The
65
+ * precise rule, which the table's "push-only / pull-only" gloss elides, is:
66
+ * `[0, +∞)` admits only forces that **reduce** `C`, and `(−∞, 0]` only forces
67
+ * that **increase** it.
68
+ *
69
+ * ## Coincident with the target
70
+ *
71
+ * `‖x − s‖` is not differentiable at zero. Below {@link CLOTH_STRETCH_EPSILON}
72
+ * the row is skipped, which is the standard guard and is also exactly when it
73
+ * has nothing to do — a particle sitting on its own leash centre is where the
74
+ * row was trying to put it.
75
+ *
76
+ * @author Alex Goldring
77
+ * @copyright Company Named Limited (c) 2026
78
+ */
79
+
80
+ /**
81
+ * Evaluate one leash row's constraint value and its gradient.
82
+ *
83
+ * This is the definition the accumulation loop below inlines, and the one the
84
+ * finite-difference spec checks — there is no second copy of the arithmetic.
85
+ *
86
+ * @param {Float64Array|number[]} gradient out, `∂C/∂x`
87
+ * @param {number} gradient_offset
88
+ * @param {ClothState} state
89
+ * @param {number} row
90
+ * @returns {number} `C`
91
+ */
92
+ export function cloth_leash_evaluate(gradient, gradient_offset, state, row) {
93
+ const self = state.leash_particle[row] * 3;
94
+ const target = row * 3;
95
+
96
+ const position = state.position;
97
+ const leash_target = state.leash_target;
98
+
99
+ const dx = position[self] - leash_target[target];
100
+ const dy = position[self + 1] - leash_target[target + 1];
101
+ const dz = position[self + 2] - leash_target[target + 2];
102
+
103
+ const length = Math.sqrt(dx * dx + dy * dy + dz * dz);
104
+
105
+ if (length < CLOTH_STRETCH_EPSILON) {
106
+ gradient[gradient_offset] = 0;
107
+ gradient[gradient_offset + 1] = 0;
108
+ gradient[gradient_offset + 2] = 0;
109
+
110
+ return length - state.leash_radius[row];
111
+ }
112
+
113
+ const inverse = 1 / length;
114
+
115
+ gradient[gradient_offset] = dx * inverse;
116
+ gradient[gradient_offset + 1] = dy * inverse;
117
+ gradient[gradient_offset + 2] = dz * inverse;
118
+
119
+ return length - state.leash_radius[row];
120
+ }
121
+
122
+ /**
123
+ * Add every leash row touching `particle` into the vertex accumulator.
124
+ *
125
+ * @param {Float64Array} accumulator
126
+ * @param {ClothState} state
127
+ * @param {number} particle
128
+ */
129
+ export function cloth_leash_accumulate(accumulator, state, particle) {
130
+ const offset = state.leash_adjacency_offset;
131
+
132
+ const start = offset[particle];
133
+ const end = offset[particle + 1];
134
+
135
+ if (start === end) {
136
+ return;
137
+ }
138
+
139
+ const adjacency = state.leash_adjacency;
140
+ const radius = state.leash_radius;
141
+ const lambda = state.leash_lambda;
142
+ const penalty = state.leash_penalty;
143
+ const leash_target = state.leash_target;
144
+ const position = state.position;
145
+
146
+ const self = particle * 3;
147
+
148
+ const x = position[self];
149
+ const y = position[self + 1];
150
+ const z = position[self + 2];
151
+
152
+ let f_x = accumulator[CVA_F_X];
153
+ let f_y = accumulator[CVA_F_Y];
154
+ let f_z = accumulator[CVA_F_Z];
155
+
156
+ let h_xx = accumulator[CVA_H_XX];
157
+ let h_yy = accumulator[CVA_H_YY];
158
+ let h_zz = accumulator[CVA_H_ZZ];
159
+ let h_xy = accumulator[CVA_H_XY];
160
+ let h_xz = accumulator[CVA_H_XZ];
161
+ let h_yz = accumulator[CVA_H_YZ];
162
+
163
+ let trust = accumulator[CVA_TRUST];
164
+
165
+ for (let i = start; i < end; i++) {
166
+ const row = adjacency[i];
167
+
168
+ if (radius[row] === Infinity) {
169
+ // A row with no bound — a particle nothing holds — has nothing to
170
+ // say, and asked first it costs nothing and cannot meet a zero
171
+ // penalty times an infinite violation.
172
+ continue;
173
+ }
174
+
175
+ const target = row * 3;
176
+
177
+ const dx = x - leash_target[target];
178
+ const dy = y - leash_target[target + 1];
179
+ const dz = z - leash_target[target + 2];
180
+
181
+ const length_squared = dx * dx + dy * dy + dz * dz;
182
+
183
+ if (length_squared < CLOTH_STRETCH_EPSILON * CLOTH_STRETCH_EPSILON) {
184
+ continue;
185
+ }
186
+
187
+ const k = penalty[row];
188
+
189
+ const length = Math.sqrt(length_squared);
190
+
191
+ const unclamped = k * (length - radius[row]) + lambda[row];
192
+
193
+ if (unclamped <= 0) {
194
+ // Inside the leash and carrying no accumulated force: the row is
195
+ // clamped out, contributes neither force nor curvature, and — this
196
+ // is the part that matters — must not narrow the trust region
197
+ // either. A particle resting near its own leash centre would
198
+ // otherwise cap every step at its distance from that centre and
199
+ // freeze for reasons that have nothing to do with the rows doing
200
+ // the work.
201
+ continue;
202
+ }
203
+
204
+ const inverse = 1 / length;
205
+
206
+ if (length < trust) {
207
+ trust = length;
208
+ }
209
+
210
+ const g_x = dx * inverse;
211
+ const g_y = dy * inverse;
212
+ const g_z = dz * inverse;
213
+
214
+ f_x -= unclamped * g_x;
215
+ f_y -= unclamped * g_y;
216
+ f_z -= unclamped * g_z;
217
+
218
+ // Geometric stiffness, positive part only. The row is in tension
219
+ // whenever it is active at all — that is what the clamp above means —
220
+ // so the `(fc/L)·(I − ggᵀ)` term is positive semidefinite here without
221
+ // a second test. `MEASUREMENTS.md` §5.1 for what dropping it costs.
222
+ const s = unclamped * inverse;
223
+
224
+ h_xx += s * (1 - g_x * g_x) + k * g_x * g_x;
225
+ h_yy += s * (1 - g_y * g_y) + k * g_y * g_y;
226
+ h_zz += s * (1 - g_z * g_z) + k * g_z * g_z;
227
+ h_xy += (k - s) * g_x * g_y;
228
+ h_xz += (k - s) * g_x * g_z;
229
+ h_yz += (k - s) * g_y * g_z;
230
+ }
231
+
232
+ accumulator[CVA_F_X] = f_x;
233
+ accumulator[CVA_F_Y] = f_y;
234
+ accumulator[CVA_F_Z] = f_z;
235
+
236
+ accumulator[CVA_H_XX] = h_xx;
237
+ accumulator[CVA_H_YY] = h_yy;
238
+ accumulator[CVA_H_ZZ] = h_zz;
239
+ accumulator[CVA_H_XY] = h_xy;
240
+ accumulator[CVA_H_XZ] = h_xz;
241
+ accumulator[CVA_H_YZ] = h_yz;
242
+
243
+ accumulator[CVA_TRUST] = trust;
244
+ }
245
+
246
+ /**
247
+ * Warm start every leash row for a substep: regularise the carried multiplier
248
+ * and put the penalty in the band. §5.2.
249
+ *
250
+ * Every leash row is hard, so — unlike the stretch table — there is no soft
251
+ * branch here. The row's inertial scale is the particle's own `m/h²`, because
252
+ * a leash has one end that can move.
253
+ *
254
+ * @param {ClothState} state
255
+ * @param {number} alpha multiplier regularisation, `[0, 1]`
256
+ * @param {number} gamma dual decay, `[0, 1)`
257
+ * @param {number} k_min_ratio penalty floor, as a multiple of `m/h²`
258
+ * @param {number} k_max_ratio penalty ceiling, as a multiple of `m/h²`
259
+ * @param {number} inverse_h_squared
260
+ */
261
+ export function cloth_leash_warm_start(state, alpha, gamma, k_min_ratio, k_max_ratio, inverse_h_squared) {
262
+ const count = state.leash_count;
263
+
264
+ const row_particle = state.leash_particle;
265
+ const mass_inverse = state.mass_inverse;
266
+ const lambda = state.leash_lambda;
267
+ const penalty = state.leash_penalty;
268
+
269
+ const decay = alpha * gamma;
270
+
271
+ for (let row = 0; row < count; row++) {
272
+ const compliance = mass_inverse[row_particle[row]];
273
+
274
+ if (compliance === 0) {
275
+ // A pinned particle cannot move, so the row has nothing to enforce
276
+ // and the band it would be clamped into is unbounded. Zeroed rather
277
+ // than left holding `Infinity` in live state.
278
+ penalty[row] = 0;
279
+ lambda[row] = 0;
280
+
281
+ continue;
282
+ }
283
+
284
+ const scale = inverse_h_squared / compliance;
285
+
286
+ const lo = k_min_ratio * scale;
287
+ const hi = k_max_ratio * scale;
288
+
289
+ lambda[row] *= decay;
290
+
291
+ let k = penalty[row] * gamma;
292
+
293
+ if (k < lo) {
294
+ k = lo;
295
+ } else if (k > hi) {
296
+ k = hi;
297
+ }
298
+
299
+ penalty[row] = k;
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Dual update for every leash row: absorb this iteration's violation into the
305
+ * multiplier and ramp the penalty. §5.2.
306
+ *
307
+ * @param {ClothState} state
308
+ * @param {number} beta penalty ramp
309
+ * @param {number} k_max_ratio
310
+ * @param {number} inverse_h_squared
311
+ */
312
+ export function cloth_leash_dual_update(state, beta, k_max_ratio, inverse_h_squared) {
313
+ const count = state.leash_count;
314
+
315
+ const row_particle = state.leash_particle;
316
+ const mass_inverse = state.mass_inverse;
317
+ const position = state.position;
318
+ const leash_target = state.leash_target;
319
+ const radius = state.leash_radius;
320
+ const lambda = state.leash_lambda;
321
+ const penalty = state.leash_penalty;
322
+
323
+ for (let row = 0; row < count; row++) {
324
+ const particle = row_particle[row];
325
+
326
+ const compliance = mass_inverse[particle];
327
+
328
+ if (compliance === 0 || radius[row] === Infinity) {
329
+ continue;
330
+ }
331
+
332
+ const k_max = k_max_ratio * inverse_h_squared / compliance;
333
+
334
+ const self = particle * 3;
335
+ const target = row * 3;
336
+
337
+ const dx = position[self] - leash_target[target];
338
+ const dy = position[self + 1] - leash_target[target + 1];
339
+ const dz = position[self + 2] - leash_target[target + 2];
340
+
341
+ const c = Math.sqrt(dx * dx + dy * dy + dz * dz) - radius[row];
342
+
343
+ const k = penalty[row];
344
+
345
+ const next = k * c + lambda[row];
346
+
347
+ lambda[row] = next > 0 ? next : 0;
348
+
349
+ const ramped = k + beta * Math.abs(c);
350
+
351
+ penalty[row] = ramped < k_max ? ramped : k_max;
352
+ }
353
+ }