@woosh/meep-engine 2.138.20 → 2.140.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 (584) hide show
  1. package/package.json +1 -1
  2. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.d.ts +3 -3
  3. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.d.ts.map +1 -1
  4. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.js +4 -4
  5. package/src/core/collection/PairUint32Map.d.ts +100 -0
  6. package/src/core/collection/PairUint32Map.d.ts.map +1 -0
  7. package/src/core/collection/PairUint32Map.js +321 -0
  8. package/src/core/collection/Uint32Map.d.ts +119 -0
  9. package/src/core/collection/Uint32Map.d.ts.map +1 -0
  10. package/src/core/collection/Uint32Map.js +345 -0
  11. package/src/core/collection/array/array_shuffle.d.ts +10 -3
  12. package/src/core/collection/array/array_shuffle.d.ts.map +1 -1
  13. package/src/core/collection/array/array_shuffle.js +27 -22
  14. package/src/core/collection/heap/FibonacciHeap.d.ts +195 -0
  15. package/src/core/collection/heap/FibonacciHeap.d.ts.map +1 -0
  16. package/src/core/collection/heap/FibonacciHeap.js +586 -0
  17. package/src/core/collection/heap/Uint32Heap.js +1 -1
  18. package/src/core/collection/heap/Uint32Heap4.d.ts +169 -0
  19. package/src/core/collection/heap/Uint32Heap4.d.ts.map +1 -0
  20. package/src/core/collection/heap/Uint32Heap4.js +490 -0
  21. package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts +30 -0
  22. package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts.map +1 -0
  23. package/src/core/geom/3d/aabb/aabb3_transform_oriented.js +93 -0
  24. package/src/core/geom/3d/line/line3_closest_points_segment_segment.d.ts +27 -0
  25. package/src/core/geom/3d/line/line3_closest_points_segment_segment.d.ts.map +1 -0
  26. package/src/core/geom/3d/line/line3_closest_points_segment_segment.js +88 -0
  27. package/src/core/geom/3d/quaternion/quat3_to_matrix3.d.ts +54 -0
  28. package/src/core/geom/3d/quaternion/quat3_to_matrix3.d.ts.map +1 -0
  29. package/src/core/geom/3d/quaternion/quat3_to_matrix3.js +69 -0
  30. package/src/core/geom/3d/shape/AbstractShape3D.d.ts +24 -2
  31. package/src/core/geom/3d/shape/AbstractShape3D.d.ts.map +1 -1
  32. package/src/core/geom/3d/shape/AbstractShape3D.js +24 -1
  33. package/src/core/geom/3d/shape/BoxShape3D.d.ts +61 -0
  34. package/src/core/geom/3d/shape/BoxShape3D.d.ts.map +1 -0
  35. package/src/core/geom/3d/shape/BoxShape3D.js +158 -0
  36. package/src/core/geom/3d/shape/CapsuleShape3D.d.ts +11 -0
  37. package/src/core/geom/3d/shape/CapsuleShape3D.d.ts.map +1 -1
  38. package/src/core/geom/3d/shape/CapsuleShape3D.js +12 -0
  39. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +148 -0
  40. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -0
  41. package/src/core/geom/3d/shape/HeightMapShape3D.js +451 -0
  42. package/src/core/geom/3d/shape/MeshShape3D.d.ts +210 -0
  43. package/src/core/geom/3d/shape/MeshShape3D.d.ts.map +1 -0
  44. package/src/core/geom/3d/shape/MeshShape3D.js +593 -0
  45. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  46. package/src/core/geom/3d/shape/TransformedShape3D.js +46 -2
  47. package/src/core/geom/3d/shape/Triangle3D.d.ts +95 -0
  48. package/src/core/geom/3d/shape/Triangle3D.d.ts.map +1 -0
  49. package/src/core/geom/3d/shape/Triangle3D.js +318 -0
  50. package/src/core/geom/3d/shape/UnionShape3D.js +13 -0
  51. package/src/core/geom/3d/shape/UnitCubeShape3D.d.ts +37 -9
  52. package/src/core/geom/3d/shape/UnitCubeShape3D.d.ts.map +1 -1
  53. package/src/core/geom/3d/shape/UnitCubeShape3D.js +45 -98
  54. package/src/core/geom/3d/shape/UnitSphereShape3D.d.ts +10 -0
  55. package/src/core/geom/3d/shape/UnitSphereShape3D.d.ts.map +1 -1
  56. package/src/core/geom/3d/shape/UnitSphereShape3D.js +11 -0
  57. package/src/core/geom/3d/shape/shape_mesh_from_geometry.d.ts +30 -0
  58. package/src/core/geom/3d/shape/shape_mesh_from_geometry.d.ts.map +1 -0
  59. package/src/core/geom/3d/shape/shape_mesh_from_geometry.js +64 -0
  60. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.d.ts +61 -0
  61. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.d.ts.map +1 -0
  62. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.js +148 -0
  63. package/src/core/geom/3d/tetrahedra/compute_tetrahedral_mesh_from_surface.d.ts +39 -0
  64. package/src/core/geom/3d/tetrahedra/compute_tetrahedral_mesh_from_surface.d.ts.map +1 -0
  65. package/src/core/geom/3d/tetrahedra/compute_tetrahedral_mesh_from_surface.js +147 -0
  66. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.d.ts +15 -0
  67. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.d.ts.map +1 -0
  68. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.js +22 -0
  69. package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.d.ts +2 -0
  70. package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.d.ts.map +1 -0
  71. package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.js +671 -0
  72. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.d.ts +28 -0
  73. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.d.ts.map +1 -0
  74. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.js +48 -0
  75. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.d.ts +26 -0
  76. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.d.ts.map +1 -0
  77. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.js +222 -0
  78. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_find_tets_around_edge.d.ts +34 -0
  79. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_find_tets_around_edge.d.ts.map +1 -0
  80. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_find_tets_around_edge.js +146 -0
  81. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.d.ts +36 -0
  82. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.d.ts.map +1 -0
  83. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.js +232 -0
  84. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.d.ts +33 -0
  85. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.d.ts.map +1 -0
  86. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.js +255 -0
  87. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.d.ts +68 -0
  88. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.d.ts.map +1 -0
  89. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.js +387 -0
  90. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts +35 -0
  91. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts.map +1 -0
  92. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.js +140 -0
  93. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts +31 -0
  94. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts.map +1 -0
  95. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.js +97 -0
  96. package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.d.ts +32 -0
  97. package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.d.ts.map +1 -0
  98. package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.js +66 -0
  99. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.d.ts +41 -0
  100. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.d.ts.map +1 -1
  101. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.js +124 -13
  102. package/src/core/geom/3d/topology/struct/binary/BinaryTopology.d.ts +134 -0
  103. package/src/core/geom/3d/topology/struct/binary/BinaryTopology.d.ts.map +1 -1
  104. package/src/core/geom/3d/topology/struct/binary/BinaryTopology.js +276 -3
  105. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts +17 -0
  106. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts.map +1 -0
  107. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.js +135 -0
  108. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compact.d.ts +14 -0
  109. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compact.d.ts.map +1 -0
  110. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compact.js +177 -0
  111. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_decouple.d.ts.map +1 -1
  112. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_decouple.js +20 -4
  113. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
  114. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +5 -3
  115. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.d.ts.map +1 -1
  116. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.js +9 -0
  117. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_get_or_create.d.ts.map +1 -1
  118. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_get_or_create.js +21 -45
  119. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill.d.ts.map +1 -1
  120. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill.js +7 -1
  121. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts +8 -6
  122. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts.map +1 -1
  123. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.js +8 -6
  124. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.d.ts +22 -0
  125. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.d.ts.map +1 -0
  126. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.js +73 -0
  127. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.d.ts.map +1 -1
  128. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.js +51 -1
  129. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.d.ts +10 -0
  130. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.d.ts.map +1 -0
  131. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.js +42 -0
  132. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.d.ts +28 -0
  133. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.d.ts.map +1 -0
  134. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.js +227 -0
  135. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_walk_boundary_loops.d.ts +13 -0
  136. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_walk_boundary_loops.d.ts.map +1 -0
  137. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_walk_boundary_loops.js +108 -0
  138. package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.d.ts +11 -0
  139. package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.d.ts.map +1 -0
  140. package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.js +20 -0
  141. package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.d.ts +20 -0
  142. package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.d.ts.map +1 -0
  143. package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.js +38 -0
  144. package/src/core/geom/3d/triangle/v3_compute_triangle_normal.d.ts +2 -2
  145. package/src/core/geom/3d/triangle/v3_compute_triangle_normal.d.ts.map +1 -1
  146. package/src/core/geom/3d/triangle/v3_compute_triangle_normal.js +1 -1
  147. package/src/core/geom/vec3/v3_dot_array_array.d.ts +3 -3
  148. package/src/core/geom/vec3/v3_dot_array_array.d.ts.map +1 -1
  149. package/src/core/geom/vec3/v3_dot_array_array.js +2 -2
  150. package/src/core/geom/vec3/v3_negate_array.d.ts +3 -3
  151. package/src/core/geom/vec3/v3_negate_array.d.ts.map +1 -1
  152. package/src/core/geom/vec3/v3_negate_array.js +2 -2
  153. package/src/core/geom/vec3/v3_quat3_apply.d.ts +29 -0
  154. package/src/core/geom/vec3/v3_quat3_apply.d.ts.map +1 -0
  155. package/src/core/geom/vec3/v3_quat3_apply.js +39 -0
  156. package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts +30 -0
  157. package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts.map +1 -0
  158. package/src/core/geom/vec3/v3_quat3_apply_inverse.js +41 -0
  159. package/src/core/geom/vec3/v3_triple_cross_product.d.ts +32 -0
  160. package/src/core/geom/vec3/v3_triple_cross_product.d.ts.map +1 -0
  161. package/src/core/geom/vec3/v3_triple_cross_product.js +45 -0
  162. package/src/core/graph/csr/CSRGraph.d.ts +168 -0
  163. package/src/core/graph/csr/CSRGraph.d.ts.map +1 -0
  164. package/src/core/graph/csr/CSRGraph.js +319 -0
  165. package/src/core/graph/metis/cluster_mesh_metis.d.ts +12 -0
  166. package/src/core/graph/metis/cluster_mesh_metis.d.ts.map +1 -1
  167. package/src/core/graph/metis/cluster_mesh_metis.js +12 -0
  168. package/src/core/graph/metis/metis.d.ts +19 -0
  169. package/src/core/graph/metis/metis.d.ts.map +1 -1
  170. package/src/core/graph/metis/metis.js +20 -0
  171. package/src/core/graph/metis/metis_cluster_bs.d.ts +11 -0
  172. package/src/core/graph/metis/metis_cluster_bs.d.ts.map +1 -1
  173. package/src/core/graph/metis/metis_cluster_bs.js +11 -0
  174. package/src/core/graph/metis/metis_options.d.ts +17 -2
  175. package/src/core/graph/metis/metis_options.d.ts.map +1 -1
  176. package/src/core/graph/metis/metis_options.js +17 -2
  177. package/src/core/graph/metis/native/MetisGraph.d.ts +144 -0
  178. package/src/core/graph/metis/native/MetisGraph.d.ts.map +1 -0
  179. package/src/core/graph/metis/native/MetisGraph.js +212 -0
  180. package/src/core/graph/metis/native/bisection/BisectionScratch.d.ts +72 -0
  181. package/src/core/graph/metis/native/bisection/BisectionScratch.d.ts.map +1 -0
  182. package/src/core/graph/metis/native/bisection/BisectionScratch.js +101 -0
  183. package/src/core/graph/metis/native/bisection/bisect_graph.d.ts +37 -0
  184. package/src/core/graph/metis/native/bisection/bisect_graph.d.ts.map +1 -0
  185. package/src/core/graph/metis/native/bisection/bisect_graph.js +100 -0
  186. package/src/core/graph/metis/native/bisection/compute_2way_params.d.ts +15 -0
  187. package/src/core/graph/metis/native/bisection/compute_2way_params.d.ts.map +1 -0
  188. package/src/core/graph/metis/native/bisection/compute_2way_params.js +84 -0
  189. package/src/core/graph/metis/native/bisection/fm_2way.d.ts +30 -0
  190. package/src/core/graph/metis/native/bisection/fm_2way.d.ts.map +1 -0
  191. package/src/core/graph/metis/native/bisection/fm_2way.js +290 -0
  192. package/src/core/graph/metis/native/bisection/grow_bisection.d.ts +23 -0
  193. package/src/core/graph/metis/native/bisection/grow_bisection.d.ts.map +1 -0
  194. package/src/core/graph/metis/native/bisection/grow_bisection.js +137 -0
  195. package/src/core/graph/metis/native/bisection/split_graph_two_way.d.ts +28 -0
  196. package/src/core/graph/metis/native/bisection/split_graph_two_way.d.ts.map +1 -0
  197. package/src/core/graph/metis/native/bisection/split_graph_two_way.js +119 -0
  198. package/src/core/graph/metis/native/coarsen/coarsen_graph.d.ts +20 -0
  199. package/src/core/graph/metis/native/coarsen/coarsen_graph.d.ts.map +1 -0
  200. package/src/core/graph/metis/native/coarsen/coarsen_graph.js +94 -0
  201. package/src/core/graph/metis/native/coarsen/create_coarse_graph.d.ts +24 -0
  202. package/src/core/graph/metis/native/coarsen/create_coarse_graph.d.ts.map +1 -0
  203. package/src/core/graph/metis/native/coarsen/create_coarse_graph.js +158 -0
  204. package/src/core/graph/metis/native/coarsen/match_shem.d.ts +41 -0
  205. package/src/core/graph/metis/native/coarsen/match_shem.d.ts.map +1 -0
  206. package/src/core/graph/metis/native/coarsen/match_shem.js +175 -0
  207. package/src/core/graph/metis/native/initial/initial_kway_bfs.d.ts +24 -0
  208. package/src/core/graph/metis/native/initial/initial_kway_bfs.d.ts.map +1 -0
  209. package/src/core/graph/metis/native/initial/initial_kway_bfs.js +122 -0
  210. package/src/core/graph/metis/native/initial/initial_kway_recursive_bisection.d.ts +29 -0
  211. package/src/core/graph/metis/native/initial/initial_kway_recursive_bisection.d.ts.map +1 -0
  212. package/src/core/graph/metis/native/initial/initial_kway_recursive_bisection.js +170 -0
  213. package/src/core/graph/metis/native/metis_partition_kway.d.ts +41 -0
  214. package/src/core/graph/metis/native/metis_partition_kway.d.ts.map +1 -0
  215. package/src/core/graph/metis/native/metis_partition_kway.js +126 -0
  216. package/src/core/graph/metis/native/refine/IndexedFloatMaxHeap.d.ts +62 -0
  217. package/src/core/graph/metis/native/refine/IndexedFloatMaxHeap.d.ts.map +1 -0
  218. package/src/core/graph/metis/native/refine/IndexedFloatMaxHeap.js +261 -0
  219. package/src/core/graph/metis/native/refine/RefinementScratch.d.ts +45 -0
  220. package/src/core/graph/metis/native/refine/RefinementScratch.d.ts.map +1 -0
  221. package/src/core/graph/metis/native/refine/RefinementScratch.js +53 -0
  222. package/src/core/graph/metis/native/refine/compute_kway_params.d.ts +18 -0
  223. package/src/core/graph/metis/native/refine/compute_kway_params.d.ts.map +1 -0
  224. package/src/core/graph/metis/native/refine/compute_kway_params.js +138 -0
  225. package/src/core/graph/metis/native/refine/fm_kway.d.ts +63 -0
  226. package/src/core/graph/metis/native/refine/fm_kway.d.ts.map +1 -0
  227. package/src/core/graph/metis/native/refine/fm_kway.js +462 -0
  228. package/src/core/graph/metis/native/refine/project_kway.d.ts +22 -0
  229. package/src/core/graph/metis/native/refine/project_kway.d.ts.map +1 -0
  230. package/src/core/graph/metis/native/refine/project_kway.js +43 -0
  231. package/src/core/graph/metis/native/refine/refine_kway.d.ts +34 -0
  232. package/src/core/graph/metis/native/refine/refine_kway.d.ts.map +1 -0
  233. package/src/core/graph/metis/native/refine/refine_kway.js +43 -0
  234. package/src/core/math/linalg/eigen/matrix_householder_in_place.d.ts +2 -2
  235. package/src/core/math/linalg/eigen/matrix_householder_in_place.js +2 -2
  236. package/src/core/math/linalg/eigen/matrix_qr_in_place.d.ts +6 -4
  237. package/src/core/math/linalg/eigen/matrix_qr_in_place.d.ts.map +1 -1
  238. package/src/core/math/linalg/eigen/matrix_qr_in_place.js +69 -23
  239. package/src/engine/EngineHarness.d.ts +3 -1
  240. package/src/engine/EngineHarness.d.ts.map +1 -1
  241. package/src/engine/EngineHarness.js +3 -0
  242. package/src/engine/control/first-person/DESIGN.md +30 -6
  243. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +563 -0
  244. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +115 -9
  245. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
  246. package/src/engine/control/first-person/FirstPersonPlayerController.js +211 -176
  247. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +601 -8
  248. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
  249. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +349 -8
  250. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts +319 -23
  251. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
  252. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +1789 -799
  253. package/src/engine/control/first-person/TODO.md +173 -0
  254. package/src/engine/control/first-person/abilities/Ability.d.ts +101 -0
  255. package/src/engine/control/first-person/abilities/Ability.d.ts.map +1 -0
  256. package/src/engine/control/first-person/abilities/Ability.js +119 -0
  257. package/src/engine/control/first-person/abilities/AbilitySet.d.ts +86 -0
  258. package/src/engine/control/first-person/abilities/AbilitySet.d.ts.map +1 -0
  259. package/src/engine/control/first-person/abilities/AbilitySet.js +185 -0
  260. package/src/engine/control/first-person/abilities/LedgeGrab.d.ts +62 -0
  261. package/src/engine/control/first-person/abilities/LedgeGrab.d.ts.map +1 -0
  262. package/src/engine/control/first-person/abilities/LedgeGrab.js +199 -0
  263. package/src/engine/control/first-person/abilities/Mantle.d.ts +45 -0
  264. package/src/engine/control/first-person/abilities/Mantle.d.ts.map +1 -0
  265. package/src/engine/control/first-person/abilities/Mantle.js +188 -0
  266. package/src/engine/control/first-person/abilities/Slide.d.ts +33 -0
  267. package/src/engine/control/first-person/abilities/Slide.d.ts.map +1 -0
  268. package/src/engine/control/first-person/abilities/Slide.js +166 -0
  269. package/src/engine/control/first-person/abilities/WallJump.d.ts +45 -0
  270. package/src/engine/control/first-person/abilities/WallJump.d.ts.map +1 -0
  271. package/src/engine/control/first-person/abilities/WallJump.js +131 -0
  272. package/src/engine/control/first-person/abilities/WallRun.d.ts +44 -0
  273. package/src/engine/control/first-person/abilities/WallRun.d.ts.map +1 -0
  274. package/src/engine/control/first-person/abilities/WallRun.js +180 -0
  275. package/src/engine/control/first-person/composer/EyeOffsetStack.d.ts +49 -0
  276. package/src/engine/control/first-person/composer/EyeOffsetStack.d.ts.map +1 -0
  277. package/src/engine/control/first-person/composer/EyeOffsetStack.js +60 -0
  278. package/src/engine/control/first-person/mastery/BreathRhythmEvaluator.d.ts +100 -0
  279. package/src/engine/control/first-person/mastery/BreathRhythmEvaluator.d.ts.map +1 -0
  280. package/src/engine/control/first-person/mastery/BreathRhythmEvaluator.js +133 -0
  281. package/src/engine/control/first-person/mastery/DecisionPoint.d.ts +10 -0
  282. package/src/engine/control/first-person/mastery/DecisionPoint.d.ts.map +1 -0
  283. package/src/engine/control/first-person/mastery/DecisionPoint.js +30 -0
  284. package/src/engine/control/first-person/mastery/FootAsymmetryTurnEvaluator.d.ts +61 -0
  285. package/src/engine/control/first-person/mastery/FootAsymmetryTurnEvaluator.d.ts.map +1 -0
  286. package/src/engine/control/first-person/mastery/FootAsymmetryTurnEvaluator.js +109 -0
  287. package/src/engine/control/first-person/mastery/MasteryEvaluator.d.ts +40 -0
  288. package/src/engine/control/first-person/mastery/MasteryEvaluator.d.ts.map +1 -0
  289. package/src/engine/control/first-person/mastery/MasteryEvaluator.js +45 -0
  290. package/src/engine/control/first-person/mastery/MasteryScore.d.ts +68 -0
  291. package/src/engine/control/first-person/mastery/MasteryScore.d.ts.map +1 -0
  292. package/src/engine/control/first-person/mastery/MasteryScore.js +100 -0
  293. package/src/engine/control/first-person/mastery/MasterySet.d.ts +60 -0
  294. package/src/engine/control/first-person/mastery/MasterySet.d.ts.map +1 -0
  295. package/src/engine/control/first-person/mastery/MasterySet.js +86 -0
  296. package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.d.ts +58 -0
  297. package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.d.ts.map +1 -0
  298. package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.js +83 -0
  299. package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.d.ts +69 -0
  300. package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.d.ts.map +1 -0
  301. package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.js +109 -0
  302. package/src/engine/control/first-person/math/Spring.d.ts +56 -0
  303. package/src/engine/control/first-person/math/Spring.d.ts.map +1 -0
  304. package/src/engine/control/first-person/math/Spring.js +71 -0
  305. package/src/engine/control/first-person/math/computeLRCBreathRate.d.ts +26 -0
  306. package/src/engine/control/first-person/math/computeLRCBreathRate.d.ts.map +1 -0
  307. package/src/engine/control/first-person/math/computeLRCBreathRate.js +41 -0
  308. package/src/engine/control/first-person/math/computeMassRatios.d.ts +35 -0
  309. package/src/engine/control/first-person/math/computeMassRatios.d.ts.map +1 -0
  310. package/src/engine/control/first-person/math/computeMassRatios.js +44 -0
  311. package/src/engine/control/first-person/pose/FirstPersonPose.d.ts +31 -1
  312. package/src/engine/control/first-person/pose/FirstPersonPose.d.ts.map +1 -1
  313. package/src/engine/control/first-person/pose/FirstPersonPose.js +49 -3
  314. package/src/engine/control/first-person/pose/FirstPersonPosture.d.ts +7 -0
  315. package/src/engine/control/first-person/pose/FirstPersonPosture.d.ts.map +1 -0
  316. package/src/engine/control/first-person/pose/FirstPersonPosture.js +27 -0
  317. package/src/engine/control/first-person/prototype_first_person_controller.js +637 -120
  318. package/src/engine/control/first-person/sensors/FirstPersonSensors.d.ts +58 -0
  319. package/src/engine/control/first-person/sensors/FirstPersonSensors.d.ts.map +1 -0
  320. package/src/engine/control/first-person/sensors/FirstPersonSensors.js +77 -0
  321. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts +80 -0
  322. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts.map +1 -0
  323. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.js +196 -0
  324. package/src/engine/control/first-person/test/buildTestPlayer.d.ts +20 -0
  325. package/src/engine/control/first-person/test/buildTestPlayer.d.ts.map +1 -0
  326. package/src/engine/control/first-person/test/buildTestPlayer.js +36 -0
  327. package/src/engine/graphics/camera/testClippingPlaneComputation.js +0 -2
  328. package/src/engine/graphics/ecs/light/Light.d.ts.map +1 -1
  329. package/src/engine/graphics/ecs/light/Light.js +27 -0
  330. package/src/engine/graphics/ecs/light/LightSystem.js +1 -1
  331. package/src/engine/graphics/ecs/path/PathDisplaySystem.d.ts.map +1 -1
  332. package/src/engine/graphics/ecs/path/testPathDisplaySystem.js +0 -2
  333. package/src/engine/graphics/ecs/path/tube/prototypeAnimatedPathMask.js +0 -2
  334. package/src/engine/graphics/geometry/CapsuleGeometry.d.ts +42 -0
  335. package/src/engine/graphics/geometry/CapsuleGeometry.d.ts.map +1 -0
  336. package/src/engine/graphics/geometry/CapsuleGeometry.js +171 -0
  337. package/src/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +0 -2
  338. package/src/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +0 -2
  339. package/src/engine/graphics/render/visibility/hiz/prototypeHiZ.js +0 -2
  340. package/src/engine/navigation/grid/find_path_on_grid_astar.d.ts.map +1 -1
  341. package/src/engine/navigation/grid/find_path_on_grid_astar.js +11 -2
  342. package/src/engine/navigation/mesh/bt_mesh_face_find_path.d.ts.map +1 -1
  343. package/src/engine/navigation/mesh/bt_mesh_face_find_path.js +11 -1
  344. package/src/engine/physics/BULLET_REVIEW.md +945 -0
  345. package/src/engine/physics/CANNON_REVIEW.md +1300 -0
  346. package/src/engine/physics/JOLT_REVIEW.md +913 -0
  347. package/src/engine/physics/PLAN.md +461 -0
  348. package/src/engine/physics/RAPIER_REVIEW.md +934 -0
  349. package/src/engine/physics/REVIEW_001_ACTION_PLAN.md +642 -0
  350. package/src/engine/physics/body/BodyStorage.d.ts +187 -0
  351. package/src/engine/physics/body/BodyStorage.d.ts.map +1 -0
  352. package/src/engine/physics/body/BodyStorage.js +427 -0
  353. package/src/engine/physics/broadphase/PairList.d.ts +62 -0
  354. package/src/engine/physics/broadphase/PairList.d.ts.map +1 -0
  355. package/src/engine/physics/broadphase/PairList.js +97 -0
  356. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts +16 -0
  357. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts.map +1 -0
  358. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +61 -0
  359. package/src/engine/physics/broadphase/generate_pairs.d.ts +38 -0
  360. package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -0
  361. package/src/engine/physics/broadphase/generate_pairs.js +101 -0
  362. package/src/engine/physics/contact/ManifoldStore.d.ts +299 -0
  363. package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -0
  364. package/src/engine/physics/contact/ManifoldStore.js +608 -0
  365. package/src/engine/physics/ecs/BodyKind.d.ts +23 -0
  366. package/src/engine/physics/ecs/BodyKind.d.ts.map +1 -0
  367. package/src/engine/physics/ecs/BodyKind.js +24 -0
  368. package/src/engine/physics/ecs/Collider.d.ts +98 -0
  369. package/src/engine/physics/ecs/Collider.d.ts.map +1 -0
  370. package/src/engine/physics/ecs/Collider.js +136 -0
  371. package/src/engine/physics/ecs/ColliderFlags.d.ts +14 -0
  372. package/src/engine/physics/ecs/ColliderFlags.d.ts.map +1 -0
  373. package/src/engine/physics/ecs/ColliderFlags.js +15 -0
  374. package/src/engine/physics/ecs/ColliderObserverSystem.d.ts +58 -0
  375. package/src/engine/physics/ecs/ColliderObserverSystem.d.ts.map +1 -0
  376. package/src/engine/physics/ecs/ColliderObserverSystem.js +103 -0
  377. package/src/engine/physics/ecs/ColliderSerializationAdapter.d.ts +25 -0
  378. package/src/engine/physics/ecs/ColliderSerializationAdapter.d.ts.map +1 -0
  379. package/src/engine/physics/ecs/ColliderSerializationAdapter.js +37 -0
  380. package/src/engine/physics/ecs/PhysicsEvents.d.ts +15 -0
  381. package/src/engine/physics/ecs/PhysicsEvents.d.ts.map +1 -0
  382. package/src/engine/physics/ecs/PhysicsEvents.js +16 -0
  383. package/src/engine/physics/ecs/PhysicsSystem.d.ts +628 -0
  384. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -0
  385. package/src/engine/physics/ecs/PhysicsSystem.js +1301 -0
  386. package/src/engine/physics/ecs/RigidBody.d.ts +197 -0
  387. package/src/engine/physics/ecs/RigidBody.d.ts.map +1 -0
  388. package/src/engine/physics/ecs/RigidBody.js +240 -0
  389. package/src/engine/physics/ecs/RigidBodyFlags.d.ts +21 -0
  390. package/src/engine/physics/ecs/RigidBodyFlags.d.ts.map +1 -0
  391. package/src/engine/physics/ecs/RigidBodyFlags.js +22 -0
  392. package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts +28 -0
  393. package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts.map +1 -0
  394. package/src/engine/physics/ecs/RigidBodySerializationAdapter.js +81 -0
  395. package/src/engine/physics/ecs/SleepState.d.ts +11 -0
  396. package/src/engine/physics/ecs/SleepState.d.ts.map +1 -0
  397. package/src/engine/physics/ecs/SleepState.js +12 -0
  398. package/src/engine/physics/events/ContactEventBuffer.d.ts +46 -0
  399. package/src/engine/physics/events/ContactEventBuffer.d.ts.map +1 -0
  400. package/src/engine/physics/events/ContactEventBuffer.js +83 -0
  401. package/src/engine/physics/events/diff_manifolds.d.ts +25 -0
  402. package/src/engine/physics/events/diff_manifolds.d.ts.map +1 -0
  403. package/src/engine/physics/events/diff_manifolds.js +50 -0
  404. package/src/engine/physics/fluid/FluidField.d.ts +294 -16
  405. package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
  406. package/src/engine/physics/fluid/FluidField.js +510 -66
  407. package/src/engine/physics/fluid/FluidSimulator.d.ts +188 -5
  408. package/src/engine/physics/fluid/FluidSimulator.d.ts.map +1 -1
  409. package/src/engine/physics/fluid/FluidSimulator.js +456 -95
  410. package/src/engine/physics/fluid/SliceVisualiser.d.ts +29 -6
  411. package/src/engine/physics/fluid/SliceVisualiser.d.ts.map +1 -1
  412. package/src/engine/physics/fluid/SliceVisualiser.js +190 -165
  413. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts +154 -0
  414. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -0
  415. package/src/engine/physics/fluid/ecs/FluidComponent.js +238 -0
  416. package/src/engine/physics/fluid/ecs/FluidEffectorsComponent.d.ts +45 -0
  417. package/src/engine/physics/fluid/ecs/FluidEffectorsComponent.d.ts.map +1 -0
  418. package/src/engine/physics/fluid/ecs/FluidEffectorsComponent.js +89 -0
  419. package/src/engine/physics/fluid/ecs/FluidSystem.d.ts +107 -0
  420. package/src/engine/physics/fluid/ecs/FluidSystem.d.ts.map +1 -0
  421. package/src/engine/physics/fluid/ecs/FluidSystem.js +278 -0
  422. package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts +62 -1
  423. package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts.map +1 -1
  424. package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +81 -6
  425. package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts +17 -4
  426. package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts.map +1 -1
  427. package/src/engine/physics/fluid/effector/GlobalFluidEffector.js +105 -12
  428. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.d.ts +43 -0
  429. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.d.ts.map +1 -0
  430. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.js +210 -0
  431. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts +62 -1
  432. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts.map +1 -1
  433. package/src/engine/physics/fluid/effector/WakeFluidEffector.js +302 -8
  434. package/src/engine/physics/fluid/prototype.js +102 -91
  435. package/src/engine/physics/fluid/solver/optimal_sor_omega.d.ts +33 -0
  436. package/src/engine/physics/fluid/solver/optimal_sor_omega.d.ts.map +1 -0
  437. package/src/engine/physics/fluid/solver/optimal_sor_omega.js +41 -0
  438. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts +20 -5
  439. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts.map +1 -1
  440. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.js +60 -38
  441. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts +25 -4
  442. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts.map +1 -1
  443. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.js +93 -73
  444. package/src/engine/physics/fluid/solver/v3_grid_apply_scalar_advection.d.ts +23 -0
  445. package/src/engine/physics/fluid/solver/v3_grid_apply_scalar_advection.d.ts.map +1 -0
  446. package/src/engine/physics/fluid/solver/v3_grid_apply_scalar_advection.js +60 -0
  447. package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.d.ts +23 -0
  448. package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.d.ts.map +1 -0
  449. package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.js +68 -0
  450. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts +30 -0
  451. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts.map +1 -0
  452. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.js +66 -0
  453. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_uniform.d.ts +26 -0
  454. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_uniform.d.ts.map +1 -0
  455. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_uniform.js +113 -0
  456. package/src/engine/physics/fluid/solver/v3_grid_shift_in_place.d.ts +30 -0
  457. package/src/engine/physics/fluid/solver/v3_grid_shift_in_place.d.ts.map +1 -0
  458. package/src/engine/physics/fluid/solver/v3_grid_shift_in_place.js +107 -0
  459. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts +49 -0
  460. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts.map +1 -0
  461. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.js +126 -0
  462. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts +93 -0
  463. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts.map +1 -0
  464. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.js +424 -0
  465. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts +48 -0
  466. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -0
  467. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +92 -0
  468. package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts +6 -6
  469. package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts.map +1 -1
  470. package/src/engine/physics/gjk/expanding_polytope_algorithm.js +76 -32
  471. package/src/engine/physics/gjk/gjk.d.ts +28 -2
  472. package/src/engine/physics/gjk/gjk.d.ts.map +1 -1
  473. package/src/engine/physics/gjk/gjk.js +421 -378
  474. package/src/engine/physics/gjk/minkowski_support.d.ts +37 -0
  475. package/src/engine/physics/gjk/minkowski_support.d.ts.map +1 -0
  476. package/src/engine/physics/gjk/minkowski_support.js +75 -0
  477. package/src/engine/physics/gjk/mpr.d.ts +56 -0
  478. package/src/engine/physics/gjk/mpr.d.ts.map +1 -0
  479. package/src/engine/physics/gjk/mpr.js +344 -0
  480. package/src/engine/physics/inertia/world_inverse_inertia.d.ts +44 -0
  481. package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -0
  482. package/src/engine/physics/inertia/world_inverse_inertia.js +77 -0
  483. package/src/engine/physics/integration/integrate_position.d.ts +34 -0
  484. package/src/engine/physics/integration/integrate_position.d.ts.map +1 -0
  485. package/src/engine/physics/integration/integrate_position.js +79 -0
  486. package/src/engine/physics/integration/integrate_velocity.d.ts +55 -0
  487. package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -0
  488. package/src/engine/physics/integration/integrate_velocity.js +160 -0
  489. package/src/engine/physics/integration/quat_integrate.d.ts +27 -0
  490. package/src/engine/physics/integration/quat_integrate.d.ts.map +1 -0
  491. package/src/engine/physics/integration/quat_integrate.js +62 -0
  492. package/src/engine/physics/island/IslandBuilder.d.ts +167 -0
  493. package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -0
  494. package/src/engine/physics/island/IslandBuilder.js +411 -0
  495. package/src/engine/physics/island/union_find.d.ts +51 -0
  496. package/src/engine/physics/island/union_find.d.ts.map +1 -0
  497. package/src/engine/physics/island/union_find.js +76 -0
  498. package/src/engine/physics/narrowphase/PosedShape.d.ts +51 -0
  499. package/src/engine/physics/narrowphase/PosedShape.d.ts.map +1 -0
  500. package/src/engine/physics/narrowphase/PosedShape.js +108 -0
  501. package/src/engine/physics/narrowphase/box_box_manifold.d.ts +32 -0
  502. package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -0
  503. package/src/engine/physics/narrowphase/box_box_manifold.js +639 -0
  504. package/src/engine/physics/narrowphase/box_triangle_contact.d.ts +30 -0
  505. package/src/engine/physics/narrowphase/box_triangle_contact.d.ts.map +1 -0
  506. package/src/engine/physics/narrowphase/box_triangle_contact.js +811 -0
  507. package/src/engine/physics/narrowphase/capsule_contacts.d.ts +122 -0
  508. package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -0
  509. package/src/engine/physics/narrowphase/capsule_contacts.js +462 -0
  510. package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts +71 -0
  511. package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts.map +1 -0
  512. package/src/engine/physics/narrowphase/capsule_triangle_contact.js +375 -0
  513. package/src/engine/physics/narrowphase/compute_penetration.d.ts +91 -0
  514. package/src/engine/physics/narrowphase/compute_penetration.d.ts.map +1 -0
  515. package/src/engine/physics/narrowphase/compute_penetration.js +396 -0
  516. package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts +35 -0
  517. package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts.map +1 -0
  518. package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.js +80 -0
  519. package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.d.ts +31 -0
  520. package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.d.ts.map +1 -0
  521. package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.js +55 -0
  522. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts +42 -0
  523. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts.map +1 -0
  524. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.js +204 -0
  525. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts +42 -0
  526. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts.map +1 -0
  527. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.js +94 -0
  528. package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.d.ts +37 -0
  529. package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.d.ts.map +1 -0
  530. package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.js +37 -0
  531. package/src/engine/physics/narrowphase/narrowphase_step.d.ts +17 -0
  532. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -0
  533. package/src/engine/physics/narrowphase/narrowphase_step.js +1422 -0
  534. package/src/engine/physics/narrowphase/sphere_box_contact.d.ts +38 -0
  535. package/src/engine/physics/narrowphase/sphere_box_contact.d.ts.map +1 -0
  536. package/src/engine/physics/narrowphase/sphere_box_contact.js +123 -0
  537. package/src/engine/physics/narrowphase/sphere_sphere_contact.d.ts +26 -0
  538. package/src/engine/physics/narrowphase/sphere_sphere_contact.d.ts.map +1 -0
  539. package/src/engine/physics/narrowphase/sphere_sphere_contact.js +51 -0
  540. package/src/engine/physics/narrowphase/sphere_triangle_contact.d.ts +48 -0
  541. package/src/engine/physics/narrowphase/sphere_triangle_contact.d.ts.map +1 -0
  542. package/src/engine/physics/narrowphase/sphere_triangle_contact.js +143 -0
  543. package/src/engine/physics/queries/PhysicsSurfacePoint.d.ts +83 -0
  544. package/src/engine/physics/queries/PhysicsSurfacePoint.d.ts.map +1 -0
  545. package/src/engine/physics/queries/PhysicsSurfacePoint.js +100 -0
  546. package/src/engine/physics/queries/overlap_shape.d.ts +51 -0
  547. package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -0
  548. package/src/engine/physics/queries/overlap_shape.js +183 -0
  549. package/src/engine/physics/queries/raycast.d.ts +20 -0
  550. package/src/engine/physics/queries/raycast.d.ts.map +1 -0
  551. package/src/engine/physics/queries/raycast.js +249 -0
  552. package/src/engine/physics/queries/shape_cast.d.ts +56 -0
  553. package/src/engine/physics/queries/shape_cast.d.ts.map +1 -0
  554. package/src/engine/physics/queries/shape_cast.js +387 -0
  555. package/src/engine/physics/solver/friction_cone.d.ts +16 -0
  556. package/src/engine/physics/solver/friction_cone.d.ts.map +1 -0
  557. package/src/engine/physics/solver/friction_cone.js +37 -0
  558. package/src/engine/physics/solver/solve_contacts.d.ts +122 -0
  559. package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -0
  560. package/src/engine/physics/solver/solve_contacts.js +1016 -0
  561. package/src/core/geom/3d/topology/struct/binary/io/edge/OrderedEdge.d.ts +0 -34
  562. package/src/core/geom/3d/topology/struct/binary/io/edge/OrderedEdge.d.ts.map +0 -1
  563. package/src/core/geom/3d/topology/struct/binary/io/edge/OrderedEdge.js +0 -66
  564. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_calc_edges.d.ts +0 -2
  565. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_calc_edges.d.ts.map +0 -1
  566. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_calc_edges.js +0 -54
  567. package/src/core/geom/3d/topology/struct/binary/io/edge/get_or_create_edge_map.d.ts +0 -2
  568. package/src/core/geom/3d/topology/struct/binary/io/edge/get_or_create_edge_map.d.ts.map +0 -1
  569. package/src/core/geom/3d/topology/struct/binary/io/edge/get_or_create_edge_map.js +0 -26
  570. package/src/engine/ecs/components/Motion.d.ts +0 -21
  571. package/src/engine/ecs/components/Motion.d.ts.map +0 -1
  572. package/src/engine/ecs/components/Motion.js +0 -27
  573. package/src/engine/ecs/components/MotionSerializationAdapter.d.ts +0 -20
  574. package/src/engine/ecs/components/MotionSerializationAdapter.d.ts.map +0 -1
  575. package/src/engine/ecs/components/MotionSerializationAdapter.js +0 -26
  576. package/src/engine/ecs/systems/MotionSystem.d.ts +0 -9
  577. package/src/engine/ecs/systems/MotionSystem.d.ts.map +0 -1
  578. package/src/engine/ecs/systems/MotionSystem.js +0 -29
  579. package/src/engine/physics/fluid/Fluid.d.ts +0 -26
  580. package/src/engine/physics/fluid/Fluid.d.ts.map +0 -1
  581. package/src/engine/physics/fluid/Fluid.js +0 -221
  582. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_reverse.d.ts +0 -7
  583. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_reverse.d.ts.map +0 -1
  584. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_reverse.js +0 -8
@@ -0,0 +1,1301 @@
1
+ import { assert } from "../../../core/assert.js";
2
+ import { BVH } from "../../../core/bvh2/bvh3/BVH.js";
3
+ import Signal from "../../../core/events/signal/Signal.js";
4
+ import Vector3 from "../../../core/geom/Vector3.js";
5
+ import { ResourceAccessKind } from "../../../core/model/ResourceAccessKind.js";
6
+ import { ResourceAccessSpecification } from "../../../core/model/ResourceAccessSpecification.js";
7
+ import { System } from "../../ecs/System.js";
8
+ import { Transform } from "../../ecs/transform/Transform.js";
9
+ import { body_id_index, BodyStorage } from "../body/BodyStorage.js";
10
+ import { aabb3_transform_oriented } from "../../../core/geom/3d/aabb/aabb3_transform_oriented.js";
11
+ import { compute_fat_world_aabb } from "../broadphase/compute_fat_world_aabb.js";
12
+ import { generate_pairs } from "../broadphase/generate_pairs.js";
13
+ import { PairList } from "../broadphase/PairList.js";
14
+ import { CONTACT_STRIDE, ManifoldStore } from "../contact/ManifoldStore.js";
15
+ import { ContactEventBuffer, ContactEventKind } from "../events/ContactEventBuffer.js";
16
+ import { diff_manifolds } from "../events/diff_manifolds.js";
17
+ import { integrate_position } from "../integration/integrate_position.js";
18
+ import { integrate_velocity_forces, integrate_velocity_gravity } from "../integration/integrate_velocity.js";
19
+ import { IslandBuilder } from "../island/IslandBuilder.js";
20
+ import { narrowphase_step } from "../narrowphase/narrowphase_step.js";
21
+ import { overlap_shape as overlap_shape_query } from "../queries/overlap_shape.js";
22
+ import { raycast as raycast_query } from "../queries/raycast.js";
23
+ import { shape_cast as shape_cast_query } from "../queries/shape_cast.js";
24
+ import { returnTrue } from "../../../core/function/returnTrue.js";
25
+ import {
26
+ prepare_contacts,
27
+ refresh_contacts,
28
+ warm_start_contacts,
29
+ solve_velocity,
30
+ apply_restitution,
31
+ solve_position,
32
+ } from "../solver/solve_contacts.js";
33
+ import { world_inverse_inertia_apply } from "../inertia/world_inverse_inertia.js";
34
+ import { PhysicsEvents } from "./PhysicsEvents.js";
35
+
36
+ /**
37
+ * Scratch for {@link applyImpulseAt}'s angular delta calculation.
38
+ * @type {Float64Array}
39
+ */
40
+ const scratch_angular_delta = new Float64Array(3);
41
+ import { BodyKind } from "./BodyKind.js";
42
+ import { Collider, COLLIDER_UNBOUND } from "./Collider.js";
43
+ import { RIGID_BODY_UNALLOCATED, RigidBody } from "./RigidBody.js";
44
+ import { RigidBodyFlags } from "./RigidBodyFlags.js";
45
+ import { SleepState } from "./SleepState.js";
46
+
47
+ /**
48
+ * Reusable scratch buffer for world-AABB construction so the link path is
49
+ * allocation-free in steady state.
50
+ * @type {Float64Array}
51
+ */
52
+ const scratch_world_aabb = new Float64Array(6);
53
+
54
+ /**
55
+ * Reusable scratch buffer for the local AABB returned by
56
+ * {@link AbstractShape3D#compute_bounding_box}.
57
+ * @type {Float64Array}
58
+ */
59
+ const scratch_local_aabb = new Float64Array(6);
60
+
61
+ /**
62
+ * Rigid-body physics system.
63
+ *
64
+ * v1 scope: pool + active list + two BVHs (static / dynamic), Transform sync
65
+ * contract, and the user-facing API surface (gravity, force / impulse, layer
66
+ * filtering, wake / sleep, contact filter). The per-step simulation pipeline
67
+ * (broadphase pair generation, narrowphase, solver, islands, sleep test,
68
+ * contact-event emission) is built on top of this skeleton in subsequent
69
+ * iterations.
70
+ *
71
+ * Dependency tuple is `(RigidBody, Collider, Transform)` — every body has
72
+ * exactly one collider on the same entity. Compound bodies via child collider
73
+ * entities are an extension point handled by a follow-up sub-observer.
74
+ *
75
+ * @author Alex Goldring
76
+ * @copyright Company Named Limited (c) 2026
77
+ */
78
+ export class PhysicsSystem extends System {
79
+
80
+ constructor() {
81
+ super();
82
+
83
+ this.dependencies = [RigidBody, Transform];
84
+
85
+ this.components_used = [
86
+ ResourceAccessSpecification.from(RigidBody, ResourceAccessKind.Read | ResourceAccessKind.Write),
87
+ ResourceAccessSpecification.from(Collider, ResourceAccessKind.Read),
88
+ ResourceAccessSpecification.from(Transform, ResourceAccessKind.Read | ResourceAccessKind.Write),
89
+ ];
90
+
91
+ /**
92
+ * @type {BodyStorage}
93
+ */
94
+ this.storage = new BodyStorage();
95
+
96
+ /**
97
+ * @type {BVH}
98
+ */
99
+ this.staticBvh = new BVH();
100
+
101
+ /**
102
+ * @type {BVH}
103
+ */
104
+ this.dynamicBvh = new BVH();
105
+
106
+ /**
107
+ * Persistent contact-manifold cache. One slot per active pair.
108
+ * @type {ManifoldStore}
109
+ */
110
+ this.manifolds = new ManifoldStore();
111
+
112
+ /**
113
+ * Per-frame list of broadphase-overlapping pairs (canonical
114
+ * `(min, max)`). Cleared at the top of each step.
115
+ * @type {PairList}
116
+ */
117
+ this.pairs = new PairList();
118
+
119
+ /**
120
+ * Per-frame contact-event buffer. Populated by the manifold diff
121
+ * pass at end-of-step and consumed by the dispatch pass.
122
+ * @type {ContactEventBuffer}
123
+ */
124
+ this.contactEvents = new ContactEventBuffer();
125
+
126
+ /**
127
+ * Per-frame island partitioning of the awake-body + contact graph.
128
+ * Rebuilt after narrowphase, consumed by the solver (and, in the
129
+ * follow-up slice, by the per-island atomic sleep test). Bodies
130
+ * static and kinematic act as constraint anchors and do not enlarge
131
+ * islands.
132
+ * @type {IslandBuilder}
133
+ */
134
+ this.islands = new IslandBuilder();
135
+
136
+ /**
137
+ * Velocity-squared threshold below which a body is eligible to start
138
+ * accumulating sleep time. Combined linear + angular kinetic-ish
139
+ * metric: `vx²+vy²+vz² + ωx²+ωy²+ωz²`. Default 0.01 corresponds to
140
+ * ~0.1 m/s linear or ~0.1 rad/s angular.
141
+ * @type {number}
142
+ */
143
+ this.sleepVelocitySqrThreshold = 0.01;
144
+
145
+ /**
146
+ * Seconds of below-threshold motion before a body is moved to the
147
+ * sleeping set. Box2D default is 0.5 s.
148
+ * @type {number}
149
+ */
150
+ this.sleepTimeThreshold = 0.5;
151
+
152
+ /**
153
+ * Number of TGS substeps per `fixedUpdate`. Each substep re-runs the
154
+ * velocity + position solve at `dt / substeps` against contacts whose
155
+ * penetration is re-derived analytically from the bodies' moved poses
156
+ * — narrowphase still runs once per outer step. Higher counts buy
157
+ * stack stability, high-mass-ratio robustness, and smoother
158
+ * trajectories at a near-linear solver cost (sleeping islands are
159
+ * unaffected — they never enter the loop).
160
+ *
161
+ * `1` reproduces the non-substepped (single-step) solve.
162
+ * @type {number}
163
+ */
164
+ this.substeps = 4;
165
+
166
+ /**
167
+ * Velocity iterations per substep. Lower than a single-step solver
168
+ * would need, because the substep loop revisits the contact set
169
+ * `substeps` times.
170
+ * @type {number}
171
+ */
172
+ this.velocityIterations = 4;
173
+
174
+ /**
175
+ * Position (split-impulse) iterations per substep.
176
+ * @type {number}
177
+ */
178
+ this.positionIterations = 1;
179
+
180
+ /**
181
+ * Reusable contact-event payload. Listeners must copy any fields they
182
+ * intend to retain past their own scope. Reset before each dispatch.
183
+ * @private
184
+ */
185
+ this.__contact_payload = {
186
+ entityA: -1,
187
+ entityB: -1,
188
+ kind: 0,
189
+ depth: 0,
190
+ normal: new Vector3(),
191
+ point: new Vector3(),
192
+ };
193
+
194
+ /**
195
+ * World gravity, m/s². Applied each step scaled by per-body gravityScale.
196
+ * @readonly
197
+ * @type {Vector3}
198
+ */
199
+ this.gravity = new Vector3(0, -9.81, 0);
200
+
201
+ /**
202
+ * Emitted at end-of-step for newly established contact pairs.
203
+ * @readonly
204
+ * @type {Signal}
205
+ */
206
+ this.onContactBegin = new Signal();
207
+
208
+ /**
209
+ * Emitted at end-of-step for contact pairs that persisted from the previous step.
210
+ * @readonly
211
+ * @type {Signal}
212
+ */
213
+ this.onContactStay = new Signal();
214
+
215
+ /**
216
+ * Emitted at end-of-step for contact pairs that disappeared.
217
+ * @readonly
218
+ * @type {Signal}
219
+ */
220
+ this.onContactEnd = new Signal();
221
+
222
+ /**
223
+ * Optional global contact filter. Called for each surviving broadphase
224
+ * pair; returning `false` discards the pair.
225
+ * @type {((entityA: number, entityB: number, colliderA: Collider, colliderB: Collider) => boolean) | null}
226
+ * @private
227
+ */
228
+ this.__contact_filter = null;
229
+
230
+ /**
231
+ * Per-body component side-tables indexed by body index (NOT packed id).
232
+ * Sparse arrays — populated at link, cleared at unlink. The hot loop
233
+ * iterates `storage.awake_at(i)` and dereferences these.
234
+ * @type {RigidBody[]}
235
+ */
236
+ this.__bodies = [];
237
+ /** @type {Transform[]} */
238
+ this.__transforms = [];
239
+
240
+ /**
241
+ * Per-body list of attached colliders. Each entry stores the
242
+ * Collider component, its world Transform, the entity that owns
243
+ * it (the body entity for same-entity attachments, a child entity
244
+ * for compound bodies), and the BVH leaf id assigned at attach
245
+ * time. A body may have zero or more attached colliders.
246
+ *
247
+ * @type {Array<Array<{collider: Collider, transform: Transform, entity: number, bvhNode: number}>>}
248
+ */
249
+ this.__body_collider_lists = [];
250
+
251
+ /**
252
+ * Per-body pseudo-velocity for the Catto split-impulse position
253
+ * pass (TGS Phase 1). Flat layout, 6 doubles per body slot index:
254
+ * `[lin.x, lin.y, lin.z, ang.x, ang.y, ang.z]`. Sized to
255
+ * `storage.high_water_mark * 6` at the top of each fixedUpdate
256
+ * and zeroed in place so unwritten slots contribute nothing to
257
+ * `integrate_position`.
258
+ *
259
+ * The solver writes during its position pass; `integrate_position`
260
+ * reads and folds into the pose update on the same tick, then
261
+ * the next tick's zero-pass wipes the state. It NEVER lands in
262
+ * `linearVelocity` / `angularVelocity` — that's the point of
263
+ * split impulse: depth correction does not contaminate persistent
264
+ * velocity (so a `restitution = 0` impact stops cleanly).
265
+ *
266
+ * @type {Float64Array}
267
+ */
268
+ this.__pseudo_velocity = new Float64Array(0);
269
+
270
+ /**
271
+ * Bound reference to {@link __pair_filter} so we hand the same
272
+ * callable to {@link generate_pairs} each step without per-step
273
+ * allocation.
274
+ * @private
275
+ */
276
+ this.__pair_filter_bound = (idA, idB) => this.__pair_filter(idA, idB);
277
+ }
278
+
279
+ /**
280
+ * Symmetric layer/mask check + optional user callback. Called per
281
+ * candidate pair during broadphase. Returns `true` to accept the pair.
282
+ *
283
+ * Layer/mask rule: pair (A, B) collides iff
284
+ * `(A.layer & B.mask) !== 0 && (B.layer & A.mask) !== 0`.
285
+ * The user's contact-filter callback is consulted only for pairs that
286
+ * pass the bitmask test (cheap gate first).
287
+ *
288
+ * @private
289
+ * @param {number} idA packed body id
290
+ * @param {number} idB packed body id
291
+ * @returns {boolean}
292
+ */
293
+ __pair_filter(idA, idB) {
294
+ const idxA = body_id_index(idA);
295
+ const idxB = body_id_index(idB);
296
+ const rbA = this.__bodies[idxA];
297
+ const rbB = this.__bodies[idxB];
298
+ if (rbA === undefined || rbB === undefined) return false;
299
+
300
+ // Layer/mask gate (symmetric).
301
+ if (((rbA.layer & rbB.mask) | 0) === 0) return false;
302
+ if (((rbB.layer & rbA.mask) | 0) === 0) return false;
303
+
304
+ // User callback gate, if installed.
305
+ const fn = this.__contact_filter;
306
+ if (fn !== null) {
307
+ const entA = this.storage.entity_at(idxA);
308
+ const entB = this.storage.entity_at(idxB);
309
+ const colA = this.__primary_collider(idxA);
310
+ const colB = this.__primary_collider(idxB);
311
+ if (!fn(entA, entB, colA, colB)) return false;
312
+ }
313
+ return true;
314
+ }
315
+
316
+ /**
317
+ * First attached collider of a body, or `null` if none. Used by the
318
+ * solver to read material parameters (friction / restitution) when the
319
+ * per-contact source-collider identity isn't tracked yet (v1 limitation
320
+ * — multi-collider bodies with mixed materials lose precision here).
321
+ *
322
+ * @private
323
+ * @param {number} body_idx
324
+ * @returns {Collider|null}
325
+ */
326
+ __primary_collider(body_idx) {
327
+ const list = this.__body_collider_lists[body_idx];
328
+ return (list !== undefined && list.length > 0) ? list[0].collider : null;
329
+ }
330
+
331
+ /**
332
+ * Resize {@link __pseudo_velocity} to cover every live body slot and
333
+ * zero its contents. Called at the top of each fixedUpdate so the
334
+ * split-impulse position pass starts from a clean state — bodies the
335
+ * solver doesn't touch contribute zero pseudo-velocity to
336
+ * {@link integrate_position}.
337
+ *
338
+ * Doubles on growth like the other physics scratches; never shrinks.
339
+ *
340
+ * @private
341
+ */
342
+ __reset_pseudo_velocity() {
343
+ const required = this.storage.high_water_mark * 6;
344
+ if (this.__pseudo_velocity.length < required) {
345
+ this.__pseudo_velocity = new Float64Array(required * 2);
346
+ } else if (required > 0) {
347
+ this.__pseudo_velocity.fill(0, 0, required);
348
+ }
349
+ }
350
+
351
+ /**
352
+ * Replace the world gravity vector. Effective on the next step.
353
+ * @param {Vector3|{x:number,y:number,z:number}} v
354
+ */
355
+ setGravity(v) {
356
+ this.gravity.set(v.x, v.y, v.z);
357
+ }
358
+
359
+ /**
360
+ * Install (or remove with `null`) the contact filter callback.
361
+ * @param {((entityA:number, entityB:number, colliderA:Collider, colliderB:Collider) => boolean) | null} fn
362
+ */
363
+ setContactFilter(fn) {
364
+ this.__contact_filter = fn;
365
+ }
366
+
367
+ /**
368
+ * @returns {((entityA:number, entityB:number, colliderA:Collider, colliderB:Collider) => boolean) | null}
369
+ */
370
+ getContactFilter() {
371
+ return this.__contact_filter;
372
+ }
373
+
374
+ /**
375
+ * @private
376
+ * @param {RigidBody} rb
377
+ * @param {Collider} collider
378
+ * @param {Transform} transform
379
+ * @returns {number} BVH node id
380
+ */
381
+ __insert_into_broadphase(rb, collider, transform) {
382
+ const shape = collider.shape;
383
+
384
+ assert.notNull(shape, 'Collider.shape must be set before attaching');
385
+
386
+ shape.compute_bounding_box(scratch_local_aabb);
387
+
388
+ const p = transform.position;
389
+ const q = transform.rotation;
390
+
391
+ aabb3_transform_oriented(
392
+ scratch_world_aabb, 0,
393
+ scratch_local_aabb[0], scratch_local_aabb[1], scratch_local_aabb[2],
394
+ scratch_local_aabb[3], scratch_local_aabb[4], scratch_local_aabb[5],
395
+ p.x, p.y, p.z,
396
+ q.x, q.y, q.z, q.w
397
+ );
398
+
399
+ const bvh = rb.kind === BodyKind.Static ? this.staticBvh : this.dynamicBvh;
400
+ const node = bvh.allocate_node();
401
+
402
+ bvh.node_set_aabb_primitive(
403
+ node,
404
+ scratch_world_aabb[0], scratch_world_aabb[1], scratch_world_aabb[2],
405
+ scratch_world_aabb[3], scratch_world_aabb[4], scratch_world_aabb[5]
406
+ );
407
+ bvh.node_set_user_data(node, rb._bodyId);
408
+ bvh.insert_leaf(node);
409
+
410
+ return node;
411
+ }
412
+
413
+ /**
414
+ * @private
415
+ * @param {RigidBody} rb
416
+ * @param {number} node
417
+ */
418
+ __remove_from_broadphase(rb, node) {
419
+ const bvh = rb.kind === BodyKind.Static ? this.staticBvh : this.dynamicBvh;
420
+ bvh.remove_leaf(node);
421
+ bvh.release_node(node);
422
+ }
423
+
424
+ /**
425
+ * Lifecycle entry: invoked when an entity gains the (RigidBody, Transform)
426
+ * tuple. Allocates the body's slot in storage and seeds an empty collider
427
+ * list. Colliders are attached separately via {@link attach_collider} (the
428
+ * paired {@link ColliderObserverSystem} drives this from the dataset; in
429
+ * tests, call manually).
430
+ *
431
+ * @param {RigidBody} rigidBody
432
+ * @param {Transform} transform
433
+ * @param {number} entity
434
+ */
435
+ link(rigidBody, transform, entity) {
436
+ const packed = this.storage.allocate(entity);
437
+ rigidBody._bodyId = packed;
438
+ rigidBody.sleepState = SleepState.Awake;
439
+
440
+ const index = body_id_index(packed);
441
+ this.storage.set_kind(index, rigidBody.kind);
442
+ this.storage.set_flags(index, rigidBody.flags);
443
+
444
+ this.__bodies[index] = rigidBody;
445
+ this.__transforms[index] = transform;
446
+ this.__body_collider_lists[index] = [];
447
+
448
+ // Static bodies do not need to live in the active list — they never move.
449
+ if (rigidBody.kind === BodyKind.Static) {
450
+ this.storage.mark_sleeping(index);
451
+ }
452
+ }
453
+
454
+ /**
455
+ * Detach every collider attached to this body, free its slot, and clear
456
+ * the side-tables.
457
+ *
458
+ * @param {RigidBody} rigidBody
459
+ * @param {Transform} transform
460
+ * @param {number} entity
461
+ */
462
+ unlink(rigidBody, transform, entity) {
463
+ const packed = rigidBody._bodyId;
464
+
465
+ assert.equal(this.storage.is_valid(packed), true, 'unlink: stale or absent body id');
466
+
467
+ // If the body is sleeping inside a multi-member sleep group, dissolve
468
+ // the group by waking every member first. Otherwise the surviving
469
+ // members would hold dangling indices in their sleep-group chain
470
+ // pointing at a slot that has just been freed.
471
+ if (rigidBody.sleep_group_next !== -1) {
472
+ this.__wake_body(rigidBody);
473
+ }
474
+
475
+ const index = body_id_index(packed);
476
+ const list = this.__body_collider_lists[index];
477
+ if (list !== undefined) {
478
+ for (let i = 0; i < list.length; i++) {
479
+ const entry = list[i];
480
+ if (entry.bvhNode !== COLLIDER_UNBOUND) {
481
+ this.__remove_from_broadphase(rigidBody, entry.bvhNode);
482
+ }
483
+ entry.collider._bvhNode = COLLIDER_UNBOUND;
484
+ entry.collider._bodyId = -1;
485
+ }
486
+ }
487
+
488
+ this.__bodies[index] = undefined;
489
+ this.__transforms[index] = undefined;
490
+ this.__body_collider_lists[index] = undefined;
491
+
492
+ this.storage.free(packed);
493
+ rigidBody._bodyId = RIGID_BODY_UNALLOCATED;
494
+ }
495
+
496
+ /**
497
+ * Attach a collider to an existing body. The collider can live on the
498
+ * same entity as the body (single-collider body) or on a child entity
499
+ * (compound body). The world transform passed here is the collider's
500
+ * own — for a same-entity collider it is the body's Transform; for a
501
+ * child collider it is the child entity's Transform.
502
+ *
503
+ * Idempotent — re-attaching the same collider is a no-op.
504
+ *
505
+ * @param {number} body_entity entity that owns the body
506
+ * @param {Collider} collider
507
+ * @param {Transform} transform world transform of the collider
508
+ * @param {number} [collider_entity] entity owning the collider (defaults to body_entity)
509
+ */
510
+ attach_collider(body_entity, collider, transform, collider_entity = body_entity) {
511
+ // Find the body by walking the storage entity table. The body must
512
+ // have been allocated via `link` before any colliders are attached.
513
+ const body_index = this.__find_body_index_by_entity(body_entity);
514
+ assert.notEqual(body_index, -1, `attach_collider: no body found for entity ${body_entity}`);
515
+
516
+ const rb = this.__bodies[body_index];
517
+ // Idempotent: skip if collider already attached.
518
+ if (collider._bvhNode !== COLLIDER_UNBOUND) return;
519
+
520
+ const node = this.__insert_into_broadphase(rb, collider, transform);
521
+
522
+ collider._bvhNode = node;
523
+ collider._bodyId = rb._bodyId;
524
+ this.__body_collider_lists[body_index].push({
525
+ collider, transform, entity: collider_entity, bvhNode: node,
526
+ });
527
+ }
528
+
529
+ /**
530
+ * Reverse of {@link attach_collider}. Idempotent.
531
+ *
532
+ * @param {number} body_entity
533
+ * @param {Collider} collider
534
+ */
535
+ detach_collider(body_entity, collider) {
536
+ if (collider._bvhNode === COLLIDER_UNBOUND) return;
537
+
538
+ const body_index = this.__find_body_index_by_entity(body_entity);
539
+ if (body_index === -1) return;
540
+
541
+ const rb = this.__bodies[body_index];
542
+ this.__remove_from_broadphase(rb, collider._bvhNode);
543
+
544
+ const list = this.__body_collider_lists[body_index];
545
+ for (let i = 0; i < list.length; i++) {
546
+ if (list[i].collider === collider) {
547
+ list.splice(i, 1);
548
+ break;
549
+ }
550
+ }
551
+
552
+ collider._bvhNode = COLLIDER_UNBOUND;
553
+ collider._bodyId = -1;
554
+ }
555
+
556
+ /**
557
+ * Linear scan over body slots looking for the one whose entity matches.
558
+ * O(N) where N is the live body count — only called on the link/unlink
559
+ * paths, not during simulation, so the scan cost is bounded.
560
+ *
561
+ * @private
562
+ * @param {number} entity
563
+ * @returns {number} body index or -1
564
+ */
565
+ __find_body_index_by_entity(entity) {
566
+ const hwm = this.storage.high_water_mark;
567
+ for (let i = 0; i < hwm; i++) {
568
+ if (this.storage.entity_at(i) === entity) return i;
569
+ }
570
+ return -1;
571
+ }
572
+
573
+ /**
574
+ * Resolve a packed body id to its entity, or `-1` if the id is stale.
575
+ * @param {number} packed_body_id
576
+ * @returns {number}
577
+ */
578
+ entityOf(packed_body_id) {
579
+ if (!this.storage.is_valid(packed_body_id)) return -1;
580
+ return this.storage.entity_at(body_id_index(packed_body_id));
581
+ }
582
+
583
+ /**
584
+ * Number of live bodies (regardless of awake/sleeping state).
585
+ * @returns {number}
586
+ */
587
+ get bodyCount() {
588
+ return this.storage.size;
589
+ }
590
+
591
+ /**
592
+ * Apply an instantaneous change of momentum at the body's centre of mass.
593
+ * Linear-only — see {@link applyImpulseAt} for an off-centre impulse that
594
+ * also produces angular response.
595
+ *
596
+ * Wakes the body if it is asleep.
597
+ *
598
+ * @param {RigidBody} rigidBody
599
+ * @param {Vector3|{x:number,y:number,z:number}} impulse
600
+ */
601
+ applyImpulse(rigidBody, impulse) {
602
+ if (rigidBody.kind !== BodyKind.Dynamic) {
603
+ return;
604
+ }
605
+ const inv_m = rigidBody.mass > 0 ? 1 / rigidBody.mass : 0;
606
+ rigidBody.linearVelocity.addScaled(impulse, inv_m);
607
+
608
+ this.__wake_body(rigidBody);
609
+ }
610
+
611
+ /**
612
+ * Apply an instantaneous change of momentum at a specific world-space point.
613
+ * Off-centre impulses produce both linear (Δv = P/m) and angular
614
+ * (Δω = I_w⁻¹·(r × P)) response.
615
+ *
616
+ * Wakes the body if it is asleep.
617
+ *
618
+ * @param {RigidBody} rigidBody
619
+ * @param {Transform} transform body's current world Transform (used for r and I_w)
620
+ * @param {Vector3|{x:number,y:number,z:number}} impulse
621
+ * @param {Vector3|{x:number,y:number,z:number}} worldPoint
622
+ */
623
+ applyImpulseAt(rigidBody, transform, impulse, worldPoint) {
624
+ if (rigidBody.kind !== BodyKind.Dynamic) {
625
+ return;
626
+ }
627
+ const inv_m = rigidBody.mass > 0 ? 1 / rigidBody.mass : 0;
628
+
629
+ rigidBody.linearVelocity.set(
630
+ rigidBody.linearVelocity.x + impulse.x * inv_m,
631
+ rigidBody.linearVelocity.y + impulse.y * inv_m,
632
+ rigidBody.linearVelocity.z + impulse.z * inv_m
633
+ );
634
+
635
+ const rx = worldPoint.x - transform.position.x;
636
+ const ry = worldPoint.y - transform.position.y;
637
+ const rz = worldPoint.z - transform.position.z;
638
+
639
+ // Δω = I_w⁻¹ · (r × P)
640
+ const tx = ry * impulse.z - rz * impulse.y;
641
+ const ty = rz * impulse.x - rx * impulse.z;
642
+ const tz = rx * impulse.y - ry * impulse.x;
643
+
644
+ world_inverse_inertia_apply(scratch_angular_delta, 0, rigidBody.inverseInertiaLocal, transform.rotation, tx, ty, tz);
645
+
646
+ rigidBody.angularVelocity.set(
647
+ rigidBody.angularVelocity.x + scratch_angular_delta[0],
648
+ rigidBody.angularVelocity.y + scratch_angular_delta[1],
649
+ rigidBody.angularVelocity.z + scratch_angular_delta[2]
650
+ );
651
+
652
+ this.__wake_body(rigidBody);
653
+ }
654
+
655
+ /**
656
+ * Accumulate a continuous torque (world-space) for integration on the
657
+ * next fixedUpdate. Pairs with {@link applyForce} for the rotational case.
658
+ *
659
+ * Wakes the body if asleep.
660
+ *
661
+ * @param {RigidBody} rigidBody
662
+ * @param {Vector3|{x:number,y:number,z:number}} torque
663
+ */
664
+ applyTorque(rigidBody, torque) {
665
+ if (rigidBody.kind !== BodyKind.Dynamic) {
666
+ return;
667
+ }
668
+ rigidBody.accumulatedTorque.set(
669
+ rigidBody.accumulatedTorque.x + torque.x,
670
+ rigidBody.accumulatedTorque.y + torque.y,
671
+ rigidBody.accumulatedTorque.z + torque.z
672
+ );
673
+ this.__wake_body(rigidBody);
674
+ }
675
+
676
+ /**
677
+ * Apply a continuous force at a specific world-space point. The force
678
+ * generates both a linear acceleration (F/m) and a torque (r × F) about
679
+ * the body's centre of mass.
680
+ *
681
+ * Wakes the body if asleep.
682
+ *
683
+ * @param {RigidBody} rigidBody
684
+ * @param {Transform} transform body's current world Transform
685
+ * @param {Vector3|{x:number,y:number,z:number}} force
686
+ * @param {Vector3|{x:number,y:number,z:number}} worldPoint
687
+ */
688
+ applyForceAt(rigidBody, transform, force, worldPoint) {
689
+ if (rigidBody.kind !== BodyKind.Dynamic) {
690
+ return;
691
+ }
692
+ rigidBody.accumulatedForce.set(
693
+ rigidBody.accumulatedForce.x + force.x,
694
+ rigidBody.accumulatedForce.y + force.y,
695
+ rigidBody.accumulatedForce.z + force.z
696
+ );
697
+
698
+ const rx = worldPoint.x - transform.position.x;
699
+ const ry = worldPoint.y - transform.position.y;
700
+ const rz = worldPoint.z - transform.position.z;
701
+
702
+ rigidBody.accumulatedTorque.set(
703
+ rigidBody.accumulatedTorque.x + (ry * force.z - rz * force.y),
704
+ rigidBody.accumulatedTorque.y + (rz * force.x - rx * force.z),
705
+ rigidBody.accumulatedTorque.z + (rx * force.y - ry * force.x)
706
+ );
707
+
708
+ this.__wake_body(rigidBody);
709
+ }
710
+
711
+ /**
712
+ * Accumulate a continuous force to be integrated next fixedUpdate step.
713
+ * Wakes the body if asleep.
714
+ *
715
+ * @param {RigidBody} rigidBody
716
+ * @param {Vector3|{x:number,y:number,z:number}} force
717
+ */
718
+ applyForce(rigidBody, force) {
719
+ if (rigidBody.kind !== BodyKind.Dynamic) {
720
+ return;
721
+ }
722
+ rigidBody.accumulatedForce.add( force);
723
+ this.__wake_body(rigidBody);
724
+ }
725
+
726
+ /**
727
+ * Replace the linear velocity. Wakes the body if asleep.
728
+ *
729
+ * @param {RigidBody} rigidBody
730
+ * @param {Vector3|{x:number,y:number,z:number}} v
731
+ */
732
+ setLinearVelocity(rigidBody, v) {
733
+ rigidBody.linearVelocity.copy(v);
734
+ if (rigidBody.kind === BodyKind.Dynamic) {
735
+ this.__wake_body(rigidBody);
736
+ }
737
+ }
738
+
739
+ /**
740
+ * Force the body awake. Static bodies are ignored.
741
+ * @param {RigidBody} rigidBody
742
+ */
743
+ wake(rigidBody) {
744
+ this.__wake_body(rigidBody);
745
+ }
746
+
747
+ /**
748
+ * Force the body asleep. Dynamic bodies will not re-enter the active list
749
+ * until a wake event occurs.
750
+ * @param {RigidBody} rigidBody
751
+ */
752
+ sleep(rigidBody) {
753
+ if (rigidBody.kind !== BodyKind.Dynamic) {
754
+ return;
755
+ }
756
+ if (rigidBody.sleepState === SleepState.Sleeping) {
757
+ return;
758
+ }
759
+ rigidBody.sleepState = SleepState.Sleeping;
760
+ const index = body_id_index(rigidBody._bodyId);
761
+ this.storage.mark_sleeping(index);
762
+ }
763
+
764
+ /**
765
+ * Wake a body and atomically wake every other body it was last sleeping
766
+ * with (its "sleep group"). Sleep groups are circular doubly-linked lists
767
+ * threaded through every member of an island when it sleeps atomically;
768
+ * waking any one member walks the chain and wakes the rest in the same
769
+ * call.
770
+ *
771
+ * Without this, a 100-block stack hit at the base would wake one block
772
+ * per frame as the broadphase propagated awareness up the stack — a
773
+ * visible ~1.6 s wave at 60 fps. Atomic wake eliminates the wave.
774
+ *
775
+ * No-op for non-dynamic bodies. Idempotent for already-awake bodies.
776
+ * @private
777
+ * @param {RigidBody} rb
778
+ */
779
+ __wake_body(rb) {
780
+ if (rb.kind !== BodyKind.Dynamic) return;
781
+ if (rb.sleepState === SleepState.Awake) return;
782
+ const index = body_id_index(rb._bodyId);
783
+
784
+ // Remember the next-in-chain before clearing the body's own pointers;
785
+ // the rest of the group is reached by walking forward from there.
786
+ const start_next = rb.sleep_group_next;
787
+
788
+ rb.sleepState = SleepState.Awake;
789
+ rb.sleep_timer = 0;
790
+ rb.sleep_group_next = -1;
791
+ rb.sleep_group_prev = -1;
792
+ this.storage.mark_awake(index);
793
+
794
+ if (start_next === -1 || start_next === index) return;
795
+
796
+ // Walk the (now-broken) chain forward until we loop back. The chain
797
+ // is circular so we know when to stop; defensive `-1` guards against
798
+ // corruption from a body being unlinked mid-sleep-group.
799
+ let cur = start_next;
800
+ while (cur !== -1 && cur !== index) {
801
+ const cur_rb = this.__bodies[cur];
802
+ if (cur_rb === undefined) break;
803
+ const nxt = cur_rb.sleep_group_next;
804
+ cur_rb.sleepState = SleepState.Awake;
805
+ cur_rb.sleep_timer = 0;
806
+ cur_rb.sleep_group_next = -1;
807
+ cur_rb.sleep_group_prev = -1;
808
+ this.storage.mark_awake(cur);
809
+ cur = nxt;
810
+ }
811
+ }
812
+
813
+ /**
814
+ * Atomically put every body in a contiguous range of island members to
815
+ * sleep. Members are threaded into a circular doubly-linked list so any
816
+ * future `wake` on any member walks the chain and revives them all.
817
+ *
818
+ * Velocities are zeroed because the body is by definition at rest at
819
+ * this point — the alternative (storing residual velocities for "softer"
820
+ * wake) is what Bullet does, but for a deterministic game-physics target
821
+ * fully resetting is simpler and avoids drift while sleeping.
822
+ *
823
+ * @private
824
+ * @param {Uint32Array} member_array view (or full array) of body indices
825
+ * @param {number} start
826
+ * @param {number} end
827
+ */
828
+ __atomic_sleep_island_range(member_array, start, end) {
829
+ const count = end - start;
830
+ if (count === 0) return;
831
+ const bodies = this.__bodies;
832
+ const storage = this.storage;
833
+
834
+ if (count === 1) {
835
+ const idx = member_array[start];
836
+ const rb = bodies[idx];
837
+ if (rb === undefined) return;
838
+ rb.sleep_group_next = -1;
839
+ rb.sleep_group_prev = -1;
840
+ rb.sleepState = SleepState.Sleeping;
841
+ rb.linearVelocity[0] = 0; rb.linearVelocity[1] = 0; rb.linearVelocity[2] = 0;
842
+ rb.angularVelocity[0] = 0; rb.angularVelocity[1] = 0; rb.angularVelocity[2] = 0;
843
+ storage.mark_sleeping(idx);
844
+ return;
845
+ }
846
+
847
+ for (let i = 0; i < count; i++) {
848
+ const idx = member_array[start + i];
849
+ const rb = bodies[idx];
850
+ if (rb === undefined) continue;
851
+ const next_idx = member_array[start + ((i + 1) % count)];
852
+ const prev_idx = member_array[start + ((i - 1 + count) % count)];
853
+ rb.sleep_group_next = next_idx;
854
+ rb.sleep_group_prev = prev_idx;
855
+ rb.sleepState = SleepState.Sleeping;
856
+ rb.linearVelocity[0] = 0; rb.linearVelocity[1] = 0; rb.linearVelocity[2] = 0;
857
+ rb.angularVelocity[0] = 0; rb.angularVelocity[1] = 0; rb.angularVelocity[2] = 0;
858
+ storage.mark_sleeping(idx);
859
+ }
860
+ }
861
+
862
+ /**
863
+ * Get the body index for a packed body id without revalidation. Used by
864
+ * query traversals that already trust the id came from a live BVH leaf.
865
+ * @param {number} packed_body_id
866
+ * @returns {number}
867
+ */
868
+ __index_of(packed_body_id) {
869
+ return body_id_index(packed_body_id);
870
+ }
871
+
872
+ /**
873
+ * Broadphase raycast against both BVHs. Fills `result` with the nearest
874
+ * hit and returns `true` on hit, `false` on miss.
875
+ *
876
+ * Narrowphase refinement against the actual shape geometry is a
877
+ * follow-up — for now `result.t` is the distance to the leaf's
878
+ * inflated AABB and `result.normal` is the AABB face normal. Both are
879
+ * exact for AABB-shaped colliders.
880
+ *
881
+ * @param {Ray3} ray origin + unit direction + `tMax`
882
+ * @param {PhysicsSurfacePoint} result populated on hit; untouched on miss
883
+ * @param {(entity:number, collider:Collider)=>boolean} [filter] defaults
884
+ * to {@link returnTrue} (accept every candidate)
885
+ * @returns {boolean}
886
+ */
887
+ raycast(ray, result, filter = returnTrue) {
888
+ return raycast_query(this, ray, result, filter);
889
+ }
890
+
891
+ /**
892
+ * Sweep a convex shape along a ray and find the first body it
893
+ * would hit. The shape starts at `ray.origin` oriented by
894
+ * `rotation` and translates along `ray.direction` for up to
895
+ * `ray.tMax` units. Returns the nearest impact within that
896
+ * interval.
897
+ *
898
+ * The "swept AABB" broadphase finds candidate bodies whose BVH
899
+ * leaves overlap the shape's swept volume; the narrowphase then
900
+ * bisects [0, t] on GJK overlap to find the time-of-impact for
901
+ * each candidate. Best-t early termination skips candidates that
902
+ * can't tighten the answer.
903
+ *
904
+ * @param {Ray3} ray origin + unit direction + `tMax`
905
+ * @param {AbstractShape3D} shape
906
+ * @param {{x:number,y:number,z:number,w:number}} rotation
907
+ * @param {PhysicsSurfacePoint} result populated on hit; untouched on miss
908
+ * @param {(entity:number, collider:Collider)=>boolean} [filter]
909
+ * @returns {boolean}
910
+ */
911
+ shapeCast(ray, shape, rotation, result, filter = returnTrue) {
912
+ return shape_cast_query(this, ray, shape, rotation, result, filter);
913
+ }
914
+
915
+ /**
916
+ * Speculative overlap query: find all bodies whose collider would
917
+ * overlap the given convex shape placed at the given world pose,
918
+ * without mutating the simulation. Intended for kinematic /
919
+ * character controllers that need to test "would I collide if I
920
+ * moved here?" before committing the move.
921
+ *
922
+ * Pipeline:
923
+ * 1. The shape's world AABB is computed from `position` + `rotation`.
924
+ * 2. Both broadphase trees (static + dynamic) are queried for
925
+ * bodies whose leaf AABB overlaps that envelope.
926
+ * 3. Each candidate is GJK-tested in world frame. Convex
927
+ * candidates run one GJK call; concave candidates (heightmap,
928
+ * mesh) run per-triangle GJK via the decomposition path.
929
+ * 4. The optional `filter` is consulted before the GJK test —
930
+ * useful for skipping the caller's own body, allies, sensors,
931
+ * etc.
932
+ *
933
+ * The output buffer is filled with overlapping bodies' `body_id`
934
+ * values (uint32 with packed generation), starting at
935
+ * `output_offset`. The caller is responsible for sizing the buffer;
936
+ * IDs past its end are dropped silently and the count caps at the
937
+ * available space.
938
+ *
939
+ * The query shape must be convex. Concave query shapes throw —
940
+ * they're typically static terrain and not used as kinematic
941
+ * probes; the M×N triangle-pair cost wouldn't be worth the rare
942
+ * use case.
943
+ *
944
+ * @param {AbstractShape3D} shape convex query shape, in its local frame
945
+ * @param {{x:number,y:number,z:number}} position world position of
946
+ * the query shape
947
+ * @param {{x:number,y:number,z:number,w:number}} rotation world
948
+ * rotation (unit quaternion)
949
+ * @param {Uint32Array|number[]} output buffer to receive body_ids
950
+ * @param {number} output_offset starting index in output
951
+ * @param {(entity:number, collider:Collider)=>boolean} [filter]
952
+ * defaults to {@link returnTrue}
953
+ * @returns {number} number of overlapping bodies written
954
+ */
955
+ overlap(shape, position, rotation, output, output_offset, filter = returnTrue) {
956
+ return overlap_shape_query(this, shape, position, rotation, output, output_offset, filter);
957
+ }
958
+
959
+ /**
960
+ * Run one simulation step. v1 pipeline: integrate velocity → integrate
961
+ * position → refit broadphase AABBs. Narrowphase, solver, islands and
962
+ * contact-event emission land in subsequent slices.
963
+ *
964
+ * @param {number} dt
965
+ */
966
+ /**
967
+ * Wake any sleeping body that appears in this step's broadphase pair list.
968
+ * A pair means the BVH AABBs overlap — even if the sleeper hasn't moved,
969
+ * an awake neighbour has come into contact range and the sleeper must
970
+ * participate in narrowphase / solve.
971
+ * @private
972
+ */
973
+ __wake_pairs() {
974
+ const list = this.pairs;
975
+ const n = list.count;
976
+ const bodies = this.__bodies;
977
+ for (let i = 0; i < n; i++) {
978
+ const idA = list.get_a(i);
979
+ const idB = list.get_b(i);
980
+ const idxA = body_id_index(idA);
981
+ const idxB = body_id_index(idB);
982
+ const a = bodies[idxA];
983
+ const b = bodies[idxB];
984
+ if (a !== undefined && a.sleepState === SleepState.Sleeping) {
985
+ this.__wake_body(a);
986
+ }
987
+ if (b !== undefined && b.sleepState === SleepState.Sleeping) {
988
+ this.__wake_body(b);
989
+ }
990
+ }
991
+ }
992
+
993
+ /**
994
+ * Per-island atomic sleep test. Walks each island once and applies the
995
+ * decision uniformly across all members:
996
+ *
997
+ * - If any member carries {@link RigidBodyFlags.DisableSleep}, the
998
+ * entire island is exempt; every member's sleep_timer is reset.
999
+ * - If `max(|v|² + |ω|²)` across all members is below
1000
+ * {@link sleepVelocitySqrThreshold}, every member's sleep_timer is
1001
+ * incremented by `dt`. When the smallest member's timer crosses
1002
+ * {@link sleepTimeThreshold}, the whole island sleeps atomically in
1003
+ * the same step (members get threaded into a sleep-group chain so
1004
+ * {@link __wake_body} can wake them all in one call).
1005
+ * - Otherwise the island has at least one active member, so every
1006
+ * member's timer is reset.
1007
+ *
1008
+ * This is the design-plan atomic-island sleep — replaces the per-body
1009
+ * approximation that lived in this slot during the previous slice.
1010
+ * Weakly-connected piles no longer chatter awake when a single member
1011
+ * blips above threshold; piles fall asleep and wake up as one.
1012
+ *
1013
+ * @private
1014
+ * @param {number} dt
1015
+ */
1016
+ __sleep_test(dt) {
1017
+ const threshold_sqr = this.sleepVelocitySqrThreshold;
1018
+ const time_threshold = this.sleepTimeThreshold;
1019
+ const bodies = this.__bodies;
1020
+ const islands = this.islands;
1021
+ const island_count = islands.island_count;
1022
+ const body_offsets = islands.body_offsets;
1023
+ const body_data = islands.body_data;
1024
+
1025
+ for (let isl = 0; isl < island_count; isl++) {
1026
+ const start = body_offsets[isl];
1027
+ const end = body_offsets[isl + 1];
1028
+ if (end === start) continue;
1029
+
1030
+ // Pass 1: find max v² + check DisableSleep across the island.
1031
+ let max_v_sqr = 0;
1032
+ let any_disable_sleep = false;
1033
+ for (let i = start; i < end; i++) {
1034
+ const idx = body_data[i];
1035
+ const rb = bodies[idx];
1036
+ if (rb === undefined) continue;
1037
+ if ((rb.flags & RigidBodyFlags.DisableSleep) !== 0) {
1038
+ any_disable_sleep = true;
1039
+ break;
1040
+ }
1041
+ const lv = rb.linearVelocity;
1042
+ const av = rb.angularVelocity;
1043
+ const v_sqr = lv[0] * lv[0] + lv[1] * lv[1] + lv[2] * lv[2]
1044
+ + av[0] * av[0] + av[1] * av[1] + av[2] * av[2];
1045
+ if (v_sqr > max_v_sqr) max_v_sqr = v_sqr;
1046
+ }
1047
+
1048
+ if (any_disable_sleep) {
1049
+ // Whole island is exempt — reset every member's timer.
1050
+ for (let i = start; i < end; i++) {
1051
+ const rb = bodies[body_data[i]];
1052
+ if (rb !== undefined) rb.sleep_timer = 0;
1053
+ }
1054
+ continue;
1055
+ }
1056
+
1057
+ if (max_v_sqr < threshold_sqr) {
1058
+ // Island is at rest — increment every member's timer; if the
1059
+ // slowest-stabilising member has crossed the time threshold,
1060
+ // every member has (they were incremented together this step),
1061
+ // so atomic-sleep the island.
1062
+ let min_timer = Infinity;
1063
+ for (let i = start; i < end; i++) {
1064
+ const rb = bodies[body_data[i]];
1065
+ if (rb === undefined) continue;
1066
+ rb.sleep_timer += dt;
1067
+ if (rb.sleep_timer < min_timer) min_timer = rb.sleep_timer;
1068
+ }
1069
+ if (min_timer >= time_threshold) {
1070
+ this.__atomic_sleep_island_range(body_data, start, end);
1071
+ }
1072
+ } else {
1073
+ // At least one member is active — reset every timer.
1074
+ for (let i = start; i < end; i++) {
1075
+ const rb = bodies[body_data[i]];
1076
+ if (rb !== undefined) rb.sleep_timer = 0;
1077
+ }
1078
+ }
1079
+ }
1080
+ }
1081
+
1082
+ /**
1083
+ * Dispatch every buffered contact event through:
1084
+ * - the system-level Signals ({@link onContactBegin}/Stay/End), always; and
1085
+ * - the entity-level event channel via `dataset.sendEvent(entity, name, payload)`,
1086
+ * when a dataset is attached.
1087
+ *
1088
+ * Payload is a reused scratch object; listeners must copy anything they
1089
+ * intend to retain past the listener body.
1090
+ * @private
1091
+ */
1092
+ __dispatch_contact_events() {
1093
+ const events = this.contactEvents;
1094
+ const n = events.count;
1095
+ if (n === 0) return;
1096
+
1097
+ const ecd = (this.entityManager !== null && this.entityManager !== undefined)
1098
+ ? this.entityManager.dataset
1099
+ : null;
1100
+ const manifolds = this.manifolds;
1101
+ const data = manifolds.data_buffer;
1102
+
1103
+ const payload = this.__contact_payload;
1104
+
1105
+ for (let i = 0; i < n; i++) {
1106
+ const kind = events.kind_at(i);
1107
+ const entA = events.entityA_at(i);
1108
+ const entB = events.entityB_at(i);
1109
+ const slot = events.slot_at(i);
1110
+
1111
+ // Use the deepest contact of the manifold as the representative
1112
+ // point/normal/depth for the event. v1: contact 0 only.
1113
+ const slot_off = manifolds.slot_data_offset(slot);
1114
+ const has_contact = manifolds.contact_count(slot) > 0;
1115
+
1116
+ // Scratch payload — no observers subscribe to its component
1117
+ // vectors; write indices directly to skip the Signal dispatch.
1118
+ const pt = payload.point;
1119
+ const nm = payload.normal;
1120
+ if (has_contact) {
1121
+ const wax = data[slot_off], way = data[slot_off + 1], waz = data[slot_off + 2];
1122
+ const wbx = data[slot_off + 3], wby = data[slot_off + 4], wbz = data[slot_off + 5];
1123
+ pt[0] = (wax + wbx) * 0.5; pt[1] = (way + wby) * 0.5; pt[2] = (waz + wbz) * 0.5;
1124
+ nm[0] = data[slot_off + 6]; nm[1] = data[slot_off + 7]; nm[2] = data[slot_off + 8];
1125
+ payload.depth = data[slot_off + 9];
1126
+ } else {
1127
+ pt[0] = 0; pt[1] = 0; pt[2] = 0;
1128
+ nm[0] = 0; nm[1] = 0; nm[2] = 0;
1129
+ payload.depth = 0;
1130
+ }
1131
+ payload.entityA = entA;
1132
+ payload.entityB = entB;
1133
+
1134
+ let event_name;
1135
+ let signal;
1136
+ if (kind === ContactEventKind.Begin) { event_name = PhysicsEvents.ContactBegin; signal = this.onContactBegin; }
1137
+ else if (kind === ContactEventKind.Stay) { event_name = PhysicsEvents.ContactStay; signal = this.onContactStay; }
1138
+ else { event_name = PhysicsEvents.ContactEnd; signal = this.onContactEnd; }
1139
+
1140
+ signal.send1(payload);
1141
+
1142
+ if (ecd !== null && ecd !== undefined) {
1143
+ if (entA >= 0) ecd.sendEvent(entA, event_name, payload);
1144
+ if (entB >= 0) ecd.sendEvent(entB, event_name, payload);
1145
+ }
1146
+ }
1147
+ }
1148
+
1149
+ fixedUpdate(dt) {
1150
+ const gx = this.gravity.x;
1151
+ const gy = this.gravity.y;
1152
+ const gz = this.gravity.z;
1153
+
1154
+ const count = this.storage.awake_count;
1155
+
1156
+ // Stage 1: consume the per-frame force / torque accumulators into
1157
+ // velocity at the full `dt`, exactly once (a user force is a per-frame
1158
+ // budget that must land in full regardless of substep count). Gravity
1159
+ // is applied per substep below, so the trajectory integrates at the
1160
+ // substep rate and — crucially — each substep's gravity is balanced by
1161
+ // that substep's contact warm-start, keeping resting stacks at zero
1162
+ // velocity.
1163
+ for (let i = 0; i < count; i++) {
1164
+ const idx = this.storage.awake_at(i);
1165
+ const rb = this.__bodies[idx];
1166
+ const tr = this.__transforms[idx];
1167
+ integrate_velocity_forces(rb, tr, dt);
1168
+ }
1169
+
1170
+ // Stage 2: refit each awake body's collider leaves at the current
1171
+ // pose, padded by the swept extent for the body's velocity. The fat
1172
+ // margin uses the post-force velocity; this frame's gravity increment
1173
+ // is a sub-millimetre slack difference, safely inside the margin.
1174
+ const lists = this.__body_collider_lists;
1175
+ for (let i = 0; i < count; i++) {
1176
+ const idx = this.storage.awake_at(i);
1177
+ const rb = this.__bodies[idx];
1178
+ const list = lists[idx];
1179
+ if (list === undefined) continue;
1180
+ const lv = rb.linearVelocity;
1181
+ for (let k = 0; k < list.length; k++) {
1182
+ const entry = list[k];
1183
+ compute_fat_world_aabb(
1184
+ scratch_world_aabb, 0,
1185
+ entry.collider.shape, entry.transform,
1186
+ lv[0], lv[1], lv[2],
1187
+ dt
1188
+ );
1189
+ this.dynamicBvh.node_move_aabb(entry.bvhNode, scratch_world_aabb);
1190
+ }
1191
+ }
1192
+
1193
+ // Stage 3: broadphase pair generation. The fat AABBs cover the full
1194
+ // outer-step motion, so the pair set stays valid across all substeps
1195
+ // — broadphase runs once.
1196
+ generate_pairs(
1197
+ this.storage,
1198
+ this.dynamicBvh,
1199
+ this.staticBvh,
1200
+ this.manifolds,
1201
+ lists,
1202
+ this.pairs,
1203
+ this.__pair_filter_bound,
1204
+ );
1205
+
1206
+ // Stage 4: wake propagation.
1207
+ this.__wake_pairs();
1208
+
1209
+ // Stage 5: narrowphase — once per outer step. The substep loop below
1210
+ // re-derives each contact's penetration analytically from the moved
1211
+ // poses rather than re-running geometry.
1212
+ narrowphase_step(this.pairs, this.manifolds, this.__body_collider_lists);
1213
+
1214
+ // Stage 6: partition awake bodies + touched contacts into islands.
1215
+ // Consumed by the solver (flattened contact list) and the sleep test.
1216
+ this.islands.build(this.storage, this.manifolds, this.__bodies, this.__body_collider_lists);
1217
+
1218
+ // Stage 7: TGS substep loop.
1219
+ //
1220
+ // prepare_contacts captures per-contact anchors / effective masses /
1221
+ // approach velocity (no warm-start — that's per-substep). Each substep
1222
+ // integrates gravity by `h`, re-derives contact geometry from the
1223
+ // current poses, replays warm-start, solves velocity (non-penetration
1224
+ // + friction) and position (pseudo-velocity), and integrates the pose
1225
+ // by `h`. Per-substep gravity + per-substep warm-start balance exactly
1226
+ // at a resting contact (each cancels `h` of the other), so stacks hold
1227
+ // at zero velocity and sleep; the position correction adapts as bodies
1228
+ // separate between substeps — the TGS stack-stability mechanism —
1229
+ // without re-running narrowphase. Restitution is applied once after
1230
+ // the loop.
1231
+ const N = this.substeps;
1232
+ const h = dt / N;
1233
+ const count_after_wake = this.storage.awake_count;
1234
+
1235
+ // Size the pseudo-velocity buffer ONCE (it may reallocate on growth),
1236
+ // then capture the reference. Inside the loop we only zero its live
1237
+ // region per substep — re-capturing is unnecessary since it won't
1238
+ // reallocate again this step.
1239
+ this.__reset_pseudo_velocity();
1240
+ const pseudoVel = this.__pseudo_velocity;
1241
+ const pseudo_len = this.storage.high_water_mark * 6;
1242
+
1243
+ prepare_contacts(this.manifolds, this, h);
1244
+
1245
+ for (let s = 0; s < N; s++) {
1246
+ // Gravity (+ damping) for this substep.
1247
+ for (let i = 0; i < count_after_wake; i++) {
1248
+ const idx = this.storage.awake_at(i);
1249
+ integrate_velocity_gravity(this.__bodies[idx], this.__transforms[idx], gx, gy, gz, h);
1250
+ }
1251
+
1252
+ // Re-derive contact geometry at the current poses, replay the
1253
+ // per-substep warm-start, then solve velocity.
1254
+ refresh_contacts(this.manifolds, this);
1255
+ warm_start_contacts(this.manifolds, this);
1256
+ solve_velocity(this.manifolds, this, this.velocityIterations);
1257
+
1258
+ // Position correction writes pseudo-velocity (zeroed first so it
1259
+ // is a fresh per-substep correction), folded into the pose by the
1260
+ // position integrate and then discarded.
1261
+ pseudoVel.fill(0, 0, pseudo_len);
1262
+ solve_position(this.manifolds, this, this.positionIterations);
1263
+
1264
+ for (let i = 0; i < count_after_wake; i++) {
1265
+ const idx = this.storage.awake_at(i);
1266
+ const rb = this.__bodies[idx];
1267
+ const tr = this.__transforms[idx];
1268
+ const base = idx * 6;
1269
+ integrate_position(rb, tr, h,
1270
+ pseudoVel[base], pseudoVel[base + 1], pseudoVel[base + 2],
1271
+ pseudoVel[base + 3], pseudoVel[base + 4], pseudoVel[base + 5]);
1272
+ }
1273
+ }
1274
+
1275
+ // Stage 8: one-shot restitution, after the substep loop, keyed off
1276
+ // the approach velocity captured at prepare time.
1277
+ apply_restitution(this.manifolds, this);
1278
+
1279
+ // Stage 9: sleep test.
1280
+ this.__sleep_test(dt);
1281
+
1282
+ // Stage 10: diff manifolds against the previous frame and dispatch
1283
+ // Begin / Stay / End events. MUST run before advance_frame, which
1284
+ // rolls the touched flags.
1285
+ diff_manifolds(this.manifolds, this.storage, this.contactEvents);
1286
+ this.__dispatch_contact_events();
1287
+
1288
+ // Stage 11 (end-of-step): roll touched → prev_touched and evict slots
1289
+ // whose pair has not been touched within the grace window.
1290
+ this.manifolds.advance_frame();
1291
+ }
1292
+ }
1293
+
1294
+ /**
1295
+ * @readonly
1296
+ * @type {boolean}
1297
+ */
1298
+ PhysicsSystem.prototype.isPhysicsSystem = true;
1299
+
1300
+ // Re-export for convenience.
1301
+ export { BodyKind, RigidBodyFlags };