@woosh/meep-engine 2.156.0 → 2.158.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 (695) hide show
  1. package/README.md +1 -3
  2. package/editor/view/ecs/components/common/AutoCanvasView.js +100 -53
  3. package/editor/view/ecs/components/common/TextController.js +59 -0
  4. package/editor/view/node-graph/NodeGraphCamera.js +90 -0
  5. package/editor/view/node-graph/NodeGraphEditorView.js +121 -22
  6. package/editor/view/node-graph/NodeGraphSelection.js +89 -0
  7. package/editor/view/node-graph/NodeGraphView.js +669 -453
  8. package/editor/view/node-graph/NodeView.js +211 -135
  9. package/editor/view/node-graph/actions/ConnectionCreateAction.js +53 -0
  10. package/editor/view/node-graph/actions/ConnectionDeleteAction.js +36 -0
  11. package/editor/view/node-graph/actions/NodeDeleteAction.js +88 -0
  12. package/editor/view/node-graph/actions/NodeParameterSetAction.js +52 -0
  13. package/editor/view/node-graph/actions/NodesMoveAction.js +41 -0
  14. package/editor/view/node-graph/actions/SelectionSetAction.js +60 -0
  15. package/editor/view/node-graph/connection_wire_geometry.js +107 -0
  16. package/package.json +1 -1
  17. package/samples/generation/SampleGenerator0.js +8 -1
  18. package/src/core/binary/reinterpret_float32_as_uint32.d.ts +7 -0
  19. package/src/core/binary/reinterpret_float32_as_uint32.d.ts.map +1 -0
  20. package/src/core/binary/reinterpret_float32_as_uint32.js +13 -0
  21. package/src/core/binary/reinterpret_uint32_as_float32.d.ts +7 -0
  22. package/src/core/binary/reinterpret_uint32_as_float32.d.ts.map +1 -0
  23. package/src/core/binary/reinterpret_uint32_as_float32.js +14 -0
  24. package/src/core/bvh2/bvh3/ebvh_build_for_geometry_incremental.d.ts.map +1 -1
  25. package/src/core/bvh2/bvh3/ebvh_build_for_geometry_incremental.js +1 -3
  26. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_sphere.d.ts +12 -0
  27. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_sphere.d.ts.map +1 -0
  28. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_sphere.js +92 -0
  29. package/src/core/bvh8/BVH8.d.ts +127 -0
  30. package/src/core/bvh8/BVH8.d.ts.map +1 -0
  31. package/src/core/bvh8/BVH8.js +436 -0
  32. package/src/core/bvh8/NOTES.md +63 -0
  33. package/src/core/bvh8/build/BVH8Converter.d.ts +59 -0
  34. package/src/core/bvh8/build/BVH8Converter.d.ts.map +1 -0
  35. package/src/core/bvh8/build/BVH8Converter.js +588 -0
  36. package/src/core/bvh8/build/NodeProxy.d.ts +66 -0
  37. package/src/core/bvh8/build/NodeProxy.d.ts.map +1 -0
  38. package/src/core/bvh8/build/NodeProxy.js +308 -0
  39. package/src/core/bvh8/build/TriangleCluster.d.ts +29 -0
  40. package/src/core/bvh8/build/TriangleCluster.d.ts.map +1 -0
  41. package/src/core/bvh8/build/TriangleCluster.js +123 -0
  42. package/src/core/bvh8/build/aabb3_compute_merge_cost.d.ts +8 -0
  43. package/src/core/bvh8/build/aabb3_compute_merge_cost.d.ts.map +1 -0
  44. package/src/core/bvh8/build/aabb3_compute_merge_cost.js +29 -0
  45. package/src/core/bvh8/build/aabb3_from_triangle_by_index.d.ts +10 -0
  46. package/src/core/bvh8/build/aabb3_from_triangle_by_index.d.ts.map +1 -0
  47. package/src/core/bvh8/build/aabb3_from_triangle_by_index.js +18 -0
  48. package/src/core/bvh8/build/bvh8_build_for_geometry.d.ts +10 -0
  49. package/src/core/bvh8/build/bvh8_build_for_geometry.d.ts.map +1 -0
  50. package/src/core/bvh8/build/bvh8_build_for_geometry.js +303 -0
  51. package/src/core/bvh8/build/bvh8_from_proxy.d.ts +9 -0
  52. package/src/core/bvh8/build/bvh8_from_proxy.d.ts.map +1 -0
  53. package/src/core/bvh8/build/bvh8_from_proxy.js +256 -0
  54. package/src/core/bvh8/build/byte.d.ts +7 -0
  55. package/src/core/bvh8/build/byte.d.ts.map +1 -0
  56. package/src/core/bvh8/build/byte.js +10 -0
  57. package/src/core/bvh8/build/encode_bounds_e.d.ts +9 -0
  58. package/src/core/bvh8/build/encode_bounds_e.d.ts.map +1 -0
  59. package/src/core/bvh8/build/encode_bounds_e.js +12 -0
  60. package/src/core/bvh8/bvh8_convert_to_dot.d.ts +11 -0
  61. package/src/core/bvh8/bvh8_convert_to_dot.d.ts.map +1 -0
  62. package/src/core/bvh8/bvh8_convert_to_dot.js +133 -0
  63. package/src/core/bvh8/bvh8_count_primitives.d.ts +22 -0
  64. package/src/core/bvh8/bvh8_count_primitives.d.ts.map +1 -0
  65. package/src/core/bvh8/bvh8_count_primitives.js +98 -0
  66. package/src/core/bvh8/bvh8_geometry_validate.d.ts +16 -0
  67. package/src/core/bvh8/bvh8_geometry_validate.d.ts.map +1 -0
  68. package/src/core/bvh8/bvh8_geometry_validate.js +149 -0
  69. package/src/core/bvh8/bvh8_geometry_validate_indirect.d.ts +16 -0
  70. package/src/core/bvh8/bvh8_geometry_validate_indirect.d.ts.map +1 -0
  71. package/src/core/bvh8/bvh8_geometry_validate_indirect.js +177 -0
  72. package/src/core/bvh8/bvh8_get_node_bounds.d.ts +9 -0
  73. package/src/core/bvh8/bvh8_get_node_bounds.d.ts.map +1 -0
  74. package/src/core/bvh8/bvh8_get_node_bounds.js +35 -0
  75. package/src/core/bvh8/bvh8_get_node_child_bounds.d.ts +10 -0
  76. package/src/core/bvh8/bvh8_get_node_child_bounds.d.ts.map +1 -0
  77. package/src/core/bvh8/bvh8_get_node_child_bounds.js +53 -0
  78. package/src/core/bvh8/bvh8_node_child_surface_area.d.ts +9 -0
  79. package/src/core/bvh8/bvh8_node_child_surface_area.d.ts.map +1 -0
  80. package/src/core/bvh8/bvh8_node_child_surface_area.js +18 -0
  81. package/src/core/bvh8/bvh8_node_count_triangles.d.ts +8 -0
  82. package/src/core/bvh8/bvh8_node_count_triangles.d.ts.map +1 -0
  83. package/src/core/bvh8/bvh8_node_count_triangles.js +28 -0
  84. package/src/core/bvh8/bvh8_quality.d.ts +8 -0
  85. package/src/core/bvh8/bvh8_quality.d.ts.map +1 -0
  86. package/src/core/bvh8/bvh8_quality.js +73 -0
  87. package/src/core/bvh8/bvh8_validate_structure.d.ts +15 -0
  88. package/src/core/bvh8/bvh8_validate_structure.d.ts.map +1 -0
  89. package/src/core/bvh8/bvh8_validate_structure.js +87 -0
  90. package/src/core/collection/Uint32MinHeap.d.ts +56 -0
  91. package/src/core/collection/Uint32MinHeap.d.ts.map +1 -0
  92. package/src/core/collection/Uint32MinHeap.js +109 -0
  93. package/src/core/collection/list/FilteredListProjection.js +1 -1
  94. package/src/{engine/physics/island → core/collection/union-find}/union_find.d.ts +8 -5
  95. package/src/core/collection/union-find/union_find.d.ts.map +1 -0
  96. package/src/{engine/physics/island → core/collection/union-find}/union_find.js +8 -5
  97. package/src/core/dom/isImageBitmap.d.ts +7 -0
  98. package/src/core/dom/isImageBitmap.d.ts.map +1 -0
  99. package/src/core/dom/isImageBitmap.js +12 -0
  100. package/src/core/function/frameThrottle.d.ts +8 -0
  101. package/src/core/function/frameThrottle.d.ts.map +1 -0
  102. package/src/core/function/frameThrottle.js +23 -0
  103. package/src/{engine/physics/narrowphase/clip_against_axis_uv.d.ts → core/geom/2d/polygon/polygon2_clip_axis_halfplane.d.ts} +3 -3
  104. package/src/core/geom/2d/polygon/polygon2_clip_axis_halfplane.d.ts.map +1 -0
  105. package/src/{engine/physics/narrowphase/clip_against_axis_uv.js → core/geom/2d/polygon/polygon2_clip_axis_halfplane.js} +51 -51
  106. package/src/{engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts → core/geom/3d/aabb/aabb3_transform_oriented_inverse.d.ts} +9 -7
  107. package/src/core/geom/3d/aabb/aabb3_transform_oriented_inverse.d.ts.map +1 -0
  108. package/src/{engine/physics/narrowphase/decomposition/aabb_world_to_local.js → core/geom/3d/aabb/aabb3_transform_oriented_inverse.js} +9 -7
  109. package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.d.ts +12 -0
  110. package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.d.ts.map +1 -0
  111. package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.js +46 -0
  112. package/src/core/geom/3d/box/box3_projected_half_extent.d.ts +28 -0
  113. package/src/core/geom/3d/box/box3_projected_half_extent.d.ts.map +1 -0
  114. package/src/core/geom/3d/box/box3_projected_half_extent.js +35 -0
  115. package/src/core/geom/3d/frustum/read_cluster_frustum_corners.js +1 -1
  116. package/src/core/geom/3d/frustum/read_frustum_corner.d.ts +9 -0
  117. package/src/core/geom/3d/frustum/read_frustum_corner.d.ts.map +1 -0
  118. package/src/core/geom/3d/frustum/read_frustum_corner.js +14 -0
  119. package/src/core/geom/3d/gjk/gjk.d.ts.map +1 -0
  120. package/src/{engine/physics → core/geom/3d}/gjk/gjk.js +430 -372
  121. package/src/{engine/physics → core/geom/3d}/gjk/gjk_epa_penetration.d.ts +8 -5
  122. package/src/core/geom/3d/gjk/gjk_epa_penetration.d.ts.map +1 -0
  123. package/src/{engine/physics → core/geom/3d}/gjk/gjk_epa_penetration.js +520 -544
  124. package/src/{engine/physics → core/geom/3d}/gjk/minkowski_support.d.ts +5 -4
  125. package/src/core/geom/3d/gjk/minkowski_support.d.ts.map +1 -0
  126. package/src/{engine/physics → core/geom/3d}/gjk/minkowski_support.js +71 -70
  127. package/src/{engine/physics → core/geom/3d}/gjk/mpr.d.ts +3 -3
  128. package/src/core/geom/3d/gjk/mpr.d.ts.map +1 -0
  129. package/src/{engine/physics → core/geom/3d}/gjk/mpr.js +368 -362
  130. package/src/{engine/physics/integration/quat_integrate.d.ts → core/geom/3d/quaternion/quat3_integrate.d.ts} +2 -2
  131. package/src/core/geom/3d/quaternion/quat3_integrate.d.ts.map +1 -0
  132. package/src/{engine/physics/integration/quat_integrate.js → core/geom/3d/quaternion/quat3_integrate.js} +1 -1
  133. package/src/{engine/physics/narrowphase/PosedShape.d.ts → core/geom/3d/shape/PosedShape3D.d.ts} +26 -8
  134. package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -0
  135. package/src/{engine/physics/narrowphase/PosedShape.js → core/geom/3d/shape/PosedShape3D.js} +60 -9
  136. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  137. package/src/core/geom/3d/shape/TransformedShape3D.js +15 -11
  138. package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts +1 -1
  139. package/src/core/geom/vec3/v3_quat3_apply_inverse.js +1 -1
  140. package/src/core/math/complex/complex_add.d.ts +1 -1
  141. package/src/core/math/complex/complex_add.d.ts.map +1 -1
  142. package/src/core/math/complex/complex_add.js +12 -3
  143. package/src/core/math/complex/complex_div.d.ts +1 -1
  144. package/src/core/math/complex/complex_div.d.ts.map +1 -1
  145. package/src/core/math/complex/complex_div.js +11 -4
  146. package/src/core/math/complex/complex_mul.d.ts +1 -1
  147. package/src/core/math/complex/complex_mul.d.ts.map +1 -1
  148. package/src/core/math/complex/complex_mul.js +10 -3
  149. package/src/core/math/complex/complex_sub.d.ts +1 -1
  150. package/src/core/math/complex/complex_sub.d.ts.map +1 -1
  151. package/src/core/math/complex/complex_sub.js +12 -3
  152. package/src/{engine/physics/fluid/solver/optimal_sor_omega.d.ts → core/math/linalg/sor_optimal_omega.d.ts} +4 -3
  153. package/src/core/math/linalg/sor_optimal_omega.d.ts.map +1 -0
  154. package/src/{engine/physics/fluid/solver/optimal_sor_omega.js → core/math/linalg/sor_optimal_omega.js} +4 -3
  155. package/src/core/math/lookup/ParameterLookupTable.d.ts +123 -0
  156. package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -0
  157. package/src/core/math/lookup/ParameterLookupTable.js +495 -0
  158. package/src/core/math/lookup/ParameterLookupTableFlags.d.ts +5 -0
  159. package/src/core/math/lookup/ParameterLookupTableFlags.d.ts.map +1 -0
  160. package/src/core/math/lookup/ParameterLookupTableFlags.js +6 -0
  161. package/src/core/math/physics/kinematics/computeInterceptPoint.d.ts.map +1 -0
  162. package/src/{engine/physics → core/math/physics/kinematics}/computeInterceptPoint.js +79 -79
  163. package/src/core/math/physics/mie/ri_air.d.ts.map +1 -1
  164. package/src/core/math/physics/mie/ri_air.js +1 -3
  165. package/src/core/math/physics/mie/ri_ammonium_sulfate.d.ts.map +1 -1
  166. package/src/core/math/physics/mie/ri_ammonium_sulfate.js +1 -3
  167. package/src/core/math/physics/mie/ri_brine.d.ts.map +1 -1
  168. package/src/core/math/physics/mie/ri_brine.js +1 -3
  169. package/src/core/math/physics/mie/ri_dust.d.ts.map +1 -1
  170. package/src/core/math/physics/mie/ri_dust.js +1 -3
  171. package/src/core/math/physics/mie/ri_pollen.d.ts.map +1 -1
  172. package/src/core/math/physics/mie/ri_pollen.js +1 -3
  173. package/src/core/math/physics/mie/ri_smoke.d.ts.map +1 -1
  174. package/src/core/math/physics/mie/ri_smoke.js +1 -3
  175. package/src/core/math/physics/mie/ri_soot.d.ts.map +1 -1
  176. package/src/core/math/physics/mie/ri_soot.js +1 -3
  177. package/src/core/math/physics/mie/ri_water.d.ts.map +1 -1
  178. package/src/core/math/physics/mie/ri_water.js +1 -3
  179. package/src/core/math/random/random_pick_weighted_index.d.ts +10 -0
  180. package/src/core/math/random/random_pick_weighted_index.d.ts.map +1 -0
  181. package/src/core/math/random/random_pick_weighted_index.js +26 -0
  182. package/src/core/model/node-graph/NodeGraph.d.ts +9 -0
  183. package/src/core/model/node-graph/NodeGraph.d.ts.map +1 -1
  184. package/src/core/model/node-graph/NodeGraph.js +38 -0
  185. package/src/core/model/node-graph/visual/NodeGraphVisualData.d.ts +23 -0
  186. package/src/core/model/node-graph/visual/NodeGraphVisualData.d.ts.map +1 -1
  187. package/src/core/model/node-graph/visual/NodeGraphVisualData.js +54 -0
  188. package/src/core/path/convertPathToURL.d.ts +9 -0
  189. package/src/core/path/convertPathToURL.d.ts.map +1 -0
  190. package/src/core/path/convertPathToURL.js +107 -0
  191. package/src/core/process/worker/WorkerBuilder.js +1 -1
  192. package/src/core/process/worker/extractTransferables.js +1 -1
  193. package/src/engine/animation/curve/draw/build_tangent_editor.d.ts.map +1 -1
  194. package/src/engine/animation/curve/draw/build_tangent_editor.js +8 -1
  195. package/src/engine/animation/curve/editor/createKeyframeDraggableAspect.d.ts.map +1 -1
  196. package/src/engine/animation/curve/editor/createKeyframeDraggableAspect.js +11 -5
  197. package/src/engine/asset/Asset.d.ts.map +1 -1
  198. package/src/engine/asset/Asset.js +16 -6
  199. package/src/engine/asset/AssetManager.d.ts +61 -52
  200. package/src/engine/asset/AssetManager.d.ts.map +1 -1
  201. package/src/engine/asset/AssetManager.js +1411 -1045
  202. package/src/engine/asset/AssetRequest.d.ts +1 -1
  203. package/src/engine/asset/AssetRequest.d.ts.map +1 -1
  204. package/src/engine/asset/AssetRequest.js +1 -1
  205. package/src/engine/asset/AssetRequestScope.d.ts.map +1 -1
  206. package/src/engine/asset/AssetRequestScope.js +7 -0
  207. package/src/engine/asset/PendingAsset.d.ts +32 -1
  208. package/src/engine/asset/PendingAsset.d.ts.map +1 -1
  209. package/src/engine/asset/PendingAsset.js +108 -61
  210. package/src/engine/asset/loaders/ArrayBufferLoader.js +2 -2
  211. package/src/engine/asset/loaders/AssetLoader.d.ts.map +1 -1
  212. package/src/engine/asset/loaders/AssetLoader.js +19 -2
  213. package/src/engine/asset/loaders/GLTFAssetLoader.d.ts.map +1 -1
  214. package/src/engine/asset/loaders/GLTFAssetLoader.js +123 -114
  215. package/src/engine/asset/loaders/JavascriptAssetLoader.d.ts +1 -1
  216. package/src/engine/asset/loaders/JavascriptAssetLoader.d.ts.map +1 -1
  217. package/src/engine/asset/loaders/JavascriptAssetLoader.js +31 -47
  218. package/src/engine/asset/loaders/JsonAssetLoader.js +1 -1
  219. package/src/engine/asset/loaders/SVGAssetLoader.js +2 -2
  220. package/src/engine/asset/loaders/SoundAssetLoader.js +1 -1
  221. package/src/engine/asset/loaders/TextAssetLoader.js +2 -2
  222. package/src/{core → engine/asset/loaders}/font/FontAsset.d.ts +1 -1
  223. package/src/engine/asset/loaders/font/FontAsset.d.ts.map +1 -0
  224. package/src/{core → engine/asset/loaders}/font/FontAsset.js +21 -21
  225. package/src/{core → engine/asset/loaders}/font/FontAssetLoader.d.ts +1 -1
  226. package/src/engine/asset/loaders/font/FontAssetLoader.d.ts.map +1 -0
  227. package/src/{core → engine/asset/loaders}/font/FontAssetLoader.js +20 -20
  228. package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts +1 -1
  229. package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts.map +1 -1
  230. package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +11 -20
  231. package/src/engine/asset/loaders/texture/TextureAssetLoader.d.ts.map +1 -1
  232. package/src/engine/asset/loaders/texture/TextureAssetLoader.js +8 -2
  233. package/src/engine/asset/preloader/AssetPreloader.js +1 -1
  234. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.d.ts +1 -1
  235. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.d.ts.map +1 -1
  236. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.js +19 -22
  237. package/src/engine/graphics/FrameThrottle.d.ts +1 -7
  238. package/src/engine/graphics/FrameThrottle.d.ts.map +1 -1
  239. package/src/engine/graphics/FrameThrottle.js +2 -24
  240. package/src/{core/geom/3d/shape/util → engine/graphics/debug}/shape_to_visual_entity.d.ts +1 -1
  241. package/src/engine/graphics/debug/shape_to_visual_entity.d.ts.map +1 -0
  242. package/src/{core/geom/3d/shape/util → engine/graphics/debug}/shape_to_visual_entity.js +159 -159
  243. package/src/{core/geom/3d/tetrahedra → engine/graphics/debug}/visualize_tetrahedral_mesh.d.ts +1 -1
  244. package/src/engine/graphics/debug/visualize_tetrahedral_mesh.d.ts.map +1 -0
  245. package/src/{core/geom/3d/tetrahedra → engine/graphics/debug}/visualize_tetrahedral_mesh.js +46 -46
  246. package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.d.ts +1 -1
  247. package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.d.ts.map +1 -1
  248. package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.js +22 -32
  249. package/src/engine/graphics/ecs/trail2d/Trail2D.d.ts.map +1 -1
  250. package/src/engine/graphics/ecs/trail2d/Trail2D.js +21 -0
  251. package/src/engine/graphics/ecs/trail2d/Trail2DFlags.d.ts +1 -0
  252. package/src/engine/graphics/ecs/trail2d/Trail2DFlags.js +9 -1
  253. package/src/engine/graphics/particles/particular/engine/emitter/serde/ParameterLookupTableSerializationAdapter.d.ts.map +1 -1
  254. package/src/engine/graphics/particles/particular/engine/emitter/serde/ParameterLookupTableSerializationAdapter.js +2 -76
  255. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.d.ts.map +1 -1
  256. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +2 -427
  257. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.d.ts +1 -4
  258. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.d.ts.map +1 -1
  259. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.js +2 -6
  260. package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +1 -1
  261. package/src/engine/graphics/render/forward_plus/read_frustum_corner.d.ts +1 -8
  262. package/src/engine/graphics/render/forward_plus/read_frustum_corner.d.ts.map +1 -1
  263. package/src/engine/graphics/render/forward_plus/read_frustum_corner.js +2 -14
  264. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.d.ts +1 -11
  265. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.d.ts.map +1 -1
  266. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.js +2 -46
  267. package/src/engine/graphics/sh3/prototypeSH3Probe.js +1 -1
  268. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts +27 -0
  269. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts.map +1 -0
  270. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.js +81 -0
  271. package/src/engine/graphics/texture/isImageBitmap.d.ts +1 -6
  272. package/src/engine/graphics/texture/isImageBitmap.d.ts.map +1 -1
  273. package/src/engine/graphics/texture/isImageBitmap.js +2 -12
  274. package/src/{core/process/action → engine/intelligence/behavior/util}/AsynchronousDelayAction.d.ts +2 -2
  275. package/src/engine/intelligence/behavior/util/AsynchronousDelayAction.d.ts.map +1 -0
  276. package/src/{core/process/action → engine/intelligence/behavior/util}/AsynchronousDelayAction.js +55 -55
  277. package/src/engine/network/NetworkSession.d.ts +12 -1
  278. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  279. package/src/engine/network/NetworkSession.js +52 -1
  280. package/src/engine/network/README.md +45 -0
  281. package/src/engine/network/convertPathToURL.d.ts +1 -8
  282. package/src/engine/network/convertPathToURL.d.ts.map +1 -1
  283. package/src/engine/network/convertPathToURL.js +2 -107
  284. package/src/engine/network/core/quantize/quantize_float.d.ts.map +1 -1
  285. package/src/engine/network/core/quantize/quantize_float.js +7 -0
  286. package/src/engine/network/core/quantize/quantize_position.d.ts.map +1 -1
  287. package/src/engine/network/core/quantize/quantize_position.js +12 -1
  288. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  289. package/src/engine/network/orchestrator/NetworkPeer.js +15 -1
  290. package/src/engine/network/replication/Replicator.d.ts +8 -0
  291. package/src/engine/network/replication/Replicator.d.ts.map +1 -1
  292. package/src/engine/network/replication/Replicator.js +48 -0
  293. package/src/engine/network/transport/Channel.d.ts.map +1 -1
  294. package/src/engine/network/transport/Channel.js +46 -12
  295. package/src/engine/network/transport/ReliableCommandPipeline.d.ts +16 -0
  296. package/src/engine/network/transport/ReliableCommandPipeline.d.ts.map +1 -1
  297. package/src/engine/network/transport/ReliableCommandPipeline.js +29 -0
  298. package/src/engine/network/transport/adapters/NodeUDPTransport.d.ts.map +1 -1
  299. package/src/engine/network/transport/adapters/NodeUDPTransport.js +7 -1
  300. package/src/engine/network/transport/fragments/packet_size.d.ts +5 -5
  301. package/src/engine/network/transport/fragments/packet_size.d.ts.map +1 -1
  302. package/src/engine/network/transport/fragments/packet_size.js +5 -5
  303. package/src/engine/physics/BULLET_REVIEW.md +1 -1
  304. package/src/engine/physics/JOLT_REVIEW.md +2 -2
  305. package/src/engine/physics/PLAN.md +1094 -945
  306. package/src/engine/physics/RAPIER_REVIEW.md +2 -2
  307. package/src/engine/physics/body/BodyStorage.d.ts +2 -12
  308. package/src/engine/physics/body/BodyStorage.d.ts.map +1 -1
  309. package/src/engine/physics/body/BodyStorage.js +406 -452
  310. package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -1
  311. package/src/engine/physics/body/SolverBodyState.js +12 -3
  312. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts +28 -3
  313. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts.map +1 -1
  314. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +60 -24
  315. package/src/engine/physics/broadphase/generate_pairs.d.ts +9 -5
  316. package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -1
  317. package/src/engine/physics/broadphase/generate_pairs.js +52 -37
  318. package/src/engine/physics/ccd/linear_sweep.d.ts +15 -5
  319. package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
  320. package/src/engine/physics/ccd/linear_sweep.js +122 -40
  321. package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -1
  322. package/src/engine/physics/constraint/solve_constraints.js +830 -805
  323. package/src/engine/physics/contact/ManifoldStore.d.ts +91 -16
  324. package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
  325. package/src/engine/physics/contact/ManifoldStore.js +204 -60
  326. package/src/engine/physics/ecs/BodyKind.d.ts +7 -3
  327. package/src/engine/physics/ecs/BodyKind.d.ts.map +1 -1
  328. package/src/engine/physics/ecs/BodyKind.js +29 -25
  329. package/src/engine/physics/ecs/Collider.d.ts +7 -0
  330. package/src/engine/physics/ecs/Collider.d.ts.map +1 -1
  331. package/src/engine/physics/ecs/Collider.js +7 -0
  332. package/src/engine/physics/ecs/ColliderSerializationAdapter.js +1 -1
  333. package/src/engine/physics/ecs/PhysicsSystem.d.ts +110 -6
  334. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  335. package/src/engine/physics/ecs/PhysicsSystem.js +467 -45
  336. package/src/engine/physics/ecs/RigidBody.d.ts +20 -5
  337. package/src/engine/physics/ecs/RigidBody.d.ts.map +1 -1
  338. package/src/engine/physics/ecs/RigidBody.js +307 -286
  339. package/src/engine/physics/ecs/RigidBodyFlags.d.ts +6 -3
  340. package/src/engine/physics/ecs/RigidBodyFlags.d.ts.map +1 -1
  341. package/src/engine/physics/ecs/RigidBodyFlags.js +31 -28
  342. package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts +12 -4
  343. package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts.map +1 -1
  344. package/src/engine/physics/ecs/RigidBodySerializationAdapter.js +19 -5
  345. package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.d.ts +10 -0
  346. package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.d.ts.map +1 -0
  347. package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.js +37 -0
  348. package/src/engine/physics/ecs/find_non_finite_physics_state.d.ts +28 -0
  349. package/src/engine/physics/ecs/find_non_finite_physics_state.d.ts.map +1 -0
  350. package/src/engine/physics/ecs/find_non_finite_physics_state.js +76 -0
  351. package/src/engine/physics/events/ContactEventBuffer.d.ts +11 -0
  352. package/src/engine/physics/events/ContactEventBuffer.d.ts.map +1 -1
  353. package/src/engine/physics/events/ContactEventBuffer.js +40 -0
  354. package/src/engine/physics/events/diff_manifolds.d.ts +30 -13
  355. package/src/engine/physics/events/diff_manifolds.d.ts.map +1 -1
  356. package/src/engine/physics/events/diff_manifolds.js +87 -50
  357. package/src/engine/physics/fluid/FluidField.d.ts +98 -26
  358. package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
  359. package/src/engine/physics/fluid/FluidField.js +684 -570
  360. package/src/engine/physics/fluid/FluidSimulator.d.ts +157 -6
  361. package/src/engine/physics/fluid/FluidSimulator.d.ts.map +1 -1
  362. package/src/engine/physics/fluid/FluidSimulator.js +450 -83
  363. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +243 -0
  364. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts +4 -3
  365. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -1
  366. package/src/engine/physics/fluid/ecs/FluidComponent.js +4 -3
  367. package/src/engine/physics/fluid/ecs/FluidObstacle.d.ts +72 -0
  368. package/src/engine/physics/fluid/ecs/FluidObstacle.d.ts.map +1 -0
  369. package/src/engine/physics/fluid/ecs/FluidObstacle.js +97 -0
  370. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +117 -0
  371. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts.map +1 -0
  372. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.js +348 -0
  373. package/src/engine/physics/fluid/ecs/FluidSystem.d.ts +3 -3
  374. package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts +62 -12
  375. package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts.map +1 -1
  376. package/src/engine/physics/fluid/effector/GlobalFluidEffector.js +135 -38
  377. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.d.ts.map +1 -1
  378. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.js +85 -38
  379. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts +27 -8
  380. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts.map +1 -1
  381. package/src/engine/physics/fluid/effector/WakeFluidEffector.js +171 -68
  382. package/src/engine/physics/fluid/prototype.js +25 -1
  383. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.d.ts +42 -0
  384. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.d.ts.map +1 -0
  385. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.js +136 -0
  386. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.d.ts +37 -0
  387. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.d.ts.map +1 -0
  388. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.js +169 -0
  389. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.d.ts +36 -0
  390. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.d.ts.map +1 -0
  391. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.js +100 -0
  392. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts +6 -0
  393. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts.map +1 -1
  394. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.js +6 -0
  395. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts +7 -2
  396. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts.map +1 -1
  397. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.js +17 -12
  398. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.d.ts +42 -0
  399. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.d.ts.map +1 -0
  400. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.js +131 -0
  401. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts +32 -22
  402. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts.map +1 -1
  403. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.js +43 -26
  404. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.d.ts +31 -0
  405. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.d.ts.map +1 -0
  406. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.js +77 -0
  407. package/src/engine/physics/fluid/solver/v3_grid_sample_scalar_masked.d.ts +30 -0
  408. package/src/engine/physics/fluid/solver/v3_grid_sample_scalar_masked.d.ts.map +1 -0
  409. package/src/engine/physics/fluid/solver/v3_grid_sample_scalar_masked.js +92 -0
  410. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts +26 -19
  411. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts.map +1 -1
  412. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.js +46 -42
  413. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts +38 -10
  414. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts.map +1 -1
  415. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.js +158 -75
  416. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts +22 -17
  417. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -1
  418. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +108 -96
  419. package/src/engine/physics/fluid/solver/v3_mac_advect_maccormack_velocity.d.ts +42 -0
  420. package/src/engine/physics/fluid/solver/v3_mac_advect_maccormack_velocity.d.ts.map +1 -0
  421. package/src/engine/physics/fluid/solver/v3_mac_advect_maccormack_velocity.js +319 -0
  422. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.d.ts +53 -0
  423. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.d.ts.map +1 -0
  424. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.js +236 -0
  425. package/src/engine/physics/fluid/solver/v3_mac_advect_sl_velocity.d.ts +46 -0
  426. package/src/engine/physics/fluid/solver/v3_mac_advect_sl_velocity.d.ts.map +1 -0
  427. package/src/engine/physics/fluid/solver/v3_mac_advect_sl_velocity.js +217 -0
  428. package/src/engine/physics/fluid/solver/v3_mac_apply_vorticity_confinement.d.ts +40 -0
  429. package/src/engine/physics/fluid/solver/v3_mac_apply_vorticity_confinement.d.ts.map +1 -0
  430. package/src/engine/physics/fluid/solver/v3_mac_apply_vorticity_confinement.js +165 -0
  431. package/src/engine/physics/fluid/solver/v3_mac_clip_trace.d.ts +44 -0
  432. package/src/engine/physics/fluid/solver/v3_mac_clip_trace.d.ts.map +1 -0
  433. package/src/engine/physics/fluid/solver/v3_mac_clip_trace.js +95 -0
  434. package/src/engine/physics/fluid/solver/v3_mac_compute_divergence.d.ts +38 -0
  435. package/src/engine/physics/fluid/solver/v3_mac_compute_divergence.d.ts.map +1 -0
  436. package/src/engine/physics/fluid/solver/v3_mac_compute_divergence.js +77 -0
  437. package/src/engine/physics/fluid/solver/v3_mac_compute_face_solid.d.ts +52 -0
  438. package/src/engine/physics/fluid/solver/v3_mac_compute_face_solid.d.ts.map +1 -0
  439. package/src/engine/physics/fluid/solver/v3_mac_compute_face_solid.js +131 -0
  440. package/src/engine/physics/fluid/solver/v3_mac_subtract_pressure_gradient.d.ts +38 -0
  441. package/src/engine/physics/fluid/solver/v3_mac_subtract_pressure_gradient.d.ts.map +1 -0
  442. package/src/engine/physics/fluid/solver/v3_mac_subtract_pressure_gradient.js +104 -0
  443. package/src/engine/physics/inertia/world_inverse_inertia.d.ts +30 -1
  444. package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -1
  445. package/src/engine/physics/inertia/world_inverse_inertia.js +160 -116
  446. package/src/engine/physics/integration/integrate_position.js +97 -97
  447. package/src/engine/physics/island/IslandBuilder.d.ts +49 -8
  448. package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -1
  449. package/src/engine/physics/island/IslandBuilder.js +93 -14
  450. package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -1
  451. package/src/engine/physics/narrowphase/box_box_manifold.js +683 -673
  452. package/src/engine/physics/narrowphase/box_triangle_contact.d.ts.map +1 -1
  453. package/src/engine/physics/narrowphase/box_triangle_contact.js +899 -749
  454. package/src/engine/physics/narrowphase/capsule_contacts.d.ts +27 -0
  455. package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -1
  456. package/src/engine/physics/narrowphase/capsule_contacts.js +624 -459
  457. package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts.map +1 -1
  458. package/src/engine/physics/narrowphase/capsule_triangle_contact.js +58 -38
  459. package/src/engine/physics/narrowphase/compute_penetration.d.ts.map +1 -1
  460. package/src/engine/physics/narrowphase/compute_penetration.js +369 -325
  461. package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts +3 -1
  462. package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts.map +1 -1
  463. package/src/engine/physics/narrowphase/convex_convex_manifold.js +568 -422
  464. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts +6 -3
  465. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts.map +1 -1
  466. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.js +66 -10
  467. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts +4 -1
  468. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts.map +1 -1
  469. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.js +97 -94
  470. package/src/engine/physics/narrowphase/mesh_mesh_tet_manifold.js +117 -117
  471. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  472. package/src/engine/physics/narrowphase/narrowphase_step.js +1738 -1739
  473. package/src/engine/physics/narrowphase/reduce_manifold_contacts.d.ts +14 -7
  474. package/src/engine/physics/narrowphase/reduce_manifold_contacts.d.ts.map +1 -1
  475. package/src/engine/physics/narrowphase/reduce_manifold_contacts.js +74 -69
  476. package/src/engine/physics/persistence/solver_caches.d.ts +20 -0
  477. package/src/engine/physics/persistence/solver_caches.d.ts.map +1 -0
  478. package/src/engine/physics/persistence/solver_caches.js +309 -0
  479. package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -1
  480. package/src/engine/physics/queries/overlap_shape.js +187 -184
  481. package/src/engine/physics/queries/raycast.d.ts +3 -2
  482. package/src/engine/physics/queries/raycast.d.ts.map +1 -1
  483. package/src/engine/physics/queries/raycast.js +37 -11
  484. package/src/engine/physics/queries/shape_cast.d.ts +18 -5
  485. package/src/engine/physics/queries/shape_cast.d.ts.map +1 -1
  486. package/src/engine/physics/queries/shape_cast.js +417 -393
  487. package/src/engine/physics/solver/solve_contacts.d.ts +22 -6
  488. package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
  489. package/src/engine/physics/solver/solve_contacts.js +1482 -1338
  490. package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
  491. package/src/engine/physics/vehicle/RaycastVehicle.js +344 -339
  492. package/src/engine/ui/DraggableAspect.d.ts +12 -3
  493. package/src/engine/ui/DraggableAspect.d.ts.map +1 -1
  494. package/src/engine/ui/DraggableAspect.js +115 -83
  495. package/src/generation/COORDINATES.md +54 -0
  496. package/src/generation/GridTaskGroup.js +2 -2
  497. package/src/generation/REVIEW_01_ACTION_PLAN.md +628 -0
  498. package/src/generation/automata/CaveGeneratorCellularAutomata.d.ts +9 -1
  499. package/src/generation/automata/CaveGeneratorCellularAutomata.d.ts.map +1 -1
  500. package/src/generation/automata/CaveGeneratorCellularAutomata.js +79 -59
  501. package/src/generation/automata/CellularAutomata.d.ts +6 -3
  502. package/src/generation/automata/CellularAutomata.d.ts.map +1 -1
  503. package/src/generation/automata/CellularAutomata.js +22 -19
  504. package/src/generation/filtering/CellFilter.d.ts +17 -0
  505. package/src/generation/filtering/CellFilter.d.ts.map +1 -1
  506. package/src/generation/filtering/CellFilter.js +117 -77
  507. package/src/generation/filtering/CellFilterCellMatcher.d.ts.map +1 -1
  508. package/src/generation/filtering/CellFilterCellMatcher.js +2 -0
  509. package/src/generation/filtering/boolean/CellFilterLiteralBoolean.d.ts +5 -0
  510. package/src/generation/filtering/boolean/CellFilterLiteralBoolean.d.ts.map +1 -1
  511. package/src/generation/filtering/boolean/CellFilterLiteralBoolean.js +15 -0
  512. package/src/generation/filtering/core/CellFilterBinaryOperation.d.ts +0 -1
  513. package/src/generation/filtering/core/CellFilterBinaryOperation.d.ts.map +1 -1
  514. package/src/generation/filtering/core/CellFilterBinaryOperation.js +37 -50
  515. package/src/generation/filtering/core/CellFilterOperationTertiary.d.ts +0 -1
  516. package/src/generation/filtering/core/CellFilterOperationTertiary.d.ts.map +1 -1
  517. package/src/generation/filtering/core/CellFilterOperationTertiary.js +43 -59
  518. package/src/generation/filtering/core/CellFilterUnaryOperation.d.ts +0 -1
  519. package/src/generation/filtering/core/CellFilterUnaryOperation.d.ts.map +1 -1
  520. package/src/generation/filtering/core/CellFilterUnaryOperation.js +29 -33
  521. package/src/generation/filtering/numeric/CellFilterCache.d.ts +1 -0
  522. package/src/generation/filtering/numeric/CellFilterCache.d.ts.map +1 -1
  523. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.d.ts +3 -2
  524. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.d.ts.map +1 -1
  525. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.js +9 -35
  526. package/src/generation/filtering/numeric/complex/CellFilterCurvature.d.ts +0 -1
  527. package/src/generation/filtering/numeric/complex/CellFilterCurvature.d.ts.map +1 -1
  528. package/src/generation/filtering/numeric/complex/CellFilterCurvature.js +19 -43
  529. package/src/generation/filtering/numeric/complex/CellFilterFXAA.d.ts +0 -1
  530. package/src/generation/filtering/numeric/complex/CellFilterFXAA.d.ts.map +1 -1
  531. package/src/generation/filtering/numeric/complex/CellFilterFXAA.js +2 -6
  532. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.d.ts.map +1 -1
  533. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.js +9 -12
  534. package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.d.ts.map +1 -1
  535. package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.js +2 -1
  536. package/src/generation/filtering/numeric/complex/CellFilterSobel.d.ts +0 -1
  537. package/src/generation/filtering/numeric/complex/CellFilterSobel.d.ts.map +1 -1
  538. package/src/generation/filtering/numeric/complex/CellFilterSobel.js +2 -6
  539. package/src/generation/filtering/numeric/math/CellFilterInverseLerp.d.ts +5 -4
  540. package/src/generation/filtering/numeric/math/CellFilterInverseLerp.d.ts.map +1 -1
  541. package/src/generation/filtering/numeric/math/CellFilterInverseLerp.js +5 -4
  542. package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.d.ts +17 -0
  543. package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.d.ts.map +1 -0
  544. package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.js +42 -0
  545. package/src/generation/filtering/numeric/sampling/AbstractCellFilterSampleGridLayer.d.ts.map +1 -1
  546. package/src/generation/filtering/numeric/sampling/AbstractCellFilterSampleGridLayer.js +7 -1
  547. package/src/generation/filtering/numeric/util/populateSampler2DFromCellFilter.d.ts.map +1 -1
  548. package/src/generation/filtering/numeric/util/populateSampler2DFromCellFilter.js +7 -10
  549. package/src/generation/filtering/numeric/util/sampler_from_filter.d.ts.map +1 -1
  550. package/src/generation/filtering/numeric/util/sampler_from_filter.js +2 -1
  551. package/src/generation/grid/GridData.d.ts.map +1 -1
  552. package/src/generation/grid/GridData.js +14 -1
  553. package/src/generation/grid/actions/ContinuousGridCellAction.d.ts +10 -3
  554. package/src/generation/grid/actions/ContinuousGridCellAction.d.ts.map +1 -1
  555. package/src/generation/grid/actions/ContinuousGridCellAction.js +18 -3
  556. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainHeight.d.ts +11 -1
  557. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainHeight.d.ts.map +1 -1
  558. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainHeight.js +13 -3
  559. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.d.ts +1 -1
  560. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.js +2 -2
  561. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.d.ts +1 -1
  562. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.d.ts.map +1 -1
  563. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.js +4 -6
  564. package/src/generation/grid/coords/grid_to_texel.d.ts +9 -0
  565. package/src/generation/grid/coords/grid_to_texel.d.ts.map +1 -0
  566. package/src/generation/grid/coords/grid_to_texel.js +10 -0
  567. package/src/generation/grid/coords/texel_to_grid.d.ts +9 -0
  568. package/src/generation/grid/coords/texel_to_grid.d.ts.map +1 -0
  569. package/src/generation/grid/coords/texel_to_grid.js +10 -0
  570. package/src/generation/grid/generation/GridTaskApplyActionToCells.d.ts +2 -2
  571. package/src/generation/grid/generation/GridTaskApplyActionToCells.d.ts.map +1 -1
  572. package/src/generation/grid/generation/GridTaskApplyActionToCells.js +10 -6
  573. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.d.ts.map +1 -1
  574. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.js +20 -21
  575. package/src/generation/grid/generation/GridTaskExecuteRuleTimes.d.ts +7 -0
  576. package/src/generation/grid/generation/GridTaskExecuteRuleTimes.d.ts.map +1 -1
  577. package/src/generation/grid/generation/GridTaskExecuteRuleTimes.js +18 -10
  578. package/src/generation/grid/generation/discrete/GridTaskCellularAutomata.d.ts.map +1 -1
  579. package/src/generation/grid/generation/discrete/GridTaskCellularAutomata.js +16 -7
  580. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.d.ts +5 -3
  581. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.d.ts.map +1 -1
  582. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.js +26 -23
  583. package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.d.ts.map +1 -1
  584. package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.js +10 -1
  585. package/src/generation/grid/generation/grid/select/CellSupplierBestN.d.ts.map +1 -1
  586. package/src/generation/grid/generation/grid/select/CellSupplierBestN.js +4 -0
  587. package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts +15 -8
  588. package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts.map +1 -1
  589. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +89 -92
  590. package/src/generation/markers/GridActionRuleSet.d.ts.map +1 -1
  591. package/src/generation/markers/GridActionRuleSet.js +10 -2
  592. package/src/generation/markers/GridCellActionPlaceMarker.d.ts +11 -0
  593. package/src/generation/markers/GridCellActionPlaceMarker.d.ts.map +1 -1
  594. package/src/generation/markers/GridCellActionPlaceMarker.js +20 -3
  595. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts +3 -1
  596. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts.map +1 -1
  597. package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +9 -2
  598. package/src/generation/markers/MarkerNode.d.ts +8 -3
  599. package/src/generation/markers/MarkerNode.d.ts.map +1 -1
  600. package/src/generation/markers/MarkerNode.js +12 -5
  601. package/src/generation/markers/actions/MarkerNodeActionEntityPlacement.js +1 -1
  602. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.d.ts +1 -1
  603. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.d.ts.map +1 -1
  604. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.js +1 -1
  605. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.d.ts +1 -1
  606. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.d.ts.map +1 -1
  607. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.js +1 -1
  608. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.d.ts +1 -1
  609. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.d.ts.map +1 -1
  610. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.js +2 -2
  611. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.d.ts +1 -1
  612. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.d.ts.map +1 -1
  613. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.js +2 -2
  614. package/src/generation/markers/actions/probability/MarkerNodeActionSelectWeighted.d.ts.map +1 -1
  615. package/src/generation/markers/actions/probability/MarkerNodeActionSelectWeighted.js +6 -4
  616. package/src/generation/markers/actions/probability/MarkerNodeActionWeightedElement.d.ts.map +1 -1
  617. package/src/generation/markers/actions/probability/MarkerNodeActionWeightedElement.js +1 -3
  618. package/src/generation/markers/actions/terrain/MarkerNodeActionPaintTerrain.d.ts.map +1 -1
  619. package/src/generation/markers/actions/terrain/MarkerNodeActionPaintTerrain.js +12 -11
  620. package/src/generation/markers/matcher/MarkerNodeMatcherAnd.js +2 -2
  621. package/src/generation/markers/transform/MarkerNodeTransformer.d.ts +4 -1
  622. package/src/generation/markers/transform/MarkerNodeTransformer.d.ts.map +1 -1
  623. package/src/generation/markers/transform/MarkerNodeTransformer.js +4 -1
  624. package/src/generation/markers/transform/MarkerNodeTransformerAddPositionYFromFilter.d.ts.map +1 -1
  625. package/src/generation/markers/transform/MarkerNodeTransformerAddPositionYFromFilter.js +1 -3
  626. package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.d.ts +5 -0
  627. package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.d.ts.map +1 -1
  628. package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.js +15 -0
  629. package/src/generation/markers/transform/MarkerNodeTransformerRecordProperty.d.ts.map +1 -1
  630. package/src/generation/markers/transform/MarkerNodeTransformerRecordProperty.js +1 -3
  631. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilter.d.ts.map +1 -1
  632. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilter.js +2 -4
  633. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilterGradient.d.ts.map +1 -1
  634. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilterGradient.js +1 -3
  635. package/src/generation/placement/GridCellPlacementRule.d.ts.map +1 -1
  636. package/src/generation/placement/GridCellPlacementRule.js +1 -3
  637. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.d.ts.map +1 -1
  638. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.js +8 -10
  639. package/src/generation/placement/action/random/weighted/CellActionSelectWeightedRandom.d.ts.map +1 -1
  640. package/src/generation/placement/action/random/weighted/CellActionSelectWeightedRandom.js +6 -4
  641. package/src/generation/placement/action/random/weighted/WeightedGridCellAction.d.ts.map +1 -1
  642. package/src/generation/placement/action/random/weighted/WeightedGridCellAction.js +1 -3
  643. package/src/generation/rules/CellMatcher.d.ts +3 -1
  644. package/src/generation/rules/CellMatcher.d.ts.map +1 -1
  645. package/src/generation/rules/CellMatcher.js +3 -1
  646. package/src/generation/rules/CellMatcherFromFilter.d.ts.map +1 -1
  647. package/src/generation/rules/CellMatcherFromFilter.js +1 -3
  648. package/src/generation/rules/CellMatcherLayerBitMaskTest.d.ts.map +1 -1
  649. package/src/generation/rules/CellMatcherLayerBitMaskTest.js +6 -20
  650. package/src/generation/test_support/executeTaskTreeSync.d.ts +9 -0
  651. package/src/generation/test_support/executeTaskTreeSync.d.ts.map +1 -0
  652. package/src/generation/test_support/executeTaskTreeSync.js +78 -0
  653. package/src/generation/theme/TerrainLayerRuleAggregator.d.ts +2 -1
  654. package/src/generation/theme/TerrainLayerRuleAggregator.d.ts.map +1 -1
  655. package/src/generation/theme/TerrainLayerRuleAggregator.js +9 -6
  656. package/src/generation/theme/Theme.d.ts +1 -1
  657. package/src/generation/theme/Theme.d.ts.map +1 -1
  658. package/src/generation/theme/Theme.js +2 -2
  659. package/src/generation/theme/ThemeEngine.d.ts +3 -3
  660. package/src/generation/theme/ThemeEngine.d.ts.map +1 -1
  661. package/src/generation/theme/ThemeEngine.js +26 -16
  662. package/src/generation/theme/cell/CellProcessingRule.d.ts +3 -3
  663. package/src/generation/theme/cell/CellProcessingRule.d.ts.map +1 -1
  664. package/src/generation/theme/cell/CellProcessingRule.js +6 -10
  665. package/src/generation/theme/cell/CellProcessingRuleSet.d.ts +1 -1
  666. package/src/generation/theme/cell/CellProcessingRuleSet.d.ts.map +1 -1
  667. package/src/generation/theme/cell/CellProcessingRuleSet.js +2 -2
  668. package/src/view/common/ListView.js +1 -1
  669. package/src/view/elements/BottomLeftResizeHandleView.d.ts.map +1 -1
  670. package/src/view/elements/BottomLeftResizeHandleView.js +13 -5
  671. package/src/core/font/FontAsset.d.ts.map +0 -1
  672. package/src/core/font/FontAssetLoader.d.ts.map +0 -1
  673. package/src/core/geom/3d/shape/util/shape_to_visual_entity.d.ts.map +0 -1
  674. package/src/core/geom/3d/tetrahedra/visualize_tetrahedral_mesh.d.ts.map +0 -1
  675. package/src/core/process/action/AsynchronousDelayAction.d.ts.map +0 -1
  676. package/src/engine/physics/computeInterceptPoint.d.ts.map +0 -1
  677. package/src/engine/physics/fluid/solver/optimal_sor_omega.d.ts.map +0 -1
  678. package/src/engine/physics/gjk/gjk.d.ts.map +0 -1
  679. package/src/engine/physics/gjk/gjk_epa_penetration.d.ts.map +0 -1
  680. package/src/engine/physics/gjk/minkowski_support.d.ts.map +0 -1
  681. package/src/engine/physics/gjk/mpr.d.ts.map +0 -1
  682. package/src/engine/physics/integration/quat_integrate.d.ts.map +0 -1
  683. package/src/engine/physics/island/union_find.d.ts.map +0 -1
  684. package/src/engine/physics/narrowphase/PosedShape.d.ts.map +0 -1
  685. package/src/engine/physics/narrowphase/clip_against_axis_uv.d.ts.map +0 -1
  686. package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts.map +0 -1
  687. package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.d.ts +0 -21
  688. package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.d.ts.map +0 -1
  689. package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.js +0 -68
  690. package/src/generation/grid/generation/grid/GridTaskGridAlignedNodeGenerator.d.ts +0 -10
  691. package/src/generation/grid/generation/grid/GridTaskGridAlignedNodeGenerator.d.ts.map +0 -1
  692. package/src/generation/grid/generation/grid/GridTaskGridAlignedNodeGenerator.js +0 -17
  693. /package/src/{engine/physics → core/geom/3d}/gjk/NOTES.md +0 -0
  694. /package/src/{engine/physics → core/geom/3d}/gjk/gjk.d.ts +0 -0
  695. /package/src/{engine/physics → core/math/physics/kinematics}/computeInterceptPoint.d.ts +0 -0
@@ -1,422 +1,568 @@
1
- import { v3_array_centroid } from "../../../core/geom/vec3/v3_array_centroid.js";
2
- import { v3_dot } from "../../../core/geom/vec3/v3_dot.js";
3
- import { v3_length } from "../../../core/geom/vec3/v3_length.js";
4
- import { v3_quat3_apply } from "../../../core/geom/vec3/v3_quat3_apply.js";
5
- import { reduce_manifold_contacts } from "./reduce_manifold_contacts.js";
6
-
7
- /**
8
- * Multi-point contact manifold between two convex polytopes with **polygon
9
- * faces**, computed entirely from the current poses no cross-frame state, so
10
- * it preserves reset-and-resimulate (rollback) determinism.
11
- *
12
- * A piece is described by:
13
- * - `vertices` : Float32Array, flat (x,y,z) per vertex, local frame
14
- * - `face_offsets` : Uint32Array length F+1, CSR offsets into `face_loops`
15
- * - `face_loops` : Uint32Array, each face's vertex indices, ordered CCW so
16
- * the face normal (from its first three loop verts) points
17
- * outward.
18
- * A triangle-faced piece (a tetrahedron) is just the special case where every
19
- * face loop has length 3; a merged/box piece has quads or larger polygons.
20
- * Handling polygon faces directly is what lets a flat face produce a full
21
- * face-on-face patch instead of mismatched triangle slivers.
22
- *
23
- * The separating axis comes from SAT (the structure mirrors Bullet's
24
- * `clipHullAgainstHull`, which clips around a `separatingNormal`). A GJK+EPA
25
- * axis source was prototyped Bullet sources the normal from EITHER SAT OR
26
- * `btGjkPairDetector`, the source being orthogonal to the clip but this
27
- * engine's EPA returns a non-minimal, non-scaling axis for polytopes (a 0.05 m
28
- * overlap reports ~0.8 m depth), so clipping around it produces a garbage
29
- * manifold. SAT is exact and, for the low-poly hulls authored as collision
30
- * proxies and the small pieces of a decomposed mesh, cheap. See memory:
31
- * feedback_epa_unreliable_polytopes.
32
- *
33
- * Algorithm (general form of {@link box_box_manifold}):
34
- * 1. SAT over every face normal of A, every face normal of B, and every
35
- * edge(A)×edge(B) cross finds the minimum-translation axis `n` (B→A).
36
- * 2. Face-axis winner ⇒ reference face = the polygon that owns the axis;
37
- * incident face = the polygon on the other piece most antiparallel to the
38
- * reference outward normal. Clip the incident polygon against the reference
39
- * polygon's side planes (3-D Sutherland–Hodgman) and keep penetrating points.
40
- * 3. Edge-axis winner a single deepest support-pair contact.
41
- * 4. Reduce survivors to {@link MAX_CONTACTS} (deepest + spread).
42
- *
43
- * Output layout (matches {@link box_box_manifold}):
44
- * out[0..2] : world normal (B→A)
45
- * out[3] : contact count (0 .. MAX_CONTACTS)
46
- * out[4 + k*7 + 0..2] : world contact on A's surface
47
- * out[4 + k*7 + 3..5] : world contact on B's surface
48
- * out[4 + k*7 + 6] : penetration depth (positive)
49
- *
50
- * @author Alex Goldring
51
- * @copyright Company Named Limited (c) 2026
52
- */
53
-
54
- const MAX_CONTACTS = 4;
55
- const CONTACT_STRIDE = 7;
56
- export const CONVEX_CONVEX_OUT_LENGTH = 4 + MAX_CONTACTS * CONTACT_STRIDE;
57
-
58
- const INITIAL_V = 256; // initial world-vertex scratch capacity (verts per piece/hull)
59
- const MAX_POLY = 64; // polygon verts during clipping
60
-
61
- const TIE_REL = 0.02;
62
- const TIE_ABS = 1e-5;
63
- const PARALLEL_EPS = 1e-9;
64
-
65
- // --- scratch ----------------------------------------------------------------
66
- // World-vertex buffers. `let` + grow-on-demand: a convex MESH routed as a single
67
- // hull (get_mesh_convex_hull) can have far more than the initial capacity of
68
- // surface vertices (a subdivided icosphere is hundreds). Without the grow, the
69
- // excess writes were silently dropped and SAT/clip read NaN past the end,
70
- // computing a truncated (wrong) manifold against part of the hull.
71
- let wvA = new Float64Array(INITIAL_V * 3);
72
- let wvB = new Float64Array(INITIAL_V * 3);
73
- const poly_in = new Float64Array(MAX_POLY * 3);
74
- const poly_out = new Float64Array(MAX_POLY * 3);
75
- const cand = new Float64Array(MAX_POLY * 4);
76
- const cenA = new Float64Array(3);
77
- const cenB = new Float64Array(3);
78
- const tmp_n = new Float64Array(3);
79
-
80
- const sat = { overlap: Infinity, nx: 0, ny: 0, nz: 0, kind: -1, face: -1 };
81
-
82
- // --- per-call geometry refs (single-thread re-entrancy, like the scratch) ---
83
- let g_foA, g_flA, g_foB, g_flB, g_fA, g_fB, g_nA, g_nB;
84
-
85
- function set_geom(A, B) {
86
- g_nA = A.vertices.length / 3; g_nB = B.vertices.length / 3;
87
- g_foA = A.face_offsets; g_flA = A.face_loops; g_fA = g_foA.length - 1;
88
- g_foB = B.face_offsets; g_flB = B.face_loops; g_fB = g_foB.length - 1;
89
- // Grow the world-vertex scratch to fit, so large hulls aren't truncated.
90
- if (wvA.length < g_nA * 3) wvA = new Float64Array(g_nA * 3);
91
- if (wvB.length < g_nB * 3) wvB = new Float64Array(g_nB * 3);
92
- }
93
-
94
- function load_world(out, verts, n, p, q) {
95
- for (let i = 0; i < n; i++) {
96
- v3_quat3_apply(out, i * 3, verts[i * 3], verts[i * 3 + 1], verts[i * 3 + 2], q.x, q.y, q.z, q.w);
97
- out[i * 3] += p.x; out[i * 3 + 1] += p.y; out[i * 3 + 2] += p.z;
98
- }
99
- }
100
-
101
- /**
102
- * Outward normal of a polygon face (Newell's method over the whole loop, world).
103
- * Robust against collinear consecutive vertices, unlike a first-three cross.
104
- */
105
- function face_normal(out, wv, loops, off, end) {
106
- let nx = 0, ny = 0, nz = 0;
107
- for (let i = off; i < end; i++) {
108
- const p = loops[i] * 3, q = loops[i + 1 < end ? i + 1 : off] * 3;
109
- nx += (wv[p + 1] - wv[q + 1]) * (wv[p + 2] + wv[q + 2]);
110
- ny += (wv[p + 2] - wv[q + 2]) * (wv[p] + wv[q]);
111
- nz += (wv[p] - wv[q]) * (wv[p + 1] + wv[q + 1]);
112
- }
113
- out[0] = nx; out[1] = ny; out[2] = nz;
114
- }
115
-
116
- /** SAT axis test; true if the axis SEPARATES the pieces. */
117
- function test_axis(ux, uy, uz, nA, nB, kind, face) {
118
- const len2 = ux * ux + uy * uy + uz * uz;
119
- if (len2 < PARALLEL_EPS) return false;
120
- const inv = 1 / Math.sqrt(len2);
121
- ux *= inv; uy *= inv; uz *= inv;
122
-
123
- let minA = Infinity, maxA = -Infinity;
124
- for (let i = 0; i < nA; i++) {
125
- const d = v3_dot(ux, uy, uz, wvA[i * 3], wvA[i * 3 + 1], wvA[i * 3 + 2]);
126
- if (d < minA) minA = d; if (d > maxA) maxA = d;
127
- }
128
- let minB = Infinity, maxB = -Infinity;
129
- for (let i = 0; i < nB; i++) {
130
- const d = v3_dot(ux, uy, uz, wvB[i * 3], wvB[i * 3 + 1], wvB[i * 3 + 2]);
131
- if (d < minB) minB = d; if (d > maxB) maxB = d;
132
- }
133
- if (maxA < minB || maxB < minA) return true;
134
-
135
- const overlap = Math.min(maxA, maxB) - Math.max(minA, minB);
136
- if (sat.kind === -1 || overlap < sat.overlap - (sat.overlap * TIE_REL + TIE_ABS)) {
137
- sat.overlap = overlap;
138
- const dcx = cenA[0] - cenB[0], dcy = cenA[1] - cenB[1], dcz = cenA[2] - cenB[2];
139
- const sign = v3_dot(ux, uy, uz, dcx, dcy, dcz) >= 0 ? 1 : -1;
140
- sat.nx = ux * sign; sat.ny = uy * sign; sat.nz = uz * sign;
141
- sat.kind = kind; sat.face = face;
142
- }
143
- return false;
144
- }
145
-
146
- /**
147
- * SAT entry point — finds the minimum-translation axis itself, then clips.
148
- * For the SMALL convex pieces of a decomposed mesh.
149
- *
150
- * @param {Float64Array|number[]} out length ≥ CONVEX_CONVEX_OUT_LENGTH
151
- * @param {{vertices:Float32Array, face_offsets:Uint32Array, face_loops:Uint32Array}} A
152
- * @param {{x,y,z}} posA @param {{x,y,z,w}} rotA
153
- * @param {{vertices:Float32Array, face_offsets:Uint32Array, face_loops:Uint32Array}} B
154
- * @param {{x,y,z}} posB @param {{x,y,z,w}} rotB
155
- * @returns {boolean}
156
- */
157
- export function convex_convex_manifold(out, A, posA, rotA, B, posB, rotB) {
158
- set_geom(A, B);
159
-
160
- load_world(wvA, A.vertices, g_nA, posA, rotA);
161
- load_world(wvB, B.vertices, g_nB, posB, rotB);
162
- v3_array_centroid(cenA, 0, wvA, 0, g_nA);
163
- v3_array_centroid(cenB, 0, wvB, 0, g_nB);
164
-
165
- sat.kind = -1; sat.overlap = Infinity;
166
-
167
- // A face normals.
168
- for (let f = 0; f < g_fA; f++) {
169
- face_normal(tmp_n, wvA, g_flA, g_foA[f], g_foA[f + 1]);
170
- if (test_axis(tmp_n[0], tmp_n[1], tmp_n[2], g_nA, g_nB, 0, f)) return false;
171
- }
172
- // B face normals.
173
- for (let f = 0; f < g_fB; f++) {
174
- face_normal(tmp_n, wvB, g_flB, g_foB[f], g_foB[f + 1]);
175
- if (test_axis(tmp_n[0], tmp_n[1], tmp_n[2], g_nA, g_nB, 1, f)) return false;
176
- }
177
- // Edge × edge crosses (face-loop edges; shared edges retest harmlessly).
178
- for (let fa = 0; fa < g_fA; fa++) {
179
- const sa = g_foA[fa], la = g_foA[fa + 1] - sa;
180
- for (let i = 0; i < la; i++) {
181
- const a0 = g_flA[sa + i] * 3, a1 = g_flA[sa + (i + 1) % la] * 3;
182
- const eax = wvA[a1] - wvA[a0], eay = wvA[a1 + 1] - wvA[a0 + 1], eaz = wvA[a1 + 2] - wvA[a0 + 2];
183
- for (let fb = 0; fb < g_fB; fb++) {
184
- const sb = g_foB[fb], lb = g_foB[fb + 1] - sb;
185
- for (let j = 0; j < lb; j++) {
186
- const b0 = g_flB[sb + j] * 3, b1 = g_flB[sb + (j + 1) % lb] * 3;
187
- const ebx = wvB[b1] - wvB[b0], eby = wvB[b1 + 1] - wvB[b0 + 1], ebz = wvB[b1 + 2] - wvB[b0 + 2];
188
- const cx = eay * ebz - eaz * eby, cy = eaz * ebx - eax * ebz, cz = eax * eby - eay * ebx;
189
- if (test_axis(cx, cy, cz, g_nA, g_nB, 2, -1)) return false;
190
- }
191
- }
192
- }
193
- }
194
-
195
- if (sat.kind === -1) return false;
196
-
197
- const nx = sat.nx, ny = sat.ny, nz = sat.nz;
198
- out[0] = nx; out[1] = ny; out[2] = nz;
199
-
200
- // Edge-cross winner: single deepest support-pair contact (v1).
201
- if (sat.kind === 2) {
202
- emit_single_contact(out, nx, ny, nz, sat.overlap);
203
- return true;
204
- }
205
-
206
- // Face winner: reference / incident polygon clipping.
207
- emit_face_manifold(out, sat.kind === 0, sat.face, nx, ny, nz);
208
- return true;
209
- }
210
-
211
- /**
212
- * Clip-only entry point the caller supplies the separating axis `n` (B→A,
213
- * unit) from a robust GJK+EPA query ({@link gjk_epa_penetration}); we only build
214
- * the multi-point manifold. This is Bullet's `clipHullAgainstHull(sepNormal,…)`
215
- * with the normal sourced from GJK rather than SAT. Used for LARGE convex
216
- * polytopes (authored hulls, a convex mesh as one piece) where SAT's O(Fa·Fb +
217
- * Ea·Eb) edge term is prohibitive but GJK+EPA is O(support queries). Always
218
- * emits ≥ 1 contact (the caller already established penetration): if the face
219
- * clip empties (a vertex/edge feature) it falls back to the deepest support-pair.
220
- *
221
- * @param {Float64Array|number[]} out length ≥ CONVEX_CONVEX_OUT_LENGTH
222
- * @param {{vertices,face_offsets,face_loops}} A @param {{x,y,z}} posA @param {{x,y,z,w}} rotA
223
- * @param {{vertices,face_offsets,face_loops}} B @param {{x,y,z}} posB @param {{x,y,z,w}} rotB
224
- * @param {number} nx @param {number} ny @param {number} nz unit axis, B→A
225
- * @returns {boolean} always true
226
- */
227
- export function convex_hull_clip(out, A, posA, rotA, B, posB, rotB, nx, ny, nz) {
228
- set_geom(A, B);
229
- load_world(wvA, A.vertices, g_nA, posA, rotA);
230
- load_world(wvB, B.vertices, g_nB, posB, rotB);
231
-
232
- // Orient the axis B→A using the shapes' GEOMETRIC centres (centroids of the
233
- // world vertices), the same robust reference the SAT path uses. A body-frame
234
- // guard (transform positions) degenerates when the two origins nearly
235
- // coincide e.g. a tet resting base-to-base on another, both transforms at
236
- // the contact plane — leaving the normal mis-oriented and the stack tunnels.
237
- v3_array_centroid(cenA, 0, wvA, 0, g_nA);
238
- v3_array_centroid(cenB, 0, wvB, 0, g_nB);
239
- if (nx * (cenA[0] - cenB[0]) + ny * (cenA[1] - cenB[1]) + nz * (cenA[2] - cenB[2]) < 0) {
240
- nx = -nx; ny = -ny; nz = -nz;
241
- }
242
- out[0] = nx; out[1] = ny; out[2] = nz;
243
-
244
- // Reference face = the face (A or B) whose outward normal is most aligned
245
- // with the axis pointing toward the other body. A's contact face points
246
- // toward B (along −n); B's toward A (along +n). The flatter (better-aligned)
247
- // one is the reference. Mirrors Bullet's "face most opposing the normal",
248
- // made symmetric across A and B.
249
- let bestA = -Infinity, faceA = 0;
250
- for (let f = 0; f < g_fA; f++) {
251
- face_normal(tmp_n, wvA, g_flA, g_foA[f], g_foA[f + 1]);
252
- const l = v3_length(tmp_n[0], tmp_n[1], tmp_n[2]) || 1;
253
- const d = v3_dot(tmp_n[0], tmp_n[1], tmp_n[2], -nx, -ny, -nz) / l;
254
- if (d > bestA) { bestA = d; faceA = f; }
255
- }
256
- let bestB = -Infinity, faceB = 0;
257
- for (let f = 0; f < g_fB; f++) {
258
- face_normal(tmp_n, wvB, g_flB, g_foB[f], g_foB[f + 1]);
259
- const l = v3_length(tmp_n[0], tmp_n[1], tmp_n[2]) || 1;
260
- const d = v3_dot(tmp_n[0], tmp_n[1], tmp_n[2], nx, ny, nz) / l;
261
- if (d > bestB) { bestB = d; faceB = f; }
262
- }
263
-
264
- const ref_is_A = bestA >= bestB;
265
- emit_face_manifold(out, ref_is_A, ref_is_A ? faceA : faceB, nx, ny, nz);
266
-
267
- if ((out[3] | 0) === 0) {
268
- const overlap = projection_overlap(nx, ny, nz);
269
- emit_single_contact(out, nx, ny, nz, overlap > 0 ? overlap : 0);
270
- }
271
- return true;
272
- }
273
-
274
- /** Overlap of the two pieces' projections onto axis `n` (B→A); A is on the +n side. */
275
- function projection_overlap(nx, ny, nz) {
276
- let minA = Infinity, maxB = -Infinity;
277
- for (let i = 0; i < g_nA; i++) {
278
- const d = v3_dot(nx, ny, nz, wvA[i * 3], wvA[i * 3 + 1], wvA[i * 3 + 2]);
279
- if (d < minA) minA = d;
280
- }
281
- for (let i = 0; i < g_nB; i++) {
282
- const d = v3_dot(nx, ny, nz, wvB[i * 3], wvB[i * 3 + 1], wvB[i * 3 + 2]);
283
- if (d > maxB) maxB = d;
284
- }
285
- return maxB - minA;
286
- }
287
-
288
- /** Single deepest support-pair contact along axis `n` (B→A). */
289
- function emit_single_contact(out, nx, ny, nz, depth) {
290
- let sa = -Infinity, ai = 0;
291
- for (let i = 0; i < g_nA; i++) {
292
- const d = -v3_dot(nx, ny, nz, wvA[i * 3], wvA[i * 3 + 1], wvA[i * 3 + 2]);
293
- if (d > sa) { sa = d; ai = i; }
294
- }
295
- let sb = -Infinity, bi = 0;
296
- for (let i = 0; i < g_nB; i++) {
297
- const d = v3_dot(nx, ny, nz, wvB[i * 3], wvB[i * 3 + 1], wvB[i * 3 + 2]);
298
- if (d > sb) { sb = d; bi = i; }
299
- }
300
- out[3] = 1;
301
- out[4] = wvA[ai * 3]; out[5] = wvA[ai * 3 + 1]; out[6] = wvA[ai * 3 + 2];
302
- out[7] = wvB[bi * 3]; out[8] = wvB[bi * 3 + 1]; out[9] = wvB[bi * 3 + 2];
303
- out[10] = depth;
304
- }
305
-
306
- /**
307
- * Reference/incident polygon clipping given the reference face. Writes the
308
- * manifold (count + contacts) into `out`; leaves out[0..2] (the normal) as set
309
- * by the caller. Shared by both the SAT and GJK+EPA entry points.
310
- *
311
- * @param {boolean} ref_is_A reference face belongs to A (else B)
312
- * @param {number} ref_face reference face index within its piece
313
- * @param {number} nx @param {number} ny @param {number} nz axis (B→A), unit
314
- */
315
- function emit_face_manifold(out, ref_is_A, ref_face, nx, ny, nz) {
316
- const ref_wv = ref_is_A ? wvA : wvB;
317
- const ref_fo = ref_is_A ? g_foA : g_foB;
318
- const ref_fl = ref_is_A ? g_flA : g_flB;
319
- const inc_wv = ref_is_A ? wvB : wvA;
320
- const inc_fo = ref_is_A ? g_foB : g_foA;
321
- const inc_fl = ref_is_A ? g_flB : g_flA;
322
- const inc_fcount = ref_is_A ? g_fB : g_fA;
323
-
324
- // Reference outward normal points ref → incident: −n if ref is A, +n if ref is B.
325
- const rmx = ref_is_A ? -nx : nx, rmy = ref_is_A ? -ny : ny, rmz = ref_is_A ? -nz : nz;
326
-
327
- const ref_s = ref_fo[ref_face], ref_len = ref_fo[ref_face + 1] - ref_s;
328
- const r0 = ref_fl[ref_s] * 3;
329
- const r0x = ref_wv[r0], r0y = ref_wv[r0 + 1], r0z = ref_wv[r0 + 2];
330
-
331
- // Incident face = the polygon on the other piece most antiparallel to rm.
332
- let inc_face = 0, most_anti = Infinity;
333
- for (let f = 0; f < inc_fcount; f++) {
334
- face_normal(tmp_n, inc_wv, inc_fl, inc_fo[f], inc_fo[f + 1]);
335
- const l = v3_length(tmp_n[0], tmp_n[1], tmp_n[2]) || 1;
336
- const dot = v3_dot(tmp_n[0], tmp_n[1], tmp_n[2], rmx, rmy, rmz) / l;
337
- if (dot < most_anti) { most_anti = dot; inc_face = f; }
338
- }
339
-
340
- // Incident polygon (world).
341
- const inc_s = inc_fo[inc_face], inc_len = inc_fo[inc_face + 1] - inc_s;
342
- let n_poly = inc_len;
343
- for (let i = 0; i < inc_len; i++) {
344
- const vi = inc_fl[inc_s + i] * 3;
345
- poly_in[i * 3] = inc_wv[vi]; poly_in[i * 3 + 1] = inc_wv[vi + 1]; poly_in[i * 3 + 2] = inc_wv[vi + 2];
346
- }
347
-
348
- // Reference polygon centroid (orients side planes inward).
349
- let rcx = 0, rcy = 0, rcz = 0;
350
- for (let i = 0; i < ref_len; i++) {
351
- const vi = ref_fl[ref_s + i] * 3;
352
- rcx += ref_wv[vi]; rcy += ref_wv[vi + 1]; rcz += ref_wv[vi + 2];
353
- }
354
- rcx /= ref_len; rcy /= ref_len; rcz /= ref_len;
355
-
356
- // Clip the incident polygon against each reference-face side plane.
357
- let src = poly_in, dst = poly_out;
358
- for (let e = 0; e < ref_len && n_poly > 0; e++) {
359
- const va = ref_fl[ref_s + e] * 3, vb = ref_fl[ref_s + (e + 1) % ref_len] * 3;
360
- const edx = ref_wv[vb] - ref_wv[va], edy = ref_wv[vb + 1] - ref_wv[va + 1], edz = ref_wv[vb + 2] - ref_wv[va + 2];
361
- let sx = edy * rmz - edz * rmy, sy = edz * rmx - edx * rmz, sz = edx * rmy - edy * rmx;
362
- const pax = ref_wv[va], pay = ref_wv[va + 1], paz = ref_wv[va + 2];
363
- if ((rcx - pax) * sx + (rcy - pay) * sy + (rcz - paz) * sz > 0) { sx = -sx; sy = -sy; sz = -sz; }
364
- n_poly = clip_poly(src, n_poly, dst, sx, sy, sz, pax, pay, paz);
365
- const t = src; src = dst; dst = t;
366
- }
367
- if (n_poly === 0) { out[3] = 0; return; }
368
-
369
- let nc = 0;
370
- for (let i = 0; i < n_poly; i++) {
371
- const px = src[i * 3], py = src[i * 3 + 1], pz = src[i * 3 + 2];
372
- const sep = (px - r0x) * rmx + (py - r0y) * rmy + (pz - r0z) * rmz;
373
- const depth = -sep;
374
- if (depth < 0) continue;
375
- cand[nc * 4] = px; cand[nc * 4 + 1] = py; cand[nc * 4 + 2] = pz; cand[nc * 4 + 3] = depth;
376
- nc++;
377
- }
378
- if (nc === 0) { out[3] = 0; return; }
379
-
380
- const kept = reduce_manifold_contacts(cand, nc, 4, MAX_CONTACTS);
381
- out[3] = kept;
382
- for (let k = 0; k < kept; k++) {
383
- const px = cand[k * 4], py = cand[k * 4 + 1], pz = cand[k * 4 + 2], depth = cand[k * 4 + 3];
384
- const d2p = (px - r0x) * rmx + (py - r0y) * rmy + (pz - r0z) * rmz;
385
- const rpx = px - rmx * d2p, rpy = py - rmy * d2p, rpz = pz - rmz * d2p;
386
- const base = 4 + k * CONTACT_STRIDE;
387
- if (ref_is_A) {
388
- out[base] = rpx; out[base + 1] = rpy; out[base + 2] = rpz;
389
- out[base + 3] = px; out[base + 4] = py; out[base + 5] = pz;
390
- } else {
391
- out[base] = px; out[base + 1] = py; out[base + 2] = pz;
392
- out[base + 3] = rpx; out[base + 4] = rpy; out[base + 5] = rpz;
393
- }
394
- out[base + 6] = depth;
395
- }
396
- }
397
-
398
- /** Sutherland–Hodgman: keep polygon points where (P − a)·s ≤ 0, with crossings. */
399
- function clip_poly(src, n, dst, sx, sy, sz, ax, ay, az) {
400
- let m = 0;
401
- for (let i = 0; i < n; i++) {
402
- const j = (i + 1) % n;
403
- const px = src[i * 3], py = src[i * 3 + 1], pz = src[i * 3 + 2];
404
- const qx = src[j * 3], qy = src[j * 3 + 1], qz = src[j * 3 + 2];
405
- const dp = v3_dot(px - ax, py - ay, pz - az, sx, sy, sz);
406
- const dq = v3_dot(qx - ax, qy - ay, qz - az, sx, sy, sz);
407
- const p_in = dp <= 0, q_in = dq <= 0;
408
- if (p_in) { dst[m * 3] = px; dst[m * 3 + 1] = py; dst[m * 3 + 2] = pz; m++; }
409
- if (p_in !== q_in) {
410
- const t = dp / (dp - dq);
411
- dst[m * 3] = px + (qx - px) * t;
412
- dst[m * 3 + 1] = py + (qy - py) * t;
413
- dst[m * 3 + 2] = pz + (qz - pz) * t;
414
- m++;
415
- if (m >= MAX_POLY) break;
416
- }
417
- }
418
- return m;
419
- }
420
-
421
- // Contact reduction (deepest + farthest-point spread) is shared with
422
- // box_box_manifold via reduce_manifold_contacts (stride 4).
1
+ import { line3_closest_points_segment_segment } from "../../../core/geom/3d/line/line3_closest_points_segment_segment.js";
2
+ import { v3_array_centroid } from "../../../core/geom/vec3/v3_array_centroid.js";
3
+ import { v3_dot } from "../../../core/geom/vec3/v3_dot.js";
4
+ import { v3_length } from "../../../core/geom/vec3/v3_length.js";
5
+ import { v3_quat3_apply } from "../../../core/geom/vec3/v3_quat3_apply.js";
6
+ import { reduce_manifold_contacts } from "./reduce_manifold_contacts.js";
7
+
8
+ /**
9
+ * Multi-point contact manifold between two convex polytopes with **polygon
10
+ * faces**, computed entirely from the current poses — no cross-frame state, so
11
+ * it preserves reset-and-resimulate (rollback) determinism.
12
+ *
13
+ * A piece is described by:
14
+ * - `vertices` : Float32Array, flat (x,y,z) per vertex, local frame
15
+ * - `face_offsets` : Uint32Array length F+1, CSR offsets into `face_loops`
16
+ * - `face_loops` : Uint32Array, each face's vertex indices, ordered CCW so
17
+ * the face normal (from its first three loop verts) points
18
+ * outward.
19
+ * A triangle-faced piece (a tetrahedron) is just the special case where every
20
+ * face loop has length 3; a merged/box piece has quads or larger polygons.
21
+ * Handling polygon faces directly is what lets a flat face produce a full
22
+ * face-on-face patch instead of mismatched triangle slivers.
23
+ *
24
+ * The separating axis comes from SAT (the structure mirrors Bullet's
25
+ * `clipHullAgainstHull`, which clips around a `separatingNormal`). A GJK+EPA
26
+ * axis source was prototyped Bullet sources the normal from EITHER SAT OR
27
+ * `btGjkPairDetector`, the source being orthogonal to the clip but this
28
+ * engine's EPA returns a non-minimal, non-scaling axis for polytopes (a 0.05 m
29
+ * overlap reports ~0.8 m depth), so clipping around it produces a garbage
30
+ * manifold. SAT is exact and, for the low-poly hulls authored as collision
31
+ * proxies and the small pieces of a decomposed mesh, cheap. See memory:
32
+ * feedback_epa_unreliable_polytopes.
33
+ *
34
+ * Algorithm (general form of {@link box_box_manifold}):
35
+ * 1. SAT over every face normal of A, every face normal of B, and every
36
+ * edge(A)×edge(B) cross finds the minimum-translation axis `n` (B→A).
37
+ * 2. Face-axis winner ⇒ reference face = the polygon that owns the axis;
38
+ * incident face = the polygon on the other piece most antiparallel to the
39
+ * reference outward normal. Clip the incident polygon against the reference
40
+ * polygon's side planes (3-D Sutherland–Hodgman) and keep penetrating points.
41
+ * 3. Edge-axis winner a single deepest support-pair contact.
42
+ * 4. Reduce survivors to ≤ {@link MAX_CONTACTS} (deepest + spread).
43
+ *
44
+ * Output layout (matches {@link box_box_manifold}):
45
+ * out[0..2] : world normal (B→A)
46
+ * out[3] : contact count (0 .. MAX_CONTACTS)
47
+ * out[4 + k*7 + 0..2] : world contact on A's surface
48
+ * out[4 + k*7 + 3..5] : world contact on B's surface
49
+ * out[4 + k*7 + 6] : penetration depth (positive)
50
+ *
51
+ * @author Alex Goldring
52
+ * @copyright Company Named Limited (c) 2026
53
+ */
54
+
55
+ const MAX_CONTACTS = 4;
56
+ const CONTACT_STRIDE = 7;
57
+ export const CONVEX_CONVEX_OUT_LENGTH = 4 + MAX_CONTACTS * CONTACT_STRIDE;
58
+
59
+ const INITIAL_V = 256; // initial world-vertex scratch capacity (verts per piece/hull)
60
+ const MAX_POLY = 64; // polygon verts during clipping
61
+
62
+ const TIE_REL = 0.02;
63
+ const TIE_ABS = 1e-5;
64
+ const PARALLEL_EPS = 1e-9;
65
+
66
+ // --- scratch ----------------------------------------------------------------
67
+ // World-vertex buffers. `let` + grow-on-demand: a convex MESH routed as a single
68
+ // hull (get_mesh_convex_hull) can have far more than the initial capacity of
69
+ // surface vertices (a subdivided icosphere is hundreds). Without the grow, the
70
+ // excess writes were silently dropped and SAT/clip read NaN past the end,
71
+ // computing a truncated (wrong) manifold against part of the hull.
72
+ let wvA = new Float64Array(INITIAL_V * 3);
73
+ let wvB = new Float64Array(INITIAL_V * 3);
74
+ // Clipping scratch `let` + grow-on-demand like wvA/wvB: a coplanar-merged
75
+ // face (e.g. a tessellated cylinder cap routed through get_mesh_convex_hull)
76
+ // can be wider than MAX_POLY, and each side-plane clip can add one more
77
+ // vertex. emit_face_manifold sizes these to inc_len + ref_len before use.
78
+ let poly_in = new Float64Array(MAX_POLY * 3);
79
+ let poly_out = new Float64Array(MAX_POLY * 3);
80
+ let cand = new Float64Array(MAX_POLY * 4);
81
+ const cenA = new Float64Array(3);
82
+ const cenB = new Float64Array(3);
83
+ const tmp_n = new Float64Array(3);
84
+
85
+ const sat = { overlap: Infinity, nx: 0, ny: 0, nz: 0, kind: -1, face: -1 };
86
+
87
+ // --- per-call geometry refs (single-thread re-entrancy, like the scratch) ---
88
+ let g_foA, g_flA, g_foB, g_flB, g_fA, g_fB, g_nA, g_nB;
89
+
90
+ function set_geom(A, B) {
91
+ g_nA = A.vertices.length / 3; g_nB = B.vertices.length / 3;
92
+ g_foA = A.face_offsets; g_flA = A.face_loops; g_fA = g_foA.length - 1;
93
+ g_foB = B.face_offsets; g_flB = B.face_loops; g_fB = g_foB.length - 1;
94
+ // Grow the world-vertex scratch to fit, so large hulls aren't truncated.
95
+ if (wvA.length < g_nA * 3) wvA = new Float64Array(g_nA * 3);
96
+ if (wvB.length < g_nB * 3) wvB = new Float64Array(g_nB * 3);
97
+ }
98
+
99
+ function load_world(out, verts, n, p, q) {
100
+ for (let i = 0; i < n; i++) {
101
+ v3_quat3_apply(out, i * 3, verts[i * 3], verts[i * 3 + 1], verts[i * 3 + 2], q.x, q.y, q.z, q.w);
102
+ out[i * 3] += p.x; out[i * 3 + 1] += p.y; out[i * 3 + 2] += p.z;
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Outward normal of a polygon face (Newell's method over the whole loop, world).
108
+ * Robust against collinear consecutive vertices, unlike a first-three cross.
109
+ */
110
+ function face_normal(out, wv, loops, off, end) {
111
+ let nx = 0, ny = 0, nz = 0;
112
+ for (let i = off; i < end; i++) {
113
+ const p = loops[i] * 3, q = loops[i + 1 < end ? i + 1 : off] * 3;
114
+ nx += (wv[p + 1] - wv[q + 1]) * (wv[p + 2] + wv[q + 2]);
115
+ ny += (wv[p + 2] - wv[q + 2]) * (wv[p] + wv[q]);
116
+ nz += (wv[p] - wv[q]) * (wv[p + 1] + wv[q + 1]);
117
+ }
118
+ out[0] = nx; out[1] = ny; out[2] = nz;
119
+ }
120
+
121
+ /**
122
+ * Unique edges of a hull piece as vertex-index pairs `(v0, v1)`, flat in a
123
+ * Uint32Array, cached on the (immutable) piece as `__sat_edges` — built on
124
+ * first use, like `get_mesh_convex_hull`'s cache (D4).
125
+ *
126
+ * The SAT edge×edge loop used to enumerate every FACE-LOOP edge of A
127
+ * against every face-loop edge of B; an interior edge of a closed hull
128
+ * borders exactly two faces, so each unique edge pair was tested up to 4×,
129
+ * each test paying a full O(nA + nB) interval projection. Deduplication
130
+ * cuts the dominant quartic term ~4×.
131
+ *
132
+ * Order and orientation are FIRST-OCCURRENCE (the face-loop scan order):
133
+ * the sequence of first tests per unique pair — which is what resolves
134
+ * near-tie axes under the deadband — is exactly the sequence the full scan
135
+ * produced, and the duplicate tests in between were no-ops (an identical
136
+ * axis can never beat itself past the hysteresis band; a reversed-edge
137
+ * duplicate only flips the axis sign, which the centroid-keyed sign
138
+ * canonicalisation in test_axis erases). Results are bit-identical.
139
+ *
140
+ * @param {{face_offsets: Uint32Array, face_loops: Uint32Array, __sat_edges: (Uint32Array|undefined)}} shape
141
+ * @returns {Uint32Array}
142
+ */
143
+ function get_sat_edges(shape) {
144
+ let edges = shape.__sat_edges;
145
+ if (edges !== undefined) return edges;
146
+
147
+ const fo = shape.face_offsets;
148
+ const fl = shape.face_loops;
149
+ const nf = fo.length - 1;
150
+ const seen = new Set();
151
+ const list = [];
152
+ for (let f = 0; f < nf; f++) {
153
+ const s = fo[f];
154
+ const l = fo[f + 1] - s;
155
+ for (let i = 0; i < l; i++) {
156
+ const v0 = fl[s + i];
157
+ const v1 = fl[s + (i + 1) % l];
158
+ // Canonical undirected key; hull vertex indices stay far below
159
+ // 2^26, so min·2^26 + max is exact in a double.
160
+ const key = v0 < v1 ? v0 * 67108864 + v1 : v1 * 67108864 + v0;
161
+ if (seen.has(key)) continue;
162
+ seen.add(key);
163
+ list.push(v0, v1);
164
+ }
165
+ }
166
+ edges = Uint32Array.from(list);
167
+ shape.__sat_edges = edges;
168
+ return edges;
169
+ }
170
+
171
+ /** SAT axis test; true if the axis SEPARATES the pieces. */
172
+ function test_axis(ux, uy, uz, nA, nB, kind, face) {
173
+ const len2 = ux * ux + uy * uy + uz * uz;
174
+ if (len2 < PARALLEL_EPS) return false;
175
+ const inv = 1 / Math.sqrt(len2);
176
+ ux *= inv; uy *= inv; uz *= inv;
177
+
178
+ let minA = Infinity, maxA = -Infinity;
179
+ for (let i = 0; i < nA; i++) {
180
+ const d = v3_dot(ux, uy, uz, wvA[i * 3], wvA[i * 3 + 1], wvA[i * 3 + 2]);
181
+ if (d < minA) minA = d; if (d > maxA) maxA = d;
182
+ }
183
+ let minB = Infinity, maxB = -Infinity;
184
+ for (let i = 0; i < nB; i++) {
185
+ const d = v3_dot(ux, uy, uz, wvB[i * 3], wvB[i * 3 + 1], wvB[i * 3 + 2]);
186
+ if (d < minB) minB = d; if (d > maxB) maxB = d;
187
+ }
188
+ if (maxA < minB || maxB < minA) return true;
189
+
190
+ const overlap = Math.min(maxA, maxB) - Math.max(minA, minB);
191
+ if (sat.kind === -1 || overlap < sat.overlap - (sat.overlap * TIE_REL + TIE_ABS)) {
192
+ sat.overlap = overlap;
193
+ const dcx = cenA[0] - cenB[0], dcy = cenA[1] - cenB[1], dcz = cenA[2] - cenB[2];
194
+ const sign = v3_dot(ux, uy, uz, dcx, dcy, dcz) >= 0 ? 1 : -1;
195
+ sat.nx = ux * sign; sat.ny = uy * sign; sat.nz = uz * sign;
196
+ sat.kind = kind; sat.face = face;
197
+ }
198
+ return false;
199
+ }
200
+
201
+ /**
202
+ * SAT entry point — finds the minimum-translation axis itself, then clips.
203
+ * For the SMALL convex pieces of a decomposed mesh.
204
+ *
205
+ * @param {Float64Array|number[]} out length ≥ CONVEX_CONVEX_OUT_LENGTH
206
+ * @param {{vertices:Float32Array, face_offsets:Uint32Array, face_loops:Uint32Array}} A
207
+ * @param {{x,y,z}} posA @param {{x,y,z,w}} rotA
208
+ * @param {{vertices:Float32Array, face_offsets:Uint32Array, face_loops:Uint32Array}} B
209
+ * @param {{x,y,z}} posB @param {{x,y,z,w}} rotB
210
+ * @returns {boolean}
211
+ */
212
+ export function convex_convex_manifold(out, A, posA, rotA, B, posB, rotB) {
213
+ set_geom(A, B);
214
+
215
+ load_world(wvA, A.vertices, g_nA, posA, rotA);
216
+ load_world(wvB, B.vertices, g_nB, posB, rotB);
217
+ v3_array_centroid(cenA, 0, wvA, 0, g_nA);
218
+ v3_array_centroid(cenB, 0, wvB, 0, g_nB);
219
+
220
+ sat.kind = -1; sat.overlap = Infinity;
221
+
222
+ // A face normals.
223
+ for (let f = 0; f < g_fA; f++) {
224
+ face_normal(tmp_n, wvA, g_flA, g_foA[f], g_foA[f + 1]);
225
+ if (test_axis(tmp_n[0], tmp_n[1], tmp_n[2], g_nA, g_nB, 0, f)) return false;
226
+ }
227
+ // B face normals.
228
+ for (let f = 0; f < g_fB; f++) {
229
+ face_normal(tmp_n, wvB, g_flB, g_foB[f], g_foB[f + 1]);
230
+ if (test_axis(tmp_n[0], tmp_n[1], tmp_n[2], g_nA, g_nB, 1, f)) return false;
231
+ }
232
+ // Edge × edge crosses, over each hull's UNIQUE edges (cached per shape —
233
+ // see get_sat_edges; the face-loop scan retested every interior edge pair
234
+ // up to 4×, each paying a full interval projection).
235
+ const edgesA = get_sat_edges(A);
236
+ const edgesB = get_sat_edges(B);
237
+ const neA = edgesA.length;
238
+ const neB = edgesB.length;
239
+ for (let ia = 0; ia < neA; ia += 2) {
240
+ const a0 = edgesA[ia] * 3, a1 = edgesA[ia + 1] * 3;
241
+ const eax = wvA[a1] - wvA[a0], eay = wvA[a1 + 1] - wvA[a0 + 1], eaz = wvA[a1 + 2] - wvA[a0 + 2];
242
+ for (let ib = 0; ib < neB; ib += 2) {
243
+ const b0 = edgesB[ib] * 3, b1 = edgesB[ib + 1] * 3;
244
+ const ebx = wvB[b1] - wvB[b0], eby = wvB[b1 + 1] - wvB[b0 + 1], ebz = wvB[b1 + 2] - wvB[b0 + 2];
245
+ const cx = eay * ebz - eaz * eby, cy = eaz * ebx - eax * ebz, cz = eax * eby - eay * ebx;
246
+ if (test_axis(cx, cy, cz, g_nA, g_nB, 2, -1)) return false;
247
+ }
248
+ }
249
+
250
+ if (sat.kind === -1) return false;
251
+
252
+ const nx = sat.nx, ny = sat.ny, nz = sat.nz;
253
+ out[0] = nx; out[1] = ny; out[2] = nz;
254
+
255
+ // Edge-cross winner: single contact at the winning edges' closest points.
256
+ if (sat.kind === 2) {
257
+ emit_edge_pair_contact(out, nx, ny, nz, sat.overlap);
258
+ return true;
259
+ }
260
+
261
+ // Face winner: reference / incident polygon clipping.
262
+ emit_face_manifold(out, sat.kind === 0, sat.face, nx, ny, nz);
263
+ return true;
264
+ }
265
+
266
+ /**
267
+ * Clip-only entry point the caller supplies the separating axis `n` (B→A,
268
+ * unit) from a robust GJK+EPA query ({@link gjk_epa_penetration}); we only build
269
+ * the multi-point manifold. This is Bullet's `clipHullAgainstHull(sepNormal,…)`
270
+ * with the normal sourced from GJK rather than SAT. Used for LARGE convex
271
+ * polytopes (authored hulls, a convex mesh as one piece) where SAT's O(Fa·Fb +
272
+ * Ea·Eb) edge term is prohibitive but GJK+EPA is O(support queries). Always
273
+ * emits ≥ 1 contact (the caller already established penetration): if the face
274
+ * clip empties (a vertex/edge feature) it falls back to the deepest support-pair.
275
+ *
276
+ * @param {Float64Array|number[]} out length ≥ CONVEX_CONVEX_OUT_LENGTH
277
+ * @param {{vertices,face_offsets,face_loops}} A @param {{x,y,z}} posA @param {{x,y,z,w}} rotA
278
+ * @param {{vertices,face_offsets,face_loops}} B @param {{x,y,z}} posB @param {{x,y,z,w}} rotB
279
+ * @param {number} nx @param {number} ny @param {number} nz unit axis as
280
+ * returned by {@link gjk_epa_penetration} (A→B); this function re-orients it
281
+ * against the geometric centres before use, so either sign convention works
282
+ * @returns {boolean} always true
283
+ */
284
+ export function convex_hull_clip(out, A, posA, rotA, B, posB, rotB, nx, ny, nz) {
285
+ set_geom(A, B);
286
+ load_world(wvA, A.vertices, g_nA, posA, rotA);
287
+ load_world(wvB, B.vertices, g_nB, posB, rotB);
288
+
289
+ // Orient the axis B→A using the shapes' GEOMETRIC centres (centroids of the
290
+ // world vertices), the same robust reference the SAT path uses. A body-frame
291
+ // guard (transform positions) degenerates when the two origins nearly
292
+ // coincide e.g. a tet resting base-to-base on another, both transforms at
293
+ // the contact plane leaving the normal mis-oriented and the stack tunnels.
294
+ v3_array_centroid(cenA, 0, wvA, 0, g_nA);
295
+ v3_array_centroid(cenB, 0, wvB, 0, g_nB);
296
+ if (nx * (cenA[0] - cenB[0]) + ny * (cenA[1] - cenB[1]) + nz * (cenA[2] - cenB[2]) < 0) {
297
+ nx = -nx; ny = -ny; nz = -nz;
298
+ }
299
+ out[0] = nx; out[1] = ny; out[2] = nz;
300
+
301
+ // Reference face = the face (A or B) whose outward normal is most aligned
302
+ // with the axis pointing toward the other body. A's contact face points
303
+ // toward B (along −n); B's toward A (along +n). The flatter (better-aligned)
304
+ // one is the reference. Mirrors Bullet's "face most opposing the normal",
305
+ // made symmetric across A and B.
306
+ let bestA = -Infinity, faceA = 0;
307
+ for (let f = 0; f < g_fA; f++) {
308
+ face_normal(tmp_n, wvA, g_flA, g_foA[f], g_foA[f + 1]);
309
+ const l = v3_length(tmp_n[0], tmp_n[1], tmp_n[2]) || 1;
310
+ const d = v3_dot(tmp_n[0], tmp_n[1], tmp_n[2], -nx, -ny, -nz) / l;
311
+ if (d > bestA) { bestA = d; faceA = f; }
312
+ }
313
+ let bestB = -Infinity, faceB = 0;
314
+ for (let f = 0; f < g_fB; f++) {
315
+ face_normal(tmp_n, wvB, g_flB, g_foB[f], g_foB[f + 1]);
316
+ const l = v3_length(tmp_n[0], tmp_n[1], tmp_n[2]) || 1;
317
+ const d = v3_dot(tmp_n[0], tmp_n[1], tmp_n[2], nx, ny, nz) / l;
318
+ if (d > bestB) { bestB = d; faceB = f; }
319
+ }
320
+
321
+ const ref_is_A = bestA >= bestB;
322
+ emit_face_manifold(out, ref_is_A, ref_is_A ? faceA : faceB, nx, ny, nz);
323
+
324
+ if ((out[3] | 0) === 0) {
325
+ const overlap = projection_overlap(nx, ny, nz);
326
+ emit_single_contact(out, nx, ny, nz, overlap > 0 ? overlap : 0);
327
+ }
328
+ return true;
329
+ }
330
+
331
+ /** Overlap of the two pieces' projections onto axis `n` (B→A); A is on the +n side. */
332
+ function projection_overlap(nx, ny, nz) {
333
+ let minA = Infinity, maxB = -Infinity;
334
+ for (let i = 0; i < g_nA; i++) {
335
+ const d = v3_dot(nx, ny, nz, wvA[i * 3], wvA[i * 3 + 1], wvA[i * 3 + 2]);
336
+ if (d < minA) minA = d;
337
+ }
338
+ for (let i = 0; i < g_nB; i++) {
339
+ const d = v3_dot(nx, ny, nz, wvB[i * 3], wvB[i * 3 + 1], wvB[i * 3 + 2]);
340
+ if (d > maxB) maxB = d;
341
+ }
342
+ return maxB - minA;
343
+ }
344
+
345
+ /** Single deepest support-pair contact along axis `n` (B→A). */
346
+ function emit_single_contact(out, nx, ny, nz, depth) {
347
+ let sa = -Infinity, ai = 0;
348
+ for (let i = 0; i < g_nA; i++) {
349
+ const d = -v3_dot(nx, ny, nz, wvA[i * 3], wvA[i * 3 + 1], wvA[i * 3 + 2]);
350
+ if (d > sa) { sa = d; ai = i; }
351
+ }
352
+ let sb = -Infinity, bi = 0;
353
+ for (let i = 0; i < g_nB; i++) {
354
+ const d = v3_dot(nx, ny, nz, wvB[i * 3], wvB[i * 3 + 1], wvB[i * 3 + 2]);
355
+ if (d > sb) { sb = d; bi = i; }
356
+ }
357
+ out[3] = 1;
358
+ out[4] = wvA[ai * 3]; out[5] = wvA[ai * 3 + 1]; out[6] = wvA[ai * 3 + 2];
359
+ out[7] = wvB[bi * 3]; out[8] = wvB[bi * 3 + 1]; out[9] = wvB[bi * 3 + 2];
360
+ out[10] = depth;
361
+ }
362
+
363
+ const scratch_st = new Float64Array(2);
364
+ const scratch_edge = new Int32Array(4); // [a0, a1] then [b0, b1] vertex indices
365
+
366
+ /**
367
+ * Find a piece's SUPPORTING EDGE along direction d: the face-loop edge that
368
+ * maximises the SMALLER of its two endpoint projections. For an edge-cross
369
+ * SAT winner the true contact edge lies perpendicular to the axis, so both
370
+ * its endpoints project to the common maximum and its min-endpoint
371
+ * projection beats every other edge's. (Recording the SAT loop's winning
372
+ * pair instead does NOT work: parallel edge pairs alias one axis with equal
373
+ * overlap, and the first-tested pair is usually not the touching one.)
374
+ *
375
+ * @param {Float64Array} wv world vertices
376
+ * @param {Uint32Array} fo face offsets
377
+ * @param {Uint32Array} fl face loops
378
+ * @param {number} fcount face count
379
+ * @param {number} dx @param {number} dy @param {number} dz
380
+ * @param {Int32Array} out_pair 2 slots written at `pair_off`
381
+ * @param {number} pair_off
382
+ */
383
+ function find_support_edge(wv, fo, fl, fcount, dx, dy, dz, out_pair, pair_off) {
384
+ let best = -Infinity;
385
+ for (let f = 0; f < fcount; f++) {
386
+ const start = fo[f], len = fo[f + 1] - start;
387
+ for (let i = 0; i < len; i++) {
388
+ const v0 = fl[start + i] * 3;
389
+ const v1 = fl[start + (i + 1) % len] * 3;
390
+ const d0 = wv[v0] * dx + wv[v0 + 1] * dy + wv[v0 + 2] * dz;
391
+ const d1 = wv[v1] * dx + wv[v1 + 1] * dy + wv[v1 + 2] * dz;
392
+ const m = d0 < d1 ? d0 : d1;
393
+ if (m > best) {
394
+ best = m;
395
+ out_pair[pair_off] = v0;
396
+ out_pair[pair_off + 1] = v1;
397
+ }
398
+ }
399
+ }
400
+ }
401
+
402
+ /**
403
+ * Single contact for an edge-cross SAT winner, at the CLOSEST POINTS of the
404
+ * two supporting edges. A support-VERTEX pick is ambiguous here: every point
405
+ * of the contact edge projects identically onto the cross axis, so the
406
+ * argmax lands on an arbitrary endpoint and hands the solver a lever arm up
407
+ * to half an edge length off - resting boxes twist.
408
+ */
409
+ function emit_edge_pair_contact(out, nx, ny, nz, depth) {
410
+ // A's supporting edge faces the contact (toward B): extreme along -n;
411
+ // B's faces A: extreme along +n. (n is B -> A.)
412
+ find_support_edge(wvA, g_foA, g_flA, g_fA, -nx, -ny, -nz, scratch_edge, 0);
413
+ find_support_edge(wvB, g_foB, g_flB, g_fB, nx, ny, nz, scratch_edge, 2);
414
+ const a0 = scratch_edge[0], a1 = scratch_edge[1];
415
+ const b0 = scratch_edge[2], b1 = scratch_edge[3];
416
+
417
+ line3_closest_points_segment_segment(
418
+ scratch_st,
419
+ wvA[a0], wvA[a0 + 1], wvA[a0 + 2],
420
+ wvA[a1], wvA[a1 + 1], wvA[a1 + 2],
421
+ wvB[b0], wvB[b0 + 1], wvB[b0 + 2],
422
+ wvB[b1], wvB[b1 + 1], wvB[b1 + 2]
423
+ );
424
+ const s = scratch_st[0];
425
+ const t = scratch_st[1];
426
+ out[3] = 1;
427
+ out[4] = wvA[a0] + (wvA[a1] - wvA[a0]) * s;
428
+ out[5] = wvA[a0 + 1] + (wvA[a1 + 1] - wvA[a0 + 1]) * s;
429
+ out[6] = wvA[a0 + 2] + (wvA[a1 + 2] - wvA[a0 + 2]) * s;
430
+ out[7] = wvB[b0] + (wvB[b1] - wvB[b0]) * t;
431
+ out[8] = wvB[b0 + 1] + (wvB[b1 + 1] - wvB[b0 + 1]) * t;
432
+ out[9] = wvB[b0 + 2] + (wvB[b1 + 2] - wvB[b0 + 2]) * t;
433
+ out[10] = depth;
434
+ }
435
+
436
+ /**
437
+ * Reference/incident polygon clipping given the reference face. Writes the
438
+ * manifold (count + contacts) into `out`; leaves out[0..2] (the normal) as set
439
+ * by the caller. Shared by both the SAT and GJK+EPA entry points.
440
+ *
441
+ * @param {boolean} ref_is_A reference face belongs to A (else B)
442
+ * @param {number} ref_face reference face index within its piece
443
+ * @param {number} nx @param {number} ny @param {number} nz axis (B→A), unit
444
+ */
445
+ function emit_face_manifold(out, ref_is_A, ref_face, nx, ny, nz) {
446
+ const ref_wv = ref_is_A ? wvA : wvB;
447
+ const ref_fo = ref_is_A ? g_foA : g_foB;
448
+ const ref_fl = ref_is_A ? g_flA : g_flB;
449
+ const inc_wv = ref_is_A ? wvB : wvA;
450
+ const inc_fo = ref_is_A ? g_foB : g_foA;
451
+ const inc_fl = ref_is_A ? g_flB : g_flA;
452
+ const inc_fcount = ref_is_A ? g_fB : g_fA;
453
+
454
+ // Reference outward normal points ref → incident: −n if ref is A, +n if ref is B.
455
+ const rmx = ref_is_A ? -nx : nx, rmy = ref_is_A ? -ny : ny, rmz = ref_is_A ? -nz : nz;
456
+
457
+ const ref_s = ref_fo[ref_face], ref_len = ref_fo[ref_face + 1] - ref_s;
458
+ const r0 = ref_fl[ref_s] * 3;
459
+ const r0x = ref_wv[r0], r0y = ref_wv[r0 + 1], r0z = ref_wv[r0 + 2];
460
+
461
+ // Incident face = the polygon on the other piece most antiparallel to rm.
462
+ let inc_face = 0, most_anti = Infinity;
463
+ for (let f = 0; f < inc_fcount; f++) {
464
+ face_normal(tmp_n, inc_wv, inc_fl, inc_fo[f], inc_fo[f + 1]);
465
+ const l = v3_length(tmp_n[0], tmp_n[1], tmp_n[2]) || 1;
466
+ const dot = v3_dot(tmp_n[0], tmp_n[1], tmp_n[2], rmx, rmy, rmz) / l;
467
+ if (dot < most_anti) { most_anti = dot; inc_face = f; }
468
+ }
469
+
470
+ // Incident polygon (world). Worst-case working size: the incident loop
471
+ // plus one extra vertex per reference side-plane clip (a convex polygon
472
+ // clipped by a half-space gains at most one vertex) — grow the shared
473
+ // scratch to fit, so wide coplanar-merged faces aren't truncated into
474
+ // OOB reads (NaN / stale contacts).
475
+ const inc_s = inc_fo[inc_face], inc_len = inc_fo[inc_face + 1] - inc_s;
476
+ const max_poly_verts = inc_len + ref_len;
477
+ if (poly_in.length < max_poly_verts * 3) {
478
+ poly_in = new Float64Array(max_poly_verts * 3);
479
+ poly_out = new Float64Array(max_poly_verts * 3);
480
+ cand = new Float64Array(max_poly_verts * 4);
481
+ }
482
+ let n_poly = inc_len;
483
+ for (let i = 0; i < inc_len; i++) {
484
+ const vi = inc_fl[inc_s + i] * 3;
485
+ poly_in[i * 3] = inc_wv[vi]; poly_in[i * 3 + 1] = inc_wv[vi + 1]; poly_in[i * 3 + 2] = inc_wv[vi + 2];
486
+ }
487
+
488
+ // Reference polygon centroid (orients side planes inward).
489
+ let rcx = 0, rcy = 0, rcz = 0;
490
+ for (let i = 0; i < ref_len; i++) {
491
+ const vi = ref_fl[ref_s + i] * 3;
492
+ rcx += ref_wv[vi]; rcy += ref_wv[vi + 1]; rcz += ref_wv[vi + 2];
493
+ }
494
+ rcx /= ref_len; rcy /= ref_len; rcz /= ref_len;
495
+
496
+ // Clip the incident polygon against each reference-face side plane.
497
+ let src = poly_in, dst = poly_out;
498
+ for (let e = 0; e < ref_len && n_poly > 0; e++) {
499
+ const va = ref_fl[ref_s + e] * 3, vb = ref_fl[ref_s + (e + 1) % ref_len] * 3;
500
+ const edx = ref_wv[vb] - ref_wv[va], edy = ref_wv[vb + 1] - ref_wv[va + 1], edz = ref_wv[vb + 2] - ref_wv[va + 2];
501
+ let sx = edy * rmz - edz * rmy, sy = edz * rmx - edx * rmz, sz = edx * rmy - edy * rmx;
502
+ const pax = ref_wv[va], pay = ref_wv[va + 1], paz = ref_wv[va + 2];
503
+ if ((rcx - pax) * sx + (rcy - pay) * sy + (rcz - paz) * sz > 0) { sx = -sx; sy = -sy; sz = -sz; }
504
+ n_poly = clip_poly(src, n_poly, dst, sx, sy, sz, pax, pay, paz);
505
+ const t = src; src = dst; dst = t;
506
+ }
507
+ if (n_poly === 0) { out[3] = 0; return; }
508
+
509
+ let nc = 0;
510
+ for (let i = 0; i < n_poly; i++) {
511
+ const px = src[i * 3], py = src[i * 3 + 1], pz = src[i * 3 + 2];
512
+ const sep = (px - r0x) * rmx + (py - r0y) * rmy + (pz - r0z) * rmz;
513
+ const depth = -sep;
514
+ if (depth < 0) continue;
515
+ cand[nc * 4] = px; cand[nc * 4 + 1] = py; cand[nc * 4 + 2] = pz; cand[nc * 4 + 3] = depth;
516
+ nc++;
517
+ }
518
+ if (nc === 0) { out[3] = 0; return; }
519
+
520
+ const kept = reduce_manifold_contacts(cand, nc, 4, MAX_CONTACTS, 3);
521
+ out[3] = kept;
522
+ for (let k = 0; k < kept; k++) {
523
+ const px = cand[k * 4], py = cand[k * 4 + 1], pz = cand[k * 4 + 2], depth = cand[k * 4 + 3];
524
+ const d2p = (px - r0x) * rmx + (py - r0y) * rmy + (pz - r0z) * rmz;
525
+ const rpx = px - rmx * d2p, rpy = py - rmy * d2p, rpz = pz - rmz * d2p;
526
+ const base = 4 + k * CONTACT_STRIDE;
527
+ if (ref_is_A) {
528
+ out[base] = rpx; out[base + 1] = rpy; out[base + 2] = rpz;
529
+ out[base + 3] = px; out[base + 4] = py; out[base + 5] = pz;
530
+ } else {
531
+ out[base] = px; out[base + 1] = py; out[base + 2] = pz;
532
+ out[base + 3] = rpx; out[base + 4] = rpy; out[base + 5] = rpz;
533
+ }
534
+ out[base + 6] = depth;
535
+ }
536
+ }
537
+
538
+ /**
539
+ * Sutherland–Hodgman: keep polygon points where (P − a)·s ≤ 0, with crossings.
540
+ * Capacity-guarded on BOTH emit branches: `m` must never pass `dst`'s capacity
541
+ * or the dropped OOB writes leave stale/NaN points that later reads consume
542
+ * (the buffers are pre-sized to inc_len + ref_len, so the guard is a backstop
543
+ * for degenerate input, not the normal bound).
544
+ */
545
+ function clip_poly(src, n, dst, sx, sy, sz, ax, ay, az) {
546
+ const cap = (dst.length / 3) | 0;
547
+ let m = 0;
548
+ for (let i = 0; i < n && m < cap; i++) {
549
+ const j = (i + 1) % n;
550
+ const px = src[i * 3], py = src[i * 3 + 1], pz = src[i * 3 + 2];
551
+ const qx = src[j * 3], qy = src[j * 3 + 1], qz = src[j * 3 + 2];
552
+ const dp = v3_dot(px - ax, py - ay, pz - az, sx, sy, sz);
553
+ const dq = v3_dot(qx - ax, qy - ay, qz - az, sx, sy, sz);
554
+ const p_in = dp <= 0, q_in = dq <= 0;
555
+ if (p_in) { dst[m * 3] = px; dst[m * 3 + 1] = py; dst[m * 3 + 2] = pz; m++; }
556
+ if (p_in !== q_in && m < cap) {
557
+ const t = dp / (dp - dq);
558
+ dst[m * 3] = px + (qx - px) * t;
559
+ dst[m * 3 + 1] = py + (qy - py) * t;
560
+ dst[m * 3 + 2] = pz + (qz - pz) * t;
561
+ m++;
562
+ }
563
+ }
564
+ return m;
565
+ }
566
+
567
+ // Contact reduction (deepest + farthest-point spread) is shared with
568
+ // box_box_manifold via reduce_manifold_contacts (stride 4).