@woosh/meep-engine 3.22.0 → 3.23.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 (267) hide show
  1. package/package.json +1 -1
  2. package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts +118 -0
  3. package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts.map +1 -0
  4. package/src/core/geom/3d/hash-grid/PointHashGrid3.js +283 -0
  5. package/src/core/geom/3d/shape/BoxShape3D.d.ts.map +1 -1
  6. package/src/core/geom/3d/shape/BoxShape3D.js +6 -17
  7. package/src/core/geom/3d/shape/CapsuleShape3D.d.ts.map +1 -1
  8. package/src/core/geom/3d/shape/CapsuleShape3D.js +3 -14
  9. package/src/core/geom/3d/shape/CylinderShape3D.d.ts.map +1 -1
  10. package/src/core/geom/3d/shape/CylinderShape3D.js +3 -21
  11. package/src/core/geom/3d/shape/PlaneShape3D.d.ts +105 -0
  12. package/src/core/geom/3d/shape/PlaneShape3D.d.ts.map +1 -0
  13. package/src/core/geom/3d/shape/PlaneShape3D.js +251 -0
  14. package/src/core/geom/3d/shape/SphereShape3D.js +3 -3
  15. package/src/core/geom/3d/shape/json/shape_to_type.d.ts.map +1 -1
  16. package/src/core/geom/3d/shape/json/shape_to_type.js +3 -0
  17. package/src/core/geom/3d/shape/json/type_adapters.d.ts +14 -0
  18. package/src/core/geom/3d/shape/json/type_adapters.d.ts.map +1 -1
  19. package/src/core/geom/3d/shape/json/type_adapters.js +15 -0
  20. package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts +51 -0
  21. package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts.map +1 -0
  22. package/src/core/geom/3d/shape/sdf/sdf3_box.js +113 -0
  23. package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts +46 -0
  24. package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts.map +1 -0
  25. package/src/core/geom/3d/shape/sdf/sdf3_capsule.js +82 -0
  26. package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts +60 -0
  27. package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts.map +1 -0
  28. package/src/core/geom/3d/shape/sdf/sdf3_cylinder.js +126 -0
  29. package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.d.ts +50 -0
  30. package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.d.ts.map +1 -0
  31. package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.js +53 -0
  32. package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts +52 -0
  33. package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts.map +1 -0
  34. package/src/core/geom/3d/shape/sdf/sdf3_plane.js +61 -0
  35. package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts +41 -0
  36. package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts.map +1 -0
  37. package/src/core/geom/3d/shape/sdf/sdf3_sphere.js +71 -0
  38. package/src/core/process/ConcurrencyGate.d.ts +103 -0
  39. package/src/core/process/ConcurrencyGate.d.ts.map +1 -0
  40. package/src/core/process/ConcurrencyGate.js +207 -0
  41. package/src/engine/asset/AssetManager.d.ts +10 -0
  42. package/src/engine/asset/AssetManager.d.ts.map +1 -1
  43. package/src/engine/asset/AssetManager.js +10 -0
  44. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +30 -13
  45. package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts +26 -0
  46. package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts.map +1 -0
  47. package/src/engine/graphics3/pose/collect_entity_playbacks.js +40 -0
  48. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts.map +1 -1
  49. package/src/engine/graphics3/pose/query_entity_node_world_pose.js +74 -101
  50. package/src/engine/physics/cloth/MEASUREMENTS.md +1287 -4
  51. package/src/engine/physics/cloth/PLAN.md +1967 -1581
  52. package/src/engine/physics/cloth/build/ClothProxy.d.ts +147 -0
  53. package/src/engine/physics/cloth/build/ClothProxy.d.ts.map +1 -0
  54. package/src/engine/physics/cloth/build/ClothProxy.js +207 -0
  55. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +70 -0
  56. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -0
  57. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +256 -0
  58. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +176 -0
  59. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -0
  60. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +435 -0
  61. package/src/engine/physics/cloth/collider/ClothColliderKind.d.ts +12 -0
  62. package/src/engine/physics/cloth/collider/ClothColliderKind.d.ts.map +1 -0
  63. package/src/engine/physics/cloth/collider/ClothColliderKind.js +38 -0
  64. package/src/engine/physics/cloth/collider/ClothColliderRecord.d.ts +120 -0
  65. package/src/engine/physics/cloth/collider/ClothColliderRecord.d.ts.map +1 -0
  66. package/src/engine/physics/cloth/collider/ClothColliderRecord.js +137 -0
  67. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts +25 -0
  68. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts.map +1 -0
  69. package/src/engine/physics/cloth/collider/cloth_collider_bounds.js +190 -0
  70. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts +44 -0
  71. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts.map +1 -0
  72. package/src/engine/physics/cloth/collider/cloth_collider_pack.js +173 -0
  73. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts +94 -0
  74. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts.map +1 -0
  75. package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +275 -0
  76. package/src/engine/physics/cloth/ecs/ClothCollider.d.ts +126 -0
  77. package/src/engine/physics/cloth/ecs/ClothCollider.d.ts.map +1 -0
  78. package/src/engine/physics/cloth/ecs/ClothCollider.js +199 -0
  79. package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts +9 -0
  80. package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts.map +1 -0
  81. package/src/engine/physics/cloth/ecs/ClothColliderFlags.js +32 -0
  82. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +114 -0
  83. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -0
  84. package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +243 -0
  85. package/src/engine/physics/cloth/ecs/ClothDynamicsFlags.js +66 -57
  86. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +109 -1
  87. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  88. package/src/engine/physics/cloth/ecs/ClothInstance.js +479 -363
  89. package/src/engine/physics/cloth/ecs/ClothRig.d.ts +95 -0
  90. package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -0
  91. package/src/engine/physics/cloth/ecs/ClothRig.js +140 -0
  92. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +30 -1
  93. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  94. package/src/engine/physics/cloth/ecs/ClothSystem.js +1021 -773
  95. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +90 -0
  96. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -0
  97. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +374 -0
  98. package/src/engine/physics/cloth/ecs/cloth_dynamics_library.d.ts +32 -3
  99. package/src/engine/physics/cloth/ecs/cloth_dynamics_library.d.ts.map +1 -1
  100. package/src/engine/physics/cloth/ecs/cloth_dynamics_library.js +283 -254
  101. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +59 -0
  102. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -0
  103. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +328 -0
  104. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts +13 -0
  105. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -0
  106. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +288 -0
  107. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +58 -0
  108. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -0
  109. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +199 -0
  110. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +8 -63
  111. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  112. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +317 -645
  113. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +61 -0
  114. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  115. package/src/engine/physics/cloth/ecs/cloth_write_back.js +212 -449
  116. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts +49 -0
  117. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -0
  118. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +115 -0
  119. package/src/engine/physics/cloth/playground/README.md +155 -1
  120. package/src/engine/physics/cloth/playground/collide.html +178 -0
  121. package/src/engine/physics/cloth/playground/collide_build.d.ts +95 -0
  122. package/src/engine/physics/cloth/playground/collide_build.d.ts.map +1 -0
  123. package/src/engine/physics/cloth/playground/collide_build.js +315 -0
  124. package/src/engine/physics/cloth/playground/collide_main.d.ts +2 -0
  125. package/src/engine/physics/cloth/playground/collide_main.d.ts.map +1 -0
  126. package/src/engine/physics/cloth/playground/collide_main.js +720 -0
  127. package/src/engine/physics/cloth/playground/garment.html +182 -0
  128. package/src/engine/physics/cloth/playground/garment_build.d.ts +78 -0
  129. package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -0
  130. package/src/engine/physics/cloth/playground/garment_build.js +359 -0
  131. package/src/engine/physics/cloth/playground/garment_main.d.ts +2 -0
  132. package/src/engine/physics/cloth/playground/garment_main.d.ts.map +1 -0
  133. package/src/engine/physics/cloth/playground/garment_main.js +633 -0
  134. package/src/engine/physics/cloth/solver/ClothState.d.ts +208 -5
  135. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  136. package/src/engine/physics/cloth/solver/ClothState.js +302 -8
  137. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +87 -0
  138. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -0
  139. package/src/engine/physics/cloth/solver/cloth_contact_find.js +343 -0
  140. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts +112 -0
  141. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -0
  142. package/src/engine/physics/cloth/solver/cloth_self_find.js +448 -0
  143. package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts +4 -1
  144. package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts.map +1 -1
  145. package/src/engine/physics/cloth/solver/cloth_solve_vertex.js +16 -1
  146. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +112 -5
  147. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  148. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +117 -6
  149. package/src/engine/physics/cloth/solver/cloth_step.d.ts +40 -9
  150. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  151. package/src/engine/physics/cloth/solver/cloth_step.js +122 -10
  152. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +95 -0
  153. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -0
  154. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +285 -0
  155. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts +129 -0
  156. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts.map +1 -0
  157. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.js +501 -0
  158. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts +75 -0
  159. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -0
  160. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +202 -0
  161. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  162. package/src/shade/playground/vgeo_viewer/README.md +18 -0
  163. package/src/shade/playground/vgeo_viewer/main.js +87 -50
  164. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
  165. package/src/shade/renderer/buffer/table/GPUDatabase.js +191 -62
  166. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts +94 -2
  167. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
  168. package/src/shade/renderer/buffer/table/GPUTypedTable.js +414 -2
  169. package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.d.ts +14 -0
  170. package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.d.ts.map +1 -0
  171. package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.js +13 -0
  172. package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.d.ts +17 -0
  173. package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.d.ts.map +1 -0
  174. package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.js +116 -0
  175. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +9 -4
  176. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  177. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +843 -734
  178. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts +12 -0
  179. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts.map +1 -1
  180. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.js +13 -0
  181. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +17 -0
  182. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  183. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +185 -30
  184. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +17 -0
  185. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +141 -24
  186. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +204 -64
  187. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +110 -10
  188. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +19 -0
  189. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +19 -6
  190. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
  191. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +26 -7
  192. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +173 -14
  193. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
  194. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +458 -51
  195. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +49 -13
  196. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
  197. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +52 -14
  198. package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.d.ts +20 -0
  199. package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.d.ts.map +1 -0
  200. package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.js +19 -0
  201. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.d.ts +27 -0
  202. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.d.ts.map +1 -0
  203. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.js +48 -0
  204. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.d.ts +29 -0
  205. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.d.ts.map +1 -0
  206. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.js +60 -0
  207. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +8 -1
  208. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
  209. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +32 -2
  210. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts +258 -0
  211. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts.map +1 -0
  212. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +723 -0
  213. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts +49 -0
  214. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts.map +1 -0
  215. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +50 -0
  216. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  217. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  218. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts +3 -0
  219. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts.map +1 -1
  220. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.js +121 -21
  221. package/src/shade/renderer/texture/virtual/README.md +6 -4
  222. package/src/shade/renderer/texture/virtual/VirtualTextureManager.d.ts.map +1 -1
  223. package/src/shade/renderer/texture/virtual/VirtualTextureManager.js +7 -0
  224. package/src/shade/renderer/texture/virtual/source/VTSourceTiled.d.ts +3 -3
  225. package/src/shade/renderer/texture/virtual/source/VTSourceTiled.js +3 -3
  226. package/src/engine/ecs/system/SystemExecutionPhase.d.ts +0 -9
  227. package/src/engine/ecs/system/SystemExecutionPhase.d.ts.map +0 -1
  228. package/src/engine/graphics/texture/virtual/NOTES.md +0 -128
  229. package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.d.ts +0 -6
  230. package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.d.ts.map +0 -1
  231. package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.js +0 -5
  232. package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.d.ts +0 -49
  233. package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.d.ts.map +0 -1
  234. package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.js +0 -264
  235. package/src/engine/graphics/texture/virtual/VirtualTextureUsage.d.ts +0 -44
  236. package/src/engine/graphics/texture/virtual/VirtualTextureUsage.d.ts.map +0 -1
  237. package/src/engine/graphics/texture/virtual/VirtualTextureUsage.js +0 -228
  238. package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.d.ts +0 -3
  239. package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.d.ts.map +0 -1
  240. package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.js +0 -73
  241. package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.d.ts +0 -14
  242. package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.d.ts.map +0 -1
  243. package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.js +0 -85
  244. package/src/engine/graphics/texture/virtual/debug/UsageDebugView.d.ts +0 -12
  245. package/src/engine/graphics/texture/virtual/debug/UsageDebugView.d.ts.map +0 -1
  246. package/src/engine/graphics/texture/virtual/debug/UsageDebugView.js +0 -63
  247. package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.d.ts +0 -12
  248. package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.d.ts.map +0 -1
  249. package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.js +0 -243
  250. package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.d.ts +0 -30
  251. package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.d.ts.map +0 -1
  252. package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.js +0 -39
  253. package/src/engine/graphics/texture/virtual/tile/compose_finger_print.d.ts +0 -9
  254. package/src/engine/graphics/texture/virtual/tile/compose_finger_print.d.ts.map +0 -1
  255. package/src/engine/graphics/texture/virtual/tile/compose_finger_print.js +0 -24
  256. package/src/engine/graphics/texture/virtual/tile/compose_tile_address.d.ts +0 -9
  257. package/src/engine/graphics/texture/virtual/tile/compose_tile_address.d.ts.map +0 -1
  258. package/src/engine/graphics/texture/virtual/tile/compose_tile_address.js +0 -26
  259. package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.d.ts +0 -11
  260. package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.d.ts.map +0 -1
  261. package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.js +0 -12
  262. package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.d.ts +0 -7
  263. package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.d.ts.map +0 -1
  264. package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.js +0 -16
  265. package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.d.ts +0 -7
  266. package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.d.ts.map +0 -1
  267. package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.js +0 -35
@@ -0,0 +1,448 @@
1
+ import { PointHashGrid3 } from "../../../../core/geom/3d/hash-grid/PointHashGrid3.js";
2
+
3
+ /**
4
+ * # Finding the self-collision pairs, once per step
5
+ *
6
+ * A uniform hash grid over the particles in the cloth's own frame, then for each
7
+ * particle the ones near it that are not already governed by a row. Rebuilt
8
+ * whole every step, exactly like the contact set (`cloth_contact_find.js`) and
9
+ * for the same reasons: one pass in a fixed order, so the step is deterministic.
10
+ *
11
+ * ## Adjacent pairs are excluded, and "adjacent" means "shares a row"
12
+ *
13
+ * §9: "Pairs sharing a triangle or an edge are excluded, since they are already
14
+ * governed by stretch and bend rows and would otherwise fight them." The exact
15
+ * form of that here is **sharing any row at all** — a stretch row, a bend
16
+ * stencil, or a chain's skip row, which is a stretch row too. Two particles a
17
+ * stretch row already holds at 5 cm do not also need a repulsion telling them to
18
+ * be 8 mm apart, and a bend stencil's four particles are a fold the bend row is
19
+ * the model of.
20
+ *
21
+ * The exclusion set is built **once, at seed**, from the row tables the state
22
+ * already carries: `cloth_self_exclusions` walks them and produces a sorted CSR
23
+ * list per particle. Testing a candidate is then a short scan over a handful of
24
+ * neighbours, which at typical garment topology is 16.8 entries a particle
25
+ * (`MEASUREMENTS.md` §8) — small enough that a scan beats a hash.
26
+ *
27
+ * ## The cell is the row's own diameter, and that fixes the neighbourhood
28
+ *
29
+ * Two particles interact when they are closer than `2·self_radius`, so a cell of
30
+ * exactly that makes the 27-cell walk necessary and sufficient. A larger cell
31
+ * would visit more candidates for nothing; a smaller one would need a wider
32
+ * walk, which is the same candidates through more buckets.
33
+ *
34
+ * **That radius is the proxy's resolution rather than the fabric's thickness**,
35
+ * and `ClothState#self_radius` carries why.
36
+ *
37
+ * @author Alex Goldring
38
+ * @copyright Company Named Limited (c) 2026
39
+ */
40
+
41
+ /**
42
+ * Pairs one particle may **originate**, before the rest are dropped.
43
+ *
44
+ * A particle in a fold has a few neighbours across the fold and a few along it;
45
+ * eight is generous for a garment and is what bounds the pair list so a cloth
46
+ * that crumples into a ball cannot allocate its way out of a frame budget. A
47
+ * particle at the limit keeps the eight it found first in grid order, which is
48
+ * arbitrary among equals — and they are equals, because every one of them is
49
+ * inside the same radius.
50
+ *
51
+ * **"Originate", not "is in".** The search emits a pair once, from its lower
52
+ * index, so this caps how many pairs a particle starts and not how many it ends
53
+ * up in: a particle can be the *higher* index of any number of them. What the
54
+ * cap does bound exactly — and the only thing `ClothState` needs it to — is the
55
+ * length of the whole list, at this many per particle, because every pair is
56
+ * charged to exactly one of its two ends.
57
+ * @type {number}
58
+ */
59
+ export const CLOTH_SELF_PAIRS_PER_PARTICLE = 8;
60
+
61
+ /**
62
+ * Build the exclusion lists from a state's persistent rows.
63
+ *
64
+ * @param {ClothState} state
65
+ * @returns {{offset: Int32Array, partner: Int32Array}} CSR, sorted within each particle
66
+ */
67
+ export function cloth_self_exclusions(state) {
68
+ const particle_count = state.particle_count;
69
+
70
+ /** @type {Set<number>[]} */
71
+ const sets = new Array(particle_count);
72
+
73
+ for (let i = 0; i < particle_count; i++) {
74
+ sets[i] = new Set();
75
+ }
76
+
77
+ /**
78
+ * @param {number} a
79
+ * @param {number} b
80
+ */
81
+ const link = (a, b) => {
82
+ if (a === b) {
83
+ return;
84
+ }
85
+
86
+ sets[a].add(b);
87
+ sets[b].add(a);
88
+ };
89
+
90
+ for (let row = 0; row < state.stretch_count; row++) {
91
+ link(state.stretch_particle[row * 2], state.stretch_particle[row * 2 + 1]);
92
+ }
93
+
94
+ for (let row = 0; row < state.bend_count; row++) {
95
+ const base = row * 4;
96
+
97
+ for (let a = 0; a < 4; a++) {
98
+ for (let b = a + 1; b < 4; b++) {
99
+ link(state.bend_particle[base + a], state.bend_particle[base + b]);
100
+ }
101
+ }
102
+ }
103
+
104
+ const offset = new Int32Array(particle_count + 1);
105
+
106
+ let total = 0;
107
+
108
+ for (let i = 0; i < particle_count; i++) {
109
+ total += sets[i].size;
110
+
111
+ offset[i + 1] = total;
112
+ }
113
+
114
+ const partner = new Int32Array(total);
115
+
116
+ for (let i = 0; i < particle_count; i++) {
117
+ const sorted = Array.from(sets[i]).sort((a, b) => a - b);
118
+
119
+ partner.set(sorted, offset[i]);
120
+ }
121
+
122
+ return { offset, partner };
123
+ }
124
+
125
+ /**
126
+ * The closest two particles get **without a row between them**, in whatever pose
127
+ * the state is in.
128
+
129
+ * This is the length that decides how wide a self-collision row may be written,
130
+ * and it has to be measured rather than assumed. On a triangulated sheet it is
131
+ * two hops — one hop is a stretch row, the mesh diagonal is a stretch row, and
132
+ * the two vertices across a diagonal are a bend stencil — so it comes out at
133
+ * twice the shortest row and the analytic answer and this one agree.
134
+ *
135
+ * **A rigged garment is not a sheet and the two do not agree.** Its proxy is a
136
+ * set of *strips*, and nothing connects one strip to the next: every pair across
137
+ * the gap between two strips is ungoverned, at whatever distance the artist
138
+ * placed the joints. That distance has nothing to do with the link length along
139
+ * a strip, which is what `shortest_row` measures. On the playground's cape they
140
+ * differ by a factor of two — 8.5 cm across the gap against the 16 cm a sheet's
141
+ * topology would predict — and a ceiling derived from the link length instead of
142
+ * measured left the settled cape with three permanently active pairs.
143
+ * `MEASUREMENTS.md` §37.
144
+ *
145
+ * Pinned particles are skipped, exactly as {@link cloth_self_find} skips them,
146
+ * so this measures the pairs the row can actually act on and nothing else.
147
+ *
148
+ * @param {ClothState} state
149
+ * @param {{offset: Int32Array, partner: Int32Array}} exclusions from {@link cloth_self_exclusions}
150
+ * @param {number} search only pairs closer than this are looked for; the walk is
151
+ * bounded by it, and a proxy with nothing that close gets `Infinity` — which is
152
+ * the right answer, because then no radius inside the bound can touch anything
153
+ * @returns {number} metres, or `Infinity`
154
+ */
155
+ export function cloth_self_closest_free_pair(state, exclusions, search) {
156
+ const particle_count = state.particle_count;
157
+
158
+ if (!(search > 0) || particle_count < 2) {
159
+ return Infinity;
160
+ }
161
+
162
+ GRID.build(state.position, particle_count, search);
163
+
164
+ const position = state.position;
165
+ const mass_inverse = state.mass_inverse;
166
+
167
+ const offset = exclusions.offset;
168
+ const partner = exclusions.partner;
169
+
170
+ const grid_offset = GRID.offset;
171
+ const grid_point = GRID.point;
172
+
173
+ const inverse = 1 / search;
174
+
175
+ // The walk is a *maybe*: two cells can hash into one bucket, so a bucket can
176
+ // hand back a point from anywhere. Without this the answer would be the
177
+ // closest ungoverned pair the table happened to collide into view, which is
178
+ // a real distance but not the one `search` was asked for.
179
+ let closest_squared = search * search;
180
+
181
+ for (let i = 0; i < particle_count; i++) {
182
+ if (mass_inverse[i] === 0) {
183
+ continue;
184
+ }
185
+
186
+ const a = i * 3;
187
+
188
+ const x = position[a];
189
+ const y = position[a + 1];
190
+ const z = position[a + 2];
191
+
192
+ const cx = Math.floor(x * inverse);
193
+ const cy = Math.floor(y * inverse);
194
+ const cz = Math.floor(z * inverse);
195
+
196
+ const exclude_start = offset[i];
197
+ const exclude_end = offset[i + 1];
198
+
199
+ let visited = 0;
200
+
201
+ for (let dz = -1; dz <= 1; dz++) {
202
+ for (let dy = -1; dy <= 1; dy++) {
203
+ for (let dx = -1; dx <= 1; dx++) {
204
+ const bucket = GRID.bucketOf(cx + dx, cy + dy, cz + dz);
205
+
206
+ let seen = false;
207
+
208
+ for (let v = 0; v < visited; v++) {
209
+ if (VISITED[v] === bucket) {
210
+ seen = true;
211
+
212
+ break;
213
+ }
214
+ }
215
+
216
+ if (seen) {
217
+ continue;
218
+ }
219
+
220
+ VISITED[visited++] = bucket;
221
+
222
+ const end = grid_offset[bucket + 1];
223
+
224
+ for (let at = grid_offset[bucket]; at < end; at++) {
225
+ const j = grid_point[at];
226
+
227
+ if (j <= i || mass_inverse[j] === 0) {
228
+ continue;
229
+ }
230
+
231
+ const b = j * 3;
232
+
233
+ const ddx = x - position[b];
234
+ const ddy = y - position[b + 1];
235
+ const ddz = z - position[b + 2];
236
+
237
+ const distance_squared = ddx * ddx + ddy * ddy + ddz * ddz;
238
+
239
+ if (distance_squared >= closest_squared) {
240
+ continue;
241
+ }
242
+
243
+ let excluded = false;
244
+
245
+ for (let e = exclude_start; e < exclude_end; e++) {
246
+ if (partner[e] === j) {
247
+ excluded = true;
248
+
249
+ break;
250
+ }
251
+
252
+ if (partner[e] > j) {
253
+ break;
254
+ }
255
+ }
256
+
257
+ if (excluded) {
258
+ continue;
259
+ }
260
+
261
+ closest_squared = distance_squared;
262
+ }
263
+ }
264
+ }
265
+ }
266
+ }
267
+
268
+ return closest_squared === search * search ? Infinity : Math.sqrt(closest_squared);
269
+ }
270
+
271
+ /**
272
+ * Rebuild the pair list.
273
+ *
274
+ * @param {ClothState} state pairs written into `self_pair`, count into `self_count`
275
+ * @param {{offset: Int32Array, partner: Int32Array}} exclusions from {@link cloth_self_exclusions}
276
+ * @returns {number} how many pairs were found
277
+ */
278
+ export function cloth_self_find(state, exclusions) {
279
+ const particle_count = state.particle_count;
280
+
281
+ const radius = state.self_radius * 2;
282
+
283
+ if (radius <= 0) {
284
+ state.self_count = 0;
285
+
286
+ return 0;
287
+ }
288
+
289
+ GRID.build(state.position, particle_count, radius);
290
+
291
+ const position = state.position;
292
+ const mass_inverse = state.mass_inverse;
293
+
294
+ const pair = state.self_pair;
295
+
296
+ const capacity = pair.length / 2;
297
+
298
+ const offset = exclusions.offset;
299
+ const partner = exclusions.partner;
300
+
301
+ let count = 0;
302
+
303
+ const grid_offset = GRID.offset;
304
+ const grid_point = GRID.point;
305
+
306
+ const inverse = 1 / radius;
307
+
308
+ const radius_squared = radius * radius;
309
+
310
+ for (let i = 0; i < particle_count; i++) {
311
+ if (mass_inverse[i] === 0) {
312
+ // A pinned particle cannot be pushed, so a pair on it is a force
313
+ // assembled and thrown away for one end and doubled for the other.
314
+ continue;
315
+ }
316
+
317
+ const a = i * 3;
318
+
319
+ const x = position[a];
320
+ const y = position[a + 1];
321
+ const z = position[a + 2];
322
+
323
+ const cx = Math.floor(x * inverse);
324
+ const cy = Math.floor(y * inverse);
325
+ const cz = Math.floor(z * inverse);
326
+
327
+ const exclude_start = offset[i];
328
+ const exclude_end = offset[i + 1];
329
+
330
+ let found = 0;
331
+
332
+ let visited = 0;
333
+
334
+ for (let dz = -1; dz <= 1 && found < CLOTH_SELF_PAIRS_PER_PARTICLE; dz++) {
335
+ for (let dy = -1; dy <= 1 && found < CLOTH_SELF_PAIRS_PER_PARTICLE; dy++) {
336
+ for (let dx = -1; dx <= 1 && found < CLOTH_SELF_PAIRS_PER_PARTICLE; dx++) {
337
+ const bucket = GRID.bucketOf(cx + dx, cy + dy, cz + dz);
338
+
339
+ let seen = false;
340
+
341
+ for (let v = 0; v < visited; v++) {
342
+ if (VISITED[v] === bucket) {
343
+ seen = true;
344
+
345
+ break;
346
+ }
347
+ }
348
+
349
+ if (seen) {
350
+ continue;
351
+ }
352
+
353
+ VISITED[visited++] = bucket;
354
+
355
+ const end = grid_offset[bucket + 1];
356
+
357
+ for (let at = grid_offset[bucket]; at < end; at++) {
358
+ const j = grid_point[at];
359
+
360
+ // Each pair once, and never a particle against itself.
361
+ // The `j > i` test is what halves the work and it is also
362
+ // what makes the list order a function of the particle
363
+ // numbering rather than of the grid's.
364
+ if (j <= i) {
365
+ continue;
366
+ }
367
+
368
+ if (mass_inverse[j] === 0) {
369
+ continue;
370
+ }
371
+
372
+ const b = j * 3;
373
+
374
+ const ddx = x - position[b];
375
+ const ddy = y - position[b + 1];
376
+ const ddz = z - position[b + 2];
377
+
378
+ if (ddx * ddx + ddy * ddy + ddz * ddz >= radius_squared) {
379
+ continue;
380
+ }
381
+
382
+ let excluded = false;
383
+
384
+ for (let e = exclude_start; e < exclude_end; e++) {
385
+ if (partner[e] === j) {
386
+ excluded = true;
387
+
388
+ break;
389
+ }
390
+
391
+ if (partner[e] > j) {
392
+ // Sorted, so nothing further can match.
393
+ break;
394
+ }
395
+ }
396
+
397
+ if (excluded) {
398
+ continue;
399
+ }
400
+
401
+ if (count >= capacity) {
402
+ // The list is full. Dropping the rest is bounded and
403
+ // visible — `ClothInstance#self_count` against the
404
+ // capacity says so — and is the alternative to a
405
+ // crumpled garment growing an allocation per frame.
406
+ state.self_count = count;
407
+
408
+ return count;
409
+ }
410
+
411
+ pair[count * 2] = i;
412
+ pair[count * 2 + 1] = j;
413
+
414
+ count++;
415
+ found++;
416
+
417
+ if (found >= CLOTH_SELF_PAIRS_PER_PARTICLE) {
418
+ break;
419
+ }
420
+ }
421
+ }
422
+ }
423
+ }
424
+ }
425
+
426
+ state.self_count = count;
427
+
428
+ return count;
429
+ }
430
+
431
+ /**
432
+ * The grid, module-level and reused across every cloth and by both of the walks
433
+ * in this file. One cloth is stepped at a time and neither walk outlives its own
434
+ * call — {@link cloth_self_find} runs before the step and
435
+ * {@link cloth_self_closest_free_pair} runs once at seed — so a grid per instance
436
+ * would be one allocation per garment for no benefit. Neither may call the other.
437
+ * @type {PointHashGrid3}
438
+ * @private
439
+ */
440
+ const GRID = new PointHashGrid3();
441
+
442
+ /**
443
+ * Buckets the 27-cell walk has already visited, shared by both walks for the
444
+ * same reason {@link GRID} is: at most 27, never nested.
445
+ * @type {Int32Array}
446
+ * @private
447
+ */
448
+ const VISITED = new Int32Array(27);
@@ -8,6 +8,9 @@
8
8
  * @param {ClothState} state
9
9
  * @param {number} particle
10
10
  * @param {number} inverse_h_squared `1/h²` for the substep in progress
11
+ * @param {Float32Array|Float64Array|null} [collider_table] packed colliders in
12
+ * the cloth's own frame, posed at this substep. `null` — the M0 and M1 case —
13
+ * skips the contact rows entirely rather than looping over empty slots.
11
14
  */
12
- export function cloth_solve_vertex(state: ClothState, particle: number, inverse_h_squared: number): void;
15
+ export function cloth_solve_vertex(state: ClothState, particle: number, inverse_h_squared: number, collider_table?: Float32Array | Float64Array | null): void;
13
16
  //# sourceMappingURL=cloth_solve_vertex.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cloth_solve_vertex.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_solve_vertex.js"],"names":[],"mappings":"AA6EA;;;;;;;;;;GAUG;AACH,gEAHW,MAAM,qBACN,MAAM,QAkHhB"}
1
+ {"version":3,"file":"cloth_solve_vertex.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_solve_vertex.js"],"names":[],"mappings":"AAgFA;;;;;;;;;;;;;GAaG;AACH,gEANW,MAAM,qBACN,MAAM,mBACN,YAAY,GAAC,YAAY,GAAC,IAAI,QA6HxC"}
@@ -1,6 +1,9 @@
1
1
  import { assert } from "../../../../core/assert.js";
2
+ import { cloth_backstop_accumulate } from "./constraint/cloth_backstop_row.js";
2
3
  import { cloth_bend_accumulate } from "./constraint/cloth_bend_row.js";
4
+ import { cloth_contact_accumulate } from "./constraint/cloth_contact_row.js";
3
5
  import { cloth_leash_accumulate } from "./constraint/cloth_leash_row.js";
6
+ import { cloth_self_accumulate } from "./constraint/cloth_self_row.js";
4
7
  import { cloth_stretch_accumulate } from "./constraint/cloth_stretch_row.js";
5
8
  import {
6
9
  CVA_F_X,
@@ -85,8 +88,11 @@ const ACCUMULATOR = new Float64Array(CVA_STRIDE);
85
88
  * @param {ClothState} state
86
89
  * @param {number} particle
87
90
  * @param {number} inverse_h_squared `1/h²` for the substep in progress
91
+ * @param {Float32Array|Float64Array|null} [collider_table] packed colliders in
92
+ * the cloth's own frame, posed at this substep. `null` — the M0 and M1 case —
93
+ * skips the contact rows entirely rather than looping over empty slots.
88
94
  */
89
- export function cloth_solve_vertex(state, particle, inverse_h_squared) {
95
+ export function cloth_solve_vertex(state, particle, inverse_h_squared, collider_table = null) {
90
96
  const inverse_mass = state.mass_inverse[particle];
91
97
 
92
98
  if (inverse_mass === 0) {
@@ -120,6 +126,15 @@ export function cloth_solve_vertex(state, particle, inverse_h_squared) {
120
126
  cloth_stretch_accumulate(accumulator, state, particle);
121
127
  cloth_bend_accumulate(accumulator, state, particle);
122
128
  cloth_leash_accumulate(accumulator, state, particle);
129
+ cloth_backstop_accumulate(accumulator, state, particle);
130
+
131
+ if (collider_table !== null) {
132
+ cloth_contact_accumulate(accumulator, state, particle, collider_table);
133
+ }
134
+
135
+ if (state.self_count > 0) {
136
+ cloth_self_accumulate(accumulator, state, particle);
137
+ }
123
138
 
124
139
  const a = accumulator[CVA_H_XX];
125
140
  const b = accumulator[CVA_H_XY];
@@ -49,10 +49,26 @@
49
49
  * for **transient** rows — a contact that should arrive soft and stiffen rather
50
50
  * than shock the mesh on its first frame — and M0 has none.
51
51
  *
52
- * **`β` could not be chosen from M0 data.** Above about 1e4 every M0 scenario
53
- * gives an identical answer, and with the band collapsed it has no effect at
54
- * all. The value below is a placeholder that M2 must replace with a
55
- * measurement against real contacts.
52
+ * **`β` is M2's, and it is 1e3 rather than M0's 1e5 placeholder.** M0 could not
53
+ * choose it: above about 1e4 every M0 scenario gave an identical answer, and
54
+ * with the band collapsed it had no effect at all. M2's contacts are the first
55
+ * transient rows in the system and the ramp is finally live. Measured on a
56
+ * 400-particle sheet landing on the ground, both ends of the range are worse
57
+ * than the middle: **no ramp at all** leaves a fast arrival's penalty at the
58
+ * floor and the multiplier alone to carry it, which settles at 1.95 J of
59
+ * residual kinetic energy against 0.12 J at 1e3; a **fast** ramp reaches the
60
+ * ceiling on violations of a millimetre and gives up most of what the low floor
61
+ * bought, settling three orders of magnitude worse on a gentle landing
62
+ * (6.4e-5 J against 3.2e-8 J). `MEASUREMENTS.md` §17.
63
+ *
64
+ * The scale-dependence the paragraph above warns of is real and is stated
65
+ * rather than removed: `β` has units of N/m², so it is a stiffness *per metre
66
+ * of violation*, and 1e3 against a ceiling of `8·(m/h²)` means the ramp is
67
+ * inert for a millimetre of penetration and reaches the ceiling within a step
68
+ * for a decimetre of it. That shape — gentle where the contact is grazing,
69
+ * immediate where it is a real interpenetration — is what the measurement
70
+ * picked, and a ratio-valued `β` that removed the dependence would have to
71
+ * choose the reference length that shape is built out of.
56
72
  *
57
73
  * @author Alex Goldring
58
74
  * @copyright Company Named Limited (c) 2026
@@ -63,7 +79,8 @@
63
79
  */
64
80
  export const CLOTH_ALPHA: number;
65
81
  /**
66
- * Penalty ramp.
82
+ * Penalty ramp, N/m². See the module docblock — measured at M2, against the
83
+ * first transient rows the system has.
67
84
  * @type {number}
68
85
  */
69
86
  export const CLOTH_BETA: number;
@@ -82,6 +99,96 @@ export const CLOTH_K_MIN_RATIO: number;
82
99
  * @type {number}
83
100
  */
84
101
  export const CLOTH_K_MAX_RATIO: number;
102
+ /**
103
+ * Penalty floor for a **contact** row, as a multiple of the row's `m/h²`.
104
+ *
105
+ * Separate from {@link CLOTH_K_MIN_RATIO}, which is pinned to the ceiling,
106
+ * because a contact is the one row kind that *arrives*: a persistent row has
107
+ * been converging since the cloth was seeded and wants the stiffest penalty the
108
+ * step is stable at, and a contact that starts there shocks the mesh on its
109
+ * first frame.
110
+ *
111
+ * **A thirty-second of the ceiling**, measured. The floor is what decides how
112
+ * hard a new contact hits, and the measurement is unambiguous about the
113
+ * direction: on a sheet landing at 3 m/s, the peak contact force falls from
114
+ * 18.9 N at the ceiling to 0.16 N at an eighth of it and the settled kinetic
115
+ * energy falls by six orders of magnitude, while the penetration *improves*
116
+ * from 1.6 cm to 1.1 cm. Below about an eighth the numbers stop moving — every
117
+ * floor from ×1/8 down to ×1/128 gives the same penetration to three figures —
118
+ * so the value is a margin decision the same way `α·γ` was, and ×1/32 sits in
119
+ * the middle of the flat region with two decades of ramp above it.
120
+ *
121
+ * The reason the floor matters so little to the *residual* is the augmented
122
+ * Lagrangian working as designed: the multiplier carries the load and the
123
+ * penalty only has to be large enough to generate one. See MEASUREMENTS §17.
124
+ * @type {number}
125
+ */
126
+ export const CLOTH_CONTACT_K_MIN_RATIO: number;
127
+ /**
128
+ * Penalty stiffness for a **self-collision** row, as a multiple of the row's
129
+ * own `m_eff/h²`.
130
+ *
131
+ * It is a plain penalty rather than a hard row because the load it carries is
132
+ * cloth against cloth. `MEASUREMENTS.md` §18 measured why a *collider* contact
133
+ * cannot be soft — 376 N for a sheet arriving at 8 m/s against the 4.6 N a soft
134
+ * row inside M0's dissipative band can deliver — and a self-collision row never
135
+ * sees anything of the kind: what it holds apart weighs grams and is moving at
136
+ * the speed cloth moves relative to itself.
137
+ *
138
+ * **Eight, and the dissipative band is not the reason.** Eight is where M0's
139
+ * band tops out and it would be natural to read this as the same ceiling, but
140
+ * `MEASUREMENTS.md` §32 swept the ratio from 1 to 64 and found no energy growth
141
+ * anywhere: the band was measured on rows that are *on every step*, and a
142
+ * one-sided row that vanishes the instant it is satisfied has no standing spring
143
+ * to pump. What picks eight is the crossing count — it is the joint minimum of
144
+ * the mean, and a stiffer row makes the *worst* case steadily worse by throwing
145
+ * a particle hard enough to put the sheet through itself elsewhere.
146
+ *
147
+ * The consequence is a row with no multiplier, no warm start and no identity
148
+ * across steps, which is what makes rebuilding the pair list from scratch every
149
+ * step affordable. `MEASUREMENTS.md` §33.
150
+ * @type {number}
151
+ */
152
+ export const CLOTH_SELF_RATIO: number;
153
+ /**
154
+ * Smallest radius a self-collision row is written at, as a multiple of the
155
+ * cloth's shortest row — so the row's **diameter** is one particle spacing.
156
+ *
157
+ * `ClothState#self_radius` carries why the radius is a property of the proxy
158
+ * rather than of the fabric, and `MEASUREMENTS.md` §31 is the sweep: at the
159
+ * fabric's own thickness the row removes 21% of a folding sheet's
160
+ * self-intersections and here it removes 82%.
161
+ * @type {number}
162
+ */
163
+ export const CLOTH_SELF_RADIUS_MIN_RATIO: number;
164
+ /**
165
+ * Largest radius a self-collision row is written at, as a fraction of the
166
+ * closest two particles get **with no row between them** in the bind pose —
167
+ * `ClothInstance#closest_free_pair`. Two fifths of it, so the row's diameter is
168
+ * four fifths of the nearest thing it could touch and a cloth at rest is never
169
+ * in contact with itself.
170
+ *
171
+ * **A ceiling is needed because the floor is not always reachable.** A thick
172
+ * fabric on a coarse proxy takes its thickness rather than
173
+ * {@link CLOTH_SELF_RADIUS_MIN_RATIO}, and a diameter that reaches the nearest
174
+ * ungoverned pair puts a cloth that is not folded at all in permanent contact
175
+ * with itself — leather, 20 mm thick on a 20 mm proxy, found 1,398 pairs a step
176
+ * across 576 particles standing still. `MEASUREMENTS.md` §36.
177
+ *
178
+ * **And it is measured rather than derived, because a garment is not a sheet.**
179
+ * On a triangulated sheet the closest ungoverned pair is exactly two hops, so
180
+ * this comes out at four fifths of the shortest row and the analytic answer
181
+ * would have done — checked at two spacings, to the precision the proxy's
182
+ * Float32 positions carry. A rigged
183
+ * garment's proxy is *strips* with nothing joining one to the next, so every
184
+ * pair across the gap is ungoverned at whatever distance the artist put the
185
+ * joints, which the shortest row knows nothing about: the playground's cape has
186
+ * 8 cm links and 8.5 cm gaps, half what a sheet would imply. Derived from the
187
+ * link length the ceiling left that cape with three pairs permanently in
188
+ * contact at rest; measured, it has none. `MEASUREMENTS.md` §37.
189
+ * @type {number}
190
+ */
191
+ export const CLOTH_SELF_RADIUS_MAX_RATIO: number;
85
192
  /**
86
193
  * The five constants as one frozen object, which is what {@link cloth_step}
87
194
  * takes. A sweep passes its own; nothing else should.
@@ -1 +1 @@
1
- {"version":3,"file":"cloth_solver_constants.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_solver_constants.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AAEH;;;GAGG;AACH,0BAFU,MAAM,CAEgB;AAEhC;;;GAGG;AACH,yBAFU,MAAM,CAEc;AAE9B;;;GAGG;AACH,0BAFU,MAAM,CAEa;AAE7B;;;GAGG;AACH,gCAFU,MAAM,CAEmB;AAEnC;;;GAGG;AACH,gCAFU,MAAM,CAEmB;AAEnC;;;;GAIG;AACH,kCAFU,SAAS;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,CAAC,CAQvG"}
1
+ {"version":3,"file":"cloth_solver_constants.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_solver_constants.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0EG;AAEH;;;GAGG;AACH,0BAFU,MAAM,CAEgB;AAEhC;;;;GAIG;AACH,yBAFU,MAAM,CAEc;AAE9B;;;GAGG;AACH,0BAFU,MAAM,CAEa;AAE7B;;;GAGG;AACH,gCAFU,MAAM,CAEmB;AAEnC;;;GAGG;AACH,gCAFU,MAAM,CAEmB;AAEnC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wCAFU,MAAM,CAE8B;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,+BAFU,MAAM,CAEkB;AAElC;;;;;;;;;GASG;AACH,0CAFU,MAAM,CAE+B;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,0CAFU,MAAM,CAE+B;AAE/C;;;;GAIG;AACH,kCAFU,SAAS;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,CAAC,CAQvG"}