@jgengine/core 0.10.0 → 0.12.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 (727) hide show
  1. package/CHANGELOG.md +39 -2
  2. package/LICENSE +203 -661
  3. package/README.md +1 -1
  4. package/dist/ai/crowd.d.ts +55 -0
  5. package/dist/ai/crowd.js +114 -0
  6. package/dist/ai/flock.d.ts +5 -2
  7. package/dist/ai/flock.js +5 -2
  8. package/dist/ai/groupAssist.d.ts +1 -0
  9. package/dist/ai/groupAssist.js +1 -0
  10. package/dist/ai/heatSystem.d.ts +76 -0
  11. package/dist/ai/heatSystem.js +97 -0
  12. package/dist/ai/interestScheduler.d.ts +107 -0
  13. package/dist/ai/interestScheduler.js +118 -0
  14. package/dist/ai/jobBoard.d.ts +1 -0
  15. package/dist/ai/jobBoard.js +1 -0
  16. package/dist/ai/laneSelect.d.ts +5 -2
  17. package/dist/ai/laneSelect.js +5 -2
  18. package/dist/ai/mobBrain.d.ts +1 -0
  19. package/dist/ai/mobBrain.js +1 -0
  20. package/dist/ai/populationDirector.d.ts +103 -0
  21. package/dist/ai/populationDirector.js +190 -0
  22. package/dist/ai/pursuit.d.ts +56 -0
  23. package/dist/ai/pursuit.js +53 -0
  24. package/dist/ai/spawnDirector.d.ts +7 -2
  25. package/dist/ai/spawnDirector.js +18 -15
  26. package/dist/ai/spawnPoint.d.ts +3 -1
  27. package/dist/ai/spawnPoint.js +3 -1
  28. package/dist/ai/targetAcquisition.d.ts +84 -0
  29. package/dist/ai/targetAcquisition.js +92 -0
  30. package/dist/anim/easing.d.ts +19 -0
  31. package/dist/anim/easing.js +19 -0
  32. package/dist/anim/oscillator.d.ts +12 -0
  33. package/dist/anim/oscillator.js +25 -0
  34. package/dist/area/areaEffectField.d.ts +127 -0
  35. package/dist/area/areaEffectField.js +175 -0
  36. package/dist/area/stackPolicy.d.ts +47 -0
  37. package/dist/area/stackPolicy.js +99 -0
  38. package/dist/authoring.d.ts +2 -1
  39. package/dist/authoring.js +2 -1
  40. package/dist/board/laneBoard.d.ts +13 -0
  41. package/dist/board/laneBoard.js +13 -0
  42. package/dist/board/timelineBoard.d.ts +10 -0
  43. package/dist/board/timelineBoard.js +10 -0
  44. package/dist/combat/abilityKit.d.ts +18 -0
  45. package/dist/combat/abilityKit.js +24 -9
  46. package/dist/combat/animationState.d.ts +5 -0
  47. package/dist/combat/animationState.js +5 -0
  48. package/dist/combat/breakMeters.d.ts +10 -0
  49. package/dist/combat/breakMeters.js +10 -0
  50. package/dist/combat/castRunner.d.ts +5 -0
  51. package/dist/combat/castRunner.js +5 -0
  52. package/dist/combat/comboPoints.d.ts +5 -0
  53. package/dist/combat/comboPoints.js +5 -0
  54. package/dist/combat/comboString.d.ts +5 -0
  55. package/dist/combat/comboString.js +5 -0
  56. package/dist/combat/damageInterceptors.d.ts +192 -0
  57. package/dist/combat/damageInterceptors.js +251 -0
  58. package/dist/combat/damageMatchup.d.ts +68 -0
  59. package/dist/combat/damageMatchup.js +42 -0
  60. package/dist/combat/damageResolution.d.ts +63 -0
  61. package/dist/combat/damageResolution.js +50 -0
  62. package/dist/combat/death.d.ts +7 -1
  63. package/dist/combat/death.js +5 -0
  64. package/dist/combat/deathReason.d.ts +14 -0
  65. package/dist/combat/deathReason.js +1 -0
  66. package/dist/combat/defensiveWindow.d.ts +5 -0
  67. package/dist/combat/defensiveWindow.js +5 -0
  68. package/dist/combat/dotField.d.ts +5 -1
  69. package/dist/combat/dotField.js +5 -1
  70. package/dist/combat/downed.d.ts +5 -0
  71. package/dist/combat/downed.js +5 -0
  72. package/dist/combat/effects.d.ts +5 -0
  73. package/dist/combat/effects.js +5 -0
  74. package/dist/combat/encounterSequence.d.ts +258 -0
  75. package/dist/combat/encounterSequence.js +426 -0
  76. package/dist/combat/hitReaction.d.ts +57 -1
  77. package/dist/combat/hitReaction.js +45 -5
  78. package/dist/combat/magazine.d.ts +54 -0
  79. package/dist/combat/magazine.js +96 -0
  80. package/dist/combat/projectiles.d.ts +5 -0
  81. package/dist/combat/projectiles.js +32 -14
  82. package/dist/combat/receivedDamage.d.ts +117 -0
  83. package/dist/combat/receivedDamage.js +92 -0
  84. package/dist/combat/regenShield.d.ts +5 -1
  85. package/dist/combat/regenShield.js +5 -1
  86. package/dist/combat/renderCues.d.ts +51 -0
  87. package/dist/combat/renderCues.js +44 -0
  88. package/dist/combat/resourcePool.d.ts +5 -0
  89. package/dist/combat/resourcePool.js +5 -0
  90. package/dist/combat/rewardAllocation.d.ts +121 -0
  91. package/dist/combat/rewardAllocation.js +251 -0
  92. package/dist/combat/shotOrigin.d.ts +18 -1
  93. package/dist/combat/shotOrigin.js +39 -0
  94. package/dist/combat/statusApplication.d.ts +96 -0
  95. package/dist/combat/statusApplication.js +81 -0
  96. package/dist/combat/telegraph.d.ts +11 -2
  97. package/dist/combat/telegraph.js +11 -2
  98. package/dist/combat/thresholdCrossings.d.ts +85 -0
  99. package/dist/combat/thresholdCrossings.js +116 -0
  100. package/dist/combat.d.ts +35 -0
  101. package/dist/combat.js +35 -0
  102. package/dist/commands/commandRegistry.d.ts +11 -0
  103. package/dist/commands/commandRegistry.js +9 -2
  104. package/dist/crafting/crop.d.ts +18 -0
  105. package/dist/crafting/crop.js +18 -0
  106. package/dist/crafting/production.d.ts +5 -0
  107. package/dist/crafting/production.js +5 -0
  108. package/dist/devtools/controls.d.ts +38 -0
  109. package/dist/devtools/controls.js +181 -0
  110. package/dist/devtools/devtools.d.ts +5 -197
  111. package/dist/devtools/devtools.js +38 -774
  112. package/dist/devtools/discover.d.ts +32 -0
  113. package/dist/devtools/discover.js +240 -0
  114. package/dist/devtools/fallbackSeams.d.ts +50 -0
  115. package/dist/devtools/fallbackSeams.js +111 -0
  116. package/dist/devtools/frame.d.ts +15 -0
  117. package/dist/devtools/frame.js +247 -0
  118. package/dist/devtools/logs.d.ts +15 -0
  119. package/dist/devtools/logs.js +86 -0
  120. package/dist/devtools/overrides.d.ts +16 -0
  121. package/dist/devtools/overrides.js +66 -0
  122. package/dist/devtools/rewriteTunables.d.ts +17 -0
  123. package/dist/devtools/rewriteTunables.js +276 -0
  124. package/dist/devtools/saveEndpoint.d.ts +46 -0
  125. package/dist/devtools/saveEndpoint.js +48 -0
  126. package/dist/devtools/transformTunables.d.ts +3 -0
  127. package/dist/devtools/transformTunables.js +3 -0
  128. package/dist/devtools/tunableSchema.d.ts +31 -0
  129. package/dist/devtools/tunableSchema.js +31 -0
  130. package/dist/devtools/types.d.ts +212 -0
  131. package/dist/devtools/types.js +1 -0
  132. package/dist/economy/auctionBook.d.ts +122 -0
  133. package/dist/economy/auctionBook.js +213 -0
  134. package/dist/economy/currency.d.ts +12 -1
  135. package/dist/economy/currency.js +12 -1
  136. package/dist/economy/listingBook.d.ts +91 -0
  137. package/dist/economy/listingBook.js +144 -0
  138. package/dist/economy/priceHistory.d.ts +44 -0
  139. package/dist/economy/priceHistory.js +89 -0
  140. package/dist/economy/resourceLedger.d.ts +222 -0
  141. package/dist/economy/resourceLedger.js +353 -0
  142. package/dist/economy/sharedWallet.d.ts +14 -0
  143. package/dist/economy/sharedWallet.js +14 -0
  144. package/dist/economy/techTree.d.ts +12 -0
  145. package/dist/economy/techTree.js +12 -0
  146. package/dist/economy/unlockPoints.d.ts +92 -0
  147. package/dist/economy/unlockPoints.js +103 -0
  148. package/dist/economy/wallet.d.ts +26 -2
  149. package/dist/economy/wallet.js +35 -6
  150. package/dist/editor/commandApply.d.ts +5 -0
  151. package/dist/editor/commandApply.js +755 -0
  152. package/dist/editor/commands.d.ts +235 -7
  153. package/dist/editor/commands.js +82 -124
  154. package/dist/editor/directives.d.ts +94 -0
  155. package/dist/editor/directives.js +206 -0
  156. package/dist/editor/document.d.ts +194 -13
  157. package/dist/editor/document.js +1166 -19
  158. package/dist/editor/entityCatalog.d.ts +42 -0
  159. package/dist/editor/entityCatalog.js +101 -0
  160. package/dist/editor/environment.d.ts +74 -0
  161. package/dist/editor/environment.js +169 -0
  162. package/dist/editor/grid.d.ts +229 -0
  163. package/dist/editor/grid.js +366 -0
  164. package/dist/editor/gridAdapters.d.ts +80 -0
  165. package/dist/editor/gridAdapters.js +134 -0
  166. package/dist/editor/index.d.ts +98 -6
  167. package/dist/editor/index.js +13 -2
  168. package/dist/editor/liveSync.d.ts +127 -0
  169. package/dist/editor/liveSync.js +249 -0
  170. package/dist/editor/minimap.d.ts +31 -0
  171. package/dist/editor/minimap.js +73 -0
  172. package/dist/editor/runtimeInspector.d.ts +88 -0
  173. package/dist/editor/runtimeInspector.js +239 -0
  174. package/dist/editor/streamer.d.ts +66 -0
  175. package/dist/editor/streamer.js +68 -0
  176. package/dist/editor/types.d.ts +250 -1
  177. package/dist/editor/world.d.ts +136 -0
  178. package/dist/editor/world.js +303 -0
  179. package/dist/faction/reputation.d.ts +5 -0
  180. package/dist/faction/reputation.js +5 -0
  181. package/dist/format/distance.d.ts +17 -0
  182. package/dist/format/distance.js +18 -0
  183. package/dist/format/duration.d.ts +27 -0
  184. package/dist/format/duration.js +45 -0
  185. package/dist/format/speed.d.ts +17 -0
  186. package/dist/format/speed.js +25 -0
  187. package/dist/game/breeding.d.ts +161 -0
  188. package/dist/game/breeding.js +181 -0
  189. package/dist/game/cameraConfig.d.ts +451 -0
  190. package/dist/game/cameraConfig.js +1 -0
  191. package/dist/game/connectedPlayers.d.ts +6 -4
  192. package/dist/game/connectedPlayers.js +2 -2
  193. package/dist/game/cosmetics.d.ts +9 -0
  194. package/dist/game/cosmetics.js +16 -0
  195. package/dist/game/defineGame.d.ts +110 -5
  196. package/dist/game/defineGame.js +49 -4
  197. package/dist/game/defineSystem.d.ts +90 -0
  198. package/dist/game/defineSystem.js +47 -0
  199. package/dist/game/dialogue.d.ts +33 -0
  200. package/dist/game/dialogue.js +21 -0
  201. package/dist/game/events.d.ts +63 -13
  202. package/dist/game/events.js +5 -0
  203. package/dist/game/feed.d.ts +33 -0
  204. package/dist/game/feed.js +35 -2
  205. package/dist/game/gamePhase.d.ts +11 -0
  206. package/dist/game/gamePhase.js +16 -0
  207. package/dist/game/leaderboard.d.ts +5 -0
  208. package/dist/game/leaderboard.js +5 -0
  209. package/dist/game/loadout.d.ts +5 -0
  210. package/dist/game/loadout.js +5 -0
  211. package/dist/game/lootFilter.d.ts +2 -0
  212. package/dist/game/lootFilter.js +2 -0
  213. package/dist/game/lootPipeline.d.ts +164 -0
  214. package/dist/game/lootPipeline.js +216 -0
  215. package/dist/game/lootTable.d.ts +19 -2
  216. package/dist/game/lootTable.js +15 -5
  217. package/dist/game/objectives.d.ts +43 -0
  218. package/dist/game/objectives.js +36 -0
  219. package/dist/game/paramLayers.d.ts +148 -0
  220. package/dist/game/paramLayers.js +185 -0
  221. package/dist/game/ping.d.ts +5 -0
  222. package/dist/game/ping.js +5 -0
  223. package/dist/game/playableGame.d.ts +116 -432
  224. package/dist/game/playableGame.js +1 -1
  225. package/dist/game/progression.d.ts +35 -0
  226. package/dist/game/progression.js +19 -0
  227. package/dist/game/quest.d.ts +8 -0
  228. package/dist/game/quest.js +30 -3
  229. package/dist/game/race.d.ts +141 -0
  230. package/dist/game/race.js +169 -0
  231. package/dist/game/recordBook.d.ts +3 -1
  232. package/dist/game/recordBook.js +4 -1
  233. package/dist/game/ruleSelection.d.ts +75 -0
  234. package/dist/game/ruleSelection.js +127 -0
  235. package/dist/game/runDraft.d.ts +5 -0
  236. package/dist/game/runDraft.js +5 -0
  237. package/dist/game/saveStore.d.ts +111 -0
  238. package/dist/game/saveStore.js +312 -0
  239. package/dist/game/snapshotHistory.d.ts +67 -0
  240. package/dist/game/snapshotHistory.js +95 -0
  241. package/dist/game/social.d.ts +38 -1
  242. package/dist/game/social.js +71 -0
  243. package/dist/game/spawnPoints.d.ts +5 -0
  244. package/dist/game/spawnPoints.js +5 -0
  245. package/dist/game/systemRuntime.d.ts +50 -0
  246. package/dist/game/systemRuntime.js +157 -0
  247. package/dist/game/systemSchedule.d.ts +72 -0
  248. package/dist/game/systemSchedule.js +242 -0
  249. package/dist/game/toasts.d.ts +43 -0
  250. package/dist/game/toasts.js +44 -0
  251. package/dist/game/trade.d.ts +10 -0
  252. package/dist/game/trade.js +10 -0
  253. package/dist/game/tribe.d.ts +184 -0
  254. package/dist/game/tribe.js +432 -0
  255. package/dist/game/unlocks.d.ts +8 -0
  256. package/dist/game/unlocks.js +16 -0
  257. package/dist/game/vfxInstance.d.ts +138 -0
  258. package/dist/game/vfxInstance.js +96 -0
  259. package/dist/game/worldItem.d.ts +17 -4
  260. package/dist/game/worldItem.js +17 -4
  261. package/dist/gameplay.d.ts +93 -0
  262. package/dist/gameplay.js +93 -0
  263. package/dist/index.d.ts +5 -14
  264. package/dist/index.js +5 -14
  265. package/dist/input/actionBindings.d.ts +23 -6
  266. package/dist/input/actionBindings.js +23 -6
  267. package/dist/input/axisInput.d.ts +7 -2
  268. package/dist/input/axisInput.js +7 -2
  269. package/dist/input/controlGroups.d.ts +67 -0
  270. package/dist/input/controlGroups.js +41 -0
  271. package/dist/input/touchScheme.d.ts +82 -6
  272. package/dist/input/touchScheme.js +123 -10
  273. package/dist/interaction/lockpick.d.ts +61 -0
  274. package/dist/interaction/lockpick.js +168 -0
  275. package/dist/interaction/proximityPrompt.d.ts +2 -0
  276. package/dist/interaction/proximityPrompt.js +2 -0
  277. package/dist/interaction/qte.d.ts +5 -0
  278. package/dist/interaction/qte.js +5 -0
  279. package/dist/interaction/skillCheck.d.ts +5 -0
  280. package/dist/interaction/skillCheck.js +5 -0
  281. package/dist/inventory/encumbrance.d.ts +69 -0
  282. package/dist/inventory/encumbrance.js +68 -0
  283. package/dist/inventory/inventoryModel.d.ts +12 -0
  284. package/dist/inventory/inventoryModel.js +12 -0
  285. package/dist/inventory/shapedGrid.d.ts +16 -0
  286. package/dist/inventory/shapedGrid.js +16 -0
  287. package/dist/inventory/slotModel.d.ts +10 -0
  288. package/dist/inventory/slotModel.js +10 -0
  289. package/dist/item/durability.d.ts +5 -0
  290. package/dist/item/durability.js +6 -3
  291. package/dist/item/itemIdentity.d.ts +171 -0
  292. package/dist/item/itemIdentity.js +138 -0
  293. package/dist/item/itemInstanceRegistry.d.ts +32 -0
  294. package/dist/item/itemInstanceRegistry.js +34 -0
  295. package/dist/item/itemgen.d.ts +163 -0
  296. package/dist/item/itemgen.js +151 -0
  297. package/dist/item/modularItem.d.ts +5 -0
  298. package/dist/item/modularItem.js +5 -0
  299. package/dist/item/use.d.ts +5 -0
  300. package/dist/item/use.js +5 -0
  301. package/dist/item/useBehavior.d.ts +142 -0
  302. package/dist/item/useBehavior.js +105 -0
  303. package/dist/item/weapon.d.ts +5 -0
  304. package/dist/item/weapon.js +5 -0
  305. package/dist/math/scalar.d.ts +25 -0
  306. package/dist/math/scalar.js +47 -0
  307. package/dist/meta/changelog.d.ts +4 -1
  308. package/dist/meta/changelog.js +39 -2
  309. package/dist/movement/avoidance.d.ts +45 -0
  310. package/dist/movement/avoidance.js +123 -0
  311. package/dist/movement/cameraRig.d.ts +8 -0
  312. package/dist/movement/cameraRig.js +8 -0
  313. package/dist/movement/dash.d.ts +11 -0
  314. package/dist/movement/dash.js +11 -0
  315. package/dist/movement/formation.d.ts +135 -0
  316. package/dist/movement/formation.js +194 -0
  317. package/dist/movement/glideModel.d.ts +5 -0
  318. package/dist/movement/glideModel.js +5 -0
  319. package/dist/movement/grappleSwing.d.ts +5 -0
  320. package/dist/movement/grappleSwing.js +5 -0
  321. package/dist/movement/leaderTrail.d.ts +5 -0
  322. package/dist/movement/leaderTrail.js +5 -0
  323. package/dist/movement/movementModel.d.ts +50 -9
  324. package/dist/movement/movementModel.js +75 -29
  325. package/dist/movement/playerMovement.js +167 -12
  326. package/dist/movement/poseState.d.ts +13 -0
  327. package/dist/movement/poseState.js +16 -0
  328. package/dist/movement/steering.d.ts +8 -0
  329. package/dist/movement/steering.js +18 -0
  330. package/dist/multiplayer/combatSnapshot.d.ts +3 -0
  331. package/dist/multiplayer/combatSnapshot.js +16 -8
  332. package/dist/multiplayer/lagCompensation.d.ts +5 -0
  333. package/dist/multiplayer/lagCompensation.js +5 -0
  334. package/dist/multiplayer/presenceModel.d.ts +11 -1
  335. package/dist/multiplayer/presenceModel.js +17 -1
  336. package/dist/multiplayer/simultaneousCommit.d.ts +3 -0
  337. package/dist/multiplayer/simultaneousCommit.js +3 -0
  338. package/dist/multiplayer.d.ts +11 -0
  339. package/dist/multiplayer.js +11 -0
  340. package/dist/nav/pathFollow.d.ts +57 -0
  341. package/dist/nav/pathFollow.js +109 -0
  342. package/dist/orders/orderKinds.d.ts +156 -0
  343. package/dist/orders/orderKinds.js +197 -0
  344. package/dist/orders/orderQueue.d.ts +208 -0
  345. package/dist/orders/orderQueue.js +211 -0
  346. package/dist/physics/drivableVehicle.d.ts +31 -0
  347. package/dist/physics/drivableVehicle.js +16 -0
  348. package/dist/physics/flightDynamics.d.ts +82 -0
  349. package/dist/physics/flightDynamics.js +165 -0
  350. package/dist/physics/gravityField.d.ts +25 -0
  351. package/dist/physics/gravityField.js +41 -0
  352. package/dist/physics/kinematicVehicle.d.ts +108 -1
  353. package/dist/physics/kinematicVehicle.js +212 -15
  354. package/dist/physics/physicsWorld.d.ts +50 -12
  355. package/dist/physics/physicsWorld.js +120 -122
  356. package/dist/physics/radialImpulse.d.ts +25 -0
  357. package/dist/physics/radialImpulse.js +27 -0
  358. package/dist/physics/vehicleObstacles.d.ts +44 -0
  359. package/dist/physics/vehicleObstacles.js +115 -0
  360. package/dist/procedural.d.ts +3 -0
  361. package/dist/procedural.js +3 -0
  362. package/dist/progression/statGraph.d.ts +116 -0
  363. package/dist/progression/statGraph.js +318 -0
  364. package/dist/puzzle/cellGrid.d.ts +9 -0
  365. package/dist/puzzle/cellGrid.js +9 -0
  366. package/dist/puzzle/fallingPiece.d.ts +9 -0
  367. package/dist/puzzle/fallingPiece.js +9 -0
  368. package/dist/puzzle/nonogram.d.ts +39 -0
  369. package/dist/puzzle/nonogram.js +136 -0
  370. package/dist/random/nameGen.d.ts +5 -0
  371. package/dist/random/nameGen.js +5 -0
  372. package/dist/random/pick.d.ts +8 -0
  373. package/dist/random/pick.js +31 -0
  374. package/dist/random/rng.d.ts +26 -1
  375. package/dist/random/rng.js +32 -9
  376. package/dist/random/seedLink.d.ts +4 -0
  377. package/dist/random/seedLink.js +4 -0
  378. package/dist/relation/keyedValues.d.ts +54 -0
  379. package/dist/relation/keyedValues.js +115 -0
  380. package/dist/relation/thresholds.d.ts +62 -0
  381. package/dist/relation/thresholds.js +62 -0
  382. package/dist/render/color.d.ts +12 -0
  383. package/dist/render/color.js +26 -0
  384. package/dist/render/lookPreset.d.ts +41 -0
  385. package/dist/render/lookPreset.js +29 -0
  386. package/dist/render/postProcessing.d.ts +20 -0
  387. package/dist/render/postProcessing.js +21 -1
  388. package/dist/rules/predicate.d.ts +53 -0
  389. package/dist/rules/predicate.js +64 -0
  390. package/dist/rules/ruleEffects.d.ts +38 -0
  391. package/dist/rules/ruleEffects.js +37 -0
  392. package/dist/rules/triggeredRules.d.ts +160 -0
  393. package/dist/rules/triggeredRules.js +241 -0
  394. package/dist/runtime/adapter.d.ts +55 -3
  395. package/dist/runtime/adapter.js +57 -1
  396. package/dist/runtime/cameraDirector.d.ts +1 -0
  397. package/dist/runtime/cameraDirector.js +1 -0
  398. package/dist/runtime/commandRunner.d.ts +1 -0
  399. package/dist/runtime/commandRunner.js +1 -0
  400. package/dist/runtime/context/combat.d.ts +51 -0
  401. package/dist/runtime/context/combat.js +130 -0
  402. package/dist/runtime/context/combatFx.d.ts +23 -0
  403. package/dist/runtime/context/combatFx.js +161 -0
  404. package/dist/runtime/context/deathLoot.d.ts +30 -0
  405. package/dist/runtime/context/deathLoot.js +39 -0
  406. package/dist/runtime/context/player.d.ts +48 -0
  407. package/dist/runtime/context/player.js +125 -0
  408. package/dist/runtime/context/registries.d.ts +13 -0
  409. package/dist/runtime/context/registries.js +84 -0
  410. package/dist/runtime/context/scene.d.ts +59 -0
  411. package/dist/runtime/context/scene.js +291 -0
  412. package/dist/runtime/context/snapshotCodecs.d.ts +12 -0
  413. package/dist/runtime/context/snapshotCodecs.js +26 -0
  414. package/dist/runtime/context/worldItems.d.ts +21 -0
  415. package/dist/runtime/context/worldItems.js +37 -0
  416. package/dist/runtime/descriptors/baseline.d.ts +48 -0
  417. package/dist/runtime/descriptors/baseline.js +157 -0
  418. package/dist/runtime/descriptors/features.d.ts +79 -0
  419. package/dist/runtime/descriptors/features.js +299 -0
  420. package/dist/runtime/gameContext.d.ts +2 -327
  421. package/dist/runtime/gameContext.js +273 -778
  422. package/dist/runtime/gameContextTypes.d.ts +467 -0
  423. package/dist/runtime/gameContextTypes.js +1 -0
  424. package/dist/runtime/gameRuntime.d.ts +1 -0
  425. package/dist/runtime/gameRuntime.js +1 -0
  426. package/dist/runtime/headlessRunner.d.ts +62 -0
  427. package/dist/runtime/headlessRunner.js +45 -0
  428. package/dist/runtime/hostPersistence.d.ts +12 -0
  429. package/dist/runtime/hostPersistence.js +12 -0
  430. package/dist/runtime/hostPolicy.d.ts +51 -0
  431. package/dist/runtime/hostPolicy.js +68 -0
  432. package/dist/runtime/hostedGameRunner.d.ts +11 -4
  433. package/dist/runtime/hostedGameRunner.js +27 -3
  434. package/dist/runtime/hostedWorldSession.d.ts +15 -5
  435. package/dist/runtime/hostedWorldSession.js +12 -4
  436. package/dist/runtime/inputSnapshot.d.ts +8 -3
  437. package/dist/runtime/inputSnapshot.js +6 -2
  438. package/dist/runtime/motionIntents.d.ts +11 -2
  439. package/dist/runtime/motionIntents.js +16 -2
  440. package/dist/runtime/perContext.d.ts +15 -0
  441. package/dist/runtime/perContext.js +21 -0
  442. package/dist/runtime/runtimeSave.d.ts +79 -0
  443. package/dist/runtime/runtimeSave.js +105 -0
  444. package/dist/runtime/save.d.ts +4 -0
  445. package/dist/runtime/save.js +4 -0
  446. package/dist/runtime/snapshot.d.ts +7 -0
  447. package/dist/runtime/snapshot.js +7 -0
  448. package/dist/runtime/visibility.d.ts +2 -1
  449. package/dist/runtime/visibility.js +2 -1
  450. package/dist/runtime/worldChannel.d.ts +7 -3
  451. package/dist/runtime/worldChannel.js +51 -6
  452. package/dist/runtime/worldMirror.d.ts +14 -2
  453. package/dist/runtime/worldMirror.js +15 -2
  454. package/dist/runtime/worldProjection.d.ts +47 -0
  455. package/dist/runtime/worldProjection.js +52 -0
  456. package/dist/runtime/worldReplication.d.ts +30 -7
  457. package/dist/runtime/worldReplication.js +41 -9
  458. package/dist/runtime/worldSnapshot.d.ts +42 -3
  459. package/dist/runtime/worldSnapshot.js +34 -7
  460. package/dist/scene/assetCatalog.d.ts +26 -0
  461. package/dist/scene/assetCatalog.js +4 -0
  462. package/dist/scene/assetDiagnostics.d.ts +69 -0
  463. package/dist/scene/assetDiagnostics.js +110 -0
  464. package/dist/scene/assetGenerator.d.ts +65 -0
  465. package/dist/scene/assetGenerator.js +64 -0
  466. package/dist/scene/assetSpace.d.ts +137 -0
  467. package/dist/scene/assetSpace.js +257 -0
  468. package/dist/scene/authoredTriggers.d.ts +219 -0
  469. package/dist/scene/authoredTriggers.js +454 -0
  470. package/dist/scene/behaviorRuntime.d.ts +75 -0
  471. package/dist/scene/behaviorRuntime.js +217 -0
  472. package/dist/scene/behaviors.d.ts +14 -2
  473. package/dist/scene/behaviors.js +7 -2
  474. package/dist/scene/bodyBind.d.ts +60 -0
  475. package/dist/scene/bodyBind.js +51 -0
  476. package/dist/scene/builtinSceneKinds.d.ts +5 -0
  477. package/dist/scene/builtinSceneKinds.js +67 -0
  478. package/dist/scene/colliders.d.ts +71 -1
  479. package/dist/scene/colliders.js +145 -1
  480. package/dist/scene/collisionMesh.d.ts +94 -0
  481. package/dist/scene/collisionMesh.js +699 -0
  482. package/dist/scene/companion.d.ts +147 -0
  483. package/dist/scene/companion.js +193 -0
  484. package/dist/scene/entityStats.d.ts +18 -11
  485. package/dist/scene/entityStats.js +21 -16
  486. package/dist/scene/entityStore.d.ts +12 -1
  487. package/dist/scene/entityStore.js +15 -0
  488. package/dist/scene/facing.d.ts +18 -0
  489. package/dist/scene/facing.js +26 -0
  490. package/dist/scene/modelSockets.d.ts +33 -0
  491. package/dist/scene/modelSockets.js +29 -0
  492. package/dist/scene/objectQuery.d.ts +2 -0
  493. package/dist/scene/objectQuery.js +2 -0
  494. package/dist/scene/objectStore.d.ts +4 -0
  495. package/dist/scene/objectStore.js +6 -0
  496. package/dist/scene/possession.d.ts +8 -0
  497. package/dist/scene/possession.js +14 -0
  498. package/dist/scene/roster.d.ts +3 -0
  499. package/dist/scene/roster.js +12 -0
  500. package/dist/scene/sceneKinds.d.ts +256 -0
  501. package/dist/scene/sceneKinds.js +218 -0
  502. package/dist/scene/sceneOwnership.d.ts +169 -0
  503. package/dist/scene/sceneOwnership.js +179 -0
  504. package/dist/scene/sceneRaycast.js +15 -0
  505. package/dist/scene/selectionBookmarks.d.ts +93 -0
  506. package/dist/scene/selectionBookmarks.js +122 -0
  507. package/dist/scene/vehicleSeat.d.ts +68 -0
  508. package/dist/scene/vehicleSeat.js +59 -0
  509. package/dist/sensor/concealment.d.ts +3 -0
  510. package/dist/sensor/concealment.js +3 -0
  511. package/dist/sensor/freezeMonitor.d.ts +1 -0
  512. package/dist/sensor/freezeMonitor.js +1 -0
  513. package/dist/sensor/frustumSensor.d.ts +7 -3
  514. package/dist/sensor/frustumSensor.js +7 -3
  515. package/dist/sensor/hiddenStateProbe.d.ts +5 -2
  516. package/dist/sensor/hiddenStateProbe.js +5 -2
  517. package/dist/sensor/recordingBuffer.d.ts +2 -1
  518. package/dist/sensor/recordingBuffer.js +2 -1
  519. package/dist/sensor/replayLoop.d.ts +6 -2
  520. package/dist/sensor/replayLoop.js +6 -2
  521. package/dist/sensor/revealQuery.d.ts +2 -1
  522. package/dist/sensor/revealQuery.js +2 -1
  523. package/dist/sensor/visionCone.d.ts +10 -3
  524. package/dist/sensor/visionCone.js +10 -3
  525. package/dist/session/contestedChannel.d.ts +1 -0
  526. package/dist/session/contestedChannel.js +1 -0
  527. package/dist/session/extraction.d.ts +1 -0
  528. package/dist/session/extraction.js +1 -0
  529. package/dist/session/roles.d.ts +6 -0
  530. package/dist/session/roles.js +6 -0
  531. package/dist/session/roundState.d.ts +8 -0
  532. package/dist/session/roundState.js +2 -0
  533. package/dist/settings/settingsModel.d.ts +1 -0
  534. package/dist/settings/settingsModel.js +1 -0
  535. package/dist/stats/accumulatorMeter.d.ts +6 -0
  536. package/dist/stats/accumulatorMeter.js +6 -0
  537. package/dist/stats/eventMeter.d.ts +5 -0
  538. package/dist/stats/eventMeter.js +5 -0
  539. package/dist/stats/rollCheck.d.ts +5 -0
  540. package/dist/stats/rollCheck.js +5 -0
  541. package/dist/stats/spawnLevelStats.d.ts +110 -0
  542. package/dist/stats/spawnLevelStats.js +140 -0
  543. package/dist/stats/statModifiers.d.ts +5 -0
  544. package/dist/stats/statModifiers.js +5 -0
  545. package/dist/stats/statPool.d.ts +70 -0
  546. package/dist/stats/statPool.js +59 -0
  547. package/dist/store/changeSignal.d.ts +3 -0
  548. package/dist/store/changeSignal.js +2 -0
  549. package/dist/store/defineKeyedStore.d.ts +38 -0
  550. package/dist/store/defineKeyedStore.js +42 -0
  551. package/dist/store/defineStore.d.ts +33 -0
  552. package/dist/store/defineStore.js +35 -0
  553. package/dist/store/observableKeyedStore.d.ts +7 -0
  554. package/dist/store/observableKeyedStore.js +35 -2
  555. package/dist/survival/decayMeter.d.ts +55 -0
  556. package/dist/survival/decayMeter.js +130 -57
  557. package/dist/survival/moodle.d.ts +2 -0
  558. package/dist/survival/regionHealth.d.ts +6 -0
  559. package/dist/survival/regionHealth.js +6 -3
  560. package/dist/tactics/fallingGrid.d.ts +4 -2
  561. package/dist/tactics/fallingGrid.js +4 -2
  562. package/dist/tactics/predictiveQuery.d.ts +3 -0
  563. package/dist/tactics/predictiveQuery.js +3 -0
  564. package/dist/tactics/snapshot.d.ts +2 -0
  565. package/dist/tactics/snapshot.js +2 -0
  566. package/dist/tactics/surface.d.ts +1 -0
  567. package/dist/tactics/surface.js +1 -0
  568. package/dist/tactics/tacticalGrid.d.ts +1 -0
  569. package/dist/tactics/tacticalGrid.js +1 -0
  570. package/dist/time/beatClock.d.ts +14 -4
  571. package/dist/time/beatClock.js +14 -4
  572. package/dist/time/calendarClock.d.ts +3 -0
  573. package/dist/time/calendarClock.js +3 -0
  574. package/dist/time/idleProgress.d.ts +4 -0
  575. package/dist/time/idleProgress.js +4 -0
  576. package/dist/time/simClock.d.ts +2 -0
  577. package/dist/time/simClock.js +20 -5
  578. package/dist/ui/actionModel.d.ts +110 -0
  579. package/dist/ui/actionModel.js +159 -0
  580. package/dist/ui/gameLayout.d.ts +30 -11
  581. package/dist/ui/gameLayout.js +30 -11
  582. package/dist/ui/hudDocument.d.ts +114 -0
  583. package/dist/ui/hudDocument.js +220 -0
  584. package/dist/ui/hudLayout.d.ts +38 -1
  585. package/dist/ui/hudLayout.js +220 -17
  586. package/dist/ui/selectionModel.d.ts +92 -0
  587. package/dist/ui/selectionModel.js +88 -0
  588. package/dist/ui/tooltipModel.d.ts +63 -0
  589. package/dist/ui/tooltipModel.js +82 -0
  590. package/dist/ui.d.ts +15 -0
  591. package/dist/ui.js +15 -0
  592. package/dist/visibility/bounds.d.ts +8 -1
  593. package/dist/visibility/bounds.js +8 -1
  594. package/dist/visibility/frustum.d.ts +12 -3
  595. package/dist/visibility/frustum.js +12 -3
  596. package/dist/work/jobQueue.d.ts +201 -0
  597. package/dist/work/jobQueue.js +253 -0
  598. package/dist/work/unitTraining.d.ts +58 -0
  599. package/dist/work/unitTraining.js +52 -0
  600. package/dist/world/authoredEntities.d.ts +29 -0
  601. package/dist/world/authoredEntities.js +29 -0
  602. package/dist/world/authoredObjects.d.ts +72 -0
  603. package/dist/world/authoredObjects.js +81 -0
  604. package/dist/world/authoredSpawn.d.ts +39 -0
  605. package/dist/world/authoredSpawn.js +37 -0
  606. package/dist/world/buildSockets.d.ts +152 -0
  607. package/dist/world/buildSockets.js +188 -0
  608. package/dist/world/buildingGenerator.d.ts +18 -0
  609. package/dist/world/buildingGenerator.js +62 -0
  610. package/dist/world/buildings.d.ts +5 -0
  611. package/dist/world/buildings.js +5 -0
  612. package/dist/world/catenary.d.ts +22 -0
  613. package/dist/world/catenary.js +69 -0
  614. package/dist/world/cityBlocks.d.ts +152 -0
  615. package/dist/world/cityBlocks.js +670 -0
  616. package/dist/world/cityContent.d.ts +77 -0
  617. package/dist/world/cityContent.js +261 -0
  618. package/dist/world/cityGeometry.d.ts +114 -0
  619. package/dist/world/cityGeometry.js +573 -0
  620. package/dist/world/cityKind.d.ts +314 -0
  621. package/dist/world/cityKind.js +1578 -0
  622. package/dist/world/features.d.ts +133 -10
  623. package/dist/world/features.js +66 -6
  624. package/dist/world/footprintGrid.d.ts +59 -0
  625. package/dist/world/footprintGrid.js +141 -0
  626. package/dist/world/geometry.d.ts +64 -0
  627. package/dist/world/geometry.js +94 -0
  628. package/dist/world/grassKind.d.ts +51 -0
  629. package/dist/world/grassKind.js +101 -0
  630. package/dist/world/markers.d.ts +50 -4
  631. package/dist/world/markers.js +49 -0
  632. package/dist/world/massing.js +1 -1
  633. package/dist/world/minimapBake.d.ts +78 -0
  634. package/dist/world/minimapBake.js +208 -0
  635. package/dist/world/minimapTrack.d.ts +17 -0
  636. package/dist/world/minimapTrack.js +22 -0
  637. package/dist/world/pathInstances.d.ts +27 -0
  638. package/dist/world/pathInstances.js +27 -0
  639. package/dist/world/pathNetwork.d.ts +159 -0
  640. package/dist/world/pathNetwork.js +684 -0
  641. package/dist/world/pathTerrain.d.ts +80 -0
  642. package/dist/world/pathTerrain.js +142 -0
  643. package/dist/world/place.d.ts +166 -0
  644. package/dist/world/place.js +96 -0
  645. package/dist/world/placeAsset.d.ts +81 -0
  646. package/dist/world/placeAsset.js +79 -0
  647. package/dist/world/placement.d.ts +4 -0
  648. package/dist/world/placement.js +4 -0
  649. package/dist/world/placementController.d.ts +6 -0
  650. package/dist/world/placementController.js +6 -0
  651. package/dist/world/poleLineKind.d.ts +40 -0
  652. package/dist/world/poleLineKind.js +97 -0
  653. package/dist/world/polyline.d.ts +34 -0
  654. package/dist/world/polyline.js +88 -0
  655. package/dist/world/resourceNode.d.ts +109 -0
  656. package/dist/world/resourceNode.js +140 -0
  657. package/dist/world/roads.d.ts +8 -0
  658. package/dist/world/roads.js +38 -0
  659. package/dist/world/scatter.js +2 -20
  660. package/dist/world/scatterRegion.d.ts +164 -0
  661. package/dist/world/scatterRegion.js +409 -0
  662. package/dist/world/sceneShapes.d.ts +43 -0
  663. package/dist/world/sceneShapes.js +1 -0
  664. package/dist/world/segment.d.ts +27 -0
  665. package/dist/world/segment.js +43 -0
  666. package/dist/world/soilKind.d.ts +48 -0
  667. package/dist/world/soilKind.js +92 -0
  668. package/dist/world/spatialSample.d.ts +241 -0
  669. package/dist/world/spatialSample.js +465 -0
  670. package/dist/world/streets.d.ts +29 -0
  671. package/dist/world/streets.js +55 -0
  672. package/dist/world/terraform.d.ts +213 -1
  673. package/dist/world/terraform.js +627 -22
  674. package/dist/world/terrain.d.ts +164 -20
  675. package/dist/world/terrain.js +325 -41
  676. package/dist/world/terrainGuides.d.ts +182 -0
  677. package/dist/world/terrainGuides.js +343 -0
  678. package/dist/world/vec2.d.ts +81 -0
  679. package/dist/world/vec2.js +128 -0
  680. package/dist/world/vec3.d.ts +49 -0
  681. package/dist/world/vec3.js +76 -0
  682. package/dist/world/vegetation.d.ts +71 -0
  683. package/dist/world/vegetation.js +151 -0
  684. package/dist/world/visibilityField.d.ts +154 -0
  685. package/dist/world/visibilityField.js +271 -0
  686. package/dist/world/volumetricClouds.d.ts +52 -0
  687. package/dist/world/volumetricClouds.js +43 -0
  688. package/dist/world/walls.d.ts +9 -0
  689. package/dist/world/walls.js +9 -0
  690. package/dist/world/waterKind.d.ts +55 -0
  691. package/dist/world/waterKind.js +99 -0
  692. package/dist/world.d.ts +141 -0
  693. package/dist/world.js +141 -0
  694. package/package.json +32 -8
  695. package/skills/game-design/SKILL.md +28 -0
  696. package/skills/game-design/agents/openai.yaml +4 -0
  697. package/skills/game-design/references/application-playbook.md +170 -0
  698. package/skills/game-design/references/field-guide.md +288 -0
  699. package/skills/jgengine/SKILL.md +54 -0
  700. package/skills/jgengine/api.md +527 -0
  701. package/skills/jgengine/capabilities.md +131 -0
  702. package/skills/jgengine/recipes/minimal-game.md +88 -0
  703. package/skills/jgengine-combat/SKILL.md +38 -0
  704. package/skills/jgengine-combat/api.md +585 -0
  705. package/skills/jgengine-combat/capabilities.md +213 -0
  706. package/skills/jgengine-combat/recipes/portable-stat-pools.md +122 -0
  707. package/skills/jgengine-combat/reference.md +108 -0
  708. package/skills/jgengine-gameplay/SKILL.md +39 -0
  709. package/skills/jgengine-gameplay/api.md +1920 -0
  710. package/skills/jgengine-gameplay/capabilities.md +454 -0
  711. package/skills/jgengine-gameplay/reference-systems.md +56 -0
  712. package/skills/jgengine-world/SKILL.md +51 -0
  713. package/skills/jgengine-world/api.md +3056 -0
  714. package/skills/jgengine-world/capabilities.md +476 -0
  715. package/skills/jgengine-world/recipes/commanding-entities.md +128 -0
  716. package/skills/jgengine-world/reference.md +261 -0
  717. package/dist/cartridge/runtime.d.ts +0 -15
  718. package/dist/cartridge/runtime.js +0 -556
  719. package/dist/cartridge/spec.d.ts +0 -188
  720. package/dist/cartridge/spec.js +0 -19
  721. package/dist/cartridge/validate.d.ts +0 -2
  722. package/dist/cartridge/validate.js +0 -78
  723. package/dist/store/engineStore.d.ts +0 -22
  724. package/dist/store/engineStore.js +0 -50
  725. package/dist/store/features.d.ts +0 -10
  726. package/dist/store/features.js +0 -23
  727. package/llms.txt +0 -5389
@@ -1,3 +1,8 @@
1
+ const PHYSICS_PRECISION_PRESETS = {
2
+ low: { solverIterations: 2, correctionFactor: 0.15, sleepThresholdSteps: 15, wakeThreshold: 0.75, jointCorrection: 0.35 },
3
+ standard: { solverIterations: 4, correctionFactor: 0.2, sleepThresholdSteps: 30, wakeThreshold: 0.5, jointCorrection: 0.5 },
4
+ high: { solverIterations: 8, correctionFactor: 0.3, sleepThresholdSteps: 45, wakeThreshold: 0.35, jointCorrection: 0.65 },
5
+ };
1
6
  export const SHAPE_BOX = 0;
2
7
  export const SHAPE_SPHERE = 1;
3
8
  export const JOINT_FIXED = 0;
@@ -90,6 +95,9 @@ export class PhysicsWorld {
90
95
  jFreeCount = 0;
91
96
  jointHigh = 0;
92
97
  jointActiveCount = 0;
98
+ // Reused scratch for a joint's two world anchor points [ax,ay,az,bx,by,bz]; filled by anchorWorld
99
+ // so the gather is defined once and no per-call array is allocated on the joint hot path.
100
+ anchorScratch = new Float64Array(6);
93
101
  // Removed bodies tombstone (FLAG_DEAD) rather than compact: `id` is the SoA slot itself, handed
94
102
  // out to callers and stored raw in joints/game state, so a slot can never move once allocated.
95
103
  // `bodyHigh` is the high-water mark of ever-used slots; `bodyFree` recycles dead ones for addBody.
@@ -119,6 +127,7 @@ export class PhysicsWorld {
119
127
  stepMs: 0,
120
128
  };
121
129
  constructor(config) {
130
+ const preset = PHYSICS_PRECISION_PRESETS[config.precision ?? "standard"];
122
131
  this.capacity = config.capacity;
123
132
  this.bounds = { min: config.bounds.min, max: config.bounds.max };
124
133
  this.gravity = config.gravity ?? -20;
@@ -129,16 +138,16 @@ export class PhysicsWorld {
129
138
  this.restitutionThreshold = config.restitutionThreshold ?? 1;
130
139
  this.friction = config.friction ?? 0.4;
131
140
  this.linearDamping = config.linearDamping ?? 0.2;
132
- this.solverIterations = Math.max(1, config.solverIterations ?? 4);
133
- this.correctionFactor = config.correctionFactor ?? 0.2;
141
+ this.solverIterations = Math.max(1, config.solverIterations ?? preset.solverIterations);
142
+ this.correctionFactor = config.correctionFactor ?? preset.correctionFactor;
134
143
  this.slop = config.slop ?? 0.005;
135
144
  const sleepV = config.sleepLinearVelocity ?? 0.08;
136
145
  const sleepMoveEps = sleepV * this.fixedDt;
137
146
  this.sleepMove2 = sleepMoveEps * sleepMoveEps;
138
- this.sleepSteps = config.sleepThresholdSteps ?? 30;
139
- this.wakeThreshold = config.wakeThreshold ?? 0.5;
147
+ this.sleepSteps = config.sleepThresholdSteps ?? preset.sleepThresholdSteps;
148
+ this.wakeThreshold = config.wakeThreshold ?? preset.wakeThreshold;
140
149
  this.jointCapacity = Math.max(0, config.jointCapacity ?? 256);
141
- this.jointCorrection = config.jointCorrection ?? 0.5;
150
+ this.jointCorrection = config.jointCorrection ?? preset.jointCorrection;
142
151
  const cap = config.capacity;
143
152
  this.posX = new Float32Array(cap);
144
153
  this.posY = new Float32Array(cap);
@@ -307,18 +316,29 @@ export class PhysicsWorld {
307
316
  setJointRest(id, restLength) {
308
317
  this.jRest[id] = restLength;
309
318
  }
310
- jointDistance(id) {
319
+ /**
320
+ * Gather joint `id`'s two world anchor points into {@link anchorScratch} as [ax,ay,az,bx,by,bz]
321
+ * (A's local offset added to body A's centre, or world-origin when A is unset; B likewise, treating
322
+ * `anchorB` as a world point when B is unset). The single definition shared by {@link jointDistance},
323
+ * {@link readJointSegments}, and {@link solveJoints}.
324
+ */
325
+ anchorWorld(id) {
326
+ const s = this.anchorScratch;
311
327
  const bA = this.jBodyA[id];
312
328
  const bB = this.jBodyB[id];
313
- const ax = (bA >= 0 ? this.posX[bA] : 0) + this.jAnchorAX[id];
314
- const ay = (bA >= 0 ? this.posY[bA] : 0) + this.jAnchorAY[id];
315
- const az = (bA >= 0 ? this.posZ[bA] : 0) + this.jAnchorAZ[id];
316
- const bx = bB >= 0 ? this.posX[bB] + this.jAnchorBX[id] : this.jAnchorBX[id];
317
- const by = bB >= 0 ? this.posY[bB] + this.jAnchorBY[id] : this.jAnchorBY[id];
318
- const bz = bB >= 0 ? this.posZ[bB] + this.jAnchorBZ[id] : this.jAnchorBZ[id];
319
- const dx = bx - ax;
320
- const dy = by - ay;
321
- const dz = bz - az;
329
+ s[0] = (bA >= 0 ? this.posX[bA] : 0) + this.jAnchorAX[id];
330
+ s[1] = (bA >= 0 ? this.posY[bA] : 0) + this.jAnchorAY[id];
331
+ s[2] = (bA >= 0 ? this.posZ[bA] : 0) + this.jAnchorAZ[id];
332
+ s[3] = bB >= 0 ? this.posX[bB] + this.jAnchorBX[id] : this.jAnchorBX[id];
333
+ s[4] = bB >= 0 ? this.posY[bB] + this.jAnchorBY[id] : this.jAnchorBY[id];
334
+ s[5] = bB >= 0 ? this.posZ[bB] + this.jAnchorBZ[id] : this.jAnchorBZ[id];
335
+ }
336
+ jointDistance(id) {
337
+ this.anchorWorld(id);
338
+ const s = this.anchorScratch;
339
+ const dx = s[3] - s[0];
340
+ const dy = s[4] - s[1];
341
+ const dz = s[5] - s[2];
322
342
  return Math.sqrt(dx * dx + dy * dy + dz * dz);
323
343
  }
324
344
  /** Write [ax,ay,az,bx,by,bz] world endpoints per active joint into `out`; returns the joint count. */
@@ -327,15 +347,15 @@ export class PhysicsWorld {
327
347
  for (let id = 0; id < this.jointHigh; id += 1) {
328
348
  if (this.jActive[id] !== 1)
329
349
  continue;
330
- const bA = this.jBodyA[id];
331
- const bB = this.jBodyB[id];
350
+ this.anchorWorld(id);
351
+ const s = this.anchorScratch;
332
352
  const o = n * 6;
333
- out[o] = (bA >= 0 ? this.posX[bA] : 0) + this.jAnchorAX[id];
334
- out[o + 1] = (bA >= 0 ? this.posY[bA] : 0) + this.jAnchorAY[id];
335
- out[o + 2] = (bA >= 0 ? this.posZ[bA] : 0) + this.jAnchorAZ[id];
336
- out[o + 3] = bB >= 0 ? this.posX[bB] + this.jAnchorBX[id] : this.jAnchorBX[id];
337
- out[o + 4] = bB >= 0 ? this.posY[bB] + this.jAnchorBY[id] : this.jAnchorBY[id];
338
- out[o + 5] = bB >= 0 ? this.posZ[bB] + this.jAnchorBZ[id] : this.jAnchorBZ[id];
353
+ out[o] = s[0];
354
+ out[o + 1] = s[1];
355
+ out[o + 2] = s[2];
356
+ out[o + 3] = s[3];
357
+ out[o + 4] = s[4];
358
+ out[o + 5] = s[5];
339
359
  n += 1;
340
360
  }
341
361
  return n;
@@ -603,6 +623,29 @@ export class PhysicsWorld {
603
623
  this.velY[i] = this.velY[i] < rt ? 0 : -this.velY[i] * e;
604
624
  }
605
625
  }
626
+ /**
627
+ * Walk every broadphase cell body `i`'s AABB overlaps, invoking `visit(cell)` once per cell. The
628
+ * cell-range math (six `cellCoord` calls plus the row-major triple loop) lives here so the count
629
+ * and scatter passes of {@link buildGrid} share one definition. `visit` is a caller-hoisted closure
630
+ * (created once per `buildGrid`, not per body) so the hot loop stays allocation-free.
631
+ */
632
+ forEachBodyCell(i, visit) {
633
+ const nx = this.nx;
634
+ const ny = this.ny;
635
+ const x0 = cellCoord(this.posX[i] - this.halfX[i], this.bounds.min[0], this.cellSize, this.nx);
636
+ const x1 = cellCoord(this.posX[i] + this.halfX[i], this.bounds.min[0], this.cellSize, this.nx);
637
+ const y0 = cellCoord(this.posY[i] - this.halfY[i], this.bounds.min[1], this.cellSize, this.ny);
638
+ const y1 = cellCoord(this.posY[i] + this.halfY[i], this.bounds.min[1], this.cellSize, this.ny);
639
+ const z0 = cellCoord(this.posZ[i] - this.halfZ[i], this.bounds.min[2], this.cellSize, this.nz);
640
+ const z1 = cellCoord(this.posZ[i] + this.halfZ[i], this.bounds.min[2], this.cellSize, this.nz);
641
+ for (let z = z0; z <= z1; z += 1) {
642
+ for (let y = y0; y <= y1; y += 1) {
643
+ const rowBase = (z * ny + y) * nx;
644
+ for (let x = x0; x <= x1; x += 1)
645
+ visit(rowBase + x);
646
+ }
647
+ }
648
+ }
606
649
  buildGrid() {
607
650
  const n = this.bodyHigh;
608
651
  const start = this.cellStart;
@@ -612,24 +655,13 @@ export class PhysicsWorld {
612
655
  const i = this.awakeList[a];
613
656
  this.bodyCell[i] = this.cellOf(i);
614
657
  }
615
- const nx = this.nx;
616
- const ny = this.ny;
658
+ const countCell = (cell) => {
659
+ start[cell + 1] += 1;
660
+ };
617
661
  for (let i = 0; i < n; i += 1) {
618
662
  if ((this.flags[i] & FLAG_DEAD) !== 0)
619
663
  continue;
620
- const x0 = cellCoord(this.posX[i] - this.halfX[i], this.bounds.min[0], this.cellSize, this.nx);
621
- const x1 = cellCoord(this.posX[i] + this.halfX[i], this.bounds.min[0], this.cellSize, this.nx);
622
- const y0 = cellCoord(this.posY[i] - this.halfY[i], this.bounds.min[1], this.cellSize, this.ny);
623
- const y1 = cellCoord(this.posY[i] + this.halfY[i], this.bounds.min[1], this.cellSize, this.ny);
624
- const z0 = cellCoord(this.posZ[i] - this.halfZ[i], this.bounds.min[2], this.cellSize, this.nz);
625
- const z1 = cellCoord(this.posZ[i] + this.halfZ[i], this.bounds.min[2], this.cellSize, this.nz);
626
- for (let z = z0; z <= z1; z += 1) {
627
- for (let y = y0; y <= y1; y += 1) {
628
- const rowBase = (z * ny + y) * nx;
629
- for (let x = x0; x <= x1; x += 1)
630
- start[rowBase + x + 1] += 1;
631
- }
632
- }
664
+ this.forEachBodyCell(i, countCell);
633
665
  }
634
666
  for (let c = 0; c < this.numCells; c += 1) {
635
667
  start[c + 1] += start[c];
@@ -639,24 +671,15 @@ export class PhysicsWorld {
639
671
  if (total > this.sorted.length) {
640
672
  this.sorted = new Int32Array(Math.max(total, this.sorted.length * 2));
641
673
  }
674
+ let scatterBody = 0;
675
+ const scatterCell = (cell) => {
676
+ this.sorted[this.cursor[cell]++] = scatterBody;
677
+ };
642
678
  for (let i = 0; i < n; i += 1) {
643
679
  if ((this.flags[i] & FLAG_DEAD) !== 0)
644
680
  continue;
645
- const x0 = cellCoord(this.posX[i] - this.halfX[i], this.bounds.min[0], this.cellSize, this.nx);
646
- const x1 = cellCoord(this.posX[i] + this.halfX[i], this.bounds.min[0], this.cellSize, this.nx);
647
- const y0 = cellCoord(this.posY[i] - this.halfY[i], this.bounds.min[1], this.cellSize, this.ny);
648
- const y1 = cellCoord(this.posY[i] + this.halfY[i], this.bounds.min[1], this.cellSize, this.ny);
649
- const z0 = cellCoord(this.posZ[i] - this.halfZ[i], this.bounds.min[2], this.cellSize, this.nz);
650
- const z1 = cellCoord(this.posZ[i] + this.halfZ[i], this.bounds.min[2], this.cellSize, this.nz);
651
- for (let z = z0; z <= z1; z += 1) {
652
- for (let y = y0; y <= y1; y += 1) {
653
- const rowBase = (z * ny + y) * nx;
654
- for (let x = x0; x <= x1; x += 1) {
655
- const c = rowBase + x;
656
- this.sorted[this.cursor[c]++] = i;
657
- }
658
- }
659
- }
681
+ scatterBody = i;
682
+ this.forEachBodyCell(i, scatterCell);
660
683
  }
661
684
  }
662
685
  cellOf(i) {
@@ -861,6 +884,39 @@ export class PhysicsWorld {
861
884
  this.posY[j] += corr * imJ * nY;
862
885
  this.posZ[j] += corr * imJ * nZ;
863
886
  }
887
+ /**
888
+ * Apply an axial velocity impulse `jn` along unit axis (nX,nY,nZ) to a joint's two bodies: body A
889
+ * recoils (−) and body B advances (+), each scaled by its inverse mass. A world anchor (body index
890
+ * < 0) is skipped. Scalar args only — no allocation on the joint hot path.
891
+ */
892
+ applyAxialImpulse(bA, bB, imA, imB, jn, nX, nY, nZ) {
893
+ if (bA >= 0) {
894
+ this.velX[bA] -= jn * imA * nX;
895
+ this.velY[bA] -= jn * imA * nY;
896
+ this.velZ[bA] -= jn * imA * nZ;
897
+ }
898
+ if (bB >= 0) {
899
+ this.velX[bB] += jn * imB * nX;
900
+ this.velY[bB] += jn * imB * nY;
901
+ this.velZ[bB] += jn * imB * nZ;
902
+ }
903
+ }
904
+ /**
905
+ * Positional (Baumgarte) twin of {@link applyAxialImpulse}: nudge the joint's two bodies along
906
+ * (nX,nY,nZ) by `corr` — body A advances (+), body B recoils (−), each scaled by its inverse mass.
907
+ */
908
+ applyAxialCorrection(bA, bB, imA, imB, corr, nX, nY, nZ) {
909
+ if (bA >= 0) {
910
+ this.posX[bA] += corr * imA * nX;
911
+ this.posY[bA] += corr * imA * nY;
912
+ this.posZ[bA] += corr * imA * nZ;
913
+ }
914
+ if (bB >= 0) {
915
+ this.posX[bB] -= corr * imB * nX;
916
+ this.posY[bB] -= corr * imB * nY;
917
+ this.posZ[bB] -= corr * imB * nZ;
918
+ }
919
+ }
864
920
  solveJoints(dt) {
865
921
  const beta = this.jointCorrection;
866
922
  const slop = this.slop;
@@ -870,15 +926,11 @@ export class PhysicsWorld {
870
926
  const kind = this.jKind[id];
871
927
  const bA = this.jBodyA[id];
872
928
  const bB = this.jBodyB[id];
873
- const ax = (bA >= 0 ? this.posX[bA] : 0) + this.jAnchorAX[id];
874
- const ay = (bA >= 0 ? this.posY[bA] : 0) + this.jAnchorAY[id];
875
- const az = (bA >= 0 ? this.posZ[bA] : 0) + this.jAnchorAZ[id];
876
- const bx = bB >= 0 ? this.posX[bB] + this.jAnchorBX[id] : this.jAnchorBX[id];
877
- const by = bB >= 0 ? this.posY[bB] + this.jAnchorBY[id] : this.jAnchorBY[id];
878
- const bz = bB >= 0 ? this.posZ[bB] + this.jAnchorBZ[id] : this.jAnchorBZ[id];
879
- let dx = bx - ax;
880
- let dy = by - ay;
881
- let dz = bz - az;
929
+ this.anchorWorld(id);
930
+ const s = this.anchorScratch;
931
+ let dx = s[3] - s[0];
932
+ let dy = s[4] - s[1];
933
+ let dz = s[5] - s[2];
882
934
  const imA = bA >= 0 ? this.invMass[bA] : 0;
883
935
  const imB = bB >= 0 ? this.invMass[bB] : 0;
884
936
  const imSum = imA + imB;
@@ -918,27 +970,9 @@ export class PhysicsWorld {
918
970
  }
919
971
  const rvn = rvx * nX + rvy * nY + rvz * nZ;
920
972
  const jn = -rvn / imSum;
921
- if (bA >= 0) {
922
- this.velX[bA] -= jn * imA * nX;
923
- this.velY[bA] -= jn * imA * nY;
924
- this.velZ[bA] -= jn * imA * nZ;
925
- }
926
- if (bB >= 0) {
927
- this.velX[bB] += jn * imB * nX;
928
- this.velY[bB] += jn * imB * nY;
929
- this.velZ[bB] += jn * imB * nZ;
930
- }
973
+ this.applyAxialImpulse(bA, bB, imA, imB, jn, nX, nY, nZ);
931
974
  const corr = (dist * beta) / imSum;
932
- if (bA >= 0) {
933
- this.posX[bA] += corr * imA * nX;
934
- this.posY[bA] += corr * imA * nY;
935
- this.posZ[bA] += corr * imA * nZ;
936
- }
937
- if (bB >= 0) {
938
- this.posX[bB] -= corr * imB * nX;
939
- this.posY[bB] -= corr * imB * nY;
940
- this.posZ[bB] -= corr * imB * nZ;
941
- }
975
+ this.applyAxialCorrection(bA, bB, imA, imB, corr, nX, nY, nZ);
942
976
  }
943
977
  else {
944
978
  const rvl = Math.sqrt(rvx * rvx + rvy * rvy + rvz * rvz);
@@ -947,16 +981,7 @@ export class PhysicsWorld {
947
981
  const nY = rvy / rvl;
948
982
  const nZ = rvz / rvl;
949
983
  const jn = -rvl / imSum;
950
- if (bA >= 0) {
951
- this.velX[bA] -= jn * imA * nX;
952
- this.velY[bA] -= jn * imA * nY;
953
- this.velZ[bA] -= jn * imA * nZ;
954
- }
955
- if (bB >= 0) {
956
- this.velX[bB] += jn * imB * nX;
957
- this.velY[bB] += jn * imB * nY;
958
- this.velZ[bB] += jn * imB * nZ;
959
- }
984
+ this.applyAxialImpulse(bA, bB, imA, imB, jn, nX, nY, nZ);
960
985
  }
961
986
  }
962
987
  continue;
@@ -988,16 +1013,7 @@ export class PhysicsWorld {
988
1013
  jn = maxJ;
989
1014
  else if (jn < -maxJ)
990
1015
  jn = -maxJ;
991
- if (bA >= 0) {
992
- this.velX[bA] -= jn * imA * nX;
993
- this.velY[bA] -= jn * imA * nY;
994
- this.velZ[bA] -= jn * imA * nZ;
995
- }
996
- if (bB >= 0) {
997
- this.velX[bB] += jn * imB * nX;
998
- this.velY[bB] += jn * imB * nY;
999
- this.velZ[bB] += jn * imB * nZ;
1000
- }
1016
+ this.applyAxialImpulse(bA, bB, imA, imB, jn, nX, nY, nZ);
1001
1017
  continue;
1002
1018
  }
1003
1019
  if (kind !== JOINT_FIXED && kind !== JOINT_DISTANCE) {
@@ -1010,27 +1026,9 @@ export class PhysicsWorld {
1010
1026
  this.wake(bB);
1011
1027
  }
1012
1028
  const jn = -rvn / imSum;
1013
- if (bA >= 0) {
1014
- this.velX[bA] -= jn * imA * nX;
1015
- this.velY[bA] -= jn * imA * nY;
1016
- this.velZ[bA] -= jn * imA * nZ;
1017
- }
1018
- if (bB >= 0) {
1019
- this.velX[bB] += jn * imB * nX;
1020
- this.velY[bB] += jn * imB * nY;
1021
- this.velZ[bB] += jn * imB * nZ;
1022
- }
1029
+ this.applyAxialImpulse(bA, bB, imA, imB, jn, nX, nY, nZ);
1023
1030
  const corr = (c * beta) / imSum;
1024
- if (bA >= 0) {
1025
- this.posX[bA] += corr * imA * nX;
1026
- this.posY[bA] += corr * imA * nY;
1027
- this.posZ[bA] += corr * imA * nZ;
1028
- }
1029
- if (bB >= 0) {
1030
- this.posX[bB] -= corr * imB * nX;
1031
- this.posY[bB] -= corr * imB * nY;
1032
- this.posZ[bB] -= corr * imB * nZ;
1033
- }
1031
+ this.applyAxialCorrection(bA, bB, imA, imB, corr, nX, nY, nZ);
1034
1032
  }
1035
1033
  }
1036
1034
  updateSleep() {
@@ -0,0 +1,25 @@
1
+ /** How a radial impulse fades from the blast center to its edge. */
2
+ export type RadialFalloff = "linear" | "quadratic" | "none";
3
+ /** A radial push: the impulse vector plus the 0..1 falloff sampled at the target. */
4
+ export interface RadialImpulse {
5
+ /** Impulse along the first axis (direction × magnitude). */
6
+ x: number;
7
+ /** Impulse along the second axis (direction × magnitude). */
8
+ y: number;
9
+ /** Impulse magnitude = `power` × `falloff`. */
10
+ magnitude: number;
11
+ /** Falloff weight at the target, 1 at the center down to 0 at the radius. */
12
+ falloff: number;
13
+ }
14
+ /** Options for {@link radialImpulse}. */
15
+ export interface RadialImpulseOptions {
16
+ /** Falloff shape. Defaults to `"linear"` (`1 − d/r`). */
17
+ falloff?: RadialFalloff;
18
+ }
19
+ /**
20
+ * Point-source radial impulse pushing a `target` away from a blast `source`: full `power` at the center
21
+ * fading to zero at `radius`. Returns `null` when the target sits at or beyond the radius (unaffected),
22
+ * so callers can early-out. At the exact center the direction is zero. This is the explosion/knockback/
23
+ * shockwave push — every arena game hand-rolled the distance, falloff, and normalize.
24
+ */
25
+ export declare function radialImpulse(source: readonly [number, number], target: readonly [number, number], radius: number, power: number, options?: RadialImpulseOptions): RadialImpulse | null;
@@ -0,0 +1,27 @@
1
+ function falloffAt(distance, radius, shape) {
2
+ const linear = 1 - distance / radius;
3
+ if (shape === "none")
4
+ return 1;
5
+ if (shape === "quadratic")
6
+ return linear * linear;
7
+ return linear;
8
+ }
9
+ /**
10
+ * Point-source radial impulse pushing a `target` away from a blast `source`: full `power` at the center
11
+ * fading to zero at `radius`. Returns `null` when the target sits at or beyond the radius (unaffected),
12
+ * so callers can early-out. At the exact center the direction is zero. This is the explosion/knockback/
13
+ * shockwave push — every arena game hand-rolled the distance, falloff, and normalize.
14
+ */
15
+ export function radialImpulse(source, target, radius, power, options = {}) {
16
+ if (radius <= 0)
17
+ return null;
18
+ const dx = target[0] - source[0];
19
+ const dy = target[1] - source[1];
20
+ const distance = Math.hypot(dx, dy);
21
+ if (distance >= radius)
22
+ return null;
23
+ const falloff = falloffAt(distance, radius, options.falloff ?? "linear");
24
+ const magnitude = power * falloff;
25
+ const invLen = distance > 1e-6 ? 1 / distance : 0;
26
+ return { x: dx * invLen * magnitude, y: dy * invLen * magnitude, magnitude, falloff };
27
+ }
@@ -0,0 +1,44 @@
1
+ import { type CollisionObstacle } from "../movement/movementModel.js";
2
+ /**
3
+ * A single blocked-move event a car can react to (#1051): crash damage, screen shake, a metal-crunch
4
+ * cue. Reported once, when a move is first vetoed, then consumed by {@link VehicleObstacleClamp.takeImpact}.
5
+ */
6
+ export interface VehicleImpact {
7
+ /** Speed (world units/s) the car was carrying *into* the obstacle at the moment the move was blocked. */
8
+ closingSpeed: number;
9
+ /** Unit push-back direction — points from the struck surface back toward the car. */
10
+ normal: readonly [number, number];
11
+ /** Index into the obstacle set passed for the blocking tick. */
12
+ obstacleIndex: number;
13
+ }
14
+ /**
15
+ * A planar move clamp for a kinematic car: feed {@link clampMove} to a vehicle's `clampMove` hook so
16
+ * an attempted XZ displacement slides along world solids instead of driving through them, and read
17
+ * {@link takeImpact} once per tick for the crash it produced.
18
+ */
19
+ export interface VehicleObstacleClamp {
20
+ /** Resolve an attempted `from`→`to` XZ move to the destination actually allowed (slide-along). */
21
+ clampMove(from: readonly [number, number], to: readonly [number, number]): readonly [number, number];
22
+ /** Impact recorded since last take, consumed on read (null when none). Closing speed is the velocity component into the obstacle at block time, units/s. */
23
+ takeImpact(): VehicleImpact | null;
24
+ }
25
+ /**
26
+ * Build a slide-along move clamp for a kinematic car (#1051). `obstacles` is sampled fresh each tick —
27
+ * the caller hands back the already-filtered set of solids near the car — and `dt` supplies the current
28
+ * tick length so a blocked move's lost displacement converts to a closing speed. `radius` inflates each
29
+ * obstacle footprint by the car's body radius (default {@link DEFAULT_VEHICLE_RADIUS}).
30
+ *
31
+ * The slide itself is delegated to {@link resolveObstacleStep} so cars and pedestrians share one proven
32
+ * axis-separated resolver: a shallow graze keeps its tangential run and only the into-wall component is
33
+ * shed, a head-on zeroes forward progress. When any component is shed the largest such block this tick is
34
+ * kept as a {@link VehicleImpact}; {@link VehicleObstacleClamp.takeImpact} returns and clears it so a hit
35
+ * fires exactly once. The happy path (no solids near) is a zero-allocation passthrough returning `to`.
36
+ */
37
+ export declare function createVehicleObstacleClamp(options: {
38
+ /** Solids near the car this tick (already filtered to the relevant, solid set). */
39
+ obstacles: () => readonly CollisionObstacle[];
40
+ /** Vehicle body radius (units). Default {@link DEFAULT_VEHICLE_RADIUS}. */
41
+ radius?: number;
42
+ /** Current tick dt (seconds) — the divisor turning shed displacement into closing speed. */
43
+ dt: () => number;
44
+ }): VehicleObstacleClamp;
@@ -0,0 +1,115 @@
1
+ import { resolveObstacleStep } from "../movement/movementModel.js";
2
+ /** Matches the unit-box default {@link resolveObstacleStep} applies to obstacles without explicit extents. */
3
+ const DEFAULT_OBSTACLE_HALF_EXTENTS = [0.5, 0.5, 0.5];
4
+ /** Default vehicle body radius (units) inflating obstacle footprints; a compact hatchback-ish disc. */
5
+ const DEFAULT_VEHICLE_RADIUS = 1.4;
6
+ /**
7
+ * Y the car body is pinned to when handing solids to {@link resolveObstacleStep}. That stepper gates
8
+ * each obstacle by a 1.8-tall pedestrian span around `current[1]`; centring every pre-filtered solid
9
+ * on this value makes the gate always admit them, so collision is purely horizontal and the car hits
10
+ * world solids at any ground elevation (bridges, hills) even though the clamp only knows XZ.
11
+ */
12
+ const CAR_BODY_MID_Y = 0.9;
13
+ /** Below this the returned step is treated as unblocked (float-noise slack), so no phantom impacts fire. */
14
+ const BLOCK_EPSILON = 1e-6;
15
+ /**
16
+ * Build a slide-along move clamp for a kinematic car (#1051). `obstacles` is sampled fresh each tick —
17
+ * the caller hands back the already-filtered set of solids near the car — and `dt` supplies the current
18
+ * tick length so a blocked move's lost displacement converts to a closing speed. `radius` inflates each
19
+ * obstacle footprint by the car's body radius (default {@link DEFAULT_VEHICLE_RADIUS}).
20
+ *
21
+ * The slide itself is delegated to {@link resolveObstacleStep} so cars and pedestrians share one proven
22
+ * axis-separated resolver: a shallow graze keeps its tangential run and only the into-wall component is
23
+ * shed, a head-on zeroes forward progress. When any component is shed the largest such block this tick is
24
+ * kept as a {@link VehicleImpact}; {@link VehicleObstacleClamp.takeImpact} returns and clears it so a hit
25
+ * fires exactly once. The happy path (no solids near) is a zero-allocation passthrough returning `to`.
26
+ */
27
+ export function createVehicleObstacleClamp(options) {
28
+ const radius = options.radius ?? DEFAULT_VEHICLE_RADIUS;
29
+ // Grow-only scratch of Y-normalised solids, reused across ticks so a sustained crash allocates nothing
30
+ // after warm-up. Per-clamp (closure-local) so concurrent cars never share it.
31
+ const scratch = [];
32
+ let pending = null;
33
+ function vehicleView(source) {
34
+ const n = source.length;
35
+ for (let i = 0; i < n; i += 1) {
36
+ let entry = scratch[i];
37
+ if (entry === undefined) {
38
+ entry = { position: [0, 0, 0] };
39
+ scratch[i] = entry;
40
+ }
41
+ const from = source[i];
42
+ entry.position[0] = from.position[0];
43
+ entry.position[1] = CAR_BODY_MID_Y;
44
+ entry.position[2] = from.position[2];
45
+ entry.halfExtents = from.halfExtents;
46
+ }
47
+ if (scratch.length > n)
48
+ scratch.length = n;
49
+ return scratch;
50
+ }
51
+ /** Obstacle the attempted endpoint penetrates deepest (its inflated footprint), else nearest centre. */
52
+ function blockingIndex(source, tx, tz) {
53
+ let bestIndex = -1;
54
+ let bestDepth = -Number.POSITIVE_INFINITY;
55
+ let fallbackIndex = 0;
56
+ let fallbackDistSq = Number.POSITIVE_INFINITY;
57
+ for (let i = 0; i < source.length; i += 1) {
58
+ const o = source[i];
59
+ const half = o.halfExtents ?? DEFAULT_OBSTACLE_HALF_EXTENTS;
60
+ const ex = half[0] + radius;
61
+ const ez = half[2] + radius;
62
+ const minX = o.position[0] - ex;
63
+ const maxX = o.position[0] + ex;
64
+ const minZ = o.position[2] - ez;
65
+ const maxZ = o.position[2] + ez;
66
+ if (tx > minX && tx < maxX && tz > minZ && tz < maxZ) {
67
+ const depth = Math.min(tx - minX, maxX - tx, tz - minZ, maxZ - tz);
68
+ if (depth > bestDepth) {
69
+ bestDepth = depth;
70
+ bestIndex = i;
71
+ }
72
+ }
73
+ const dx = o.position[0] - tx;
74
+ const dz = o.position[2] - tz;
75
+ const distSq = dx * dx + dz * dz;
76
+ if (distSq < fallbackDistSq) {
77
+ fallbackDistSq = distSq;
78
+ fallbackIndex = i;
79
+ }
80
+ }
81
+ return bestIndex >= 0 ? bestIndex : fallbackIndex;
82
+ }
83
+ return {
84
+ clampMove(from, to) {
85
+ const obstacles = options.obstacles();
86
+ if (obstacles.length === 0)
87
+ return to;
88
+ const attemptedX = to[0] - from[0];
89
+ const attemptedZ = to[1] - from[1];
90
+ const step = resolveObstacleStep([from[0], CAR_BODY_MID_Y, from[1]], attemptedX, attemptedZ, vehicleView(obstacles), radius);
91
+ const blockedX = attemptedX - step.stepX;
92
+ const blockedZ = attemptedZ - step.stepZ;
93
+ if (blockedX === 0 && blockedZ === 0)
94
+ return to;
95
+ const blockedMag = Math.hypot(blockedX, blockedZ);
96
+ if (blockedMag > BLOCK_EPSILON) {
97
+ const dt = options.dt();
98
+ const closingSpeed = dt > 0 ? blockedMag / dt : 0;
99
+ if (pending === null || closingSpeed > pending.closingSpeed) {
100
+ pending = {
101
+ closingSpeed,
102
+ normal: [-blockedX / blockedMag, -blockedZ / blockedMag],
103
+ obstacleIndex: blockingIndex(obstacles, to[0], to[1]),
104
+ };
105
+ }
106
+ }
107
+ return [from[0] + step.stepX, from[1] + step.stepZ];
108
+ },
109
+ takeImpact() {
110
+ const impact = pending;
111
+ pending = null;
112
+ return impact;
113
+ },
114
+ };
115
+ }
@@ -0,0 +1,3 @@
1
+ export { createDecayMeterSet, type DecayMeterSet } from "./survival/decayMeter.js";
2
+ export { createMoodleStack, stackMoodles, type Moodle, type MoodleStack } from "./survival/moodle.js";
3
+ export { createMultiRegionHealth, type MultiRegionHealth } from "./survival/regionHealth.js";
@@ -0,0 +1,3 @@
1
+ export { createDecayMeterSet } from "./survival/decayMeter.js";
2
+ export { createMoodleStack, stackMoodles } from "./survival/moodle.js";
3
+ export { createMultiRegionHealth } from "./survival/regionHealth.js";