@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,87 @@
1
+ /**
2
+ * Rebuild every particle's contact slots against the packed collider table.
3
+ *
4
+ * The table is expected to be posed at the **end** of the step —
5
+ * {@link cloth_collider_pose_at} at `t = 1` — because that is where the
6
+ * colliders will be when the last substep runs, and a contact discovered
7
+ * against where a collider *was* is a contact behind the thing it is meant to
8
+ * stop. This function poses it there itself, so the caller cannot get it wrong,
9
+ * and leaves it there for the first substep to overwrite.
10
+ *
11
+ * @param {ClothState} state
12
+ * @param {Float32Array|Float64Array} table packed colliders, cloth-local
13
+ * @param {Int32Array} keys index handle per record in `table`
14
+ * @param {number} count records in `table`
15
+ * @returns {number} how many contact rows were created
16
+ */
17
+ export function cloth_contact_find(state: ClothState, table: Float32Array | Float64Array, keys: Int32Array, count: number): number;
18
+ /**
19
+ * # Finding the contacts, once per step
20
+ *
21
+ * Which particles are in contact with which colliders is decided **once per
22
+ * fixed step**, not per substep and not per iteration, and that is a design
23
+ * commitment rather than an optimisation. Three things fall out of it:
24
+ *
25
+ * - **The step is deterministic.** The set is built by one pass in a fixed
26
+ * order over a fixed table, so the same inputs produce the same rows in the
27
+ * same order — which is what §12's bit-parity gate between the main thread
28
+ * and the worker is going to be held to.
29
+ * - **A multiplier has something to be warm-started against.** A row that
30
+ * appeared and vanished within a step would have no history to carry, and a
31
+ * contact whose multiplier starts at zero every iteration is a contact that
32
+ * never becomes hard.
33
+ * - **The cost is bounded and known.** One broadphase pass per particle per
34
+ * step, against a table that has already been narrowed to the colliders
35
+ * overlapping this cloth.
36
+ *
37
+ * ## Speculative contacts, and the collider's own travel
38
+ *
39
+ * A row is created while the particle is still {@link CLOTH_CONTACT_MARGIN}
40
+ * radii clear of the surface, and stays inactive — clamped out, costing a field
41
+ * evaluation and nothing else — until it is actually touching. That is what
42
+ * makes a contact decided once per step safe: a particle approaching at speed
43
+ * has a row waiting for it, rather than arriving inside a collider that nothing
44
+ * is watching. Without the margin the discovery pass would have to run per
45
+ * substep, which is the cost this structure exists to avoid.
46
+ *
47
+ * **The margin has to include how far the collider moved**, and M2 got this
48
+ * wrong before it got it right. Discovery evaluates the field at the end-of-step
49
+ * pose; a collider that crossed the cloth *within* the step is nowhere near it
50
+ * by then, so a fixed margin finds nothing and the swept poses of §8.2 have no
51
+ * rows to act through. Measured on a capsule driven through a hanging sheet: at
52
+ * 20 m/s the pass produced **zero contact rows**, and the sheet was untouched —
53
+ * not tunnelled through so much as never noticed. Adding the collider's travel
54
+ * to the reach costs one subtraction per record per step and makes the whole
55
+ * range from 2 to 40 m/s behave the same way. `MEASUREMENTS.md` §20.
56
+ *
57
+ * That is also the honest boundary of P3's "swept collision": the *set* is
58
+ * swept by this margin, and the *poses* are swept by `cloth_collider_pose_at`.
59
+ * Both are translation-first — a collider spinning fast enough that a point on
60
+ * its surface travels more than its own radius within one substep is still
61
+ * missed, and more substeps is the answer to that.
62
+ *
63
+ * ## Warm-starting across the rebuild
64
+ *
65
+ * Slots are keyed on the collider's **handle in the index**, which is stable
66
+ * across a rebuild in a way the record index in the per-cloth table is not — the
67
+ * table is whatever this step's broadphase returned, in whatever order. A slot
68
+ * whose key survives keeps its multipliers and its friction anchor; one that
69
+ * does not starts cold. A collider that leaves the index takes its contacts
70
+ * with it, which is correct: the surface the multiplier described is gone.
71
+ *
72
+ * @author Alex Goldring
73
+ * @copyright Company Named Limited (c) 2026
74
+ */
75
+ /**
76
+ * How far clear of a surface a contact row is still created, as a multiple of
77
+ * the contact offset (`thickness + inflation`).
78
+ *
79
+ * One, so a row exists from twice the offset inwards. At a garment's 8 mm that
80
+ * is 8 mm of warning, which at 60 Hz covers half a metre a second of approach
81
+ * before a substep can carry a particle past the discovery — and a cloth moving
82
+ * faster than that relative to a collider is one the velocity clamp of §7 P1 is
83
+ * already the bound on.
84
+ * @type {number}
85
+ */
86
+ export const CLOTH_CONTACT_MARGIN: number;
87
+ //# sourceMappingURL=cloth_contact_find.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloth_contact_find.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_contact_find.js"],"names":[],"mappings":"AA8FA;;;;;;;;;;;;;;;GAeG;AACH,6DALW,YAAY,GAAC,YAAY,QACzB,UAAU,SACV,MAAM,GACJ,MAAM,CA4KlB;AAjQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAEH;;;;;;;;;;GAUG;AACH,mCAFU,MAAM,CAEsB"}
@@ -0,0 +1,343 @@
1
+ import {
2
+ CCR_AABB_MAX_X,
3
+ CCR_AABB_MAX_Y,
4
+ CCR_AABB_MAX_Z,
5
+ CCR_AABB_MIN_X,
6
+ CCR_AABB_MIN_Y,
7
+ CCR_AABB_MIN_Z,
8
+ CCR_INFLATION,
9
+ CCR_PREV_TX,
10
+ CCR_PREV_TY,
11
+ CCR_PREV_TZ,
12
+ CCR_STRIDE,
13
+ CCR_TX,
14
+ CCR_TY,
15
+ CCR_TZ
16
+ } from "../collider/ClothColliderRecord.js";
17
+ import {
18
+ cloth_collider_pose_at,
19
+ cloth_collider_signed_distance,
20
+ cloth_collider_to_local
21
+ } from "../collider/cloth_collider_sdf.js";
22
+ import { CLOTH_CONTACT_SLOTS } from "./constraint/cloth_contact_row.js";
23
+
24
+ /**
25
+ * # Finding the contacts, once per step
26
+ *
27
+ * Which particles are in contact with which colliders is decided **once per
28
+ * fixed step**, not per substep and not per iteration, and that is a design
29
+ * commitment rather than an optimisation. Three things fall out of it:
30
+ *
31
+ * - **The step is deterministic.** The set is built by one pass in a fixed
32
+ * order over a fixed table, so the same inputs produce the same rows in the
33
+ * same order — which is what §12's bit-parity gate between the main thread
34
+ * and the worker is going to be held to.
35
+ * - **A multiplier has something to be warm-started against.** A row that
36
+ * appeared and vanished within a step would have no history to carry, and a
37
+ * contact whose multiplier starts at zero every iteration is a contact that
38
+ * never becomes hard.
39
+ * - **The cost is bounded and known.** One broadphase pass per particle per
40
+ * step, against a table that has already been narrowed to the colliders
41
+ * overlapping this cloth.
42
+ *
43
+ * ## Speculative contacts, and the collider's own travel
44
+ *
45
+ * A row is created while the particle is still {@link CLOTH_CONTACT_MARGIN}
46
+ * radii clear of the surface, and stays inactive — clamped out, costing a field
47
+ * evaluation and nothing else — until it is actually touching. That is what
48
+ * makes a contact decided once per step safe: a particle approaching at speed
49
+ * has a row waiting for it, rather than arriving inside a collider that nothing
50
+ * is watching. Without the margin the discovery pass would have to run per
51
+ * substep, which is the cost this structure exists to avoid.
52
+ *
53
+ * **The margin has to include how far the collider moved**, and M2 got this
54
+ * wrong before it got it right. Discovery evaluates the field at the end-of-step
55
+ * pose; a collider that crossed the cloth *within* the step is nowhere near it
56
+ * by then, so a fixed margin finds nothing and the swept poses of §8.2 have no
57
+ * rows to act through. Measured on a capsule driven through a hanging sheet: at
58
+ * 20 m/s the pass produced **zero contact rows**, and the sheet was untouched —
59
+ * not tunnelled through so much as never noticed. Adding the collider's travel
60
+ * to the reach costs one subtraction per record per step and makes the whole
61
+ * range from 2 to 40 m/s behave the same way. `MEASUREMENTS.md` §20.
62
+ *
63
+ * That is also the honest boundary of P3's "swept collision": the *set* is
64
+ * swept by this margin, and the *poses* are swept by `cloth_collider_pose_at`.
65
+ * Both are translation-first — a collider spinning fast enough that a point on
66
+ * its surface travels more than its own radius within one substep is still
67
+ * missed, and more substeps is the answer to that.
68
+ *
69
+ * ## Warm-starting across the rebuild
70
+ *
71
+ * Slots are keyed on the collider's **handle in the index**, which is stable
72
+ * across a rebuild in a way the record index in the per-cloth table is not — the
73
+ * table is whatever this step's broadphase returned, in whatever order. A slot
74
+ * whose key survives keeps its multipliers and its friction anchor; one that
75
+ * does not starts cold. A collider that leaves the index takes its contacts
76
+ * with it, which is correct: the surface the multiplier described is gone.
77
+ *
78
+ * @author Alex Goldring
79
+ * @copyright Company Named Limited (c) 2026
80
+ */
81
+
82
+ /**
83
+ * How far clear of a surface a contact row is still created, as a multiple of
84
+ * the contact offset (`thickness + inflation`).
85
+ *
86
+ * One, so a row exists from twice the offset inwards. At a garment's 8 mm that
87
+ * is 8 mm of warning, which at 60 Hz covers half a metre a second of approach
88
+ * before a substep can carry a particle past the discovery — and a cloth moving
89
+ * faster than that relative to a collider is one the velocity clamp of §7 P1 is
90
+ * already the bound on.
91
+ * @type {number}
92
+ */
93
+ export const CLOTH_CONTACT_MARGIN = 1;
94
+
95
+ /**
96
+ * Rebuild every particle's contact slots against the packed collider table.
97
+ *
98
+ * The table is expected to be posed at the **end** of the step —
99
+ * {@link cloth_collider_pose_at} at `t = 1` — because that is where the
100
+ * colliders will be when the last substep runs, and a contact discovered
101
+ * against where a collider *was* is a contact behind the thing it is meant to
102
+ * stop. This function poses it there itself, so the caller cannot get it wrong,
103
+ * and leaves it there for the first substep to overwrite.
104
+ *
105
+ * @param {ClothState} state
106
+ * @param {Float32Array|Float64Array} table packed colliders, cloth-local
107
+ * @param {Int32Array} keys index handle per record in `table`
108
+ * @param {number} count records in `table`
109
+ * @returns {number} how many contact rows were created
110
+ */
111
+ export function cloth_contact_find(state, table, keys, count) {
112
+ const particle_count = state.particle_count;
113
+
114
+ const collider = state.contact_collider;
115
+ const key = state.contact_key;
116
+ const lambda = state.contact_lambda;
117
+ const penalty = state.contact_penalty;
118
+ const friction_lambda = state.contact_friction_lambda;
119
+ const friction_penalty = state.contact_friction_penalty;
120
+ const anchor = state.contact_anchor;
121
+
122
+ const position = state.position;
123
+ const mass_inverse = state.mass_inverse;
124
+
125
+ const radius = state.contact_radius;
126
+
127
+ if (count > TRAVEL.length) {
128
+ TRAVEL = new Float64Array(count);
129
+ }
130
+
131
+ if (count === 0) {
132
+ // Nothing to collide against. Clearing is still necessary — last step's
133
+ // slots name records in a table that no longer exists.
134
+ collider.fill(-1);
135
+ key.fill(-1);
136
+
137
+ return 0;
138
+ }
139
+
140
+ cloth_collider_pose_at(table, count, 1);
141
+
142
+ // How far each collider moved this step. A particle within this of the
143
+ // end-of-step surface is one the collider could have crossed on the way,
144
+ // and it needs a row before the substeps replay that crossing.
145
+ for (let record = 0; record < count; record++) {
146
+ const r = record * CCR_STRIDE;
147
+
148
+ TRAVEL[record] = Math.hypot(
149
+ table[r + CCR_TX] - table[r + CCR_PREV_TX],
150
+ table[r + CCR_TY] - table[r + CCR_PREV_TY],
151
+ table[r + CCR_TZ] - table[r + CCR_PREV_TZ]
152
+ );
153
+ }
154
+
155
+ let created = 0;
156
+
157
+ for (let particle = 0; particle < particle_count; particle++) {
158
+ const base = particle * CLOTH_CONTACT_SLOTS;
159
+
160
+ // Remember what this particle had, then clear. The carry-over is a
161
+ // linear scan over at most four entries, which is why the slot count is
162
+ // small enough to make a scan the right structure.
163
+ for (let s = 0; s < CLOTH_CONTACT_SLOTS; s++) {
164
+ const slot = base + s;
165
+
166
+ PREVIOUS_KEY[s] = key[slot];
167
+ PREVIOUS_LAMBDA[s] = lambda[slot];
168
+ PREVIOUS_PENALTY[s] = penalty[slot];
169
+ PREVIOUS_FRICTION_LAMBDA[s] = friction_lambda[slot];
170
+ PREVIOUS_FRICTION_PENALTY[s] = friction_penalty[slot];
171
+ PREVIOUS_ANCHOR[s * 3] = anchor[slot * 3];
172
+ PREVIOUS_ANCHOR[s * 3 + 1] = anchor[slot * 3 + 1];
173
+ PREVIOUS_ANCHOR[s * 3 + 2] = anchor[slot * 3 + 2];
174
+
175
+ collider[slot] = -1;
176
+ key[slot] = -1;
177
+ }
178
+
179
+ if (mass_inverse[particle] === 0) {
180
+ // A pinned particle cannot be pushed anywhere, so a contact on it
181
+ // would be a row that assembles a force and throws it away.
182
+ continue;
183
+ }
184
+
185
+ const p = particle * 3;
186
+
187
+ const x = position[p];
188
+ const y = position[p + 1];
189
+ const z = position[p + 2];
190
+
191
+ let found = 0;
192
+
193
+ for (let record = 0; record < count; record++) {
194
+ const r = record * CCR_STRIDE;
195
+
196
+ const reach = (radius + table[r + CCR_INFLATION]) * (1 + CLOTH_CONTACT_MARGIN) + TRAVEL[record];
197
+
198
+ if (x + reach < table[r + CCR_AABB_MIN_X] || x - reach > table[r + CCR_AABB_MAX_X]) {
199
+ continue;
200
+ }
201
+
202
+ if (y + reach < table[r + CCR_AABB_MIN_Y] || y - reach > table[r + CCR_AABB_MAX_Y]) {
203
+ continue;
204
+ }
205
+
206
+ if (z + reach < table[r + CCR_AABB_MIN_Z] || z - reach > table[r + CCR_AABB_MAX_Z]) {
207
+ continue;
208
+ }
209
+
210
+ const distance = cloth_collider_signed_distance(NORMAL, 0, table, record, x, y, z);
211
+
212
+ if (distance > reach) {
213
+ continue;
214
+ }
215
+
216
+ // Insert, nearest first, into a list of at most CLOTH_CONTACT_SLOTS.
217
+ // The ones that fall off the end are the furthest from binding.
218
+ let at = found < CLOTH_CONTACT_SLOTS ? found : CLOTH_CONTACT_SLOTS - 1;
219
+
220
+ if (found === CLOTH_CONTACT_SLOTS && distance >= CANDIDATE_DISTANCE[at]) {
221
+ continue;
222
+ }
223
+
224
+ while (at > 0 && CANDIDATE_DISTANCE[at - 1] > distance) {
225
+ CANDIDATE_DISTANCE[at] = CANDIDATE_DISTANCE[at - 1];
226
+ CANDIDATE_RECORD[at] = CANDIDATE_RECORD[at - 1];
227
+
228
+ at--;
229
+ }
230
+
231
+ CANDIDATE_DISTANCE[at] = distance;
232
+ CANDIDATE_RECORD[at] = record;
233
+
234
+ if (found < CLOTH_CONTACT_SLOTS) {
235
+ found++;
236
+ }
237
+ }
238
+
239
+ for (let s = 0; s < found; s++) {
240
+ const slot = base + s;
241
+
242
+ const record = CANDIDATE_RECORD[s];
243
+ const handle = keys[record];
244
+
245
+ collider[slot] = record;
246
+ key[slot] = handle;
247
+
248
+ let carried = -1;
249
+
250
+ for (let q = 0; q < CLOTH_CONTACT_SLOTS; q++) {
251
+ if (PREVIOUS_KEY[q] === handle) {
252
+ carried = q;
253
+
254
+ break;
255
+ }
256
+ }
257
+
258
+ if (carried >= 0) {
259
+ lambda[slot] = PREVIOUS_LAMBDA[carried];
260
+ penalty[slot] = PREVIOUS_PENALTY[carried];
261
+ friction_lambda[slot] = PREVIOUS_FRICTION_LAMBDA[carried];
262
+ friction_penalty[slot] = PREVIOUS_FRICTION_PENALTY[carried];
263
+ anchor[slot * 3] = PREVIOUS_ANCHOR[carried * 3];
264
+ anchor[slot * 3 + 1] = PREVIOUS_ANCHOR[carried * 3 + 1];
265
+ anchor[slot * 3 + 2] = PREVIOUS_ANCHOR[carried * 3 + 2];
266
+ } else {
267
+ lambda[slot] = 0;
268
+ penalty[slot] = 0;
269
+ friction_lambda[slot] = 0;
270
+ friction_penalty[slot] = 0;
271
+
272
+ // A new contact sticks where the particle is now.
273
+ cloth_collider_to_local(anchor, slot * 3, table, record, x, y, z);
274
+ }
275
+
276
+ created++;
277
+ }
278
+ }
279
+
280
+ return created;
281
+ }
282
+
283
+ /**
284
+ * How far each collider moved this step, in the frame the table is expressed
285
+ * in. Grown and never shrunk; only `[0, count)` is meaningful.
286
+ * @type {Float64Array}
287
+ * @private
288
+ */
289
+ let TRAVEL = new Float64Array(0);
290
+
291
+ /**
292
+ * @type {Float64Array}
293
+ * @private
294
+ */
295
+ const NORMAL = new Float64Array(3);
296
+
297
+ /**
298
+ * @type {Float64Array}
299
+ * @private
300
+ */
301
+ const CANDIDATE_DISTANCE = new Float64Array(CLOTH_CONTACT_SLOTS);
302
+
303
+ /**
304
+ * @type {Int32Array}
305
+ * @private
306
+ */
307
+ const CANDIDATE_RECORD = new Int32Array(CLOTH_CONTACT_SLOTS);
308
+
309
+ /**
310
+ * @type {Int32Array}
311
+ * @private
312
+ */
313
+ const PREVIOUS_KEY = new Int32Array(CLOTH_CONTACT_SLOTS);
314
+
315
+ /**
316
+ * @type {Float32Array}
317
+ * @private
318
+ */
319
+ const PREVIOUS_LAMBDA = new Float32Array(CLOTH_CONTACT_SLOTS);
320
+
321
+ /**
322
+ * @type {Float32Array}
323
+ * @private
324
+ */
325
+ const PREVIOUS_PENALTY = new Float32Array(CLOTH_CONTACT_SLOTS);
326
+
327
+ /**
328
+ * @type {Float32Array}
329
+ * @private
330
+ */
331
+ const PREVIOUS_FRICTION_LAMBDA = new Float32Array(CLOTH_CONTACT_SLOTS);
332
+
333
+ /**
334
+ * @type {Float32Array}
335
+ * @private
336
+ */
337
+ const PREVIOUS_FRICTION_PENALTY = new Float32Array(CLOTH_CONTACT_SLOTS);
338
+
339
+ /**
340
+ * @type {Float32Array}
341
+ * @private
342
+ */
343
+ const PREVIOUS_ANCHOR = new Float32Array(CLOTH_CONTACT_SLOTS * 3);
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Build the exclusion lists from a state's persistent rows.
3
+ *
4
+ * @param {ClothState} state
5
+ * @returns {{offset: Int32Array, partner: Int32Array}} CSR, sorted within each particle
6
+ */
7
+ export function cloth_self_exclusions(state: ClothState): {
8
+ offset: Int32Array;
9
+ partner: Int32Array;
10
+ };
11
+ /**
12
+ * The closest two particles get **without a row between them**, in whatever pose
13
+ * the state is in.
14
+
15
+ * This is the length that decides how wide a self-collision row may be written,
16
+ * and it has to be measured rather than assumed. On a triangulated sheet it is
17
+ * two hops — one hop is a stretch row, the mesh diagonal is a stretch row, and
18
+ * the two vertices across a diagonal are a bend stencil — so it comes out at
19
+ * twice the shortest row and the analytic answer and this one agree.
20
+ *
21
+ * **A rigged garment is not a sheet and the two do not agree.** Its proxy is a
22
+ * set of *strips*, and nothing connects one strip to the next: every pair across
23
+ * the gap between two strips is ungoverned, at whatever distance the artist
24
+ * placed the joints. That distance has nothing to do with the link length along
25
+ * a strip, which is what `shortest_row` measures. On the playground's cape they
26
+ * differ by a factor of two — 8.5 cm across the gap against the 16 cm a sheet's
27
+ * topology would predict — and a ceiling derived from the link length instead of
28
+ * measured left the settled cape with three permanently active pairs.
29
+ * `MEASUREMENTS.md` §37.
30
+ *
31
+ * Pinned particles are skipped, exactly as {@link cloth_self_find} skips them,
32
+ * so this measures the pairs the row can actually act on and nothing else.
33
+ *
34
+ * @param {ClothState} state
35
+ * @param {{offset: Int32Array, partner: Int32Array}} exclusions from {@link cloth_self_exclusions}
36
+ * @param {number} search only pairs closer than this are looked for; the walk is
37
+ * bounded by it, and a proxy with nothing that close gets `Infinity` — which is
38
+ * the right answer, because then no radius inside the bound can touch anything
39
+ * @returns {number} metres, or `Infinity`
40
+ */
41
+ export function cloth_self_closest_free_pair(state: ClothState, exclusions: {
42
+ offset: Int32Array;
43
+ partner: Int32Array;
44
+ }, search: number): number;
45
+ /**
46
+ * Rebuild the pair list.
47
+ *
48
+ * @param {ClothState} state pairs written into `self_pair`, count into `self_count`
49
+ * @param {{offset: Int32Array, partner: Int32Array}} exclusions from {@link cloth_self_exclusions}
50
+ * @returns {number} how many pairs were found
51
+ */
52
+ export function cloth_self_find(state: ClothState, exclusions: {
53
+ offset: Int32Array;
54
+ partner: Int32Array;
55
+ }): number;
56
+ /**
57
+ * # Finding the self-collision pairs, once per step
58
+ *
59
+ * A uniform hash grid over the particles in the cloth's own frame, then for each
60
+ * particle the ones near it that are not already governed by a row. Rebuilt
61
+ * whole every step, exactly like the contact set (`cloth_contact_find.js`) and
62
+ * for the same reasons: one pass in a fixed order, so the step is deterministic.
63
+ *
64
+ * ## Adjacent pairs are excluded, and "adjacent" means "shares a row"
65
+ *
66
+ * §9: "Pairs sharing a triangle or an edge are excluded, since they are already
67
+ * governed by stretch and bend rows and would otherwise fight them." The exact
68
+ * form of that here is **sharing any row at all** — a stretch row, a bend
69
+ * stencil, or a chain's skip row, which is a stretch row too. Two particles a
70
+ * stretch row already holds at 5 cm do not also need a repulsion telling them to
71
+ * be 8 mm apart, and a bend stencil's four particles are a fold the bend row is
72
+ * the model of.
73
+ *
74
+ * The exclusion set is built **once, at seed**, from the row tables the state
75
+ * already carries: `cloth_self_exclusions` walks them and produces a sorted CSR
76
+ * list per particle. Testing a candidate is then a short scan over a handful of
77
+ * neighbours, which at typical garment topology is 16.8 entries a particle
78
+ * (`MEASUREMENTS.md` §8) — small enough that a scan beats a hash.
79
+ *
80
+ * ## The cell is the row's own diameter, and that fixes the neighbourhood
81
+ *
82
+ * Two particles interact when they are closer than `2·self_radius`, so a cell of
83
+ * exactly that makes the 27-cell walk necessary and sufficient. A larger cell
84
+ * would visit more candidates for nothing; a smaller one would need a wider
85
+ * walk, which is the same candidates through more buckets.
86
+ *
87
+ * **That radius is the proxy's resolution rather than the fabric's thickness**,
88
+ * and `ClothState#self_radius` carries why.
89
+ *
90
+ * @author Alex Goldring
91
+ * @copyright Company Named Limited (c) 2026
92
+ */
93
+ /**
94
+ * Pairs one particle may **originate**, before the rest are dropped.
95
+ *
96
+ * A particle in a fold has a few neighbours across the fold and a few along it;
97
+ * eight is generous for a garment and is what bounds the pair list so a cloth
98
+ * that crumples into a ball cannot allocate its way out of a frame budget. A
99
+ * particle at the limit keeps the eight it found first in grid order, which is
100
+ * arbitrary among equals — and they are equals, because every one of them is
101
+ * inside the same radius.
102
+ *
103
+ * **"Originate", not "is in".** The search emits a pair once, from its lower
104
+ * index, so this caps how many pairs a particle starts and not how many it ends
105
+ * up in: a particle can be the *higher* index of any number of them. What the
106
+ * cap does bound exactly — and the only thing `ClothState` needs it to — is the
107
+ * length of the whole list, at this many per particle, because every pair is
108
+ * charged to exactly one of its two ends.
109
+ * @type {number}
110
+ */
111
+ export const CLOTH_SELF_PAIRS_PER_PARTICLE: number;
112
+ //# sourceMappingURL=cloth_self_find.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloth_self_find.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/solver/cloth_self_find.js"],"names":[],"mappings":"AA4DA;;;;;GAKG;AACH,0DAFa;IAAC,MAAM,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAC,CA0DrD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,4EANW;IAAC,MAAM,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAC,UACzC,MAAM,GAGJ,MAAM,CAoHlB;AAED;;;;;;GAMG;AACH,+DAHW;IAAC,MAAM,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAC,GACvC,MAAM,CAyJlB;AA1aD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,4CAFU,MAAM,CAE+B"}