@woosh/meep-engine 3.22.0 → 3.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. package/package.json +1 -1
  2. package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts +118 -0
  3. package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts.map +1 -0
  4. package/src/core/geom/3d/hash-grid/PointHashGrid3.js +283 -0
  5. package/src/core/geom/3d/shape/BoxShape3D.d.ts.map +1 -1
  6. package/src/core/geom/3d/shape/BoxShape3D.js +6 -17
  7. package/src/core/geom/3d/shape/CapsuleShape3D.d.ts.map +1 -1
  8. package/src/core/geom/3d/shape/CapsuleShape3D.js +3 -14
  9. package/src/core/geom/3d/shape/CylinderShape3D.d.ts.map +1 -1
  10. package/src/core/geom/3d/shape/CylinderShape3D.js +3 -21
  11. package/src/core/geom/3d/shape/PlaneShape3D.d.ts +105 -0
  12. package/src/core/geom/3d/shape/PlaneShape3D.d.ts.map +1 -0
  13. package/src/core/geom/3d/shape/PlaneShape3D.js +251 -0
  14. package/src/core/geom/3d/shape/SphereShape3D.js +3 -3
  15. package/src/core/geom/3d/shape/json/shape_to_type.d.ts.map +1 -1
  16. package/src/core/geom/3d/shape/json/shape_to_type.js +3 -0
  17. package/src/core/geom/3d/shape/json/type_adapters.d.ts +14 -0
  18. package/src/core/geom/3d/shape/json/type_adapters.d.ts.map +1 -1
  19. package/src/core/geom/3d/shape/json/type_adapters.js +15 -0
  20. package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts +51 -0
  21. package/src/core/geom/3d/shape/sdf/sdf3_box.d.ts.map +1 -0
  22. package/src/core/geom/3d/shape/sdf/sdf3_box.js +113 -0
  23. package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts +46 -0
  24. package/src/core/geom/3d/shape/sdf/sdf3_capsule.d.ts.map +1 -0
  25. package/src/core/geom/3d/shape/sdf/sdf3_capsule.js +82 -0
  26. package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts +60 -0
  27. package/src/core/geom/3d/shape/sdf/sdf3_cylinder.d.ts.map +1 -0
  28. package/src/core/geom/3d/shape/sdf/sdf3_cylinder.js +126 -0
  29. package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.d.ts +50 -0
  30. package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.d.ts.map +1 -0
  31. package/src/core/geom/3d/shape/sdf/sdf3_degenerate_normal.js +53 -0
  32. package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts +52 -0
  33. package/src/core/geom/3d/shape/sdf/sdf3_plane.d.ts.map +1 -0
  34. package/src/core/geom/3d/shape/sdf/sdf3_plane.js +61 -0
  35. package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts +41 -0
  36. package/src/core/geom/3d/shape/sdf/sdf3_sphere.d.ts.map +1 -0
  37. package/src/core/geom/3d/shape/sdf/sdf3_sphere.js +71 -0
  38. package/src/core/process/ConcurrencyGate.d.ts +103 -0
  39. package/src/core/process/ConcurrencyGate.d.ts.map +1 -0
  40. package/src/core/process/ConcurrencyGate.js +207 -0
  41. package/src/engine/asset/AssetManager.d.ts +10 -0
  42. package/src/engine/asset/AssetManager.d.ts.map +1 -1
  43. package/src/engine/asset/AssetManager.js +10 -0
  44. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +30 -13
  45. package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts +26 -0
  46. package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts.map +1 -0
  47. package/src/engine/graphics3/pose/collect_entity_playbacks.js +40 -0
  48. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts.map +1 -1
  49. package/src/engine/graphics3/pose/query_entity_node_world_pose.js +74 -101
  50. package/src/engine/physics/cloth/MEASUREMENTS.md +1287 -4
  51. package/src/engine/physics/cloth/PLAN.md +1967 -1581
  52. package/src/engine/physics/cloth/build/ClothProxy.d.ts +147 -0
  53. package/src/engine/physics/cloth/build/ClothProxy.d.ts.map +1 -0
  54. package/src/engine/physics/cloth/build/ClothProxy.js +207 -0
  55. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +70 -0
  56. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -0
  57. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +256 -0
  58. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +176 -0
  59. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -0
  60. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +435 -0
  61. package/src/engine/physics/cloth/collider/ClothColliderKind.d.ts +12 -0
  62. package/src/engine/physics/cloth/collider/ClothColliderKind.d.ts.map +1 -0
  63. package/src/engine/physics/cloth/collider/ClothColliderKind.js +38 -0
  64. package/src/engine/physics/cloth/collider/ClothColliderRecord.d.ts +120 -0
  65. package/src/engine/physics/cloth/collider/ClothColliderRecord.d.ts.map +1 -0
  66. package/src/engine/physics/cloth/collider/ClothColliderRecord.js +137 -0
  67. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts +25 -0
  68. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts.map +1 -0
  69. package/src/engine/physics/cloth/collider/cloth_collider_bounds.js +190 -0
  70. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts +44 -0
  71. package/src/engine/physics/cloth/collider/cloth_collider_pack.d.ts.map +1 -0
  72. package/src/engine/physics/cloth/collider/cloth_collider_pack.js +173 -0
  73. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts +94 -0
  74. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts.map +1 -0
  75. package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +275 -0
  76. package/src/engine/physics/cloth/ecs/ClothCollider.d.ts +126 -0
  77. package/src/engine/physics/cloth/ecs/ClothCollider.d.ts.map +1 -0
  78. package/src/engine/physics/cloth/ecs/ClothCollider.js +199 -0
  79. package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts +9 -0
  80. package/src/engine/physics/cloth/ecs/ClothColliderFlags.d.ts.map +1 -0
  81. package/src/engine/physics/cloth/ecs/ClothColliderFlags.js +32 -0
  82. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +114 -0
  83. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -0
  84. package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +243 -0
  85. package/src/engine/physics/cloth/ecs/ClothDynamicsFlags.js +66 -57
  86. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +109 -1
  87. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  88. package/src/engine/physics/cloth/ecs/ClothInstance.js +479 -363
  89. package/src/engine/physics/cloth/ecs/ClothRig.d.ts +95 -0
  90. package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -0
  91. package/src/engine/physics/cloth/ecs/ClothRig.js +140 -0
  92. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +30 -1
  93. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  94. package/src/engine/physics/cloth/ecs/ClothSystem.js +1021 -773
  95. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +90 -0
  96. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -0
  97. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +374 -0
  98. package/src/engine/physics/cloth/ecs/cloth_dynamics_library.d.ts +32 -3
  99. package/src/engine/physics/cloth/ecs/cloth_dynamics_library.d.ts.map +1 -1
  100. package/src/engine/physics/cloth/ecs/cloth_dynamics_library.js +283 -254
  101. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +59 -0
  102. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -0
  103. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +328 -0
  104. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts +13 -0
  105. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -0
  106. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +288 -0
  107. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +58 -0
  108. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -0
  109. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +199 -0
  110. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +8 -63
  111. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  112. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +317 -645
  113. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +61 -0
  114. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  115. package/src/engine/physics/cloth/ecs/cloth_write_back.js +212 -449
  116. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts +49 -0
  117. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -0
  118. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +115 -0
  119. package/src/engine/physics/cloth/playground/README.md +155 -1
  120. package/src/engine/physics/cloth/playground/collide.html +178 -0
  121. package/src/engine/physics/cloth/playground/collide_build.d.ts +95 -0
  122. package/src/engine/physics/cloth/playground/collide_build.d.ts.map +1 -0
  123. package/src/engine/physics/cloth/playground/collide_build.js +315 -0
  124. package/src/engine/physics/cloth/playground/collide_main.d.ts +2 -0
  125. package/src/engine/physics/cloth/playground/collide_main.d.ts.map +1 -0
  126. package/src/engine/physics/cloth/playground/collide_main.js +720 -0
  127. package/src/engine/physics/cloth/playground/garment.html +182 -0
  128. package/src/engine/physics/cloth/playground/garment_build.d.ts +78 -0
  129. package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -0
  130. package/src/engine/physics/cloth/playground/garment_build.js +359 -0
  131. package/src/engine/physics/cloth/playground/garment_main.d.ts +2 -0
  132. package/src/engine/physics/cloth/playground/garment_main.d.ts.map +1 -0
  133. package/src/engine/physics/cloth/playground/garment_main.js +633 -0
  134. package/src/engine/physics/cloth/solver/ClothState.d.ts +208 -5
  135. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  136. package/src/engine/physics/cloth/solver/ClothState.js +302 -8
  137. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +87 -0
  138. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -0
  139. package/src/engine/physics/cloth/solver/cloth_contact_find.js +343 -0
  140. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts +112 -0
  141. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -0
  142. package/src/engine/physics/cloth/solver/cloth_self_find.js +448 -0
  143. package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts +4 -1
  144. package/src/engine/physics/cloth/solver/cloth_solve_vertex.d.ts.map +1 -1
  145. package/src/engine/physics/cloth/solver/cloth_solve_vertex.js +16 -1
  146. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +112 -5
  147. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  148. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +117 -6
  149. package/src/engine/physics/cloth/solver/cloth_step.d.ts +40 -9
  150. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  151. package/src/engine/physics/cloth/solver/cloth_step.js +122 -10
  152. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +95 -0
  153. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -0
  154. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +285 -0
  155. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts +129 -0
  156. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts.map +1 -0
  157. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.js +501 -0
  158. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts +75 -0
  159. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -0
  160. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +202 -0
  161. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  162. package/src/shade/playground/vgeo_viewer/README.md +18 -0
  163. package/src/shade/playground/vgeo_viewer/main.js +87 -50
  164. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
  165. package/src/shade/renderer/buffer/table/GPUDatabase.js +191 -62
  166. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts +94 -2
  167. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
  168. package/src/shade/renderer/buffer/table/GPUTypedTable.js +414 -2
  169. package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.d.ts +14 -0
  170. package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.d.ts.map +1 -0
  171. package/src/shade/renderer/buffer/table/GPU_TABLE_PARTIAL_UPLOAD_DESCRIPTOR_WORDS.js +13 -0
  172. package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.d.ts +17 -0
  173. package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.d.ts.map +1 -0
  174. package/src/shade/renderer/buffer/table/gpu_table_partial_upload_shader.js +116 -0
  175. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +9 -4
  176. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  177. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +843 -734
  178. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts +12 -0
  179. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.d.ts.map +1 -1
  180. package/src/shade/renderer/geometry/bvh/GPUGeometryMeshletsBVH.js +13 -0
  181. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +17 -0
  182. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  183. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +185 -30
  184. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +17 -0
  185. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +141 -24
  186. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +204 -64
  187. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +110 -10
  188. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +19 -0
  189. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +19 -6
  190. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
  191. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +26 -7
  192. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +173 -14
  193. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
  194. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +458 -51
  195. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +49 -13
  196. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
  197. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +52 -14
  198. package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.d.ts +20 -0
  199. package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.d.ts.map +1 -0
  200. package/src/shade/renderer/geometry/virtual/format/read/tool/VGEO_MAX_AUDIT_BYTES.js +19 -0
  201. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.d.ts +27 -0
  202. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.d.ts.map +1 -0
  203. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_audit_container.js +48 -0
  204. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.d.ts +29 -0
  205. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.d.ts.map +1 -0
  206. package/src/shade/renderer/geometry/virtual/format/read/tool/vgeo_install_all_pages.js +60 -0
  207. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +8 -1
  208. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
  209. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +32 -2
  210. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts +258 -0
  211. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts.map +1 -0
  212. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +723 -0
  213. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts +49 -0
  214. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts.map +1 -0
  215. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +50 -0
  216. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  217. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  218. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts +3 -0
  219. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts.map +1 -1
  220. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.js +121 -21
  221. package/src/shade/renderer/texture/virtual/README.md +6 -4
  222. package/src/shade/renderer/texture/virtual/VirtualTextureManager.d.ts.map +1 -1
  223. package/src/shade/renderer/texture/virtual/VirtualTextureManager.js +7 -0
  224. package/src/shade/renderer/texture/virtual/source/VTSourceTiled.d.ts +3 -3
  225. package/src/shade/renderer/texture/virtual/source/VTSourceTiled.js +3 -3
  226. package/src/engine/ecs/system/SystemExecutionPhase.d.ts +0 -9
  227. package/src/engine/ecs/system/SystemExecutionPhase.d.ts.map +0 -1
  228. package/src/engine/graphics/texture/virtual/NOTES.md +0 -128
  229. package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.d.ts +0 -6
  230. package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.d.ts.map +0 -1
  231. package/src/engine/graphics/texture/virtual/VT_DEFAULT_PAGE_RESOLUTION.js +0 -5
  232. package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.d.ts +0 -49
  233. package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.d.ts.map +0 -1
  234. package/src/engine/graphics/texture/virtual/VirtualTextureTileLoader.js +0 -264
  235. package/src/engine/graphics/texture/virtual/VirtualTextureUsage.d.ts +0 -44
  236. package/src/engine/graphics/texture/virtual/VirtualTextureUsage.d.ts.map +0 -1
  237. package/src/engine/graphics/texture/virtual/VirtualTextureUsage.js +0 -228
  238. package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.d.ts +0 -3
  239. package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.d.ts.map +0 -1
  240. package/src/engine/graphics/texture/virtual/VirtualTextureUsageShader.js +0 -73
  241. package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.d.ts +0 -14
  242. package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.d.ts.map +0 -1
  243. package/src/engine/graphics/texture/virtual/debug/ResidencyDebugView.js +0 -85
  244. package/src/engine/graphics/texture/virtual/debug/UsageDebugView.d.ts +0 -12
  245. package/src/engine/graphics/texture/virtual/debug/UsageDebugView.d.ts.map +0 -1
  246. package/src/engine/graphics/texture/virtual/debug/UsageDebugView.js +0 -63
  247. package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.d.ts +0 -12
  248. package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.d.ts.map +0 -1
  249. package/src/engine/graphics/texture/virtual/debug/UsagePyramidDebugView.js +0 -243
  250. package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.d.ts +0 -30
  251. package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.d.ts.map +0 -1
  252. package/src/engine/graphics/texture/virtual/tile/VirtualTextureTile.js +0 -39
  253. package/src/engine/graphics/texture/virtual/tile/compose_finger_print.d.ts +0 -9
  254. package/src/engine/graphics/texture/virtual/tile/compose_finger_print.d.ts.map +0 -1
  255. package/src/engine/graphics/texture/virtual/tile/compose_finger_print.js +0 -24
  256. package/src/engine/graphics/texture/virtual/tile/compose_tile_address.d.ts +0 -9
  257. package/src/engine/graphics/texture/virtual/tile/compose_tile_address.d.ts.map +0 -1
  258. package/src/engine/graphics/texture/virtual/tile/compose_tile_address.js +0 -26
  259. package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.d.ts +0 -11
  260. package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.d.ts.map +0 -1
  261. package/src/engine/graphics/texture/virtual/tile/decompose_finger_print.js +0 -12
  262. package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.d.ts +0 -7
  263. package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.d.ts.map +0 -1
  264. package/src/engine/graphics/texture/virtual/tile/finger_print_to_tile_address.js +0 -16
  265. package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.d.ts +0 -7
  266. package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.d.ts.map +0 -1
  267. package/src/engine/graphics/texture/virtual/tile/tile_address_to_finger_print.js +0 -35
@@ -0,0 +1,328 @@
1
+ import { quat3_multiply } from "../../../../core/geom/3d/quaternion/quat3_multiply.js";
2
+ import { v3_quaternion_apply } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
3
+ import { v3_quaternion_apply_inverse } from "../../../../core/geom/vec3/v3_quaternion_apply_inverse.js";
4
+ import {
5
+ CCR_FEATURE,
6
+ CCR_FRICTION,
7
+ CCR_INFLATION,
8
+ CCR_KIND,
9
+ CCR_PARAM_0,
10
+ CCR_PARAM_1,
11
+ CCR_PARAM_2,
12
+ CCR_PARAM_3,
13
+ CCR_PREV_QW,
14
+ CCR_PREV_QX,
15
+ CCR_PREV_QY,
16
+ CCR_PREV_QZ,
17
+ CCR_PREV_TX,
18
+ CCR_PREV_TY,
19
+ CCR_PREV_TZ,
20
+ CCR_QW,
21
+ CCR_QX,
22
+ CCR_QY,
23
+ CCR_QZ,
24
+ CCR_STRIDE,
25
+ CCR_TX,
26
+ CCR_TY,
27
+ CCR_TZ
28
+ } from "../collider/ClothColliderRecord.js";
29
+ import { cloth_collider_refit_bounds } from "../collider/cloth_collider_bounds.js";
30
+
31
+ /**
32
+ * # Bringing the world's colliders into a cloth's frame
33
+ *
34
+ * The index holds every live cloth collider in **world** coordinates; the
35
+ * solver works in the cloth's own **local** frame (§12 — garment-sized
36
+ * coordinates are what makes `Float32` particle state ample, and the local
37
+ * frame is what makes §7 P7's inertia model natural). So once per cloth per
38
+ * step, the colliders that could touch it are queried out of the index and
39
+ * rewritten into its frame.
40
+ *
41
+ * ## Both poses go into the *current* anchor frame
42
+ *
43
+ * A record carries where the collider was and where it is. Both are converted
44
+ * using the anchor's pose **now**, not each with the anchor pose of its own
45
+ * step, so what the sweep interpolates is the collider's motion *relative to
46
+ * the cloth's frame*. That is the motion the particles actually see: the frame
47
+ * change has already been applied to them by `move_local_frame`, scaled by
48
+ * `ClothDynamics#inertia`, before the step begins.
49
+ *
50
+ * The alternative — converting each pose in its own frame — would make a
51
+ * collider appear to move whenever the anchor did, so a character running past
52
+ * a static wall would sweep the wall through their own cape.
53
+ *
54
+ * ## The query box
55
+ *
56
+ * The cloth's own particle bounds, fattened by how far a contact reaches, and
57
+ * then by how far the solver will let a particle travel in one step. The second
58
+ * term is what stops a fast cloth outrunning its own broadphase within the step
59
+ * it was gathered for; it is the velocity clamp of §7 P1 read as a distance,
60
+ * which is the quantity it was built out of.
61
+ *
62
+ * @author Alex Goldring
63
+ * @copyright Company Named Limited (c) 2026
64
+ */
65
+
66
+ /**
67
+ * Query the index and rewrite the overlapping colliders into the cloth's frame.
68
+ *
69
+ * @param {ClothInstance} instance filled in place — `collider_table`,
70
+ * `collider_key` and `collider_count`
71
+ * @param {ClothColliderIndex} index
72
+ * @param {number} reach how far a particle may travel this step, metres
73
+ * @returns {number} how many colliders were gathered
74
+ */
75
+ export function cloth_gather_colliders(instance, index, reach) {
76
+ const state = instance.state;
77
+
78
+ const particle_count = state.particle_count;
79
+ const position = state.position;
80
+
81
+ let min_x = Infinity;
82
+ let min_y = Infinity;
83
+ let min_z = Infinity;
84
+ let max_x = -Infinity;
85
+ let max_y = -Infinity;
86
+ let max_z = -Infinity;
87
+
88
+ for (let i = 0; i < particle_count; i++) {
89
+ const p = i * 3;
90
+
91
+ const x = position[p];
92
+ const y = position[p + 1];
93
+ const z = position[p + 2];
94
+
95
+ if (x < min_x) { min_x = x; }
96
+ if (y < min_y) { min_y = y; }
97
+ if (z < min_z) { min_z = z; }
98
+ if (x > max_x) { max_x = x; }
99
+ if (y > max_y) { max_y = y; }
100
+ if (z > max_z) { max_z = z; }
101
+ }
102
+
103
+ if (particle_count === 0) {
104
+ instance.collider_count = 0;
105
+
106
+ return 0;
107
+ }
108
+
109
+ const margin = reach + state.contact_radius * 2;
110
+
111
+ min_x -= margin;
112
+ min_y -= margin;
113
+ min_z -= margin;
114
+ max_x += margin;
115
+ max_y += margin;
116
+ max_z += margin;
117
+
118
+ // The anchor pose the particles were carried into this step, not the live
119
+ // component — those are the same value by the time this runs, and the
120
+ // cached pair is the one `move_local_frame` used.
121
+ const anchor_x = instance.anchor_translation[0];
122
+ const anchor_y = instance.anchor_translation[1];
123
+ const anchor_z = instance.anchor_translation[2];
124
+
125
+ const qx = instance.anchor_rotation[0];
126
+ const qy = instance.anchor_rotation[1];
127
+ const qz = instance.anchor_rotation[2];
128
+ const qw = instance.anchor_rotation[3];
129
+
130
+ // The local box's eight corners, in world. A rotated box is not a box, so
131
+ // the world query volume is the bounds of the rotated one rather than the
132
+ // rotation of the bounds.
133
+ let world_min_x = Infinity;
134
+ let world_min_y = Infinity;
135
+ let world_min_z = Infinity;
136
+ let world_max_x = -Infinity;
137
+ let world_max_y = -Infinity;
138
+ let world_max_z = -Infinity;
139
+
140
+ for (let corner = 0; corner < 8; corner++) {
141
+ v3_quaternion_apply(
142
+ CORNER, 0,
143
+ (corner & 1) === 0 ? min_x : max_x,
144
+ (corner & 2) === 0 ? min_y : max_y,
145
+ (corner & 4) === 0 ? min_z : max_z,
146
+ qx, qy, qz, qw
147
+ );
148
+
149
+ const x = CORNER[0] + anchor_x;
150
+ const y = CORNER[1] + anchor_y;
151
+ const z = CORNER[2] + anchor_z;
152
+
153
+ if (x < world_min_x) { world_min_x = x; }
154
+ if (y < world_min_y) { world_min_y = y; }
155
+ if (z < world_min_z) { world_min_z = z; }
156
+ if (x > world_max_x) { world_max_x = x; }
157
+ if (y > world_max_y) { world_max_y = y; }
158
+ if (z > world_max_z) { world_max_z = z; }
159
+ }
160
+
161
+ const cloth = instance.cloth;
162
+
163
+ const found = index.query(
164
+ HANDLES, world_min_x, world_min_y, world_min_z,
165
+ world_max_x, world_max_y, world_max_z,
166
+ cloth.layer, cloth.mask
167
+ );
168
+
169
+ if (instance.collider_table === null || instance.collider_table.length < found * CCR_STRIDE) {
170
+ let capacity = 8;
171
+
172
+ while (capacity < found) {
173
+ capacity *= 2;
174
+ }
175
+
176
+ instance.collider_table = new Float32Array(capacity * CCR_STRIDE);
177
+ instance.collider_key = new Int32Array(capacity);
178
+ }
179
+
180
+ const table = instance.collider_table;
181
+ const keys = instance.collider_key;
182
+
183
+ const source = index.table;
184
+
185
+ for (let i = 0; i < found; i++) {
186
+ const handle = HANDLES[i];
187
+
188
+ const from = handle * CCR_STRIDE;
189
+ const to = i * CCR_STRIDE;
190
+
191
+ keys[i] = handle;
192
+
193
+ table[to + CCR_KIND] = source[from + CCR_KIND];
194
+ table[to + CCR_PARAM_0] = source[from + CCR_PARAM_0];
195
+ table[to + CCR_PARAM_1] = source[from + CCR_PARAM_1];
196
+ table[to + CCR_PARAM_2] = source[from + CCR_PARAM_2];
197
+ table[to + CCR_PARAM_3] = source[from + CCR_PARAM_3];
198
+ table[to + CCR_FEATURE] = source[from + CCR_FEATURE];
199
+ table[to + CCR_FRICTION] = source[from + CCR_FRICTION];
200
+ table[to + CCR_INFLATION] = source[from + CCR_INFLATION];
201
+
202
+ localise(
203
+ table, to + CCR_TX, to + CCR_QX,
204
+ source[from + CCR_TX], source[from + CCR_TY], source[from + CCR_TZ],
205
+ source[from + CCR_QX], source[from + CCR_QY], source[from + CCR_QZ], source[from + CCR_QW],
206
+ anchor_x, anchor_y, anchor_z, qx, qy, qz, qw
207
+ );
208
+
209
+ localise(
210
+ table, to + CCR_PREV_TX, to + CCR_PREV_QX,
211
+ source[from + CCR_PREV_TX], source[from + CCR_PREV_TY], source[from + CCR_PREV_TZ],
212
+ source[from + CCR_PREV_QX], source[from + CCR_PREV_QY],
213
+ source[from + CCR_PREV_QZ], source[from + CCR_PREV_QW],
214
+ anchor_x, anchor_y, anchor_z, qx, qy, qz, qw
215
+ );
216
+
217
+ cloth_collider_refit_bounds(table, i, CCR_STRIDE);
218
+ }
219
+
220
+ instance.collider_count = found;
221
+
222
+ return found;
223
+ }
224
+
225
+ /**
226
+ * Write a world pose into a record's translation and rotation slots, expressed
227
+ * in the anchor's frame.
228
+ *
229
+ * @param {Float32Array} table
230
+ * @param {number} translation_slot
231
+ * @param {number} rotation_slot
232
+ * @param {number} tx
233
+ * @param {number} ty
234
+ * @param {number} tz
235
+ * @param {number} rx
236
+ * @param {number} ry
237
+ * @param {number} rz
238
+ * @param {number} rw
239
+ * @param {number} anchor_x
240
+ * @param {number} anchor_y
241
+ * @param {number} anchor_z
242
+ * @param {number} qx
243
+ * @param {number} qy
244
+ * @param {number} qz
245
+ * @param {number} qw
246
+ * @private
247
+ */
248
+ function localise(
249
+ table, translation_slot, rotation_slot,
250
+ tx, ty, tz, rx, ry, rz, rw,
251
+ anchor_x, anchor_y, anchor_z, qx, qy, qz, qw
252
+ ) {
253
+ v3_quaternion_apply_inverse(
254
+ LOCAL_TRANSLATION, 0,
255
+ tx - anchor_x, ty - anchor_y, tz - anchor_z,
256
+ qx, qy, qz, qw
257
+ );
258
+
259
+ table[translation_slot] = LOCAL_TRANSLATION[0];
260
+ table[translation_slot + 1] = LOCAL_TRANSLATION[1];
261
+ table[translation_slot + 2] = LOCAL_TRANSLATION[2];
262
+
263
+ quat3_multiply(LOCAL_ROTATION, 0, -qx, -qy, -qz, qw, rx, ry, rz, rw);
264
+
265
+ table[rotation_slot] = LOCAL_ROTATION[0];
266
+ table[rotation_slot + 1] = LOCAL_ROTATION[1];
267
+ table[rotation_slot + 2] = LOCAL_ROTATION[2];
268
+ table[rotation_slot + 3] = LOCAL_ROTATION[3];
269
+ }
270
+
271
+ /**
272
+ * Whether any collider overlapping this cloth moved between the previous step
273
+ * and this one — §7 P5's "wake on collider motion", asked without waking.
274
+ *
275
+ * A sleeping cloth is not stepped and not written back, so something has to
276
+ * notice when the world it was resting against moves. This is that something,
277
+ * and it is a broadphase query plus a pose comparison: cheaper than a step by
278
+ * three orders of magnitude, which is what makes sleep worth having at all.
279
+ *
280
+ * @param {ClothInstance} instance
281
+ * @param {ClothColliderIndex} index
282
+ * @returns {boolean}
283
+ */
284
+ export function cloth_colliders_moved(instance, index) {
285
+ const found = cloth_gather_colliders(instance, index, 0);
286
+
287
+ const table = instance.collider_table;
288
+
289
+ for (let i = 0; i < found; i++) {
290
+ const r = i * CCR_STRIDE;
291
+
292
+ if (table[r + CCR_TX] !== table[r + CCR_PREV_TX]
293
+ || table[r + CCR_TY] !== table[r + CCR_PREV_TY]
294
+ || table[r + CCR_TZ] !== table[r + CCR_PREV_TZ]
295
+ || table[r + CCR_QX] !== table[r + CCR_PREV_QX]
296
+ || table[r + CCR_QY] !== table[r + CCR_PREV_QY]
297
+ || table[r + CCR_QZ] !== table[r + CCR_PREV_QZ]
298
+ || table[r + CCR_QW] !== table[r + CCR_PREV_QW]) {
299
+ return true;
300
+ }
301
+ }
302
+
303
+ return false;
304
+ }
305
+
306
+ /**
307
+ * @type {number[]}
308
+ * @private
309
+ */
310
+ const HANDLES = [];
311
+
312
+ /**
313
+ * @type {Float64Array}
314
+ * @private
315
+ */
316
+ const CORNER = new Float64Array(3);
317
+
318
+ /**
319
+ * @type {Float64Array}
320
+ * @private
321
+ */
322
+ const LOCAL_TRANSLATION = new Float64Array(3);
323
+
324
+ /**
325
+ * @type {Float64Array}
326
+ * @private
327
+ */
328
+ const LOCAL_ROTATION = new Float64Array(4);
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Fill `blended_position` and `blended_rotation` from the solved particles.
3
+ *
4
+ * Both are in the **cloth's own frame**: the position is the particle lerped
5
+ * towards its animated one by `Cloth#blend`, and the rotation is the swing
6
+ * composed onto the animated orientation. Node 0 — the anchor — is the origin of
7
+ * that frame, so its rotation is the identity rather than anything read off it.
8
+ *
9
+ * @param {ClothInstance} instance
10
+ * @returns {void}
11
+ */
12
+ export function cloth_reconstruct_pose(instance: ClothInstance): void;
13
+ //# sourceMappingURL=cloth_reconstruct_pose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloth_reconstruct_pose.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js"],"names":[],"mappings":"AA6DA;;;;;;;;;;GAUG;AACH,iEAFa,IAAI,CAqEhB"}
@@ -0,0 +1,288 @@
1
+ import { quat3_multiply } from "../../../../core/geom/3d/quaternion/quat3_multiply.js";
2
+ import { quat3_nlerp } from "../../../../core/geom/3d/quaternion/quat3_nlerp.js";
3
+ import { quat3_shortest_arc } from "../../../../core/geom/3d/quaternion/quat3_shortest_arc.js";
4
+
5
+ /**
6
+ * # From particles to a pose — the half of the write-back that is arithmetic
7
+ *
8
+ * A particle has a position and no orientation, so a node's rotation has to be
9
+ * reconstructed. This module does that, in the cloth's own frame, into
10
+ * {@link ClothInstance#blended_position} and
11
+ * {@link ClothInstance#blended_rotation} — and then stops. What is done with the
12
+ * result is the *writer's* business, and there are two of them: the entity path
13
+ * writes a `Transform64` and a `TransformAttachment`, the rig path writes a
14
+ * `Node3D`.
15
+ *
16
+ * M3 split it out for exactly that reason. §11 claims "the solver is identical
17
+ * either way; only seeding and write-back differ", and a second copy of the
18
+ * swing reconstruction would have made that claim true of the solver and false
19
+ * of everything above it.
20
+ *
21
+ * ## Rotation is a swing on top of the animated orientation
22
+ *
23
+ * q_node = swing(d_animated → d_simulated) ⊗ q_animated
24
+ *
25
+ * Twist about the link is inherited from the animation rather than invented,
26
+ * which is right: a chain of particles carries no twist degree of freedom and
27
+ * any twist this code produced would be a fabrication. And it degenerates
28
+ * correctly — at `blend = 0` the simulated direction *is* the animated one, the
29
+ * swing is the identity, and the reconstruction reproduces the authored pose
30
+ * exactly.
31
+ *
32
+ * A node with a parent and children has two links and two swings, and takes the
33
+ * half-way rotation between them. A leaf has only its parent's. Without that,
34
+ * every link points at its child and a two-link chain reads as a hinge with a
35
+ * corner in it.
36
+ *
37
+ * @author Alex Goldring
38
+ * @copyright Company Named Limited (c) 2026
39
+ */
40
+
41
+ /**
42
+ * Scratch for one node's swing quaternions. Module-level: the reconstruction
43
+ * allocates nothing.
44
+ * @type {Float64Array}
45
+ * @private
46
+ */
47
+ const SWING = new Float64Array(12);
48
+
49
+ /** Where the parent-driven swing sits in {@link SWING}. @private */
50
+ const SWING_PARENT = 0;
51
+ /** Where the child-driven swing sits in {@link SWING}. @private */
52
+ const SWING_CHILD = 4;
53
+ /** Where the blended swing sits. @private */
54
+ const SWING_OUT = 8;
55
+
56
+ /**
57
+ * @type {Float64Array}
58
+ * @private
59
+ */
60
+ const DIRECTION = new Float64Array(12);
61
+
62
+ /**
63
+ * Fill `blended_position` and `blended_rotation` from the solved particles.
64
+ *
65
+ * Both are in the **cloth's own frame**: the position is the particle lerped
66
+ * towards its animated one by `Cloth#blend`, and the rotation is the swing
67
+ * composed onto the animated orientation. Node 0 — the anchor — is the origin of
68
+ * that frame, so its rotation is the identity rather than anything read off it.
69
+ *
70
+ * @param {ClothInstance} instance
71
+ * @returns {void}
72
+ */
73
+ export function cloth_reconstruct_pose(instance) {
74
+ const node_count = instance.node_count;
75
+
76
+ const state = instance.state;
77
+ const particle_of_node = instance.particle_of_node;
78
+
79
+ const blended = instance.blended_position;
80
+ const animated = instance.animated_position;
81
+
82
+ let blend = instance.cloth.blend;
83
+
84
+ if (blend < 0) {
85
+ blend = 0;
86
+ } else if (blend > 1) {
87
+ blend = 1;
88
+ }
89
+
90
+ const position = state.position;
91
+
92
+ for (let node = 0; node < node_count; node++) {
93
+ const p = particle_of_node[node] * 3;
94
+ const n = node * 3;
95
+
96
+ blended[n] = animated[n] + blend * (position[p] - animated[n]);
97
+ blended[n + 1] = animated[n + 1] + blend * (position[p + 1] - animated[n + 1]);
98
+ blended[n + 2] = animated[n + 2] + blend * (position[p + 2] - animated[n + 2]);
99
+ }
100
+
101
+ const parent = instance.node_parent;
102
+ const rotation = instance.animated_rotation;
103
+
104
+ const reconstructed = instance.blended_rotation;
105
+
106
+ reconstructed[0] = 0;
107
+ reconstructed[1] = 0;
108
+ reconstructed[2] = 0;
109
+ reconstructed[3] = 1;
110
+
111
+ for (let node = 1; node < node_count; node++) {
112
+ const has_parent_swing = link_swing(instance, parent[node], node, SWING_PARENT);
113
+ const has_child_swing = children_swing(instance, node, SWING_CHILD);
114
+
115
+ let swing = SWING_OUT;
116
+
117
+ if (has_parent_swing && has_child_swing) {
118
+ quat3_nlerp(
119
+ SWING, SWING_OUT,
120
+ SWING[SWING_PARENT], SWING[SWING_PARENT + 1], SWING[SWING_PARENT + 2], SWING[SWING_PARENT + 3],
121
+ SWING[SWING_CHILD], SWING[SWING_CHILD + 1], SWING[SWING_CHILD + 2], SWING[SWING_CHILD + 3],
122
+ 0.5
123
+ );
124
+ } else if (has_child_swing) {
125
+ swing = SWING_CHILD;
126
+ } else {
127
+ // A leaf, or a link so short its direction is meaningless — in
128
+ // which case `link_swing` left the identity there.
129
+ swing = SWING_PARENT;
130
+ }
131
+
132
+ // Animated orientation first, then the swing: the swing is expressed in
133
+ // the cloth's local frame.
134
+ quat3_multiply(
135
+ reconstructed, node * 4,
136
+ SWING[swing], SWING[swing + 1], SWING[swing + 2], SWING[swing + 3],
137
+ rotation[node * 4], rotation[node * 4 + 1], rotation[node * 4 + 2], rotation[node * 4 + 3]
138
+ );
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Swing of the link from `from` to `to`, into `SWING` at `out`.
144
+ *
145
+ * @param {ClothInstance} instance
146
+ * @param {number} from node
147
+ * @param {number} to node
148
+ * @param {number} out
149
+ * @returns {boolean} false when the link is too short to carry a direction, in
150
+ * which case the identity was written
151
+ * @private
152
+ */
153
+ function link_swing(instance, from, to, out) {
154
+ const animated = instance.animated_position;
155
+ const blended = instance.blended_position;
156
+
157
+ const a = from * 3;
158
+ const b = to * 3;
159
+
160
+ const has_animated = unit(DIRECTION, 0,
161
+ animated[b] - animated[a], animated[b + 1] - animated[a + 1], animated[b + 2] - animated[a + 2]);
162
+
163
+ const has_blended = unit(DIRECTION, 3,
164
+ blended[b] - blended[a], blended[b + 1] - blended[a + 1], blended[b + 2] - blended[a + 2]);
165
+
166
+ if (!has_animated || !has_blended) {
167
+ identity(out);
168
+
169
+ return false;
170
+ }
171
+
172
+ quat3_shortest_arc(
173
+ SWING, out,
174
+ DIRECTION[0], DIRECTION[1], DIRECTION[2],
175
+ DIRECTION[3], DIRECTION[4], DIRECTION[5]
176
+ );
177
+
178
+ return true;
179
+ }
180
+
181
+ /**
182
+ * Swing of a node's outgoing links, averaged over its simulated children.
183
+ *
184
+ * The average is over **unit** directions rather than over child positions, so
185
+ * a fork whose two branches are of different lengths is not dominated by the
186
+ * longer one.
187
+ *
188
+ * @param {ClothInstance} instance
189
+ * @param {number} node
190
+ * @param {number} out
191
+ * @returns {boolean}
192
+ * @private
193
+ */
194
+ function children_swing(instance, node, out) {
195
+ const start = instance.node_child_offset[node];
196
+ const end = instance.node_child_offset[node + 1];
197
+
198
+ if (start === end) {
199
+ identity(out);
200
+
201
+ return false;
202
+ }
203
+
204
+ const animated = instance.animated_position;
205
+ const blended = instance.blended_position;
206
+ const child = instance.node_child;
207
+
208
+ const a = node * 3;
209
+
210
+ let anim_x = 0, anim_y = 0, anim_z = 0;
211
+ let sim_x = 0, sim_y = 0, sim_z = 0;
212
+
213
+ for (let i = start; i < end; i++) {
214
+ const b = child[i] * 3;
215
+
216
+ if (unit(DIRECTION, 6,
217
+ animated[b] - animated[a], animated[b + 1] - animated[a + 1], animated[b + 2] - animated[a + 2])) {
218
+ anim_x += DIRECTION[6];
219
+ anim_y += DIRECTION[7];
220
+ anim_z += DIRECTION[8];
221
+ }
222
+
223
+ if (unit(DIRECTION, 9,
224
+ blended[b] - blended[a], blended[b + 1] - blended[a + 1], blended[b + 2] - blended[a + 2])) {
225
+ sim_x += DIRECTION[9];
226
+ sim_y += DIRECTION[10];
227
+ sim_z += DIRECTION[11];
228
+ }
229
+ }
230
+
231
+ const has_animated = unit(DIRECTION, 0, anim_x, anim_y, anim_z);
232
+ const has_blended = unit(DIRECTION, 3, sim_x, sim_y, sim_z);
233
+
234
+ if (!has_animated || !has_blended) {
235
+ // Branches that cancel — a node with two children pointing opposite
236
+ // ways has no outgoing direction to speak of, and the parent link is a
237
+ // better answer than an arbitrary one.
238
+ identity(out);
239
+
240
+ return false;
241
+ }
242
+
243
+ quat3_shortest_arc(
244
+ SWING, out,
245
+ DIRECTION[0], DIRECTION[1], DIRECTION[2],
246
+ DIRECTION[3], DIRECTION[4], DIRECTION[5]
247
+ );
248
+
249
+ return true;
250
+ }
251
+
252
+ /**
253
+ * Normalise into `out`, reporting whether there was a direction to find.
254
+ *
255
+ * @param {Float64Array} out
256
+ * @param {number} offset
257
+ * @param {number} x
258
+ * @param {number} y
259
+ * @param {number} z
260
+ * @returns {boolean}
261
+ * @private
262
+ */
263
+ function unit(out, offset, x, y, z) {
264
+ const length_squared = x * x + y * y + z * z;
265
+
266
+ if (length_squared < 1e-24) {
267
+ return false;
268
+ }
269
+
270
+ const inverse = 1 / Math.sqrt(length_squared);
271
+
272
+ out[offset] = x * inverse;
273
+ out[offset + 1] = y * inverse;
274
+ out[offset + 2] = z * inverse;
275
+
276
+ return true;
277
+ }
278
+
279
+ /**
280
+ * @param {number} offset
281
+ * @private
282
+ */
283
+ function identity(offset) {
284
+ SWING[offset] = 0;
285
+ SWING[offset + 1] = 0;
286
+ SWING[offset + 2] = 0;
287
+ SWING[offset + 3] = 1;
288
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * # Seeding a cloth from a skinned model's joints — §11.2
3
+ *
4
+ * One particle per joint the proxy names, with the anchor as the fixed set, and
5
+ * everything after that is `cloth_build_rows.js` — the same rows, the same
6
+ * geodesics, the same leashes the entity path gets. §11 says "the solver is
7
+ * identical either way; only seeding and write-back differ", and this file plus
8
+ * `cloth_write_back_rig.js` is the whole of the difference.
9
+ *
10
+ * ## Cloth takes authority, and that is a real claim
11
+ *
12
+ * §11.2 says the writable handle is "the joint's `Node3D.transform_local` — the
13
+ * same handle the animation systems write". **The animation systems do not
14
+ * write it.** `TransformAuthority` is explicit: a node a clip drives is
15
+ * `GPU`, and "the CPU allocates and seeds the row, then never writes to it
16
+ * again, so the node's own `transform_local` stops describing it and should not
17
+ * be read as if it did". Cloth writing `transform_local` on such a node would
18
+ * be writing to something nothing reads.
19
+ *
20
+ * So the seed **claims** `TransformAuthority.CPU` on every joint it drives. The
21
+ * consequence is stated rather than hidden: a joint cloth simulates stops being
22
+ * animatable by a clip, because two writers of one row is the race the authority
23
+ * enum exists to prevent. That is the right trade for a cape — the whole point
24
+ * of simulating it is that nobody keyframes it — and it is an authoring error
25
+ * for a garment whose joints are also keyed, which is why the seed says so.
26
+ *
27
+ * ## The animated pose is constant, exactly as it is for a rope
28
+ *
29
+ * §11.1 says a subtree's authored pose is rigid relative to its anchor, so in
30
+ * the anchor's own frame it does not move, and then says "a subtree whose links
31
+ * are themselves animated is not an M1 case — that is the rig path, where the
32
+ * animated pose comes from the skeleton and is live".
33
+ *
34
+ * For a **rigged** garment it is not live either, and the reason is the
35
+ * authority claim above: cloth owns those joints, so nothing else poses them,
36
+ * so their authored pose is the proxy's baked bind pose — constant in the
37
+ * anchor's frame, exactly as a rope's is. What moves is the anchor, and the
38
+ * anchor is a joint of the character's own animated skeleton.
39
+ *
40
+ * The live case is the **unrigged** path, where the animated targets are mesh
41
+ * vertices skinned to the character's skeleton by
42
+ * `mesh_apply_skeletal_vertex_skinning` and genuinely move under the animation.
43
+ * That path is not in M3.
44
+ *
45
+ * @author Alex Goldring
46
+ * @copyright Company Named Limited (c) 2026
47
+ */
48
+ /**
49
+ * Seed `instance` from a proxy and the joints of a skin.
50
+ *
51
+ * @param {ClothInstance} instance seeded in place
52
+ * @param {ClothProxy} proxy
53
+ * @param {Node3D[]} joints the skin's joints, in the order the proxy indexes
54
+ * @param {number} dt fixed step, seconds
55
+ * @returns {void}
56
+ */
57
+ export function cloth_seed_rig(instance: ClothInstance, proxy: ClothProxy, joints: Node3D[], dt: number): void;
58
+ //# sourceMappingURL=cloth_seed_rig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloth_seed_rig.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/cloth_seed_rig.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH;;;;;;;;GAQG;AACH,mFAJW,QAAQ,MACR,MAAM,GACJ,IAAI,CA6DhB"}