@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
@@ -1,3 +1,4 @@
1
+ /** @internal */
1
2
  export function idleWindow(lastSeenMs, nowMs, config = {}) {
2
3
  const elapsedSeconds = Math.max(0, (nowMs - lastSeenMs) / 1000);
3
4
  const capped = config.maxSeconds !== undefined && elapsedSeconds > config.maxSeconds;
@@ -9,17 +10,20 @@ export function idleWindow(lastSeenMs, nowMs, config = {}) {
9
10
  capped,
10
11
  };
11
12
  }
13
+ /** @internal */
12
14
  export function linearCatchUp(seconds, input) {
13
15
  const clampedSeconds = Math.max(0, seconds);
14
16
  const value = input.current + input.ratePerSecond * clampedSeconds;
15
17
  return Math.min(input.max ?? Number.POSITIVE_INFINITY, Math.max(input.min ?? Number.NEGATIVE_INFINITY, value));
16
18
  }
19
+ /** @internal */
17
20
  export function exponentialCatchUp(seconds, input) {
18
21
  const clampedSeconds = Math.max(0, seconds);
19
22
  const factor = Math.max(0, input.factorPerSecond);
20
23
  const value = input.current * factor ** clampedSeconds;
21
24
  return Math.min(input.max ?? Number.POSITIVE_INFINITY, Math.max(input.min ?? Number.NEGATIVE_INFINITY, value));
22
25
  }
26
+ /** @internal */
23
27
  export function steppedCatchUp(seconds, stepSeconds, step, maxSteps) {
24
28
  if (stepSeconds <= 0 || seconds <= 0) {
25
29
  return { steps: 0, remainderSeconds: Math.max(0, seconds) };
@@ -51,6 +51,8 @@ export interface SimClock {
51
51
  advance(realDt: number): number;
52
52
  now(): number;
53
53
  snapshot(): ClockSnapshot;
54
+ /** Restore clock position — game-time, pause state, and speed multipliers — from a {@link ClockSnapshot} for whole-world save/load. Live timers registered via `after`/`every`/`at` are unaffected. */
55
+ hydrate(snapshot: ClockSnapshot): void;
54
56
  calendar(): CalendarTime;
55
57
  isPaused(): boolean;
56
58
  speed(): number;
@@ -1,5 +1,11 @@
1
1
  import { SECONDS_PER_GAME_DAY } from "./gameClock.js";
2
- const MAX_TIMER_FIRES = 10_000;
2
+ const MAX_TIMER_FIRES_PER_ADVANCE = 10_000;
3
+ function requireFiniteTimerValue(label, value) {
4
+ if (!Number.isFinite(value)) {
5
+ throw new Error(`SimClock ${label} must be finite, got ${value}`);
6
+ }
7
+ return value;
8
+ }
3
9
  export function createSimClock(options = {}) {
4
10
  const config = options.config ?? {};
5
11
  const onChange = options.onChange ?? (() => { });
@@ -62,7 +68,7 @@ export function createSimClock(options = {}) {
62
68
  }
63
69
  timer.callback();
64
70
  fires += 1;
65
- if (fires >= MAX_TIMER_FIRES)
71
+ if (fires >= MAX_TIMER_FIRES_PER_ADVANCE)
66
72
  return;
67
73
  }
68
74
  }
@@ -121,10 +127,19 @@ export function createSimClock(options = {}) {
121
127
  timers.delete(id);
122
128
  };
123
129
  }
130
+ function hydrate(state) {
131
+ now = state.now;
132
+ paused = state.paused;
133
+ playSpeed = state.playSpeed;
134
+ timescale = state.timescale;
135
+ displayMinute = minuteIndex(now, dayLength);
136
+ onChange();
137
+ }
124
138
  return {
125
139
  advance,
126
140
  now: () => now,
127
141
  calendar,
142
+ hydrate,
128
143
  snapshot: () => ({
129
144
  now,
130
145
  paused,
@@ -144,12 +159,12 @@ export function createSimClock(options = {}) {
144
159
  cycleSpeed,
145
160
  timescale: () => timescale,
146
161
  setTimescale,
147
- after: (seconds, callback) => register(now + Math.max(0, seconds), null, callback),
162
+ after: (seconds, callback) => register(now + Math.max(0, requireFiniteTimerValue("after(seconds)", seconds)), null, callback),
148
163
  every: (seconds, callback) => {
149
- const interval = Math.max(Number.EPSILON, seconds);
164
+ const interval = Math.max(Number.EPSILON, requireFiniteTimerValue("every(seconds)", seconds));
150
165
  return register(now + interval, interval, callback);
151
166
  },
152
- at: (time, callback) => register(time, null, callback),
167
+ at: (time, callback) => register(requireFiniteTimerValue("at(time)", time), null, callback),
153
168
  };
154
169
  }
155
170
  function minuteIndex(seconds, dayLength) {
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Headless view model for a contextual action collection — the data layer behind an RTS command
3
+ * card, an ability action bar, a build menu, or a radial. It carries *what the buttons mean*
4
+ * (label, hotkey, cost, cooldown, disabled reasons, toggle state) with zero rendering opinion, so a
5
+ * game keeps layout, dimensions, hotkeys, catalog-id mapping, renderer, and chrome caller-owned. The
6
+ * React renderers in `@jgengine/react/actionHud` consume this; a game can swap either without
7
+ * forking the logic here.
8
+ */
9
+ /** A spendable-resource line on an action (e.g. `40` mana). `met` is false only when `available` is known and short. */
10
+ export interface ActionCost {
11
+ resourceId: string;
12
+ amount: number;
13
+ /** Current pool, when the caller knows it — drives {@link ActionCost.met}. Omit when unknown. */
14
+ available?: number;
15
+ /** True unless `available` is known and below `amount`. */
16
+ met: boolean;
17
+ }
18
+ /** Cooldown state for an action, expressed so a radial sweep or countdown can render directly. */
19
+ export interface ActionCooldown {
20
+ remainingMs: number;
21
+ totalMs: number;
22
+ /** Remaining share of the cooldown, `0..1` — the fraction a radial wipe should still cover. */
23
+ fraction: number;
24
+ ready: boolean;
25
+ }
26
+ /** A single blocking reason: a stable machine `code` plus caller-facing `message`. */
27
+ export interface ActionReason {
28
+ /** Stable tag for styling/branching, e.g. `"cooldown" | "cost" | "range" | "disabled"`. */
29
+ code: string;
30
+ message: string;
31
+ }
32
+ /**
33
+ * A caller-authored contextual action — the DATA input to the model. Every field except `id` is
34
+ * optional so a build button, a stance toggle, and a cooldown ability all use the same shape.
35
+ * Catalog-id mapping (turning `icon`/`label` into art and copy) stays caller-owned.
36
+ */
37
+ export interface ActionDef {
38
+ id: string;
39
+ label?: string;
40
+ description?: string;
41
+ /** Icon id / glyph the caller maps to a catalog; the model only carries it through. */
42
+ icon?: string;
43
+ /** Human hotkey label (e.g. `"Q"`, `"1"`). Matched case-insensitively by {@link actionByHotkey}. */
44
+ hotkey?: string;
45
+ /** Section id for grouping a large card into rows/tabs; caller-owned. */
46
+ group?: string;
47
+ cooldown?: ActionCooldown;
48
+ costs?: readonly ActionCost[];
49
+ /** Toggle/stance state — a mode that is currently on. */
50
+ active?: boolean;
51
+ /** Hard-disable regardless of cost/cooldown (not yet researched, no valid target). */
52
+ disabled?: boolean;
53
+ /** Extra caller reasons (out of range, needs tech). Merged after the derived cost/cooldown ones. */
54
+ reasons?: readonly ActionReason[];
55
+ }
56
+ /**
57
+ * A resolved action view model — availability computed once from cooldown, cost, `disabled`, and any
58
+ * caller reasons. `enabled` is the single truth a renderer gates interaction on; `reasons` is the
59
+ * ordered explanation (cooldown, then unmet costs, then caller reasons, then a generic disable).
60
+ */
61
+ export interface ResolvedAction {
62
+ id: string;
63
+ label: string;
64
+ description?: string;
65
+ icon?: string;
66
+ hotkey?: string;
67
+ group?: string;
68
+ active: boolean;
69
+ enabled: boolean;
70
+ cooldown: ActionCooldown | null;
71
+ costs: readonly ActionCost[];
72
+ reasons: readonly ActionReason[];
73
+ }
74
+ /** Build an {@link ActionCooldown} from remaining/total milliseconds. `ready` when nothing remains. */
75
+ export declare function actionCooldown(remainingMs: number, totalMs: number): ActionCooldown;
76
+ /**
77
+ * Build an {@link ActionCooldown} from remaining milliseconds and a known remaining fraction — the
78
+ * shape adapters get from sources (like an ability snapshot) that report a fraction but not a total.
79
+ */
80
+ export declare function actionCooldownFromFraction(remainingMs: number, fraction: number): ActionCooldown;
81
+ /** Build an {@link ActionCost}. `met` is true unless `available` is provided and below `amount`. */
82
+ export declare function actionCost(resourceId: string, amount: number, available?: number): ActionCost;
83
+ /**
84
+ * Resolve one {@link ActionDef} into a {@link ResolvedAction}: normalize label, compute `enabled`,
85
+ * and order the blocking `reasons`. Pure — the same input always yields the same view model.
86
+ */
87
+ export declare function resolveAction(def: ActionDef): ResolvedAction;
88
+ /** Resolve an ordered list of actions, preserving input order. */
89
+ export declare function resolveActionCollection(defs: readonly ActionDef[]): ResolvedAction[];
90
+ /**
91
+ * Find the action whose `hotkey` matches `key`, case-insensitively — the keyboard-shortcut router for
92
+ * an action bar. Returns the first match's id, or null. Matching by hotkey does not consider
93
+ * `enabled`; the caller decides whether to fire a disabled action's feedback.
94
+ */
95
+ export declare function actionByHotkey(actions: readonly ResolvedAction[], key: string): string | null;
96
+ /** A focus move for keyboard/controller grid navigation over an action collection. */
97
+ export type FocusDirection = "left" | "right" | "up" | "down" | "next" | "prev" | "first" | "last";
98
+ /** Options for {@link moveGridFocus}. */
99
+ export interface GridFocusOptions {
100
+ /** Wrap around edges instead of clamping (default false). */
101
+ wrap?: boolean;
102
+ }
103
+ /**
104
+ * Pure grid focus math for keyboard and controller navigation of an action card laid out in
105
+ * `columns`-wide rows. Given the current index (`-1` for none) it returns the next index, clamped to
106
+ * `[0, count)` — or wrapped when `wrap` is set. `left/right` move within/across columns, `up/down`
107
+ * across rows, `next/prev` walk the flat order, `first/last` jump to the ends. Renderer-agnostic:
108
+ * radial and list layouts pass `columns: 1` (or `count`) to get sensible 1-D stepping.
109
+ */
110
+ export declare function moveGridFocus(current: number, count: number, columns: number, dir: FocusDirection, options?: GridFocusOptions): number;
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Headless view model for a contextual action collection — the data layer behind an RTS command
3
+ * card, an ability action bar, a build menu, or a radial. It carries *what the buttons mean*
4
+ * (label, hotkey, cost, cooldown, disabled reasons, toggle state) with zero rendering opinion, so a
5
+ * game keeps layout, dimensions, hotkeys, catalog-id mapping, renderer, and chrome caller-owned. The
6
+ * React renderers in `@jgengine/react/actionHud` consume this; a game can swap either without
7
+ * forking the logic here.
8
+ */
9
+ const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);
10
+ /** Build an {@link ActionCooldown} from remaining/total milliseconds. `ready` when nothing remains. */
11
+ export function actionCooldown(remainingMs, totalMs) {
12
+ const remaining = Math.max(0, remainingMs);
13
+ const total = Math.max(0, totalMs);
14
+ return {
15
+ remainingMs: remaining,
16
+ totalMs: total,
17
+ fraction: total <= 0 ? 0 : clamp01(remaining / total),
18
+ ready: remaining <= 0,
19
+ };
20
+ }
21
+ /**
22
+ * Build an {@link ActionCooldown} from remaining milliseconds and a known remaining fraction — the
23
+ * shape adapters get from sources (like an ability snapshot) that report a fraction but not a total.
24
+ */
25
+ export function actionCooldownFromFraction(remainingMs, fraction) {
26
+ const remaining = Math.max(0, remainingMs);
27
+ const frac = clamp01(fraction);
28
+ return {
29
+ remainingMs: remaining,
30
+ totalMs: frac > 0 ? Math.round(remaining / frac) : remaining,
31
+ fraction: frac,
32
+ ready: remaining <= 0,
33
+ };
34
+ }
35
+ /** Build an {@link ActionCost}. `met` is true unless `available` is provided and below `amount`. */
36
+ export function actionCost(resourceId, amount, available) {
37
+ const cost = {
38
+ resourceId,
39
+ amount,
40
+ met: available === undefined ? true : available >= amount,
41
+ };
42
+ if (available !== undefined)
43
+ cost.available = available;
44
+ return cost;
45
+ }
46
+ /**
47
+ * Resolve one {@link ActionDef} into a {@link ResolvedAction}: normalize label, compute `enabled`,
48
+ * and order the blocking `reasons`. Pure — the same input always yields the same view model.
49
+ */
50
+ export function resolveAction(def) {
51
+ const costs = def.costs ?? [];
52
+ const reasons = [];
53
+ const cooldown = def.cooldown ?? null;
54
+ if (cooldown !== null && !cooldown.ready) {
55
+ reasons.push({ code: "cooldown", message: cooldownMessage(cooldown) });
56
+ }
57
+ for (const cost of costs) {
58
+ if (!cost.met)
59
+ reasons.push({ code: "cost", message: costMessage(cost) });
60
+ }
61
+ for (const reason of def.reasons ?? [])
62
+ reasons.push(reason);
63
+ if (def.disabled === true && reasons.length === 0) {
64
+ reasons.push({ code: "disabled", message: "Unavailable" });
65
+ }
66
+ const enabled = def.disabled !== true && reasons.length === 0;
67
+ const resolved = {
68
+ id: def.id,
69
+ label: def.label ?? def.id,
70
+ active: def.active === true,
71
+ enabled,
72
+ cooldown,
73
+ costs,
74
+ reasons,
75
+ };
76
+ if (def.description !== undefined)
77
+ resolved.description = def.description;
78
+ if (def.icon !== undefined)
79
+ resolved.icon = def.icon;
80
+ if (def.hotkey !== undefined)
81
+ resolved.hotkey = def.hotkey;
82
+ if (def.group !== undefined)
83
+ resolved.group = def.group;
84
+ return resolved;
85
+ }
86
+ /** Resolve an ordered list of actions, preserving input order. */
87
+ export function resolveActionCollection(defs) {
88
+ return defs.map(resolveAction);
89
+ }
90
+ /** @internal Default cooldown reason copy: `Ready in 2.4s`. */
91
+ function cooldownMessage(cooldown) {
92
+ return `Ready in ${(cooldown.remainingMs / 1000).toFixed(1)}s`;
93
+ }
94
+ /** @internal Default unmet-cost reason copy: `Needs 40 mana`. */
95
+ function costMessage(cost) {
96
+ return `Needs ${cost.amount} ${cost.resourceId}`;
97
+ }
98
+ /**
99
+ * Find the action whose `hotkey` matches `key`, case-insensitively — the keyboard-shortcut router for
100
+ * an action bar. Returns the first match's id, or null. Matching by hotkey does not consider
101
+ * `enabled`; the caller decides whether to fire a disabled action's feedback.
102
+ */
103
+ export function actionByHotkey(actions, key) {
104
+ const needle = key.toLowerCase();
105
+ for (const action of actions) {
106
+ if (action.hotkey !== undefined && action.hotkey.toLowerCase() === needle)
107
+ return action.id;
108
+ }
109
+ return null;
110
+ }
111
+ /**
112
+ * Pure grid focus math for keyboard and controller navigation of an action card laid out in
113
+ * `columns`-wide rows. Given the current index (`-1` for none) it returns the next index, clamped to
114
+ * `[0, count)` — or wrapped when `wrap` is set. `left/right` move within/across columns, `up/down`
115
+ * across rows, `next/prev` walk the flat order, `first/last` jump to the ends. Renderer-agnostic:
116
+ * radial and list layouts pass `columns: 1` (or `count`) to get sensible 1-D stepping.
117
+ */
118
+ export function moveGridFocus(current, count, columns, dir, options) {
119
+ if (count <= 0)
120
+ return -1;
121
+ const cols = Math.max(1, Math.floor(columns));
122
+ const wrap = options?.wrap === true;
123
+ if (dir === "first")
124
+ return 0;
125
+ if (dir === "last")
126
+ return count - 1;
127
+ if (current < 0) {
128
+ return dir === "prev" || dir === "left" || dir === "up" ? count - 1 : 0;
129
+ }
130
+ const clampIndex = (index) => Math.max(0, Math.min(count - 1, index));
131
+ if (dir === "next")
132
+ return current + 1 >= count ? (wrap ? 0 : count - 1) : current + 1;
133
+ if (dir === "prev")
134
+ return current - 1 < 0 ? (wrap ? count - 1 : 0) : current - 1;
135
+ const row = Math.floor(current / cols);
136
+ const col = current % cols;
137
+ if (dir === "right" || dir === "left") {
138
+ const rowStart = row * cols;
139
+ const rowEnd = Math.min(count - 1, rowStart + cols - 1);
140
+ const width = rowEnd - rowStart + 1;
141
+ if (width <= 1)
142
+ return current;
143
+ const nextCol = dir === "right" ? col + 1 : col - 1;
144
+ if (nextCol < 0)
145
+ return wrap ? rowEnd : current;
146
+ if (nextCol > rowEnd - rowStart)
147
+ return wrap ? rowStart : current;
148
+ return rowStart + nextCol;
149
+ }
150
+ // up / down
151
+ const nextRow = dir === "down" ? row + 1 : row - 1;
152
+ const rowCount = Math.ceil(count / cols);
153
+ if (nextRow < 0)
154
+ return wrap ? clampIndex((rowCount - 1) * cols + col) : current;
155
+ if (nextRow > rowCount - 1)
156
+ return wrap ? col : current;
157
+ const target = nextRow * cols + col;
158
+ return target >= count ? (dir === "down" ? current : clampIndex(target)) : target;
159
+ }
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Shared mobile-composition geometry. Every UI subsystem (HUD, touch controls,
3
+ * system chrome, screens) registers the physical rectangle it occupies; the
4
+ * engine allocates the viewport once and detects when two subsystems collide,
5
+ * instead of each independently claiming an edge. Pure math — no DOM, no React.
6
+ */
7
+ import type { LayoutOrientation } from "./orientation.js";
8
+ /** The explicit composition mode a game renders for — not a scaled desktop layout. */
9
+ export type GameLayoutMode = "desktop-wide" | "desktop-compact" | "mobile-landscape" | "mobile-portrait";
10
+ /** Edge insets in CSS pixels (safe areas, reservations). */
11
+ export interface Insets {
12
+ top: number;
13
+ right: number;
14
+ bottom: number;
15
+ left: number;
16
+ }
17
+ /** All-zero insets. */
18
+ export declare const ZERO_INSETS: Insets;
19
+ /** Axis-aligned rectangle in CSS pixels (origin top-left). Structurally compatible with a `DOMRect`'s edge fields. */
20
+ export interface LayoutRect {
21
+ left: number;
22
+ top: number;
23
+ right: number;
24
+ bottom: number;
25
+ }
26
+ /** Width of a rect (clamped to ≥0).
27
+ * @internal
28
+ */
29
+ export declare function rectWidth(rect: LayoutRect): number;
30
+ /** Height of a rect (clamped to ≥0).
31
+ * @internal
32
+ */
33
+ export declare function rectHeight(rect: LayoutRect): number;
34
+ /** Area of a rect in px².
35
+ * @internal
36
+ */
37
+ export declare function rectArea(rect: LayoutRect): number;
38
+ /** Do the two rectangles share any interior area? Touching edges do not count.
39
+ * @internal
40
+ */
41
+ export declare function intersects(a: LayoutRect, b: LayoutRect): boolean;
42
+ /** Overlapping area in px²; 0 when the rectangles don't intersect.
43
+ * @internal
44
+ */
45
+ export declare function overlapArea(a: LayoutRect, b: LayoutRect): number;
46
+ /** Portrait when taller than wide, else landscape.
47
+ * @internal
48
+ */
49
+ export declare function orientationOf(width: number, height: number): LayoutOrientation;
50
+ /** Inputs to `resolveLayoutMode`. */
51
+ export interface LayoutModeInput {
52
+ /** Live visible viewport dimensions (prefer `visualViewport`). */
53
+ width: number;
54
+ height: number;
55
+ /** Touchscreen is the primary input (`(pointer: coarse)`). */
56
+ coarsePointer: boolean;
57
+ /** Does the game support phones at all (`platforms` includes `"mobile"`)? Default true. */
58
+ mobileSupported?: boolean;
59
+ /** Desktop width below which the layout is "compact". Default 900. */
60
+ compactWidth?: number;
61
+ }
62
+ /**
63
+ * Resolve the explicit composition mode. A mobile layout is not a scaled
64
+ * desktop layout: a coarse-pointer device on a game that supports mobile is
65
+ * always a `mobile-*` mode, split by live orientation; everything else is a
66
+ * desktop mode split by width.
67
+ * @internal
68
+ */
69
+ export declare function resolveLayoutMode(input: LayoutModeInput): GameLayoutMode;
70
+ /** Whether a mode is one of the phone modes.
71
+ * @internal
72
+ */
73
+ export declare function isMobileMode(mode: GameLayoutMode): boolean;
74
+ /** What kind of UI a registered region belongs to. */
75
+ export type LayoutRegionKind = "hud" | "control" | "system" | "screen";
76
+ /** How a region participates in collision reporting. */
77
+ export type LayoutCollisionPolicy = "forbid" | "allow" | "warn";
78
+ /** Gameplay-importance tier of a HUD element. */
79
+ export type HudPriority = "critical" | "secondary" | "tertiary";
80
+ /** How a HUD element adapts on phones. */
81
+ export type MobileHudBehavior = "persistent" | "compact" | "icon" | "transient" | "hidden" | "sheet" | "modal";
82
+ /** A physical rectangle a UI subsystem occupies, published to the shared registry. */
83
+ export interface LayoutRegion {
84
+ id: string;
85
+ kind: LayoutRegionKind;
86
+ rect: LayoutRect;
87
+ /** `forbid` reports any overlap, `warn` reports softly, `allow` opts this region out of collision reporting entirely. */
88
+ collisionPolicy: LayoutCollisionPolicy;
89
+ priority?: HudPriority;
90
+ /** Region ids this one may overlap without a report. */
91
+ allowOverlapWith?: readonly string[];
92
+ /** Regions sharing a non-empty group never report against each other. */
93
+ collisionGroup?: string;
94
+ }
95
+ /** One detected forbidden/warned overlap between two regions. */
96
+ export interface LayoutCollision {
97
+ a: string;
98
+ b: string;
99
+ kindA: LayoutRegionKind;
100
+ kindB: LayoutRegionKind;
101
+ /** Overlapping area in px². */
102
+ area: number;
103
+ severity: "forbid" | "warn";
104
+ }
105
+ /** Options for `detectLayoutCollisions`. */
106
+ export interface DetectCollisionsOptions {
107
+ /** Ignore overlaps smaller than this many px² — avoids meaningless sub-pixel warnings. Default 64. */
108
+ minArea?: number;
109
+ }
110
+ /**
111
+ * Every forbidden or warned rectangle intersection across the registered
112
+ * regions. A pair is skipped when either side's policy is `allow`, when either
113
+ * opts into the other via `allowOverlapWith`, when they share a
114
+ * `collisionGroup`, or when the overlap is below `minArea`.
115
+ * @internal
116
+ */
117
+ export declare function detectLayoutCollisions(regions: readonly LayoutRegion[], options?: DetectCollisionsOptions): LayoutCollision[];
118
+ /** Human-readable diagnostic block for a set of collisions (empty string when there are none).
119
+ * @internal
120
+ */
121
+ export declare function formatLayoutCollisions(collisions: readonly LayoutCollision[]): string;
122
+ /**
123
+ * The usable gameplay rectangle after reserving physical zones for touch
124
+ * controls and system UI. Starts from the safe-area-inset viewport and carves
125
+ * each reserved zone from whichever edge it hugs.
126
+ * @internal
127
+ */
128
+ export declare function computeGameplayRect(viewport: LayoutRect, safeArea: Insets, reserved: readonly LayoutRect[]): LayoutRect;
129
+ /** The shared live geometry the engine allocates once and every UI subsystem reads. */
130
+ export interface GameViewportLayout {
131
+ /** The layout (CSS-pixel) viewport. */
132
+ viewport: LayoutRect;
133
+ /** The live visible viewport (`window.visualViewport`), which excludes mobile browser chrome. */
134
+ visualViewport: LayoutRect;
135
+ safeArea: Insets;
136
+ mode: GameLayoutMode;
137
+ orientation: LayoutOrientation;
138
+ /** All registered regions with their live rects. */
139
+ regions: readonly LayoutRegion[];
140
+ /** Rects reserved by touch controls and system UI. */
141
+ controlZones: readonly LayoutRect[];
142
+ /** Usable world/gameplay area after reservations. */
143
+ gameplayRect: LayoutRect;
144
+ }
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Shared mobile-composition geometry. Every UI subsystem (HUD, touch controls,
3
+ * system chrome, screens) registers the physical rectangle it occupies; the
4
+ * engine allocates the viewport once and detects when two subsystems collide,
5
+ * instead of each independently claiming an edge. Pure math — no DOM, no React.
6
+ */
7
+ /** All-zero insets. */
8
+ export const ZERO_INSETS = { top: 0, right: 0, bottom: 0, left: 0 };
9
+ /** Width of a rect (clamped to ≥0).
10
+ * @internal
11
+ */
12
+ export function rectWidth(rect) {
13
+ return Math.max(0, rect.right - rect.left);
14
+ }
15
+ /** Height of a rect (clamped to ≥0).
16
+ * @internal
17
+ */
18
+ export function rectHeight(rect) {
19
+ return Math.max(0, rect.bottom - rect.top);
20
+ }
21
+ /** Area of a rect in px².
22
+ * @internal
23
+ */
24
+ export function rectArea(rect) {
25
+ return rectWidth(rect) * rectHeight(rect);
26
+ }
27
+ /** Do the two rectangles share any interior area? Touching edges do not count.
28
+ * @internal
29
+ */
30
+ export function intersects(a, b) {
31
+ return a.left < b.right && a.right > b.left && a.top < b.bottom && a.bottom > b.top;
32
+ }
33
+ /** Overlapping area in px²; 0 when the rectangles don't intersect.
34
+ * @internal
35
+ */
36
+ export function overlapArea(a, b) {
37
+ const w = Math.min(a.right, b.right) - Math.max(a.left, b.left);
38
+ const h = Math.min(a.bottom, b.bottom) - Math.max(a.top, b.top);
39
+ return w > 0 && h > 0 ? w * h : 0;
40
+ }
41
+ /** Portrait when taller than wide, else landscape.
42
+ * @internal
43
+ */
44
+ export function orientationOf(width, height) {
45
+ return height > width ? "portrait" : "landscape";
46
+ }
47
+ const DEFAULT_COMPACT_WIDTH = 900;
48
+ /**
49
+ * Resolve the explicit composition mode. A mobile layout is not a scaled
50
+ * desktop layout: a coarse-pointer device on a game that supports mobile is
51
+ * always a `mobile-*` mode, split by live orientation; everything else is a
52
+ * desktop mode split by width.
53
+ * @internal
54
+ */
55
+ export function resolveLayoutMode(input) {
56
+ const orientation = orientationOf(input.width, input.height);
57
+ const mobile = input.coarsePointer && (input.mobileSupported ?? true);
58
+ if (mobile)
59
+ return orientation === "portrait" ? "mobile-portrait" : "mobile-landscape";
60
+ const compactWidth = input.compactWidth ?? DEFAULT_COMPACT_WIDTH;
61
+ return input.width < compactWidth ? "desktop-compact" : "desktop-wide";
62
+ }
63
+ /** Whether a mode is one of the phone modes.
64
+ * @internal
65
+ */
66
+ export function isMobileMode(mode) {
67
+ return mode === "mobile-portrait" || mode === "mobile-landscape";
68
+ }
69
+ function allowsOverlap(a, b) {
70
+ if (a.allowOverlapWith?.includes(b.id) === true)
71
+ return true;
72
+ if (b.allowOverlapWith?.includes(a.id) === true)
73
+ return true;
74
+ if (a.collisionGroup !== undefined && a.collisionGroup === b.collisionGroup)
75
+ return true;
76
+ return false;
77
+ }
78
+ const DEFAULT_MIN_AREA = 64;
79
+ /**
80
+ * Every forbidden or warned rectangle intersection across the registered
81
+ * regions. A pair is skipped when either side's policy is `allow`, when either
82
+ * opts into the other via `allowOverlapWith`, when they share a
83
+ * `collisionGroup`, or when the overlap is below `minArea`.
84
+ * @internal
85
+ */
86
+ export function detectLayoutCollisions(regions, options) {
87
+ const minArea = options?.minArea ?? DEFAULT_MIN_AREA;
88
+ const out = [];
89
+ for (let i = 0; i < regions.length; i += 1) {
90
+ for (let j = i + 1; j < regions.length; j += 1) {
91
+ const a = regions[i];
92
+ const b = regions[j];
93
+ if (a.collisionPolicy === "allow" || b.collisionPolicy === "allow")
94
+ continue;
95
+ if (allowsOverlap(a, b))
96
+ continue;
97
+ const area = overlapArea(a.rect, b.rect);
98
+ if (area < minArea)
99
+ continue;
100
+ const severity = a.collisionPolicy === "forbid" || b.collisionPolicy === "forbid" ? "forbid" : "warn";
101
+ out.push({ a: a.id, b: b.id, kindA: a.kind, kindB: b.kind, area: Math.round(area), severity });
102
+ }
103
+ }
104
+ return out;
105
+ }
106
+ function withThousands(n) {
107
+ return Math.round(n)
108
+ .toString()
109
+ .replace(/\B(?=(\d{3})+(?!\d))/g, ",");
110
+ }
111
+ /** Human-readable diagnostic block for a set of collisions (empty string when there are none).
112
+ * @internal
113
+ */
114
+ export function formatLayoutCollisions(collisions) {
115
+ if (collisions.length === 0)
116
+ return "";
117
+ const lines = collisions.map((c) => `${c.a} intersects ${c.b} by ${withThousands(c.area)} px²`);
118
+ return ["JGENGINE MOBILE LAYOUT COLLISION", ...lines].join("\n");
119
+ }
120
+ /**
121
+ * The usable gameplay rectangle after reserving physical zones for touch
122
+ * controls and system UI. Starts from the safe-area-inset viewport and carves
123
+ * each reserved zone from whichever edge it hugs.
124
+ * @internal
125
+ */
126
+ export function computeGameplayRect(viewport, safeArea, reserved) {
127
+ let top = viewport.top + safeArea.top;
128
+ let bottom = viewport.bottom - safeArea.bottom;
129
+ let left = viewport.left + safeArea.left;
130
+ let right = viewport.right - safeArea.right;
131
+ const midX = (viewport.left + viewport.right) / 2;
132
+ const midY = (viewport.top + viewport.bottom) / 2;
133
+ for (const zone of reserved) {
134
+ const zoneMidX = (zone.left + zone.right) / 2;
135
+ const zoneMidY = (zone.top + zone.bottom) / 2;
136
+ const spanX = zone.right - zone.left;
137
+ const spanY = zone.bottom - zone.top;
138
+ if (zoneMidY > midY)
139
+ bottom = Math.min(bottom, zone.top);
140
+ else if (zoneMidY < midY && spanX >= spanY)
141
+ top = Math.max(top, zone.bottom);
142
+ else if (zoneMidX < midX)
143
+ left = Math.max(left, zone.right);
144
+ else
145
+ right = Math.min(right, zone.left);
146
+ }
147
+ return { left, top, right: Math.max(left, right), bottom: Math.max(top, bottom) };
148
+ }