@jgengine/core 0.9.0 → 0.11.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 (631) hide show
  1. package/CHANGELOG.md +34 -3
  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/spawnDirector.d.ts +19 -1
  21. package/dist/ai/spawnDirector.js +53 -26
  22. package/dist/ai/spawnPoint.d.ts +7 -0
  23. package/dist/ai/spawnPoint.js +7 -0
  24. package/dist/ai/targetAcquisition.d.ts +84 -0
  25. package/dist/ai/targetAcquisition.js +92 -0
  26. package/dist/anim/easing.d.ts +19 -0
  27. package/dist/anim/easing.js +19 -0
  28. package/dist/anim/oscillator.d.ts +12 -0
  29. package/dist/anim/oscillator.js +25 -0
  30. package/dist/area/areaEffectField.d.ts +127 -0
  31. package/dist/area/areaEffectField.js +175 -0
  32. package/dist/area/stackPolicy.d.ts +47 -0
  33. package/dist/area/stackPolicy.js +99 -0
  34. package/dist/audio/audioFalloff.d.ts +5 -2
  35. package/dist/audio/music.d.ts +53 -0
  36. package/dist/audio/music.js +34 -0
  37. package/dist/audio/synth.d.ts +60 -0
  38. package/dist/audio/synth.js +8 -0
  39. package/dist/authoring.d.ts +15 -0
  40. package/dist/authoring.js +15 -0
  41. package/dist/board/laneBoard.d.ts +13 -0
  42. package/dist/board/laneBoard.js +13 -0
  43. package/dist/board/timelineBoard.d.ts +10 -0
  44. package/dist/board/timelineBoard.js +10 -0
  45. package/dist/combat/abilityKit.d.ts +18 -0
  46. package/dist/combat/abilityKit.js +24 -9
  47. package/dist/combat/animationState.d.ts +5 -0
  48. package/dist/combat/animationState.js +5 -0
  49. package/dist/combat/breakMeters.d.ts +10 -0
  50. package/dist/combat/breakMeters.js +10 -0
  51. package/dist/combat/castRunner.d.ts +5 -0
  52. package/dist/combat/castRunner.js +5 -0
  53. package/dist/combat/comboPoints.d.ts +5 -0
  54. package/dist/combat/comboPoints.js +5 -0
  55. package/dist/combat/comboString.d.ts +5 -0
  56. package/dist/combat/comboString.js +5 -0
  57. package/dist/combat/damageInterceptors.d.ts +192 -0
  58. package/dist/combat/damageInterceptors.js +251 -0
  59. package/dist/combat/damageMatchup.d.ts +68 -0
  60. package/dist/combat/damageMatchup.js +42 -0
  61. package/dist/combat/damageResolution.d.ts +63 -0
  62. package/dist/combat/damageResolution.js +50 -0
  63. package/dist/combat/death.d.ts +7 -1
  64. package/dist/combat/death.js +5 -0
  65. package/dist/combat/deathReason.d.ts +14 -0
  66. package/dist/combat/deathReason.js +1 -0
  67. package/dist/combat/defensiveWindow.d.ts +5 -0
  68. package/dist/combat/defensiveWindow.js +5 -0
  69. package/dist/combat/dotField.d.ts +47 -0
  70. package/dist/combat/dotField.js +52 -0
  71. package/dist/combat/downed.d.ts +5 -0
  72. package/dist/combat/downed.js +5 -0
  73. package/dist/combat/effects.d.ts +5 -0
  74. package/dist/combat/effects.js +5 -0
  75. package/dist/combat/encounterSequence.d.ts +258 -0
  76. package/dist/combat/encounterSequence.js +426 -0
  77. package/dist/combat/hitReaction.d.ts +57 -1
  78. package/dist/combat/hitReaction.js +45 -5
  79. package/dist/combat/magazine.d.ts +54 -0
  80. package/dist/combat/magazine.js +96 -0
  81. package/dist/combat/projectiles.d.ts +7 -2
  82. package/dist/combat/projectiles.js +48 -17
  83. package/dist/combat/receivedDamage.d.ts +117 -0
  84. package/dist/combat/receivedDamage.js +92 -0
  85. package/dist/combat/regenShield.d.ts +39 -0
  86. package/dist/combat/regenShield.js +49 -0
  87. package/dist/combat/renderCues.d.ts +51 -0
  88. package/dist/combat/renderCues.js +44 -0
  89. package/dist/combat/resourcePool.d.ts +5 -0
  90. package/dist/combat/resourcePool.js +5 -0
  91. package/dist/combat/rewardAllocation.d.ts +121 -0
  92. package/dist/combat/rewardAllocation.js +251 -0
  93. package/dist/combat/shotOrigin.d.ts +30 -1
  94. package/dist/combat/shotOrigin.js +70 -2
  95. package/dist/combat/statusApplication.d.ts +96 -0
  96. package/dist/combat/statusApplication.js +81 -0
  97. package/dist/combat/telegraph.d.ts +11 -2
  98. package/dist/combat/telegraph.js +11 -2
  99. package/dist/combat/thresholdCrossings.d.ts +85 -0
  100. package/dist/combat/thresholdCrossings.js +116 -0
  101. package/dist/combat.d.ts +34 -0
  102. package/dist/combat.js +34 -0
  103. package/dist/commands/commandRegistry.d.ts +11 -0
  104. package/dist/commands/commandRegistry.js +9 -2
  105. package/dist/crafting/crop.d.ts +18 -0
  106. package/dist/crafting/crop.js +18 -0
  107. package/dist/crafting/production.d.ts +5 -0
  108. package/dist/crafting/production.js +5 -0
  109. package/dist/devtools/rewriteTunables.d.ts +17 -0
  110. package/dist/devtools/rewriteTunables.js +276 -0
  111. package/dist/devtools/saveEndpoint.d.ts +46 -0
  112. package/dist/devtools/saveEndpoint.js +48 -0
  113. package/dist/devtools/transformTunables.d.ts +3 -0
  114. package/dist/devtools/transformTunables.js +3 -0
  115. package/dist/devtools/tunableSchema.d.ts +31 -0
  116. package/dist/devtools/tunableSchema.js +31 -0
  117. package/dist/economy/currency.d.ts +12 -1
  118. package/dist/economy/currency.js +12 -1
  119. package/dist/economy/listingBook.d.ts +91 -0
  120. package/dist/economy/listingBook.js +144 -0
  121. package/dist/economy/resourceLedger.d.ts +222 -0
  122. package/dist/economy/resourceLedger.js +353 -0
  123. package/dist/economy/sharedWallet.d.ts +14 -0
  124. package/dist/economy/sharedWallet.js +14 -0
  125. package/dist/economy/techTree.d.ts +12 -0
  126. package/dist/economy/techTree.js +12 -0
  127. package/dist/economy/wallet.d.ts +26 -2
  128. package/dist/economy/wallet.js +35 -6
  129. package/dist/editor/commands.d.ts +248 -0
  130. package/dist/editor/commands.js +865 -0
  131. package/dist/editor/document.d.ts +186 -0
  132. package/dist/editor/document.js +884 -0
  133. package/dist/editor/grid.d.ts +229 -0
  134. package/dist/editor/grid.js +366 -0
  135. package/dist/editor/gridAdapters.d.ts +80 -0
  136. package/dist/editor/gridAdapters.js +134 -0
  137. package/dist/editor/index.d.ts +97 -0
  138. package/dist/editor/index.js +10 -0
  139. package/dist/editor/liveSync.d.ts +127 -0
  140. package/dist/editor/liveSync.js +249 -0
  141. package/dist/editor/runtimeInspector.d.ts +88 -0
  142. package/dist/editor/runtimeInspector.js +239 -0
  143. package/dist/editor/types.d.ts +175 -0
  144. package/dist/editor/types.js +29 -0
  145. package/dist/faction/reputation.d.ts +5 -0
  146. package/dist/faction/reputation.js +5 -0
  147. package/dist/format/distance.d.ts +17 -0
  148. package/dist/format/distance.js +18 -0
  149. package/dist/format/duration.d.ts +27 -0
  150. package/dist/format/duration.js +45 -0
  151. package/dist/format/speed.d.ts +17 -0
  152. package/dist/format/speed.js +25 -0
  153. package/dist/game/connectedPlayers.d.ts +30 -0
  154. package/dist/game/connectedPlayers.js +21 -0
  155. package/dist/game/cosmetics.d.ts +9 -0
  156. package/dist/game/cosmetics.js +16 -0
  157. package/dist/game/defineGame.d.ts +141 -2
  158. package/dist/game/defineGame.js +39 -1
  159. package/dist/game/defineSystem.d.ts +88 -0
  160. package/dist/game/defineSystem.js +45 -0
  161. package/dist/game/dialogue.d.ts +33 -0
  162. package/dist/game/dialogue.js +21 -0
  163. package/dist/game/events.d.ts +50 -13
  164. package/dist/game/events.js +5 -0
  165. package/dist/game/feed.d.ts +33 -0
  166. package/dist/game/feed.js +35 -2
  167. package/dist/game/gamePhase.d.ts +11 -0
  168. package/dist/game/gamePhase.js +16 -0
  169. package/dist/game/keyValueStore.d.ts +25 -0
  170. package/dist/game/keyValueStore.js +61 -0
  171. package/dist/game/leaderboard.d.ts +5 -0
  172. package/dist/game/leaderboard.js +5 -0
  173. package/dist/game/levelSequence.d.ts +24 -2
  174. package/dist/game/levelSequence.js +51 -2
  175. package/dist/game/loadout.d.ts +5 -0
  176. package/dist/game/loadout.js +5 -0
  177. package/dist/game/lootFilter.d.ts +2 -0
  178. package/dist/game/lootFilter.js +2 -0
  179. package/dist/game/lootPipeline.d.ts +164 -0
  180. package/dist/game/lootPipeline.js +216 -0
  181. package/dist/game/lootTable.d.ts +21 -0
  182. package/dist/game/lootTable.js +15 -4
  183. package/dist/game/modelAnimation.d.ts +8 -0
  184. package/dist/game/modelAnimation.js +18 -0
  185. package/dist/game/objectives.d.ts +43 -0
  186. package/dist/game/objectives.js +36 -0
  187. package/dist/game/paramLayers.d.ts +148 -0
  188. package/dist/game/paramLayers.js +185 -0
  189. package/dist/game/ping.d.ts +5 -0
  190. package/dist/game/ping.js +5 -0
  191. package/dist/game/playableGame.d.ts +160 -12
  192. package/dist/game/quest.d.ts +8 -0
  193. package/dist/game/quest.js +29 -0
  194. package/dist/game/race.d.ts +141 -0
  195. package/dist/game/race.js +169 -0
  196. package/dist/game/recordBook.d.ts +5 -5
  197. package/dist/game/recordBook.js +4 -1
  198. package/dist/game/ruleSelection.d.ts +75 -0
  199. package/dist/game/ruleSelection.js +127 -0
  200. package/dist/game/runDraft.d.ts +5 -0
  201. package/dist/game/runDraft.js +5 -0
  202. package/dist/game/saveStore.d.ts +111 -0
  203. package/dist/game/saveStore.js +312 -0
  204. package/dist/game/snapshotHistory.d.ts +67 -0
  205. package/dist/game/snapshotHistory.js +95 -0
  206. package/dist/game/social.d.ts +38 -1
  207. package/dist/game/social.js +71 -0
  208. package/dist/game/spawnPoints.d.ts +5 -0
  209. package/dist/game/spawnPoints.js +5 -0
  210. package/dist/game/systemRuntime.d.ts +50 -0
  211. package/dist/game/systemRuntime.js +157 -0
  212. package/dist/game/systemSchedule.d.ts +72 -0
  213. package/dist/game/systemSchedule.js +242 -0
  214. package/dist/game/toasts.d.ts +43 -0
  215. package/dist/game/toasts.js +44 -0
  216. package/dist/game/trade.d.ts +10 -0
  217. package/dist/game/trade.js +10 -0
  218. package/dist/game/unlocks.d.ts +8 -0
  219. package/dist/game/unlocks.js +16 -0
  220. package/dist/game/vfxInstance.d.ts +138 -0
  221. package/dist/game/vfxInstance.js +96 -0
  222. package/dist/game/worldItem.d.ts +17 -4
  223. package/dist/game/worldItem.js +17 -4
  224. package/dist/gameplay.d.ts +91 -0
  225. package/dist/gameplay.js +91 -0
  226. package/dist/index.d.ts +5 -7
  227. package/dist/index.js +5 -7
  228. package/dist/input/actionBindings.d.ts +24 -5
  229. package/dist/input/actionBindings.js +23 -5
  230. package/dist/input/axisInput.d.ts +13 -1
  231. package/dist/input/axisInput.js +22 -1
  232. package/dist/input/controlGroups.d.ts +67 -0
  233. package/dist/input/controlGroups.js +41 -0
  234. package/dist/input/touchScheme.d.ts +82 -6
  235. package/dist/input/touchScheme.js +123 -10
  236. package/dist/interaction/contextMenu.d.ts +1 -0
  237. package/dist/interaction/contextMenu.js +1 -0
  238. package/dist/interaction/lockpick.d.ts +61 -0
  239. package/dist/interaction/lockpick.js +168 -0
  240. package/dist/interaction/proximityPrompt.d.ts +5 -1
  241. package/dist/interaction/proximityPrompt.js +5 -3
  242. package/dist/interaction/qte.d.ts +5 -0
  243. package/dist/interaction/qte.js +5 -0
  244. package/dist/interaction/skillCheck.d.ts +5 -0
  245. package/dist/interaction/skillCheck.js +5 -0
  246. package/dist/inventory/inventoryModel.d.ts +12 -0
  247. package/dist/inventory/inventoryModel.js +12 -0
  248. package/dist/inventory/shapedGrid.d.ts +16 -0
  249. package/dist/inventory/shapedGrid.js +16 -0
  250. package/dist/inventory/slotModel.d.ts +10 -0
  251. package/dist/inventory/slotModel.js +10 -0
  252. package/dist/item/durability.d.ts +5 -0
  253. package/dist/item/durability.js +5 -0
  254. package/dist/item/itemIdentity.d.ts +171 -0
  255. package/dist/item/itemIdentity.js +138 -0
  256. package/dist/item/itemInstanceRegistry.d.ts +32 -0
  257. package/dist/item/itemInstanceRegistry.js +34 -0
  258. package/dist/item/itemgen.d.ts +163 -0
  259. package/dist/item/itemgen.js +151 -0
  260. package/dist/item/modularItem.d.ts +5 -0
  261. package/dist/item/modularItem.js +5 -0
  262. package/dist/item/use.d.ts +5 -0
  263. package/dist/item/use.js +5 -0
  264. package/dist/item/useBehavior.d.ts +142 -0
  265. package/dist/item/useBehavior.js +105 -0
  266. package/dist/item/weapon.d.ts +5 -0
  267. package/dist/item/weapon.js +5 -0
  268. package/dist/math/scalar.d.ts +25 -0
  269. package/dist/math/scalar.js +47 -0
  270. package/dist/meta/changelog.d.ts +4 -1
  271. package/dist/meta/changelog.js +36 -1
  272. package/dist/movement/avoidance.d.ts +45 -0
  273. package/dist/movement/avoidance.js +123 -0
  274. package/dist/movement/cameraRig.d.ts +8 -0
  275. package/dist/movement/cameraRig.js +8 -0
  276. package/dist/movement/dash.d.ts +11 -0
  277. package/dist/movement/dash.js +11 -0
  278. package/dist/movement/formation.d.ts +135 -0
  279. package/dist/movement/formation.js +194 -0
  280. package/dist/movement/glideModel.d.ts +5 -0
  281. package/dist/movement/glideModel.js +5 -0
  282. package/dist/movement/grappleSwing.d.ts +5 -0
  283. package/dist/movement/grappleSwing.js +5 -0
  284. package/dist/movement/leaderTrail.d.ts +5 -0
  285. package/dist/movement/leaderTrail.js +5 -0
  286. package/dist/movement/movementModel.d.ts +38 -7
  287. package/dist/movement/movementModel.js +54 -13
  288. package/dist/movement/playerMovement.d.ts +41 -0
  289. package/dist/movement/playerMovement.js +236 -0
  290. package/dist/movement/poseState.d.ts +13 -0
  291. package/dist/movement/poseState.js +16 -0
  292. package/dist/movement/steering.d.ts +8 -0
  293. package/dist/movement/steering.js +18 -0
  294. package/dist/multiplayer/combatSnapshot.d.ts +3 -0
  295. package/dist/multiplayer/combatSnapshot.js +3 -0
  296. package/dist/multiplayer/lagCompensation.d.ts +5 -0
  297. package/dist/multiplayer/lagCompensation.js +5 -0
  298. package/dist/multiplayer/presenceModel.d.ts +9 -1
  299. package/dist/multiplayer/presenceModel.js +9 -1
  300. package/dist/multiplayer/simultaneousCommit.d.ts +3 -0
  301. package/dist/multiplayer/simultaneousCommit.js +3 -0
  302. package/dist/multiplayer.d.ts +11 -0
  303. package/dist/multiplayer.js +11 -0
  304. package/dist/nav/pathFollow.d.ts +57 -0
  305. package/dist/nav/pathFollow.js +109 -0
  306. package/dist/orders/orderKinds.d.ts +156 -0
  307. package/dist/orders/orderKinds.js +197 -0
  308. package/dist/orders/orderQueue.d.ts +208 -0
  309. package/dist/orders/orderQueue.js +211 -0
  310. package/dist/physics/drivableVehicle.d.ts +29 -0
  311. package/dist/physics/drivableVehicle.js +16 -0
  312. package/dist/physics/kinematicVehicle.d.ts +21 -1
  313. package/dist/physics/kinematicVehicle.js +23 -8
  314. package/dist/physics/physicsWorld.d.ts +24 -12
  315. package/dist/physics/physicsWorld.js +11 -5
  316. package/dist/physics/radialImpulse.d.ts +25 -0
  317. package/dist/physics/radialImpulse.js +27 -0
  318. package/dist/procedural.d.ts +3 -0
  319. package/dist/procedural.js +3 -0
  320. package/dist/progression/statGraph.d.ts +116 -0
  321. package/dist/progression/statGraph.js +318 -0
  322. package/dist/puzzle/cellGrid.d.ts +9 -0
  323. package/dist/puzzle/cellGrid.js +9 -0
  324. package/dist/puzzle/fallingPiece.d.ts +9 -0
  325. package/dist/puzzle/fallingPiece.js +9 -0
  326. package/dist/puzzle/nonogram.d.ts +39 -0
  327. package/dist/puzzle/nonogram.js +136 -0
  328. package/dist/random/nameGen.d.ts +5 -0
  329. package/dist/random/nameGen.js +5 -0
  330. package/dist/random/pick.d.ts +8 -0
  331. package/dist/random/pick.js +31 -0
  332. package/dist/random/rng.d.ts +24 -0
  333. package/dist/random/rng.js +30 -8
  334. package/dist/random/seedLink.d.ts +4 -0
  335. package/dist/random/seedLink.js +4 -0
  336. package/dist/relation/keyedValues.d.ts +54 -0
  337. package/dist/relation/keyedValues.js +115 -0
  338. package/dist/relation/thresholds.d.ts +62 -0
  339. package/dist/relation/thresholds.js +62 -0
  340. package/dist/render/color.d.ts +12 -0
  341. package/dist/render/color.js +26 -0
  342. package/dist/render/lookPreset.d.ts +41 -0
  343. package/dist/render/lookPreset.js +29 -0
  344. package/dist/render/postProcessing.d.ts +76 -0
  345. package/dist/render/postProcessing.js +21 -0
  346. package/dist/rules/predicate.d.ts +53 -0
  347. package/dist/rules/predicate.js +64 -0
  348. package/dist/rules/ruleEffects.d.ts +38 -0
  349. package/dist/rules/ruleEffects.js +37 -0
  350. package/dist/rules/triggeredRules.d.ts +160 -0
  351. package/dist/rules/triggeredRules.js +241 -0
  352. package/dist/runtime/adapter.d.ts +58 -0
  353. package/dist/runtime/adapter.js +54 -5
  354. package/dist/runtime/cameraDirector.d.ts +1 -0
  355. package/dist/runtime/cameraDirector.js +1 -0
  356. package/dist/runtime/commandRunner.d.ts +1 -0
  357. package/dist/runtime/commandRunner.js +1 -0
  358. package/dist/runtime/context/combatFx.d.ts +23 -0
  359. package/dist/runtime/context/combatFx.js +161 -0
  360. package/dist/runtime/context/registries.d.ts +13 -0
  361. package/dist/runtime/context/registries.js +84 -0
  362. package/dist/runtime/context/worldItems.d.ts +21 -0
  363. package/dist/runtime/context/worldItems.js +37 -0
  364. package/dist/runtime/descriptors/baseline.d.ts +48 -0
  365. package/dist/runtime/descriptors/baseline.js +134 -0
  366. package/dist/runtime/descriptors/features.d.ts +74 -0
  367. package/dist/runtime/descriptors/features.js +281 -0
  368. package/dist/runtime/gameContext.d.ts +163 -19
  369. package/dist/runtime/gameContext.js +385 -339
  370. package/dist/runtime/gameRuntime.d.ts +1 -0
  371. package/dist/runtime/gameRuntime.js +1 -0
  372. package/dist/runtime/headlessRunner.d.ts +60 -0
  373. package/dist/runtime/headlessRunner.js +44 -0
  374. package/dist/runtime/hostPersistence.d.ts +12 -0
  375. package/dist/runtime/hostPersistence.js +12 -0
  376. package/dist/runtime/hostedGameRunner.d.ts +54 -0
  377. package/dist/runtime/hostedGameRunner.js +85 -0
  378. package/dist/runtime/hostedWorldSession.d.ts +73 -0
  379. package/dist/runtime/hostedWorldSession.js +64 -0
  380. package/dist/runtime/inputSnapshot.d.ts +21 -3
  381. package/dist/runtime/inputSnapshot.js +8 -2
  382. package/dist/runtime/motionIntents.d.ts +12 -1
  383. package/dist/runtime/motionIntents.js +26 -1
  384. package/dist/runtime/perContext.d.ts +15 -0
  385. package/dist/runtime/perContext.js +21 -0
  386. package/dist/runtime/runtimeSave.d.ts +79 -0
  387. package/dist/runtime/runtimeSave.js +105 -0
  388. package/dist/runtime/save.d.ts +4 -0
  389. package/dist/runtime/save.js +4 -0
  390. package/dist/runtime/snapshot.d.ts +7 -0
  391. package/dist/runtime/snapshot.js +7 -0
  392. package/dist/runtime/visibility.d.ts +2 -1
  393. package/dist/runtime/visibility.js +2 -1
  394. package/dist/runtime/worldChannel.d.ts +62 -0
  395. package/dist/runtime/worldChannel.js +114 -0
  396. package/dist/runtime/worldMirror.d.ts +36 -0
  397. package/dist/runtime/worldMirror.js +44 -0
  398. package/dist/runtime/worldProjection.d.ts +47 -0
  399. package/dist/runtime/worldProjection.js +52 -0
  400. package/dist/runtime/worldReplication.d.ts +69 -0
  401. package/dist/runtime/worldReplication.js +217 -0
  402. package/dist/runtime/worldSnapshot.d.ts +44 -0
  403. package/dist/runtime/worldSnapshot.js +30 -0
  404. package/dist/scene/assetCatalog.d.ts +22 -0
  405. package/dist/scene/assetCatalog.js +4 -0
  406. package/dist/scene/assetDiagnostics.d.ts +69 -0
  407. package/dist/scene/assetDiagnostics.js +110 -0
  408. package/dist/scene/assetGenerator.d.ts +65 -0
  409. package/dist/scene/assetGenerator.js +64 -0
  410. package/dist/scene/assetSpace.d.ts +137 -0
  411. package/dist/scene/assetSpace.js +259 -0
  412. package/dist/scene/authoredTriggers.d.ts +169 -0
  413. package/dist/scene/authoredTriggers.js +340 -0
  414. package/dist/scene/behaviorRuntime.d.ts +75 -0
  415. package/dist/scene/behaviorRuntime.js +217 -0
  416. package/dist/scene/behaviors.d.ts +14 -2
  417. package/dist/scene/behaviors.js +7 -2
  418. package/dist/scene/bodyBind.d.ts +60 -0
  419. package/dist/scene/bodyBind.js +51 -0
  420. package/dist/scene/builtinSceneKinds.d.ts +5 -0
  421. package/dist/scene/builtinSceneKinds.js +62 -0
  422. package/dist/scene/colliders.d.ts +18 -0
  423. package/dist/scene/colliders.js +61 -1
  424. package/dist/scene/entityStats.d.ts +13 -0
  425. package/dist/scene/entityStats.js +30 -0
  426. package/dist/scene/entityStore.d.ts +41 -1
  427. package/dist/scene/entityStore.js +75 -0
  428. package/dist/scene/facing.d.ts +18 -0
  429. package/dist/scene/facing.js +26 -0
  430. package/dist/scene/modelSockets.d.ts +33 -0
  431. package/dist/scene/modelSockets.js +29 -0
  432. package/dist/scene/objectQuery.d.ts +2 -0
  433. package/dist/scene/objectQuery.js +2 -0
  434. package/dist/scene/objectStore.d.ts +4 -0
  435. package/dist/scene/objectStore.js +6 -0
  436. package/dist/scene/possession.d.ts +8 -0
  437. package/dist/scene/possession.js +14 -0
  438. package/dist/scene/roster.d.ts +3 -0
  439. package/dist/scene/roster.js +12 -0
  440. package/dist/scene/sceneKinds.d.ts +240 -0
  441. package/dist/scene/sceneKinds.js +214 -0
  442. package/dist/scene/sceneOwnership.d.ts +169 -0
  443. package/dist/scene/sceneOwnership.js +179 -0
  444. package/dist/scene/selectionBookmarks.d.ts +93 -0
  445. package/dist/scene/selectionBookmarks.js +122 -0
  446. package/dist/scene/vehicleSeat.d.ts +68 -0
  447. package/dist/scene/vehicleSeat.js +59 -0
  448. package/dist/sensor/concealment.d.ts +3 -0
  449. package/dist/sensor/concealment.js +3 -0
  450. package/dist/sensor/freezeMonitor.d.ts +1 -0
  451. package/dist/sensor/freezeMonitor.js +1 -0
  452. package/dist/sensor/frustumSensor.d.ts +7 -3
  453. package/dist/sensor/frustumSensor.js +7 -3
  454. package/dist/sensor/hiddenStateProbe.d.ts +5 -2
  455. package/dist/sensor/hiddenStateProbe.js +5 -2
  456. package/dist/sensor/recordingBuffer.d.ts +2 -1
  457. package/dist/sensor/recordingBuffer.js +2 -1
  458. package/dist/sensor/replayLoop.d.ts +6 -2
  459. package/dist/sensor/replayLoop.js +6 -2
  460. package/dist/sensor/revealQuery.d.ts +2 -1
  461. package/dist/sensor/revealQuery.js +2 -1
  462. package/dist/sensor/visionCone.d.ts +10 -3
  463. package/dist/sensor/visionCone.js +10 -3
  464. package/dist/session/contestedChannel.d.ts +1 -0
  465. package/dist/session/contestedChannel.js +1 -0
  466. package/dist/session/extraction.d.ts +1 -0
  467. package/dist/session/extraction.js +1 -0
  468. package/dist/session/roles.d.ts +6 -0
  469. package/dist/session/roles.js +6 -0
  470. package/dist/session/roundState.d.ts +8 -0
  471. package/dist/session/roundState.js +2 -0
  472. package/dist/settings/settingsModel.d.ts +1 -0
  473. package/dist/settings/settingsModel.js +1 -0
  474. package/dist/stats/accumulatorMeter.d.ts +6 -0
  475. package/dist/stats/accumulatorMeter.js +6 -0
  476. package/dist/stats/eventMeter.d.ts +5 -0
  477. package/dist/stats/eventMeter.js +5 -0
  478. package/dist/stats/rollCheck.d.ts +5 -0
  479. package/dist/stats/rollCheck.js +5 -0
  480. package/dist/stats/statModifiers.d.ts +5 -0
  481. package/dist/stats/statModifiers.js +5 -0
  482. package/dist/store/defineKeyedStore.d.ts +38 -0
  483. package/dist/store/defineKeyedStore.js +42 -0
  484. package/dist/store/defineStore.d.ts +33 -0
  485. package/dist/store/defineStore.js +35 -0
  486. package/dist/store/observableKeyedStore.d.ts +9 -0
  487. package/dist/store/observableKeyedStore.js +43 -2
  488. package/dist/survival/decayMeter.d.ts +55 -0
  489. package/dist/survival/decayMeter.js +130 -55
  490. package/dist/survival/moodle.d.ts +2 -0
  491. package/dist/survival/regionHealth.d.ts +6 -0
  492. package/dist/survival/regionHealth.js +5 -0
  493. package/dist/tactics/fallingGrid.d.ts +6 -4
  494. package/dist/tactics/fallingGrid.js +6 -4
  495. package/dist/tactics/predictiveQuery.d.ts +3 -0
  496. package/dist/tactics/predictiveQuery.js +3 -0
  497. package/dist/tactics/snapshot.d.ts +2 -0
  498. package/dist/tactics/snapshot.js +2 -0
  499. package/dist/tactics/surface.d.ts +1 -0
  500. package/dist/tactics/surface.js +1 -0
  501. package/dist/tactics/tacticalGrid.d.ts +1 -0
  502. package/dist/tactics/tacticalGrid.js +1 -0
  503. package/dist/time/beatClock.d.ts +14 -4
  504. package/dist/time/beatClock.js +14 -4
  505. package/dist/time/calendarClock.d.ts +3 -0
  506. package/dist/time/calendarClock.js +3 -0
  507. package/dist/time/idleProgress.d.ts +4 -0
  508. package/dist/time/idleProgress.js +4 -0
  509. package/dist/time/simClock.d.ts +2 -0
  510. package/dist/time/simClock.js +20 -5
  511. package/dist/ui/actionModel.d.ts +110 -0
  512. package/dist/ui/actionModel.js +159 -0
  513. package/dist/ui/gameLayout.d.ts +144 -0
  514. package/dist/ui/gameLayout.js +148 -0
  515. package/dist/ui/hudDocument.d.ts +114 -0
  516. package/dist/ui/hudDocument.js +220 -0
  517. package/dist/ui/hudLayout.d.ts +33 -1
  518. package/dist/ui/hudLayout.js +204 -17
  519. package/dist/ui/orientation.d.ts +39 -0
  520. package/dist/ui/orientation.js +49 -0
  521. package/dist/ui/selectionModel.d.ts +92 -0
  522. package/dist/ui/selectionModel.js +88 -0
  523. package/dist/ui/swingTimer.d.ts +42 -0
  524. package/dist/ui/swingTimer.js +38 -0
  525. package/dist/ui/tooltipModel.d.ts +63 -0
  526. package/dist/ui/tooltipModel.js +82 -0
  527. package/dist/ui.d.ts +15 -0
  528. package/dist/ui.js +15 -0
  529. package/dist/visibility/bounds.d.ts +8 -1
  530. package/dist/visibility/bounds.js +8 -1
  531. package/dist/visibility/frustum.d.ts +12 -3
  532. package/dist/visibility/frustum.js +12 -3
  533. package/dist/visibility/spatialIndex.js +34 -20
  534. package/dist/work/jobQueue.d.ts +201 -0
  535. package/dist/work/jobQueue.js +253 -0
  536. package/dist/work/unitTraining.d.ts +58 -0
  537. package/dist/work/unitTraining.js +52 -0
  538. package/dist/world/authoredObjects.d.ts +58 -0
  539. package/dist/world/authoredObjects.js +69 -0
  540. package/dist/world/buildingGenerator.d.ts +18 -0
  541. package/dist/world/buildingGenerator.js +62 -0
  542. package/dist/world/buildings.d.ts +5 -0
  543. package/dist/world/buildings.js +5 -0
  544. package/dist/world/catenary.d.ts +22 -0
  545. package/dist/world/catenary.js +69 -0
  546. package/dist/world/environmentSummary.d.ts +11 -2
  547. package/dist/world/environmentSummary.js +11 -1
  548. package/dist/world/features.d.ts +244 -7
  549. package/dist/world/features.js +92 -4
  550. package/dist/world/footprintGrid.d.ts +59 -0
  551. package/dist/world/footprintGrid.js +141 -0
  552. package/dist/world/geometry.d.ts +64 -0
  553. package/dist/world/geometry.js +94 -0
  554. package/dist/world/grassKind.d.ts +51 -0
  555. package/dist/world/grassKind.js +101 -0
  556. package/dist/world/pathInstances.d.ts +27 -0
  557. package/dist/world/pathInstances.js +27 -0
  558. package/dist/world/pathTerrain.d.ts +80 -0
  559. package/dist/world/pathTerrain.js +142 -0
  560. package/dist/world/placeAsset.d.ts +81 -0
  561. package/dist/world/placeAsset.js +77 -0
  562. package/dist/world/placement.d.ts +4 -0
  563. package/dist/world/placement.js +4 -0
  564. package/dist/world/placementController.d.ts +6 -0
  565. package/dist/world/placementController.js +6 -0
  566. package/dist/world/polyline.d.ts +34 -0
  567. package/dist/world/polyline.js +81 -0
  568. package/dist/world/roads.d.ts +55 -0
  569. package/dist/world/roads.js +184 -0
  570. package/dist/world/scatterRegion.d.ts +164 -0
  571. package/dist/world/scatterRegion.js +409 -0
  572. package/dist/world/sceneShapes.d.ts +43 -0
  573. package/dist/world/sceneShapes.js +1 -0
  574. package/dist/world/segment.d.ts +27 -0
  575. package/dist/world/segment.js +43 -0
  576. package/dist/world/soilKind.d.ts +48 -0
  577. package/dist/world/soilKind.js +92 -0
  578. package/dist/world/spatialSample.d.ts +241 -0
  579. package/dist/world/spatialSample.js +465 -0
  580. package/dist/world/streets.d.ts +80 -0
  581. package/dist/world/streets.js +144 -0
  582. package/dist/world/terraform.d.ts +213 -1
  583. package/dist/world/terraform.js +655 -20
  584. package/dist/world/terrain.d.ts +138 -12
  585. package/dist/world/terrain.js +346 -28
  586. package/dist/world/terrainGuides.d.ts +182 -0
  587. package/dist/world/terrainGuides.js +343 -0
  588. package/dist/world/vec2.d.ts +81 -0
  589. package/dist/world/vec2.js +128 -0
  590. package/dist/world/vec3.d.ts +49 -0
  591. package/dist/world/vec3.js +76 -0
  592. package/dist/world/vegetation.d.ts +71 -0
  593. package/dist/world/vegetation.js +151 -0
  594. package/dist/world/visibilityField.d.ts +154 -0
  595. package/dist/world/visibilityField.js +271 -0
  596. package/dist/world/volumetricClouds.d.ts +52 -0
  597. package/dist/world/volumetricClouds.js +43 -0
  598. package/dist/world/walls.d.ts +9 -0
  599. package/dist/world/walls.js +9 -0
  600. package/dist/world/waterKind.d.ts +55 -0
  601. package/dist/world/waterKind.js +99 -0
  602. package/dist/world.d.ts +132 -0
  603. package/dist/world.js +132 -0
  604. package/package.json +32 -8
  605. package/skills/jgengine/SKILL.md +51 -0
  606. package/skills/jgengine/api.md +434 -0
  607. package/skills/jgengine/capabilities.md +29 -0
  608. package/skills/jgengine/reference-cartridge.md +72 -0
  609. package/skills/jgengine-combat/SKILL.md +34 -0
  610. package/skills/jgengine-combat/api.md +549 -0
  611. package/skills/jgengine-combat/capabilities.md +169 -0
  612. package/skills/jgengine-combat/reference.md +98 -0
  613. package/skills/jgengine-gameplay/SKILL.md +39 -0
  614. package/skills/jgengine-gameplay/api.md +1794 -0
  615. package/skills/jgengine-gameplay/capabilities.md +378 -0
  616. package/skills/jgengine-gameplay/reference-systems.md +60 -0
  617. package/skills/jgengine-world/SKILL.md +38 -0
  618. package/skills/jgengine-world/api.md +2652 -0
  619. package/skills/jgengine-world/capabilities.md +370 -0
  620. package/skills/jgengine-world/reference.md +222 -0
  621. package/dist/cartridge/runtime.d.ts +0 -15
  622. package/dist/cartridge/runtime.js +0 -556
  623. package/dist/cartridge/spec.d.ts +0 -188
  624. package/dist/cartridge/spec.js +0 -19
  625. package/dist/cartridge/validate.d.ts +0 -2
  626. package/dist/cartridge/validate.js +0 -78
  627. package/dist/store/engineStore.d.ts +0 -22
  628. package/dist/store/engineStore.js +0 -50
  629. package/dist/store/features.d.ts +0 -10
  630. package/dist/store/features.js +0 -23
  631. package/llms.txt +0 -4983
@@ -43,4 +43,5 @@ export type GameRuntime = {
43
43
  joinPlayer: (snapshot: GameRuntimeSnapshot, userId: string, isNew: boolean) => GameRuntimeSnapshot;
44
44
  toProfileRow: (snapshot: GameRuntimeSnapshot, userId: string) => RuntimeProfileRow | null;
45
45
  };
46
+ /** @internal */
46
47
  export declare function createGameRuntime(definition: GameRuntimeDefinition): GameRuntime;
@@ -1,5 +1,6 @@
1
1
  import { runCommand } from "./commandRunner.js";
2
2
  import { createEmptyPlayerRow, createRuntimeSnapshot, } from "./snapshot.js";
3
+ /** @internal */
3
4
  export function createGameRuntime(definition) {
4
5
  const loop = definition.loop;
5
6
  let initialized = false;
@@ -0,0 +1,60 @@
1
+ import type { GameDefinition, GameLoop } from "../game/defineGame.js";
2
+ import type { PointerAxisState } from "../input/pointerAxis.js";
3
+ import type { ModelAssetRef } from "../scene/assetCatalog.js";
4
+ import { type GameContext, type GameContextContent } from "./gameContext.js";
5
+ import type { InputSnapshot } from "./inputSnapshot.js";
6
+ /** One step's worth of player intent handed to {@link HeadlessRunner.step} — the held-action set and pointer state the shell would otherwise publish from the browser each frame. */
7
+ export interface HeadlessInput {
8
+ /** Replaces the held-action set for this step; edge detection (`justPressed`/`justReleased`) rolls the previous set forward. Omit to keep the last published set. */
9
+ held?: readonly string[];
10
+ /** Replaces the normalized pointer state; omit to leave the last pointer unchanged (pass `null` to clear it). */
11
+ pointer?: PointerAxisState | null;
12
+ }
13
+ export interface HeadlessRunnerOptions<TAssetRef extends ModelAssetRef, TMultiplayer> {
14
+ definition: GameDefinition<TAssetRef, TMultiplayer>;
15
+ /** Catalog resolvers (`entityById`/`objectById`) the context uses; defaults to an empty catalog. */
16
+ content?: GameContextContent;
17
+ /** Lifecycle hooks — `onInit`/`onNewPlayer` fire at construction, `onTick` on every {@link HeadlessRunner.step}. The shell keeps this separate from `definition` (presentation wraps it); a headless caller passes it directly. */
18
+ loop?: GameLoop<GameContext>;
19
+ /** The single local player; defaults to `{ userId: "player", isNew: true }`. */
20
+ player?: {
21
+ userId: string;
22
+ isNew: boolean;
23
+ };
24
+ /** Wall-clock source for the sim clock — inject a deterministic counter for reproducible runs. */
25
+ now?: () => number;
26
+ /** Per-step real-dt clamp in seconds, matching the shell's frame cap so one long stall can't fast-forward the sim. Default `0.05`. */
27
+ maxStepSeconds?: number;
28
+ /**
29
+ * Drive the built-in keyboard player-movement controller from the held-action set each step, exactly as the shell's
30
+ * FrameDriver does for pose-driven games. Off by default — cartridge/tick-driven games move their own entities inside
31
+ * `onTick` and don't need it.
32
+ */
33
+ playerMovement?: boolean;
34
+ /** Yaw heading (radians) fed to the movement controller when `playerMovement` is on; the shell supplies its camera yaw. */
35
+ heading?: number;
36
+ }
37
+ /**
38
+ * A renderer-free driver for a game loop: builds a {@link GameContext} from a {@link GameDefinition}, runs the init
39
+ * hooks, then advances the simulation one step at a time from injected input. No React, R3F, or three.js — the whole
40
+ * play path (time, input, `onTick`, behaviour nav, optional player movement) runs from `core` primitives alone, so a
41
+ * non-React host (a server tick, a test, a CLI replay) can play a real game and read its world snapshot. The shell's
42
+ * FrameDriver is one such driver bolted to `useFrame`; this is the same step distilled out of the render tree.
43
+ *
44
+ * @capability headless-runner play a real game loop with no renderer — tick, feed input, read the world snapshot
45
+ */
46
+ export interface HeadlessRunner {
47
+ /** The live game context — read `ctx.scene.entity.list()`, `ctx.game.store`, `ctx.subscribe`/`ctx.version()` for the world snapshot. */
48
+ readonly ctx: GameContext;
49
+ /** The per-frame input the loop reads; the same object exposed as `ctx.input`. */
50
+ readonly input: InputSnapshot;
51
+ readonly userId: string;
52
+ /**
53
+ * Advance the simulation one step. Publishes `input` (if given), advances the sim clock by the clamped real dt,
54
+ * runs optional player movement, then `loop.onTick` and behaviour nav. Returns the scaled game dt `onTick` saw.
55
+ */
56
+ step(dtSeconds: number, input?: HeadlessInput): number;
57
+ /** Publish input without advancing — for pre-seeding the held set before the first {@link step}. */
58
+ publishInput(input: HeadlessInput): void;
59
+ }
60
+ export declare function createHeadlessRunner<TAssetRef extends ModelAssetRef, TMultiplayer>(options: HeadlessRunnerOptions<TAssetRef, TMultiplayer>): HeadlessRunner;
@@ -0,0 +1,44 @@
1
+ import { resolvePlayerMovementTuning, stepPlayerMovement, } from "../movement/playerMovement.js";
2
+ import { advanceBehaviors } from "../scene/behaviorRuntime.js";
3
+ import { createGameContext } from "./gameContext.js";
4
+ export function createHeadlessRunner(options) {
5
+ const { definition, loop } = options;
6
+ const content = options.content ?? {};
7
+ const player = options.player ?? { userId: "player", isNew: true };
8
+ const maxStep = options.maxStepSeconds ?? 0.05;
9
+ const ctx = createGameContext({
10
+ definition,
11
+ content,
12
+ player,
13
+ ...(options.now === undefined ? {} : { now: options.now }),
14
+ });
15
+ loop?.onInit?.(ctx);
16
+ loop?.onNewPlayer?.(ctx);
17
+ const tuning = options.playerMovement === true
18
+ ? resolvePlayerMovementTuning({ physics: definition.physics, world: definition.world })
19
+ : null;
20
+ function publishInput(input) {
21
+ if (input.held !== undefined)
22
+ ctx.input.publish(input.held);
23
+ if (input.pointer !== undefined)
24
+ ctx.input.publishPointer(input.pointer);
25
+ }
26
+ return {
27
+ ctx,
28
+ input: ctx.input,
29
+ userId: player.userId,
30
+ publishInput,
31
+ step(dtSeconds, input) {
32
+ if (input !== undefined)
33
+ publishInput(input);
34
+ const dt = Math.min(dtSeconds, maxStep);
35
+ const gameDt = ctx.time.advance(dt);
36
+ if (tuning !== null) {
37
+ stepPlayerMovement(ctx, player.userId, { held: ctx.input.held(), pointer: ctx.input.pointer() }, dt, tuning, options.heading);
38
+ }
39
+ loop?.onTick?.(ctx, gameDt);
40
+ advanceBehaviors(ctx, gameDt);
41
+ return gameDt;
42
+ },
43
+ };
44
+ }
@@ -58,11 +58,13 @@ export type LeaderboardEntry = {
58
58
  value: number;
59
59
  };
60
60
  export declare const LEADERBOARD_PENDING_KEY = "leaderboardPending";
61
+ /** @internal */
61
62
  export declare function drainPendingLeaderboardIncrements(session: Record<string, unknown>): {
62
63
  increments: LeaderboardIncrement[];
63
64
  session: Record<string, unknown>;
64
65
  };
65
66
  export declare const LEADERBOARD_TOP_LIMIT = 100;
67
+ /** @internal */
66
68
  export declare function clampLimit(value: number | undefined, fallback: number, max: number): number;
67
69
  export type LeaderboardRow = {
68
70
  gameId: string;
@@ -73,8 +75,11 @@ export type LeaderboardRow = {
73
75
  value: number;
74
76
  updatedAt: number;
75
77
  };
78
+ /** @internal */
76
79
  export declare function leaderboardRowKey(row: Omit<LeaderboardRow, "value" | "updatedAt">): string;
80
+ /** @internal */
77
81
  export declare function applyLeaderboardRows(rows: Map<string, LeaderboardRow>, gameId: string, entries: LeaderboardIncrement[], now: number): void;
82
+ /** @internal */
78
83
  export declare function topLeaderboardRows(rows: Iterable<LeaderboardRow>, args: {
79
84
  gameId: string;
80
85
  stat: string;
@@ -82,9 +87,12 @@ export declare function topLeaderboardRows(rows: Iterable<LeaderboardRow>, args:
82
87
  serverId?: string;
83
88
  limit?: number;
84
89
  }): LeaderboardEntry[];
90
+ /** @internal */
85
91
  export declare function profileLeaderboardStats(rows: Iterable<LeaderboardRow>, gameId: string, userId: string): Record<string, number>;
86
92
  export declare const FEED_RING_LIMIT = 20;
93
+ /** @internal */
87
94
  export declare function trimFeedEntries<T>(entries: T[], limit?: number): T[];
95
+ /** @internal */
88
96
  export declare function shouldAutoSave(save: SaveConfig, dirtyAt: number | undefined, lastSavedAt: number | undefined, now: number): boolean;
89
97
  export type ServerListing = {
90
98
  serverId: string;
@@ -101,9 +109,11 @@ export type ServerListing = {
101
109
  export type ToServerListingOptions = {
102
110
  includeJoinCode?: boolean;
103
111
  };
112
+ /** @internal */
104
113
  export declare function toServerListing(record: GameServerRecord, options?: ToServerListingOptions): ServerListing;
105
114
  export declare const OPEN_SERVER_LISTING_LIMIT = 20;
106
115
  export declare const OPEN_SERVER_LISTING_MAX = 100;
116
+ /** @internal */
107
117
  export declare function toOpenServerListings(listings: Iterable<ServerListing>, limit?: number): ServerListing[];
108
118
  export type HostPersistence = {
109
119
  savePlan?: (plan: ServerPersistPlan) => Promise<void>;
@@ -141,6 +151,7 @@ export type HostPersistence = {
141
151
  userId: string;
142
152
  }) => Promise<Record<string, number>>;
143
153
  };
154
+ /** @internal */
144
155
  export declare function buildHydratePlayers(server: GameServerRecord, profiles: Record<string, PlayerProfileRecord | null>): Record<string, RuntimePlayerRow>;
145
156
  export type ServerPersistPlan = {
146
157
  server: GameServerRecord;
@@ -149,4 +160,5 @@ export type ServerPersistPlan = {
149
160
  deletedChunks: string[];
150
161
  leaderboard: LeaderboardIncrement[];
151
162
  };
163
+ /** @internal */
152
164
  export declare function planServerPersist(server: GameServerRecord, snapshot: GameRuntimeSnapshot, save: SaveConfig, now: number): ServerPersistPlan;
@@ -11,6 +11,7 @@ function isLeaderboardIncrement(value) {
11
11
  typeof candidate.by === "number" &&
12
12
  (candidate.serverId === undefined || typeof candidate.serverId === "string"));
13
13
  }
14
+ /** @internal */
14
15
  export function drainPendingLeaderboardIncrements(session) {
15
16
  const raw = session[LEADERBOARD_PENDING_KEY];
16
17
  if (!Array.isArray(raw) || raw.length === 0) {
@@ -21,15 +22,18 @@ export function drainPendingLeaderboardIncrements(session) {
21
22
  return { increments: raw.filter(isLeaderboardIncrement), session: rest };
22
23
  }
23
24
  export const LEADERBOARD_TOP_LIMIT = 100;
25
+ /** @internal */
24
26
  export function clampLimit(value, fallback, max) {
25
27
  const candidate = value ?? fallback;
26
28
  if (!Number.isFinite(candidate))
27
29
  return fallback;
28
30
  return Math.min(Math.max(Math.floor(candidate), 1), max);
29
31
  }
32
+ /** @internal */
30
33
  export function leaderboardRowKey(row) {
31
34
  return [row.gameId, row.scope, row.stat, row.serverId ?? "", row.userId].join("|");
32
35
  }
36
+ /** @internal */
33
37
  export function applyLeaderboardRows(rows, gameId, entries, now) {
34
38
  for (const entry of entries) {
35
39
  const key = leaderboardRowKey({ ...entry, gameId });
@@ -50,6 +54,7 @@ export function applyLeaderboardRows(rows, gameId, entries, now) {
50
54
  }
51
55
  }
52
56
  }
57
+ /** @internal */
53
58
  export function topLeaderboardRows(rows, args) {
54
59
  const limit = clampLimit(args.limit, LEADERBOARD_TOP_LIMIT, LEADERBOARD_TOP_LIMIT);
55
60
  return [...rows]
@@ -61,6 +66,7 @@ export function topLeaderboardRows(rows, args) {
61
66
  .slice(0, limit)
62
67
  .map((row) => ({ userId: row.userId, value: row.value }));
63
68
  }
69
+ /** @internal */
64
70
  export function profileLeaderboardStats(rows, gameId, userId) {
65
71
  const profile = {};
66
72
  for (const row of rows) {
@@ -71,11 +77,13 @@ export function profileLeaderboardStats(rows, gameId, userId) {
71
77
  return profile;
72
78
  }
73
79
  export const FEED_RING_LIMIT = 20;
80
+ /** @internal */
74
81
  export function trimFeedEntries(entries, limit = FEED_RING_LIMIT) {
75
82
  if (entries.length <= limit)
76
83
  return entries;
77
84
  return entries.slice(entries.length - limit);
78
85
  }
86
+ /** @internal */
79
87
  export function shouldAutoSave(save, dirtyAt, lastSavedAt, now) {
80
88
  if (!isSaveEnabled(save))
81
89
  return false;
@@ -85,6 +93,7 @@ export function shouldAutoSave(save, dirtyAt, lastSavedAt, now) {
85
93
  const anchor = lastSavedAt ?? 0;
86
94
  return now - anchor >= intervalMs;
87
95
  }
96
+ /** @internal */
88
97
  export function toServerListing(record, options = {}) {
89
98
  return {
90
99
  serverId: record.serverId,
@@ -103,12 +112,14 @@ export function toServerListing(record, options = {}) {
103
112
  }
104
113
  export const OPEN_SERVER_LISTING_LIMIT = 20;
105
114
  export const OPEN_SERVER_LISTING_MAX = 100;
115
+ /** @internal */
106
116
  export function toOpenServerListings(listings, limit = OPEN_SERVER_LISTING_LIMIT) {
107
117
  return [...listings]
108
118
  .filter((listing) => listing.status === "running")
109
119
  .sort((a, b) => b.updatedAt - a.updatedAt)
110
120
  .slice(0, clampLimit(limit, OPEN_SERVER_LISTING_LIMIT, OPEN_SERVER_LISTING_MAX));
111
121
  }
122
+ /** @internal */
112
123
  export function buildHydratePlayers(server, profiles) {
113
124
  const players = {};
114
125
  for (const userId of server.memberUserIds) {
@@ -129,6 +140,7 @@ export function buildHydratePlayers(server, profiles) {
129
140
  }
130
141
  return players;
131
142
  }
143
+ /** @internal */
132
144
  export function planServerPersist(server, snapshot, save, now) {
133
145
  const drained = drainPendingLeaderboardIncrements(snapshot.server.session);
134
146
  const serverState = drained.increments.length > 0 ? { ...snapshot.server, session: drained.session } : snapshot.server;
@@ -0,0 +1,54 @@
1
+ import type { CommandResult } from "../commands/commandRegistry.js";
2
+ import type { GameDefinition, LoopPlayer } from "../game/defineGame.js";
3
+ import type { ModelAssetRef } from "../scene/assetCatalog.js";
4
+ import { type GameContext, type GameContextContent } from "./gameContext.js";
5
+ import { type InputFrame } from "./inputSnapshot.js";
6
+ import { type WorldDiff } from "./worldReplication.js";
7
+ import type { SnapshotViewer, WorldSnapshot } from "./worldSnapshot.js";
8
+ export type { InputFrame };
9
+ /** Reserved command name the authoritative host intercepts on the existing `runCommand` transport to route a client's {@link InputFrame} to `session.input`, so per-tick input needs no separate wire. */
10
+ export declare const INPUT_COMMAND = "engine.input";
11
+ /** Config for {@link createHostedGameRunner}: the game definition, its content lookup, and an optional host identity. */
12
+ export interface HostedGameRunnerOptions<TAssetRef extends ModelAssetRef, TMultiplayer> {
13
+ definition: GameDefinition<TAssetRef, TMultiplayer>;
14
+ content: GameContextContent;
15
+ /** The world's own authoritative identity (`ctx.player` server-side); real players join as members. */
16
+ host?: LoopPlayer;
17
+ now?: () => number;
18
+ /**
19
+ * Rehydrate a persisted world instead of booting a fresh one — for stateless hosts (Convex) that reconstruct
20
+ * the runner each invocation. `onInit` still runs (so commands and systems it registers exist), then this
21
+ * snapshot overlays the world state it seeded. Omit for a long-lived stateful host (ws) that keeps one runner.
22
+ */
23
+ restore?: WorldSnapshot;
24
+ }
25
+ /**
26
+ * The GameContext-loop equivalent of the pure-reducer `createGameHost`: one authoritative `createGameContext`
27
+ * per world, driven server-side. `onInit` runs once at construction; `onNewPlayer`/`onPlayerLeave` fire per
28
+ * join/leave; `tick` advances `onTick` then commits a revision. Clients pull a full {@link WorldSnapshot}
29
+ * baseline once, then per-tick {@link WorldDiff}s from their last revision. Games ship only normal GameContext
30
+ * code — the runner adds no per-game surface.
31
+ */
32
+ export interface HostedGameRunner {
33
+ join(userId: string, isNew: boolean): void;
34
+ /** Re-attach an already-joined member on a reconstructed runner — restores membership and `ctx.game.players` without re-firing `onNewPlayer`. Stateless hosts call it once per persisted member after `restore`. */
35
+ resume(userId: string): void;
36
+ leave(userId: string): void;
37
+ /** Record a client's latest input frame — stashed for {@link heldInput} and mirrored onto `ctx.game.players` so the movement seam reads each player's intent in `onTick`. */
38
+ input(userId: string, frame: InputFrame): void;
39
+ heldInput(userId: string): InputFrame | null;
40
+ command(userId: string, name: string, input: unknown): CommandResult<GameContext>;
41
+ tick(dt: number): number;
42
+ diff(sinceRevision: number): WorldDiff;
43
+ revision(): number;
44
+ /** The full world baseline — projected to only what `viewer` may see when the context carries a replication policy, else the whole world. */
45
+ snapshot(viewer?: SnapshotViewer): WorldSnapshot;
46
+ /** True when {@link snapshot} is viewer-dependent (a replication policy projects private/AOI state); a host must then serve each viewer its own frame. */
47
+ projectsViewers(): boolean;
48
+ members(): readonly string[];
49
+ context(): GameContext;
50
+ }
51
+ /** Build a {@link HostedGameRunner} — one authoritative GameContext world driven server-side from the game's own loop.
52
+ * @internal
53
+ */
54
+ export declare function createHostedGameRunner<TAssetRef extends ModelAssetRef, TMultiplayer>(options: HostedGameRunnerOptions<TAssetRef, TMultiplayer>): HostedGameRunner;
@@ -0,0 +1,85 @@
1
+ import { syncLifecyclePhase } from "../game/gamePhase.js";
2
+ import { advanceBehaviors } from "../scene/behaviorRuntime.js";
3
+ import { createGameContext } from "./gameContext.js";
4
+ import {} from "./inputSnapshot.js";
5
+ import { createWorldReplicator } from "./worldReplication.js";
6
+ /** Reserved command name the authoritative host intercepts on the existing `runCommand` transport to route a client's {@link InputFrame} to `session.input`, so per-tick input needs no separate wire. */
7
+ export const INPUT_COMMAND = "engine.input";
8
+ /** Build a {@link HostedGameRunner} — one authoritative GameContext world driven server-side from the game's own loop.
9
+ * @internal
10
+ */
11
+ export function createHostedGameRunner(options) {
12
+ const { definition, content, host, now, restore } = options;
13
+ const ctx = createGameContext({
14
+ definition,
15
+ content,
16
+ player: host ?? { userId: "host", isNew: true },
17
+ ...(now === undefined ? {} : { now }),
18
+ ...(definition.replication === undefined ? {} : { replication: definition.replication }),
19
+ });
20
+ const loop = definition.loop ?? {};
21
+ const replicator = createWorldReplicator(() => ctx.snapshot(), {
22
+ worldVersion: () => ctx.replicationVersion(),
23
+ });
24
+ const members = new Map();
25
+ const inputs = new Map();
26
+ const inputSeq = new Map();
27
+ loop.onInit?.(ctx);
28
+ syncLifecyclePhase(ctx, definition.lifecycle);
29
+ if (restore !== undefined)
30
+ ctx.hydrate(restore);
31
+ return {
32
+ join(userId, isNew) {
33
+ if (members.has(userId))
34
+ return;
35
+ const player = { userId, isNew };
36
+ members.set(userId, player);
37
+ ctx.game.players?.join(userId, isNew);
38
+ loop.onNewPlayer?.(ctx, player);
39
+ syncLifecyclePhase(ctx, definition.lifecycle);
40
+ },
41
+ resume(userId) {
42
+ members.set(userId, { userId, isNew: false });
43
+ ctx.game.players?.join(userId, false);
44
+ },
45
+ leave(userId) {
46
+ const player = members.get(userId);
47
+ if (player === undefined)
48
+ return;
49
+ members.delete(userId);
50
+ inputs.delete(userId);
51
+ inputSeq.delete(userId);
52
+ loop.onPlayerLeave?.(ctx, player);
53
+ ctx.game.players?.leave(userId);
54
+ },
55
+ input(userId, frame) {
56
+ const seq = frame.seq;
57
+ if (seq !== undefined) {
58
+ const lastSeq = inputSeq.get(userId);
59
+ if (lastSeq !== undefined && seq <= lastSeq)
60
+ return;
61
+ inputSeq.set(userId, seq);
62
+ }
63
+ inputs.set(userId, frame);
64
+ ctx.game.players?.setInput(userId, frame);
65
+ },
66
+ heldInput(userId) {
67
+ return inputs.get(userId) ?? null;
68
+ },
69
+ command(userId, name, input) {
70
+ return ctx.game.commands.runAs(userId, name, input);
71
+ },
72
+ tick(dt) {
73
+ loop.onTick?.(ctx, dt);
74
+ advanceBehaviors(ctx, dt);
75
+ syncLifecyclePhase(ctx, definition.lifecycle);
76
+ return replicator.commit();
77
+ },
78
+ diff: (sinceRevision) => replicator.diff(sinceRevision),
79
+ revision: () => replicator.revision(),
80
+ snapshot: (viewer) => ctx.snapshot(viewer),
81
+ projectsViewers: () => ctx.replicatesPerViewer(),
82
+ members: () => Array.from(members.keys()),
83
+ context: () => ctx,
84
+ };
85
+ }
@@ -0,0 +1,73 @@
1
+ import type { CommandResult } from "../commands/commandRegistry.js";
2
+ import type { ModelAssetRef } from "../scene/assetCatalog.js";
3
+ import type { GameContext, GameContextContent } from "./gameContext.js";
4
+ import type { GameDefinition, LoopPlayer } from "../game/defineGame.js";
5
+ import { type HostedGameRunner, type InputFrame } from "./hostedGameRunner.js";
6
+ import type { WorldDiff } from "./worldReplication.js";
7
+ import type { SnapshotViewer, WorldSnapshot } from "./worldSnapshot.js";
8
+ /** One hosted world's persisted authoritative state — the unit a {@link HostedWorldStore} loads and saves. */
9
+ export interface HostedWorldRecord {
10
+ snapshot: WorldSnapshot;
11
+ revision: number;
12
+ }
13
+ /**
14
+ * Narrow persistence seam for a hosted world — the {@link HostedWorldRecord} counterpart of `HostPersistence`.
15
+ * Backends implement it (memory/file/sql/convex); the session never names one. A stateful host loads once and
16
+ * saves on a cadence; a stateless host reconstructs from `load()` each invocation.
17
+ */
18
+ export interface HostedWorldStore {
19
+ load(): HostedWorldRecord | null;
20
+ save(record: HostedWorldRecord): void;
21
+ }
22
+ /** In-process {@link HostedWorldStore} for tests, local play, and the browser-tab P2P host.
23
+ * @internal
24
+ */
25
+ export declare function memoryWorldStore(seed?: HostedWorldRecord): HostedWorldStore;
26
+ /** A client replication pull: a full baseline (first sync / fell behind) or a diff since the client's cursor. */
27
+ export type HostedWorldSync = {
28
+ kind: "baseline";
29
+ revision: number;
30
+ snapshot: WorldSnapshot;
31
+ } | {
32
+ kind: "diff";
33
+ diff: WorldDiff;
34
+ };
35
+ /** Config for {@link createHostedWorldSession}: the game, its persistence store, and the auto-save cadence. */
36
+ export interface HostedWorldSessionOptions<TAssetRef extends ModelAssetRef, TMultiplayer> {
37
+ definition: GameDefinition<TAssetRef, TMultiplayer>;
38
+ content: GameContextContent;
39
+ host?: LoopPlayer;
40
+ now?: () => number;
41
+ /** Where the authoritative snapshot persists; defaults to {@link memoryWorldStore}. */
42
+ store?: HostedWorldStore;
43
+ /** Minimum elapsed ms between auto-saves on tick, measured against `now` (defaults to `Date.now` when omitted). Default `0` — persist on every revision-changing tick. */
44
+ saveIntervalMs?: number;
45
+ }
46
+ /**
47
+ * The stateful host substrate a long-lived backend binds (ws server, browser P2P host): a live
48
+ * {@link HostedGameRunner} loaded from a {@link HostedWorldStore}, auto-persisted on tick, serving each client a
49
+ * baseline then diffs. The stateless Convex path doesn't use this — it reconstructs a runner from the same store
50
+ * per invocation and diffs with `diffSnapshots`. Either way the store seam and the game code are identical.
51
+ */
52
+ export interface HostedWorldSession {
53
+ join(userId: string, isNew: boolean): void;
54
+ leave(userId: string): void;
55
+ input(userId: string, frame: InputFrame): void;
56
+ command(userId: string, name: string, input: unknown): CommandResult<GameContext>;
57
+ tick(dt: number): number;
58
+ /** Replication pull: `null`/`0` cursor → full baseline; a prior revision → a diff since it. */
59
+ sync(sinceRevision: number | null): HostedWorldSync;
60
+ /** The full world baseline projected for one viewer (private/AOI). Identity when no replication policy is set. */
61
+ snapshotFor(viewer: SnapshotViewer): WorldSnapshot;
62
+ /** True when {@link snapshotFor} is viewer-dependent — a host must serve each connection its own projected frame instead of a shared diff. */
63
+ projectsViewers(): boolean;
64
+ revision(): number;
65
+ members(): readonly string[];
66
+ /** Force-persist the current world to the store. */
67
+ save(): void;
68
+ runner(): HostedGameRunner;
69
+ }
70
+ /** Build a {@link HostedWorldSession} — a live runner loaded from a {@link HostedWorldStore} and auto-persisted on tick.
71
+ * @internal
72
+ */
73
+ export declare function createHostedWorldSession<TAssetRef extends ModelAssetRef, TMultiplayer>(options: HostedWorldSessionOptions<TAssetRef, TMultiplayer>): HostedWorldSession;
@@ -0,0 +1,64 @@
1
+ import { createHostedGameRunner } from "./hostedGameRunner.js";
2
+ /** In-process {@link HostedWorldStore} for tests, local play, and the browser-tab P2P host.
3
+ * @internal
4
+ */
5
+ export function memoryWorldStore(seed) {
6
+ let record = seed ?? null;
7
+ return {
8
+ load: () => record,
9
+ save(next) {
10
+ record = { snapshot: next.snapshot, revision: next.revision };
11
+ },
12
+ };
13
+ }
14
+ /** Build a {@link HostedWorldSession} — a live runner loaded from a {@link HostedWorldStore} and auto-persisted on tick.
15
+ * @internal
16
+ */
17
+ export function createHostedWorldSession(options) {
18
+ const { definition, content, host, now, saveIntervalMs = 0 } = options;
19
+ const clock = now ?? Date.now;
20
+ const store = options.store ?? memoryWorldStore();
21
+ const loaded = store.load();
22
+ const runner = createHostedGameRunner({
23
+ definition,
24
+ content,
25
+ ...(host === undefined ? {} : { host }),
26
+ ...(now === undefined ? {} : { now }),
27
+ ...(loaded === null ? {} : { restore: loaded.snapshot }),
28
+ });
29
+ let savedRevision = loaded?.revision ?? 0;
30
+ let lastSaveAt = clock();
31
+ function persist() {
32
+ savedRevision = runner.revision();
33
+ store.save({ snapshot: runner.snapshot(), revision: savedRevision });
34
+ }
35
+ return {
36
+ join: (userId, isNew) => runner.join(userId, isNew),
37
+ leave: (userId) => runner.leave(userId),
38
+ input: (userId, frame) => runner.input(userId, frame),
39
+ command: (userId, name, input) => runner.command(userId, name, input),
40
+ tick(dt) {
41
+ const revision = runner.tick(dt);
42
+ if (revision !== savedRevision) {
43
+ const at = clock();
44
+ if (saveIntervalMs <= 0 || at - lastSaveAt >= saveIntervalMs) {
45
+ lastSaveAt = at;
46
+ persist();
47
+ }
48
+ }
49
+ return revision;
50
+ },
51
+ sync(sinceRevision) {
52
+ if (sinceRevision === null || sinceRevision <= 0) {
53
+ return { kind: "baseline", revision: runner.revision(), snapshot: runner.snapshot() };
54
+ }
55
+ return { kind: "diff", diff: runner.diff(sinceRevision) };
56
+ },
57
+ snapshotFor: (viewer) => runner.snapshot(viewer),
58
+ projectsViewers: () => runner.projectsViewers(),
59
+ revision: () => runner.revision(),
60
+ members: () => runner.members(),
61
+ save: persist,
62
+ runner: () => runner,
63
+ };
64
+ }
@@ -1,12 +1,30 @@
1
1
  import type { PointerAxisState } from "../input/pointerAxis.js";
2
+ import { type AxisBinding, type AxisRange } from "../input/axisInput.js";
3
+ /** One client's input for a tick — the semantic held-action set plus pointer state, the serializable, over-the-wire counterpart of {@link InputSnapshot} the host stores per connected player. */
4
+ export interface InputFrame {
5
+ held: readonly string[];
6
+ pointer: PointerAxisState | null;
7
+ }
2
8
  export interface InputSnapshot {
3
- /** Replaces the held-action set for this frame. Called by the shell before `onTick` each frame; does not bump `ctx.version()` or notify `ctx.subscribe` listeners — per-frame publishes would storm subscribers. */
9
+ /** Replaces the held-action set for this frame, rolling the previous held set forward for edge detection (#671). Called by the shell before `onTick` each frame; does not bump `ctx.version()` or notify `ctx.subscribe` listeners — per-frame publishes would storm subscribers. */
4
10
  publish(held: readonly string[]): void;
5
11
  /** Replaces the normalized pointer-position state for this frame (#293). Same no-notify contract as `publish`. */
6
12
  publishPointer(state: PointerAxisState | null): void;
7
13
  isDown(action: string): boolean;
14
+ /** The held-action set for this frame — an owned, frozen array; the array {@link publish} was called with is never aliased or returned. */
8
15
  held(): readonly string[];
9
- /** Pointer position over the play surface, `[-1, 1]` per axis with `+y` down, published by the shell each frame; `null` until the first pointer move. */
10
- pointer(): PointerAxisState | null;
16
+ /** True only on the frame `action` transitions from up to down (#671) — derived from the last two published held sets, so it stays replay-safe. */
17
+ justPressed(action: string): boolean;
18
+ /** True only on the frame `action` transitions from down to up (#671); mirrors {@link justPressed}. */
19
+ justReleased(action: string): boolean;
20
+ /** Pointer position over the play surface, `[-1, 1]` per axis with `+y` down, published by the shell each frame; `null` until the first pointer move. Frozen — an owned copy of what {@link publishPointer} was called with. */
21
+ pointer(): Readonly<PointerAxisState> | null;
22
+ /**
23
+ * Instantaneous analog axis sample against the held-action set and current pointer (#533.7) — bind
24
+ * throttle/steer/handbrake (or any axes) to *action names*, not raw key codes, since the held set is
25
+ * semantic actions. Feed the result into an `AxisChannel` for smoothing; unlisted ranges default to
26
+ * bipolar `[-1, 1]`, so pass `{ min: 0, max: 1 }` for one-directional pedals.
27
+ */
28
+ axis<TAxes extends string>(bindings: Record<TAxes, AxisBinding>, ranges?: Partial<Record<TAxes, AxisRange>>): Record<TAxes, number>;
11
29
  }
12
30
  export declare function createInputSnapshot(): InputSnapshot;
@@ -1,17 +1,23 @@
1
+ import { sampleAxisBindings } from "../input/axisInput.js";
1
2
  export function createInputSnapshot() {
2
3
  let heldSet = new Set();
4
+ let previousHeldSet = new Set();
3
5
  let heldList = [];
4
6
  let pointerState = null;
5
7
  return {
6
8
  publish(held) {
7
- heldList = held;
9
+ previousHeldSet = heldSet;
10
+ heldList = Object.freeze([...held]);
8
11
  heldSet = new Set(held);
9
12
  },
10
13
  publishPointer(state) {
11
- pointerState = state;
14
+ pointerState = state === null ? null : Object.freeze({ ...state });
12
15
  },
13
16
  isDown: (action) => heldSet.has(action),
14
17
  held: () => heldList,
15
18
  pointer: () => pointerState,
19
+ axis: (bindings, ranges) => sampleAxisBindings(bindings, (action) => heldSet.has(action), pointerState, ranges),
20
+ justPressed: (action) => heldSet.has(action) && !previousHeldSet.has(action),
21
+ justReleased: (action) => !heldSet.has(action) && previousHeldSet.has(action),
16
22
  };
17
23
  }
@@ -21,6 +21,10 @@ export interface MotionIntents {
21
21
  setVerticalVelocity(velocityY: number): void;
22
22
  setY(y: number): void;
23
23
  takePending(): MotionIntentBatch | null;
24
+ /** Non-draining copy of the pending intents for a whole-world save; unlike `takePending` it leaves the queue intact. */
25
+ snapshot(): MotionIntentBatch;
26
+ /** Replace the pending intents from a {@link snapshot} payload on save load. */
27
+ hydrate(batch: MotionIntentBatch): void;
24
28
  }
25
29
  export interface MotionIntentBatch {
26
30
  impulses: readonly number[];
@@ -28,6 +32,13 @@ export interface MotionIntentBatch {
28
32
  verticalVelocity: number | null;
29
33
  y: number | null;
30
34
  }
35
+ /** @internal */
31
36
  export declare function createMotionIntents(): MotionIntents;
32
- /** Fold a batch's horizontal pushes into a controller's velocity pair — shared by the walk and voxel drivers. */
37
+ /** Fold a batch's vertical impulses into a controller's velocity, then apply an outright `setVerticalVelocity` override — the vertical counterpart of {@link applyHorizontalImpulses}.
38
+ * @internal
39
+ */
40
+ export declare function applyMotionImpulses(currentVelocity: number, batch: MotionIntentBatch | null): number;
41
+ /** Fold a batch's horizontal pushes into a controller's velocity pair — shared by the walk and voxel drivers.
42
+ * @internal
43
+ */
33
44
  export declare function applyHorizontalImpulses(velocityX: number, velocityZ: number, batch: MotionIntentBatch | null): readonly [number, number];