@woosh/meep-engine 3.43.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 (287) hide show
  1. package/editor/prototypeEditorShell.d.ts.map +1 -1
  2. package/editor/prototypeEditorShell.js +4 -2
  3. package/package.json +1 -1
  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/renderer/animation/GPUAnimationManager.d.ts +45 -14
  177. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  178. package/src/shade/renderer/animation/GPUAnimationManager.js +316 -64
  179. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts +5 -0
  180. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  181. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +11 -1
  182. package/src/shade/renderer/geometry/BoxGeometry.d.ts +1 -11
  183. package/src/shade/renderer/geometry/BoxGeometry.d.ts.map +1 -1
  184. package/src/shade/renderer/geometry/BoxGeometry.js +6 -13
  185. package/src/shade/renderer/geometry/CapsuleGeometry.d.ts +19 -0
  186. package/src/shade/renderer/geometry/CapsuleGeometry.d.ts.map +1 -0
  187. package/src/shade/renderer/geometry/CapsuleGeometry.js +24 -0
  188. package/src/shade/renderer/geometry/ConeGeometry.d.ts +20 -0
  189. package/src/shade/renderer/geometry/ConeGeometry.d.ts.map +1 -0
  190. package/src/shade/renderer/geometry/ConeGeometry.js +33 -0
  191. package/src/shade/renderer/geometry/CylinderGeometry.d.ts +21 -0
  192. package/src/shade/renderer/geometry/CylinderGeometry.d.ts.map +1 -0
  193. package/src/shade/renderer/geometry/CylinderGeometry.js +35 -0
  194. package/src/shade/renderer/geometry/PlaneGeometry.d.ts +17 -0
  195. package/src/shade/renderer/geometry/PlaneGeometry.d.ts.map +1 -0
  196. package/src/shade/renderer/geometry/PlaneGeometry.js +22 -0
  197. package/src/shade/renderer/geometry/TorusGeometry.d.ts +18 -0
  198. package/src/shade/renderer/geometry/TorusGeometry.d.ts.map +1 -0
  199. package/src/shade/renderer/geometry/TorusGeometry.js +23 -0
  200. package/src/shade/renderer/geometry/UVSphereGeometry.d.ts +21 -0
  201. package/src/shade/renderer/geometry/UVSphereGeometry.d.ts.map +1 -0
  202. package/src/shade/renderer/geometry/UVSphereGeometry.js +34 -0
  203. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts +19 -0
  204. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts.map +1 -0
  205. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.js +205 -0
  206. package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts +21 -0
  207. package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts.map +1 -0
  208. package/src/shade/renderer/geometry/primitives/make_cone_geometry.js +36 -0
  209. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts +1 -1
  210. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts.map +1 -1
  211. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.js +44 -9
  212. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts +20 -0
  213. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts.map +1 -0
  214. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.js +190 -0
  215. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  216. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +7 -2
  217. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts +26 -8
  218. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts.map +1 -1
  219. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js +56 -39
  220. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts +7 -0
  221. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts.map +1 -1
  222. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.js +46 -4
  223. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.d.ts.map +1 -1
  224. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.js +4 -2
  225. package/src/shade/renderer/gpu_primitive/sort/defs.d.ts +2 -2
  226. package/src/shade/renderer/gpu_primitive/sort/defs.js +79 -79
  227. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts +1 -1
  228. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts.map +1 -1
  229. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.js +7 -3
  230. package/src/shade/renderer/particles/GPUParticleSystem.js +1 -1
  231. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts +4 -3
  232. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts.map +1 -1
  233. package/src/shade/renderer/particles/coherence/graph_particle_bucket.js +200 -194
  234. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  235. package/src/shade/renderer/particles/graph_particles.js +6 -2
  236. package/src/shade/renderer/particles/warmup/graph_particle_warmup.d.ts.map +1 -1
  237. package/src/shade/renderer/particles/warmup/graph_particle_warmup.js +334 -329
  238. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  239. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +7 -2
  240. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.d.ts.map +1 -1
  241. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.js +16 -4
  242. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +2444 -2345
  243. package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.d.ts.map +1 -1
  244. package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.js +312 -310
  245. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts +3 -3
  246. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts.map +1 -1
  247. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.js +383 -375
  248. package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.d.ts.map +1 -1
  249. package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.js +349 -346
  250. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts +58 -0
  251. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts.map +1 -0
  252. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.js +536 -0
  253. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts +21 -7
  254. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts.map +1 -1
  255. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.js +291 -327
  256. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts +25 -0
  257. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts.map +1 -0
  258. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.js +99 -0
  259. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts +5 -3
  260. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts.map +1 -1
  261. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.js +47 -71
  262. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts +10 -0
  263. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts.map +1 -0
  264. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.js +50 -0
  265. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts +4 -5
  266. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts.map +1 -1
  267. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.js +7 -8
  268. package/src/shade/renderer/water/chunk_water_transport.d.ts.map +1 -1
  269. package/src/shade/renderer/water/chunk_water_transport.js +7 -5
  270. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +1 -1
  271. package/src/shade/renderer/water/medium/GPUWaterBodies.js +8 -2
  272. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts +3 -2
  273. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts.map +1 -1
  274. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.js +3 -2
  275. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  276. package/src/shade/renderer/water/shader_water.js +3 -1
  277. package/src/shade/renderer/water/surface/GPUWaterSurface.d.ts.map +1 -1
  278. package/src/shade/renderer/water/surface/GPUWaterSurface.js +3 -1
  279. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts.map +1 -1
  280. package/src/shade/renderer/water/surface/graph_water_tessellation.js +11 -4
  281. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -1
  282. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +37 -20
  283. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  284. package/src/shade/wgsl/validate_wgsl_source.js +74 -3
  285. package/src/engine/graphics3/register_instance_animation.d.ts +0 -114
  286. package/src/engine/graphics3/register_instance_animation.d.ts.map +0 -1
  287. package/src/engine/graphics3/register_instance_animation.js +0 -201
@@ -1,284 +1,357 @@
1
- import {
2
- TRANSFORM64_ROTATION_OFFSET,
3
- TRANSFORM64_TRANSLATION_OFFSET
4
- } from "../../../ecs/transform/Transform64.js";
5
- import { ClothProxy } from "./ClothProxy.js";
6
-
7
- /**
8
- * @typedef {import("../../../graphics3/prefab/Prefab.js").Prefab} Prefab
9
- * @typedef {import("../../../../shade/renderer/animation/Skin.js").Skin} Skin
10
- */
11
-
12
- /**
13
- * # Building a proxy for a garment that is already rigged
14
- *
15
- * §11.3 lists ten steps and says that for a rigged garment "only steps 5–8 run,
16
- * over the joint graph rather than a mesh". This is those steps: derive the
17
- * fixed set, bake the bind pose, resolve names to indices, and validate. Steps
18
- * 1–4 are mesh work a rigged garment does not need — the artist's joints *are*
19
- * the particle set and the artist's skin *is* the binding — and steps 9 and 10's
20
- * mesh half belong to the unrigged path.
21
- *
22
- * The colouring step (7) is absent for a reason rather than an omission: the
23
- * cloth's own row builder colours the particle graph inside
24
- * `ClothState.from`, and it does that for the entity path too. Baking a
25
- * permutation into the proxy would be a second answer to a question that
26
- * already has one, and it would have to agree with `cloth_color_particles`
27
- * exactly or the rows would name the wrong particles.
28
- *
29
- * ## The fixed set falls out of the topology
30
- *
31
- * A joint whose parent is outside the named set is a joint the garment hangs
32
- * from, and **every one of them must hang from the same bone** — that bone is
33
- * the anchor. §11.3 step 5 derives the fixed set from *skin weights* instead,
34
- * which is the right rule for the unrigged path, where the particles are mesh
35
- * vertices and there is no joint tree to read. For a rigged garment the tree is
36
- * the answer and the weights are not needed.
37
- *
38
- * Several chains from one bone are one garment and are the point: §3.1's "put
39
- * `Cloth` on a node with several chains under it and you get all of them in one
40
- * coupled solve" is exactly a cape's four strips off one shoulder. Chains from
41
- * *different* bones are refused, because there is then no single frame to
42
- * simulate in and no single fixed set — that is two garments, and nothing stops
43
- * a caller building two proxies.
44
- *
45
- * ## The joint graph is the prefab's
46
- *
47
- * A model's hierarchy is its compiled prefab: parent indices, names and rest
48
- * poses per node, fixed for every placement. The skin handed in is one of the
49
- * prefab's — joints as node indices — and what comes back holds indices into
50
- * that skin's joints, which is what a placement's own skin (joints as entities)
51
- * is indexed by too. Built once per model, like the prefab.
52
- *
53
- * @author Alex Goldring
54
- * @copyright Company Named Limited (c) 2026
55
- */
56
-
57
- /**
58
- * @typedef {object} ClothProxyBuildResult
59
- * @property {ClothProxy|null} proxy `null` when the build refused
60
- * @property {string} error empty when it did not
61
- */
62
-
63
- /**
64
- * Build a proxy from the joints of a skin, named.
65
- *
66
- * The names are the only place a name appears anywhere in the system (§11.3
67
- * step 8) and they do not survive: what comes back holds indices into
68
- * `skin.joints`.
69
- *
70
- * @param {Prefab} prefab the compiled model whose hierarchy the joints are nodes of
71
- * @param {Skin} skin one of the prefab's skins — joints as node indices. The joint *order* is
72
- * what is read, and instantiation preserves it
73
- * @param {string[]} joint_names the garment's own joints, in any order
74
- * @param {object} [options]
75
- * @param {string} [options.name]
76
- * @returns {ClothProxyBuildResult}
77
- */
78
- export function cloth_proxy_from_joints(prefab, skin, joint_names, { name = "" } = {}) {
79
- if (prefab === undefined || prefab === null || prefab.isPrefab !== true) {
80
- return refuse(`${name}: no prefab`);
81
- }
82
-
83
- if (skin === undefined || skin === null) {
84
- return refuse(`${name}: no skin`);
85
- }
86
-
87
- const joints = skin.joints;
88
- const parent_of = prefab.parent;
89
- const name_of = prefab.name;
90
-
91
- /**
92
- * @type {Map<number, number>} node index → position in the skin's joints
93
- */
94
- const index_of = new Map();
95
-
96
- for (let i = 0; i < joints.length; i++) {
97
- index_of.set(joints[i], i);
98
- }
99
-
100
- /**
101
- * @type {Map<string, number>} name → node index, first of the skin's joints to carry it
102
- */
103
- const by_name = new Map();
104
-
105
- for (let i = 0; i < joints.length; i++) {
106
- const joint = joints[i];
107
- const joint_name = name_of[joint];
108
-
109
- if (joint_name !== "" && !by_name.has(joint_name)) {
110
- by_name.set(joint_name, joint);
111
- }
112
- }
113
-
114
- /**
115
- * @type {Set<number>} node indices
116
- */
117
- const members = new Set();
118
-
119
- for (const joint_name of joint_names) {
120
- const node = by_name.get(joint_name);
121
-
122
- if (node === undefined) {
123
- return refuse(`${name}: the skin has no joint named "${joint_name}"`);
124
- }
125
-
126
- if (members.has(node)) {
127
- return refuse(`${name}: "${joint_name}" is named twice`);
128
- }
129
-
130
- members.add(node);
131
- }
132
-
133
- if (members.size === 0) {
134
- return refuse(`${name}: no joints`);
135
- }
136
-
137
- // Roots: members whose parent is not a member. They all have to hang from
138
- // the same bone, and that bone is the anchor.
139
- const roots = [];
140
-
141
- for (const node of members) {
142
- if (parent_of[node] < 0 || !members.has(parent_of[node])) {
143
- roots.push(node);
144
- }
145
- }
146
-
147
- const anchor_node = parent_of[roots[0]];
148
-
149
- // Node 0 is the prefab's own root — the placement an instance stands at, never a bone of the
150
- // skin — so a garment whose first joint sits directly under it has no bone above it.
151
- if (anchor_node <= 0) {
152
- return refuse(`${name}: "${name_of[roots[0]]}" has no bone above it, so the garment has nothing to hang from`);
153
- }
154
-
155
- for (const root of roots) {
156
- if (parent_of[root] !== anchor_node) {
157
- return refuse(
158
- `${name}: "${name_of[roots[0]]}" hangs from "${name_of[anchor_node]}" and "${name_of[root]}" hangs`
159
- + ` from "${parent_of[root] < 0 ? 'nothing' : name_of[parent_of[root]]}" — a garment hangs from one`
160
- + ` anchor, and chains from different bones are two garments`
161
- );
162
- }
163
- }
164
-
165
- const anchor = index_of.get(anchor_node);
166
-
167
- if (anchor === undefined) {
168
- return refuse(
169
- `${name}: "${name_of[roots[0]]}" hangs from "${name_of[anchor_node]}", which is not a joint of this skin`
170
- );
171
- }
172
-
173
- // Parents before children, so one forward pass composes the chain.
174
- const ordered = [];
175
-
176
- /**
177
- * @type {Map<number, number>} node index → position in `ordered`
178
- */
179
- const position = new Map();
180
-
181
- // Breadth-first from every root at once, which keeps parents before
182
- // children across the whole forest rather than only within one chain.
183
- const queue = roots.slice();
184
-
185
- while (queue.length > 0) {
186
- const node = queue.shift();
187
-
188
- position.set(node, ordered.length);
189
- ordered.push(node);
190
-
191
- for (const child of members) {
192
- if (parent_of[child] === node) {
193
- queue.push(child);
194
- }
195
- }
196
- }
197
-
198
- if (ordered.length !== members.size) {
199
- const stranded = [];
200
-
201
- for (const node of members) {
202
- if (!position.has(node)) {
203
- stranded.push(name_of[node]);
204
- }
205
- }
206
-
207
- return refuse(
208
- `${name}: ${stranded.length} joints are unreachable from the anchor (${stranded.join(', ')})`
209
- );
210
- }
211
-
212
- const joint_count = ordered.length;
213
-
214
- const joint = new Int32Array(joint_count);
215
- const joint_parent = new Int32Array(joint_count);
216
-
217
- const rest_position = new Float32Array(joint_count * 3);
218
- const rest_rotation = new Float32Array(joint_count * 4);
219
-
220
- const joint_name = [];
221
-
222
- for (let i = 0; i < joint_count; i++) {
223
- const node = ordered[i];
224
-
225
- const resolved = index_of.get(node);
226
-
227
- if (resolved === undefined) {
228
- return refuse(`${name}: "${name_of[node]}" is not a joint of this skin`);
229
- }
230
-
231
- joint[i] = resolved;
232
- joint_parent[i] = members.has(parent_of[node]) ? position.get(parent_of[node]) : -1;
233
-
234
- joint_name.push(name_of[node]);
235
-
236
- const local = prefab.local[node];
237
-
238
- rest_position[i * 3] = local[TRANSFORM64_TRANSLATION_OFFSET];
239
- rest_position[i * 3 + 1] = local[TRANSFORM64_TRANSLATION_OFFSET + 1];
240
- rest_position[i * 3 + 2] = local[TRANSFORM64_TRANSLATION_OFFSET + 2];
241
-
242
- rest_rotation[i * 4] = local[TRANSFORM64_ROTATION_OFFSET];
243
- rest_rotation[i * 4 + 1] = local[TRANSFORM64_ROTATION_OFFSET + 1];
244
- rest_rotation[i * 4 + 2] = local[TRANSFORM64_ROTATION_OFFSET + 2];
245
- rest_rotation[i * 4 + 3] = local[TRANSFORM64_ROTATION_OFFSET + 3];
246
-
247
- // A joint at no distance from its parent is a zero-length link, which
248
- // has no direction for a stretch row's gradient and no rest length for
249
- // it to hold. §7 P8 rejects it at build time rather than tolerating it
250
- // at runtime, which is what "build-time validation, not runtime
251
- // tolerance" means. The root is included: its parent is the anchor.
252
- const length = Math.hypot(
253
- rest_position[i * 3], rest_position[i * 3 + 1], rest_position[i * 3 + 2]
254
- );
255
-
256
- if (length <= 0) {
257
- return refuse(
258
- `${name}: "${name_of[node]}" sits exactly on its parent, so the link between them`
259
- + ` has no length and no direction`
260
- );
261
- }
262
- }
263
-
264
- return {
265
- proxy: ClothProxy.from({
266
- name,
267
- joint,
268
- joint_parent,
269
- anchor,
270
- rest_position,
271
- rest_rotation,
272
- joint_name
273
- }),
274
- error: ""
275
- };
276
- }
277
-
278
- /**
279
- * @param {string} error
280
- * @returns {ClothProxyBuildResult}
281
- */
282
- function refuse(error) {
283
- return { proxy: null, error };
284
- }
1
+ import { ClothProxy } from "./ClothProxy.js";
2
+ import { cloth_bind_in_frame } from "./cloth_bind_in_frame.js";
3
+
4
+ /**
5
+ * @typedef {import("../../../graphics3/prefab/Prefab.js").Prefab} Prefab
6
+ * @typedef {import("../../../../shade/renderer/animation/Skin.js").Skin} Skin
7
+ */
8
+
9
+ /**
10
+ * # Building a proxy for a garment that is already rigged
11
+ *
12
+ * §11.3 lists ten steps and says that for a rigged garment "only steps 5–8 run,
13
+ * over the joint graph rather than a mesh". This is those steps: find what the
14
+ * garment hangs from, bake the bind pose, resolve names to indices, and
15
+ * validate. Steps 1–4 are mesh work a rigged garment does not need — the
16
+ * artist's joints *are* the particle set and the artist's skin *is* the binding.
17
+ *
18
+ * The colouring step (7) is absent for a reason rather than an omission: the
19
+ * cloth's own row builder colours the particle graph inside `ClothState.from`.
20
+ *
21
+ * ## What the garment hangs from falls out of the topology
22
+ *
23
+ * A joint whose parent is outside the named set is a root of the garment, and
24
+ * its parent is a bone the garment hangs from. Every such bone becomes a
25
+ * particle cloth reads and never writes, with the links to its roots the first
26
+ * links of the fabric — so a cape hanging from one shoulder bone is the cape it
27
+ * always was, and one hanging from both shoulders and the spine is three such
28
+ * particles rather than a refusal. What holds them is a `ClothPin` on each bone,
29
+ * and the build hands back exactly the pins to add, as {@link ClothProxyGroup}s:
30
+ * the topology answers the question, the scene does the holding.
31
+ *
32
+ * ## The frame is the nearest joint above all of them
33
+ *
34
+ * A garment is simulated in the frame of the joint it rides, whose motion §7 P7
35
+ * softens. For a garment hanging from one bone that is the bone; for one hanging
36
+ * from several it is the nearest skin joint above all of them, so that a garment
37
+ * across both shoulders rides the chest between them.
38
+ *
39
+ * @author Alex Goldring
40
+ * @copyright Company Named Limited (c) 2026
41
+ */
42
+
43
+ /**
44
+ * One pin to add: a bone the garment hangs from, and its particle.
45
+ * @typedef {object} ClothProxyGroup
46
+ * @property {number} joint index into `Skin#joints` of the bone
47
+ * @property {Int32Array} particles the proxy particles that bone holds
48
+ */
49
+
50
+ /**
51
+ * @typedef {object} ClothProxyBuildResult
52
+ * @property {ClothProxy|null} proxy `null` when the build refused
53
+ * @property {ClothProxyGroup[]} groups one per bone the garment hangs from; empty when it refused
54
+ * @property {string} error empty when it did not
55
+ */
56
+
57
+ /**
58
+ * Build a proxy from the joints of a skin, named.
59
+ *
60
+ * The names are the only place a name appears anywhere in the system (§11.3
61
+ * step 8) and they do not survive: what comes back holds indices into
62
+ * `skin.joints`.
63
+ *
64
+ * @param {Prefab} prefab the compiled model whose hierarchy the joints are nodes of
65
+ * @param {Skin} skin one of the prefab's skins — joints as node indices. The joint *order* is
66
+ * what is read, and instantiation preserves it
67
+ * @param {string[]} joint_names the garment's own joints, in any order
68
+ * @param {object} [options]
69
+ * @param {string} [options.name]
70
+ * @returns {ClothProxyBuildResult}
71
+ */
72
+ export function cloth_proxy_from_joints(prefab, skin, joint_names, { name = "" } = {}) {
73
+ if (prefab === undefined || prefab === null || prefab.isPrefab !== true) {
74
+ return refuse(`${name}: no prefab`);
75
+ }
76
+
77
+ if (skin === undefined || skin === null) {
78
+ return refuse(`${name}: no skin`);
79
+ }
80
+
81
+ const joints = skin.joints;
82
+ const parent_of = prefab.parent;
83
+ const name_of = prefab.name;
84
+
85
+ /**
86
+ * @type {Map<number, number>} node index → position in the skin's joints
87
+ */
88
+ const index_of = new Map();
89
+
90
+ for (let i = 0; i < joints.length; i++) {
91
+ index_of.set(joints[i], i);
92
+ }
93
+
94
+ /**
95
+ * @type {Map<string, number>} name → node index, first of the skin's joints to carry it
96
+ */
97
+ const by_name = new Map();
98
+
99
+ for (let i = 0; i < joints.length; i++) {
100
+ const joint = joints[i];
101
+ const joint_name = name_of[joint];
102
+
103
+ if (joint_name !== "" && !by_name.has(joint_name)) {
104
+ by_name.set(joint_name, joint);
105
+ }
106
+ }
107
+
108
+ /**
109
+ * @type {Set<number>} node indices
110
+ */
111
+ const members = new Set();
112
+
113
+ for (const joint_name of joint_names) {
114
+ const node = by_name.get(joint_name);
115
+
116
+ if (node === undefined) {
117
+ return refuse(`${name}: the skin has no joint named "${joint_name}"`);
118
+ }
119
+
120
+ if (members.has(node)) {
121
+ return refuse(`${name}: "${joint_name}" is named twice`);
122
+ }
123
+
124
+ members.add(node);
125
+ }
126
+
127
+ if (members.size === 0) {
128
+ return refuse(`${name}: no joints`);
129
+ }
130
+
131
+ // Roots: members whose parent is not a member. Their parents are what the
132
+ // garment hangs from.
133
+ const roots = [];
134
+
135
+ /**
136
+ * @type {number[]} node indices, ascending
137
+ */
138
+ const hung_from = [];
139
+
140
+ for (const node of members) {
141
+ const parent = parent_of[node];
142
+
143
+ if (parent >= 0 && members.has(parent)) {
144
+ continue;
145
+ }
146
+
147
+ // Node 0 is the prefab's own root — the placement an instance stands at, never a bone of the
148
+ // skin — so a garment whose first joint sits directly under it has no bone above it.
149
+ if (parent <= 0) {
150
+ return refuse(`${name}: "${name_of[node]}" has no bone above it, so the garment has nothing to hang from`);
151
+ }
152
+
153
+ if (!index_of.has(parent)) {
154
+ return refuse(`${name}: "${name_of[node]}" hangs from "${name_of[parent]}", which is not a joint of this skin`);
155
+ }
156
+
157
+ roots.push(node);
158
+
159
+ if (hung_from.indexOf(parent) === -1) {
160
+ hung_from.push(parent);
161
+ }
162
+ }
163
+
164
+ hung_from.sort((a, b) => a - b);
165
+
166
+ // The frame: the nearest skin joint above every bone the garment hangs from
167
+ // — for one bone, the bone itself.
168
+ let frame_node = hung_from[0];
169
+
170
+ for (let i = 1; i < hung_from.length; i++) {
171
+ frame_node = common_ancestor(parent_of, frame_node, hung_from[i]);
172
+ }
173
+
174
+ while (frame_node > 0 && !index_of.has(frame_node)) {
175
+ frame_node = parent_of[frame_node];
176
+ }
177
+
178
+ if (frame_node <= 0) {
179
+ return refuse(
180
+ `${name}: nothing in the skin is above all of ${hung_from.map(n => `"${name_of[n]}"`).join(', ')},`
181
+ + ` so the garment has no joint to ride`
182
+ );
183
+ }
184
+
185
+ // Particle order: the bones the garment hangs from, then the garment
186
+ // breadth-first from every root at once, which keeps parents before
187
+ // children across the whole forest.
188
+ const ordered = hung_from.slice();
189
+
190
+ /**
191
+ * @type {Map<number, number>} node index → particle
192
+ */
193
+ const particle_of = new Map();
194
+
195
+ for (let i = 0; i < ordered.length; i++) {
196
+ particle_of.set(ordered[i], i);
197
+ }
198
+
199
+ const queue = roots.slice();
200
+
201
+ while (queue.length > 0) {
202
+ const node = queue.shift();
203
+
204
+ particle_of.set(node, ordered.length);
205
+ ordered.push(node);
206
+
207
+ for (const child of members) {
208
+ if (parent_of[child] === node) {
209
+ queue.push(child);
210
+ }
211
+ }
212
+ }
213
+
214
+ if (ordered.length !== members.size + hung_from.length) {
215
+ const stranded = [];
216
+
217
+ for (const node of members) {
218
+ if (!particle_of.has(node)) {
219
+ stranded.push(name_of[node]);
220
+ }
221
+ }
222
+
223
+ return refuse(
224
+ `${name}: ${stranded.length} joints are unreachable from what the garment hangs from (${stranded.join(', ')})`
225
+ );
226
+ }
227
+
228
+ const particle_count = ordered.length;
229
+
230
+ const joint = new Int32Array(particle_count);
231
+ const output = new Uint8Array(particle_count);
232
+ const parent = new Int32Array(particle_count);
233
+
234
+ const rest_position = new Float32Array(particle_count * 3);
235
+ const rest_rotation = new Float32Array(particle_count * 4);
236
+
237
+ const particle_name = [];
238
+
239
+ const pose = cloth_bind_in_frame(prefab, frame_node);
240
+
241
+ for (let i = 0; i < particle_count; i++) {
242
+ const node = ordered[i];
243
+
244
+ joint[i] = index_of.get(node);
245
+
246
+ const is_garment = members.has(node);
247
+
248
+ output[i] = is_garment ? 1 : 0;
249
+ parent[i] = is_garment ? particle_of.get(parent_of[node]) : -1;
250
+
251
+ particle_name.push(name_of[node]);
252
+
253
+ const p = pose(node);
254
+
255
+ rest_position[i * 3] = p[0];
256
+ rest_position[i * 3 + 1] = p[1];
257
+ rest_position[i * 3 + 2] = p[2];
258
+
259
+ rest_rotation[i * 4] = p[3];
260
+ rest_rotation[i * 4 + 1] = p[4];
261
+ rest_rotation[i * 4 + 2] = p[5];
262
+ rest_rotation[i * 4 + 3] = p[6];
263
+
264
+ if (!is_garment) {
265
+ continue;
266
+ }
267
+
268
+ // A joint at no distance from its parent is a zero-length link, which
269
+ // has no direction for a stretch row's gradient and no rest length for
270
+ // it to hold. §7 P8 rejects it at build time rather than tolerating it
271
+ // at runtime, which is what "build-time validation, not runtime
272
+ // tolerance" means. A root is included: its parent is the bone it
273
+ // hangs from.
274
+ const q = pose(parent_of[node]);
275
+
276
+ if (Math.hypot(p[0] - q[0], p[1] - q[1], p[2] - q[2]) <= 0) {
277
+ return refuse(
278
+ `${name}: "${name_of[node]}" sits exactly on its parent, so the link between them`
279
+ + ` has no length and no direction`
280
+ );
281
+ }
282
+ }
283
+
284
+ const groups = hung_from.map((node, i) => ({
285
+ joint: index_of.get(node),
286
+ particles: Int32Array.from([i])
287
+ }));
288
+
289
+ // A chain's fabric runs along its links, and it bends through the pair two
290
+ // links apart.
291
+ const edge = [];
292
+ const skip = [];
293
+
294
+ for (let i = 0; i < particle_count; i++) {
295
+ const p = parent[i];
296
+
297
+ if (p < 0) {
298
+ continue;
299
+ }
300
+
301
+ edge.push(p, i);
302
+
303
+ if (parent[p] >= 0) {
304
+ skip.push(parent[p], i);
305
+ }
306
+ }
307
+
308
+ return {
309
+ proxy: ClothProxy.from({
310
+ name,
311
+ joint,
312
+ output,
313
+ parent,
314
+ edge,
315
+ skip,
316
+ hinge: [],
317
+ triangle: [],
318
+ frame: index_of.get(frame_node),
319
+ rest_position,
320
+ rest_rotation,
321
+ particle_name
322
+ }),
323
+ groups,
324
+ error: ""
325
+ };
326
+ }
327
+
328
+ /**
329
+ * @param {Int32Array} parent_of
330
+ * @param {number} a node
331
+ * @param {number} b node
332
+ * @returns {number} the deepest node both hang from, or themselves
333
+ * @private
334
+ */
335
+ function common_ancestor(parent_of, a, b) {
336
+ const above_a = new Set();
337
+
338
+ for (let n = a; n >= 0; n = parent_of[n]) {
339
+ above_a.add(n);
340
+ }
341
+
342
+ for (let n = b; n >= 0; n = parent_of[n]) {
343
+ if (above_a.has(n)) {
344
+ return n;
345
+ }
346
+ }
347
+
348
+ return 0;
349
+ }
350
+
351
+ /**
352
+ * @param {string} error
353
+ * @returns {ClothProxyBuildResult}
354
+ */
355
+ function refuse(error) {
356
+ return { proxy: null, groups: [], error };
357
+ }