@woosh/meep-engine 2.138.20 → 2.139.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 (491) hide show
  1. package/package.json +1 -1
  2. package/src/core/collection/PairUint32Map.d.ts +100 -0
  3. package/src/core/collection/PairUint32Map.d.ts.map +1 -0
  4. package/src/core/collection/PairUint32Map.js +321 -0
  5. package/src/core/collection/Uint32Map.d.ts +119 -0
  6. package/src/core/collection/Uint32Map.d.ts.map +1 -0
  7. package/src/core/collection/Uint32Map.js +345 -0
  8. package/src/core/collection/array/array_shuffle.d.ts +10 -3
  9. package/src/core/collection/array/array_shuffle.d.ts.map +1 -1
  10. package/src/core/collection/array/array_shuffle.js +27 -22
  11. package/src/core/collection/heap/FibonacciHeap.d.ts +195 -0
  12. package/src/core/collection/heap/FibonacciHeap.d.ts.map +1 -0
  13. package/src/core/collection/heap/FibonacciHeap.js +586 -0
  14. package/src/core/collection/heap/Uint32Heap.js +1 -1
  15. package/src/core/collection/heap/Uint32Heap4.d.ts +169 -0
  16. package/src/core/collection/heap/Uint32Heap4.d.ts.map +1 -0
  17. package/src/core/collection/heap/Uint32Heap4.js +490 -0
  18. package/src/core/geom/3d/line/line3_closest_points_segment_segment.d.ts +27 -0
  19. package/src/core/geom/3d/line/line3_closest_points_segment_segment.d.ts.map +1 -0
  20. package/src/core/geom/3d/line/line3_closest_points_segment_segment.js +88 -0
  21. package/src/core/geom/3d/shape/BoxShape3D.d.ts +61 -0
  22. package/src/core/geom/3d/shape/BoxShape3D.d.ts.map +1 -0
  23. package/src/core/geom/3d/shape/BoxShape3D.js +158 -0
  24. package/src/core/geom/3d/shape/CapsuleShape3D.d.ts +11 -0
  25. package/src/core/geom/3d/shape/CapsuleShape3D.d.ts.map +1 -1
  26. package/src/core/geom/3d/shape/CapsuleShape3D.js +12 -0
  27. package/src/core/geom/3d/shape/UnitCubeShape3D.d.ts +37 -9
  28. package/src/core/geom/3d/shape/UnitCubeShape3D.d.ts.map +1 -1
  29. package/src/core/geom/3d/shape/UnitCubeShape3D.js +45 -98
  30. package/src/core/geom/3d/shape/UnitSphereShape3D.d.ts +10 -0
  31. package/src/core/geom/3d/shape/UnitSphereShape3D.d.ts.map +1 -1
  32. package/src/core/geom/3d/shape/UnitSphereShape3D.js +11 -0
  33. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.d.ts +61 -0
  34. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.d.ts.map +1 -0
  35. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.js +148 -0
  36. package/src/core/geom/3d/tetrahedra/compute_tetrahedral_mesh_from_surface.d.ts +39 -0
  37. package/src/core/geom/3d/tetrahedra/compute_tetrahedral_mesh_from_surface.d.ts.map +1 -0
  38. package/src/core/geom/3d/tetrahedra/compute_tetrahedral_mesh_from_surface.js +147 -0
  39. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.d.ts +15 -0
  40. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.d.ts.map +1 -0
  41. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.js +22 -0
  42. package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.d.ts +2 -0
  43. package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.d.ts.map +1 -0
  44. package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.js +673 -0
  45. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.d.ts +26 -0
  46. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.d.ts.map +1 -0
  47. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.js +222 -0
  48. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_find_tets_around_edge.d.ts +34 -0
  49. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_find_tets_around_edge.d.ts.map +1 -0
  50. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_find_tets_around_edge.js +146 -0
  51. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.d.ts +36 -0
  52. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.d.ts.map +1 -0
  53. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.js +232 -0
  54. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.d.ts +33 -0
  55. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.d.ts.map +1 -0
  56. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.js +255 -0
  57. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.d.ts +68 -0
  58. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.d.ts.map +1 -0
  59. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.js +365 -0
  60. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts +31 -0
  61. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts.map +1 -0
  62. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.js +112 -0
  63. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts +22 -0
  64. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts.map +1 -0
  65. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.js +55 -0
  66. package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.d.ts +32 -0
  67. package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.d.ts.map +1 -0
  68. package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.js +66 -0
  69. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.d.ts +22 -0
  70. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.d.ts.map +1 -1
  71. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.js +49 -0
  72. package/src/core/geom/3d/topology/struct/binary/BinaryTopology.d.ts +134 -0
  73. package/src/core/geom/3d/topology/struct/binary/BinaryTopology.d.ts.map +1 -1
  74. package/src/core/geom/3d/topology/struct/binary/BinaryTopology.js +276 -3
  75. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts +17 -0
  76. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts.map +1 -0
  77. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.js +135 -0
  78. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compact.d.ts +14 -0
  79. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compact.d.ts.map +1 -0
  80. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compact.js +177 -0
  81. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_decouple.d.ts.map +1 -1
  82. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_decouple.js +20 -4
  83. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
  84. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +5 -3
  85. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.d.ts.map +1 -1
  86. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.js +9 -0
  87. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_get_or_create.d.ts.map +1 -1
  88. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_get_or_create.js +21 -45
  89. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill.d.ts.map +1 -1
  90. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill.js +7 -1
  91. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts +8 -6
  92. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts.map +1 -1
  93. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.js +8 -6
  94. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.d.ts +22 -0
  95. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.d.ts.map +1 -0
  96. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.js +73 -0
  97. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.d.ts.map +1 -1
  98. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.js +51 -1
  99. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.d.ts +10 -0
  100. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.d.ts.map +1 -0
  101. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.js +42 -0
  102. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.d.ts +28 -0
  103. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.d.ts.map +1 -0
  104. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.js +227 -0
  105. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_walk_boundary_loops.d.ts +13 -0
  106. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_walk_boundary_loops.d.ts.map +1 -0
  107. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_walk_boundary_loops.js +108 -0
  108. package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.d.ts +11 -0
  109. package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.d.ts.map +1 -0
  110. package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.js +20 -0
  111. package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.d.ts +20 -0
  112. package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.d.ts.map +1 -0
  113. package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.js +38 -0
  114. package/src/core/graph/csr/CSRGraph.d.ts +168 -0
  115. package/src/core/graph/csr/CSRGraph.d.ts.map +1 -0
  116. package/src/core/graph/csr/CSRGraph.js +319 -0
  117. package/src/core/graph/metis/cluster_mesh_metis.d.ts +12 -0
  118. package/src/core/graph/metis/cluster_mesh_metis.d.ts.map +1 -1
  119. package/src/core/graph/metis/cluster_mesh_metis.js +12 -0
  120. package/src/core/graph/metis/metis.d.ts +19 -0
  121. package/src/core/graph/metis/metis.d.ts.map +1 -1
  122. package/src/core/graph/metis/metis.js +20 -0
  123. package/src/core/graph/metis/metis_cluster_bs.d.ts +11 -0
  124. package/src/core/graph/metis/metis_cluster_bs.d.ts.map +1 -1
  125. package/src/core/graph/metis/metis_cluster_bs.js +11 -0
  126. package/src/core/graph/metis/metis_options.d.ts +17 -2
  127. package/src/core/graph/metis/metis_options.d.ts.map +1 -1
  128. package/src/core/graph/metis/metis_options.js +17 -2
  129. package/src/core/graph/metis/native/MetisGraph.d.ts +144 -0
  130. package/src/core/graph/metis/native/MetisGraph.d.ts.map +1 -0
  131. package/src/core/graph/metis/native/MetisGraph.js +212 -0
  132. package/src/core/graph/metis/native/bisection/BisectionScratch.d.ts +72 -0
  133. package/src/core/graph/metis/native/bisection/BisectionScratch.d.ts.map +1 -0
  134. package/src/core/graph/metis/native/bisection/BisectionScratch.js +101 -0
  135. package/src/core/graph/metis/native/bisection/bisect_graph.d.ts +37 -0
  136. package/src/core/graph/metis/native/bisection/bisect_graph.d.ts.map +1 -0
  137. package/src/core/graph/metis/native/bisection/bisect_graph.js +100 -0
  138. package/src/core/graph/metis/native/bisection/compute_2way_params.d.ts +15 -0
  139. package/src/core/graph/metis/native/bisection/compute_2way_params.d.ts.map +1 -0
  140. package/src/core/graph/metis/native/bisection/compute_2way_params.js +84 -0
  141. package/src/core/graph/metis/native/bisection/fm_2way.d.ts +30 -0
  142. package/src/core/graph/metis/native/bisection/fm_2way.d.ts.map +1 -0
  143. package/src/core/graph/metis/native/bisection/fm_2way.js +290 -0
  144. package/src/core/graph/metis/native/bisection/grow_bisection.d.ts +23 -0
  145. package/src/core/graph/metis/native/bisection/grow_bisection.d.ts.map +1 -0
  146. package/src/core/graph/metis/native/bisection/grow_bisection.js +137 -0
  147. package/src/core/graph/metis/native/bisection/split_graph_two_way.d.ts +28 -0
  148. package/src/core/graph/metis/native/bisection/split_graph_two_way.d.ts.map +1 -0
  149. package/src/core/graph/metis/native/bisection/split_graph_two_way.js +119 -0
  150. package/src/core/graph/metis/native/coarsen/coarsen_graph.d.ts +20 -0
  151. package/src/core/graph/metis/native/coarsen/coarsen_graph.d.ts.map +1 -0
  152. package/src/core/graph/metis/native/coarsen/coarsen_graph.js +94 -0
  153. package/src/core/graph/metis/native/coarsen/create_coarse_graph.d.ts +24 -0
  154. package/src/core/graph/metis/native/coarsen/create_coarse_graph.d.ts.map +1 -0
  155. package/src/core/graph/metis/native/coarsen/create_coarse_graph.js +158 -0
  156. package/src/core/graph/metis/native/coarsen/match_shem.d.ts +41 -0
  157. package/src/core/graph/metis/native/coarsen/match_shem.d.ts.map +1 -0
  158. package/src/core/graph/metis/native/coarsen/match_shem.js +175 -0
  159. package/src/core/graph/metis/native/initial/initial_kway_bfs.d.ts +24 -0
  160. package/src/core/graph/metis/native/initial/initial_kway_bfs.d.ts.map +1 -0
  161. package/src/core/graph/metis/native/initial/initial_kway_bfs.js +122 -0
  162. package/src/core/graph/metis/native/initial/initial_kway_recursive_bisection.d.ts +29 -0
  163. package/src/core/graph/metis/native/initial/initial_kway_recursive_bisection.d.ts.map +1 -0
  164. package/src/core/graph/metis/native/initial/initial_kway_recursive_bisection.js +170 -0
  165. package/src/core/graph/metis/native/metis_partition_kway.d.ts +41 -0
  166. package/src/core/graph/metis/native/metis_partition_kway.d.ts.map +1 -0
  167. package/src/core/graph/metis/native/metis_partition_kway.js +126 -0
  168. package/src/core/graph/metis/native/refine/IndexedFloatMaxHeap.d.ts +62 -0
  169. package/src/core/graph/metis/native/refine/IndexedFloatMaxHeap.d.ts.map +1 -0
  170. package/src/core/graph/metis/native/refine/IndexedFloatMaxHeap.js +261 -0
  171. package/src/core/graph/metis/native/refine/RefinementScratch.d.ts +45 -0
  172. package/src/core/graph/metis/native/refine/RefinementScratch.d.ts.map +1 -0
  173. package/src/core/graph/metis/native/refine/RefinementScratch.js +53 -0
  174. package/src/core/graph/metis/native/refine/compute_kway_params.d.ts +18 -0
  175. package/src/core/graph/metis/native/refine/compute_kway_params.d.ts.map +1 -0
  176. package/src/core/graph/metis/native/refine/compute_kway_params.js +138 -0
  177. package/src/core/graph/metis/native/refine/fm_kway.d.ts +63 -0
  178. package/src/core/graph/metis/native/refine/fm_kway.d.ts.map +1 -0
  179. package/src/core/graph/metis/native/refine/fm_kway.js +462 -0
  180. package/src/core/graph/metis/native/refine/project_kway.d.ts +22 -0
  181. package/src/core/graph/metis/native/refine/project_kway.d.ts.map +1 -0
  182. package/src/core/graph/metis/native/refine/project_kway.js +43 -0
  183. package/src/core/graph/metis/native/refine/refine_kway.d.ts +34 -0
  184. package/src/core/graph/metis/native/refine/refine_kway.d.ts.map +1 -0
  185. package/src/core/graph/metis/native/refine/refine_kway.js +43 -0
  186. package/src/core/math/linalg/eigen/matrix_householder_in_place.d.ts +2 -2
  187. package/src/core/math/linalg/eigen/matrix_householder_in_place.js +2 -2
  188. package/src/core/math/linalg/eigen/matrix_qr_in_place.d.ts +6 -4
  189. package/src/core/math/linalg/eigen/matrix_qr_in_place.d.ts.map +1 -1
  190. package/src/core/math/linalg/eigen/matrix_qr_in_place.js +69 -23
  191. package/src/engine/EngineHarness.d.ts +3 -1
  192. package/src/engine/EngineHarness.d.ts.map +1 -1
  193. package/src/engine/EngineHarness.js +3 -0
  194. package/src/engine/control/first-person/DESIGN.md +30 -6
  195. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +563 -0
  196. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +102 -9
  197. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
  198. package/src/engine/control/first-person/FirstPersonPlayerController.js +38 -3
  199. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +533 -4
  200. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
  201. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +315 -6
  202. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts +220 -22
  203. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
  204. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +858 -241
  205. package/src/engine/control/first-person/TODO.md +127 -0
  206. package/src/engine/control/first-person/abilities/Ability.d.ts +101 -0
  207. package/src/engine/control/first-person/abilities/Ability.d.ts.map +1 -0
  208. package/src/engine/control/first-person/abilities/Ability.js +119 -0
  209. package/src/engine/control/first-person/abilities/AbilitySet.d.ts +86 -0
  210. package/src/engine/control/first-person/abilities/AbilitySet.d.ts.map +1 -0
  211. package/src/engine/control/first-person/abilities/AbilitySet.js +185 -0
  212. package/src/engine/control/first-person/abilities/LedgeGrab.d.ts +62 -0
  213. package/src/engine/control/first-person/abilities/LedgeGrab.d.ts.map +1 -0
  214. package/src/engine/control/first-person/abilities/LedgeGrab.js +199 -0
  215. package/src/engine/control/first-person/abilities/Mantle.d.ts +45 -0
  216. package/src/engine/control/first-person/abilities/Mantle.d.ts.map +1 -0
  217. package/src/engine/control/first-person/abilities/Mantle.js +188 -0
  218. package/src/engine/control/first-person/abilities/Slide.d.ts +33 -0
  219. package/src/engine/control/first-person/abilities/Slide.d.ts.map +1 -0
  220. package/src/engine/control/first-person/abilities/Slide.js +158 -0
  221. package/src/engine/control/first-person/abilities/WallJump.d.ts +45 -0
  222. package/src/engine/control/first-person/abilities/WallJump.d.ts.map +1 -0
  223. package/src/engine/control/first-person/abilities/WallJump.js +131 -0
  224. package/src/engine/control/first-person/abilities/WallRun.d.ts +44 -0
  225. package/src/engine/control/first-person/abilities/WallRun.d.ts.map +1 -0
  226. package/src/engine/control/first-person/abilities/WallRun.js +180 -0
  227. package/src/engine/control/first-person/composer/EyeOffsetStack.d.ts +49 -0
  228. package/src/engine/control/first-person/composer/EyeOffsetStack.d.ts.map +1 -0
  229. package/src/engine/control/first-person/composer/EyeOffsetStack.js +60 -0
  230. package/src/engine/control/first-person/mastery/BreathRhythmEvaluator.d.ts +100 -0
  231. package/src/engine/control/first-person/mastery/BreathRhythmEvaluator.d.ts.map +1 -0
  232. package/src/engine/control/first-person/mastery/BreathRhythmEvaluator.js +133 -0
  233. package/src/engine/control/first-person/mastery/DecisionPoint.d.ts +10 -0
  234. package/src/engine/control/first-person/mastery/DecisionPoint.d.ts.map +1 -0
  235. package/src/engine/control/first-person/mastery/DecisionPoint.js +30 -0
  236. package/src/engine/control/first-person/mastery/FootAsymmetryTurnEvaluator.d.ts +61 -0
  237. package/src/engine/control/first-person/mastery/FootAsymmetryTurnEvaluator.d.ts.map +1 -0
  238. package/src/engine/control/first-person/mastery/FootAsymmetryTurnEvaluator.js +109 -0
  239. package/src/engine/control/first-person/mastery/MasteryEvaluator.d.ts +40 -0
  240. package/src/engine/control/first-person/mastery/MasteryEvaluator.d.ts.map +1 -0
  241. package/src/engine/control/first-person/mastery/MasteryEvaluator.js +45 -0
  242. package/src/engine/control/first-person/mastery/MasteryScore.d.ts +68 -0
  243. package/src/engine/control/first-person/mastery/MasteryScore.d.ts.map +1 -0
  244. package/src/engine/control/first-person/mastery/MasteryScore.js +100 -0
  245. package/src/engine/control/first-person/mastery/MasterySet.d.ts +60 -0
  246. package/src/engine/control/first-person/mastery/MasterySet.d.ts.map +1 -0
  247. package/src/engine/control/first-person/mastery/MasterySet.js +86 -0
  248. package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.d.ts +58 -0
  249. package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.d.ts.map +1 -0
  250. package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.js +83 -0
  251. package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.d.ts +69 -0
  252. package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.d.ts.map +1 -0
  253. package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.js +109 -0
  254. package/src/engine/control/first-person/math/Spring.d.ts +56 -0
  255. package/src/engine/control/first-person/math/Spring.d.ts.map +1 -0
  256. package/src/engine/control/first-person/math/Spring.js +71 -0
  257. package/src/engine/control/first-person/math/computeLRCBreathRate.d.ts +26 -0
  258. package/src/engine/control/first-person/math/computeLRCBreathRate.d.ts.map +1 -0
  259. package/src/engine/control/first-person/math/computeLRCBreathRate.js +41 -0
  260. package/src/engine/control/first-person/math/computeMassRatios.d.ts +35 -0
  261. package/src/engine/control/first-person/math/computeMassRatios.d.ts.map +1 -0
  262. package/src/engine/control/first-person/math/computeMassRatios.js +44 -0
  263. package/src/engine/control/first-person/pose/FirstPersonPose.d.ts +31 -1
  264. package/src/engine/control/first-person/pose/FirstPersonPose.d.ts.map +1 -1
  265. package/src/engine/control/first-person/pose/FirstPersonPose.js +49 -3
  266. package/src/engine/control/first-person/pose/FirstPersonPosture.d.ts +7 -0
  267. package/src/engine/control/first-person/pose/FirstPersonPosture.d.ts.map +1 -0
  268. package/src/engine/control/first-person/pose/FirstPersonPosture.js +27 -0
  269. package/src/engine/control/first-person/prototype_first_person_controller.js +550 -119
  270. package/src/engine/control/first-person/sensors/FirstPersonSensors.d.ts +58 -0
  271. package/src/engine/control/first-person/sensors/FirstPersonSensors.d.ts.map +1 -0
  272. package/src/engine/control/first-person/sensors/FirstPersonSensors.js +77 -0
  273. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts +80 -0
  274. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts.map +1 -0
  275. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.js +196 -0
  276. package/src/engine/control/first-person/test/buildTestPlayer.d.ts +20 -0
  277. package/src/engine/control/first-person/test/buildTestPlayer.d.ts.map +1 -0
  278. package/src/engine/control/first-person/test/buildTestPlayer.js +28 -0
  279. package/src/engine/graphics/camera/testClippingPlaneComputation.js +0 -2
  280. package/src/engine/graphics/ecs/light/Light.d.ts.map +1 -1
  281. package/src/engine/graphics/ecs/light/Light.js +27 -0
  282. package/src/engine/graphics/ecs/light/LightSystem.js +1 -1
  283. package/src/engine/graphics/ecs/path/PathDisplaySystem.d.ts.map +1 -1
  284. package/src/engine/graphics/ecs/path/testPathDisplaySystem.js +0 -2
  285. package/src/engine/graphics/ecs/path/tube/prototypeAnimatedPathMask.js +0 -2
  286. package/src/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +0 -2
  287. package/src/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +0 -2
  288. package/src/engine/graphics/render/visibility/hiz/prototypeHiZ.js +0 -2
  289. package/src/engine/navigation/grid/find_path_on_grid_astar.d.ts.map +1 -1
  290. package/src/engine/navigation/grid/find_path_on_grid_astar.js +11 -2
  291. package/src/engine/navigation/mesh/bt_mesh_face_find_path.d.ts.map +1 -1
  292. package/src/engine/navigation/mesh/bt_mesh_face_find_path.js +11 -1
  293. package/src/engine/physics/PLAN.md +236 -0
  294. package/src/engine/physics/body/BodyStorage.d.ts +187 -0
  295. package/src/engine/physics/body/BodyStorage.d.ts.map +1 -0
  296. package/src/engine/physics/body/BodyStorage.js +427 -0
  297. package/src/engine/physics/broadphase/PairList.d.ts +62 -0
  298. package/src/engine/physics/broadphase/PairList.d.ts.map +1 -0
  299. package/src/engine/physics/broadphase/PairList.js +97 -0
  300. package/src/engine/physics/broadphase/aabb_transform_oriented.d.ts +30 -0
  301. package/src/engine/physics/broadphase/aabb_transform_oriented.d.ts.map +1 -0
  302. package/src/engine/physics/broadphase/aabb_transform_oriented.js +93 -0
  303. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts +16 -0
  304. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts.map +1 -0
  305. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +61 -0
  306. package/src/engine/physics/broadphase/generate_pairs.d.ts +38 -0
  307. package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -0
  308. package/src/engine/physics/broadphase/generate_pairs.js +101 -0
  309. package/src/engine/physics/contact/ManifoldStore.d.ts +226 -0
  310. package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -0
  311. package/src/engine/physics/contact/ManifoldStore.js +499 -0
  312. package/src/engine/physics/ecs/BodyKind.d.ts +23 -0
  313. package/src/engine/physics/ecs/BodyKind.d.ts.map +1 -0
  314. package/src/engine/physics/ecs/BodyKind.js +24 -0
  315. package/src/engine/physics/ecs/Collider.d.ts +98 -0
  316. package/src/engine/physics/ecs/Collider.d.ts.map +1 -0
  317. package/src/engine/physics/ecs/Collider.js +136 -0
  318. package/src/engine/physics/ecs/ColliderFlags.d.ts +14 -0
  319. package/src/engine/physics/ecs/ColliderFlags.d.ts.map +1 -0
  320. package/src/engine/physics/ecs/ColliderFlags.js +15 -0
  321. package/src/engine/physics/ecs/ColliderObserverSystem.d.ts +58 -0
  322. package/src/engine/physics/ecs/ColliderObserverSystem.d.ts.map +1 -0
  323. package/src/engine/physics/ecs/ColliderObserverSystem.js +103 -0
  324. package/src/engine/physics/ecs/ColliderSerializationAdapter.d.ts +25 -0
  325. package/src/engine/physics/ecs/ColliderSerializationAdapter.d.ts.map +1 -0
  326. package/src/engine/physics/ecs/ColliderSerializationAdapter.js +37 -0
  327. package/src/engine/physics/ecs/PhysicsEvents.d.ts +15 -0
  328. package/src/engine/physics/ecs/PhysicsEvents.d.ts.map +1 -0
  329. package/src/engine/physics/ecs/PhysicsEvents.js +16 -0
  330. package/src/engine/physics/ecs/PhysicsSystem.d.ts +520 -0
  331. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -0
  332. package/src/engine/physics/ecs/PhysicsSystem.js +1159 -0
  333. package/src/engine/physics/ecs/RigidBody.d.ts +197 -0
  334. package/src/engine/physics/ecs/RigidBody.d.ts.map +1 -0
  335. package/src/engine/physics/ecs/RigidBody.js +240 -0
  336. package/src/engine/physics/ecs/RigidBodyFlags.d.ts +21 -0
  337. package/src/engine/physics/ecs/RigidBodyFlags.d.ts.map +1 -0
  338. package/src/engine/physics/ecs/RigidBodyFlags.js +22 -0
  339. package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts +28 -0
  340. package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts.map +1 -0
  341. package/src/engine/physics/ecs/RigidBodySerializationAdapter.js +81 -0
  342. package/src/engine/physics/ecs/SleepState.d.ts +11 -0
  343. package/src/engine/physics/ecs/SleepState.d.ts.map +1 -0
  344. package/src/engine/physics/ecs/SleepState.js +12 -0
  345. package/src/engine/physics/events/ContactEventBuffer.d.ts +46 -0
  346. package/src/engine/physics/events/ContactEventBuffer.d.ts.map +1 -0
  347. package/src/engine/physics/events/ContactEventBuffer.js +83 -0
  348. package/src/engine/physics/events/diff_manifolds.d.ts +25 -0
  349. package/src/engine/physics/events/diff_manifolds.d.ts.map +1 -0
  350. package/src/engine/physics/events/diff_manifolds.js +50 -0
  351. package/src/engine/physics/fluid/FluidField.d.ts +294 -16
  352. package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
  353. package/src/engine/physics/fluid/FluidField.js +510 -66
  354. package/src/engine/physics/fluid/FluidSimulator.d.ts +188 -5
  355. package/src/engine/physics/fluid/FluidSimulator.d.ts.map +1 -1
  356. package/src/engine/physics/fluid/FluidSimulator.js +455 -95
  357. package/src/engine/physics/fluid/SliceVisualiser.d.ts +29 -6
  358. package/src/engine/physics/fluid/SliceVisualiser.d.ts.map +1 -1
  359. package/src/engine/physics/fluid/SliceVisualiser.js +190 -165
  360. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts +154 -0
  361. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -0
  362. package/src/engine/physics/fluid/ecs/FluidComponent.js +238 -0
  363. package/src/engine/physics/fluid/ecs/FluidEffectorsComponent.d.ts +45 -0
  364. package/src/engine/physics/fluid/ecs/FluidEffectorsComponent.d.ts.map +1 -0
  365. package/src/engine/physics/fluid/ecs/FluidEffectorsComponent.js +89 -0
  366. package/src/engine/physics/fluid/ecs/FluidSystem.d.ts +107 -0
  367. package/src/engine/physics/fluid/ecs/FluidSystem.d.ts.map +1 -0
  368. package/src/engine/physics/fluid/ecs/FluidSystem.js +278 -0
  369. package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts +62 -1
  370. package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts.map +1 -1
  371. package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +81 -6
  372. package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts +17 -4
  373. package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts.map +1 -1
  374. package/src/engine/physics/fluid/effector/GlobalFluidEffector.js +105 -12
  375. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.d.ts +43 -0
  376. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.d.ts.map +1 -0
  377. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.js +210 -0
  378. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts +62 -1
  379. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts.map +1 -1
  380. package/src/engine/physics/fluid/effector/WakeFluidEffector.js +302 -8
  381. package/src/engine/physics/fluid/prototype.js +102 -91
  382. package/src/engine/physics/fluid/solver/optimal_sor_omega.d.ts +33 -0
  383. package/src/engine/physics/fluid/solver/optimal_sor_omega.d.ts.map +1 -0
  384. package/src/engine/physics/fluid/solver/optimal_sor_omega.js +41 -0
  385. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts +20 -5
  386. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts.map +1 -1
  387. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.js +60 -38
  388. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts +25 -4
  389. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts.map +1 -1
  390. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.js +93 -73
  391. package/src/engine/physics/fluid/solver/v3_grid_apply_scalar_advection.d.ts +23 -0
  392. package/src/engine/physics/fluid/solver/v3_grid_apply_scalar_advection.d.ts.map +1 -0
  393. package/src/engine/physics/fluid/solver/v3_grid_apply_scalar_advection.js +60 -0
  394. package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.d.ts +23 -0
  395. package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.d.ts.map +1 -0
  396. package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.js +68 -0
  397. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts +30 -0
  398. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts.map +1 -0
  399. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.js +66 -0
  400. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_uniform.d.ts +26 -0
  401. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_uniform.d.ts.map +1 -0
  402. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_uniform.js +113 -0
  403. package/src/engine/physics/fluid/solver/v3_grid_shift_in_place.d.ts +30 -0
  404. package/src/engine/physics/fluid/solver/v3_grid_shift_in_place.d.ts.map +1 -0
  405. package/src/engine/physics/fluid/solver/v3_grid_shift_in_place.js +107 -0
  406. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts +49 -0
  407. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts.map +1 -0
  408. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.js +126 -0
  409. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts +93 -0
  410. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts.map +1 -0
  411. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.js +424 -0
  412. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.d.ts +20 -0
  413. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.d.ts.map +1 -0
  414. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.js +83 -0
  415. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts +26 -0
  416. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -0
  417. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +70 -0
  418. package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts.map +1 -1
  419. package/src/engine/physics/gjk/expanding_polytope_algorithm.js +8 -10
  420. package/src/engine/physics/inertia/world_inverse_inertia.d.ts +29 -0
  421. package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -0
  422. package/src/engine/physics/inertia/world_inverse_inertia.js +79 -0
  423. package/src/engine/physics/integration/integrate_position.d.ts +16 -0
  424. package/src/engine/physics/integration/integrate_position.d.ts.map +1 -0
  425. package/src/engine/physics/integration/integrate_position.js +48 -0
  426. package/src/engine/physics/integration/integrate_velocity.d.ts +25 -0
  427. package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -0
  428. package/src/engine/physics/integration/integrate_velocity.js +79 -0
  429. package/src/engine/physics/integration/quat_integrate.d.ts +27 -0
  430. package/src/engine/physics/integration/quat_integrate.d.ts.map +1 -0
  431. package/src/engine/physics/integration/quat_integrate.js +62 -0
  432. package/src/engine/physics/island/IslandBuilder.d.ts +167 -0
  433. package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -0
  434. package/src/engine/physics/island/IslandBuilder.js +411 -0
  435. package/src/engine/physics/island/union_find.d.ts +51 -0
  436. package/src/engine/physics/island/union_find.d.ts.map +1 -0
  437. package/src/engine/physics/island/union_find.js +76 -0
  438. package/src/engine/physics/narrowphase/PosedShape.d.ts +59 -0
  439. package/src/engine/physics/narrowphase/PosedShape.d.ts.map +1 -0
  440. package/src/engine/physics/narrowphase/PosedShape.js +110 -0
  441. package/src/engine/physics/narrowphase/box_box_manifold.d.ts +32 -0
  442. package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -0
  443. package/src/engine/physics/narrowphase/box_box_manifold.js +543 -0
  444. package/src/engine/physics/narrowphase/capsule_contacts.d.ts +122 -0
  445. package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -0
  446. package/src/engine/physics/narrowphase/capsule_contacts.js +508 -0
  447. package/src/engine/physics/narrowphase/narrowphase_step.d.ts +11 -0
  448. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -0
  449. package/src/engine/physics/narrowphase/narrowphase_step.js +382 -0
  450. package/src/engine/physics/narrowphase/sphere_box_contact.d.ts +38 -0
  451. package/src/engine/physics/narrowphase/sphere_box_contact.d.ts.map +1 -0
  452. package/src/engine/physics/narrowphase/sphere_box_contact.js +130 -0
  453. package/src/engine/physics/narrowphase/sphere_sphere_contact.d.ts +26 -0
  454. package/src/engine/physics/narrowphase/sphere_sphere_contact.d.ts.map +1 -0
  455. package/src/engine/physics/narrowphase/sphere_sphere_contact.js +51 -0
  456. package/src/engine/physics/queries/PhysicsSurfacePoint.d.ts +83 -0
  457. package/src/engine/physics/queries/PhysicsSurfacePoint.d.ts.map +1 -0
  458. package/src/engine/physics/queries/PhysicsSurfacePoint.js +100 -0
  459. package/src/engine/physics/queries/raycast.d.ts +20 -0
  460. package/src/engine/physics/queries/raycast.d.ts.map +1 -0
  461. package/src/engine/physics/queries/raycast.js +249 -0
  462. package/src/engine/physics/solver/friction_cone.d.ts +16 -0
  463. package/src/engine/physics/solver/friction_cone.d.ts.map +1 -0
  464. package/src/engine/physics/solver/friction_cone.js +37 -0
  465. package/src/engine/physics/solver/solve_contacts.d.ts +36 -0
  466. package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -0
  467. package/src/engine/physics/solver/solve_contacts.js +598 -0
  468. package/src/core/geom/3d/topology/struct/binary/io/edge/OrderedEdge.d.ts +0 -34
  469. package/src/core/geom/3d/topology/struct/binary/io/edge/OrderedEdge.d.ts.map +0 -1
  470. package/src/core/geom/3d/topology/struct/binary/io/edge/OrderedEdge.js +0 -66
  471. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_calc_edges.d.ts +0 -2
  472. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_calc_edges.d.ts.map +0 -1
  473. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_calc_edges.js +0 -54
  474. package/src/core/geom/3d/topology/struct/binary/io/edge/get_or_create_edge_map.d.ts +0 -2
  475. package/src/core/geom/3d/topology/struct/binary/io/edge/get_or_create_edge_map.d.ts.map +0 -1
  476. package/src/core/geom/3d/topology/struct/binary/io/edge/get_or_create_edge_map.js +0 -26
  477. package/src/engine/ecs/components/Motion.d.ts +0 -21
  478. package/src/engine/ecs/components/Motion.d.ts.map +0 -1
  479. package/src/engine/ecs/components/Motion.js +0 -27
  480. package/src/engine/ecs/components/MotionSerializationAdapter.d.ts +0 -20
  481. package/src/engine/ecs/components/MotionSerializationAdapter.d.ts.map +0 -1
  482. package/src/engine/ecs/components/MotionSerializationAdapter.js +0 -26
  483. package/src/engine/ecs/systems/MotionSystem.d.ts +0 -9
  484. package/src/engine/ecs/systems/MotionSystem.d.ts.map +0 -1
  485. package/src/engine/ecs/systems/MotionSystem.js +0 -29
  486. package/src/engine/physics/fluid/Fluid.d.ts +0 -26
  487. package/src/engine/physics/fluid/Fluid.d.ts.map +0 -1
  488. package/src/engine/physics/fluid/Fluid.js +0 -221
  489. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_reverse.d.ts +0 -7
  490. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_reverse.d.ts.map +0 -1
  491. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_reverse.js +0 -8
@@ -1,9 +1,13 @@
1
1
  import { BoxGeometry, MeshStandardMaterial } from "three";
2
+ import { Ray3 } from "../../../core/geom/3d/ray/Ray3.js";
3
+ import { BoxShape3D } from "../../../core/geom/3d/shape/BoxShape3D.js";
4
+ import { CapsuleShape3D } from "../../../core/geom/3d/shape/CapsuleShape3D.js";
2
5
  import Vector2 from "../../../core/geom/Vector2.js";
3
6
  import Vector3 from "../../../core/geom/Vector3.js";
4
7
  import { SerializationMetadata } from "../../ecs/components/SerializationMetadata.js";
5
8
  import { Tag } from "../../ecs/components/Tag.js";
6
9
  import Entity from "../../ecs/Entity.js";
10
+ import { obtainTerrain } from "../../ecs/terrain/util/obtainTerrain.js";
7
11
  import { Transform } from "../../ecs/transform/Transform.js";
8
12
  import { EngineHarness } from "../../EngineHarness.js";
9
13
  import { CameraSystem } from "../../graphics/ecs/camera/CameraSystem.js";
@@ -12,11 +16,29 @@ import { ShadedGeometryFlags } from "../../graphics/ecs/mesh-v2/ShadedGeometryFl
12
16
  import { ShadedGeometrySystem } from "../../graphics/ecs/mesh-v2/ShadedGeometrySystem.js";
13
17
  import InputController from "../../input/ecs/components/InputController.js";
14
18
  import InputControllerSystem from "../../input/ecs/systems/InputControllerSystem.js";
19
+ import { BodyKind } from "../../physics/ecs/BodyKind.js";
20
+ import { Collider } from "../../physics/ecs/Collider.js";
21
+ import { ColliderObserverSystem } from "../../physics/ecs/ColliderObserverSystem.js";
22
+ import { PhysicsSystem } from "../../physics/ecs/PhysicsSystem.js";
23
+ import { RigidBody } from "../../physics/ecs/RigidBody.js";
24
+ import { PhysicsSurfacePoint } from "../../physics/queries/PhysicsSurfacePoint.js";
25
+ import { LedgeGrab } from "./abilities/LedgeGrab.js";
26
+ import { Mantle } from "./abilities/Mantle.js";
27
+ import { Slide } from "./abilities/Slide.js";
28
+ import { WallJump } from "./abilities/WallJump.js";
29
+ import { WallRun } from "./abilities/WallRun.js";
15
30
  import { FirstPersonPlayerController } from "./FirstPersonPlayerController.js";
16
31
  import { FirstPersonPlayerControllerSystem } from "./FirstPersonPlayerControllerSystem.js";
32
+ import { BreathRhythmEvaluator } from "./mastery/BreathRhythmEvaluator.js";
33
+ import { DecisionPoint } from "./mastery/DecisionPoint.js";
34
+ import { FootAsymmetryTurnEvaluator } from "./mastery/FootAsymmetryTurnEvaluator.js";
35
+ import { SlideInitiationTimingEvaluator } from "./mastery/SlideInitiationTimingEvaluator.js";
36
+ import { StrideTimingJumpEvaluator } from "./mastery/StrideTimingJumpEvaluator.js";
37
+ import { FirstPersonSensorsSystem } from "./sensors/FirstPersonSensorsSystem.js";
17
38
 
18
39
  /**
19
- * Prototype harness for {@link FirstPersonPlayerController}.
40
+ * Prototype harness for {@link FirstPersonPlayerController} — a parkour
41
+ * "gym" laid out as discrete test stations around the spawn point.
20
42
  *
21
43
  * Controls:
22
44
  * - Click to capture mouse (pointer lock); ESC to release
@@ -24,12 +46,38 @@ import { FirstPersonPlayerControllerSystem } from "./FirstPersonPlayerController
24
46
  * - Mouse — look
25
47
  * - Space — jump (tap; holding does not auto-repeat)
26
48
  * - Shift — sprint (hold while moving forward)
27
- * - C — crouch (hold)
49
+ * - C — crouch (hold; sprint+crouch press → slide)
28
50
  *
29
- * Scene: a flat ground at y=0 with a handful of coloured cubes for spatial
30
- * reference, lit by the harness's default sun.
51
+ * Stations (compass directions from spawn):
52
+ *
53
+ * N Mantle row four obstacles from too-low to too-tall
54
+ * NE Slide tunnel sprint run-up + low ceiling
55
+ * E Wall-run wall one long wall to run alongside
56
+ * SE Gap jump raised platforms with a gap to clear
57
+ * S Ledge-grab wall too tall to mantle; jump + catch the lip
58
+ * SW (open)
59
+ * W Wall-jump chimney two parallel walls for back-and-forth jumps
60
+ * NW (open)
61
+ *
62
+ * Each station is colour-coded at the entrance. Look around: the
63
+ * coloured pad on the ground tells you what's there.
64
+ *
65
+ * @author Alex Goldring
66
+ * @copyright Company Named Limited (c) 2026
31
67
  */
32
68
 
69
+ const SPAWN_X = 100;
70
+ const SPAWN_Z = 100;
71
+
72
+ // Station palette — used for entry pads + matching obstacle colour.
73
+ const COLOR_MANTLE = 0x55ff55;
74
+ const COLOR_WALLRUN = 0xff5555;
75
+ const COLOR_WALLJUMP = 0xaa55ff;
76
+ const COLOR_LEDGE = 0xffaa44;
77
+ const COLOR_SLIDE = 0x44ddee;
78
+ const COLOR_GAP = 0xff66cc;
79
+ const COLOR_NEUTRAL = 0xaaaaaa;
80
+
33
81
  const eh = new EngineHarness();
34
82
 
35
83
  async function main(engine) {
@@ -43,6 +91,8 @@ async function main(engine) {
43
91
  engine,
44
92
  sunIntensity: 1.0,
45
93
  ambientIntensity: 0.25,
94
+ shadowmapResolution: 2048,
95
+ sunShadowDistance: 30,
46
96
  });
47
97
 
48
98
  if (em.getSystem(CameraSystem) === null) {
@@ -55,11 +105,30 @@ async function main(engine) {
55
105
  await em.addSystem(new ShadedGeometrySystem(engine));
56
106
  }
57
107
 
108
+ // Physics — owns RigidBody+Collider lifecycle, fires contact events,
109
+ // and serves spatial queries (raycast). Sensors and the ground
110
+ // resolver both go through it. Added BEFORE the controller so the
111
+ // sensors and ground resolver find it in their startup auto-acquire.
112
+ const physicsSystem = new PhysicsSystem();
113
+ await em.addSystem(physicsSystem);
114
+ // ColliderObserver wires Collider components into PhysicsSystem
115
+ // bodies as entities are built. Without it, every collider would
116
+ // need an explicit attach_collider call.
117
+ await em.addSystem(new ColliderObserverSystem(physicsSystem));
118
+
58
119
  const fpsSystem = new FirstPersonPlayerControllerSystem();
59
- fpsSystem.useBuiltInFlatGround = true;
60
- fpsSystem.groundY = 0;
120
+ // Built-in flat-ground OFF — the gym uses the physics-backed ground
121
+ // resolver below (which finds the highest static surface under the
122
+ // player from BVH raycasts). Leaving the flat baseline on would
123
+ // pin the player to y=0 even when standing on a 2 m platform.
124
+ fpsSystem.useBuiltInFlatGround = false;
61
125
  await em.addSystem(fpsSystem);
62
126
 
127
+ // Sensors system — populates wall/obstacle/ledge probes via
128
+ // PhysicsSystem.raycast. Auto-acquires the physics system in startup.
129
+ const sensorsSystem = new FirstPersonSensorsSystem();
130
+ await em.addSystem(sensorsSystem);
131
+
63
132
  if (!ecd.isComponentTypeRegistered(Tag)) {
64
133
  ecd.registerComponentType(Tag);
65
134
  }
@@ -76,11 +145,22 @@ async function main(engine) {
76
145
  diffuse0: "data/textures/materials/terrain_township_set/512/Grass_3.png",
77
146
  });
78
147
 
79
- addReferenceMarkers(ecd);
148
+ obtainTerrain(ecd); // no-op call to ensure terrain is built
149
+
150
+ buildGym(ecd);
80
151
 
81
152
  // -- Player ----------------------------------------------------------
82
153
  const player = buildPlayerEntity(ecd);
83
154
 
155
+ // Ground resolver: downward raycast through PhysicsSystem, filtered
156
+ // to exclude the player's own capsule. Wired AFTER the player is
157
+ // built so the filter has the right entity id. The controller's
158
+ // vertical integrator falls through when the resolver returns null
159
+ // (no platform below) — set up with `useBuiltInFlatGround = false`
160
+ // above so that means actual airborne / void, not a hidden y=0
161
+ // safety floor.
162
+ fpsSystem.groundResolver = makePhysicsGroundResolver(physicsSystem, player.entity);
163
+
84
164
  // -- Inputs ----------------------------------------------------------
85
165
  buildInputBindings(ecd, player);
86
166
 
@@ -89,26 +169,461 @@ async function main(engine) {
89
169
  logHelp();
90
170
  }
91
171
 
172
+ /**
173
+ * Downward-raycast ground resolver, backed by {@link PhysicsSystem.raycast}.
174
+ * Each call: from just above the player's feet, cast straight down
175
+ * through static + dynamic broadphase; filter out the player's own
176
+ * body; return the hit y, or null if no surface below.
177
+ *
178
+ * The controller's vertical integrator picks max(useBuiltInFlatGround,
179
+ * resolver). In the gym we leave useBuiltInFlatGround off so the
180
+ * resolver is the sole source of truth — gaps in the floor are real
181
+ * gaps (the player falls into them).
182
+ *
183
+ * @param {PhysicsSystem} physicsSystem
184
+ * @param {number} playerEntity excluded from raycasts to skip the player capsule
185
+ * @returns {(x:number, y:number, z:number) => number|null}
186
+ */
187
+ function makePhysicsGroundResolver(physicsSystem, playerEntity) {
188
+ // Probe starts slightly above the player feet so a grounded player
189
+ // standing right on a platform still raycasts cleanly. Length is
190
+ // longer than any reasonable gym platform.
191
+ const PROBE_LIFT = 0.1;
192
+ const PROBE_DOWN = 50;
193
+ const filter = (entity) => entity !== playerEntity;
194
+ // Reuse a single ray and surface-point across calls — the resolver
195
+ // can fire many times per frame as the controller hunts for foothold.
196
+ const ray = Ray3.from(0, 0, 0, 0, -1, 0, PROBE_DOWN);
197
+ const hit = new PhysicsSurfacePoint();
198
+ return function physicsGroundResolver(x, y, z) {
199
+ ray.setOrigin(x, y + PROBE_LIFT, z);
200
+ if (!physicsSystem.raycast(ray, hit, filter)) return null;
201
+ // Direction is unit (0,-1,0); t is the distance to the surface
202
+ // along that direction. Surface Y = origin Y minus t.
203
+ return (y + PROBE_LIFT) - hit.t;
204
+ };
205
+ }
206
+
207
+ // =====================================================================
208
+ // Gym construction
209
+ // =====================================================================
210
+
211
+ function buildGym(ecd) {
212
+ buildGroundPlane(ecd);
213
+ buildSpawnPlaza(ecd);
214
+ buildMantleStation(ecd);
215
+ buildWallRunStation(ecd);
216
+ buildWallJumpChimney(ecd);
217
+ buildLedgeGrabStation(ecd);
218
+ buildSlideTunnel(ecd);
219
+ buildGapJumpStation(ecd);
220
+ }
221
+
222
+ /**
223
+ * Reference markers around spawn so motion is visually obvious — a ring
224
+ * of coloured cubes (circle-strafe targets) and a few tall pillars at
225
+ * radius 22 for parallax-at-distance.
226
+ */
227
+ function buildSpawnPlaza(ecd) {
228
+ const unitCubeGeom = new BoxGeometry(1, 1, 1);
229
+ const palette = [
230
+ 0xff5555, 0x55ff55, 0x5577ff, 0xffaa44,
231
+ 0xaa55ff, 0x44ddee, 0xff66cc, 0x66ffcc,
232
+ ];
233
+
234
+ // Inner ring at radius 6 — close enough to circle-strafe around.
235
+ const RING_N = 8;
236
+ for (let i = 0; i < RING_N; i++) {
237
+ const a = (i / RING_N) * Math.PI * 2;
238
+ spawnBox(ecd, {
239
+ center: new Vector3(SPAWN_X + Math.cos(a) * 6, 0.5, SPAWN_Z + Math.sin(a) * 6),
240
+ size: new Vector3(1, 1, 1),
241
+ geometry: unitCubeGeom,
242
+ color: palette[i % palette.length],
243
+ });
244
+ }
245
+
246
+ // Tall pillars further out — parallax depth perception when running.
247
+ const pillarGeom = new BoxGeometry(1, 6, 1);
248
+ const PILLAR_N = 6;
249
+ for (let i = 0; i < PILLAR_N; i++) {
250
+ const a = (i / PILLAR_N) * Math.PI * 2 + 0.3;
251
+ const r = 22;
252
+ spawnBox(ecd, {
253
+ center: new Vector3(SPAWN_X + Math.cos(a) * r, 3, SPAWN_Z + Math.sin(a) * r),
254
+ size: new Vector3(1, 6, 1),
255
+ geometry: pillarGeom,
256
+ color: 0x888888,
257
+ roughness: 0.9,
258
+ });
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Mantle row — directly north of spawn. Four obstacles in line, heights
264
+ * stepping past the mantle range:
265
+ *
266
+ * - 0.6m: well within mantle range; lowest "step-up" test
267
+ * - 1.0m: mid mantle range
268
+ * - 1.3m: near top of mantle range
269
+ * - 2.0m: too tall to mantle from the ground (heightDiff > maxHeight)
270
+ *
271
+ * The 2.0m block is also the canonical "LedgeGrab if you jump at it"
272
+ * candidate, but the dedicated LedgeGrab station to the south has a
273
+ * cleaner approach path.
274
+ */
275
+ function buildMantleStation(ecd) {
276
+ const baseZ = SPAWN_Z + 15;
277
+ spawnPad(ecd, SPAWN_X, baseZ - 3, COLOR_MANTLE);
278
+
279
+ const heights = [0.6, 1.0, 1.3, 2.0];
280
+ for (let i = 0; i < heights.length; i++) {
281
+ const h = heights[i];
282
+ spawnBox(ecd, {
283
+ center: new Vector3(SPAWN_X, h / 2, baseZ + i * 5),
284
+ size: new Vector3(3, h, 1),
285
+ color: COLOR_MANTLE,
286
+ roughness: 0.6,
287
+ });
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Wall-run wall — a long wall on the east side. Player runs east past
293
+ * spawn, jumps near the wall, runs along it.
294
+ *
295
+ * Two walls actually — left and right — so the player can wall-run on
296
+ * either side without needing to circle back.
297
+ */
298
+ function buildWallRunStation(ecd) {
299
+ const baseX = SPAWN_X + 15;
300
+ spawnPad(ecd, baseX - 3, SPAWN_Z, COLOR_WALLRUN);
301
+
302
+ // South wall (run along its north face).
303
+ spawnBox(ecd, {
304
+ center: new Vector3(baseX + 5, 2, SPAWN_Z - 2),
305
+ size: new Vector3(10, 4, 0.5),
306
+ color: COLOR_WALLRUN,
307
+ roughness: 0.6,
308
+ });
309
+ // North wall (run along its south face) — separated by 4m so the
310
+ // wall-runner picks one side, not both.
311
+ spawnBox(ecd, {
312
+ center: new Vector3(baseX + 5, 2, SPAWN_Z + 2),
313
+ size: new Vector3(10, 4, 0.5),
314
+ color: COLOR_WALLRUN,
315
+ roughness: 0.6,
316
+ });
317
+ }
318
+
319
+ /**
320
+ * Wall-jump chimney — two parallel walls on the west side, ~3m apart,
321
+ * 6m tall. Player walks into the gap, jumps, hits one wall, wall-jumps
322
+ * to the other side. Repeat to climb.
323
+ *
324
+ * The walls are wide enough that wall-jumping straight back to the
325
+ * other side stays inside the chimney.
326
+ */
327
+ function buildWallJumpChimney(ecd) {
328
+ const baseX = SPAWN_X - 15;
329
+ spawnPad(ecd, baseX + 3, SPAWN_Z, COLOR_WALLJUMP);
330
+
331
+ // North wall of the chimney (pushes south).
332
+ spawnBox(ecd, {
333
+ center: new Vector3(baseX - 2, 3, SPAWN_Z + 2),
334
+ size: new Vector3(4, 6, 0.5),
335
+ color: COLOR_WALLJUMP,
336
+ roughness: 0.6,
337
+ });
338
+ // South wall of the chimney (pushes north). 3m gap to the north wall.
339
+ spawnBox(ecd, {
340
+ center: new Vector3(baseX - 2, 3, SPAWN_Z - 1.25),
341
+ size: new Vector3(4, 6, 0.5),
342
+ color: COLOR_WALLJUMP,
343
+ roughness: 0.6,
344
+ });
345
+ }
346
+
347
+ /**
348
+ * Ledge-grab station — a single 2m-tall wall just south of spawn.
349
+ * Too tall to mantle from the ground (heightDiff = 2 > maxHeight 1.4),
350
+ * but the player can run-jump at it and catch the lip on descent:
351
+ *
352
+ * 1. sprint south
353
+ * 2. jump just before the wall
354
+ * 3. on the way down, chest probe hits the wall face;
355
+ * ledgeAhead probe finds the top → LedgeGrab fires
356
+ * 4. press jump to chain into Mantle (mantle-up release)
357
+ *
358
+ * The wall is 6m wide so the player doesn't have to aim perfectly.
359
+ */
360
+ function buildLedgeGrabStation(ecd) {
361
+ const baseZ = SPAWN_Z - 15;
362
+ spawnPad(ecd, SPAWN_X, baseZ + 3, COLOR_LEDGE);
363
+
364
+ spawnBox(ecd, {
365
+ center: new Vector3(SPAWN_X, 1.0, baseZ - 1),
366
+ size: new Vector3(6, 2.0, 2),
367
+ color: COLOR_LEDGE,
368
+ roughness: 0.6,
369
+ });
370
+
371
+ // A larger top-of-wall platform behind the lip, so once the player
372
+ // climbs up they have somewhere to stand and look around.
373
+ spawnBox(ecd, {
374
+ center: new Vector3(SPAWN_X, 1.0, baseZ - 4.5),
375
+ size: new Vector3(6, 2.0, 5),
376
+ color: COLOR_LEDGE,
377
+ roughness: 0.6,
378
+ });
379
+ }
380
+
381
+ /**
382
+ * Slide tunnel — a sprint run-up followed by a low ceiling that forces
383
+ * the player to slide under. NE of spawn.
384
+ *
385
+ * Layout: a long flat lane (just an entry pad / marker, ground is
386
+ * already flat), with an overhead box at 1m height. Approaching at
387
+ * sprint + crouch press → slide → fits under the gap.
388
+ */
389
+ function buildSlideTunnel(ecd) {
390
+ const baseX = SPAWN_X + 11;
391
+ const baseZ = SPAWN_Z + 11;
392
+ spawnPad(ecd, baseX, baseZ, COLOR_SLIDE);
393
+
394
+ // The "ceiling" — a slab suspended 1.0m above the ground. Sliding
395
+ // brings the eye height down to ~0.4m; standing-eye-height would
396
+ // collide.
397
+ spawnBox(ecd, {
398
+ center: new Vector3(baseX + 4, 1.5, baseZ + 4),
399
+ size: new Vector3(4, 1.0, 4),
400
+ color: COLOR_SLIDE,
401
+ roughness: 0.6,
402
+ });
403
+
404
+ // Side pillars to make the tunnel feel like a tunnel.
405
+ spawnBox(ecd, {
406
+ center: new Vector3(baseX + 4, 1.0, baseZ + 2.0),
407
+ size: new Vector3(4, 2.0, 0.5),
408
+ color: COLOR_SLIDE,
409
+ roughness: 0.7,
410
+ });
411
+ spawnBox(ecd, {
412
+ center: new Vector3(baseX + 4, 1.0, baseZ + 6.0),
413
+ size: new Vector3(4, 2.0, 0.5),
414
+ color: COLOR_SLIDE,
415
+ roughness: 0.7,
416
+ });
417
+ }
418
+
419
+ /**
420
+ * Gap jump — two elevated platforms with a 3m gap between them. Player
421
+ * approaches via a mantle stair, runs across the first platform,
422
+ * sprints + jumps the gap.
423
+ *
424
+ * The platforms sit 1.5m above the spawn ground (mantleable). The gap
425
+ * doesn't actually break the floor — landing flat would still catch
426
+ * the player on the y=0 floor below. That's fine for testing the
427
+ * mid-flight feel of a jump; survival of misses is a feature here.
428
+ */
429
+ function buildGapJumpStation(ecd) {
430
+ const baseX = SPAWN_X + 11;
431
+ const baseZ = SPAWN_Z - 11;
432
+ spawnPad(ecd, baseX, baseZ, COLOR_GAP);
433
+
434
+ // Approach mantle (step up to the first platform).
435
+ spawnBox(ecd, {
436
+ center: new Vector3(baseX + 2, 0.5, baseZ - 2),
437
+ size: new Vector3(2, 1.0, 2),
438
+ color: COLOR_GAP,
439
+ roughness: 0.7,
440
+ });
441
+
442
+ // First platform — 4m long along Z.
443
+ spawnBox(ecd, {
444
+ center: new Vector3(baseX + 5, 0.75, baseZ - 4),
445
+ size: new Vector3(4, 1.5, 4),
446
+ color: COLOR_GAP,
447
+ roughness: 0.6,
448
+ });
449
+
450
+ // Second platform — same height, 3m gap.
451
+ spawnBox(ecd, {
452
+ center: new Vector3(baseX + 5, 0.75, baseZ - 11),
453
+ size: new Vector3(4, 1.5, 4),
454
+ color: COLOR_GAP,
455
+ roughness: 0.6,
456
+ });
457
+ }
458
+
459
+ // =====================================================================
460
+ // Spawn helpers
461
+ // =====================================================================
462
+
463
+ /**
464
+ * Add a box-shaped obstacle to the world. Position is the box centre.
465
+ *
466
+ * Single entity carrying both visual (ShadedGeometry) and physical
467
+ * (RigidBody + Collider) representations so the player can stand on it,
468
+ * sensors can raycast against it, and dynamic crates (when added) bump
469
+ * off it. Bodies are {@link BodyKind.Static} — gym geometry never moves.
470
+ *
471
+ * @param {EntityComponentDataset} ecd
472
+ * @param {object} p
473
+ * @param {Vector3} p.center
474
+ * @param {Vector3} p.size w, h, d (box dimensions)
475
+ * @param {number} p.color
476
+ * @param {number} [p.roughness]
477
+ * @param {THREE.BufferGeometry} [p.geometry] reuse to avoid new geometry per spawn
478
+ * @param {string} [p.tag]
479
+ * @param {boolean} [p.collide] default true; set false for decorative pads
480
+ */
481
+ function spawnBox(ecd, { center, size, color, roughness = 0.7, geometry, tag = "GymObstacle", collide = true }) {
482
+ const geom = geometry !== undefined ? geometry : new BoxGeometry(size.x, size.y, size.z);
483
+ const material = new MeshStandardMaterial({ color, roughness });
484
+ const sg = ShadedGeometry.from(geom, material);
485
+ sg.setFlag(ShadedGeometryFlags.CastShadow);
486
+ sg.setFlag(ShadedGeometryFlags.ReceiveShadow);
487
+ sg.setFlag(ShadedGeometryFlags.Visible);
488
+
489
+ const transform = new Transform();
490
+ transform.position.copy(center);
491
+
492
+ const eb = new Entity()
493
+ .add(sg)
494
+ .add(Tag.fromJSON([tag]))
495
+ .add(SerializationMetadata.Transient);
496
+
497
+ if (collide) {
498
+ const rigidBody = new RigidBody();
499
+ rigidBody.kind = BodyKind.Static;
500
+ const collider = new Collider();
501
+ // BoxShape3D with explicit half-extents — routes through the
502
+ // closed-form sphere-box / box-box / capsule-box narrowphase paths
503
+ // instead of degenerating into GJK+EPA, which is unreliable on
504
+ // smooth-surface pairs like capsule-vs-box.
505
+ collider.shape = BoxShape3D.from_size(size.x, size.y, size.z);
506
+ // Transform is added LAST so the (RigidBody, Transform) tuple
507
+ // completes only after the body is present — PhysicsSystem.link
508
+ // is the trigger, not the rigidBody add.
509
+ eb.add(rigidBody).add(collider).add(transform).build(ecd);
510
+ } else {
511
+ eb.add(transform).build(ecd);
512
+ }
513
+ }
514
+
515
+ /**
516
+ * Lay a thin coloured "entry pad" on the ground at (x, z). Visual
517
+ * landmark only — flush with the floor, no collision (a 5 cm-thick
518
+ * static body in the player's walking path would bump the camera).
519
+ */
520
+ function spawnPad(ecd, x, z, color) {
521
+ spawnBox(ecd, {
522
+ center: new Vector3(x, 0.025, z),
523
+ size: new Vector3(4, 0.05, 4),
524
+ color,
525
+ roughness: 0.95,
526
+ tag: "GymEntryPad",
527
+ collide: false,
528
+ });
529
+ }
530
+
531
+ /**
532
+ * Lay a physics-only ground body underneath the entire gym so the
533
+ * player has something to stand on. The terrain mesh provides the
534
+ * grass visual at y=0; this is its physics counterpart (the player
535
+ * controller's vertical integrator and sensors only look at physics
536
+ * bodies, not the terrain heightfield).
537
+ *
538
+ * Sized to comfortably encompass all stations (the gym spans ~30 m
539
+ * radius around spawn). The slab top sits at y=0 — same as the
540
+ * terrain visual — so standing on it puts the player's feet on the
541
+ * grass.
542
+ */
543
+ function buildGroundPlane(ecd) {
544
+ const SIZE = 120;
545
+ const THICKNESS = 1.0;
546
+
547
+ const rigidBody = new RigidBody();
548
+ rigidBody.kind = BodyKind.Static;
549
+ const collider = new Collider();
550
+ collider.shape = BoxShape3D.from_size(SIZE, THICKNESS, SIZE);
551
+
552
+ const transform = new Transform();
553
+ // Top face at y=0 → centre at y = -thickness/2.
554
+ transform.position.set(SPAWN_X, -THICKNESS / 2, SPAWN_Z);
555
+
556
+ new Entity()
557
+ .add(rigidBody)
558
+ .add(collider)
559
+ .add(Tag.fromJSON(["GymGroundPlane"]))
560
+ .add(SerializationMetadata.Transient)
561
+ .add(transform)
562
+ .build(ecd);
563
+ }
564
+
565
+ // =====================================================================
566
+ // Player + input
567
+ // =====================================================================
568
+
92
569
  /**
93
570
  * @param {EntityComponentDataset} ecd
94
571
  * @returns {{entity:number, controller:FirstPersonPlayerController}}
95
572
  */
96
573
  function buildPlayerEntity(ecd) {
97
574
  const transform = new Transform();
98
- // Spawn standing on the ground (body origin sits at the feet)
99
- transform.position.set(100, 0, 100);
575
+ // Spawn standing on the ground at the centre of the plaza.
576
+ transform.position.set(SPAWN_X, 0, SPAWN_Z);
100
577
 
101
578
  const controller = new FirstPersonPlayerController();
102
- // Most tuning lives at config defaults; mass-tweak example shown for
103
- // documentation. Comment out for the default soldier feel.
104
- // controller.config.body.mass = 120;
105
- // controller.config.bob.verticalAmpAtWalk = 0.08;
106
579
 
580
+ // Movement abilities (priority order — see DESIGN_EXTENSIONS §2.2):
581
+ // Slide(10) < Mantle(30) < LedgeGrab(40) < WallRun(50) < WallJump(60).
582
+ controller.abilities.add(new Slide());
583
+ controller.abilities.add(new Mantle());
584
+ controller.abilities.add(new LedgeGrab());
585
+ controller.abilities.add(new WallRun());
586
+ controller.abilities.add(new WallJump());
587
+
588
+ // Mastery evaluators — small bonuses/penalties tied to gait phase,
589
+ // foot asymmetry, and breath rhythm. Each fires on one (or a few)
590
+ // DecisionPoint(s); contributions compose multiplicatively.
591
+ controller.mastery.add(new StrideTimingJumpEvaluator());
592
+ controller.mastery.add(new SlideInitiationTimingEvaluator());
593
+ controller.mastery.add(new FootAsymmetryTurnEvaluator());
594
+ controller.mastery.add(new BreathRhythmEvaluator());
595
+ controller.mastery.add(new BreathRhythmEvaluator({
596
+ decisionPoints: [DecisionPoint.GroundAccel],
597
+ peakBonus: 0.015,
598
+ troughPenalty: 0.005,
599
+ requireExertionAbove: 0.3,
600
+ }));
601
+
602
+ // Kinematic capsule body: the controller writes Transform directly,
603
+ // physics derives velocity from the per-step delta. Capsule centred
604
+ // on the Transform — bottom hemisphere extends below the feet (this
605
+ // is fine for spatial queries since sensor probes start at chest
606
+ // height and the ground resolver filters out the player's own body).
607
+ const bodyCfg = controller.config.body;
608
+ const radius = bodyCfg.radius;
609
+ const totalHeight = bodyCfg.height; // standing eye height ≈ body extent
610
+ const cylinderHeight = Math.max(0, totalHeight - 2 * radius);
611
+ const rigidBody = new RigidBody();
612
+ rigidBody.kind = BodyKind.KinematicPosition;
613
+ rigidBody.mass = bodyCfg.mass;
614
+ const collider = new Collider();
615
+ collider.shape = CapsuleShape3D.from(radius, cylinderHeight);
616
+
617
+ // Build order matters: Transform is added LAST so the FirstPerson
618
+ // controller system's link() sees the RigidBody already attached.
619
+ // (Same pattern as the spec helpers.)
107
620
  const eb = new Entity()
108
- .add(transform)
109
621
  .add(controller)
622
+ .add(rigidBody)
623
+ .add(collider)
110
624
  .add(Tag.fromJSON(["Player"]))
111
- .add(SerializationMetadata.Transient);
625
+ .add(SerializationMetadata.Transient)
626
+ .add(transform);
112
627
 
113
628
  eb.build(ecd);
114
629
 
@@ -116,9 +631,7 @@ function buildPlayerEntity(ecd) {
116
631
  }
117
632
 
118
633
  /**
119
- * Wire keyboard + mouse to the controller's intent surface. Uses the same
120
- * `InputController` plumbing as the orbital-camera controller, so the
121
- * standard `InputControllerSystem` does the device subscription bookkeeping.
634
+ * Wire keyboard + mouse to the controller's intent surface.
122
635
  *
123
636
  * @param {EntityComponentDataset} ecd
124
637
  * @param {{entity:number, controller:FirstPersonPlayerController}} player
@@ -128,14 +641,9 @@ function buildInputBindings(ecd, player) {
128
641
  const intent = player.controller.intent;
129
642
 
130
643
  // Mouse sensitivity — radians of view rotation per pixel of mouse delta.
131
- // ~1200px sweep = one full 360° turn. Comparable to Source-engine
132
- // "sensitivity 2" at 800 DPI; calmer than typical web demos.
133
644
  const SENSITIVITY = (Math.PI * 2) / 1200;
134
645
 
135
646
  // -- WASD movement --------------------------------------------------
136
- // Keep a small "held" mirror so we can recompute intent.move whenever
137
- // any of the four keys change. We can't read intent.move directly
138
- // because both keys can be pressed simultaneously.
139
647
  const held = { w: false, a: false, s: false, d: false };
140
648
 
141
649
  function recomputeMove() {
@@ -148,15 +656,22 @@ function buildInputBindings(ecd, player) {
148
656
  }
149
657
 
150
658
  function bindMoveKey(key, prop) {
151
- ic.bind(`keyboard/keys/${key}/down`, () => { held[prop] = true; recomputeMove(); });
152
- ic.bind(`keyboard/keys/${key}/up`, () => { held[prop] = false; recomputeMove(); });
659
+ ic.bind(`keyboard/keys/${key}/down`, () => {
660
+ held[prop] = true;
661
+ recomputeMove();
662
+ });
663
+ ic.bind(`keyboard/keys/${key}/up`, () => {
664
+ held[prop] = false;
665
+ recomputeMove();
666
+ });
153
667
  }
668
+
154
669
  bindMoveKey("w", "w");
155
670
  bindMoveKey("a", "a");
156
671
  bindMoveKey("s", "s");
157
672
  bindMoveKey("d", "d");
158
673
 
159
- // -- Jump (hold-state; the system does the edge detection) -----------
674
+ // -- Jump ------------------------------------------------------------
160
675
  ic.bind("keyboard/keys/space/down", () => { intent.jump = true; });
161
676
  ic.bind("keyboard/keys/space/up", () => { intent.jump = false; });
162
677
 
@@ -169,16 +684,11 @@ function buildInputBindings(ecd, player) {
169
684
  ic.bind("keyboard/keys/c/up", () => { intent.crouch = false; });
170
685
 
171
686
  // -- Mouse look ------------------------------------------------------
172
- // Only accumulate look delta while the pointer is captured — otherwise
173
- // moving the cursor over the page would steer the camera, which is
174
- // jarring before the user has "claimed" the input surface.
175
687
  ic.bind("pointer/on/move", (position, event, delta) => {
176
688
  if (document.pointerLockElement === null) return;
177
689
  intent.look._add(delta.x * SENSITIVITY, delta.y * SENSITIVITY);
178
690
  });
179
691
 
180
- // When the InputController unlinks (e.g. system shutdown), zero
181
- // everything so a held key doesn't get stuck.
182
692
  ic.on.unlinked.add(() => {
183
693
  intent.move.set(0, 0);
184
694
  intent.look.set(0, 0);
@@ -200,10 +710,6 @@ function buildInputBindings(ecd, player) {
200
710
  */
201
711
  function setupPointerLock(engine) {
202
712
  const el = engine.graphics.domElement;
203
-
204
- // The harness wires the engine into the page body via viewStack; the
205
- // canvas is the actual pointer-lock target. Listen on the viewStack
206
- // element so clicks anywhere inside the canvas trigger the request.
207
713
  const captureEl = engine.viewStack.el;
208
714
 
209
715
  captureEl.addEventListener("click", () => {
@@ -212,98 +718,23 @@ function setupPointerLock(engine) {
212
718
  }
213
719
  });
214
720
 
215
- // Suppress the right-click context menu so the canvas stays usable.
216
721
  captureEl.addEventListener("contextmenu", (e) => e.preventDefault());
217
722
  }
218
723
 
219
- /**
220
- * Spawn a handful of marker entities around the player so motion is
221
- * visually obvious. All markers go through the standard ECS pipeline
222
- * (Transform + ShadedGeometry) — same path as gameplay geometry — so
223
- * shadows and lighting work correctly.
224
- *
225
- * @param {EntityComponentDataset} ecd
226
- */
227
- function addReferenceMarkers(ecd) {
228
- const SPAWN_X = 100, SPAWN_Z = 100;
229
-
230
- // Share one unit-cube geometry across the ring cubes — cheap and lets
231
- // the renderer's instancing path kick in if it wants.
232
- const unitCubeGeom = new BoxGeometry(1, 1, 1);
233
- const palette = [0xff5555, 0x55ff55, 0x5577ff, 0xffaa44, 0xaa55ff, 0x44ddee, 0xff66cc, 0x66ffcc];
234
-
235
- // Ring of coloured cubes at radius 6 — circle-strafe targets.
236
- const RING_N = 8;
237
- for (let i = 0; i < RING_N; i++) {
238
- const a = (i / RING_N) * Math.PI * 2;
239
- spawnMarker({
240
- ecd,
241
- geometry: unitCubeGeom,
242
- color: palette[i % palette.length],
243
- roughness: 0.8,
244
- position: new Vector3(SPAWN_X + Math.cos(a) * 6, 0.5, SPAWN_Z + Math.sin(a) * 6),
245
- });
246
- }
247
-
248
- // Tall pillars further out — for parallax depth-perception while
249
- // testing bob and breath at distance.
250
- const pillarGeom = new BoxGeometry(1, 6, 1);
251
- const PILLAR_N = 6;
252
- for (let i = 0; i < PILLAR_N; i++) {
253
- const a = (i / PILLAR_N) * Math.PI * 2 + 0.3;
254
- const r = 22;
255
- spawnMarker({
256
- ecd,
257
- geometry: pillarGeom,
258
- color: 0x888888,
259
- roughness: 0.9,
260
- position: new Vector3(SPAWN_X + Math.cos(a) * r, 3, SPAWN_Z + Math.sin(a) * r),
261
- });
262
- }
263
-
264
- // A low platform next to spawn — easy hop target, plus a chance to see
265
- // the landing dip when stepping back down.
266
- spawnMarker({
267
- ecd,
268
- geometry: new BoxGeometry(2, 0.4, 2),
269
- color: 0xddddee,
270
- roughness: 0.7,
271
- position: new Vector3(SPAWN_X + 3, 0.2, SPAWN_Z),
272
- });
273
- }
274
-
275
- /**
276
- * @param {object} p
277
- * @param {EntityComponentDataset} p.ecd
278
- * @param {THREE.BufferGeometry} p.geometry
279
- * @param {number} p.color Hex color, e.g. 0xff5555
280
- * @param {number} [p.roughness]
281
- * @param {Vector3} p.position
282
- */
283
- function spawnMarker({ ecd, geometry, color, roughness = 0.8, position }) {
284
- const material = new MeshStandardMaterial({ color, roughness });
285
- const sg = ShadedGeometry.from(geometry, material);
286
- sg.setFlag(ShadedGeometryFlags.CastShadow);
287
- sg.setFlag(ShadedGeometryFlags.ReceiveShadow);
288
- sg.setFlag(ShadedGeometryFlags.Visible);
289
-
290
- const transform = new Transform();
291
- transform.position.copy(position);
292
-
293
- new Entity()
294
- .add(transform)
295
- .add(sg)
296
- .add(Tag.fromJSON(["ReferenceMarker"]))
297
- .add(SerializationMetadata.Transient)
298
- .build(ecd);
299
- }
300
-
301
724
  function logHelp() {
302
725
  /* eslint-disable no-console */
303
- console.log("%cFirstPersonPlayerController prototype",
726
+ console.log("%cFirstPersonPlayerController — Parkour Gym",
304
727
  "color:#88ddff;font-weight:bold;font-size:14px");
305
728
  console.log("Click the canvas to capture mouse. ESC to release.");
306
729
  console.log("WASD = move | Mouse = look | Space = jump | Shift = sprint | C = crouch");
730
+ console.log("");
731
+ console.log("%cStations:", "font-weight:bold");
732
+ console.log(" N Mantle row — four obstacles, last one is too tall");
733
+ console.log(" NE Slide tunnel — sprint + C to slide under the low ceiling");
734
+ console.log(" E Wall-run — sprint along, jump near the wall");
735
+ console.log(" SE Gap jump — mantle up the stair, sprint, jump the gap");
736
+ console.log(" S Ledge-grab — too tall to mantle; jump at it, catch the lip");
737
+ console.log(" W Wall-jump chimney — alternate walls to climb");
307
738
  }
308
739
 
309
740
  async function init() {