@woosh/meep-engine 3.42.0 → 3.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (345) hide show
  1. package/editor/prototypeEditorShell.d.ts.map +1 -1
  2. package/editor/prototypeEditorShell.js +4 -2
  3. package/package.json +91 -96
  4. package/src/engine/Clock.d.ts +15 -0
  5. package/src/engine/Clock.d.ts.map +1 -1
  6. package/src/engine/Clock.js +29 -5
  7. package/src/engine/Engine.d.ts.map +1 -1
  8. package/src/engine/Engine.js +11 -19
  9. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.d.ts +57 -0
  10. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.d.ts.map +1 -0
  11. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.js +84 -0
  12. package/src/engine/graphics3/AnimationGraphSystem.d.ts +23 -13
  13. package/src/engine/graphics3/AnimationGraphSystem.d.ts.map +1 -1
  14. package/src/engine/graphics3/AnimationGraphSystem.js +61 -64
  15. package/src/engine/graphics3/AnimationSystem.d.ts +24 -15
  16. package/src/engine/graphics3/AnimationSystem.d.ts.map +1 -1
  17. package/src/engine/graphics3/AnimationSystem.js +67 -61
  18. package/src/engine/graphics3/MeshSkinSystem.d.ts +56 -0
  19. package/src/engine/graphics3/MeshSkinSystem.d.ts.map +1 -0
  20. package/src/engine/graphics3/MeshSkinSystem.js +317 -0
  21. package/src/engine/graphics3/MeshSystem.d.ts +15 -35
  22. package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
  23. package/src/engine/graphics3/MeshSystem.js +21 -298
  24. package/src/engine/graphics3/RowChains.d.ts +76 -0
  25. package/src/engine/graphics3/RowChains.d.ts.map +1 -0
  26. package/src/engine/graphics3/RowChains.js +347 -0
  27. package/src/engine/graphics3/ShadedGeometrySystem.d.ts +6 -0
  28. package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
  29. package/src/engine/graphics3/ShadedGeometrySystem.js +329 -309
  30. package/src/engine/graphics3/animation/AnimationClips.d.ts +56 -0
  31. package/src/engine/graphics3/animation/AnimationClips.d.ts.map +1 -0
  32. package/src/engine/graphics3/animation/AnimationClips.js +79 -0
  33. package/src/engine/graphics3/animation/ClipListPlayer.d.ts +13 -14
  34. package/src/engine/graphics3/animation/ClipListPlayer.d.ts.map +1 -1
  35. package/src/engine/graphics3/animation/ClipListPlayer.js +262 -263
  36. package/src/engine/graphics3/animation/write_clip_playback.d.ts +3 -3
  37. package/src/engine/graphics3/animation/write_clip_playback.js +4 -4
  38. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts +5 -0
  39. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts.map +1 -1
  40. package/src/engine/graphics3/pose/query_entity_node_world_pose.js +80 -75
  41. package/src/engine/graphics3/prefab/PrefabInstance.d.ts +4 -24
  42. package/src/engine/graphics3/prefab/PrefabInstance.d.ts.map +1 -1
  43. package/src/engine/graphics3/prefab/PrefabInstance.js +60 -80
  44. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts +16 -3
  45. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts.map +1 -1
  46. package/src/engine/graphics3/prefab/prefab_instantiate.js +49 -12
  47. package/src/engine/graphics3/prefab/prefab_place.d.ts +31 -17
  48. package/src/engine/graphics3/prefab/prefab_place.d.ts.map +1 -1
  49. package/src/engine/graphics3/prefab/prefab_place.js +175 -130
  50. package/src/engine/graphics3/register_clips.d.ts +64 -0
  51. package/src/engine/graphics3/register_clips.d.ts.map +1 -0
  52. package/src/engine/graphics3/register_clips.js +114 -0
  53. package/src/engine/physics/cloth/MEASUREMENTS.md +795 -0
  54. package/src/engine/physics/cloth/PLAN.md +339 -9
  55. package/src/engine/physics/cloth/build/ClothProxy.d.ts +113 -61
  56. package/src/engine/physics/cloth/build/ClothProxy.d.ts.map +1 -1
  57. package/src/engine/physics/cloth/build/ClothProxy.js +142 -77
  58. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts +22 -0
  59. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts.map +1 -0
  60. package/src/engine/physics/cloth/build/cloth_bind_in_frame.js +75 -0
  61. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +43 -30
  62. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  63. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +357 -284
  64. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts +62 -0
  65. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts.map +1 -0
  66. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.js +280 -0
  67. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts +1 -1
  68. package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +1 -1
  69. package/src/engine/physics/cloth/ecs/Cloth.d.ts +17 -9
  70. package/src/engine/physics/cloth/ecs/Cloth.d.ts.map +1 -1
  71. package/src/engine/physics/cloth/ecs/Cloth.js +220 -212
  72. package/src/engine/physics/cloth/ecs/ClothDynamicsFlags.js +6 -0
  73. package/src/engine/physics/cloth/ecs/ClothHold.d.ts +91 -0
  74. package/src/engine/physics/cloth/ecs/ClothHold.d.ts.map +1 -0
  75. package/src/engine/physics/cloth/ecs/ClothHold.js +103 -0
  76. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +254 -48
  77. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  78. package/src/engine/physics/cloth/ecs/ClothInstance.js +277 -47
  79. package/src/engine/physics/cloth/ecs/ClothPin.d.ts +73 -0
  80. package/src/engine/physics/cloth/ecs/ClothPin.d.ts.map +1 -0
  81. package/src/engine/physics/cloth/ecs/ClothPin.js +92 -0
  82. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.d.ts +36 -0
  83. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.d.ts.map +1 -0
  84. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.js +61 -0
  85. package/src/engine/physics/cloth/ecs/ClothRig.d.ts +23 -17
  86. package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -1
  87. package/src/engine/physics/cloth/ecs/ClothRig.js +29 -27
  88. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +12 -14
  89. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  90. package/src/engine/physics/cloth/ecs/ClothSystem.js +20 -15
  91. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +57 -36
  92. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  93. package/src/engine/physics/cloth/ecs/ClothWorld.js +816 -179
  94. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +12 -13
  95. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -1
  96. package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +20 -14
  97. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +63 -11
  98. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  99. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +321 -84
  100. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +9 -7
  101. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  102. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +9 -7
  103. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +3 -3
  104. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +30 -30
  105. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts +37 -0
  106. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts.map +1 -0
  107. package/src/engine/physics/cloth/ecs/cloth_geodesic.js +142 -0
  108. package/src/engine/physics/cloth/ecs/cloth_holds.d.ts +97 -0
  109. package/src/engine/physics/cloth/ecs/cloth_holds.d.ts.map +1 -0
  110. package/src/engine/physics/cloth/ecs/cloth_holds.js +608 -0
  111. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts +2 -2
  112. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -1
  113. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +160 -9
  114. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +17 -22
  115. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  116. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +55 -117
  117. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -6
  118. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  119. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +44 -15
  120. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +5 -0
  121. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  122. package/src/engine/physics/cloth/ecs/cloth_write_back.js +60 -16
  123. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -1
  124. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +65 -58
  125. package/src/engine/physics/cloth/playground/collide_main.js +1 -1
  126. package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -1
  127. package/src/engine/physics/cloth/playground/garment_build.js +17 -5
  128. package/src/engine/physics/cloth/playground/garment_main.js +1 -1
  129. package/src/engine/physics/cloth/playground/rig_build.d.ts.map +1 -1
  130. package/src/engine/physics/cloth/playground/rig_build.js +302 -296
  131. package/src/engine/physics/cloth/solver/ClothState.d.ts +45 -7
  132. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  133. package/src/engine/physics/cloth/solver/ClothState.js +63 -7
  134. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +6 -1
  135. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
  136. package/src/engine/physics/cloth/solver/cloth_contact_find.js +7 -2
  137. package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts +114 -0
  138. package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts.map +1 -0
  139. package/src/engine/physics/cloth/solver/cloth_hold_line.js +362 -0
  140. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts +6 -2
  141. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -1
  142. package/src/engine/physics/cloth/solver/cloth_self_find.js +13 -13
  143. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +24 -12
  144. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  145. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +24 -12
  146. package/src/engine/physics/cloth/solver/cloth_step.d.ts +16 -0
  147. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  148. package/src/engine/physics/cloth/solver/cloth_step.js +183 -20
  149. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts +1 -0
  150. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -1
  151. package/src/engine/physics/cloth/solver/cloth_step_instance.js +10 -3
  152. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.d.ts +1 -1
  153. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.d.ts.map +1 -1
  154. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.js +353 -346
  155. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts +7 -5
  156. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -1
  157. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +7 -5
  158. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +9 -9
  159. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
  160. package/src/engine/physics/cloth/wind/cloth_sample_air.js +26 -26
  161. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  162. package/src/engine/simulation/Ticker.d.ts +13 -0
  163. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  164. package/src/engine/simulation/Ticker.js +43 -8
  165. package/src/shade/RENDERER_CONTRACT.md +8 -2
  166. package/src/shade/playground/mesh_row_ceiling/main.js +2 -1
  167. package/src/shade/playground/skinned_blas_refit/main.d.ts.map +1 -1
  168. package/src/shade/playground/skinned_blas_refit/main.js +11 -19
  169. package/src/shade/playground/skinned_blas_refit/place_character.d.ts +6 -3
  170. package/src/shade/playground/skinned_blas_refit/place_character.d.ts.map +1 -1
  171. package/src/shade/playground/skinned_blas_refit/place_character.js +90 -90
  172. package/src/shade/playground/skinned_mesh_soup/main.d.ts.map +1 -1
  173. package/src/shade/playground/skinned_mesh_soup/main.js +502 -509
  174. package/src/shade/playground/texture_encode/README.md +129 -109
  175. package/src/shade/playground/texture_encode/main.js +1430 -1430
  176. package/src/shade/playground/vgeo_runtime/README.md +5 -4
  177. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  178. package/src/shade/renderer/Renderer.js +6 -5
  179. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +45 -14
  180. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  181. package/src/shade/renderer/animation/GPUAnimationManager.js +316 -64
  182. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts +5 -0
  183. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  184. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +11 -1
  185. package/src/shade/renderer/atmosphere/GPUSky.d.ts +12 -0
  186. package/src/shade/renderer/atmosphere/GPUSky.d.ts.map +1 -1
  187. package/src/shade/renderer/atmosphere/GPUSky.js +162 -147
  188. package/src/shade/renderer/geometry/BoxGeometry.d.ts +1 -11
  189. package/src/shade/renderer/geometry/BoxGeometry.d.ts.map +1 -1
  190. package/src/shade/renderer/geometry/BoxGeometry.js +6 -13
  191. package/src/shade/renderer/geometry/CapsuleGeometry.d.ts +19 -0
  192. package/src/shade/renderer/geometry/CapsuleGeometry.d.ts.map +1 -0
  193. package/src/shade/renderer/geometry/CapsuleGeometry.js +24 -0
  194. package/src/shade/renderer/geometry/ConeGeometry.d.ts +20 -0
  195. package/src/shade/renderer/geometry/ConeGeometry.d.ts.map +1 -0
  196. package/src/shade/renderer/geometry/ConeGeometry.js +33 -0
  197. package/src/shade/renderer/geometry/CylinderGeometry.d.ts +21 -0
  198. package/src/shade/renderer/geometry/CylinderGeometry.d.ts.map +1 -0
  199. package/src/shade/renderer/geometry/CylinderGeometry.js +35 -0
  200. package/src/shade/renderer/geometry/PlaneGeometry.d.ts +17 -0
  201. package/src/shade/renderer/geometry/PlaneGeometry.d.ts.map +1 -0
  202. package/src/shade/renderer/geometry/PlaneGeometry.js +22 -0
  203. package/src/shade/renderer/geometry/TorusGeometry.d.ts +18 -0
  204. package/src/shade/renderer/geometry/TorusGeometry.d.ts.map +1 -0
  205. package/src/shade/renderer/geometry/TorusGeometry.js +23 -0
  206. package/src/shade/renderer/geometry/UVSphereGeometry.d.ts +21 -0
  207. package/src/shade/renderer/geometry/UVSphereGeometry.d.ts.map +1 -0
  208. package/src/shade/renderer/geometry/UVSphereGeometry.js +34 -0
  209. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts +19 -0
  210. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts.map +1 -0
  211. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.js +205 -0
  212. package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts +21 -0
  213. package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts.map +1 -0
  214. package/src/shade/renderer/geometry/primitives/make_cone_geometry.js +36 -0
  215. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts +1 -1
  216. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts.map +1 -1
  217. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.js +44 -9
  218. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts +20 -0
  219. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts.map +1 -0
  220. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.js +190 -0
  221. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  222. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +7 -2
  223. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts +26 -8
  224. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts.map +1 -1
  225. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js +56 -39
  226. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts +7 -0
  227. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts.map +1 -1
  228. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.js +46 -4
  229. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.d.ts.map +1 -1
  230. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.js +4 -2
  231. package/src/shade/renderer/gpu_primitive/sort/defs.d.ts +2 -2
  232. package/src/shade/renderer/gpu_primitive/sort/defs.js +79 -79
  233. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts +1 -1
  234. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts.map +1 -1
  235. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.js +7 -3
  236. package/src/shade/renderer/lightmap/bake/shader_lightmap_denoise_sh.d.ts.map +1 -1
  237. package/src/shade/renderer/lightmap/bake/shader_lightmap_denoise_sh.js +10 -3
  238. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  239. package/src/shade/renderer/particles/DESIGN.md +13 -9
  240. package/src/shade/renderer/particles/GPUParticleSystem.js +1 -1
  241. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts +4 -3
  242. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts.map +1 -1
  243. package/src/shade/renderer/particles/coherence/graph_particle_bucket.js +200 -194
  244. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  245. package/src/shade/renderer/particles/graph_particles.js +6 -2
  246. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts +1 -1
  247. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.js +1 -1
  248. package/src/shade/renderer/particles/warmup/graph_particle_warmup.d.ts.map +1 -1
  249. package/src/shade/renderer/particles/warmup/graph_particle_warmup.js +334 -329
  250. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  251. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  252. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +7 -2
  253. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.d.ts.map +1 -1
  254. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.js +16 -4
  255. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +3 -2
  256. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
  257. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +3 -2
  258. package/src/shade/renderer/scene/GPUSceneContext.d.ts +9 -1
  259. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  260. package/src/shade/renderer/scene/GPUSceneContext.js +23 -1
  261. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +2444 -2345
  262. package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.d.ts.map +1 -1
  263. package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.js +312 -310
  264. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts +3 -3
  265. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts.map +1 -1
  266. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.js +383 -375
  267. package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.d.ts.map +1 -1
  268. package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.js +349 -346
  269. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts +58 -0
  270. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts.map +1 -0
  271. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.js +536 -0
  272. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts +21 -7
  273. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts.map +1 -1
  274. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.js +291 -327
  275. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts +25 -0
  276. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts.map +1 -0
  277. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.js +99 -0
  278. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts +5 -3
  279. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts.map +1 -1
  280. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.js +47 -71
  281. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts +10 -0
  282. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts.map +1 -0
  283. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.js +50 -0
  284. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts +4 -5
  285. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts.map +1 -1
  286. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.js +7 -8
  287. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +4 -1
  288. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  289. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +74 -3
  290. package/src/shade/renderer/volumetrics/NOTES.md +1023 -957
  291. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.d.ts +5 -4
  292. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.d.ts.map +1 -1
  293. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.js +5 -4
  294. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.d.ts +1 -1
  295. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.js +1 -1
  296. package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.d.ts +1 -1
  297. package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.js +1 -1
  298. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts +41 -0
  299. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts.map +1 -0
  300. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.js +112 -0
  301. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts +9 -23
  302. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
  303. package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +18 -126
  304. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.d.ts +22 -0
  305. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.d.ts.map +1 -0
  306. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.js +228 -0
  307. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  308. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +0 -53
  309. package/src/shade/renderer/water/chunk_water_transport.d.ts.map +1 -1
  310. package/src/shade/renderer/water/chunk_water_transport.js +7 -5
  311. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +1 -1
  312. package/src/shade/renderer/water/medium/GPUWaterBodies.js +8 -2
  313. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts +3 -2
  314. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts.map +1 -1
  315. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.js +3 -2
  316. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  317. package/src/shade/renderer/water/shader_water.js +3 -1
  318. package/src/shade/renderer/water/surface/GPUWaterSurface.d.ts.map +1 -1
  319. package/src/shade/renderer/water/surface/GPUWaterSurface.js +3 -1
  320. package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts +4 -3
  321. package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts.map +1 -1
  322. package/src/shade/renderer/water/surface/chunk_water_surface_sample.js +17 -7
  323. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts.map +1 -1
  324. package/src/shade/renderer/water/surface/graph_water_tessellation.js +11 -4
  325. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -1
  326. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +93 -30
  327. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts.map +1 -1
  328. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.js +13 -5
  329. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts +29 -8
  330. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts.map +1 -1
  331. package/src/shade/renderer/water/surface/particles/chunk_water_particle.js +155 -30
  332. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts +6 -1
  333. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts.map +1 -1
  334. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.js +157 -39
  335. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts +91 -21
  336. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts.map +1 -1
  337. package/src/shade/renderer/water/surface/particles/shader_water_particles.js +442 -70
  338. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +11 -3
  339. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  340. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +3 -0
  341. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  342. package/src/shade/wgsl/validate_wgsl_source.js +74 -3
  343. package/src/engine/graphics3/register_instance_animation.d.ts +0 -114
  344. package/src/engine/graphics3/register_instance_animation.d.ts.map +0 -1
  345. package/src/engine/graphics3/register_instance_animation.js +0 -201
@@ -18,10 +18,15 @@ One solver over particles, driven by components:
18
18
  - **`Cloth`** — the thing that simulates. Put it on an entity and that entity's transform subtree
19
19
  becomes a simulated chain: a rope, a chain, a hanging sign, a mooring line.
20
20
  - **`ClothRig`** — add it alongside `Cloth` and the particles are the **joints of a skinned model**
21
- rather than the entity subtree. This is what makes a cape, a skirt, a banner on a character.
21
+ rather than the entity subtree. This is what makes a cape, a skirt, a banner on a character — and,
22
+ built from triangles by `cloth_proxy_from_mesh`, a sheet: a flag, a curtain, a cloth thrown over a
23
+ table (§19.5).
22
24
  - **`ClothCollider`** — the marker that opts an existing `(Collider, Transform64)` entity into being
23
25
  something cloth collides with. This is the `RigidBody`-analogue: it says *this collider participates*,
24
26
  and carries only what cloth needs that `Collider` does not already say.
27
+ - **`ClothPin`** — *M7.* Put it on any entity and that entity holds the particles it names. A cloth
28
+ has as many holders as name it — a rope its own top, a flag its pole, a cape both shoulders — and
29
+ none is a cloth that falls. §19.
25
30
 
26
31
  That last component follows a pattern the engine already has twice. `AcousticBody` opts a collider
27
32
  into the acoustic simulation and carries an `AcousticMaterial`; `FluidObstacle` opts a collider into
@@ -63,8 +68,10 @@ The design commitments, in priority order, because they conflict and the orderin
63
68
 
64
69
  ```js
65
70
  // An entity hierarchy — rope, chain, hanging sign, a prop built out of entities.
66
- // Cloth simulates the transform subtree of the entity it is on. That entity is the anchor.
71
+ // Cloth simulates the transform subtree of the entity it is on, that entity included.
72
+ // What holds it is a ClothPin: here the top holds its own particle, 0.
67
73
  rope_top.add(Cloth.from(ClothDynamics.ROPE));
74
+ rope_top.add(ClothPin.from({ cloth: rope_top, particles: [0] }));
68
75
 
69
76
  // A skinned model's garment — cape, skirt, banner, hair.
70
77
  // Cloth simulates the JOINTS of the model instance this entity owns.
@@ -76,6 +83,12 @@ There is no mode enum and no discriminator field. **`Cloth` alone simulates the
76
83
  `Cloth` + `ClothRig` simulates a skinned model's joints** — component presence doing the job an enum
77
84
  would otherwise do badly. The solver is identical either way; only seeding and write-back differ.
78
85
 
86
+ **M7 note: what holds a cloth is not part of it.** Every sentence below that says "the anchor" meant
87
+ three things at once — the frame the cloth is simulated in, the particle it was pinned at, and what
88
+ its tethers measured from — and only the first is the `Cloth` entity's. The fixed set is now whatever
89
+ `ClothPin`s name (§19), any number of them, and the rest of the "anchor" sentences are read through
90
+ §19.
91
+
79
92
  Those are two cases rather than one because **the engine has two hierarchies, and that is a decision
80
93
  rather than an accident**. `shade_node_to_entity_composition` expands a loaded model into entities and
81
94
  gives a `ShadedGeometry` to every node that draws — except a skinned one, which "is not expanded, and
@@ -113,6 +126,13 @@ Two rules keep the walk unambiguous:
113
126
  With a `ClothRig`, the entity is instead the one that owns the skinned model instance, and the
114
127
  subtree walk does not run at all — the particle set comes from the proxy's joint list (§3.2).
115
128
 
129
+ **M7 corrected "the anchor is the entity the component is on".** The entity is the cloth's **frame**:
130
+ what it is simulated in and what §7 P7's inertia is measured against. It is still particle 0 of the
131
+ walk — links run from it — but nothing pins it: a `ClothPin` on it does, `ClothPin.from({ cloth: e,
132
+ particles: [0] })`, and without one the rope falls while the entity, which cloth reads and never
133
+ writes, stays where it is. That is the price of there being no structural pin, paid in one line per
134
+ rope, and §19 has why it is the right one.
135
+
116
136
  `blend` is the escape hatch for cinematics, LOD and "turn it off for this one shot". It is a lerp
117
137
  between the animated pose and the simulated pose applied at write-back, not a solver parameter, so it
118
138
  is free and always safe. **M1 note:** writing it wakes a sleeping cloth, because sleep skips the
@@ -124,7 +144,7 @@ effect at whatever later moment something else happened to wake it.
124
144
  ```js
125
145
  export class ClothRig {
126
146
  proxy = null; // ClothProxy — shared, immutable, built at import
127
- skin = 0; // which of the instance's skins the proxy's joint indices are into
147
+ skin = -1; // the entity whose MeshSkin the proxy's joint indices are into
128
148
  }
129
149
  ```
130
150
 
@@ -132,7 +152,13 @@ A `ClothProxy` **object**, not a path. This is the convention the engine already
132
152
  that points at a built, shared, immutable asset: `Collider#shape` holds an `AbstractShape3D` and is
133
153
  documented as *not* serialised because shapes are shared assets the pipeline wires up;
134
154
  `ParticleEffect` holds a `ParticleLayout` and a `ParticleProgram` the same way. `ClothRig` serialises
135
- the proxy's identity and the skin ordinal, and the asset pipeline resolves the rest.
155
+ the proxy's identity and the skin's entity, and the asset pipeline resolves the rest.
156
+
157
+ **The skin is an entity's, named by entity** (2026-10-11). `skin` was an ordinal into the skins of
158
+ whatever `MeshSystem.instance_of` answered for the cloth's entity, which made a rig reachable only
159
+ through a loaded model. A skin is now a `MeshSkin` component on the mesh it deforms, and the rig
160
+ names that entity; a mesh built in code is rigged the same way as a loaded one. -1 means not named
161
+ yet, and waits like a model still loading.
136
162
 
137
163
  **The proxy addresses joints by index, never by name.** The binding is resolved **once, at import**:
138
164
  the builder turns authored bone names into integer indices into `Skin#joints`, and the runtime
@@ -223,7 +249,10 @@ reach of that position. Three things fall out of that and none of them need a kn
223
249
  - **The profile is automatic.** A hem gets a long leash and a waistband gets a short one, because
224
250
  that is what their geodesic depth says, not because someone painted it.
225
251
  - **The fixed set falls out too.** A pinned particle has `d_geo = 0`, so `r_i = 0`, so the leash *is*
226
- the pin. There is no separate attach constraint — one row covers both (§6).
252
+ the pin. There is no separate attach constraint — one row covers both (§6). *M7: not any more — a
253
+ held particle is kinematic, inverse mass zero, carried by its holder (§19); `d_geo` is its distance
254
+ to the nearest held particle along the fabric, and the animated position `s_i` is the rest pose hung
255
+ from that particle. The factor of two still holds exactly: `|s_i − x_p| = |r_i − r_p| ≤ d_geo`.*
227
256
  - **There is no magic default.** The old formulation had a radius in metres with `0` meaning "derive
228
257
  it from the mesh extent", which is the kind of overloaded sentinel that gets copied into a save file
229
258
  and then means the wrong thing.
@@ -295,6 +324,11 @@ engine/physics/cloth/
295
324
  makeClothWorker.js the spawn expression, isolated because it needs import.meta
296
325
  cloth_worker_protocol.js the command region: a count, then a block per cloth
297
326
  ClothSerializationAdapter.js the component + its ClothDynamics, by value
327
+ ClothPin.js component: this entity holds these particles of that cloth (§19)
328
+ ClothPinSerializationAdapter.js the pin, with its cloth as a raw entity id
329
+ ClothHold.js one pin as the cloth sees it: offsets, the holder's pose
330
+ cloth_holds.js what holding decides: who is kinematic, tethers, the animated pose
331
+ cloth_geodesic.js distance along the fabric from a set of particles
298
332
  ClothColliderSerializationAdapter.js five authored scalars, the same way
299
333
  ClothRigSerializationAdapter.js NOT BUILT — §3.2's asset identity, and the proxy codec
300
334
  collider/
@@ -485,6 +519,13 @@ iterate repeat `iterations` times:
485
519
  H += k_c·(g gᵀ)
486
520
  x_i += H⁻¹·f (3×3 LDLᵀ, capped at the shortest incident row)
487
521
 
522
+ last iteration only, when the held particles lie on one line (axis a through o):
523
+ for each free particle i: r_i = x_i − o, t_i = a × r_i
524
+ ∇E_i, H_i = the vertex update's inertial term + leash, backstop, contact rows
525
+ g = Σ t_i·∇E_i
526
+ H = Σ t_iᵀ·H_i·t_i + max(0, Σ ∇E_i·(a(a·r_i) − r_i))
527
+ turn every free particle about the line by θ = −g/H
528
+
488
529
  dual update, for each HARD constraint c:
489
530
  λ_c ← clamp(k_c·C_c + λ_c, fmin_c, fmax_c)
490
531
  k_c ← min(k_c + β·|C_c|, k_max·s_c)
@@ -563,6 +604,29 @@ non-positive-definite Hessian inside a second. A mechanism that costs, does not
563
604
  the top of its own range is worse than its absence. `MEASUREMENTS.md` §21 keeps the grid so a future
564
605
  attempt starts from the numbers.
565
606
 
607
+ **M7 added one block to the descent: the turn about a hold line** (`cloth_hold_line.js`). Every vertex
608
+ update is a 3×3 block, and a cloth whose held particles lie on one line has a motion no such block can
609
+ make — turning about the line as a rigid body. A vertex update moves one particle, so each adds
610
+ `x_i × m·Δx_i` of angular momentum about the line, and the step stopped at a fabric's iteration count
611
+ leaves a gradient along the turn. About a vertical line nothing restores it, and the warm start's
612
+ `α·γ = 0.25` means a cloth at rest re-solves three quarters of its weight every substep and is never a
613
+ fixed point: a flag on a pole turned for as long as it was run (§18).
614
+
615
+ So the turn gets its own block, in the listing above: one Newton step of `E` along it, in the last
616
+ iteration, after the sweep and before the dual update. Internal rows are invariant under the turn —
617
+ their ends turn together, or one of them is on the axis — so only the inertial term and the unary rows
618
+ enter. The last term of `H` is the path's own curvature, `d²x/dθ² = −r⊥`: near zero about a vertical
619
+ axis, the pendulum's gravity stiffness about a horizontal one, and added only where positive so the step
620
+ is never longer than the one without it. It is a descent step on the same energy, so §5.3 stands, and it
621
+ changes no row, multiplier or constant. It runs when the held particles lie on one line at that substep,
622
+ at two distinct points or more, to `2⁻¹⁶` of their largest coordinate. That is a runtime fact about the
623
+ holds, and the predict, which carries every held particle, lists them on its way.
624
+
625
+ What it does not cover: a single held point has three free turns and a cloth nothing holds has six, and
626
+ neither is handled. On a line gravity does restore it has slowed some sleeps and kept one cloth awake
627
+ (§18). Carrying the multiplier instead — AVBD's Eq. 18, or the reference code's post-stabilisation —
628
+ stops the turn too, and fails six to ten of the cloth gates. `MEASUREMENTS.md` §66.
629
+
566
630
  ### 5.3 Why the update never explodes
567
631
 
568
632
  `H = (m/h²)·I + Σ_tension (fc/L)·(I − g gᵀ) + Σ_active k_c·(g gᵀ)`. The mass term is positive
@@ -696,6 +760,15 @@ distinction between "pinned" and "loosely following" is a number rather than a b
696
760
  `‖x − s‖` is undefined at `x = s`; the row is skipped below an epsilon, which is the standard guard and
697
761
  is also exactly when it has nothing to do.)
698
762
 
763
+ **M7: and there still is none, but a pin is not a row either.** The anchor was pinned by inverse mass
764
+ zero all along, and that is what a hold is: a kinematic particle carried to where its holder puts it,
765
+ an equal share of the way at each substep (§19). Both leash rows now measure from a **particle** —
766
+ `ClothState#leash_source` and an offset, re-centred every substep after the held particles move —
767
+ because a centre written once a step sits a step behind a held particle that is moving, and a hard
768
+ row measured from a stale point fights the hold. The tether's centre is the nearest held particle,
769
+ not "the anchor"; a particle nothing holds has both rows at radius `Infinity`, skipped before any
770
+ arithmetic.
771
+
699
772
  **Slack and tether are different questions, and a cape needs both.** Slack bounds distance to the
700
773
  particle's *animated position*; the tether bounds distance to the *anchor*. Slack alone implies a
701
774
  tether bound of `(1 + slack)·d_geo` — enough to stop a catastrophe, not enough to stop visible rubber —
@@ -1031,6 +1104,15 @@ cloth's own switches — a mode enum for two values is the discriminator field
1031
1104
  frame anchored to the cloth's own entity the particles are already anchor-relative, so "apply the
1032
1105
  delta" is doing nothing. The implementation is a `return`.
1033
1106
 
1107
+ **M7: a holder can jump too, and it is measured in the frame.** A rope tied to a ship that is moved
1108
+ across the map has a frame that did not move and a holder that did. The test is now the frame's jump
1109
+ in the world *or* any holder's jump in the frame, against the same threshold. `Reset` puts every
1110
+ particle on the animated pose hung from where the holders now are, held particles on their targets so
1111
+ the jump is taken between steps rather than dragged through one; `Keep` does nothing for the frame, as
1112
+ before, and for a holder applies that holder's own jump to what hangs from it. Measured: a hand holding
1113
+ a rope's top, moved a kilometre in one step, resets once and peaks under 5% of the velocity clamp
1114
+ (`cloth_pin.spec.js`).
1115
+
1034
1116
  **P7 — Fast locomotion: whipping, lag, centrifugal spray.**
1035
1117
  *Mechanism:* the simulation runs in a **local frame anchored to the cloth's own entity**, with
1036
1118
  `ClothDynamics#inertia` controlling how much of the anchor's world motion the cloth is allowed to
@@ -1047,6 +1129,15 @@ against the cloth's own geometry so a 3 cm pendant and a 30 m mooring line get t
1047
1129
  its range, which is what makes it a dial rather than a switch with a meaningless middle.
1048
1130
  `MEASUREMENTS.md` §13.
1049
1131
 
1132
+ **M7: the frame is the only motion this softens.** A holder moving *relative to the frame* moves its
1133
+ particles in full — that is what holding means — so P7's limits protect a cloth whose holders ride its
1134
+ frame, which is every garment and every rope hung from its own top. A cloth held by something that
1135
+ moves independently — a banner between two characters — feels that motion unsoftened, and the frame
1136
+ it should ride is the author's choice, as Chaos Cloth's reference bone is. What bounds such a cloth is
1137
+ P1's clamp and P2's authority: measured, a hand dragging a rope at four times what one step can
1138
+ correct stays under the clamp every step and is back inside 1% of its tether within ten seconds of
1139
+ stopping (`cloth_pin.spec.js`).
1140
+
1050
1141
  **P8 — Degenerate authoring.**
1051
1142
  *Mechanism:* build-time validation, not runtime tolerance. The proxy builder welds duplicates, drops
1052
1143
  zero-area triangles, and refuses non-manifold and inconsistently-wound configurations. The existing
@@ -1177,10 +1268,13 @@ it once at seed, in the bind pose, and the ceiling is two fifths of it. `MEASURE
1177
1268
  "O(n) with a small constant" is right about the shape and optimistic about the constant: the pair
1178
1269
  search is linear in particles with no term in the pair count, and it is **12% of a frame** at the
1179
1270
  §17 workload, and most of everything self-collision costs. The rows themselves are nearly free.
1180
- `MEASUREMENTS.md` §34. "The great majority of visible interpenetration" is 82% of it, and the
1181
- stiffness that does it is `8·(m_eff/h²)`, chosen on the crossing count rather than on M0's
1182
- dissipative band — a one-sided row that vanishes when satisfied shows no energy growth at 64×
1183
- that. `MEASUREMENTS.md` §32.
1271
+ `MEASUREMENTS.md` §34. "The great majority of visible interpenetration" is 82% of it at the
1272
+ stiffness M4 shipped, `8·(m_eff/h²)`, which §32 chose on a folding sheet's crossing count.
1273
+ **Post-M7 corrected the stiffness to `2·(m_eff/h²)`.** §32's sheet showed no energy growth at 64×
1274
+ because its contacts come and go. A fold resting on a fold is a pair that carries weight, a spring
1275
+ that is on every step, and at 8 it never comes to rest (§18). 2 is the stiffest ratio that lets it,
1276
+ and it removes 63% to 71% of the folding sheet's crossings rather than 73% to 79%.
1277
+ `MEASUREMENTS.md` §32, §65.
1184
1278
 
1185
1279
  *This tier cannot see cloth passing between particles.* A sheet thinner than its particle spacing can
1186
1280
  still slip through itself. Stated, not hidden.
@@ -1517,6 +1611,13 @@ For a **rigged** garment, only steps 5–8 run, over the joint graph rather than
1517
1611
  saying "this one is pinned". Several chains from one bone are one garment and are §3.1's coupled
1518
1612
  solve; chains from *different* bones are refused, because there is then no single frame to
1519
1613
  simulate in.
1614
+
1615
+ **M7 lifted the refusal, because the frame and the fixed set came apart.** The bones a garment
1616
+ hangs from are particles of the proxy that cloth reads and never writes (`ClothProxy#output`), with
1617
+ the links to their roots the first links of the fabric; the frame is the nearest skin joint above
1618
+ all of them (`ClothProxy#frame`); and the builder hands back one `ClothProxyGroup` per bone — the
1619
+ pin to add. A cape across both shoulders is one proxy, two pins, riding the chest
1620
+ (`cloth_rig.spec.js`).
1520
1621
  6. Bake `d_geo` — geodesic distance from every particle to the fixed set. This one array drives the
1521
1622
  tether row, the slack profile, and the pinning, so the three cannot disagree.
1522
1623
  7. Colour the particle graph (`colorizeGraphGreedy`, checked by `validateGraphColoring`), and permute
@@ -2361,6 +2462,45 @@ question it answers has become "does all the cloth in the scene fit in one worke
2361
2462
  `MEASUREMENTS.md` §41. Re-measure the absolute column on a quiet machine, and check the process count
2362
2463
  first.
2363
2464
 
2465
+ **M7 — attachment points. DONE, 2026-10-10.** `ClothPin`, `ClothHold`, `cloth_holds.js`,
2466
+ `cloth_geodesic.js`, `ClothPinSerializationAdapter`; the rows built from a particle graph rather than a
2467
+ parent array; held particles carried through the step (`ClothState#kinematic_target`) and leash rows
2468
+ measured from a particle (`leash_source`); the rig proxy's bones-to-hang-from and frame joint. There is
2469
+ no anchor: a cloth is held by whatever pins name it, from none up. §19 is the design.
2470
+ *Proofs, all green:* `cloth_held.spec.js` (five of six red against the previous solver),
2471
+ `cloth_pin.spec.js` (free fall, a rope held at its top, a rope bridge, letting go and catching mid-swing,
2472
+ a holder teleporting, a holder outrunning the cloth, holds pulled beyond the fabric, a pin before its
2473
+ cloth, lifecycle and refusals), `cloth_geodesic.spec.js`, the adapter's, a two-shoulder cape in
2474
+ `cloth_rig.spec.js`, and a worker parity run in which a second holder drags, lets go and takes hold
2475
+ again — bit-identical every step for 240. Cloth suite 327, slow 7, physics 1,861. *Cost:* +1.4% and
2476
+ +2.8% median a step on a 129- and a 1,025-particle rope rig, paired against the previous build in one
2477
+ process. *Equivalence:* a rope pinned at its own top under M7 and the same rope under the anchor differ
2478
+ by 1.9e-7 m after one step, and grow apart exactly as fast as two copies of the old build nudged 1e-7 m
2479
+ apart — chaos, not a change. `MEASUREMENTS.md` §62.
2480
+
2481
+ **M7, sheets. DONE, 2026-10-10.** `cloth_proxy_from_mesh`: a proxy from a skin with one joint per vertex
2482
+ and the triangles over them — a stretch row per edge, a hinge per interior edge, the authoring mistakes
2483
+ refused by name (§7 P8). `ClothProxy` carries its graph for both builders; hinge rows are built wherever
2484
+ a proxy has hinges, each stiffened as a ratio of its own inertia; a joint with triangles round it is
2485
+ turned by its surface rather than swung along a chain. §19.5 is the design.
2486
+ *Proofs, all green:* `cloth_proxy_from_mesh.spec.js`, and `cloth_sheet.spec.js` through `ClothSystem` —
2487
+ a flag held at its hoist by a pole, every library fabric swinging down from a held edge and coming to
2488
+ rest, a free sheet draped on a sphere with every joint turned onto its surface, and a cloth in two
2489
+ pieces of which only one is held. *Found:* a flag on a pole in still air turns about the pole, and the
2490
+ solver did it before holds existed (§18). `MEASUREMENTS.md` §63.
2491
+ *The stage's remaining scenes, later:* a sheet carried round by friction on a turning sphere, and a
2492
+ circle skirt that flares on a turning body and settles, both in `cloth_sheet.slow.spec.js`. The third, a
2493
+ pile of ribbons, found that a fold resting on a fold never comes to rest at the shipped self-collision
2494
+ stiffness (§18), and is kept as the proof a change to it needs. `MEASUREMENTS.md` §64.
2495
+
2496
+ **Post-M7 — a fold resting on a fold comes to rest. DONE, 2026-10-11.** `CLOTH_SELF_RATIO` goes from
2497
+ 8 to 2 (§9, §18). *Proofs, red on 8 and green on 2:* in `cloth_sheet.slow.spec.js`, a pile of three
2498
+ silk ribbons fanned 60°, which sleeps with no crossing at any step and its order kept, and the circle
2499
+ skirt, asleep after its twirl; in `cloth_sheet.spec.js`, the sheet draped on a sphere, asleep. *Cost:*
2500
+ §32's folding sheet goes from 2.09 to 2.98 crossings a sample over 48 gusts, and the library bench
2501
+ does not move. The turning-sphere spec's 2° on where the sheet stops after the spin was one
2502
+ realisation and is now 10°. `MEASUREMENTS.md` §65.
2503
+
2364
2504
  ---
2365
2505
 
2366
2506
  ## 18. Risks and open questions
@@ -2506,6 +2646,11 @@ inextensibility, but the fixed set still has to come from the mesh boundary or f
2506
2646
  neither is built. It belongs with the unrigged path, which is where a mesh first becomes a particle
2507
2647
  set.
2508
2648
 
2649
+ **M7 closed half of this.** The fixed set is authored now, by `ClothPin` (§19), for every case: a
2650
+ flag's hoist is the vertices a pin on the pole names. **M7's sheets closed the mesh:**
2651
+ `cloth_proxy_from_mesh` builds the proxy from triangles (§19.5). What is left is a way to draw one
2652
+ (§19.6).
2653
+
2509
2654
  **Open — LOD.** Distance-based particle-count reduction would need either multiple baked proxies per
2510
2655
  garment or a runtime hierarchy. Culling (§12.1) covers the off-screen case; the far-but-visible case is
2511
2656
  unaddressed.
@@ -2623,3 +2768,188 @@ whose rig was taken away kept driving the joints. Both edges are now watched by
2623
2768
  `Cloth` + `ClothRig` inside `ClothWorld`, so the discriminator is read whenever it changes rather than
2624
2769
  once. The **subtree** case above is untouched and stays open: an entity appearing under a live rope is
2625
2770
  still a `reseed` the caller has to ask for.
2771
+
2772
+ **Open — M7: a seam between two holders that move apart.** The animated pose hangs each particle from
2773
+ its *nearest* held particle, so two holders moving relative to each other put a step in it where their
2774
+ regions meet. It binds only where the slack row does — past `2·slack·d_geo`, which at a seam is the
2775
+ widest radius the cloth has — and nothing measured has reached it. A geodesic-weighted blend of the
2776
+ holders' motions is the shape of a fix if a garment ever does.
2777
+
2778
+ **M7: a sheet held along a vertical line turned about it. — FIXED, by one more block of the descent.**
2779
+ A flag on a pole in still air did not hang still: it turned about the pole as a rigid body, ten degrees
2780
+ a second at rope's settings, for all 3,000 steps measured. A turn about a vertical hold line is the one
2781
+ motion nothing restores — gravity is parallel to it, and every row ends on the axis or is an equal and
2782
+ opposite pair — and AVBD stopped at a fabric's iteration count left a residual whose torque about that
2783
+ axis was not zero, so the step's fixed point was a steady turn rather than rest. `damping` balanced the
2784
+ torque rather than removing it: ten times the rate, a tenth of the speed. It was there with hard stretch
2785
+ rows and nothing else, and in the solver from before holds existed, digit for digit. A fabric with
2786
+ `slack < 1` came to rest only because its slack row caught the turn — a silk flag 123° round its pole,
2787
+ cotton 74° — and one at `slack = 1`, rope or chain, never did. `MEASUREMENTS.md` §63.
2788
+
2789
+ *The cause, measured.* A vertex update moves one particle, so each adds `x_i × m·Δx_i` of angular
2790
+ momentum about the line, and the step's change about the pole is exactly `h·Σ x × R`, `R` the energy
2791
+ gradient left when the iterations stop; the identity closes to four figures. The warm start keeps
2792
+ `α·γ = 0.25` of each hard multiplier, so a cloth at rest re-solves three quarters of its weight every
2793
+ substep and leaves that gradient every substep. Sweep order is not it: forward, backward and
2794
+ alternating each step all read −0.46 at 8 iterations.
2795
+
2796
+ *The fix* is the turn as a block of its own (§5.2, `cloth_hold_line.js`): one Newton step along it in
2797
+ the last iteration, whenever the held particles lie on one line. The bare flag reads 0 to four figures
2798
+ at every budget from 1 to 16 iterations, and every library fabric's flag sleeps: rope at step 416,
2799
+ chain at 250 and cotton at 336, where they never did. It costs 3–9% of a sheet's step, and nothing on a
2800
+ cloth held at one point, where it never runs. Carrying the multiplier instead — AVBD's Eq. 18, or the
2801
+ reference code's post-stabilisation — stops the turn too, fails six to ten of the 345 cloth gates, and
2802
+ diverges where its rows meet rows still on the old warm start. `MEASUREMENTS.md` §66.
2803
+
2804
+ *Still open, measured and not fixed:*
2805
+ - A single held point has three free turns and a cloth nothing holds has six; the block covers a line
2806
+ only. A sheet hung from one corner turns at no more than 0.004, and silk's is awake at step 3,000.
2807
+ - Where gravity does restore the turn, the block slows some sleeps: leather's lying sheet from 72 steps
2808
+ to 165, and rope and chain on a pole tilted 30° from 474 to 574 and 264 to 312. Why is not measured.
2809
+ - And in one case it keeps a cloth awake. Cotton held by its two top corners, after the hands see-saw
2810
+ for 900 steps and stop, never sleeps under the block, creeping 1.7 mm per 30 steps at step 8,000;
2811
+ before it, it slept at 1,378. Switched off at the stop it sleeps at 1,409, so it is the block's
2812
+ ongoing action: it takes out the leftover turn about the corner line rigidly, about 7e-7 rad a
2813
+ substep, and the sweeps put it back near a corner. Rope never sleeps after that see-saw in either
2814
+ build. Running the block only on hold lines near the vertical would remove this and the item above,
2815
+ at the price of a tolerance constant and a test against gravity; it was not done.
2816
+ - Far from the frame's origin the correction is smaller than the coordinates' rounding. A bare flag
2817
+ 100 m out turns at −0.025 at step 500 and −0.136 at 3,000, against −0.18 to −0.23 before. `ClothSystem`
2818
+ steps a cloth in its own frame, where its coordinates are its own size.
2819
+ - After a one-kilometre teleport neither build sleeps within 2,400 steps, rope, silk, hair or chain. It
2820
+ was so before the block, and the cause is not measured.
2821
+
2822
+ **A fold resting on a fold never came to rest. — FIXED, `CLOTH_SELF_RATIO` 8 → 2, and the cost is
2823
+ measured.** §32 cleared `CLOTH_SELF_RATIO = 8` of adding energy on a folding sheet, whose
2824
+ contacts come and go. A self-collision pair that carries weight stays in contact, so a resting fold is
2825
+ a standing spring, which is the case M0's dissipative band was measured on. At 8 the step gains energy
2826
+ through it:
2827
+ - Two silk ribbons stacked parallel on a floor peak at 1.5 m/s after a 0.35 m/s drop, and never sleep.
2828
+ - Two crossed at 90°, dropped from gaps of 4 to 12 cm, sleep only from the 6 and 8 cm drops. From the
2829
+ others they creep 3 to 56 mm every five seconds.
2830
+ - Piles of three to six reach up to 5.7 m/s, 1.3 to 3.8 times what their drop gives them, and are
2831
+ left with 11 to 139 crossings. Every three-ribbon pile tried crosses.
2832
+ - §63's draped sheet stays awake on its sphere, with 14 to 18 pairs found every step.
2833
+ - A circle skirt stays awake after a twirl, with eight.
2834
+
2835
+ At ratio 1 all of them sleep. Averaging a particle's Jacobi share over its pairs is not the fix.
2836
+ *Fixed at 2*, the stiffest ratio at which cloth resting on itself reliably comes to rest. Of 225 ribbon
2837
+ piles in silk, cotton and hair, the 135 that land without passing through themselves all sleep but
2838
+ one, and so do the draped sheet and the skirt. At 4, five of 38 clean silk piles never do, and above
2839
+ 2.25 the draped sheet's sleep is erratic. *What it costs* is §32's folding sheet: 2.09 → 2.98 crossings
2840
+ a sample over 48 gusts, where ratio 1 would cost 3.74. The library bench does not move. The proof is a
2841
+ three-ribbon pile fanned 60°, asserting no crossing at any step and the order kept. "No crossings at
2842
+ rest" is not enough, because a ribbon can land right through another and lie under it. *Still open,
2843
+ and not this:* piles land through themselves, 90 of 225 at 2, every one of them while landing. That is
2844
+ §35's missing travel term in the pair search. `MEASUREMENTS.md` §64, §65.
2845
+
2846
+ ---
2847
+
2848
+ ## 19. Attachment points
2849
+
2850
+ Written for M7, after an adversarial review of the first draft by three reviewers against the code;
2851
+ the review's findings are folded in below and listed in `MEASUREMENTS.md` §62.
2852
+
2853
+ ### 19.1 The anchor was four jobs
2854
+
2855
+ Node 0 was the frame the cloth was simulated in, the one pinned particle, the point every tether
2856
+ measured from, and the root the rows were derived from. Only the first is a property of the entity the
2857
+ `Cloth` is on, and splitting the other three off is the whole design:
2858
+
2859
+ | Job | Now |
2860
+ |---|---|
2861
+ | Frame: the solve, gravity, colliders, wind, §7 P7 | The `Cloth` entity for a subtree; `ClothProxy#frame` for a rig |
2862
+ | The fixed set | Held particles: any number, each held by an entity carrying a `ClothPin` |
2863
+ | Tether centre and `d_geo` | The nearest held particle along the fabric |
2864
+ | Root of the rows | A particle graph — `ClothInstance#edge`, `#skip`, `#hinge` |
2865
+
2866
+ A cloth with no pins is the case where nothing is held, and it needs no code: every tether and slack
2867
+ row has radius `Infinity`.
2868
+
2869
+ ### 19.2 `ClothPin`
2870
+
2871
+ On the holder, naming the cloth's entity and its particles by index — a proxy's particle order, or for
2872
+ a subtree the breadth-first walk, where 0 is the `Cloth` entity. Every field required; references fixed
2873
+ while attached; saved with its entity. A hold begins **where the particle is**: on a cloth's first step
2874
+ that is the rest pose, mid-run it is a grab. Removing the pin lets go, and the particle leaves at the
2875
+ speed its holder carried it. Destroying the cloth's entity removes the pins naming it (an entity id is
2876
+ reused). A particle two pins name goes to the lower holder; a holder the cloth itself moves is refused,
2877
+ once, by name.
2878
+
2879
+ The world keeps one `ClothHold` per pin **outside** the seeded instance: the offsets a hold takes are
2880
+ the hold's, so a re-seed does not move what is held. The observer only notices; everything a hold
2881
+ writes into a `ClothState` is written in `ClothWorld#advance`, the one window in which the main thread
2882
+ owns that state under both systems.
2883
+
2884
+ A holder's pose is read off its `Transform64` when the CPU owns it and evaluated exactly, under the
2885
+ clips of every model on its chain, when the GPU does; a holder whose chain is not complete yet holds
2886
+ where it last held.
2887
+
2888
+ ### 19.3 What a hold does in the step
2889
+
2890
+ A held particle is kinematic: inverse mass zero, carried towards `kinematic_target` by an equal share
2891
+ of what remains at every substep, so it lands exactly at the last one and a target equal to the
2892
+ position moves nothing by a single bit. Chaos Cloth interpolates its kinematic particles the same way.
2893
+ Held particles are not carried by the frame's inertia; they belong to their holders.
2894
+
2895
+ **One tether per particle, to the nearest held particle.** Chaos tethers to the nearest of up to four
2896
+ kinematic islands; that is four hard rows per particle, three of them idle on every cloth with one
2897
+ hold, and two hard tethers to holders pulled apart are bounds no position satisfies. The fabric between
2898
+ two holders already carries everything a second tether would. The search is one Dijkstra over the
2899
+ fabric edges with every held particle a source, in double. A tether starts no tighter than where its
2900
+ particle already is and only ever comes in, so a hold taken mid-run does not snap the cloth onto it.
2901
+
2902
+ The **animated pose** is the rest pose hung from the nearest held particle and turned with its holder,
2903
+ `s_i = x_p + R_p·(r_i − r_p)`; it keeps §3.4's factor of two exact. When no holder has moved in the
2904
+ frame since the last step — every holder that rides its frame — nothing per step is recomputed.
2905
+
2906
+ `reach` is the largest `d_geo`, with a particle no hold reaches counted at its rest distance from the
2907
+ frame's origin.
2908
+
2909
+ ### 19.4 The rig path
2910
+
2911
+ A rig proxy's particles are the garment's joints and the bones it hangs from; cloth writes the first
2912
+ and reads the second, each step, exactly, to express the garment's roots against. The builder finds
2913
+ the bones, the frame and the pins; the spawn code adds the pins. `Cloth` and `ClothRig` stay on the
2914
+ model's root, which is saved, rather than on a bone, which is not.
2915
+
2916
+ ### 19.5 Sheets
2917
+
2918
+ A sheet is a skin with **one joint per vertex**, every one hanging straight off one root joint, and
2919
+ `cloth_proxy_from_mesh` builds its proxy from the triangles over them: a stretch row per edge, a hinge
2920
+ per interior edge — the shared edge, then each triangle's opposite wing, which is `cloth_bend_row`'s
2921
+ stencil — the root joint as the frame, and nothing pinned: a pin on a pole names the hoist. A triangle
2922
+ with no area, an edge three triangles share, joints under two roots and a name the skin lacks are
2923
+ refused by name. `ClothProxy` carries its graph (`edge`, `skip`, `hinge`, `triangle`) for both
2924
+ builders.
2925
+
2926
+ A hinge's stiffness is the skip row's rule over its own stencil, `bend ratio × (m / Σ w²) / h²`: a
2927
+ hinge across a sliver, whose cotangent weights are large, is softer per unit of `C` for exactly the
2928
+ reason its `C` is larger, and stays inside M0's dissipative band where a stiffness in newtons per metre
2929
+ would leave it.
2930
+
2931
+ A joint with triangles round it has no chain to swing along, and what its orientation is for is the
2932
+ normal it turns its vertex's normal by. It takes the swing carrying the area-weighted normal of its
2933
+ triangles in the animated pose onto the same in the simulated one, then the twist about that normal
2934
+ carrying one fixed neighbour's direction onto where it is now. A joint hanging straight off the frame is
2935
+ written in the frame.
2936
+
2937
+ ### 19.6 Not done
2938
+
2939
+ - **Drawing a sheet: the route exists, nothing takes it yet.** A skin is a `MeshSkin` on the mesh it
2940
+ deforms and a rig names that entity (`38b2fe208`, `0e20799be`), so a sheet built in code needs no
2941
+ loaded asset: a mesh entity with `ShadedGeometry` and a `MeshSkin` naming the vertex joints, named
2942
+ by `ClothRig.from(proxy, mesh)`. Not built: a helper that makes that geometry, its skin and the
2943
+ joints from the triangles, and anything that shows a sheet drawn.
2944
+ - **The cost of a joint per vertex.** About 620 ns a joint a step, on the main thread, where
2945
+ `WorkerClothSystem` leaves it: 0.25 ms for a 400-particle sheet. `MEASUREMENTS.md` §63.
2946
+ - **Curved rest shapes.** The hinge stencil reads a curved rest as already bent (§18); a flag, a banner
2947
+ and a circle skirt cut flat are what it serves.
2948
+ - **Welding.** The builder takes a mesh that is already one joint per welded vertex.
2949
+ - **A sheet held at one point, or by two holders that see-saw.** The hold-line block that stopped a
2950
+ flag turning on its pole covers a line only, and after a see-saw it keeps a corner-held sheet awake
2951
+ (§18).
2952
+ - **A seam between holders that move apart** (§18).
2953
+ - **A pile landing through itself.** A fold resting on a fold comes to rest since the self-collision row
2954
+ went to 2 (§18). What is left is a pile passing through itself while it lands, which is §35's
2955
+ missing travel term in the pair search.