@woosh/meep-engine 3.24.0 → 3.26.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 (349) hide show
  1. package/package.json +1 -1
  2. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +59 -0
  3. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
  4. package/src/core/geom/3d/shape/HeightMapShape3D.js +285 -0
  5. package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
  6. package/src/core/geom/3d/shape/PosedShape3D.js +57 -0
  7. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  8. package/src/core/geom/3d/shape/TransformedShape3D.js +102 -0
  9. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  10. package/src/core/geom/3d/shape/UnionShape3D.js +64 -0
  11. package/src/engine/graphics3/PickingSystem.d.ts +3 -3
  12. package/src/engine/graphics3/PickingSystem.d.ts.map +1 -1
  13. package/src/engine/graphics3/PickingSystem.js +52 -55
  14. package/src/engine/graphics3/shader_picking_gather.d.ts +40 -0
  15. package/src/engine/graphics3/shader_picking_gather.d.ts.map +1 -0
  16. package/src/engine/graphics3/shader_picking_gather.js +120 -0
  17. package/src/engine/physics/cloth/MEASUREMENTS.md +1632 -0
  18. package/src/engine/physics/cloth/PLAN.md +738 -95
  19. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +84 -17
  20. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
  21. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +451 -42
  22. package/src/engine/physics/cloth/ecs/ClothColliderSerializationAdapter.d.ts +52 -0
  23. package/src/engine/physics/cloth/ecs/ClothColliderSerializationAdapter.d.ts.map +1 -0
  24. package/src/engine/physics/cloth/ecs/ClothColliderSerializationAdapter.js +70 -0
  25. package/src/engine/physics/cloth/ecs/ClothDynamics.d.ts +12 -3
  26. package/src/engine/physics/cloth/ecs/ClothDynamics.d.ts.map +1 -1
  27. package/src/engine/physics/cloth/ecs/ClothDynamics.js +340 -331
  28. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +101 -29
  29. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  30. package/src/engine/physics/cloth/ecs/ClothInstance.js +110 -31
  31. package/src/engine/physics/cloth/ecs/ClothSerializationAdapter.d.ts +84 -0
  32. package/src/engine/physics/cloth/ecs/ClothSerializationAdapter.d.ts.map +1 -0
  33. package/src/engine/physics/cloth/ecs/ClothSerializationAdapter.js +141 -0
  34. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +71 -81
  35. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  36. package/src/engine/physics/cloth/ecs/ClothSystem.js +135 -856
  37. package/src/engine/physics/cloth/ecs/ClothWorkerCore.d.ts +48 -0
  38. package/src/engine/physics/cloth/ecs/ClothWorkerCore.d.ts.map +1 -0
  39. package/src/engine/physics/cloth/ecs/ClothWorkerCore.js +107 -0
  40. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +323 -0
  41. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -0
  42. package/src/engine/physics/cloth/ecs/ClothWorld.js +1248 -0
  43. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +192 -0
  44. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -0
  45. package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +578 -0
  46. package/src/engine/physics/cloth/ecs/cloth.worker.d.ts +2 -0
  47. package/src/engine/physics/cloth/ecs/cloth.worker.d.ts.map +1 -0
  48. package/src/engine/physics/cloth/ecs/cloth.worker.js +12 -0
  49. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  50. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +2 -1
  51. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +85 -3
  52. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  53. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +366 -271
  54. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +95 -12
  55. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
  56. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +170 -27
  57. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +19 -0
  58. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  59. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +249 -201
  60. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -0
  61. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  62. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +62 -1
  63. package/src/engine/physics/cloth/ecs/cloth_worker_protocol.d.ts +29 -0
  64. package/src/engine/physics/cloth/ecs/cloth_worker_protocol.d.ts.map +1 -0
  65. package/src/engine/physics/cloth/ecs/cloth_worker_protocol.js +78 -0
  66. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  67. package/src/engine/physics/cloth/ecs/cloth_write_back.js +18 -10
  68. package/src/engine/physics/cloth/ecs/makeClothWorker.d.ts +17 -0
  69. package/src/engine/physics/cloth/ecs/makeClothWorker.d.ts.map +1 -0
  70. package/src/engine/physics/cloth/ecs/makeClothWorker.js +18 -0
  71. package/src/engine/physics/cloth/playground/README.md +73 -2
  72. package/src/engine/physics/cloth/playground/collide_main.js +1 -1
  73. package/src/engine/physics/cloth/playground/wind.html +166 -0
  74. package/src/engine/physics/cloth/playground/wind_build.d.ts +81 -0
  75. package/src/engine/physics/cloth/playground/wind_build.d.ts.map +1 -0
  76. package/src/engine/physics/cloth/playground/wind_build.js +141 -0
  77. package/src/engine/physics/cloth/playground/wind_main.d.ts +2 -0
  78. package/src/engine/physics/cloth/playground/wind_main.d.ts.map +1 -0
  79. package/src/engine/physics/cloth/playground/wind_main.js +681 -0
  80. package/src/engine/physics/cloth/solver/ClothState.d.ts +134 -79
  81. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  82. package/src/engine/physics/cloth/solver/ClothState.js +273 -12
  83. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +29 -8
  84. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
  85. package/src/engine/physics/cloth/solver/cloth_contact_find.js +37 -9
  86. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +45 -2
  87. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  88. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +46 -2
  89. package/src/engine/physics/cloth/solver/cloth_step.d.ts +21 -2
  90. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  91. package/src/engine/physics/cloth/solver/cloth_step.js +173 -4
  92. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts +40 -0
  93. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -0
  94. package/src/engine/physics/cloth/solver/cloth_step_instance.js +284 -0
  95. package/src/engine/physics/cloth/solver/cloth_wind_accelerate.d.ts +107 -0
  96. package/src/engine/physics/cloth/solver/cloth_wind_accelerate.d.ts.map +1 -0
  97. package/src/engine/physics/cloth/solver/cloth_wind_accelerate.js +263 -0
  98. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +9 -2
  99. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -1
  100. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +9 -2
  101. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts +102 -0
  102. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts.map +1 -0
  103. package/src/engine/physics/cloth/wind/AbstractClothWind.js +114 -0
  104. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts +87 -0
  105. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts.map +1 -0
  106. package/src/engine/physics/cloth/wind/ClothAmbientWind.js +185 -0
  107. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts +79 -0
  108. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -0
  109. package/src/engine/physics/cloth/wind/ClothFluidWind.js +213 -0
  110. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +106 -0
  111. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -0
  112. package/src/engine/physics/cloth/wind/cloth_sample_air.js +297 -0
  113. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  114. package/src/shade/device/mock/texture_copy.d.ts.map +1 -1
  115. package/src/shade/device/mock/texture_copy.js +28 -0
  116. package/src/shade/playground/vgeo_runtime/README.md +94 -0
  117. package/src/shade/playground/vgeo_runtime/index.html +62 -0
  118. package/src/shade/playground/vgeo_runtime/main.d.ts +2 -0
  119. package/src/shade/playground/vgeo_runtime/main.d.ts.map +1 -0
  120. package/src/shade/playground/vgeo_runtime/main.js +399 -0
  121. package/src/shade/playground/vgeo_viewer/sample_asset.js +1 -1
  122. package/src/shade/renderer/camera/Camera.d.ts +14 -0
  123. package/src/shade/renderer/camera/Camera.d.ts.map +1 -1
  124. package/src/shade/renderer/camera/Camera.js +7 -1
  125. package/src/shade/renderer/geometry/GEOMETRY_METADATA_STRUCT.d.ts.map +1 -1
  126. package/src/shade/renderer/geometry/GEOMETRY_METADATA_STRUCT.js +16 -1
  127. package/src/shade/renderer/geometry/GPUGeometryManager.d.ts.map +1 -1
  128. package/src/shade/renderer/geometry/GPUGeometryManager.js +29 -9
  129. package/src/shade/renderer/geometry/GPUGeometryMetadata.d.ts +10 -0
  130. package/src/shade/renderer/geometry/GPUGeometryMetadata.d.ts.map +1 -1
  131. package/src/shade/renderer/geometry/GPUGeometryMetadata.js +13 -0
  132. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +46 -18
  133. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +70 -22
  134. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +97 -19
  135. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +12 -2
  136. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
  137. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +14 -3
  138. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts +2 -2
  139. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +1 -1
  140. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js +124 -6
  141. package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.d.ts +22 -0
  142. package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.d.ts.map +1 -0
  143. package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.js +53 -0
  144. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +8 -1
  145. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
  146. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +8 -1
  147. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.d.ts +16 -0
  148. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.d.ts.map +1 -0
  149. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.js +15 -0
  150. package/src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.d.ts +54 -0
  151. package/src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.d.ts.map +1 -0
  152. package/src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.js +53 -0
  153. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts +13 -2
  154. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts.map +1 -1
  155. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js +14 -2
  156. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +100 -0
  157. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
  158. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +113 -0
  159. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_header.d.ts.map +1 -1
  160. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_header.js +5 -0
  161. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts.map +1 -1
  162. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +108 -0
  163. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
  164. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +23 -0
  165. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  166. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +40 -0
  167. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts +228 -0
  168. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts.map +1 -0
  169. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.js +932 -0
  170. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +176 -0
  171. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -0
  172. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +425 -0
  173. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +241 -0
  174. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +574 -0
  175. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +120 -0
  176. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -0
  177. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +674 -0
  178. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts +287 -0
  179. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -0
  180. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +976 -0
  181. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +42 -0
  182. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts.map +1 -0
  183. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +96 -0
  184. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_CULL.d.ts +16 -0
  185. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_CULL.d.ts.map +1 -0
  186. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_CULL.js +15 -0
  187. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts +19 -0
  188. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts.map +1 -0
  189. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js +83 -0
  190. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_WORKGROUP_SIZE.d.ts +9 -0
  191. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_WORKGROUP_SIZE.d.ts.map +1 -0
  192. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_WORKGROUP_SIZE.js +8 -0
  193. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts +19 -0
  194. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -0
  195. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +160 -0
  196. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts +3 -0
  197. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -0
  198. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +255 -0
  199. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts +3 -0
  200. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts.map +1 -0
  201. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js +80 -0
  202. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts +3 -0
  203. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts.map +1 -0
  204. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js +144 -0
  205. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts +3 -0
  206. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -0
  207. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +530 -0
  208. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts +39 -0
  209. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts.map +1 -0
  210. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.js +54 -0
  211. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.d.ts +41 -0
  212. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.d.ts.map +1 -0
  213. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.js +56 -0
  214. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts +49 -0
  215. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -0
  216. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +328 -0
  217. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.d.ts +10 -0
  218. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.d.ts.map +1 -0
  219. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.js +51 -0
  220. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts +13 -0
  221. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts.map +1 -0
  222. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.js +12 -0
  223. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +17 -0
  224. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts.map +1 -0
  225. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +99 -0
  226. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.d.ts +9 -0
  227. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.d.ts.map +1 -0
  228. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +8 -0
  229. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts +7 -0
  230. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts.map +1 -0
  231. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.js +27 -0
  232. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.d.ts +14 -0
  233. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.d.ts.map +1 -0
  234. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.js +13 -0
  235. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_OFFSET.d.ts +7 -0
  236. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_OFFSET.d.ts.map +1 -0
  237. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_OFFSET.js +35 -0
  238. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_WORDS.d.ts +9 -0
  239. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_WORDS.d.ts.map +1 -0
  240. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_WORDS.js +8 -0
  241. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_FLAG_SELECTABLE.d.ts +15 -0
  242. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_FLAG_SELECTABLE.d.ts.map +1 -0
  243. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_FLAG_SELECTABLE.js +14 -0
  244. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts +7 -0
  245. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts.map +1 -0
  246. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.js +36 -0
  247. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts +10 -0
  248. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts.map +1 -0
  249. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.js +9 -0
  250. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_OFFSET.d.ts +11 -0
  251. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_OFFSET.d.ts.map +1 -0
  252. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_OFFSET.js +54 -0
  253. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_WORDS.d.ts +9 -0
  254. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_WORDS.d.ts.map +1 -0
  255. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_WORDS.js +8 -0
  256. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_LEAF_BIT.d.ts +11 -0
  257. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_LEAF_BIT.d.ts.map +1 -0
  258. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_LEAF_BIT.js +10 -0
  259. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_OFFSET.d.ts +7 -0
  260. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_OFFSET.d.ts.map +1 -0
  261. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_OFFSET.js +30 -0
  262. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_WORDS.d.ts +9 -0
  263. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_WORDS.d.ts.map +1 -0
  264. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_WORDS.js +8 -0
  265. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NO_CHILD_PAGE.d.ts +13 -0
  266. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NO_CHILD_PAGE.d.ts.map +1 -0
  267. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NO_CHILD_PAGE.js +12 -0
  268. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_NONE.d.ts +14 -0
  269. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_NONE.d.ts.map +1 -0
  270. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_NONE.js +13 -0
  271. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts +11 -0
  272. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts.map +1 -0
  273. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.js +61 -0
  274. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts +9 -0
  275. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts.map +1 -0
  276. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.js +8 -0
  277. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_ITEM_WORDS.d.ts +13 -0
  278. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_ITEM_WORDS.d.ts.map +1 -0
  279. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_ITEM_WORDS.js +12 -0
  280. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_GROUP_BIT.d.ts +9 -0
  281. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_GROUP_BIT.d.ts.map +1 -0
  282. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_GROUP_BIT.js +8 -0
  283. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_WANT_WORDS.d.ts +20 -0
  284. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_WANT_WORDS.d.ts.map +1 -0
  285. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_WANT_WORDS.js +19 -0
  286. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts +23 -0
  287. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -0
  288. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +70 -0
  289. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts +18 -0
  290. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts.map +1 -0
  291. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.js +25 -0
  292. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts +35 -0
  293. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts.map +1 -0
  294. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.js +41 -0
  295. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts +32 -0
  296. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -0
  297. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +138 -0
  298. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  299. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  300. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  301. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +9 -0
  302. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
  303. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +12 -1
  304. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  305. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +12 -1
  306. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
  307. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +10 -0
  308. package/src/shade/renderer/scene/GPUSceneContext.d.ts +18 -0
  309. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  310. package/src/shade/renderer/scene/GPUSceneContext.js +647 -594
  311. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -1
  312. package/src/shade/renderer/scene/rows/GPUSceneRows.js +22 -0
  313. package/src/shade/renderer/shader/chunk/geometry/mat3/chunk_mat3_singular_values.d.ts +35 -0
  314. package/src/shade/renderer/shader/chunk/geometry/mat3/chunk_mat3_singular_values.d.ts.map +1 -0
  315. package/src/shade/renderer/shader/chunk/geometry/mat3/chunk_mat3_singular_values.js +91 -0
  316. package/src/engine/graphics3/instantiate_scene_bundle.d.ts +0 -54
  317. package/src/engine/graphics3/instantiate_scene_bundle.d.ts.map +0 -1
  318. package/src/engine/graphics3/shade_node_to_entity_composition.d.ts +0 -39
  319. package/src/engine/graphics3/shade_node_to_entity_composition.d.ts.map +0 -1
  320. package/src/shade/renderer/animation/compute_skin_world_bounds.d.ts +0 -35
  321. package/src/shade/renderer/animation/compute_skin_world_bounds.d.ts.map +0 -1
  322. package/src/shade/renderer/animation/compute_skinned_mesh_clip_bounding_sphere.d.ts +0 -96
  323. package/src/shade/renderer/animation/compute_skinned_mesh_clip_bounding_sphere.d.ts.map +0 -1
  324. package/src/shade/renderer/animation/pose/pose_evaluate_world.d.ts +0 -20
  325. package/src/shade/renderer/animation/pose/pose_evaluate_world.d.ts.map +0 -1
  326. package/src/shade/renderer/animation/skin_bind_transform.d.ts +0 -25
  327. package/src/shade/renderer/animation/skin_bind_transform.d.ts.map +0 -1
  328. package/src/shade/renderer/animation/skin_frame_defect.d.ts +0 -34
  329. package/src/shade/renderer/animation/skin_frame_defect.d.ts.map +0 -1
  330. package/src/shade/renderer/animation/skin_joint_matrix.d.ts +0 -24
  331. package/src/shade/renderer/animation/skin_joint_matrix.d.ts.map +0 -1
  332. package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts +0 -70
  333. package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts.map +0 -1
  334. package/src/shade/renderer/buffer/table/GPUReadbackStagingRing.d.ts +0 -96
  335. package/src/shade/renderer/buffer/table/GPUReadbackStagingRing.d.ts.map +0 -1
  336. package/src/shade/renderer/scene/InstanceBatch.d.ts +0 -92
  337. package/src/shade/renderer/scene/InstanceBatch.d.ts.map +0 -1
  338. package/src/shade/renderer/scene/Mesh.d.ts +0 -55
  339. package/src/shade/renderer/scene/Mesh.d.ts.map +0 -1
  340. package/src/shade/renderer/scene/Node3D.d.ts +0 -159
  341. package/src/shade/renderer/scene/Node3D.d.ts.map +0 -1
  342. package/src/shade/renderer/scene/Node3DDirtyList.d.ts +0 -59
  343. package/src/shade/renderer/scene/Node3DDirtyList.d.ts.map +0 -1
  344. package/src/shade/renderer/scene/SceneNodeBinding.d.ts +0 -52
  345. package/src/shade/renderer/scene/SceneNodeBinding.d.ts.map +0 -1
  346. package/src/shade/renderer/scene/SkinnedMesh.d.ts +0 -27
  347. package/src/shade/renderer/scene/SkinnedMesh.d.ts.map +0 -1
  348. package/src/shade/renderer/scene/TransformAuthority.d.ts +0 -19
  349. package/src/shade/renderer/scene/TransformAuthority.d.ts.map +0 -1
@@ -1,271 +1,366 @@
1
- /**
2
- * # Normalised coordinates → row parameters
3
- *
4
- * {@link ClothDynamics}' stiffnesses are coordinates in `[0, 1]`, and this is
5
- * the whole of what they mean. It is one module rather than methods on the
6
- * value object because the mapping is *measured* — every constant below has a
7
- * number in `MEASUREMENTS.md` behind it — and a measured mapping deserves to be
8
- * readable on its own and specced on its own.
9
- *
10
- * ## Why neither stiffness maps to newtons per metre
11
- *
12
- * M0's central finding: a **soft** row — a plain penalty — is dissipative only
13
- * while its stiffness stays below about `8·(m/h²)`, and above that boundary the
14
- * step *adds* energy and the cloth sustains a limit cycle forever. More
15
- * iterations and more substeps shrink it; neither removes it
16
- * (`MEASUREMENTS.md` §6). And that boundary is not a stiffness: it is a
17
- * multiple of the row's own inertial scale, which moved across five decades of
18
- * particle mass in §4's sweep without the answer changing.
19
- *
20
- * Two consequences, one for each stiffness:
21
- *
22
- * - **`stretch` cannot be a penalty at all.** Real fabric wants a stretch
23
- * stiffness far above that boundary — for a half-gram particle at 60 Hz × 2
24
- * substeps it sits near 60 N/m, a rubber band — so the stretch row is hard
25
- * (`Infinity`, augmented Lagrangian), and what `stretch` actually selects is
26
- * {@link cloth_strain_allowance}: how far the fabric may extend before the
27
- * strain-limit row of §6 stops it.
28
- * - **`bend` maps to a ratio.** A bend row is soft and must stay inside the
29
- * dissipative band, so its stiffness is expressed as a multiple of
30
- * `m_eff/dt²` — the row's own inertial scale at the **fixed** step rather
31
- * than the substep. Two things fall out of that choice and both are wanted:
32
- * the fabric's look is invariant to how heavy the author made the particles
33
- * (which is what a normalised `[0, 1]` knob should mean), and the row is
34
- * inside the band at *any* substep count, since `k/(m/h²) = ratio/substeps²`
35
- * and `substeps ≥ 1`. A stiffness in newtons per metre has neither property.
36
- *
37
- * @author Alex Goldring
38
- * @copyright Company Named Limited (c) 2026
39
- */
40
-
41
- /**
42
- * Strain a fabric at `stretch = 0` may carry: a quarter of its own length, a
43
- * loose knit. Chosen as the loosest thing that still reads as fabric rather
44
- * than as elastic.
45
- * @type {number}
46
- */
47
- export const CLOTH_STRAIN_MAX = 0.25;
48
-
49
- /**
50
- * Strain a fabric at `stretch = 1` may carry: a tenth of a per cent, which is
51
- * a chain. Below this the strain-limit row is asking for more precision than a
52
- * `Float32` position over a garment-sized coordinate resolves.
53
- * @type {number}
54
- */
55
- export const CLOTH_STRAIN_MIN = 1e-3;
56
-
57
- /**
58
- * Bend stiffness at `bend = 1`, as a multiple of the row's `m_eff/dt²`.
59
- *
60
- * It is 8 because that is the top of the dissipative band M0 measured
61
- * (`MEASUREMENTS.md` §4 and §6) and a bend row is soft. The consequence, stated
62
- * rather than hidden: **bending saturates**. A fabric stiffer than this cannot
63
- * be expressed as a soft row that also comes to rest, and asking for one is
64
- * asking for the limit cycle §7 P5 exists to prevent. If a garment ever needs
65
- * more, the answer is a hard bend row with a multiplier, not a bigger number
66
- * here.
67
- * @type {number}
68
- */
69
- export const CLOTH_BEND_RATIO_MAX = 8;
70
-
71
- /**
72
- * Bend stiffness just above `bend = 0`, as a multiple of `m_eff/dt²`. Four
73
- * orders of magnitude below the ceiling, which is what makes the log map
74
- * useful across the whole range instead of spending most of it near zero.
75
- * @type {number}
76
- */
77
- export const CLOTH_BEND_RATIO_MIN = 1e-3;
78
-
79
- /**
80
- * How many times its own **correction authority** a particle may travel in one
81
- * fixed step before the velocity clamp of §7 P1 catches it.
82
- *
83
- * ## Not `thickness`, and the measurement is why
84
- *
85
- * §7 P1 asks for a clamp "derived from `thickness` and `h`", and that turns out
86
- * to be the wrong length scale for this job. `thickness` is a **contact**
87
- * radius: a clamp built from it is a tunnelling bound, and a tunnelling bound
88
- * sits *below* ordinary cloth speeds rather than above them. Silk is 4 mm
89
- * thick, so at 60 Hz "a particle may not cross its own radius in a step" is
90
- * 0.24 m/s — and M1 measured a rope behind a 9 m/s sprinter reaching 13 m/s
91
- * (§7 P7). Any multiple large enough to stop the clamp being a *behaviour* for
92
- * silk is large enough to make it meaningless for leather, because the two
93
- * thicknesses differ by 5× and their speeds do not.
94
- *
95
- * ## What the scale actually is
96
- *
97
- * The solver has a measurable ability to pull a particle back, and it is not
98
- * unlimited: the trust region caps each vertex update at the **shortest row
99
- * incident on that particle** (§5.3), so one fixed step can move a particle at
100
- * most `shortest_row · substeps · iterations`. M1 measured what happens past
101
- * it — a 30-link chain kicked at 16 m/s at 1 substep × 1 iteration stretches to
102
- * **17× its own reach** before recovering, against 1.02× when it is dropped
103
- * under gravity, and 2.6× for the same kick at 2×4. The tether row is not what
104
- * failed there; the tether row was never given a chance to act.
105
- *
106
- * So the clamp is a multiple of exactly that quantity, which makes it a bound
107
- * on *the solver being asked to do more than it can*, and makes it scale with
108
- * the budget the fabric bought and the mesh it is built on rather than with a
109
- * contact radius it does not use until M2.
110
- *
111
- * Four, because one would bind: a coat on a sprinting character carries several
112
- * metres a second of anchor-relative velocity, and a clamp that engages there
113
- * is a behaviour rather than a backstop. Four leaves every library entry an
114
- * order of magnitude of headroom over its measured peak and still bounds the
115
- * absurd cases in a handful of steps.
116
- * @type {number}
117
- */
118
- export const CLOTH_VELOCITY_CORRECTION_MARGIN = 4;
119
-
120
- /**
121
- * Velocity decay rate at `damping = 1`, per second.
122
- *
123
- * `damping` maps to an exponential decay rather than a per-step multiplier so
124
- * that the same value means the same thing at any fixed rate. At the default
125
- * `damping = 0.15` the time constant is a third of a second, which is a cape
126
- * that stops swinging without looking like it is under water.
127
- * @type {number}
128
- */
129
- export const CLOTH_DAMPING_RATE = 20;
130
-
131
- /**
132
- * How far a cloth's anchor may carry it in one fixed step, as a multiple of the
133
- * cloth's own reach. Motion above this is felt as though it were exactly this,
134
- * which is what "anchor speed limit" means in §7 P7.
135
- *
136
- * Expressing it as a fraction of reach rather than in metres per second is what
137
- * makes it work for a 3 cm pendant and a 30 m mooring line at the same time: a
138
- * cloth is whipped by motion large *compared to itself*, and the reach is the
139
- * only length scale the cloth carries. Half a reach per step is 30 reaches a
140
- * second at 60 Hz, which no character locomotion comes near — §7 P7's own
141
- * profile peaks two orders below it — and which a lift, a lurching vehicle or a
142
- * badly-keyed cut does exceed.
143
- * @type {number}
144
- */
145
- export const CLOTH_ANCHOR_TRAVEL_REACH = 0.5;
146
-
147
- /**
148
- * How far a cloth's anchor may rotate in one fixed step, radians. Rotation
149
- * above this is felt as though it were exactly this.
150
- *
151
- * Unlike the travel limit this has no length scale to hang off — an angle is
152
- * already dimensionless — so it is a plain number. Half a radian per step is
153
- * about 1,700 degrees a second, which is a spin rather than a turn.
154
- * @type {number}
155
- */
156
- export const CLOTH_ANCHOR_ROTATION_LIMIT = 0.5;
157
-
158
- /**
159
- * Anchor displacement in one fixed step, as a multiple of the cloth's reach,
160
- * above which the motion is a **teleport** rather than locomotion (§7 P6).
161
- *
162
- * Four reaches in one step is 240 reaches a second: for a 1 m rope that is
163
- * 240 m/s, well past anything the world moves at and well short of the values a
164
- * cut or a level load produces.
165
- * @type {number}
166
- */
167
- export const CLOTH_TELEPORT_REACH = 4;
168
-
169
- /**
170
- * Absolute floor on the teleport threshold, metres per fixed step.
171
- *
172
- * The reach multiple alone would make a small cloth absurdly twitchy — a 3 cm
173
- * pendant would call 7 m/s a teleport, which is a brisk walk. This floor is
174
- * 2 metres in a sixtieth of a second, so nothing under 120 m/s is a teleport
175
- * whatever size the cloth is.
176
- * @type {number}
177
- */
178
- export const CLOTH_TELEPORT_FLOOR = 2;
179
-
180
- /**
181
- * Length of the stabilisation window after a teleport reset, in fixed steps.
182
- *
183
- * The velocity limit ramps linearly from zero back to its full value across it,
184
- * so a re-seeded cloth cannot leave the animated pose faster than the window
185
- * allows however wrong its first solve is. A third of a second at 60 Hz.
186
- * @type {number}
187
- */
188
- export const CLOTH_STABILISE_STEPS = 20;
189
-
190
- /**
191
- * Speed below which a particle counts as still, as a fraction of the cloth's
192
- * reach per second. A metre-long rope sleeps once nothing on it is moving
193
- * faster than a millimetre a second.
194
- * @type {number}
195
- */
196
- export const CLOTH_SLEEP_SPEED_RATIO = 1e-3;
197
-
198
- /**
199
- * How many consecutive still steps put a cloth to sleep (§7 P5). Half a second
200
- * at 60 Hz, which is long enough that a cloth pausing at the top of a swing
201
- * does not sleep through the way down.
202
- * @type {number}
203
- */
204
- export const CLOTH_SLEEP_STEPS = 30;
205
-
206
- /**
207
- * Fabric extension allowance for a normalised `stretch`, as a fraction of rest
208
- * length. Log-mapped between {@link CLOTH_STRAIN_MAX} and
209
- * {@link CLOTH_STRAIN_MIN}, so equal steps in `stretch` are equal ratios in
210
- * strain and `0.9` is not four orders of magnitude away from `0.7`.
211
- *
212
- * @param {number} stretch `[0, 1]`
213
- * @returns {number} strain, `L_max = L₀·(1 + ε)`
214
- */
215
- export function cloth_strain_allowance(stretch) {
216
- const t = stretch < 0 ? 0 : (stretch > 1 ? 1 : stretch);
217
-
218
- return CLOTH_STRAIN_MAX * Math.pow(CLOTH_STRAIN_MIN / CLOTH_STRAIN_MAX, t);
219
- }
220
-
221
- /**
222
- * Bend row stiffness for a normalised `bend`, as a multiple of the row's own
223
- * `m_eff/dt²`. Log-mapped, and **exactly zero at `bend = 0`** — a log map
224
- * cannot reach zero, and "no bending resistance at all" is a state a chain is
225
- * actually in rather than a limit it approaches.
226
- *
227
- * @param {number} bend `[0, 1]`
228
- * @returns {number} ratio of `m_eff/dt²`
229
- */
230
- export function cloth_bend_ratio(bend) {
231
- if (bend <= 0) {
232
- return 0;
233
- }
234
-
235
- const t = bend > 1 ? 1 : bend;
236
-
237
- return CLOTH_BEND_RATIO_MIN * Math.pow(CLOTH_BEND_RATIO_MAX / CLOTH_BEND_RATIO_MIN, t);
238
- }
239
-
240
- /**
241
- * Largest speed a particle may carry, metres per second. §7 P1, and see
242
- * {@link CLOTH_VELOCITY_CORRECTION_MARGIN} for why this is built out of the
243
- * mesh and the budget rather than out of `thickness`.
244
- *
245
- * @param {number} shortest_row metres — the shortest row in the cloth, which
246
- is what the trust region caps a vertex update at
247
- * @param {number} substeps
248
- * @param {number} iterations
249
- * @param {number} dt fixed step, seconds
250
- * @returns {number}
251
- */
252
- export function cloth_velocity_limit(shortest_row, substeps, iterations, dt) {
253
- return CLOTH_VELOCITY_CORRECTION_MARGIN * shortest_row * substeps * iterations / dt;
254
- }
255
-
256
- /**
257
- * Fraction of a particle's velocity surviving one fixed step. §7 P5, and see
258
- * {@link ClothDynamics#damping} for why this is a correctness mechanism rather
259
- * than a taste control.
260
- *
261
- * @param {number} damping `[0, 1]`
262
- * @param {number} dt fixed step, seconds
263
- * @returns {number} `[0, 1]`
264
- */
265
- export function cloth_velocity_retention(damping, dt) {
266
- if (damping <= 0) {
267
- return 1;
268
- }
269
-
270
- return Math.exp(-CLOTH_DAMPING_RATE * (damping > 1 ? 1 : damping) * dt);
271
- }
1
+ /**
2
+ * # Normalised coordinates → row parameters
3
+ *
4
+ * {@link ClothDynamics}' stiffnesses are coordinates in `[0, 1]`, and this is
5
+ * the whole of what they mean. It is one module rather than methods on the
6
+ * value object because the mapping is *measured* — every constant below has a
7
+ * number in `MEASUREMENTS.md` behind it — and a measured mapping deserves to be
8
+ * readable on its own and specced on its own.
9
+ *
10
+ * ## Why neither stiffness maps to newtons per metre
11
+ *
12
+ * M0's central finding: a **soft** row — a plain penalty — is dissipative only
13
+ * while its stiffness stays below about `8·(m/h²)`, and above that boundary the
14
+ * step *adds* energy and the cloth sustains a limit cycle forever. More
15
+ * iterations and more substeps shrink it; neither removes it
16
+ * (`MEASUREMENTS.md` §6). And that boundary is not a stiffness: it is a
17
+ * multiple of the row's own inertial scale, which moved across five decades of
18
+ * particle mass in §4's sweep without the answer changing.
19
+ *
20
+ * Two consequences, one for each stiffness:
21
+ *
22
+ * - **`stretch` cannot be a penalty at all.** Real fabric wants a stretch
23
+ * stiffness far above that boundary — for a half-gram particle at 60 Hz × 2
24
+ * substeps it sits near 60 N/m, a rubber band — so the stretch row is hard
25
+ * (`Infinity`, augmented Lagrangian), and what `stretch` actually selects is
26
+ * {@link cloth_strain_allowance}: how far the fabric may extend before the
27
+ * strain-limit row of §6 stops it.
28
+ * - **`bend` maps to a ratio.** A bend row is soft and must stay inside the
29
+ * dissipative band, so its stiffness is expressed as a multiple of
30
+ * `m_eff/dt²` — the row's own inertial scale at the **fixed** step rather
31
+ * than the substep. Two things fall out of that choice and both are wanted:
32
+ * the fabric's look is invariant to how heavy the author made the particles
33
+ * (which is what a normalised `[0, 1]` knob should mean), and the row is
34
+ * inside the band at *any* substep count, since `k/(m/h²) = ratio/substeps²`
35
+ * and `substeps ≥ 1`. A stiffness in newtons per metre has neither property.
36
+ *
37
+ * @author Alex Goldring
38
+ * @copyright Company Named Limited (c) 2026
39
+ */
40
+
41
+ /**
42
+ * Strain a fabric at `stretch = 0` may carry: a quarter of its own length, a
43
+ * loose knit. Chosen as the loosest thing that still reads as fabric rather
44
+ * than as elastic.
45
+ * @type {number}
46
+ */
47
+ export const CLOTH_STRAIN_MAX = 0.25;
48
+
49
+ /**
50
+ * Strain a fabric at `stretch = 1` may carry: a tenth of a per cent, which is
51
+ * a chain. Below this the strain-limit row is asking for more precision than a
52
+ * `Float32` position over a garment-sized coordinate resolves.
53
+ * @type {number}
54
+ */
55
+ export const CLOTH_STRAIN_MIN = 1e-3;
56
+
57
+ /**
58
+ * Bend stiffness at `bend = 1`, as a multiple of the row's `m_eff/dt²`.
59
+ *
60
+ * It is 8 because that is the top of the dissipative band M0 measured
61
+ * (`MEASUREMENTS.md` §4 and §6) and a bend row is soft. The consequence, stated
62
+ * rather than hidden: **bending saturates**. A fabric stiffer than this cannot
63
+ * be expressed as a soft row that also comes to rest, and asking for one is
64
+ * asking for the limit cycle §7 P5 exists to prevent. If a garment ever needs
65
+ * more, the answer is a hard bend row with a multiplier, not a bigger number
66
+ * here.
67
+ * @type {number}
68
+ */
69
+ export const CLOTH_BEND_RATIO_MAX = 8;
70
+
71
+ /**
72
+ * Bend stiffness just above `bend = 0`, as a multiple of `m_eff/dt²`. Four
73
+ * orders of magnitude below the ceiling, which is what makes the log map
74
+ * useful across the whole range instead of spending most of it near zero.
75
+ * @type {number}
76
+ */
77
+ export const CLOTH_BEND_RATIO_MIN = 1e-3;
78
+
79
+ /**
80
+ * How many times its own **correction authority** a particle may travel in one
81
+ * fixed step before the velocity clamp of §7 P1 catches it.
82
+ *
83
+ * ## Not `thickness`, and the measurement is why
84
+ *
85
+ * §7 P1 asks for a clamp "derived from `thickness` and `h`", and that turns out
86
+ * to be the wrong length scale for this job. `thickness` is a **contact**
87
+ * radius: a clamp built from it is a tunnelling bound, and a tunnelling bound
88
+ * sits *below* ordinary cloth speeds rather than above them. Silk is 4 mm
89
+ * thick, so at 60 Hz "a particle may not cross its own radius in a step" is
90
+ * 0.24 m/s — and M1 measured a rope behind a 9 m/s sprinter reaching 13 m/s
91
+ * (§7 P7). Any multiple large enough to stop the clamp being a *behaviour* for
92
+ * silk is large enough to make it meaningless for leather, because the two
93
+ * thicknesses differ by 5× and their speeds do not.
94
+ *
95
+ * ## What the scale actually is
96
+ *
97
+ * The solver has a measurable ability to pull a particle back, and it is not
98
+ * unlimited: the trust region caps each vertex update at the **shortest row
99
+ * incident on that particle** (§5.3), so one fixed step can move a particle at
100
+ * most `shortest_row · substeps · iterations`. M1 measured what happens past
101
+ * it — a 30-link chain kicked at 16 m/s at 1 substep × 1 iteration stretches to
102
+ * **17× its own reach** before recovering, against 1.02× when it is dropped
103
+ * under gravity, and 2.6× for the same kick at 2×4. The tether row is not what
104
+ * failed there; the tether row was never given a chance to act.
105
+ *
106
+ * So the clamp is a multiple of exactly that quantity, which makes it a bound
107
+ * on *the solver being asked to do more than it can*, and makes it scale with
108
+ * the budget the fabric bought and the mesh it is built on rather than with a
109
+ * contact radius it does not use until M2.
110
+ *
111
+ * Four, because one would bind: a coat on a sprinting character carries several
112
+ * metres a second of anchor-relative velocity, and a clamp that engages there
113
+ * is a behaviour rather than a backstop. Four leaves every library entry an
114
+ * order of magnitude of headroom over its measured peak and still bounds the
115
+ * absurd cases in a handful of steps.
116
+ * @type {number}
117
+ */
118
+ export const CLOTH_VELOCITY_CORRECTION_MARGIN = 4;
119
+
120
+ /**
121
+ * Velocity decay rate at `damping = 1`, per second.
122
+ *
123
+ * `damping` maps to an exponential decay rather than a per-step multiplier so
124
+ * that the same value means the same thing at any fixed rate. At the default
125
+ * `damping = 0.15` the time constant is a third of a second, which is a cape
126
+ * that stops swinging without looking like it is under water.
127
+ * @type {number}
128
+ */
129
+ export const CLOTH_DAMPING_RATE = 20;
130
+
131
+ /**
132
+ * How far a cloth's anchor may carry it in one fixed step, as a multiple of the
133
+ * cloth's own reach. Motion above this is felt as though it were exactly this,
134
+ * which is what "anchor speed limit" means in §7 P7.
135
+ *
136
+ * Expressing it as a fraction of reach rather than in metres per second is what
137
+ * makes it work for a 3 cm pendant and a 30 m mooring line at the same time: a
138
+ * cloth is whipped by motion large *compared to itself*, and the reach is the
139
+ * only length scale the cloth carries. Half a reach per step is 30 reaches a
140
+ * second at 60 Hz, which no character locomotion comes near — §7 P7's own
141
+ * profile peaks two orders below it — and which a lift, a lurching vehicle or a
142
+ * badly-keyed cut does exceed.
143
+ * @type {number}
144
+ */
145
+ export const CLOTH_ANCHOR_TRAVEL_REACH = 0.5;
146
+
147
+ /**
148
+ * How far a cloth's anchor may rotate in one fixed step, radians. Rotation
149
+ * above this is felt as though it were exactly this.
150
+ *
151
+ * Unlike the travel limit this has no length scale to hang off — an angle is
152
+ * already dimensionless — so it is a plain number. Half a radian per step is
153
+ * about 1,700 degrees a second, which is a spin rather than a turn.
154
+ * @type {number}
155
+ */
156
+ export const CLOTH_ANCHOR_ROTATION_LIMIT = 0.5;
157
+
158
+ /**
159
+ * Anchor displacement in one fixed step, as a multiple of the cloth's reach,
160
+ * above which the motion is a **teleport** rather than locomotion (§7 P6).
161
+ *
162
+ * Four reaches in one step is 240 reaches a second: for a 1 m rope that is
163
+ * 240 m/s, well past anything the world moves at and well short of the values a
164
+ * cut or a level load produces.
165
+ * @type {number}
166
+ */
167
+ export const CLOTH_TELEPORT_REACH = 4;
168
+
169
+ /**
170
+ * Absolute floor on the teleport threshold, metres per fixed step.
171
+ *
172
+ * The reach multiple alone would make a small cloth absurdly twitchy — a 3 cm
173
+ * pendant would call 7 m/s a teleport, which is a brisk walk. This floor is
174
+ * 2 metres in a sixtieth of a second, so nothing under 120 m/s is a teleport
175
+ * whatever size the cloth is.
176
+ * @type {number}
177
+ */
178
+ export const CLOTH_TELEPORT_FLOOR = 2;
179
+
180
+ /**
181
+ * Length of the stabilisation window after a teleport reset, in fixed steps.
182
+ *
183
+ * The velocity limit ramps linearly from zero back to its full value across it,
184
+ * so a re-seeded cloth cannot leave the animated pose faster than the window
185
+ * allows however wrong its first solve is. A third of a second at 60 Hz.
186
+ * @type {number}
187
+ */
188
+ export const CLOTH_STABILISE_STEPS = 20;
189
+
190
+ /**
191
+ * Aerodynamic relaxation rate at `drag = 1`, per second (§10).
192
+ *
193
+ * ## Linear, not log
194
+ *
195
+ * `bend` is log-mapped because a stiffness spans decades and an author needs
196
+ * the whole range to be useful. Drag does not: the library's own entries run
197
+ * from leather at 0.05 to silk at 0.45, a factor of nine, and a linear map is
198
+ * the one that keeps that factor of nine meaning a factor of nine. It is also
199
+ * exactly zero at zero without a special case, which a log map cannot be.
200
+ *
201
+ * ## Sixty, because that is "the cloth goes where the air goes"
202
+ *
203
+ * The rate is a reciprocal time constant, so what `drag = 1` has to mean is a
204
+ * cloth with no aerodynamic memory at all — one that takes the air's velocity
205
+ * within a step. At 60 Hz, a rate of 60 closes 63% of the gap to the air every
206
+ * step and has a time constant of 17 ms, which is that. The library then reads:
207
+ * silk 27/s (37 ms), hair 18/s, cotton 12/s (83 ms), rope 7.2/s, denim 4.8/s
208
+ * (0.21 s), leather and chain 3/s (0.33 s) — a light banner that answers a gust
209
+ * within a couple of frames and an armour skirt that takes a third of a second
210
+ * to notice one, which is the ordering the fabrics already claimed.
211
+ *
212
+ * Raising it further buys nothing: {@link cloth_drag_response} saturates at
213
+ * `1/dt` by construction, so past about `1/dt` the whole range compresses into
214
+ * "the cloth is a streamer". `MEASUREMENTS.md` §48.
215
+ * @type {number}
216
+ */
217
+ export const CLOTH_DRAG_RATE_MAX = 60;
218
+
219
+ /**
220
+ * Speed below which the air counts as unchanged, as a fraction of the cloth's
221
+ * reach per second — §10's wake test, which asks whether a gust has arrived.
222
+ *
223
+ * This was the sleep test's own threshold until the sleep test stopped reading
224
+ * a speed; see {@link CLOTH_SLEEP_DISPLACEMENT_RATIO} for why.
225
+ * @type {number}
226
+ */
227
+ export const CLOTH_SLEEP_SPEED_RATIO = 1e-3;
228
+
229
+ /**
230
+ * How far a particle may travel from the window's anchor and still count as
231
+ * still, as a fraction of the cloth's reach (§7 P5).
232
+ *
233
+ * **Displacement rather than speed, and a contact is why.** A cloth resting on
234
+ * a collider carries contact rows whose penalty `γ = 1` never decays, and the
235
+ * configuration it settles into is a *bounded limit cycle* rather than a rest
236
+ * state: measured on an 8-link rope on a floor, a tenth of a millimetre of
237
+ * travel per step — invisible — at a peak particle speed of 1.5e-2 m/s, which
238
+ * is eighteen times what the old speed threshold allowed. An instantaneous
239
+ * speed cannot tell a cloth vibrating in place apart from one going somewhere;
240
+ * the distance it has covered since the window opened can, and that is what
241
+ * §7 P5's own text has always described.
242
+ *
243
+ * `5e-4` rather than {@link CLOTH_SLEEP_SPEED_RATIO}'s `1e-3` so the gate is no
244
+ * *looser* than the speed test it replaces: over the {@link CLOTH_SLEEP_STEPS}
245
+ * window at the engine's 60 Hz fixed step, half a thousandth of a reach is the
246
+ * same millimetre a second. Every library entry on a floor or a sphere sleeps
247
+ * inside 961 steps at this value. `MEASUREMENTS.md` §53.
248
+ * @type {number}
249
+ */
250
+ export const CLOTH_SLEEP_DISPLACEMENT_RATIO = 5e-4;
251
+
252
+ /**
253
+ * How many consecutive still steps put a cloth to sleep (§7 P5). Half a second
254
+ * at 60 Hz, which is long enough that a cloth pausing at the top of a swing
255
+ * does not sleep through the way down.
256
+ * @type {number}
257
+ */
258
+ export const CLOTH_SLEEP_STEPS = 30;
259
+
260
+ /**
261
+ * Fabric extension allowance for a normalised `stretch`, as a fraction of rest
262
+ * length. Log-mapped between {@link CLOTH_STRAIN_MAX} and
263
+ * {@link CLOTH_STRAIN_MIN}, so equal steps in `stretch` are equal ratios in
264
+ * strain and `0.9` is not four orders of magnitude away from `0.7`.
265
+ *
266
+ * @param {number} stretch `[0, 1]`
267
+ * @returns {number} strain, `L_max = L₀·(1 + ε)`
268
+ */
269
+ export function cloth_strain_allowance(stretch) {
270
+ const t = stretch < 0 ? 0 : (stretch > 1 ? 1 : stretch);
271
+
272
+ return CLOTH_STRAIN_MAX * Math.pow(CLOTH_STRAIN_MIN / CLOTH_STRAIN_MAX, t);
273
+ }
274
+
275
+ /**
276
+ * Bend row stiffness for a normalised `bend`, as a multiple of the row's own
277
+ * `m_eff/dt²`. Log-mapped, and **exactly zero at `bend = 0`** — a log map
278
+ * cannot reach zero, and "no bending resistance at all" is a state a chain is
279
+ * actually in rather than a limit it approaches.
280
+ *
281
+ * @param {number} bend `[0, 1]`
282
+ * @returns {number} ratio of `m_eff/dt²`
283
+ */
284
+ export function cloth_bend_ratio(bend) {
285
+ if (bend <= 0) {
286
+ return 0;
287
+ }
288
+
289
+ const t = bend > 1 ? 1 : bend;
290
+
291
+ return CLOTH_BEND_RATIO_MIN * Math.pow(CLOTH_BEND_RATIO_MAX / CLOTH_BEND_RATIO_MIN, t);
292
+ }
293
+
294
+ /**
295
+ * Largest speed a particle may carry, metres per second. §7 P1, and see
296
+ * {@link CLOTH_VELOCITY_CORRECTION_MARGIN} for why this is built out of the
297
+ * mesh and the budget rather than out of `thickness`.
298
+ *
299
+ * @param {number} shortest_row metres — the shortest row in the cloth, which
300
+ is what the trust region caps a vertex update at
301
+ * @param {number} substeps
302
+ * @param {number} iterations
303
+ * @param {number} dt fixed step, seconds
304
+ * @returns {number}
305
+ */
306
+ export function cloth_velocity_limit(shortest_row, substeps, iterations, dt) {
307
+ return CLOTH_VELOCITY_CORRECTION_MARGIN * shortest_row * substeps * iterations / dt;
308
+ }
309
+
310
+ /**
311
+ * §10's aerodynamic coupling as the **per-step response** the step multiplies
312
+ * the relative flow by, 1/s.
313
+ *
314
+ * Not a rate, and the difference is a stability argument rather than a
315
+ * convenience. The step holds one acceleration for the whole fixed step, so an
316
+ * explicit `rate·(u − v)` changes the velocity by `rate·dt·(u − v)` — which
317
+ * overshoots the air once `rate·dt > 1` and diverges past 2. §1's first
318
+ * commitment is "not at 5 fps", which is a `dt` of 0.2 s and a rate of 10.
319
+ *
320
+ * The exact solution of the same linear ODE has no such boundary:
321
+ *
322
+ * Δv = (1 − e^(−rate·dt))·(u − v)
323
+ *
324
+ * closes a fraction of the gap that is strictly below one for every `rate` and
325
+ * every `dt`, so the drag can never push a particle past the air it is
326
+ * relaxing toward. Dividing by `dt` turns it back into the acceleration the
327
+ * solver wants, and the exponential is evaluated **once per cloth per step** on
328
+ * the main thread rather than per particle.
329
+ *
330
+ * It is also the same step `GlobalFluidEffector` takes for the air itself —
331
+ * both are relaxations toward a velocity, and a cloth and the air around it
332
+ * reaching their common answer by the same arithmetic is a symmetry worth
333
+ * having.
334
+ *
335
+ * @param {number} drag `[0, 1]`
336
+ * @param {number} dt fixed step, seconds
337
+ * @returns {number} 1/s; `0` when there is no coupling at all
338
+ */
339
+ export function cloth_drag_response(drag, dt) {
340
+ if (drag <= 0 || dt <= 0) {
341
+ return 0;
342
+ }
343
+
344
+ const rate = CLOTH_DRAG_RATE_MAX * (drag > 1 ? 1 : drag);
345
+
346
+ // `-expm1(-x)` is `1 - exp(-x)` without the cancellation at small `x`, and
347
+ // small `x` is every fabric below silk at a 60 Hz step.
348
+ return -Math.expm1(-rate * dt) / dt;
349
+ }
350
+
351
+ /**
352
+ * Fraction of a particle's velocity surviving one fixed step. §7 P5, and see
353
+ * {@link ClothDynamics#damping} for why this is a correctness mechanism rather
354
+ * than a taste control.
355
+ *
356
+ * @param {number} damping `[0, 1]`
357
+ * @param {number} dt fixed step, seconds
358
+ * @returns {number} `[0, 1]`
359
+ */
360
+ export function cloth_velocity_retention(damping, dt) {
361
+ if (damping <= 0) {
362
+ return 1;
363
+ }
364
+
365
+ return Math.exp(-CLOTH_DAMPING_RATE * (damping > 1 ? 1 : damping) * dt);
366
+ }