@woosh/meep-engine 2.156.0 → 2.157.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 (654) 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} +9 -8
  134. package/src/{engine/physics/narrowphase/PosedShape.d.ts.map → core/geom/3d/shape/PosedShape3D.d.ts.map} +1 -1
  135. package/src/{engine/physics/narrowphase/PosedShape.js → core/geom/3d/shape/PosedShape3D.js} +10 -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/particles/particular/engine/emitter/serde/ParameterLookupTableSerializationAdapter.d.ts.map +1 -1
  250. package/src/engine/graphics/particles/particular/engine/emitter/serde/ParameterLookupTableSerializationAdapter.js +2 -76
  251. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.d.ts.map +1 -1
  252. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +2 -427
  253. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.d.ts +1 -4
  254. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.d.ts.map +1 -1
  255. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.js +2 -6
  256. package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +1 -1
  257. package/src/engine/graphics/render/forward_plus/read_frustum_corner.d.ts +1 -8
  258. package/src/engine/graphics/render/forward_plus/read_frustum_corner.d.ts.map +1 -1
  259. package/src/engine/graphics/render/forward_plus/read_frustum_corner.js +2 -14
  260. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.d.ts +1 -11
  261. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.d.ts.map +1 -1
  262. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.js +2 -46
  263. package/src/engine/graphics/sh3/prototypeSH3Probe.js +1 -1
  264. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts +27 -0
  265. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts.map +1 -0
  266. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.js +81 -0
  267. package/src/engine/graphics/texture/isImageBitmap.d.ts +1 -6
  268. package/src/engine/graphics/texture/isImageBitmap.d.ts.map +1 -1
  269. package/src/engine/graphics/texture/isImageBitmap.js +2 -12
  270. package/src/{core/process/action → engine/intelligence/behavior/util}/AsynchronousDelayAction.d.ts +2 -2
  271. package/src/engine/intelligence/behavior/util/AsynchronousDelayAction.d.ts.map +1 -0
  272. package/src/{core/process/action → engine/intelligence/behavior/util}/AsynchronousDelayAction.js +55 -55
  273. package/src/engine/network/NetworkSession.d.ts +12 -1
  274. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  275. package/src/engine/network/NetworkSession.js +52 -1
  276. package/src/engine/network/README.md +45 -0
  277. package/src/engine/network/convertPathToURL.d.ts +1 -8
  278. package/src/engine/network/convertPathToURL.d.ts.map +1 -1
  279. package/src/engine/network/convertPathToURL.js +2 -107
  280. package/src/engine/network/core/quantize/quantize_float.d.ts.map +1 -1
  281. package/src/engine/network/core/quantize/quantize_float.js +7 -0
  282. package/src/engine/network/core/quantize/quantize_position.d.ts.map +1 -1
  283. package/src/engine/network/core/quantize/quantize_position.js +12 -1
  284. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  285. package/src/engine/network/orchestrator/NetworkPeer.js +15 -1
  286. package/src/engine/network/replication/Replicator.d.ts +8 -0
  287. package/src/engine/network/replication/Replicator.d.ts.map +1 -1
  288. package/src/engine/network/replication/Replicator.js +48 -0
  289. package/src/engine/network/transport/Channel.d.ts.map +1 -1
  290. package/src/engine/network/transport/Channel.js +46 -12
  291. package/src/engine/network/transport/ReliableCommandPipeline.d.ts +16 -0
  292. package/src/engine/network/transport/ReliableCommandPipeline.d.ts.map +1 -1
  293. package/src/engine/network/transport/ReliableCommandPipeline.js +29 -0
  294. package/src/engine/network/transport/adapters/NodeUDPTransport.d.ts.map +1 -1
  295. package/src/engine/network/transport/adapters/NodeUDPTransport.js +7 -1
  296. package/src/engine/network/transport/fragments/packet_size.d.ts +5 -5
  297. package/src/engine/network/transport/fragments/packet_size.d.ts.map +1 -1
  298. package/src/engine/network/transport/fragments/packet_size.js +5 -5
  299. package/src/engine/physics/BULLET_REVIEW.md +1 -1
  300. package/src/engine/physics/JOLT_REVIEW.md +2 -2
  301. package/src/engine/physics/PLAN.md +1094 -945
  302. package/src/engine/physics/RAPIER_REVIEW.md +2 -2
  303. package/src/engine/physics/body/BodyStorage.d.ts +2 -12
  304. package/src/engine/physics/body/BodyStorage.d.ts.map +1 -1
  305. package/src/engine/physics/body/BodyStorage.js +406 -452
  306. package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -1
  307. package/src/engine/physics/body/SolverBodyState.js +12 -3
  308. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts +28 -3
  309. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts.map +1 -1
  310. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +60 -24
  311. package/src/engine/physics/broadphase/generate_pairs.d.ts +9 -5
  312. package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -1
  313. package/src/engine/physics/broadphase/generate_pairs.js +52 -37
  314. package/src/engine/physics/ccd/linear_sweep.d.ts +15 -5
  315. package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
  316. package/src/engine/physics/ccd/linear_sweep.js +122 -40
  317. package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -1
  318. package/src/engine/physics/constraint/solve_constraints.js +830 -805
  319. package/src/engine/physics/contact/ManifoldStore.d.ts +91 -16
  320. package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
  321. package/src/engine/physics/contact/ManifoldStore.js +204 -60
  322. package/src/engine/physics/ecs/BodyKind.d.ts +7 -3
  323. package/src/engine/physics/ecs/BodyKind.d.ts.map +1 -1
  324. package/src/engine/physics/ecs/BodyKind.js +29 -25
  325. package/src/engine/physics/ecs/Collider.d.ts +7 -0
  326. package/src/engine/physics/ecs/Collider.d.ts.map +1 -1
  327. package/src/engine/physics/ecs/Collider.js +7 -0
  328. package/src/engine/physics/ecs/ColliderSerializationAdapter.js +1 -1
  329. package/src/engine/physics/ecs/PhysicsSystem.d.ts +110 -6
  330. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  331. package/src/engine/physics/ecs/PhysicsSystem.js +467 -45
  332. package/src/engine/physics/ecs/RigidBody.d.ts +20 -5
  333. package/src/engine/physics/ecs/RigidBody.d.ts.map +1 -1
  334. package/src/engine/physics/ecs/RigidBody.js +307 -286
  335. package/src/engine/physics/ecs/RigidBodyFlags.d.ts +6 -3
  336. package/src/engine/physics/ecs/RigidBodyFlags.d.ts.map +1 -1
  337. package/src/engine/physics/ecs/RigidBodyFlags.js +31 -28
  338. package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts +12 -4
  339. package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts.map +1 -1
  340. package/src/engine/physics/ecs/RigidBodySerializationAdapter.js +19 -5
  341. package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.d.ts +10 -0
  342. package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.d.ts.map +1 -0
  343. package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.js +37 -0
  344. package/src/engine/physics/ecs/find_non_finite_physics_state.d.ts +28 -0
  345. package/src/engine/physics/ecs/find_non_finite_physics_state.d.ts.map +1 -0
  346. package/src/engine/physics/ecs/find_non_finite_physics_state.js +76 -0
  347. package/src/engine/physics/events/ContactEventBuffer.d.ts +11 -0
  348. package/src/engine/physics/events/ContactEventBuffer.d.ts.map +1 -1
  349. package/src/engine/physics/events/ContactEventBuffer.js +40 -0
  350. package/src/engine/physics/events/diff_manifolds.d.ts +30 -13
  351. package/src/engine/physics/events/diff_manifolds.d.ts.map +1 -1
  352. package/src/engine/physics/events/diff_manifolds.js +87 -50
  353. package/src/engine/physics/fluid/FluidField.d.ts +45 -17
  354. package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
  355. package/src/engine/physics/fluid/FluidField.js +53 -23
  356. package/src/engine/physics/fluid/FluidSimulator.d.ts +141 -5
  357. package/src/engine/physics/fluid/FluidSimulator.d.ts.map +1 -1
  358. package/src/engine/physics/fluid/FluidSimulator.js +336 -43
  359. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +114 -0
  360. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts +4 -3
  361. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -1
  362. package/src/engine/physics/fluid/ecs/FluidComponent.js +4 -3
  363. package/src/engine/physics/fluid/ecs/FluidSystem.d.ts +3 -3
  364. package/src/engine/physics/fluid/effector/AmbientWindFluidEffector.d.ts +41 -0
  365. package/src/engine/physics/fluid/effector/AmbientWindFluidEffector.d.ts.map +1 -0
  366. package/src/engine/physics/fluid/effector/AmbientWindFluidEffector.js +124 -0
  367. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts +27 -8
  368. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts.map +1 -1
  369. package/src/engine/physics/fluid/effector/WakeFluidEffector.js +67 -18
  370. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.d.ts +42 -0
  371. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.d.ts.map +1 -0
  372. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.js +136 -0
  373. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.d.ts +37 -0
  374. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.d.ts.map +1 -0
  375. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.js +169 -0
  376. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.d.ts +36 -0
  377. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.d.ts.map +1 -0
  378. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.js +100 -0
  379. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts +6 -0
  380. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts.map +1 -1
  381. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.js +6 -0
  382. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts +7 -2
  383. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts.map +1 -1
  384. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.js +17 -12
  385. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.d.ts +42 -0
  386. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.d.ts.map +1 -0
  387. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.js +131 -0
  388. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts +32 -22
  389. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts.map +1 -1
  390. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.js +43 -26
  391. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.d.ts +31 -0
  392. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.d.ts.map +1 -0
  393. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.js +77 -0
  394. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts +26 -19
  395. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts.map +1 -1
  396. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.js +46 -42
  397. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts +38 -10
  398. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts.map +1 -1
  399. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.js +158 -75
  400. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts +22 -17
  401. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -1
  402. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +108 -96
  403. package/src/engine/physics/inertia/world_inverse_inertia.d.ts +30 -1
  404. package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -1
  405. package/src/engine/physics/inertia/world_inverse_inertia.js +160 -116
  406. package/src/engine/physics/integration/integrate_position.js +97 -97
  407. package/src/engine/physics/island/IslandBuilder.d.ts +49 -8
  408. package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -1
  409. package/src/engine/physics/island/IslandBuilder.js +93 -14
  410. package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -1
  411. package/src/engine/physics/narrowphase/box_box_manifold.js +683 -673
  412. package/src/engine/physics/narrowphase/box_triangle_contact.d.ts.map +1 -1
  413. package/src/engine/physics/narrowphase/box_triangle_contact.js +899 -749
  414. package/src/engine/physics/narrowphase/capsule_contacts.d.ts +27 -0
  415. package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -1
  416. package/src/engine/physics/narrowphase/capsule_contacts.js +624 -459
  417. package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts.map +1 -1
  418. package/src/engine/physics/narrowphase/capsule_triangle_contact.js +58 -38
  419. package/src/engine/physics/narrowphase/compute_penetration.d.ts.map +1 -1
  420. package/src/engine/physics/narrowphase/compute_penetration.js +369 -325
  421. package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts +3 -1
  422. package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts.map +1 -1
  423. package/src/engine/physics/narrowphase/convex_convex_manifold.js +568 -422
  424. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts +6 -3
  425. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts.map +1 -1
  426. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.js +66 -10
  427. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts +4 -1
  428. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts.map +1 -1
  429. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.js +97 -94
  430. package/src/engine/physics/narrowphase/mesh_mesh_tet_manifold.js +117 -117
  431. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  432. package/src/engine/physics/narrowphase/narrowphase_step.js +1738 -1739
  433. package/src/engine/physics/narrowphase/reduce_manifold_contacts.d.ts +14 -7
  434. package/src/engine/physics/narrowphase/reduce_manifold_contacts.d.ts.map +1 -1
  435. package/src/engine/physics/narrowphase/reduce_manifold_contacts.js +74 -69
  436. package/src/engine/physics/persistence/solver_caches.d.ts +20 -0
  437. package/src/engine/physics/persistence/solver_caches.d.ts.map +1 -0
  438. package/src/engine/physics/persistence/solver_caches.js +309 -0
  439. package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -1
  440. package/src/engine/physics/queries/overlap_shape.js +187 -184
  441. package/src/engine/physics/queries/raycast.d.ts +3 -2
  442. package/src/engine/physics/queries/raycast.d.ts.map +1 -1
  443. package/src/engine/physics/queries/raycast.js +37 -11
  444. package/src/engine/physics/queries/shape_cast.d.ts +18 -5
  445. package/src/engine/physics/queries/shape_cast.d.ts.map +1 -1
  446. package/src/engine/physics/queries/shape_cast.js +417 -393
  447. package/src/engine/physics/solver/solve_contacts.d.ts +22 -6
  448. package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
  449. package/src/engine/physics/solver/solve_contacts.js +1482 -1338
  450. package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
  451. package/src/engine/physics/vehicle/RaycastVehicle.js +344 -339
  452. package/src/engine/ui/DraggableAspect.d.ts +12 -3
  453. package/src/engine/ui/DraggableAspect.d.ts.map +1 -1
  454. package/src/engine/ui/DraggableAspect.js +115 -83
  455. package/src/generation/COORDINATES.md +54 -0
  456. package/src/generation/GridTaskGroup.js +2 -2
  457. package/src/generation/REVIEW_01_ACTION_PLAN.md +628 -0
  458. package/src/generation/automata/CaveGeneratorCellularAutomata.d.ts +9 -1
  459. package/src/generation/automata/CaveGeneratorCellularAutomata.d.ts.map +1 -1
  460. package/src/generation/automata/CaveGeneratorCellularAutomata.js +79 -59
  461. package/src/generation/automata/CellularAutomata.d.ts +6 -3
  462. package/src/generation/automata/CellularAutomata.d.ts.map +1 -1
  463. package/src/generation/automata/CellularAutomata.js +22 -19
  464. package/src/generation/filtering/CellFilter.d.ts +17 -0
  465. package/src/generation/filtering/CellFilter.d.ts.map +1 -1
  466. package/src/generation/filtering/CellFilter.js +117 -77
  467. package/src/generation/filtering/CellFilterCellMatcher.d.ts.map +1 -1
  468. package/src/generation/filtering/CellFilterCellMatcher.js +2 -0
  469. package/src/generation/filtering/boolean/CellFilterLiteralBoolean.d.ts +5 -0
  470. package/src/generation/filtering/boolean/CellFilterLiteralBoolean.d.ts.map +1 -1
  471. package/src/generation/filtering/boolean/CellFilterLiteralBoolean.js +15 -0
  472. package/src/generation/filtering/core/CellFilterBinaryOperation.d.ts +0 -1
  473. package/src/generation/filtering/core/CellFilterBinaryOperation.d.ts.map +1 -1
  474. package/src/generation/filtering/core/CellFilterBinaryOperation.js +37 -50
  475. package/src/generation/filtering/core/CellFilterOperationTertiary.d.ts +0 -1
  476. package/src/generation/filtering/core/CellFilterOperationTertiary.d.ts.map +1 -1
  477. package/src/generation/filtering/core/CellFilterOperationTertiary.js +43 -59
  478. package/src/generation/filtering/core/CellFilterUnaryOperation.d.ts +0 -1
  479. package/src/generation/filtering/core/CellFilterUnaryOperation.d.ts.map +1 -1
  480. package/src/generation/filtering/core/CellFilterUnaryOperation.js +29 -33
  481. package/src/generation/filtering/numeric/CellFilterCache.d.ts +1 -0
  482. package/src/generation/filtering/numeric/CellFilterCache.d.ts.map +1 -1
  483. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.d.ts +3 -2
  484. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.d.ts.map +1 -1
  485. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.js +9 -35
  486. package/src/generation/filtering/numeric/complex/CellFilterCurvature.d.ts +0 -1
  487. package/src/generation/filtering/numeric/complex/CellFilterCurvature.d.ts.map +1 -1
  488. package/src/generation/filtering/numeric/complex/CellFilterCurvature.js +19 -43
  489. package/src/generation/filtering/numeric/complex/CellFilterFXAA.d.ts +0 -1
  490. package/src/generation/filtering/numeric/complex/CellFilterFXAA.d.ts.map +1 -1
  491. package/src/generation/filtering/numeric/complex/CellFilterFXAA.js +2 -6
  492. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.d.ts.map +1 -1
  493. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.js +9 -12
  494. package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.d.ts.map +1 -1
  495. package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.js +2 -1
  496. package/src/generation/filtering/numeric/complex/CellFilterSobel.d.ts +0 -1
  497. package/src/generation/filtering/numeric/complex/CellFilterSobel.d.ts.map +1 -1
  498. package/src/generation/filtering/numeric/complex/CellFilterSobel.js +2 -6
  499. package/src/generation/filtering/numeric/math/CellFilterInverseLerp.d.ts +5 -4
  500. package/src/generation/filtering/numeric/math/CellFilterInverseLerp.d.ts.map +1 -1
  501. package/src/generation/filtering/numeric/math/CellFilterInverseLerp.js +5 -4
  502. package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.d.ts +17 -0
  503. package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.d.ts.map +1 -0
  504. package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.js +42 -0
  505. package/src/generation/filtering/numeric/sampling/AbstractCellFilterSampleGridLayer.d.ts.map +1 -1
  506. package/src/generation/filtering/numeric/sampling/AbstractCellFilterSampleGridLayer.js +7 -1
  507. package/src/generation/filtering/numeric/util/populateSampler2DFromCellFilter.d.ts.map +1 -1
  508. package/src/generation/filtering/numeric/util/populateSampler2DFromCellFilter.js +7 -10
  509. package/src/generation/filtering/numeric/util/sampler_from_filter.d.ts.map +1 -1
  510. package/src/generation/filtering/numeric/util/sampler_from_filter.js +2 -1
  511. package/src/generation/grid/GridData.d.ts.map +1 -1
  512. package/src/generation/grid/GridData.js +14 -1
  513. package/src/generation/grid/actions/ContinuousGridCellAction.d.ts +10 -3
  514. package/src/generation/grid/actions/ContinuousGridCellAction.d.ts.map +1 -1
  515. package/src/generation/grid/actions/ContinuousGridCellAction.js +18 -3
  516. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainHeight.d.ts +11 -1
  517. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainHeight.d.ts.map +1 -1
  518. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainHeight.js +13 -3
  519. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.d.ts +1 -1
  520. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.js +2 -2
  521. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.d.ts +1 -1
  522. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.d.ts.map +1 -1
  523. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.js +4 -6
  524. package/src/generation/grid/coords/grid_to_texel.d.ts +9 -0
  525. package/src/generation/grid/coords/grid_to_texel.d.ts.map +1 -0
  526. package/src/generation/grid/coords/grid_to_texel.js +10 -0
  527. package/src/generation/grid/coords/texel_to_grid.d.ts +9 -0
  528. package/src/generation/grid/coords/texel_to_grid.d.ts.map +1 -0
  529. package/src/generation/grid/coords/texel_to_grid.js +10 -0
  530. package/src/generation/grid/generation/GridTaskApplyActionToCells.d.ts +2 -2
  531. package/src/generation/grid/generation/GridTaskApplyActionToCells.d.ts.map +1 -1
  532. package/src/generation/grid/generation/GridTaskApplyActionToCells.js +10 -6
  533. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.d.ts.map +1 -1
  534. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.js +20 -21
  535. package/src/generation/grid/generation/GridTaskExecuteRuleTimes.d.ts +7 -0
  536. package/src/generation/grid/generation/GridTaskExecuteRuleTimes.d.ts.map +1 -1
  537. package/src/generation/grid/generation/GridTaskExecuteRuleTimes.js +18 -10
  538. package/src/generation/grid/generation/discrete/GridTaskCellularAutomata.d.ts.map +1 -1
  539. package/src/generation/grid/generation/discrete/GridTaskCellularAutomata.js +16 -7
  540. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.d.ts +5 -3
  541. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.d.ts.map +1 -1
  542. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.js +26 -23
  543. package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.d.ts.map +1 -1
  544. package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.js +10 -1
  545. package/src/generation/grid/generation/grid/select/CellSupplierBestN.d.ts.map +1 -1
  546. package/src/generation/grid/generation/grid/select/CellSupplierBestN.js +4 -0
  547. package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts +15 -8
  548. package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts.map +1 -1
  549. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +89 -92
  550. package/src/generation/markers/GridActionRuleSet.d.ts.map +1 -1
  551. package/src/generation/markers/GridActionRuleSet.js +10 -2
  552. package/src/generation/markers/GridCellActionPlaceMarker.d.ts +11 -0
  553. package/src/generation/markers/GridCellActionPlaceMarker.d.ts.map +1 -1
  554. package/src/generation/markers/GridCellActionPlaceMarker.js +20 -3
  555. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts +3 -1
  556. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts.map +1 -1
  557. package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +9 -2
  558. package/src/generation/markers/MarkerNode.d.ts +8 -3
  559. package/src/generation/markers/MarkerNode.d.ts.map +1 -1
  560. package/src/generation/markers/MarkerNode.js +12 -5
  561. package/src/generation/markers/actions/MarkerNodeActionEntityPlacement.js +1 -1
  562. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.d.ts +1 -1
  563. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.d.ts.map +1 -1
  564. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.js +1 -1
  565. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.d.ts +1 -1
  566. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.d.ts.map +1 -1
  567. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.js +1 -1
  568. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.d.ts +1 -1
  569. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.d.ts.map +1 -1
  570. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.js +2 -2
  571. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.d.ts +1 -1
  572. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.d.ts.map +1 -1
  573. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.js +2 -2
  574. package/src/generation/markers/actions/probability/MarkerNodeActionSelectWeighted.d.ts.map +1 -1
  575. package/src/generation/markers/actions/probability/MarkerNodeActionSelectWeighted.js +6 -4
  576. package/src/generation/markers/actions/probability/MarkerNodeActionWeightedElement.d.ts.map +1 -1
  577. package/src/generation/markers/actions/probability/MarkerNodeActionWeightedElement.js +1 -3
  578. package/src/generation/markers/actions/terrain/MarkerNodeActionPaintTerrain.d.ts.map +1 -1
  579. package/src/generation/markers/actions/terrain/MarkerNodeActionPaintTerrain.js +12 -11
  580. package/src/generation/markers/matcher/MarkerNodeMatcherAnd.js +2 -2
  581. package/src/generation/markers/transform/MarkerNodeTransformer.d.ts +4 -1
  582. package/src/generation/markers/transform/MarkerNodeTransformer.d.ts.map +1 -1
  583. package/src/generation/markers/transform/MarkerNodeTransformer.js +4 -1
  584. package/src/generation/markers/transform/MarkerNodeTransformerAddPositionYFromFilter.d.ts.map +1 -1
  585. package/src/generation/markers/transform/MarkerNodeTransformerAddPositionYFromFilter.js +1 -3
  586. package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.d.ts +5 -0
  587. package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.d.ts.map +1 -1
  588. package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.js +15 -0
  589. package/src/generation/markers/transform/MarkerNodeTransformerRecordProperty.d.ts.map +1 -1
  590. package/src/generation/markers/transform/MarkerNodeTransformerRecordProperty.js +1 -3
  591. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilter.d.ts.map +1 -1
  592. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilter.js +2 -4
  593. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilterGradient.d.ts.map +1 -1
  594. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilterGradient.js +1 -3
  595. package/src/generation/placement/GridCellPlacementRule.d.ts.map +1 -1
  596. package/src/generation/placement/GridCellPlacementRule.js +1 -3
  597. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.d.ts.map +1 -1
  598. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.js +8 -10
  599. package/src/generation/placement/action/random/weighted/CellActionSelectWeightedRandom.d.ts.map +1 -1
  600. package/src/generation/placement/action/random/weighted/CellActionSelectWeightedRandom.js +6 -4
  601. package/src/generation/placement/action/random/weighted/WeightedGridCellAction.d.ts.map +1 -1
  602. package/src/generation/placement/action/random/weighted/WeightedGridCellAction.js +1 -3
  603. package/src/generation/rules/CellMatcher.d.ts +3 -1
  604. package/src/generation/rules/CellMatcher.d.ts.map +1 -1
  605. package/src/generation/rules/CellMatcher.js +3 -1
  606. package/src/generation/rules/CellMatcherFromFilter.d.ts.map +1 -1
  607. package/src/generation/rules/CellMatcherFromFilter.js +1 -3
  608. package/src/generation/rules/CellMatcherLayerBitMaskTest.d.ts.map +1 -1
  609. package/src/generation/rules/CellMatcherLayerBitMaskTest.js +6 -20
  610. package/src/generation/test_support/executeTaskTreeSync.d.ts +9 -0
  611. package/src/generation/test_support/executeTaskTreeSync.d.ts.map +1 -0
  612. package/src/generation/test_support/executeTaskTreeSync.js +78 -0
  613. package/src/generation/theme/TerrainLayerRuleAggregator.d.ts +2 -1
  614. package/src/generation/theme/TerrainLayerRuleAggregator.d.ts.map +1 -1
  615. package/src/generation/theme/TerrainLayerRuleAggregator.js +9 -6
  616. package/src/generation/theme/Theme.d.ts +1 -1
  617. package/src/generation/theme/Theme.d.ts.map +1 -1
  618. package/src/generation/theme/Theme.js +2 -2
  619. package/src/generation/theme/ThemeEngine.d.ts +3 -3
  620. package/src/generation/theme/ThemeEngine.d.ts.map +1 -1
  621. package/src/generation/theme/ThemeEngine.js +26 -16
  622. package/src/generation/theme/cell/CellProcessingRule.d.ts +3 -3
  623. package/src/generation/theme/cell/CellProcessingRule.d.ts.map +1 -1
  624. package/src/generation/theme/cell/CellProcessingRule.js +6 -10
  625. package/src/generation/theme/cell/CellProcessingRuleSet.d.ts +1 -1
  626. package/src/generation/theme/cell/CellProcessingRuleSet.d.ts.map +1 -1
  627. package/src/generation/theme/cell/CellProcessingRuleSet.js +2 -2
  628. package/src/view/common/ListView.js +1 -1
  629. package/src/view/elements/BottomLeftResizeHandleView.d.ts.map +1 -1
  630. package/src/view/elements/BottomLeftResizeHandleView.js +13 -5
  631. package/src/core/font/FontAsset.d.ts.map +0 -1
  632. package/src/core/font/FontAssetLoader.d.ts.map +0 -1
  633. package/src/core/geom/3d/shape/util/shape_to_visual_entity.d.ts.map +0 -1
  634. package/src/core/geom/3d/tetrahedra/visualize_tetrahedral_mesh.d.ts.map +0 -1
  635. package/src/core/process/action/AsynchronousDelayAction.d.ts.map +0 -1
  636. package/src/engine/physics/computeInterceptPoint.d.ts.map +0 -1
  637. package/src/engine/physics/fluid/solver/optimal_sor_omega.d.ts.map +0 -1
  638. package/src/engine/physics/gjk/gjk.d.ts.map +0 -1
  639. package/src/engine/physics/gjk/gjk_epa_penetration.d.ts.map +0 -1
  640. package/src/engine/physics/gjk/minkowski_support.d.ts.map +0 -1
  641. package/src/engine/physics/gjk/mpr.d.ts.map +0 -1
  642. package/src/engine/physics/integration/quat_integrate.d.ts.map +0 -1
  643. package/src/engine/physics/island/union_find.d.ts.map +0 -1
  644. package/src/engine/physics/narrowphase/clip_against_axis_uv.d.ts.map +0 -1
  645. package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts.map +0 -1
  646. package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.d.ts +0 -21
  647. package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.d.ts.map +0 -1
  648. package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.js +0 -68
  649. package/src/generation/grid/generation/grid/GridTaskGridAlignedNodeGenerator.d.ts +0 -10
  650. package/src/generation/grid/generation/grid/GridTaskGridAlignedNodeGenerator.d.ts.map +0 -1
  651. package/src/generation/grid/generation/grid/GridTaskGridAlignedNodeGenerator.js +0 -17
  652. /package/src/{engine/physics → core/geom/3d}/gjk/NOTES.md +0 -0
  653. /package/src/{engine/physics → core/geom/3d}/gjk/gjk.d.ts +0 -0
  654. /package/src/{engine/physics → core/math/physics/kinematics}/computeInterceptPoint.d.ts +0 -0
@@ -1,393 +1,417 @@
1
- import { bvh_query_user_data_overlaps_aabb } from "../../../core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.js";
2
- import { returnTrue } from "../../../core/function/returnTrue.js";
3
- import { aabb3_transform_oriented } from "../../../core/geom/3d/aabb/aabb3_transform_oriented.js";
4
- import { body_id_index } from "../body/BodyStorage.js";
5
- import { gjk } from "../gjk/gjk.js";
6
- import { mpr } from "../gjk/mpr.js";
7
- import { PosedShape } from "../narrowphase/PosedShape.js";
8
-
9
- /**
10
- * Bisection halts when the search interval is below this fraction of
11
- * the sweep length. With `MAX_BISECTION = 32` and a unit-length sweep
12
- * the achieved precision is 1 / 2³² (well below any practical
13
- * world-scale tolerance), but we cap on relative tolerance so a
14
- * 10 m sweep doesn't insist on sub-micron precision.
15
- * @type {number}
16
- */
17
- const TOI_TOLERANCE = 1e-4;
18
-
19
- /**
20
- * Maximum bisection iterations. `log2(1 / TOI_TOLERANCE)` is enough
21
- * for any practical sweep; this is the hard upper bound to prevent
22
- * pathological inputs (NaN ray, etc.) from hanging the query.
23
- * @type {number}
24
- */
25
- const MAX_BISECTION = 32;
26
-
27
- /**
28
- * Coarse linear-search resolution for finding *any* overlap moment
29
- * along the per-candidate AABB-overlap interval (NOT the full sweep —
30
- * see `aabb_overlap_interval` for the analytical narrowing that runs
31
- * upstream). 32 substeps over the AABB-overlap window is dense enough
32
- * for any sweep where the shape's smallest extent is on the order of
33
- * its AABB's extent (true for spheres / boxes / capsules); the slab
34
- * intersection keeps that interval small even for kilometre-scale
35
- * sweeps, so this isn't the limit it would otherwise be.
36
- * @type {number}
37
- */
38
- const COARSE_STEPS = 32;
39
-
40
- const swept_aabb = new Float64Array(6);
41
- const local_aabb = new Float64Array(6);
42
- const initial_aabb = new Float64Array(6);
43
- const target_local_aabb = new Float64Array(6);
44
- const target_world_aabb = new Float64Array(6);
45
-
46
- // GJK simplex buffer (used to detect overlap during the bisection).
47
- const simplex_buf = new Float64Array(12);
48
-
49
- // Scratch for MPR's MTV output — same vec3 convention as EPA: direction
50
- // is "A's interior into B" with the magnitude being the depth. We use
51
- // MPR for the contact-normal recovery at the kiss point because it
52
- // converges reliably on smooth-vs-smooth supports where EPA hits its
53
- // iteration cap before tightening (sphere-vs-sphere shallow overlap).
54
- const mpr_result = new Float64Array(3);
55
-
56
- /**
57
- * Long-lived PosedShape adapters for the swept shape and the
58
- * candidate's collider. Both are re-bound per query the swept one
59
- * also gets its position field re-written every bisection step
60
- * without re-running `setup()`, since shape and rotation are
61
- * constant through the sweep.
62
- */
63
- const swept_posed = new PosedShape();
64
- const candidate_posed = new PosedShape();
65
-
66
- /**
67
- * Buffer for the union of static-BVH and dynamic-BVH candidates that
68
- * overlap the swept AABB. Grows by doubling on the rare overflow.
69
- * @type {Uint32Array}
70
- */
71
- let scratch_candidates = new Uint32Array(64);
72
-
73
- /**
74
- * Sweep a convex shape along a ray and find the first body it would
75
- * hit. Used by character controllers (sweep a capsule along intended
76
- * movement to find blockers), high-speed projectile movement (avoid
77
- * tunnelling without paying for full per-body CCD), and any kinematic
78
- * "where would this body end up if I tried to move it?" query.
79
- *
80
- * Pipeline:
81
- * 1. Build the swept AABB: the shape's local-frame AABB rotated
82
- * into world by `rotation`, translated to `ray.origin`, then
83
- * stretched along `ray.direction * ray.tMax`.
84
- * 2. Query both broadphase BVHs (static + dynamic) for leaves whose
85
- * AABB overlaps the swept volume.
86
- * 3. For each candidate, bisect the [0, best_t] interval for the
87
- * smallest `t` at which the swept shape overlaps the candidate's
88
- * collider. GJK on each midpoint.
89
- *
90
- * Picking `best_t` (rather than always running the full [0, tMax]
91
- * bisection) is the early-termination optimisation: once we have a
92
- * hit at some t, no later candidate can produce a smaller TOI by
93
- * being checked at its full [0, tMax] interval.
94
- *
95
- * Output on hit:
96
- * - `result.t` sweep distance to impact (in the same units as
97
- * `ray.direction`'s magnitude; for a unit-direction ray, this is
98
- * metres).
99
- * - `result.position` — `ray.origin + t * ray.direction`, i.e. the
100
- * centre of the swept shape at the moment of first contact. NOT
101
- * a point on the target's surface; that would need narrowphase
102
- * refinement which the broadphase-only architecture doesn't have
103
- * wired up yet.
104
- * - `result.normal` — target surface's outward normal at the kiss
105
- * point (unit length), computed by running GJK + EPA against the
106
- * just-overlapping configuration at the TOI. Falls back to
107
- * `-ray.direction` on the rare case EPA degenerates (NaN / zero
108
- * depth) see comment near the EPA call.
109
- * - `result.entity` / `result.body_id` the hit body.
110
- *
111
- * Output on miss: untouched; same convention as `raycast`.
112
- *
113
- * @param {PhysicsSystem} system
114
- * @param {Ray3} ray origin + unit direction + `tMax`
115
- * @param {AbstractShape3D} shape shape being swept, in its local frame
116
- * @param {{x:number,y:number,z:number,w:number}} rotation fixed orientation
117
- * @param {PhysicsSurfacePoint} result populated on hit; untouched on miss
118
- * @param {(entity:number, collider:Collider)=>boolean} [filter] mandatory in
119
- * contract; defaults to {@link returnTrue}
120
- * @returns {boolean}
121
- */
122
- export function shape_cast(system, ray, shape, rotation, result, filter = returnTrue) {
123
- const ox = ray.origin_x;
124
- const oy = ray.origin_y;
125
- const oz = ray.origin_z;
126
- const dx = ray.direction_x;
127
- const dy = ray.direction_y;
128
- const dz = ray.direction_z;
129
- const tMax = ray.tMax;
130
- if (!(tMax > 0) || !Number.isFinite(tMax)) return false;
131
-
132
- const rx = rotation.x, ry = rotation.y, rz = rotation.z, rw = rotation.w;
133
-
134
- // ── 1. Swept AABB ──────────────────────────────────────────────
135
- shape.compute_bounding_box(local_aabb);
136
- // Rotation around ray.origin gives the shape's initial AABB in
137
- // world space.
138
- aabb3_transform_oriented(
139
- initial_aabb, 0,
140
- local_aabb[0], local_aabb[1], local_aabb[2],
141
- local_aabb[3], local_aabb[4], local_aabb[5],
142
- ox, oy, oz,
143
- rx, ry, rz, rw
144
- );
145
- // Stretch by the sweep displacement. Positive direction components
146
- // push the +face out; negative components push the −face out.
147
- swept_aabb[0] = initial_aabb[0];
148
- swept_aabb[1] = initial_aabb[1];
149
- swept_aabb[2] = initial_aabb[2];
150
- swept_aabb[3] = initial_aabb[3];
151
- swept_aabb[4] = initial_aabb[4];
152
- swept_aabb[5] = initial_aabb[5];
153
- if (dx > 0) swept_aabb[3] += dx * tMax; else swept_aabb[0] += dx * tMax;
154
- if (dy > 0) swept_aabb[4] += dy * tMax; else swept_aabb[1] += dy * tMax;
155
- if (dz > 0) swept_aabb[5] += dz * tMax; else swept_aabb[2] += dz * tMax;
156
-
157
- // ── 2. Broadphase: gather candidates from both trees ───────────
158
- // The BVH query returns the TRUE overlap count and silently drops writes past
159
- // the buffer end. An undersized buffer would make the narrowphase loop read
160
- // `undefined` candidates and silently MISS the true nearest hit (tunnelling on
161
- // a long sweep through a dense scene). Grow by doubling and re-query until
162
- // both fit (deterministic queries → converges in one resize).
163
- let n_static, n_dynamic, n_total;
164
- for (;;) {
165
- n_static = bvh_query_user_data_overlaps_aabb(scratch_candidates, 0, system.staticBvh, swept_aabb);
166
- n_dynamic = bvh_query_user_data_overlaps_aabb(scratch_candidates, n_static, system.dynamicBvh, swept_aabb);
167
- n_total = n_static + n_dynamic;
168
- if (n_total <= scratch_candidates.length) break;
169
- scratch_candidates = new Uint32Array(Math.max(n_total, scratch_candidates.length * 2));
170
- }
171
- if (n_total === 0) return false;
172
-
173
- // ── 3. Narrowphase: per-candidate bisection ────────────────────
174
- //
175
- // Re-bind the swept shape's PosedShape once for shape + rotation;
176
- // we update `px/py/pz` per bisection midpoint without rerunning
177
- // setup (px/py/pz are public fields by contract).
178
- swept_posed.shape = shape;
179
- swept_posed.qx = rx; swept_posed.qy = ry; swept_posed.qz = rz; swept_posed.qw = rw;
180
-
181
- let best_t = tMax;
182
- let best_body_id = -1;
183
- let best_entity = -1;
184
-
185
- for (let i = 0; i < n_total; i++) {
186
- const body_id = scratch_candidates[i];
187
- const body_idx = body_id_index(body_id);
188
- const entity = system.entityOf(body_id);
189
- if (entity < 0) continue;
190
-
191
- const collider = system.__primary_collider(body_idx);
192
- if (collider === null) continue;
193
- if (!filter(entity, collider)) continue;
194
-
195
- const target_tr = system.__transforms[body_idx];
196
- candidate_posed.setup(collider.shape, target_tr.position, target_tr.rotation);
197
-
198
- // Already overlapping at t = 0? Return immediately — can't beat
199
- // this, and the bisection's "no overlap at lo, overlap at hi"
200
- // invariant doesn't hold.
201
- swept_posed.px = ox; swept_posed.py = oy; swept_posed.pz = oz;
202
- if (gjk(simplex_buf, swept_posed, candidate_posed)) {
203
- best_t = 0;
204
- best_body_id = body_id;
205
- best_entity = entity;
206
- break;
207
- }
208
-
209
- // ── Slab intersection: narrow the search interval analytically ─
210
- //
211
- // Compute the body's tight world AABB and intersect it with the
212
- // swept shape's AABB sliding along the sweep direction. The
213
- // result is the t-interval `[t_aabb_enter, t_aabb_exit]` during
214
- // which the two AABBs overlap. Outside this interval the actual
215
- // shapes can't overlap either (AABB is a superset of the
216
- // shape), so we get to skip all of [0, t_aabb_enter) and
217
- // (t_aabb_exit, best_t] without testing.
218
- //
219
- // This is the key to making `shapeCast` scale to long sweeps:
220
- // a 1 km cast of a 1 m sphere against another 1 m sphere has an
221
- // AABB-overlap window of 2 m (the sum of diameters along the
222
- // sweep axis), reducing the coarse-step grid from a 30 m
223
- // resolution (1000/32) to 6 cm (2/32).
224
- collider.shape.compute_bounding_box(target_local_aabb);
225
- aabb3_transform_oriented(
226
- target_world_aabb, 0,
227
- target_local_aabb[0], target_local_aabb[1], target_local_aabb[2],
228
- target_local_aabb[3], target_local_aabb[4], target_local_aabb[5],
229
- target_tr.position.x, target_tr.position.y, target_tr.position.z,
230
- target_tr.rotation.x, target_tr.rotation.y, target_tr.rotation.z, target_tr.rotation.w
231
- );
232
-
233
- let t_aabb_enter = -Infinity;
234
- let t_aabb_exit = Infinity;
235
- let skip_candidate = false;
236
- for (let ax = 0; ax < 3; ax++) {
237
- const init_min = initial_aabb[ax];
238
- const init_max = initial_aabb[ax + 3];
239
- const body_min = target_world_aabb[ax];
240
- const body_max = target_world_aabb[ax + 3];
241
- const d_ax = ax === 0 ? dx : (ax === 1 ? dy : dz);
242
- if (d_ax === 0) {
243
- // Static along this axis: AABBs must overlap in their
244
- // initial position or this candidate is unreachable.
245
- if (init_max < body_min || init_min > body_max) {
246
- skip_candidate = true;
247
- break;
248
- }
249
- continue;
250
- }
251
- // swept_min(t) = init_min + d·t, swept_max(t) = init_max + d·t.
252
- // Slab-enter: swept_max(t) = body_min → t = (body_min − init_max) / d
253
- // Slab-exit: swept_min(t) = body_max → t = (body_max − init_min) / d
254
- const t1 = (body_min - init_max) / d_ax;
255
- const t2 = (body_max - init_min) / d_ax;
256
- const lo = t1 < t2 ? t1 : t2;
257
- const hi = t1 < t2 ? t2 : t1;
258
- if (lo > t_aabb_enter) t_aabb_enter = lo;
259
- if (hi < t_aabb_exit) t_aabb_exit = hi;
260
- }
261
- if (skip_candidate) continue;
262
- if (t_aabb_enter > t_aabb_exit) continue;
263
-
264
- // Clamp to the relevant t-window: [0, best_t]. Anything beyond
265
- // best_t can't tighten the answer.
266
- const t_start = t_aabb_enter > 0 ? t_aabb_enter : 0;
267
- const t_end = t_aabb_exit < best_t ? t_aabb_exit : best_t;
268
- if (t_start >= t_end) continue;
269
-
270
- // Coarse-search within the narrowed interval to find any t for
271
- // which the shapes overlap (their AABBs do by construction; the
272
- // shapes themselves may not, e.g. two spheres passing alongside).
273
- const step_dt = (t_end - t_start) / COARSE_STEPS;
274
- let t_prev = t_start;
275
- let t_hi = -1;
276
- for (let s = 1; s <= COARSE_STEPS; s++) {
277
- const t = t_start + s * step_dt;
278
- swept_posed.px = ox + dx * t;
279
- swept_posed.py = oy + dy * t;
280
- swept_posed.pz = oz + dz * t;
281
- if (gjk(simplex_buf, swept_posed, candidate_posed)) {
282
- t_hi = t;
283
- break;
284
- }
285
- t_prev = t;
286
- }
287
- if (t_hi < 0) continue;
288
-
289
- // Bisect [t_prev, t_hi]: invariant is `gjk(t_lo) === false` and
290
- // `gjk(t_hi) === true`.
291
- let t_lo = t_prev;
292
- const stop_width = TOI_TOLERANCE * tMax;
293
- for (let bi = 0; bi < MAX_BISECTION && (t_hi - t_lo) > stop_width; bi++) {
294
- const t_mid = (t_lo + t_hi) * 0.5;
295
- swept_posed.px = ox + dx * t_mid;
296
- swept_posed.py = oy + dy * t_mid;
297
- swept_posed.pz = oz + dz * t_mid;
298
- if (gjk(simplex_buf, swept_posed, candidate_posed)) {
299
- t_hi = t_mid;
300
- } else {
301
- t_lo = t_mid;
302
- }
303
- }
304
-
305
- // Use t_lo (the just-SEPARATING side of the bisection) rather
306
- // than t_hi (just-overlapping). With the fixed GJK that no
307
- // longer flags 5 mm-clear gaps as overlap, the bisection is
308
- // tight; reporting t_lo gives kinematic callers a conservative
309
- // TOI — the swept shape at the reported moment is provably NOT
310
- // overlapping the target. The normal-probe below steps a few
311
- // mm past best_t to get a valid simplex for MPR.
312
- if (t_lo < best_t) {
313
- best_t = t_lo;
314
- best_body_id = body_id;
315
- best_entity = entity;
316
- }
317
- }
318
-
319
- if (best_body_id === -1) return false;
320
-
321
- const rp = result.position;
322
- const rn = result.normal;
323
-
324
- const swept_x = ox + dx * best_t;
325
- const swept_y = oy + dy * best_t;
326
- const swept_z = oz + dz * best_t;
327
-
328
- rp[0] = swept_x;
329
- rp[1] = swept_y;
330
- rp[2] = swept_z;
331
-
332
- // ── Contact-normal recovery via MPR ────────────────────────────
333
- //
334
- // Bisection converges with `swept_posed` somewhere within
335
- // `stop_width = TOI_TOLERANCE * tMax` of the true contact. At
336
- // exactly `best_t` the overlap depth is therefore sub-millimetre
337
- // on practical sweeps. EPA on smooth-vs-smooth supports at this
338
- // overlap can't tighten before its iteration cap and returns a
339
- // direction off by ~30° from truth. MPR is the better tool here:
340
- // it converges in 5-15 iterations on smooth surfaces, same MTV
341
- // output convention as EPA (direction = A's interior into B,
342
- // magnitude = depth).
343
- //
344
- // We still advance the swept centre by NORMAL_PROBE_OFFSET past
345
- // best_t (a few mm into the target) before sampling — the extra
346
- // overlap gives both MPR and the body-centre sign check a more
347
- // robust geometric basis. The reported `result.t` stays at
348
- // `best_t`; only the normal probe moves.
349
- //
350
- // Sign-validation: MPR's polytope can also settle on either side
351
- // of the origin for highly symmetric configurations, so we dot
352
- // against the body-centre axis and flip if needed (same pattern
353
- // as `narrowphase_step`'s EPA path). The stored normal is the
354
- // target's outward surface normal — `B → A` direction — i.e. the
355
- // negated (validated) MTV.
356
- const NORMAL_PROBE_OFFSET = 0.01;
357
- const probe_t = best_t + NORMAL_PROBE_OFFSET;
358
- const probe_x = ox + dx * probe_t;
359
- const probe_y = oy + dy * probe_t;
360
- const probe_z = oz + dz * probe_t;
361
- const best_body_idx = body_id_index(best_body_id);
362
- const best_collider = system.__primary_collider(best_body_idx);
363
- let normal_x = -dx, normal_y = -dy, normal_z = -dz;
364
- if (best_collider !== null) {
365
- const best_tr = system.__transforms[best_body_idx];
366
- candidate_posed.setup(best_collider.shape, best_tr.position, best_tr.rotation);
367
- swept_posed.px = probe_x;
368
- swept_posed.py = probe_y;
369
- swept_posed.pz = probe_z;
370
- if (mpr(mpr_result, 0, swept_posed, candidate_posed)) {
371
- let ex = mpr_result[0], ey = mpr_result[1], ez = mpr_result[2];
372
- const depth = Math.sqrt(ex * ex + ey * ey + ez * ez);
373
- if (depth > 0 && Number.isFinite(depth)) {
374
- const ab_x = best_tr.position.x - probe_x;
375
- const ab_y = best_tr.position.y - probe_y;
376
- const ab_z = best_tr.position.z - probe_z;
377
- if (ex * ab_x + ey * ab_y + ez * ab_z < 0) {
378
- ex = -ex; ey = -ey; ez = -ez;
379
- }
380
- const inv = 1 / depth;
381
- normal_x = -ex * inv;
382
- normal_y = -ey * inv;
383
- normal_z = -ez * inv;
384
- }
385
- }
386
- }
387
-
388
- rn[0] = normal_x; rn[1] = normal_y; rn[2] = normal_z;
389
- result.t = best_t;
390
- result.entity = best_entity;
391
- result.body_id = best_body_id;
392
- return true;
393
- }
1
+ import { assert } from "../../../core/assert.js";
2
+ import { bvh_query_user_data_overlaps_aabb } from "../../../core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.js";
3
+ import { returnTrue } from "../../../core/function/returnTrue.js";
4
+ import { aabb3_transform_oriented } from "../../../core/geom/3d/aabb/aabb3_transform_oriented.js";
5
+ import { body_id_index } from "../body/BodyStorage.js";
6
+ import { gjk } from "../../../core/geom/3d/gjk/gjk.js";
7
+ import { mpr } from "../../../core/geom/3d/gjk/mpr.js";
8
+ import { PosedShape3D } from "../../../core/geom/3d/shape/PosedShape3D.js";
9
+
10
+ /**
11
+ * Bisection halts when the search interval is below this fraction of
12
+ * the sweep length. With `MAX_BISECTION = 32` and a unit-length sweep
13
+ * the achieved precision is 1 / 2³² (well below any practical
14
+ * world-scale tolerance), but we cap on relative tolerance so a
15
+ * 10 m sweep doesn't insist on sub-micron precision.
16
+ * @type {number}
17
+ */
18
+ const TOI_TOLERANCE = 1e-4;
19
+
20
+ /**
21
+ * Maximum bisection iterations. `log2(1 / TOI_TOLERANCE)` is enough
22
+ * for any practical sweep; this is the hard upper bound to prevent
23
+ * pathological inputs (NaN ray, etc.) from hanging the query.
24
+ * @type {number}
25
+ */
26
+ const MAX_BISECTION = 32;
27
+
28
+ /**
29
+ * Coarse linear-search resolution for finding *any* overlap moment
30
+ * along the per-candidate AABB-overlap interval (NOT the full sweep
31
+ * see `aabb_overlap_interval` for the analytical narrowing that runs
32
+ * upstream). 32 substeps over the AABB-overlap window is dense enough
33
+ * for any sweep where the shape's smallest extent is on the order of
34
+ * its AABB's extent (true for spheres / boxes / capsules); the slab
35
+ * intersection keeps that interval small even for kilometre-scale
36
+ * sweeps, so this isn't the limit it would otherwise be.
37
+ * @type {number}
38
+ */
39
+ const COARSE_STEPS = 32;
40
+
41
+ const swept_aabb = new Float64Array(6);
42
+ const local_aabb = new Float64Array(6);
43
+ const initial_aabb = new Float64Array(6);
44
+ const target_local_aabb = new Float64Array(6);
45
+ const target_world_aabb = new Float64Array(6);
46
+
47
+ // GJK simplex buffer (used to detect overlap during the bisection).
48
+ const simplex_buf = new Float64Array(12);
49
+
50
+ // Scratch for MPR's MTV output same vec3 convention as EPA: direction
51
+ // is "A's interior into B" with the magnitude being the depth. We use
52
+ // MPR for the contact-normal recovery at the kiss point because it
53
+ // converges reliably on smooth-vs-smooth supports where EPA hits its
54
+ // iteration cap before tightening (sphere-vs-sphere shallow overlap).
55
+ const mpr_result = new Float64Array(3);
56
+
57
+ /**
58
+ * Long-lived PosedShape3D adapters for the swept shape and the
59
+ * candidate's collider. Both are re-bound per query — the swept one
60
+ * also gets its position field re-written every bisection step
61
+ * without re-running `setup()`, since shape and rotation are
62
+ * constant through the sweep.
63
+ */
64
+ const swept_posed = new PosedShape3D();
65
+ const candidate_posed = new PosedShape3D();
66
+
67
+ /**
68
+ * Buffer for the union of static-BVH and dynamic-BVH candidates that
69
+ * overlap the swept AABB. Grows by doubling on the rare overflow.
70
+ * @type {Uint32Array}
71
+ */
72
+ let scratch_candidates = new Uint32Array(64);
73
+
74
+ /**
75
+ * Sweep a convex shape along a ray and find the first body it would
76
+ * hit. Used by character controllers (sweep a capsule along intended
77
+ * movement to find blockers), high-speed projectile movement (avoid
78
+ * tunnelling without paying for full per-body CCD), and any kinematic
79
+ * "where would this body end up if I tried to move it?" query.
80
+ *
81
+ * Pipeline:
82
+ * 1. Build the swept AABB: the shape's local-frame AABB rotated
83
+ * into world by `rotation`, translated to `ray.origin`, then
84
+ * stretched along `ray.direction * ray.tMax`.
85
+ * 2. Query both broadphase BVHs (static + dynamic) for leaves whose
86
+ * AABB overlaps the swept volume.
87
+ * 3. For each candidate, bisect the [0, best_t] interval for the
88
+ * smallest `t` at which the swept shape overlaps the candidate's
89
+ * collider. GJK on each midpoint.
90
+ *
91
+ * Picking `best_t` (rather than always running the full [0, tMax]
92
+ * bisection) is the early-termination optimisation: once we have a
93
+ * hit at some t, no later candidate can produce a smaller TOI by
94
+ * being checked at its full [0, tMax] interval.
95
+ *
96
+ * Output on hit:
97
+ * - `result.t` sweep distance to impact (in the same units as
98
+ * `ray.direction`'s magnitude; for a unit-direction ray, this is
99
+ * metres).
100
+ * - `result.position` `ray.origin + t * ray.direction`, i.e. the
101
+ * centre of the swept shape at the moment of first contact. NOT
102
+ * a point on the target's surface; that would need narrowphase
103
+ * refinement which the broadphase-only architecture doesn't have
104
+ * wired up yet.
105
+ * - `result.normal` target surface's outward normal at the kiss
106
+ * point (unit length), computed by running GJK + EPA against the
107
+ * just-overlapping configuration at the TOI. Falls back to
108
+ * `-ray.direction` on the rare case EPA degenerates (NaN / zero
109
+ * depth) see comment near the EPA call.
110
+ * - `result.entity` / `result.body_id` — the hit body.
111
+ *
112
+ * Output on miss: untouched; same convention as `raycast`.
113
+ *
114
+ * @param {PhysicsSystem} system
115
+ * @param {Ray3|{origin_x:number,origin_y:number,origin_z:number,direction_x:number,direction_y:number,direction_z:number,tMax:number}} ray
116
+ * origin + unit direction + `tMax`. Only the named accessors are read, so a
117
+ * plain double-precision ray-like works `Ray3` is Float32Array-backed and
118
+ * quantises large-coordinate sweeps (the CCD pass passes a f64 ray-like)
119
+ * @param {AbstractShape3D} shape shape being swept, in its local frame
120
+ * @param {{x:number,y:number,z:number,w:number}} rotation fixed orientation
121
+ * @param {PhysicsSurfacePoint} result populated on hit; untouched on miss
122
+ * @param {(entity:number, collider:Collider, body_id:number)=>boolean} [filter]
123
+ * mandatory in contract; defaults to {@link returnTrue}. Receives the
124
+ * candidate body's entity, primary collider, and packed body id (the id
125
+ * distinguishes bodies when colliders live on child entities)
126
+ * @param {boolean} [skip_initial_overlaps=false] how a candidate ALREADY
127
+ * overlapping the swept shape at `t = 0` is treated. `false` (kinematic
128
+ * "can I move?" semantics): the cast is blocked where it stands — report a
129
+ * hit at `t = 0`. `true` (CCD semantics): such a candidate is a resting /
130
+ * sliding contact the discrete solver already owns, NOT a tunnelling
131
+ * threat — skip it and keep scanning the remaining candidates for real
132
+ * blockers along the sweep. Without the skip, one resting contact at the
133
+ * start of the sweep would blind the cast to every other obstacle.
134
+ * @returns {boolean}
135
+ */
136
+ export function shape_cast(system, ray, shape, rotation, result, filter = returnTrue, skip_initial_overlaps = false) {
137
+ const ox = ray.origin_x;
138
+ const oy = ray.origin_y;
139
+ const oz = ray.origin_z;
140
+ const dx = ray.direction_x;
141
+ const dy = ray.direction_y;
142
+ const dz = ray.direction_z;
143
+ const tMax = ray.tMax;
144
+ // A fresh Ray3 defaults tMax to Infinity, which a sweep cannot use (the
145
+ // swept AABB and the bisection interval would be unbounded). Loud in dev
146
+ // silently returning false for the DEFAULT ray construction reads as
147
+ // "nothing there" and is a debugging trap; prod degrades to a miss.
148
+ assert.ok(Number.isFinite(tMax) && tMax > 0,
149
+ `shape_cast: ray.tMax must be a positive finite sweep length, got ${tMax}`);
150
+ if (!(tMax > 0) || !Number.isFinite(tMax)) return false;
151
+
152
+ const rx = rotation.x, ry = rotation.y, rz = rotation.z, rw = rotation.w;
153
+
154
+ // ── 1. Swept AABB ──────────────────────────────────────────────
155
+ shape.compute_bounding_box(local_aabb);
156
+ // Rotation around ray.origin gives the shape's initial AABB in
157
+ // world space.
158
+ aabb3_transform_oriented(
159
+ initial_aabb, 0,
160
+ local_aabb[0], local_aabb[1], local_aabb[2],
161
+ local_aabb[3], local_aabb[4], local_aabb[5],
162
+ ox, oy, oz,
163
+ rx, ry, rz, rw
164
+ );
165
+ // Stretch by the sweep displacement. Positive direction components
166
+ // push the +face out; negative components push the −face out.
167
+ swept_aabb[0] = initial_aabb[0];
168
+ swept_aabb[1] = initial_aabb[1];
169
+ swept_aabb[2] = initial_aabb[2];
170
+ swept_aabb[3] = initial_aabb[3];
171
+ swept_aabb[4] = initial_aabb[4];
172
+ swept_aabb[5] = initial_aabb[5];
173
+ if (dx > 0) swept_aabb[3] += dx * tMax; else swept_aabb[0] += dx * tMax;
174
+ if (dy > 0) swept_aabb[4] += dy * tMax; else swept_aabb[1] += dy * tMax;
175
+ if (dz > 0) swept_aabb[5] += dz * tMax; else swept_aabb[2] += dz * tMax;
176
+
177
+ // ── 2. Broadphase: gather candidates from both trees ───────────
178
+ // The BVH query returns the TRUE overlap count and silently drops writes past
179
+ // the buffer end. An undersized buffer would make the narrowphase loop read
180
+ // `undefined` candidates and silently MISS the true nearest hit (tunnelling on
181
+ // a long sweep through a dense scene). Grow by doubling and re-query until
182
+ // both fit (deterministic queries → converges in one resize).
183
+ let n_static, n_dynamic, n_total;
184
+ for (;;) {
185
+ n_static = bvh_query_user_data_overlaps_aabb(scratch_candidates, 0, system.staticBvh, swept_aabb);
186
+ n_dynamic = bvh_query_user_data_overlaps_aabb(scratch_candidates, n_static, system.dynamicBvh, swept_aabb);
187
+ n_total = n_static + n_dynamic;
188
+ if (n_total <= scratch_candidates.length) break;
189
+ scratch_candidates = new Uint32Array(Math.max(n_total, scratch_candidates.length * 2));
190
+ }
191
+ if (n_total === 0) return false;
192
+
193
+ // ── 3. Narrowphase: per-candidate bisection ────────────────────
194
+ //
195
+ // Re-bind the swept shape's PosedShape3D once for shape + rotation;
196
+ // we update `px/py/pz` per bisection midpoint without rerunning
197
+ // setup (px/py/pz are public fields by contract).
198
+ swept_posed.shape = shape;
199
+ swept_posed.qx = rx; swept_posed.qy = ry; swept_posed.qz = rz; swept_posed.qw = rw;
200
+
201
+ let best_t = tMax;
202
+ let best_body_id = -1;
203
+ let best_entity = -1;
204
+
205
+ for (let i = 0; i < n_total; i++) {
206
+ const body_id = scratch_candidates[i];
207
+ const body_idx = body_id_index(body_id);
208
+ const entity = system.entityOf(body_id);
209
+ if (entity < 0) continue;
210
+
211
+ const collider = system.__primary_collider(body_idx);
212
+ if (collider === null) continue;
213
+ if (!filter(entity, collider, body_id)) continue;
214
+
215
+ const target_tr = system.__transforms[body_idx];
216
+ candidate_posed.setup(collider.shape, target_tr.position, target_tr.rotation);
217
+
218
+ // Already overlapping at t = 0? The bisection's "no overlap at lo,
219
+ // overlap at hi" invariant doesn't hold for this candidate. Either
220
+ // it IS the answer (kinematic semantics: blocked where it stands,
221
+ // t = 0 nothing can beat that, stop scanning) or it is a resting
222
+ // contact to step over (CCD semantics: skip THIS candidate only;
223
+ // the remaining candidates must still be scanned for real blockers).
224
+ swept_posed.px = ox; swept_posed.py = oy; swept_posed.pz = oz;
225
+ if (gjk(simplex_buf, swept_posed, candidate_posed)) {
226
+ if (skip_initial_overlaps) continue;
227
+ best_t = 0;
228
+ best_body_id = body_id;
229
+ best_entity = entity;
230
+ break;
231
+ }
232
+
233
+ // ── Slab intersection: narrow the search interval analytically ─
234
+ //
235
+ // Compute the body's tight world AABB and intersect it with the
236
+ // swept shape's AABB sliding along the sweep direction. The
237
+ // result is the t-interval `[t_aabb_enter, t_aabb_exit]` during
238
+ // which the two AABBs overlap. Outside this interval the actual
239
+ // shapes can't overlap either (AABB is a superset of the
240
+ // shape), so we get to skip all of [0, t_aabb_enter) and
241
+ // (t_aabb_exit, best_t] without testing.
242
+ //
243
+ // This is the key to making `shapeCast` scale to long sweeps:
244
+ // a 1 km cast of a 1 m sphere against another 1 m sphere has an
245
+ // AABB-overlap window of 2 m (the sum of diameters along the
246
+ // sweep axis), reducing the coarse-step grid from a 30 m
247
+ // resolution (1000/32) to 6 cm (2/32).
248
+ collider.shape.compute_bounding_box(target_local_aabb);
249
+ aabb3_transform_oriented(
250
+ target_world_aabb, 0,
251
+ target_local_aabb[0], target_local_aabb[1], target_local_aabb[2],
252
+ target_local_aabb[3], target_local_aabb[4], target_local_aabb[5],
253
+ target_tr.position.x, target_tr.position.y, target_tr.position.z,
254
+ target_tr.rotation.x, target_tr.rotation.y, target_tr.rotation.z, target_tr.rotation.w
255
+ );
256
+
257
+ let t_aabb_enter = -Infinity;
258
+ let t_aabb_exit = Infinity;
259
+ let skip_candidate = false;
260
+ for (let ax = 0; ax < 3; ax++) {
261
+ const init_min = initial_aabb[ax];
262
+ const init_max = initial_aabb[ax + 3];
263
+ const body_min = target_world_aabb[ax];
264
+ const body_max = target_world_aabb[ax + 3];
265
+ const d_ax = ax === 0 ? dx : (ax === 1 ? dy : dz);
266
+ if (d_ax === 0) {
267
+ // Static along this axis: AABBs must overlap in their
268
+ // initial position or this candidate is unreachable.
269
+ if (init_max < body_min || init_min > body_max) {
270
+ skip_candidate = true;
271
+ break;
272
+ }
273
+ continue;
274
+ }
275
+ // swept_min(t) = init_min + d·t, swept_max(t) = init_max + d·t.
276
+ // Slab-enter: swept_max(t) = body_min → t = (body_min init_max) / d
277
+ // Slab-exit: swept_min(t) = body_max → t = (body_max init_min) / d
278
+ const t1 = (body_min - init_max) / d_ax;
279
+ const t2 = (body_max - init_min) / d_ax;
280
+ const lo = t1 < t2 ? t1 : t2;
281
+ const hi = t1 < t2 ? t2 : t1;
282
+ if (lo > t_aabb_enter) t_aabb_enter = lo;
283
+ if (hi < t_aabb_exit) t_aabb_exit = hi;
284
+ }
285
+ if (skip_candidate) continue;
286
+ if (t_aabb_enter > t_aabb_exit) continue;
287
+
288
+ // Clamp to the relevant t-window: [0, best_t]. Anything beyond
289
+ // best_t can't tighten the answer.
290
+ const t_start = t_aabb_enter > 0 ? t_aabb_enter : 0;
291
+ const t_end = t_aabb_exit < best_t ? t_aabb_exit : best_t;
292
+ if (t_start >= t_end) continue;
293
+
294
+ // Coarse-search within the narrowed interval to find any t for
295
+ // which the shapes overlap (their AABBs do by construction; the
296
+ // shapes themselves may not, e.g. two spheres passing alongside).
297
+ const step_dt = (t_end - t_start) / COARSE_STEPS;
298
+ let t_prev = t_start;
299
+ let t_hi = -1;
300
+ for (let s = 1; s <= COARSE_STEPS; s++) {
301
+ const t = t_start + s * step_dt;
302
+ swept_posed.px = ox + dx * t;
303
+ swept_posed.py = oy + dy * t;
304
+ swept_posed.pz = oz + dz * t;
305
+ if (gjk(simplex_buf, swept_posed, candidate_posed)) {
306
+ t_hi = t;
307
+ break;
308
+ }
309
+ t_prev = t;
310
+ }
311
+ if (t_hi < 0) continue;
312
+
313
+ // Bisect [t_prev, t_hi]: invariant is `gjk(t_lo) === false` and
314
+ // `gjk(t_hi) === true`.
315
+ let t_lo = t_prev;
316
+ const stop_width = TOI_TOLERANCE * tMax;
317
+ for (let bi = 0; bi < MAX_BISECTION && (t_hi - t_lo) > stop_width; bi++) {
318
+ const t_mid = (t_lo + t_hi) * 0.5;
319
+ swept_posed.px = ox + dx * t_mid;
320
+ swept_posed.py = oy + dy * t_mid;
321
+ swept_posed.pz = oz + dz * t_mid;
322
+ if (gjk(simplex_buf, swept_posed, candidate_posed)) {
323
+ t_hi = t_mid;
324
+ } else {
325
+ t_lo = t_mid;
326
+ }
327
+ }
328
+
329
+ // Use t_lo (the just-SEPARATING side of the bisection) rather
330
+ // than t_hi (just-overlapping). With the fixed GJK that no
331
+ // longer flags 5 mm-clear gaps as overlap, the bisection is
332
+ // tight; reporting t_lo gives kinematic callers a conservative
333
+ // TOI — the swept shape at the reported moment is provably NOT
334
+ // overlapping the target. The normal-probe below steps a few
335
+ // mm past best_t to get a valid simplex for MPR.
336
+ if (t_lo < best_t) {
337
+ best_t = t_lo;
338
+ best_body_id = body_id;
339
+ best_entity = entity;
340
+ }
341
+ }
342
+
343
+ if (best_body_id === -1) return false;
344
+
345
+ const rp = result.position;
346
+ const rn = result.normal;
347
+
348
+ const swept_x = ox + dx * best_t;
349
+ const swept_y = oy + dy * best_t;
350
+ const swept_z = oz + dz * best_t;
351
+
352
+ rp[0] = swept_x;
353
+ rp[1] = swept_y;
354
+ rp[2] = swept_z;
355
+
356
+ // ── Contact-normal recovery via MPR ────────────────────────────
357
+ //
358
+ // Bisection converges with `swept_posed` somewhere within
359
+ // `stop_width = TOI_TOLERANCE * tMax` of the true contact. At
360
+ // exactly `best_t` the overlap depth is therefore sub-millimetre
361
+ // on practical sweeps. EPA on smooth-vs-smooth supports at this
362
+ // overlap can't tighten before its iteration cap and returns a
363
+ // direction off by ~30° from truth. MPR is the better tool here:
364
+ // it converges in 5-15 iterations on smooth surfaces, same MTV
365
+ // output convention as EPA (direction = A's interior into B,
366
+ // magnitude = depth).
367
+ //
368
+ // We still advance the swept centre by NORMAL_PROBE_OFFSET past
369
+ // best_t (a few mm into the target) before sampling — the extra
370
+ // overlap gives both MPR and the body-centre sign check a more
371
+ // robust geometric basis. The reported `result.t` stays at
372
+ // `best_t`; only the normal probe moves.
373
+ //
374
+ // Sign-validation: MPR's polytope can also settle on either side
375
+ // of the origin for highly symmetric configurations, so we dot
376
+ // against the body-centre axis and flip if needed (same pattern
377
+ // as `narrowphase_step`'s EPA path). The stored normal is the
378
+ // target's outward surface normal `B A` direction — i.e. the
379
+ // negated (validated) MTV.
380
+ const NORMAL_PROBE_OFFSET = 0.01;
381
+ const probe_t = best_t + NORMAL_PROBE_OFFSET;
382
+ const probe_x = ox + dx * probe_t;
383
+ const probe_y = oy + dy * probe_t;
384
+ const probe_z = oz + dz * probe_t;
385
+ const best_body_idx = body_id_index(best_body_id);
386
+ const best_collider = system.__primary_collider(best_body_idx);
387
+ let normal_x = -dx, normal_y = -dy, normal_z = -dz;
388
+ if (best_collider !== null) {
389
+ const best_tr = system.__transforms[best_body_idx];
390
+ candidate_posed.setup(best_collider.shape, best_tr.position, best_tr.rotation);
391
+ swept_posed.px = probe_x;
392
+ swept_posed.py = probe_y;
393
+ swept_posed.pz = probe_z;
394
+ if (mpr(mpr_result, 0, swept_posed, candidate_posed)) {
395
+ let ex = mpr_result[0], ey = mpr_result[1], ez = mpr_result[2];
396
+ const depth = Math.sqrt(ex * ex + ey * ey + ez * ez);
397
+ if (depth > 0 && Number.isFinite(depth)) {
398
+ const ab_x = best_tr.position.x - probe_x;
399
+ const ab_y = best_tr.position.y - probe_y;
400
+ const ab_z = best_tr.position.z - probe_z;
401
+ if (ex * ab_x + ey * ab_y + ez * ab_z < 0) {
402
+ ex = -ex; ey = -ey; ez = -ez;
403
+ }
404
+ const inv = 1 / depth;
405
+ normal_x = -ex * inv;
406
+ normal_y = -ey * inv;
407
+ normal_z = -ez * inv;
408
+ }
409
+ }
410
+ }
411
+
412
+ rn[0] = normal_x; rn[1] = normal_y; rn[2] = normal_z;
413
+ result.t = best_t;
414
+ result.entity = best_entity;
415
+ result.body_id = best_body_id;
416
+ return true;
417
+ }