@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,49 @@
1
+ /**
2
+ * # Putting the answer back onto a skinned model's joints — §11.2
3
+ *
4
+ * The same reconstruction the entity path uses, written onto `Node3D`s instead
5
+ * of onto entities. **Cloth moves joints; it does not produce vertices** — the
6
+ * mapping from a simulated joint to a render vertex already exists in this
7
+ * engine and it is the skin, so the existing skinning pass does the rest,
8
+ * including bounds refresh and BLAS refit that a bespoke vertex-deformation
9
+ * path would have to reimplement.
10
+ *
11
+ * ## `transform_local` is the output, and `transform_global` is written too
12
+ *
13
+ * `transform_local` is a joint's own truth and the handle §11.2 names. It is
14
+ * also *passive*: a `Node3D` does not track its components, and nothing
15
+ * downstream sees a change until `updateMatrices` runs — which recurses into
16
+ * every descendant, so calling it on the anchor would recompose the whole
17
+ * character every fixed step to move a cape.
18
+ *
19
+ * So this pass composes the cloth subtree's `transform_global` itself, which
20
+ * costs nothing because the pose is already in hand, and bumps each joint's
21
+ * version through `needsUpdate` so the renderer uploads the row. Nothing above
22
+ * the anchor is touched and nothing below the garment is walked.
23
+ *
24
+ * `transform_global` is derived, so writing it is only ever a shortcut for the
25
+ * recomposition it saves — and it is a *correct* shortcut only because this
26
+ * pass has the anchor's world pose and the whole chain under it. Anything that
27
+ * moves the anchor without telling cloth invalidates it, which is the same
28
+ * contract every consumer of a derived transform already has.
29
+ *
30
+ * ## What is not here
31
+ *
32
+ * No announcement, and no pruned boundary. The entity path has both because its
33
+ * subtree is an entity hierarchy with other things hanging off it; a proxy's
34
+ * joint list is closed by construction, and a socket parented to a cape joint
35
+ * follows it through the ordinary node hierarchy.
36
+ *
37
+ * @author Alex Goldring
38
+ * @copyright Company Named Limited (c) 2026
39
+ */
40
+ /**
41
+ * Write one cloth's solved pose onto the joints it drives.
42
+ *
43
+ * @param {ClothInstance} instance
44
+ * @param {Transform64} anchor the anchor joint's **world** pose, evaluated by
45
+ * the caller — see `ClothSystem` for why it is not read off the node
46
+ * @returns {void}
47
+ */
48
+ export function cloth_write_back_rig(instance: ClothInstance, anchor: Transform64): void;
49
+ //# sourceMappingURL=cloth_write_back_rig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloth_write_back_rig.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/cloth_write_back_rig.js"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH;;;;;;;GAOG;AACH,oFAFa,IAAI,CA2DhB"}
@@ -0,0 +1,115 @@
1
+ import { quat3_multiply } from "../../../../core/geom/3d/quaternion/quat3_multiply.js";
2
+ import { v3_quaternion_apply } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
3
+ import {
4
+ TRANSFORM64_ROTATION_OFFSET,
5
+ TRANSFORM64_TRANSLATION_OFFSET
6
+ } from "../../../ecs/transform/Transform64.js";
7
+ import { cloth_reconstruct_pose } from "./cloth_reconstruct_pose.js";
8
+ import { cloth_write_local_pose } from "./cloth_write_back.js";
9
+
10
+ /**
11
+ * # Putting the answer back onto a skinned model's joints — §11.2
12
+ *
13
+ * The same reconstruction the entity path uses, written onto `Node3D`s instead
14
+ * of onto entities. **Cloth moves joints; it does not produce vertices** — the
15
+ * mapping from a simulated joint to a render vertex already exists in this
16
+ * engine and it is the skin, so the existing skinning pass does the rest,
17
+ * including bounds refresh and BLAS refit that a bespoke vertex-deformation
18
+ * path would have to reimplement.
19
+ *
20
+ * ## `transform_local` is the output, and `transform_global` is written too
21
+ *
22
+ * `transform_local` is a joint's own truth and the handle §11.2 names. It is
23
+ * also *passive*: a `Node3D` does not track its components, and nothing
24
+ * downstream sees a change until `updateMatrices` runs — which recurses into
25
+ * every descendant, so calling it on the anchor would recompose the whole
26
+ * character every fixed step to move a cape.
27
+ *
28
+ * So this pass composes the cloth subtree's `transform_global` itself, which
29
+ * costs nothing because the pose is already in hand, and bumps each joint's
30
+ * version through `needsUpdate` so the renderer uploads the row. Nothing above
31
+ * the anchor is touched and nothing below the garment is walked.
32
+ *
33
+ * `transform_global` is derived, so writing it is only ever a shortcut for the
34
+ * recomposition it saves — and it is a *correct* shortcut only because this
35
+ * pass has the anchor's world pose and the whole chain under it. Anything that
36
+ * moves the anchor without telling cloth invalidates it, which is the same
37
+ * contract every consumer of a derived transform already has.
38
+ *
39
+ * ## What is not here
40
+ *
41
+ * No announcement, and no pruned boundary. The entity path has both because its
42
+ * subtree is an entity hierarchy with other things hanging off it; a proxy's
43
+ * joint list is closed by construction, and a socket parented to a cape joint
44
+ * follows it through the ordinary node hierarchy.
45
+ *
46
+ * @author Alex Goldring
47
+ * @copyright Company Named Limited (c) 2026
48
+ */
49
+
50
+ /**
51
+ * Write one cloth's solved pose onto the joints it drives.
52
+ *
53
+ * @param {ClothInstance} instance
54
+ * @param {Transform64} anchor the anchor joint's **world** pose, evaluated by
55
+ * the caller — see `ClothSystem` for why it is not read off the node
56
+ * @returns {void}
57
+ */
58
+ export function cloth_write_back_rig(instance, anchor) {
59
+ cloth_reconstruct_pose(instance);
60
+
61
+ const node_count = instance.node_count;
62
+
63
+ const blended = instance.blended_position;
64
+ const reconstructed = instance.blended_rotation;
65
+
66
+ const ax = anchor[TRANSFORM64_TRANSLATION_OFFSET];
67
+ const ay = anchor[TRANSFORM64_TRANSLATION_OFFSET + 1];
68
+ const az = anchor[TRANSFORM64_TRANSLATION_OFFSET + 2];
69
+
70
+ const aqx = anchor[TRANSFORM64_ROTATION_OFFSET];
71
+ const aqy = anchor[TRANSFORM64_ROTATION_OFFSET + 1];
72
+ const aqz = anchor[TRANSFORM64_ROTATION_OFFSET + 2];
73
+ const aqw = anchor[TRANSFORM64_ROTATION_OFFSET + 3];
74
+
75
+ const parent = instance.node_parent;
76
+ const node_joint = instance.node_joint;
77
+
78
+ for (let node = 1; node < node_count; node++) {
79
+ const joint = node_joint[node];
80
+
81
+ if (joint === undefined || joint === null) {
82
+ continue;
83
+ }
84
+
85
+ cloth_write_local_pose(joint.transform_local, instance, node, parent[node]);
86
+
87
+ const global = joint.transform_global;
88
+
89
+ const n = node * 3;
90
+
91
+ v3_quaternion_apply(
92
+ global, TRANSFORM64_TRANSLATION_OFFSET,
93
+ blended[n], blended[n + 1], blended[n + 2],
94
+ aqx, aqy, aqz, aqw
95
+ );
96
+
97
+ global[TRANSFORM64_TRANSLATION_OFFSET] += ax;
98
+ global[TRANSFORM64_TRANSLATION_OFFSET + 1] += ay;
99
+ global[TRANSFORM64_TRANSLATION_OFFSET + 2] += az;
100
+
101
+ quat3_multiply(
102
+ global, TRANSFORM64_ROTATION_OFFSET,
103
+ aqx, aqy, aqz, aqw,
104
+ reconstructed[node * 4], reconstructed[node * 4 + 1],
105
+ reconstructed[node * 4 + 2], reconstructed[node * 4 + 3]
106
+ );
107
+
108
+ global.updateMatrix();
109
+
110
+ // The version is what the renderer compares against to decide whether
111
+ // to upload the row, so a joint whose transform changed and whose
112
+ // version did not is a joint that moved nowhere.
113
+ joint.needsUpdate = true;
114
+ }
115
+ }
@@ -4,13 +4,15 @@
4
4
  npm run dev --workspace @woosh/meep-engine
5
5
  ```
6
6
 
7
- Two pages, one directory, one layer of the system each. (Vite takes the next
7
+ Four pages, one directory, one layer of the system each. (Vite takes the next
8
8
  free port if 5173 is busy — the terminal says which.)
9
9
 
10
10
  | | |
11
11
  |---|---|
12
12
  | [`index.html`](./index.html) | **the solver, M0.** `cloth_step` over a `ClothState`, no ECS at all. |
13
13
  | [`rig.html`](./rig.html) | **the entity subtree, M1.** A real `EntityManager`, real entities, `ClothSystem` walking and writing back. |
14
+ | [`collide.html`](./collide.html) | **collision, M2.** The solver again, with a packed collider table in the argument list. |
15
+ | [`garment.html`](./garment.html) | **skinned garments, M3, and self-collision, M4.** A `Node3D` skeleton, a `Skin`, and a `Cloth` + `ClothRig` driving some of its joints. |
14
16
 
15
17
  Both are at
16
18
  `http://localhost:5173/src/engine/physics/cloth/playground/<page>`.
@@ -183,3 +185,155 @@ real: `rebuild` returns a promise, because `EntityManager#startup` does and an
183
185
  entity created before it resolves is never linked; and `render` is separate from
184
186
  `step_once`, because `requestAnimationFrame` does not fire in a hidden pane and
185
187
  everything on the page hangs off it.
188
+
189
+ ---
190
+
191
+ # The collision page — `collide.html`
192
+
193
+ ## What it is
194
+
195
+ The solver page again, with a **packed collider table** in `cloth_step`'s
196
+ argument list. There is no `EntityManager`, no `ClothColliderIndex` and no
197
+ `ClothColliderSystem`: `collide_build.js` hands the solver exactly what
198
+ `cloth_gather_colliders` would, already in the cloth's own frame, so what is on
199
+ screen is the layer M2's findings live in and nothing above it.
200
+
201
+ Two of those findings are things to *watch* rather than read.
202
+
203
+ **The sweep, which is not really about tunnelling.** Pick **a capsule swept
204
+ through** and press *end-of-step only*. The capsule stops being *noticed*: the
205
+ contact readout drops by four while the capsule visibly passes through the sheet.
206
+ Discovery evaluates the field at the end-of-step pose, so a collider that crossed
207
+ the cloth within the step is nowhere near it by then, and without the travel term
208
+ in the discovery reach no row is ever created for the swept poses to act through.
209
+ At 20 m/s in `MEASUREMENTS.md` §20 the difference is 95 rows a step against none.
210
+
211
+ **The penalty floor, which decides how hard a new contact hits.** Pick **the
212
+ ground**, drag `k_min ÷ k_max` to 1, and press *reset*: the cape slaps down.
213
+ Drag it back to 1/32 and it lands. Peak contact force across that range measured
214
+ 18.9 N against 0.16 N, and the settled energy six orders of magnitude apart —
215
+ with the *penetration improving* at the low end, which is the augmented
216
+ Lagrangian working as designed. §17.
217
+
218
+ ## The scenes
219
+
220
+ - **sphere under a cape** — the simplest thing a contact row can be right about.
221
+ - **every primitive** — sphere, capsule, box and cylinder side by side, each
222
+ protruding 25 mm through the sheet. Four different fields, one dispatch, and
223
+ the same free functions the shape classes now call.
224
+ - **the ground** — `PlaneShape3D`, which §14.3 asked for and did not exist.
225
+ - **a shoulder, animated** — three capsules as an arm, swinging. The swept pose,
226
+ in the configuration it was designed for.
227
+ - **a capsule swept through** — 3 m/s straight through the sheet. The sweep
228
+ toggle's scene.
229
+ - **a spinning bar** — a bar turning behind the cape and through its plane. It is
230
+ also the one scene that does not resolve: a rigid collider driven through cloth
231
+ that is pinned above it wraps rather than parts, and the 18 mm of resting
232
+ penetration is the row bounding a case it cannot prevent. That is authoring
233
+ rather than a solver gap, and it is here so it is visible rather than
234
+ surprising.
235
+
236
+ ## The readout
237
+
238
+ - **contacts** — rows the discovery pass created this step. Zero while a collider
239
+ is visibly passing through the cloth is the finding above.
240
+ - **worst penetration** — the deepest any particle got, over the whole run.
241
+ - **resting penetration** — how deep anything is *now*. This is the number that
242
+ says whether a screenshot showing a sphere apparently poking through a cape is
243
+ a simulation problem or a drawing one — the collider outline is dashed and has
244
+ no depth test, so it is painted over the cloth whether it is in front or behind.
245
+ - **step** — milliseconds for `cloth_contact_find` plus `cloth_step`, window
246
+ minimum, against §17's 2 ms. Browser `performance.now()` is coarse and a hidden
247
+ pane throttles the page; `__fixtures__/cloth_m2_measure.mjs` under node is the
248
+ number that means something.
249
+
250
+ ## Notes
251
+
252
+ `globalThis.cloth_collide_playground` exposes `{ control, camera, rebuild,
253
+ step_once, penetration, cloth, colliders, contacts }`. `requestAnimationFrame`
254
+ does not fire in a hidden pane, so a driver calls `step_once` itself.
255
+
256
+ ---
257
+
258
+ # The garment page — `garment.html`
259
+
260
+ ## What it is
261
+
262
+ `rig.html` is a `Cloth` over an entity subtree; this is a `Cloth` + a `ClothRig`
263
+ over a skinned model's **joints**. Every point on screen is a
264
+ `Node3D.transform_global` — a joint of a `Skin`, not an entity — and it is where
265
+ it is because the solver wrote its `transform_local` and this page composed the
266
+ chain.
267
+
268
+ `ClothSystem#models` takes a stub rather than a `MeshSystem` for the reason the
269
+ field exists: a `MeshSystem` needs a graphics engine, a scene and a loader, and a
270
+ garment's joints are a `Node3D` tree that needs none of the three. The stub
271
+ answers exactly the one method the system calls.
272
+
273
+ ## The garments
274
+
275
+ - **cape** — five strips of seven off the chest. The common case and the cheap
276
+ one: an artist made the joints and skinned the cape to them, so the proxy is
277
+ joint indices, the topology and the bind pose. No binding step, no generated
278
+ geometry.
279
+ - **coat tails** — three strips of nine in denim, which is the library entry that
280
+ spends its two levers on particles rather than iterations.
281
+ - **ponytail** — one chain of twelve off the neck. The rig path is the entity
282
+ path with `Node3D`s in it, and a single chain is where that is most obviously
283
+ true.
284
+ - **loincloth** — seven strips of five off the pelvis, and the one preset that
285
+ spends most of its time against the leg colliders.
286
+
287
+ ## The motion drives the character, and only the character
288
+
289
+ The buttons write the **character's own bones**. The garment's joints are
290
+ cloth's, and the seed says so: it claims `TransformAuthority.CPU` on every one of
291
+ them, because a joint a clip drives is under GPU authority and its
292
+ `transform_local` is not read by anything. Two writers of one row is the race the
293
+ authority enum exists to prevent, and the claim is where a garment whose joints
294
+ are *also* keyed shows up as an authoring error.
295
+
296
+ **sprint** is §7 P7's own profile: a square wave in velocity, integrated. Written
297
+ as a position that resets it would be a nine-metre discontinuity, which is a
298
+ teleport wearing a sprint's clothes — and the cloth would be right to treat it as
299
+ one.
300
+
301
+ ## The readout
302
+
303
+ - **worst |x−anchor| / d_geo** — §7 P2's rubber number. Green at rest and under
304
+ walking and turning; **sprint takes it past 1.1**, which is P2's own conditional
305
+ bound showing on a shape M1 did not measure. `MEASUREMENTS.md` §26 has both
306
+ paths side by side, and they agree to the digit — this is the geometry, not the
307
+ rig path.
308
+ - **contacts** — with **collide with the body** on. A cape clear of its own
309
+ torso reads zero here most of the time, which is what a garment that was
310
+ authored correctly looks like; see below.
311
+ - **self pairs** — M4's, with **collide with itself** on. Zero while the
312
+ garment hangs and climbing the moment a fold closes, which is the shape of
313
+ the whole tier: it is a broadphase over particles and it has nothing to do
314
+ until two of them are near. Three library entries set the flag — silk,
315
+ cotton and hair — and the button overrides whichever the fabric picker is
316
+ on, by cloning the frozen entry and moving one bit.
317
+
318
+ **The radius is the proxy's resolution, not the fabric's thickness**, and it
319
+ is the single thing most worth knowing about this tier. Silk is 4 mm thick
320
+ and this cape's particles are 8 cm apart; at 4 mm the two layers of a fold
321
+ are never in contact and the feature does nothing at all.
322
+ `MEASUREMENTS.md` §31 is the sweep, §36 is the clamp at the other end.
323
+
324
+ ## The one thing worth knowing before authoring a garment
325
+
326
+ A garment authored **inside** its own body collider reads as a *tether* failure.
327
+ The contact row pushes it out, the tether pulls it back, the contact wins, and
328
+ the readout says the tether is failing by thirty per cent. It is not. §11.3
329
+ step 10 validates exactly this at build time — "the skinned bind pose is
330
+ collision-free against the character's `ClothCollider` set" — and M3 does not
331
+ build that check, so this page's geometry is right by hand. `MEASUREMENTS.md` §29
332
+ has the numbers, because it cost an hour to diagnose the first time.
333
+
334
+ ## Notes
335
+
336
+ `globalThis.cloth_garment_playground` exposes `{ control, camera, ready, rebuild,
337
+ step_once, draw, scene }`. `rebuild` returns a promise, because
338
+ `EntityManager#startup` does and an entity created before it resolves is never
339
+ linked.
@@ -0,0 +1,178 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>meep — cloth collision (M2)</title>
6
+ <style>
7
+ :root {
8
+ color-scheme: dark;
9
+ --ink: #d6dae0;
10
+ --dim: #8b939f;
11
+ --line: #2b3038;
12
+ --panel: #14171c;
13
+ --warn: #e5b54a;
14
+ --bad: #e5533d;
15
+ --good: #5ad19a;
16
+ }
17
+
18
+ html, body {
19
+ margin: 0;
20
+ height: 100%;
21
+ background: #0d0f12;
22
+ color: var(--ink);
23
+ font: 12px/1.5 ui-monospace, Consolas, monospace;
24
+ overflow: hidden;
25
+ }
26
+
27
+ body { display: flex; }
28
+
29
+ #stage { position: relative; flex: 1; min-width: 0; }
30
+ #view { display: block; width: 100%; height: 100%; cursor: grab; }
31
+ #view.grabbing { cursor: grabbing; }
32
+
33
+ #hint {
34
+ position: absolute; left: 14px; bottom: 12px;
35
+ color: var(--dim); pointer-events: none;
36
+ }
37
+
38
+ #readout {
39
+ position: absolute; left: 14px; top: 12px;
40
+ background: rgba(13, 15, 18, 0.82);
41
+ border: 1px solid var(--line);
42
+ padding: 8px 12px;
43
+ min-width: 260px;
44
+ }
45
+
46
+ #readout table { border-collapse: collapse; width: 100%; }
47
+ #readout td { padding: 1px 0; white-space: nowrap; }
48
+ #readout td:last-child { text-align: right; padding-left: 18px; }
49
+ #readout td:first-child { color: var(--dim); }
50
+
51
+ #budget {
52
+ height: 4px; margin-top: 7px;
53
+ background: #22262d; position: relative; overflow: hidden;
54
+ }
55
+ #budget > i { display: block; height: 100%; background: var(--good); width: 0; }
56
+ #budget.over > i { background: var(--bad); }
57
+
58
+ aside {
59
+ width: 310px; flex: none; overflow-y: auto;
60
+ background: var(--panel); border-left: 1px solid var(--line);
61
+ padding: 12px 14px 40px;
62
+ }
63
+
64
+ aside h2 {
65
+ font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em;
66
+ color: var(--dim); margin: 18px 0 6px; font-weight: 600;
67
+ }
68
+
69
+ aside h2:first-child { margin-top: 0; }
70
+
71
+ .blurb { color: var(--dim); margin: 0 0 8px; font-size: 11px; }
72
+ .blurb b { color: var(--ink); font-weight: 600; }
73
+
74
+ label { display: flex; align-items: center; gap: 8px; margin: 3px 0; }
75
+ label > span { flex: none; width: 96px; color: var(--dim); }
76
+ label > input[type=range] { flex: 1; min-width: 0; accent-color: #6b8afd; }
77
+ label > output { flex: none; width: 54px; text-align: right; }
78
+
79
+ select {
80
+ width: 100%; background: #1b1f26; color: var(--ink);
81
+ border: 1px solid var(--line); padding: 4px 6px; font: inherit;
82
+ }
83
+
84
+ .buttons { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0; }
85
+
86
+ button {
87
+ background: #1b1f26; color: var(--ink); border: 1px solid var(--line);
88
+ padding: 4px 9px; font: inherit; cursor: pointer;
89
+ }
90
+
91
+ button:hover { border-color: #47506045; background: #232833; }
92
+ button.on { background: #2b3546; border-color: #4a5b7d; color: #cfe0ff; }
93
+
94
+ .bad { color: var(--bad); }
95
+ .warn { color: var(--warn); }
96
+ .good { color: var(--good); }
97
+ </style>
98
+ </head>
99
+ <body>
100
+ <div id="stage">
101
+ <canvas id="view"></canvas>
102
+
103
+ <div id="readout">
104
+ <table>
105
+ <tr><td>step</td><td id="r_step">—</td></tr>
106
+ <tr><td>contacts</td><td id="r_contacts">—</td></tr>
107
+ <tr><td>worst penetration</td><td id="r_pen">—</td></tr>
108
+ <tr><td>resting penetration</td><td id="r_rest">—</td></tr>
109
+ <tr><td>kinetic energy</td><td id="r_energy">—</td></tr>
110
+ <tr><td>finite</td><td id="r_finite">—</td></tr>
111
+ </table>
112
+ <div id="budget"><i></i></div>
113
+ </div>
114
+
115
+ <div id="hint">drag to orbit · shift-drag to pan · wheel to zoom · the dashed collider outline has no depth test</div>
116
+ </div>
117
+
118
+ <aside>
119
+ <h2>Scene</h2>
120
+ <select id="scene"></select>
121
+ <p class="blurb" id="scene_blurb"></p>
122
+
123
+ <h2>Cloth</h2>
124
+ <label><span>particles</span><input id="size" type="range" min="8" max="34" step="1"><output id="size_out"></output></label>
125
+ <label><span>spacing</span><input id="spacing" type="range" min="0.01" max="0.08" step="0.002"><output id="spacing_out"></output></label>
126
+ <label><span>thickness</span><input id="thickness" type="range" min="0.001" max="0.05" step="0.001"><output id="thickness_out"></output></label>
127
+ <p class="blurb">
128
+ <b>thickness</b> is the contact offset: the row holds every particle that far off the surface,
129
+ and a row is created — inactive — from twice that out. It is <i>not</i> where the velocity
130
+ clamp comes from; §7 P1 measured that and it is the solver's own correction authority.
131
+ </p>
132
+
133
+ <h2>Surface</h2>
134
+ <label><span>friction</span><input id="friction" type="range" min="0" max="2" step="0.02"><output id="friction_out"></output></label>
135
+ <label><span>inflation</span><input id="inflation" type="range" min="0" max="0.06" step="0.002"><output id="inflation_out"></output></label>
136
+ <p class="blurb">
137
+ Friction is a row on the same contact, clamped at <b>μ·f<sub>n</sub></b> — the collision row's
138
+ own force this iteration. Its anchor lives in the <b>collider's</b> frame, which is what makes
139
+ a sliding surface drag cloth instead of a stationary point holding it still.
140
+ </p>
141
+
142
+ <h2>Budget</h2>
143
+ <label><span>substeps</span><input id="substeps" type="range" min="1" max="8" step="1"><output id="substeps_out"></output></label>
144
+ <label><span>iterations</span><input id="iterations" type="range" min="1" max="16" step="1"><output id="iterations_out"></output></label>
145
+
146
+ <h2>Contact band</h2>
147
+ <p class="blurb">
148
+ M0 could not choose these: the ramp only means something for a row that <b>arrives</b>, and a
149
+ contact is the first one in the system that does. Measured defaults are
150
+ k_min = k_max/32 and β = 1e3.
151
+ </p>
152
+ <label><span>k_min ÷ k_max</span><input id="k_floor" type="range" min="-7" max="0" step="0.25"><output id="k_floor_out"></output></label>
153
+ <label><span>β</span><input id="beta" type="range" min="0" max="7" step="0.25"><output id="beta_out"></output></label>
154
+ <div class="buttons"><button id="defaults">measured defaults</button></div>
155
+
156
+ <h2>Sweep</h2>
157
+ <div class="buttons">
158
+ <button id="sweep" class="on">swept (§8.2)</button>
159
+ <button id="unswept">end-of-step only</button>
160
+ </div>
161
+ <p class="blurb">
162
+ With the sweep off, a collider's previous pose is its current one: the substeps stop
163
+ interpolating <i>and</i> the discovery pass loses the travel margin. On the swept-capsule
164
+ scene that is the difference between a capsule the cloth notices and one it does not.
165
+ </p>
166
+
167
+ <h2>Run</h2>
168
+ <div class="buttons">
169
+ <button id="pause">pause</button>
170
+ <button id="single">step once</button>
171
+ <button id="reset">reset</button>
172
+ <button id="animate" class="on">animate colliders</button>
173
+ </div>
174
+ </aside>
175
+
176
+ <script type="module" src="./collide_main.js"></script>
177
+ </body>
178
+ </html>
@@ -0,0 +1,95 @@
1
+ /**
2
+ * @param {number} x
3
+ * @param {number} y
4
+ * @param {number} z
5
+ * @param {number} angle radians
6
+ * @returns {number[]} `[x, y, z, w]`
7
+ */
8
+ export function axis_angle(x: number, y: number, z: number, angle: number): number[];
9
+ /**
10
+ * Move a record, carrying its current pose into its previous one — what a fixed
11
+ * step does to the index.
12
+ *
13
+ * @param {ColliderScene} built
14
+ * @param {number} record
15
+ * @param {number} x
16
+ * @param {number} y
17
+ * @param {number} z
18
+ */
19
+ export function move(built: ColliderScene, record: number, x: number, y: number, z: number): void;
20
+ /**
21
+ * @param {ColliderScene} built
22
+ * @param {number} record
23
+ * @param {number} x
24
+ * @param {number} y
25
+ * @param {number} z
26
+ * @param {number[]} rotation
27
+ */
28
+ export function turn(built: ColliderScene, record: number, x: number, y: number, z: number, rotation: number[]): void;
29
+ /**
30
+ * Freeze a record's previous pose onto its current one, so the sweep has nothing
31
+ * to interpolate. This is the "sweep off" switch, and it is exactly what the
32
+ * design would be without §8.2.
33
+ *
34
+ * @param {ColliderScene} built
35
+ * @param {number} record
36
+ */
37
+ export function unsweep(built: ColliderScene, record: number): void;
38
+ /**
39
+ * # The collider scenes the M2 page collides against
40
+ *
41
+ * Packed tables built straight from shapes, already in the cloth's own frame —
42
+ * there is no `EntityManager` on this page, so `ClothColliderIndex` and
43
+ * `ClothColliderSystem` are not in the loop and everything below the gather is.
44
+ *
45
+ * Kept beside the page rather than in `__fixtures__` for the reason
46
+ * `cloth_playground_build.js` gives: `__fixtures__` is excluded from the
47
+ * published package and the playground is not, so importing across that line
48
+ * would ship a broken module.
49
+ *
50
+ * @author Alex Goldring
51
+ * @copyright Company Named Limited (c) 2026
52
+ */
53
+ /**
54
+ * @typedef {object} ColliderScene
55
+ * @property {string} label
56
+ * @property {string} blurb what the scene is for
57
+ * @property {Float32Array} table packed records, cloth-local
58
+ * @property {Int32Array} keys
59
+ * @property {number} count
60
+ * @property {AbstractShape3D[]} shape the shape behind each record, for drawing
61
+ * @property {function(number, number): void} [animate] `(record, time) => void`
62
+ */
63
+ /**
64
+ * Every scene, by name.
65
+ * @type {Readonly<Object<string, {label: string, blurb: string, build: function}>>}
66
+ */
67
+ export const COLLIDER_SCENES: Readonly<{
68
+ [x: string]: {
69
+ label: string;
70
+ blurb: string;
71
+ build: Function;
72
+ };
73
+ }>;
74
+ export type ColliderScene = {
75
+ label: string;
76
+ /**
77
+ * what the scene is for
78
+ */
79
+ blurb: string;
80
+ /**
81
+ * packed records, cloth-local
82
+ */
83
+ table: Float32Array;
84
+ keys: Int32Array;
85
+ count: number;
86
+ /**
87
+ * the shape behind each record, for drawing
88
+ */
89
+ shape: AbstractShape3D[];
90
+ /**
91
+ * `(record, time) => void`
92
+ */
93
+ animate?: (arg0: number, arg1: number) => void;
94
+ };
95
+ //# sourceMappingURL=collide_build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collide_build.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/playground/collide_build.js"],"names":[],"mappings":"AAsKA;;;;;;GAMG;AACH,8BANW,MAAM,KACN,MAAM,KACN,MAAM,SACN,MAAM,GACJ,MAAM,EAAE,CAOpB;AAyDD;;;;;;;;;GASG;AACH,4BANW,aAAa,UACb,MAAM,KACN,MAAM,KACN,MAAM,KACN,MAAM,QAchB;AAED;;;;;;;GAOG;AACH,4BAPW,aAAa,UACb,MAAM,KACN,MAAM,KACN,MAAM,KACN,MAAM,YACN,MAAM,EAAE,QAmBlB;AAED;;;;;;;GAOG;AACH,+BAHW,aAAa,UACb,MAAM,QAMhB;AA/QD;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;GASG;AAEH;;;GAGG;AACH,8BAFU;QAAgB,MAAM,GAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,WAAU;KAAC;EAAE,CA4GhF;;WAvHW,MAAM;;;;WACN,MAAM;;;;WACN,YAAY;UACZ,UAAU;WACV,MAAM;;;;WACN,iBAAiB;;;;qBACR,MAAM,QAAE,MAAM,KAAG,IAAI"}