@jgengine/core 0.18.1 → 0.21.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 (404) hide show
  1. package/CHANGELOG.md +504 -7
  2. package/dist/ai/decisionGraph.d.ts +50 -4
  3. package/dist/ai/decisionGraph.js +159 -23
  4. package/dist/ai/flock.d.ts +1 -1
  5. package/dist/ai/flock.js +7 -4
  6. package/dist/ai/groupAssist.d.ts +10 -0
  7. package/dist/ai/groupAssist.js +11 -0
  8. package/dist/ai/pursuit.d.ts +1 -1
  9. package/dist/ai/pursuit.js +1 -1
  10. package/dist/ai/threat.d.ts +8 -0
  11. package/dist/ai/threat.js +10 -0
  12. package/dist/anim/animGraph.d.ts +43 -1
  13. package/dist/anim/animGraph.js +326 -10
  14. package/dist/anim/boneTexture.d.ts +55 -0
  15. package/dist/anim/boneTexture.js +43 -0
  16. package/dist/anim/footPlacement.d.ts +57 -0
  17. package/dist/anim/footPlacement.js +67 -0
  18. package/dist/anim/locomotionGraph.d.ts +18 -1
  19. package/dist/anim/locomotionGraph.js +42 -3
  20. package/dist/audio/audioFalloff.d.ts +6 -0
  21. package/dist/audio/doppler.d.ts +21 -0
  22. package/dist/audio/doppler.js +32 -0
  23. package/dist/audio/engineLayers.d.ts +83 -0
  24. package/dist/audio/engineLayers.js +115 -0
  25. package/dist/audio/voiceAllocator.d.ts +46 -0
  26. package/dist/audio/voiceAllocator.js +76 -0
  27. package/dist/combat/abilityKit.d.ts +20 -0
  28. package/dist/combat/abilityKit.js +41 -4
  29. package/dist/combat/death.d.ts +11 -3
  30. package/dist/combat/death.js +3 -3
  31. package/dist/combat/magazine.d.ts +9 -0
  32. package/dist/combat/magazine.js +24 -2
  33. package/dist/combat/projectiles.d.ts +94 -2
  34. package/dist/combat/projectiles.js +282 -61
  35. package/dist/combat/regenShield.d.ts +14 -0
  36. package/dist/combat/regenShield.js +23 -7
  37. package/dist/combat/shotOrigin.d.ts +6 -0
  38. package/dist/combat/shotOrigin.js +6 -0
  39. package/dist/combat/weaponFeedback.d.ts +36 -0
  40. package/dist/combat/weaponFeedback.js +42 -0
  41. package/dist/combat/weaponHandling.d.ts +161 -0
  42. package/dist/combat/weaponHandling.js +202 -0
  43. package/dist/combat/weaponPresentation.d.ts +115 -0
  44. package/dist/combat/weaponPresentation.js +96 -0
  45. package/dist/crafting/recipeCatalog.d.ts +16 -0
  46. package/dist/crafting/recipeCatalog.js +55 -0
  47. package/dist/devtools/warnOnce.d.ts +8 -0
  48. package/dist/devtools/warnOnce.js +18 -0
  49. package/dist/economy/auctionBook.d.ts +1 -1
  50. package/dist/economy/auctionBook.js +11 -1
  51. package/dist/economy/listingBook.d.ts +1 -1
  52. package/dist/economy/listingBook.js +11 -1
  53. package/dist/economy/resourceLedger.js +3 -3
  54. package/dist/economy/shopStock.js +7 -6
  55. package/dist/economy/techTree.js +7 -6
  56. package/dist/economy/unlockPoints.js +3 -6
  57. package/dist/editor/commandApply.js +89 -16
  58. package/dist/editor/commands.d.ts +38 -1
  59. package/dist/editor/commands.js +320 -3
  60. package/dist/editor/creatorStorage.d.ts +59 -0
  61. package/dist/editor/creatorStorage.js +164 -0
  62. package/dist/editor/document.d.ts +4 -0
  63. package/dist/editor/document.js +119 -18
  64. package/dist/editor/environment.js +8 -0
  65. package/dist/editor/index.d.ts +2 -0
  66. package/dist/editor/liveSync.d.ts +4 -1
  67. package/dist/editor/liveSync.js +26 -10
  68. package/dist/editor/materialAuthoring.d.ts +14 -0
  69. package/dist/editor/materialAuthoring.js +38 -0
  70. package/dist/editor/modelNodeVisibility.d.ts +11 -0
  71. package/dist/editor/modelNodeVisibility.js +29 -0
  72. package/dist/editor/movementCatalog.d.ts +90 -0
  73. package/dist/editor/movementCatalog.js +144 -0
  74. package/dist/editor/simulation.d.ts +60 -0
  75. package/dist/editor/simulation.js +202 -0
  76. package/dist/editor/staticPrefab.d.ts +17 -0
  77. package/dist/editor/staticPrefab.js +51 -0
  78. package/dist/editor/types.d.ts +15 -0
  79. package/dist/faction/reputation.d.ts +6 -0
  80. package/dist/faction/reputation.js +11 -0
  81. package/dist/game/cameraConfig.d.ts +54 -2
  82. package/dist/game/clipRoles.d.ts +2 -1
  83. package/dist/game/clipRoles.js +7 -3
  84. package/dist/game/contentValidation.d.ts +69 -0
  85. package/dist/game/contentValidation.js +118 -0
  86. package/dist/game/controlGate.d.ts +8 -0
  87. package/dist/game/controlGate.js +43 -6
  88. package/dist/game/defineGame.d.ts +32 -3
  89. package/dist/game/dialogueGraph.d.ts +20 -0
  90. package/dist/game/dialogueGraph.js +107 -0
  91. package/dist/game/events.d.ts +11 -0
  92. package/dist/game/keyValueStore.d.ts +17 -4
  93. package/dist/game/keyValueStore.js +35 -23
  94. package/dist/game/lootModifiers.d.ts +17 -0
  95. package/dist/game/lootModifiers.js +26 -0
  96. package/dist/game/lootTable.d.ts +4 -0
  97. package/dist/game/lootTable.js +16 -0
  98. package/dist/game/narrativeAuthoring.d.ts +67 -0
  99. package/dist/game/narrativeAuthoring.js +122 -0
  100. package/dist/game/playableGame.d.ts +134 -35
  101. package/dist/game/quest.d.ts +15 -0
  102. package/dist/game/quest.js +209 -63
  103. package/dist/game/questCatalog.d.ts +50 -0
  104. package/dist/game/questCatalog.js +205 -0
  105. package/dist/game/saveStore.d.ts +6 -5
  106. package/dist/game/saveStore.js +57 -57
  107. package/dist/game/systemRuntime.d.ts +2 -2
  108. package/dist/game/systemRuntime.js +84 -33
  109. package/dist/game/toasts.d.ts +8 -0
  110. package/dist/game/toasts.js +7 -0
  111. package/dist/game/vfxInstance.d.ts +9 -0
  112. package/dist/game/vfxInstance.js +12 -1
  113. package/dist/game/viewports.d.ts +43 -0
  114. package/dist/game/viewports.js +46 -0
  115. package/dist/game/worldItem.d.ts +5 -1
  116. package/dist/game/worldItem.js +0 -1
  117. package/dist/gameplay.d.ts +3 -0
  118. package/dist/gameplay.js +3 -0
  119. package/dist/input/actionBindings.d.ts +15 -1
  120. package/dist/input/actionBindings.js +14 -3
  121. package/dist/input/actionContexts.d.ts +25 -1
  122. package/dist/input/actionContexts.js +82 -25
  123. package/dist/input/axisInput.d.ts +4 -0
  124. package/dist/input/axisInput.js +4 -0
  125. package/dist/input/axisShaper.d.ts +73 -0
  126. package/dist/input/axisShaper.js +105 -0
  127. package/dist/input/gamepadModel.d.ts +36 -2
  128. package/dist/input/gamepadModel.js +69 -30
  129. package/dist/input/haptics.d.ts +50 -0
  130. package/dist/input/haptics.js +74 -0
  131. package/dist/input/inputBuffer.d.ts +40 -0
  132. package/dist/input/inputBuffer.js +59 -0
  133. package/dist/input/lookChannel.d.ts +10 -0
  134. package/dist/input/lookChannel.js +6 -0
  135. package/dist/input/pointer.d.ts +2 -0
  136. package/dist/input/pointer.js +4 -0
  137. package/dist/interaction/promptRegistry.d.ts +5 -4
  138. package/dist/interaction/promptRegistry.js +8 -2
  139. package/dist/inventory/inventoryModel.js +9 -6
  140. package/dist/inventory/shapedGrid.d.ts +48 -9
  141. package/dist/inventory/shapedGrid.js +69 -10
  142. package/dist/item/affix.d.ts +6 -0
  143. package/dist/item/affix.js +6 -0
  144. package/dist/item/durability.js +4 -0
  145. package/dist/item/itemInstanceRegistry.d.ts +32 -1
  146. package/dist/item/itemInstanceRegistry.js +111 -7
  147. package/dist/item/itemgen.d.ts +1 -1
  148. package/dist/item/itemgen.js +1 -1
  149. package/dist/item/modularItem.js +7 -1
  150. package/dist/material/appearanceSignals.d.ts +53 -0
  151. package/dist/material/appearanceSignals.js +47 -0
  152. package/dist/material/hairCards.d.ts +47 -0
  153. package/dist/material/hairCards.js +136 -0
  154. package/dist/material/materialAsset.d.ts +162 -0
  155. package/dist/material/materialAsset.js +382 -0
  156. package/dist/meta/changelog.d.ts +1 -1
  157. package/dist/meta/changelog.js +444 -1
  158. package/dist/movement/characterController.d.ts +5 -2
  159. package/dist/movement/characterController.js +50 -23
  160. package/dist/movement/freeFlight.d.ts +2 -2
  161. package/dist/movement/freeFlight.js +3 -3
  162. package/dist/movement/glideModel.d.ts +3 -0
  163. package/dist/movement/glideModel.js +6 -0
  164. package/dist/movement/grappleSwing.d.ts +2 -0
  165. package/dist/movement/grappleSwing.js +5 -1
  166. package/dist/movement/movementModel.d.ts +63 -1
  167. package/dist/movement/movementModel.js +136 -26
  168. package/dist/movement/movementProbe.d.ts +51 -0
  169. package/dist/movement/movementProbe.js +119 -0
  170. package/dist/movement/playerMovement.d.ts +48 -2
  171. package/dist/movement/playerMovement.js +493 -87
  172. package/dist/movement/poseState.d.ts +2 -0
  173. package/dist/movement/poseState.js +29 -1
  174. package/dist/movement/solidObstacles.d.ts +11 -1
  175. package/dist/movement/solidObstacles.js +48 -3
  176. package/dist/movement/terrainGrade.d.ts +13 -0
  177. package/dist/movement/terrainGrade.js +33 -0
  178. package/dist/movement/voxelController.d.ts +2 -2
  179. package/dist/movement/voxelController.js +10 -10
  180. package/dist/nav/navFromEnvironment.d.ts +9 -3
  181. package/dist/nav/navFromEnvironment.js +18 -12
  182. package/dist/nav/navGrid.d.ts +19 -1
  183. package/dist/nav/navGrid.js +26 -10
  184. package/dist/nav/navMesh.d.ts +43 -2
  185. package/dist/nav/navMesh.js +534 -128
  186. package/dist/nav/solidRoute.d.ts +50 -0
  187. package/dist/nav/solidRoute.js +144 -0
  188. package/dist/physics/aircraftDynamics.d.ts +390 -0
  189. package/dist/physics/aircraftDynamics.js +704 -0
  190. package/dist/physics/ballisticSweep.d.ts +10 -3
  191. package/dist/physics/ballisticSweep.js +53 -29
  192. package/dist/physics/boatDynamics.d.ts +116 -0
  193. package/dist/physics/boatDynamics.js +160 -0
  194. package/dist/physics/drivableVehicle.d.ts +22 -8
  195. package/dist/physics/drivableVehicle.js +4 -2
  196. package/dist/physics/flightDynamics.d.ts +21 -4
  197. package/dist/physics/flightDynamics.js +28 -5
  198. package/dist/physics/forceVolume.d.ts +41 -0
  199. package/dist/physics/forceVolume.js +88 -0
  200. package/dist/physics/handlingProbe.d.ts +249 -0
  201. package/dist/physics/handlingProbe.js +606 -0
  202. package/dist/physics/kinematicVehicle.d.ts +40 -5
  203. package/dist/physics/kinematicVehicle.js +17 -2
  204. package/dist/physics/physicsBackend.d.ts +12 -0
  205. package/dist/physics/physicsBackendConformance.js +34 -0
  206. package/dist/physics/physicsWorldBackend.d.ts +1 -0
  207. package/dist/physics/physicsWorldBackend.js +52 -3
  208. package/dist/physics/spatialGrid.d.ts +1 -1
  209. package/dist/physics/spatialGrid.js +8 -9
  210. package/dist/physics/vehicleBackendLink.d.ts +49 -0
  211. package/dist/physics/vehicleBackendLink.js +102 -0
  212. package/dist/physics/vehicleDynamics.d.ts +375 -0
  213. package/dist/physics/vehicleDynamics.js +737 -0
  214. package/dist/physics/vehicleObstacles.d.ts +3 -2
  215. package/dist/physics/vehicleObstacles.js +29 -5
  216. package/dist/physics/worldColliders.d.ts +1 -1
  217. package/dist/physics/worldColliders.js +35 -3
  218. package/dist/puzzle/cellGrid.d.ts +15 -9
  219. package/dist/puzzle/cellGrid.js +13 -9
  220. package/dist/render/lookPreset.d.ts +9 -2
  221. package/dist/render/lookPreset.js +29 -2
  222. package/dist/render/postProcessing.d.ts +30 -0
  223. package/dist/render/postProcessing.js +1 -1
  224. package/dist/runtime/cameraDirector.d.ts +54 -3
  225. package/dist/runtime/cameraDirector.js +187 -0
  226. package/dist/runtime/commandDispatch.d.ts +14 -0
  227. package/dist/runtime/commandDispatch.js +19 -0
  228. package/dist/runtime/commandInput.d.ts +37 -0
  229. package/dist/runtime/commandInput.js +58 -0
  230. package/dist/runtime/commandRunner.d.ts +27 -0
  231. package/dist/runtime/commandRunner.js +31 -3
  232. package/dist/runtime/context/combat.d.ts +12 -4
  233. package/dist/runtime/context/combat.js +179 -11
  234. package/dist/runtime/context/deathLoot.d.ts +11 -8
  235. package/dist/runtime/context/deathLoot.js +17 -16
  236. package/dist/runtime/context/scene.d.ts +2 -0
  237. package/dist/runtime/context/scene.js +13 -21
  238. package/dist/runtime/descriptors/baseline.js +34 -3
  239. package/dist/runtime/descriptors/features.d.ts +2 -1
  240. package/dist/runtime/descriptors/features.js +18 -0
  241. package/dist/runtime/gameContext.js +86 -13
  242. package/dist/runtime/gameContextTypes.d.ts +33 -3
  243. package/dist/runtime/gameRuntime.d.ts +3 -1
  244. package/dist/runtime/gameRuntime.js +4 -0
  245. package/dist/runtime/headlessRunner.d.ts +3 -1
  246. package/dist/runtime/headlessRunner.js +11 -11
  247. package/dist/runtime/hostedGameRunner.d.ts +24 -1
  248. package/dist/runtime/hostedGameRunner.js +156 -10
  249. package/dist/runtime/hostedWorldSession.d.ts +17 -5
  250. package/dist/runtime/hostedWorldSession.js +154 -16
  251. package/dist/runtime/hostedWorldStore.d.ts +2 -2
  252. package/dist/runtime/inputRecorder.d.ts +1 -1
  253. package/dist/runtime/inputRecorder.js +21 -1
  254. package/dist/runtime/inputSnapshot.d.ts +22 -4
  255. package/dist/runtime/inputSnapshot.js +41 -3
  256. package/dist/runtime/localPlayers.d.ts +73 -0
  257. package/dist/runtime/localPlayers.js +119 -0
  258. package/dist/runtime/runtimeSave.d.ts +10 -6
  259. package/dist/runtime/runtimeSave.js +11 -5
  260. package/dist/runtime/simContext.d.ts +8 -3
  261. package/dist/runtime/simContext.js +7 -3
  262. package/dist/runtime/simSnapshot.js +2 -0
  263. package/dist/runtime/transport.d.ts +9 -0
  264. package/dist/runtime/transport.js +7 -1
  265. package/dist/runtime/worldReplication.d.ts +2 -0
  266. package/dist/runtime/worldReplication.js +1 -1
  267. package/dist/scene/assetCatalog.d.ts +2 -0
  268. package/dist/scene/behaviorRuntime.d.ts +38 -7
  269. package/dist/scene/behaviorRuntime.js +293 -30
  270. package/dist/scene/behaviors.d.ts +35 -2
  271. package/dist/scene/behaviors.js +29 -0
  272. package/dist/scene/entityStore.d.ts +14 -3
  273. package/dist/scene/entityStore.js +45 -9
  274. package/dist/scene/mount.d.ts +9 -0
  275. package/dist/scene/mount.js +35 -0
  276. package/dist/scene/possession.d.ts +2 -0
  277. package/dist/scene/possession.js +21 -1
  278. package/dist/scene/sceneKinds.d.ts +9 -0
  279. package/dist/scene/sceneRaycast.d.ts +7 -0
  280. package/dist/scene/sceneRaycast.js +55 -0
  281. package/dist/scene/spatial.d.ts +20 -1
  282. package/dist/scene/spatial.js +94 -2
  283. package/dist/scene/vehicleSeat.d.ts +41 -3
  284. package/dist/scene/vehicleSeat.js +94 -3
  285. package/dist/sensor/concealment.d.ts +6 -0
  286. package/dist/sensor/concealment.js +8 -0
  287. package/dist/sensor/freezeMonitor.d.ts +6 -0
  288. package/dist/sensor/freezeMonitor.js +8 -0
  289. package/dist/sensor/perception.d.ts +11 -1
  290. package/dist/sensor/perception.js +57 -10
  291. package/dist/sensor/recordingBuffer.d.ts +3 -0
  292. package/dist/sensor/recordingBuffer.js +8 -0
  293. package/dist/session/roundState.d.ts +4 -0
  294. package/dist/session/roundState.js +11 -0
  295. package/dist/settings/frameRateLimit.d.ts +16 -0
  296. package/dist/settings/frameRateLimit.js +37 -0
  297. package/dist/settings/graphicsProfile.d.ts +2 -0
  298. package/dist/settings/graphicsProfile.js +12 -0
  299. package/dist/settings/graphicsSettings.d.ts +40 -0
  300. package/dist/settings/graphicsSettings.js +81 -0
  301. package/dist/settings/settingsModel.d.ts +9 -1
  302. package/dist/settings/settingsModel.js +10 -0
  303. package/dist/stats/accumulatorMeter.d.ts +10 -0
  304. package/dist/stats/accumulatorMeter.js +6 -0
  305. package/dist/stats/eventMeter.d.ts +10 -3
  306. package/dist/stats/eventMeter.js +6 -3
  307. package/dist/store/defineStore.d.ts +3 -1
  308. package/dist/store/defineStore.js +3 -1
  309. package/dist/store/observableKeyedStore.d.ts +1 -1
  310. package/dist/store/observableKeyedStore.js +8 -6
  311. package/dist/time/simClock.d.ts +6 -2
  312. package/dist/time/simClock.js +5 -0
  313. package/dist/vfx/feedbackMixer.d.ts +61 -0
  314. package/dist/vfx/feedbackMixer.js +106 -0
  315. package/dist/vfx/particleDirector.d.ts +58 -6
  316. package/dist/vfx/particleDirector.js +113 -22
  317. package/dist/vfx/particles.d.ts +68 -5
  318. package/dist/vfx/particles.js +284 -32
  319. package/dist/visibility/assetStreaming.d.ts +21 -3
  320. package/dist/visibility/assetStreaming.js +108 -24
  321. package/dist/visibility/settings.d.ts +8 -2
  322. package/dist/visibility/settings.js +3 -0
  323. package/dist/visibility/simulationCulling.d.ts +8 -1
  324. package/dist/visibility/simulationCulling.js +7 -0
  325. package/dist/visibility/spatialIndex.d.ts +21 -0
  326. package/dist/visibility/spatialIndex.js +16 -0
  327. package/dist/visibility/visibilitySystem.js +1 -0
  328. package/dist/work/expedition.d.ts +110 -0
  329. package/dist/work/expedition.js +195 -0
  330. package/dist/work/staffedStation.d.ts +29 -0
  331. package/dist/work/staffedStation.js +27 -0
  332. package/dist/world/authoredAnimation.d.ts +38 -0
  333. package/dist/world/authoredAnimation.js +99 -0
  334. package/dist/world/authoredObjects.d.ts +24 -4
  335. package/dist/world/authoredObjects.js +43 -16
  336. package/dist/world/authoredSimulation.d.ts +74 -0
  337. package/dist/world/authoredSimulation.js +302 -0
  338. package/dist/world/authoredSolids.d.ts +46 -0
  339. package/dist/world/authoredSolids.js +75 -0
  340. package/dist/world/authoredWeather.d.ts +120 -0
  341. package/dist/world/authoredWeather.js +314 -0
  342. package/dist/world/buildingGenerator.js +2 -2
  343. package/dist/world/buildingKit.d.ts +11 -4
  344. package/dist/world/buildingKit.js +21 -8
  345. package/dist/world/buildings.d.ts +34 -2
  346. package/dist/world/buildings.js +11 -1
  347. package/dist/world/cityKind.d.ts +7 -0
  348. package/dist/world/cityKind.js +52 -1
  349. package/dist/world/environmentForces.d.ts +21 -0
  350. package/dist/world/environmentForces.js +42 -0
  351. package/dist/world/features.d.ts +32 -5
  352. package/dist/world/features.js +6 -0
  353. package/dist/world/footprintGrid.d.ts +62 -0
  354. package/dist/world/footprintGrid.js +217 -0
  355. package/dist/world/interiors.d.ts +1 -0
  356. package/dist/world/interiors.js +5 -3
  357. package/dist/world/lod.d.ts +6 -0
  358. package/dist/world/lod.js +8 -0
  359. package/dist/world/pathTerrain.d.ts +1 -1
  360. package/dist/world/terraform.d.ts +9 -1
  361. package/dist/world/terraform.js +53 -18
  362. package/dist/world/walls.d.ts +7 -0
  363. package/dist/world/walls.js +7 -0
  364. package/dist/world/weather.d.ts +17 -0
  365. package/dist/world/weather.js +116 -20
  366. package/dist/world/worldSolids.d.ts +95 -0
  367. package/dist/world/worldSolids.js +351 -0
  368. package/dist/world.d.ts +6 -6
  369. package/dist/world.js +5 -5
  370. package/package.json +1 -1
  371. package/skills/ce-handoff/SKILL.md +2 -2
  372. package/skills/game-design/SKILL.md +2 -2
  373. package/skills/jgengine/SKILL.md +28 -6
  374. package/skills/jgengine/api.md +139 -99
  375. package/skills/jgengine/capabilities.md +28 -0
  376. package/skills/jgengine/recipes/minimal-game.md +10 -2
  377. package/skills/jgengine-combat/SKILL.md +13 -2
  378. package/skills/jgengine-combat/api.md +150 -103
  379. package/skills/jgengine-combat/capabilities.md +29 -1
  380. package/skills/jgengine-combat/recipes/portable-runtime-state.md +60 -6
  381. package/skills/jgengine-combat/recipes/portable-weapon-plumbing.md +37 -3
  382. package/skills/jgengine-combat/recipes/weapon-feel.md +50 -0
  383. package/skills/jgengine-combat/reference.md +24 -2
  384. package/skills/jgengine-gameplay/SKILL.md +63 -0
  385. package/skills/jgengine-gameplay/api.md +583 -463
  386. package/skills/jgengine-gameplay/capabilities.md +92 -0
  387. package/skills/jgengine-gameplay/recipes/device-save-status.md +46 -0
  388. package/skills/jgengine-gameplay/recipes/expeditions.md +108 -0
  389. package/skills/jgengine-gameplay/recipes/narrative-authoring.md +76 -0
  390. package/skills/jgengine-gameplay/recipes/paged-item-storage.md +101 -0
  391. package/skills/jgengine-gameplay/recipes/quest-authoring.md +63 -0
  392. package/skills/jgengine-gameplay/recipes/shaped-inventory.md +50 -0
  393. package/skills/jgengine-gameplay/reference-content-validation.md +74 -0
  394. package/skills/jgengine-gameplay/reference-systems.md +123 -0
  395. package/skills/jgengine-world/SKILL.md +25 -4
  396. package/skills/jgengine-world/api.md +1045 -655
  397. package/skills/jgengine-world/capabilities.md +246 -9
  398. package/skills/jgengine-world/recipes/character-animation.md +62 -0
  399. package/skills/jgengine-world/recipes/controls.md +48 -0
  400. package/skills/jgengine-world/recipes/flight-feel.md +76 -0
  401. package/skills/jgengine-world/recipes/npc-senses.md +55 -0
  402. package/skills/jgengine-world/recipes/vehicle-feel.md +87 -0
  403. package/skills/jgengine-world/reference.md +180 -4
  404. package/skills/jgengine-world/visibility.md +139 -0
@@ -1,14 +1,31 @@
1
1
  import { DEFAULT_STREAMING_SETTINGS, mergeStreamingSettings } from "./settings.js";
2
2
  import { nowMs } from "./diagnostics.js";
3
+ /** Stream shared resources with bounded load concurrency, per-tick resident-byte eviction, and explicit inactive-history cleanup. */
3
4
  export function createAssetStreamingSystem(options) {
4
- const settings = mergeStreamingSettings(DEFAULT_STREAMING_SETTINGS, options.settings ?? {});
5
+ function mergeSettings(base, patch) {
6
+ const next = mergeStreamingSettings(base, patch);
7
+ if (!Number.isSafeInteger(next.maxConcurrentLoads) || next.maxConcurrentLoads < 0) {
8
+ throw new RangeError("AssetStreamingSystem: maxConcurrentLoads must be a nonnegative safe integer");
9
+ }
10
+ if (next.maxResidentBytes !== Infinity && (!Number.isFinite(next.maxResidentBytes) || next.maxResidentBytes < 0)) {
11
+ throw new RangeError("AssetStreamingSystem: maxResidentBytes must be nonnegative and finite, or Infinity");
12
+ }
13
+ if (next.residentEvictionOrder !== "oldest" && next.residentEvictionOrder !== "largest") {
14
+ throw new RangeError("AssetStreamingSystem: residentEvictionOrder must be oldest or largest");
15
+ }
16
+ return next;
17
+ }
18
+ let settings = mergeSettings(DEFAULT_STREAMING_SETTINGS, options.settings ?? {});
5
19
  const clock = options.now ?? nowMs;
6
20
  const records = new Map();
7
21
  const queued = new Set();
22
+ const residents = new Set();
23
+ const unknownSizes = new Set();
8
24
  const signals = new Map();
9
25
  const inFlight = new Set();
10
26
  let unloadedTotal = 0;
11
27
  let cancelledTotal = 0;
28
+ let budgetEvictedTotal = 0;
12
29
  function ensure(id) {
13
30
  let record = records.get(id);
14
31
  if (record === undefined) {
@@ -31,29 +48,56 @@ export function createAssetStreamingSystem(options) {
31
48
  record.state = "loading";
32
49
  const signal = { cancelled: false };
33
50
  signals.set(record.id, signal);
34
- const promise = options
35
- .load(record.id, signal)
51
+ let loading;
52
+ try {
53
+ loading = options.load(record.id, signal);
54
+ }
55
+ catch (error) {
56
+ loading = Promise.reject(error);
57
+ }
58
+ const promise = loading
36
59
  .then((result) => {
37
- signals.delete(record.id);
38
- if (signal.cancelled || !records.has(record.id)) {
39
- record.state = "unloaded";
60
+ if (signal.cancelled || records.get(record.id) !== record) {
61
+ options.unload?.(record.id);
40
62
  return;
41
63
  }
42
64
  record.state = "loaded";
43
- record.bytes = result.bytes ?? 0;
65
+ const knownSize = typeof result.bytes === "number" && Number.isFinite(result.bytes) && result.bytes >= 0;
66
+ record.bytes = knownSize ? result.bytes : 0;
67
+ if (!knownSize)
68
+ unknownSizes.add(record);
44
69
  record.value = result.value;
45
70
  record.lastActiveMs = clock();
71
+ residents.add(record);
46
72
  })
47
73
  .catch(() => {
48
- signals.delete(record.id);
49
- if (!signal.cancelled)
74
+ if (!signal.cancelled && records.get(record.id) === record)
50
75
  record.state = "error";
51
76
  })
52
77
  .finally(() => {
78
+ if (signals.get(record.id) === signal)
79
+ signals.delete(record.id);
53
80
  inFlight.delete(promise);
54
81
  });
55
82
  inFlight.add(promise);
56
83
  }
84
+ function unprotected(record) {
85
+ return record.state === "loaded" && !record.pinned && record.refCount === 0;
86
+ }
87
+ function compareEviction(a, b) {
88
+ if (settings.residentEvictionOrder === "largest" && a.bytes !== b.bytes)
89
+ return b.bytes - a.bytes;
90
+ return a.lastActiveMs - b.lastActiveMs || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
91
+ }
92
+ function unload(record) {
93
+ options.unload?.(record.id);
94
+ residents.delete(record);
95
+ unknownSizes.delete(record);
96
+ record.state = "unloaded";
97
+ record.bytes = 0;
98
+ record.value = undefined;
99
+ unloadedTotal += 1;
100
+ }
57
101
  function evictable(record, now) {
58
102
  if (record.state !== "loaded")
59
103
  return false;
@@ -92,29 +136,45 @@ export function createAssetStreamingSystem(options) {
92
136
  },
93
137
  tick() {
94
138
  const now = clock();
95
- if (queued.size > 0) {
139
+ if (queued.size > 0 && signals.size < settings.maxConcurrentLoads) {
96
140
  const pending = [];
97
141
  for (const id of queued) {
98
142
  const record = records.get(id);
99
- if (record !== undefined)
143
+ if (record !== undefined && !signals.has(id))
100
144
  pending.push(record);
101
145
  }
102
146
  pending.sort((a, b) => b.priority - a.priority);
103
- const budget = Math.min(settings.maxLoadsPerFrame, pending.length);
104
- for (let i = 0; i < budget; i += 1)
105
- startLoad(pending[i]);
147
+ const budget = Math.min(settings.maxLoadsPerFrame, settings.maxConcurrentLoads - signals.size, pending.length);
148
+ for (let i = 0; i < budget && signals.size < settings.maxConcurrentLoads; i += 1) {
149
+ const record = pending[i];
150
+ if (queued.has(record.id) && records.get(record.id) === record && !signals.has(record.id))
151
+ startLoad(record);
152
+ }
106
153
  }
154
+ let bytes = 0;
155
+ for (const record of residents)
156
+ bytes += record.bytes;
107
157
  let unloads = 0;
108
- for (const record of records.values()) {
158
+ while (bytes > settings.maxResidentBytes && unloads < settings.maxUnloadsPerFrame) {
159
+ let candidate;
160
+ for (const record of residents) {
161
+ if (record.bytes > 0 && unprotected(record) && (candidate === undefined || compareEviction(record, candidate) < 0))
162
+ candidate = record;
163
+ }
164
+ if (candidate === undefined)
165
+ break;
166
+ const releasedBytes = candidate.bytes;
167
+ unload(candidate);
168
+ bytes -= releasedBytes;
169
+ budgetEvictedTotal += 1;
170
+ unloads += 1;
171
+ }
172
+ for (const record of residents) {
109
173
  if (unloads >= settings.maxUnloadsPerFrame)
110
174
  break;
111
175
  if (!evictable(record, now))
112
176
  continue;
113
- options.unload?.(record.id);
114
- record.state = "unloaded";
115
- record.bytes = 0;
116
- record.value = undefined;
117
- unloadedTotal += 1;
177
+ unload(record);
118
178
  unloads += 1;
119
179
  }
120
180
  },
@@ -127,7 +187,7 @@ export function createAssetStreamingSystem(options) {
127
187
  return;
128
188
  }
129
189
  const signal = signals.get(assetId);
130
- if (signal !== undefined) {
190
+ if (signal !== undefined && !signal.cancelled) {
131
191
  signal.cancelled = true;
132
192
  const record = records.get(assetId);
133
193
  if (record !== undefined)
@@ -135,6 +195,9 @@ export function createAssetStreamingSystem(options) {
135
195
  cancelledTotal += 1;
136
196
  }
137
197
  },
198
+ retune(patch) {
199
+ settings = mergeSettings(settings, patch);
200
+ },
138
201
  stateOf(assetId) {
139
202
  return records.get(assetId)?.state;
140
203
  },
@@ -144,8 +207,16 @@ export function createAssetStreamingSystem(options) {
144
207
  record(assetId) {
145
208
  return records.get(assetId);
146
209
  },
210
+ forget(assetId) {
211
+ const record = records.get(assetId);
212
+ if (record === undefined || record.pinned || record.refCount > 0 || signals.has(assetId) || queued.has(assetId))
213
+ return false;
214
+ if (record.state !== "unloaded" && record.state !== "error")
215
+ return false;
216
+ return records.delete(assetId);
217
+ },
147
218
  stats() {
148
- let queuedCount = 0, loading = 0, loaded = 0, errored = 0, bytes = 0;
219
+ let queuedCount = 0, loading = 0, loaded = 0, errored = 0, bytes = 0, protectedBytes = 0, unknownSizeLoaded = 0;
149
220
  for (const record of records.values()) {
150
221
  switch (record.state) {
151
222
  case "queued":
@@ -157,6 +228,10 @@ export function createAssetStreamingSystem(options) {
157
228
  case "loaded":
158
229
  loaded += 1;
159
230
  bytes += record.bytes;
231
+ if (record.pinned || record.refCount > 0)
232
+ protectedBytes += record.bytes;
233
+ if (unknownSizes.has(record))
234
+ unknownSizeLoaded += 1;
160
235
  break;
161
236
  case "error":
162
237
  errored += 1;
@@ -172,6 +247,11 @@ export function createAssetStreamingSystem(options) {
172
247
  inFlight: inFlight.size,
173
248
  cancelled: cancelledTotal,
174
249
  bytes,
250
+ records: records.size,
251
+ protectedBytes,
252
+ unknownSizeLoaded,
253
+ overBudgetBytes: Math.max(0, bytes - settings.maxResidentBytes),
254
+ budgetEvicted: budgetEvictedTotal,
175
255
  };
176
256
  },
177
257
  applyTo(stats) {
@@ -190,12 +270,16 @@ export function createAssetStreamingSystem(options) {
190
270
  clear() {
191
271
  for (const signal of signals.values())
192
272
  signal.cancelled = true;
273
+ const loaded = [...records.values()].filter((record) => record.state === "loaded").map((record) => record.id);
193
274
  records.clear();
194
275
  queued.clear();
195
- signals.clear();
196
- inFlight.clear();
276
+ residents.clear();
277
+ unknownSizes.clear();
278
+ budgetEvictedTotal = 0;
197
279
  unloadedTotal = 0;
198
280
  cancelledTotal = 0;
281
+ for (const id of loaded)
282
+ options.unload?.(id);
199
283
  },
200
284
  };
201
285
  }
@@ -23,11 +23,17 @@ export interface StreamingSettings {
23
23
  readonly enabled: boolean;
24
24
  /** Extra world units around the camera whose assets are preloaded ahead of visibility. */
25
25
  readonly preloadMargin: number;
26
- /** Seconds an asset must stay outside the active area before it is eligible for unload. */
26
+ /** Idle unload delay; resident-byte pressure can evict unprotected assets sooner. */
27
27
  readonly unloadGraceSeconds: number;
28
28
  readonly maxLoadsPerFrame: number;
29
+ /** Maximum unresolved loads, including cancelled work until its loader settles. Zero pauses new loads. */
30
+ readonly maxConcurrentLoads: number;
29
31
  readonly maxUnloadsPerFrame: number;
30
- /** Assets at or below this byte size are kept resident once loaded (small shared assets). */
32
+ /** Resident-byte target, enforced on ticks within maxUnloadsPerFrame; protected assets may exceed it. */
33
+ readonly maxResidentBytes: number;
34
+ /** Budget eviction order. Ties use oldest activity then asset id for deterministic selection. */
35
+ readonly residentEvictionOrder: "oldest" | "largest";
36
+ /** Small shared assets survive idle unloading, but remain eligible under resident-byte pressure. */
31
37
  readonly keepResidentBytes: number;
32
38
  }
33
39
  export declare const DEFAULT_STREAMING_SETTINGS: StreamingSettings;
@@ -13,8 +13,11 @@ export const DEFAULT_STREAMING_SETTINGS = {
13
13
  preloadMargin: 32,
14
14
  unloadGraceSeconds: 10,
15
15
  maxLoadsPerFrame: 4,
16
+ maxConcurrentLoads: 4,
16
17
  maxUnloadsPerFrame: 2,
17
18
  keepResidentBytes: 64 * 1024,
19
+ maxResidentBytes: Infinity,
20
+ residentEvictionOrder: "oldest",
18
21
  };
19
22
  const EMPTY = {};
20
23
  /** Merge override layers by precedence: earlier arguments win. Pass object, then layer, then scene, then global. */
@@ -1,4 +1,4 @@
1
- import type { LodBand } from "../world/lod.js";
1
+ import type { LodBand, LodSchedulerState } from "../world/lod.js";
2
2
  /**
3
3
  * Simulation culling is a SEPARATE, opt-in system from render culling. Render culling only
4
4
  * decides what is drawn; this decides whether a low-priority off-screen entity updates this
@@ -23,6 +23,11 @@ export interface SimulationDecision {
23
23
  /** Seconds of accumulated time delivered when `update` is true (for catch-up integration). */
24
24
  elapsed: number;
25
25
  }
26
+ /** Plain JSON state of a {@link SimulationCuller}: the enabled flag and each id's throttle accumulator. */
27
+ export interface SimulationCullerState {
28
+ enabled: boolean;
29
+ scheduler: LodSchedulerState;
30
+ }
26
31
  export interface SimulationCuller {
27
32
  enabled(): boolean;
28
33
  setEnabled(value: boolean): void;
@@ -30,5 +35,7 @@ export interface SimulationCuller {
30
35
  step(id: string, distance: number, dt: number): SimulationDecision;
31
36
  forget(id: string): void;
32
37
  clear(): void;
38
+ snapshot(): SimulationCullerState;
39
+ restore(next: SimulationCullerState): void;
33
40
  }
34
41
  export declare function createSimulationCuller(options?: SimulationCullingOptions): SimulationCuller;
@@ -32,5 +32,12 @@ export function createSimulationCuller(options = {}) {
32
32
  clear() {
33
33
  scheduler.clear();
34
34
  },
35
+ snapshot() {
36
+ return { enabled, scheduler: scheduler.snapshot() };
37
+ },
38
+ restore(next) {
39
+ enabled = next.enabled;
40
+ scheduler.restore(next.scheduler);
41
+ },
35
42
  };
36
43
  }
@@ -10,6 +10,25 @@ export interface SpatialIndexOptions {
10
10
  */
11
11
  readonly maxCellSpan?: number;
12
12
  }
13
+ /** Integer cell bounds an object covers, inclusive on both ends. */
14
+ export interface SpatialCellRange {
15
+ x0: number;
16
+ y0: number;
17
+ z0: number;
18
+ x1: number;
19
+ y1: number;
20
+ z1: number;
21
+ }
22
+ /**
23
+ * Plain JSON state of a {@link SpatialIndex}. Cells and their ids keep insertion order, so a restored
24
+ * index returns query results in the same order.
25
+ */
26
+ export interface SpatialIndexState {
27
+ /** Per object: its cell range (`null` when oversized) and whether it was inserted as dynamic. */
28
+ entries: [id: string, range: SpatialCellRange | null, dynamic: boolean][];
29
+ cells: [x: number, y: number, z: number, ids: string[]][];
30
+ oversized: string[];
31
+ }
13
32
  /**
14
33
  * A uniform 3D spatial hash the renderer and streaming system query for potentially-visible
15
34
  * objects instead of scanning the whole scene. Objects are keyed by their world AABB into
@@ -39,6 +58,8 @@ export interface SpatialIndex {
39
58
  }[];
40
59
  cellSize(): number;
41
60
  clear(): void;
61
+ snapshot(): SpatialIndexState;
62
+ restore(next: SpatialIndexState): void;
42
63
  }
43
64
  export declare function createSpatialIndex(options?: SpatialIndexOptions): SpatialIndex;
44
65
  /** Precise AABB-vs-AABB test re-exported for callers refining a broad-phase result. */
@@ -206,6 +206,22 @@ export function createSpatialIndex(options = {}) {
206
206
  entries.clear();
207
207
  stamps.clear();
208
208
  },
209
+ snapshot() {
210
+ return {
211
+ entries: [...entries].map(([id, entry]) => [id, entry.range === null ? null : { ...entry.range }, entry.dynamic]),
212
+ cells: [...cells.values()].map((bucket) => [bucket.x, bucket.y, bucket.z, [...bucket.ids]]),
213
+ oversized: [...oversized],
214
+ };
215
+ },
216
+ restore(next) {
217
+ this.clear();
218
+ for (const [id, range, dynamic] of next.entries)
219
+ entries.set(id, { range: range === null ? null : { ...range }, dynamic });
220
+ for (const [x, y, z, ids] of next.cells)
221
+ cells.set(packCell(x, y, z), { x, y, z, ids: new Set(ids) });
222
+ for (const id of next.oversized)
223
+ oversized.add(id);
224
+ },
209
225
  };
210
226
  }
211
227
  /** Precise AABB-vs-AABB test re-exported for callers refining a broad-phase result. */
@@ -68,6 +68,7 @@ export function createVisibilitySystem(options) {
68
68
  index.remove(id);
69
69
  bounds.delete(id);
70
70
  records.delete(id);
71
+ consideredStamp.delete(id);
71
72
  }
72
73
  return alwaysVisibleList;
73
74
  }
@@ -0,0 +1,110 @@
1
+ import type { LootPipeline, LootResolution } from "../game/lootPipeline.js";
2
+ import type { Drop } from "../game/lootTable.js";
3
+ import { type RandomSeed } from "../random/rng.js";
4
+ /** Timestamped serializable event. `at` is epoch milliseconds, compatible with `appendFeed`. */
5
+ export interface ExpeditionEvent {
6
+ at: number;
7
+ /** Lifecycle kinds are loot/hazard/supply/death/recall/return; encounter notices may use caller kinds. */
8
+ kind: string;
9
+ text: string;
10
+ /** Accepted drops; `loot.drops` records the full roll before the item-unit capacity bound. */
11
+ drops?: readonly Drop[];
12
+ loot?: LootResolution;
13
+ hpDelta?: number;
14
+ exposureDelta?: number;
15
+ supply?: string;
16
+ }
17
+ /** Plain saveable expedition data. Persist this whole value, including the RNG cursor and tick frontier. */
18
+ export interface ExpeditionState {
19
+ readonly id: string;
20
+ readonly status: "exploring" | "returning" | "home" | "dead";
21
+ readonly startedAtMs: number;
22
+ /** Last completed event tick (arrival time after return), never an unprocessed catch-up target. */
23
+ readonly lastSettledMs: number;
24
+ readonly elapsedMs: number;
25
+ readonly returnUntilMs: number | null;
26
+ readonly hp: number;
27
+ /** Caller-interpreted hazard meter; its meaning and effective max-HP policy are injected. */
28
+ readonly exposure: number;
29
+ readonly supplies: Readonly<Record<string, number>>;
30
+ /** Counts are merged by item/currency id; currency does not consume item capacity. */
31
+ readonly carried: readonly Drop[];
32
+ readonly log: readonly ExpeditionEvent[];
33
+ readonly seed: string;
34
+ readonly cursor: RandomSeed;
35
+ }
36
+ /** Dispatch data, detached from the caller's supply record. All timestamps are epoch milliseconds. */
37
+ export interface ExpeditionDispatch {
38
+ id: string;
39
+ startAtMs: number;
40
+ hp: number;
41
+ exposure?: number;
42
+ supplies?: Readonly<Record<string, number>>;
43
+ seed: string;
44
+ }
45
+ /** One encounter's mechanical effects and optional caller-authored notices. */
46
+ export interface ExpeditionHazard {
47
+ damage?: number;
48
+ exposure?: number;
49
+ notices?: readonly {
50
+ kind: string;
51
+ text: string;
52
+ }[];
53
+ }
54
+ /** Ordered auto-consumption rule: spends one finite supply only when its declared effect changes a vital. */
55
+ export interface ExpeditionSupplyRule {
56
+ key: string;
57
+ when: (state: ExpeditionState) => boolean;
58
+ restoreHp?: number;
59
+ clearExposure?: number;
60
+ }
61
+ /** Runtime policy, supplied on each transition and never saved. Callbacks must be pure. */
62
+ export interface ExpeditionConfig<TCtx> {
63
+ /** Positive whole milliseconds between events; cadence retuning anchors at the last completed tick. */
64
+ tickMs: number;
65
+ loot: LootPipeline<TCtx>;
66
+ lootCtx: (state: ExpeditionState) => TCtx;
67
+ maxHp: (state: ExpeditionState) => number;
68
+ hazard?: (state: ExpeditionState, rng: () => number) => ExpeditionHazard;
69
+ supplies?: readonly ExpeditionSupplyRule[];
70
+ /** Nonnegative fraction of exploring elapsed time spent returning. */
71
+ returnFraction: number;
72
+ /** Positive whole item units; currency is carried without consuming item slots. */
73
+ carryCap: number;
74
+ /** Bounded work per call, default 10,000; excess ticks remain unsettled for the next call. */
75
+ maxTicksPerSettle?: number;
76
+ /** Newest event count retained by appendFeed, default 200; rewards and RNG are retained separately. */
77
+ logLimit?: number;
78
+ /** Optional alternative persisted RNG recurrence; returns a [0,1) value and its next cursor. */
79
+ randomStep?: (cursor: RandomSeed) => readonly [number, RandomSeed];
80
+ /** All lifecycle prose is caller-authored; omit for headless logs with empty text. */
81
+ describe?: (event: Omit<ExpeditionEvent, "text">, state: ExpeditionState) => string;
82
+ }
83
+ /**
84
+ * Dispatch plain expedition state with a persisted seeded cursor; no clock, scheduler or storage is owned.
85
+ *
86
+ * @capability expedition-dispatch dispatch a saveable timed away mission with finite supplies and a seeded RNG cursor
87
+ */
88
+ export declare function dispatchExpedition(input: ExpeditionDispatch): ExpeditionState;
89
+ /**
90
+ * Replay due event ticks using the existing stepped catch-up primitive. Order is loot → hazard → ordered
91
+ * supplies → death → capacity recall. Unprocessed ticks retain their frontier; returning never rolls or
92
+ * takes damage. Auto-recall uses the triggering tick's time, including offline arrival in the same call.
93
+ *
94
+ * @capability expedition-settle settle bounded offline expedition ticks without losing supplies rewards or RNG continuity
95
+ */
96
+ export declare function settleExpedition<TCtx>(config: ExpeditionConfig<TCtx>, state: ExpeditionState, nowMs: number): ExpeditionState;
97
+ /**
98
+ * Settle first, then recall safely. If the catch-up budget leaves due exploring ticks, return that state
99
+ * without recalling; repeat at the same target until the frontier catches up. Dead state never revives.
100
+ *
101
+ * @capability expedition-recall begin a safe fractional-time return after settling the pending expedition frontier
102
+ */
103
+ export declare function recallExpedition<TCtx>(config: ExpeditionConfig<TCtx>, state: ExpeditionState, nowMs: number): ExpeditionState;
104
+ /**
105
+ * Settle first, then complete a live return instantly. Caller owns payment/authorization; pending ticks
106
+ * remain unsettled when the budget is exhausted, and dead/home state is never changed.
107
+ *
108
+ * @capability expedition-return complete an authorized instant return without skipping unsettled ticks or reviving death
109
+ */
110
+ export declare function returnExpeditionNow<TCtx>(config: ExpeditionConfig<TCtx>, state: ExpeditionState, nowMs: number): ExpeditionState;