@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
@@ -0,0 +1,74 @@
1
+ # Validate references and declared progression
2
+
3
+ Run these pure validators during authoring, build or CI, never per frame. Decode
4
+ external JSON into typed definitions first. Preserve authored array order and
5
+ stable ids so repeated validation returns identical located diagnostics. Each
6
+ `ContentIssue` carries `contentId`, a caller document `path`, and a `repair` action.
7
+ For a bounded generated batch, validate its dependency-complete reviewed catalog,
8
+ repair the located fields, then validate again before registration.
9
+
10
+ `validateContentReferences` (`@jgengine/core/game/contentValidation`) indexes
11
+ `{ kind, id, path }` definitions once and checks located
12
+ `{ kind, id, path, contentId }` references. A namespace can describe a game-owned
13
+ role: referencing a `questgiver` checks the role rather than merely the existence
14
+ of an NPC. Do not derive roles from names or parse dialogue prose. Validate explicit
15
+ dialogue command arguments against the appropriate namespace.
16
+ For relationships stricter than existence, set a reference's `allowedIds` from
17
+ the game's declared rule, such as this giver's quests or this record's key.
18
+ An existing but disallowed id reports `inconsistent-reference`; omitted policy
19
+ does not infer restrictions from names, prose or ordering.
20
+
21
+ `validateRecipeCatalog` (`@jgengine/core/crafting/recipeCatalog`) checks native
22
+ `RecipeDef` rows and optional item, station and unlock lookups. Build lookup Sets
23
+ once in the adapter. Empty outputs are valid for benefits applied by game code.
24
+ Zero and fractional counts are valid; enforce discrete units in game policy.
25
+ Duplicate input rows reject because crafting checks each row separately; merge
26
+ their counts. Prices, rarity, ingredient scarcity and recipe cycles are game-owned.
27
+ Compose existing `validateQuestCatalog` and `validateDialogueGraph` for their native
28
+ structures; do not replace the quest journal or conversation model.
29
+
30
+ ```ts
31
+ import { validateContentProgression } from "@jgengine/core/game/contentValidation";
32
+
33
+ const result = validateContentProgression({
34
+ initial: ["material:wire", "material:seals", "place:home"],
35
+ rules: [{
36
+ id: "sealed-tank",
37
+ path: "/refits/tank",
38
+ requires: ["material:wire", "material:seals", "place:home"],
39
+ provides: ["benefit:sealed-tank"],
40
+ }],
41
+ required: [{ id: "benefit:sealed-tank", contentId: "tank", path: "/refits/tank" }],
42
+ closedWorld: true,
43
+ });
44
+ ```
45
+
46
+ Facts are opaque game-owned strings. All facts in one rule are necessary;
47
+ alternative sources are separate rules. An initial fact or a reachable source
48
+ can seed an intentional cycle. Missing seeds block cycles; cycles themselves
49
+ are never forbidden. `closedWorld: true` asserts all possible sources have been
50
+ declared and makes blocked rules/required facts errors. The default leaves them
51
+ warnings. Legitimate external suppliers belong in `initial` or a source rule,
52
+ not a blanket declaration of every catalog item as available.
53
+
54
+ Translate skill gates into milestone facts in the game adapter. A repeatable
55
+ action requiring skill 0 and training to 50 can provide milestones through 50;
56
+ it cannot provide the next source's skill-100 fact. Derive milestones from actual
57
+ gates and training caps rather than inventing thousands of skill nodes. Bound the
58
+ analysis to the reviewed content and dependency edges. The engine visits each
59
+ rule and dependency edge with an iterative queue rather than rescanning a catalog
60
+ until convergence.
61
+
62
+ This proves potential availability only. It does not prove affordable quantities,
63
+ repeatability, inventory capacity, consumed prerequisites, exclusive choices,
64
+ chronology, station proximity, story coherence or obtainable rewards in actual play.
65
+ Declare distinct route/branch facts when combining branches would be misleading,
66
+ and drive representative choices through the actual commands with save/reload.
67
+ Keep story facts, terms, assets and economy decisions in the game. Remove older
68
+ generic reference/topology algorithms when adopting these checks; retain custom
69
+ semantic and durable-save policy validators.
70
+
71
+ Verify built tarball imports and the actual adopter in an isolated scratch copy.
72
+ Keep the candidate on a prepared branch until a verified published package contains
73
+ these APIs, then adopt through the games workspace catalog and lockfile together.
74
+ Never route game imports to engine source or add per-game version pins.
@@ -2,6 +2,23 @@
2
2
 
3
3
  Single public authoring path: `defineGame({ systems, loop?, … })` from `@jgengine/shell/defineGame`. Systems are meaningful capabilities — not micro-ticks.
4
4
 
5
+ ## Authoritative state
6
+
7
+ Use `ctx.state()` / `ctx.restore(state)` for detached whole-world persistence, including economy, clock, movement pose, possession, progression and registered system saves. These work without `persist` or a save backend. `ctx.snapshot()` / `ctx.hydrate()` remain client replication and omit save-only modules. `createRuntimeSave({ target: ctx, backend })` selects the authoritative pair automatically; existing snapshot-only targets still work.
8
+
9
+ Restore after initialization has registered every system. Missing keys in older saves retain initialized values; unavailable historical economy/progression cannot be recovered by the engine. Keep a game's legacy migration until its older saves have been converted. Simulation tick and pose-buffer state persist, but callbacks, timers and game-owned closures must be registered/reconstructed at boot or exposed through a system save module.
10
+
11
+ Declare `persist: { version, migrate(data, fromVersion) }` to convert incompatible
12
+ older whole-world saves before restoration. Raw payloads use version 0; matching
13
+ versions bypass the hook. Throw to reject a missing historical runtime module:
14
+ load returns false, leaving the initialized world and stored
15
+ save untouched. A version number alone preserves compatible mismatch loading;
16
+ it is not a rejection gate. Migration exceptions retain the save store's existing
17
+ decode fallback to initial data with idle status; they are not backend errors.
18
+ Explicit context `save` options override `persist`.
19
+
20
+ `ctx.sim.advance(realDt, (stepDt, tick, gameDt) => ...)` owns advancement of `ctx.time` once per simulation step. Use the third argument for scaled gameplay time and `stepDt` for movement; remove manual `ctx.time.advance` calls inside simulation callbacks. Movement prediction opts out with `{ advanceTime: false }` and must not run authoritative gameplay stages. Standalone clocks retain their explicit `advance` API.
21
+
5
22
  ## Portable XP and leveling
6
23
 
7
24
  `leveling` (`@jgengine/core/game/progression`) is usable without a scheduled
@@ -11,6 +28,36 @@ and level state, then emits every reached level in ascending order. State stays
11
28
  in the caller's save format and round-trips as ordinary JSON. See the
12
29
  [portable XP/leveling recipe](recipes/portable-xp-leveling.md).
13
30
 
31
+ ## Coherent authored content
32
+
33
+ Keep stable ids and canonical facts for characters, factions, places, and world rules in the game's authored data. Record each chapter's prerequisites, consequences, and which facts it may introduce or change. The game's creative pillars, story voice, content palette, and desired player experience come from its author; generated prose, items, art, and assets must serve those constraints. Reuse constrained generation and validation code across games while each game owns its content and visual identity; do not fill catalogs from default genre kits or mass generic content.
34
+
35
+ Generate bounded chapter or catalog batches against those facts and existing definitions. Validate references and dependencies before merging each batch, giving humans and agents precise repair locations early to reduce failed retries and speed up game creation. Preserve reviewed facts across batches instead of asking a model to recreate the world from memory. `QuestDef.requires` accepts completed quest ids or unlock ids, so dependency checks must include the game's declared unlocks rather than treating every requirement as a quest. Check reward quest ids and objective/item references against their owning catalogs too.
36
+
37
+ Use `validateQuestCatalog` (`@jgengine/core/game/questCatalog`) before registering quest batches. Declare unlocks supplied by other systems with `externalUnlocks`, and quest grants that bypass acceptance with `externallyStartedQuests`. Catalog reward unlocks are recognized automatically. `hasReference` optionally checks item, target, inventory, and currency ids against caller catalogs. Duplicate ids, missing references, and invalid quantities are errors; blocked prerequisites and dependency cycles are warnings under a model where any eligible quest may be accepted and its objectives completed. External grants can change actual reachability. Follow the [quest authoring recipe](recipes/quest-authoring.md) and `npx jgengine recipe quest-authoring` for SDK-typechecked bounded generation and repair locations.
38
+
39
+ For repeated authoring and repair, follow the [narrative authoring recipe](recipes/narrative-authoring.md). It freezes a reviewed canon revision, bounds dialogue batches and checks explicit character/fact/event-order claims before an injected semantic reviewer approves. New canon is a separate author decision.
40
+
41
+ Validate dialogue structure before opening a conversation:
42
+
43
+ ```ts
44
+ import { validateDialogueGraph, type DialogueGraph } from "@jgengine/core/game/dialogueGraph";
45
+
46
+ function reviewDialogue(graph: DialogueGraph) {
47
+ const issues = validateDialogueGraph(graph);
48
+ const errors = issues.filter((issue) => issue.severity === "error");
49
+ return { publishable: errors.length === 0, issues };
50
+ }
51
+ ```
52
+
53
+ The validator locates duplicate ids, missing start/choice targets, unreachable nodes, and nodes without a route to an ending in linear time without recursive traversal. Loops with an exit are valid. Review warnings against intended entry points and conversation behavior; unreachable nodes may be entered with `goTo`, and closed loops may be deliberate. Run validation on authored batches, outside the frame loop.
54
+
55
+ Structural validity cannot establish story coherence. Review generated content for contradictions with canonical facts, character motivations, chronology, and meaningful consequences; play representative paths and check that choices support the intended experience. Large item counts need useful distinctions, economy balance, discoverability, and bounded runtime lookup. Counting generated items or passing reference checks alone does not establish those qualities.
56
+
57
+ Quest item rewards use a whole-batch grant before XP, currency, and unlocks. `ctx.game.quest` stages every item against the declared inventories and commits only when all fit, including cumulative capacity in one bag. Capacity/kind/unknown-inventory rejections leave inventories and quest status unchanged, so the player can make room and retry. Inventory commits still notify subscribers synchronously; this does not roll back thrown observer exceptions or arbitrary callback side effects.
58
+
59
+ Custom `createQuestJournal` dependencies and `applyQuestRewards` appliers must supply `grantItems` for multiple item rewards. The callback grants the entire batch or returns a rejection without writes; implement staging or a transaction in the owning store. Legacy `grantItem` remains supported for a single reward. Multiple rewards without `grantItems` reject before any grant. Keep callbacks nonthrowing; external stores own exception handling and durable transaction boundaries.
60
+
14
61
  ## API
15
62
 
16
63
  ```ts
@@ -63,3 +110,79 @@ Default stages: fixed `input → movement → combat → ai → activities → c
63
110
 
64
111
  - **Save / replicate** — system modules register via `ctx.game.registerSave` / `registerReplicate` at install.
65
112
  - **Reset / dispose** — `loop.onReset` / `loop.onDispose` (composed) run system hooks.
113
+
114
+ Each context owns its installed schedules and listeners, even when worlds share
115
+ one game definition. Retirement removes listeners, disposes systems in reverse
116
+ install order, then invokes the classic loop's disposal hook (including shell
117
+ environment cleanup). Every cleanup is attempted; the first thrown value is
118
+ rethrown afterward. Reentrant or repeated disposal does not invoke hooks again.
119
+ Retired installed handles ignore tick, reset and manual work. `onInit` after
120
+ retirement starts a fresh schedule/listener lifecycle; `onReset` resets an active
121
+ lifecycle and does not reinstall it. Failed installation retires every entered
122
+ system, including one whose `create` throws, and acquired listeners before
123
+ rethrowing the startup error. The caller still retires the classic loop (the
124
+ shell does so on initialization failure). Save/replication registrations are not
125
+ transactional or withdrawn by disposal; discard a failed context, and use a fresh
126
+ context when rebooting systems with registered modules.
127
+
128
+ ## Snapshot and restore on stateful handles
129
+
130
+ These handles hand back a plain JSON `snapshot()` that later ticks do not mutate, and take it back with `restore(next)`, so a host, save file or replay can rewind them bit-exactly: `game/lootTable` `createLootRegistry` (registered tables; not JSON when an entry uses `generate`), `game/toasts` `createToastQueue`, `game/vfxInstance` `createVfxInstanceStore` (restore emits `stop` then `upsert` so the renderer follows), `session/roundState` `createRoundState` (`RoundSnapshot` now carries `pendingWinner`), `input/lookChannel` `createLookChannel`, and `input/pointer` `createDragCapture` (`state()` out, `restore(state | null)` in).
131
+
132
+ ## Staffed production
133
+
134
+ `stationOutputRate` (`@jgengine/core/work/staffedStation`) converts a plain staffing
135
+ snapshot to cycles per game-second: `(base + perStat * sum(worker.stat)) * efficiency`.
136
+ Only the first `floor(slots)` workers contribute, in caller order. Empty staffing
137
+ keeps base output; set `base: 0` to require workers. Efficiency defaults to one and
138
+ clamps to 0…1. Negative/nonfinite contributions are zero, nonfinite slots admit no
139
+ workers, and nonfinite efficiency or an overflowing result returns zero.
140
+
141
+ The caller owns unique worker ids, assignment/release policy, stat selection,
142
+ modifiers, happiness, and tuning. Resolve numeric contributions from your stat
143
+ store before writing staffing: one station might read `stats.get("strength")`,
144
+ another `stats.get("agility")` with equipment modifiers. Invalid contributions
145
+ still occupy their ordered slot; the function does not promote overflow workers,
146
+ allocate collections, or mutate saved staffing.
147
+
148
+ ```ts
149
+ import { stationOutputRate, type StaffedStation } from "@jgengine/core/work/staffedStation";
150
+ import { createProductionState, productionBuilding, tickProduction, type ProductionState } from "@jgengine/core/crafting/production";
151
+ import { defineStore } from "@jgengine/core/store/defineStore";
152
+ import { defineSystem } from "@jgengine/core/game/defineSystem";
153
+
154
+ const room = defineStore<{
155
+ staffing: StaffedStation;
156
+ efficiency: number;
157
+ production: ProductionState;
158
+ }>("workshop", () => ({
159
+ staffing: { stationId: "workshop", slots: 2, workers: [] },
160
+ efficiency: 1,
161
+ production: createProductionState(),
162
+ }));
163
+ const recipe = productionBuilding({
164
+ id: "workshop", outputs: [{ itemId: "supplies", count: 1 }], rate: 0,
165
+ });
166
+ export const staffedProduction = defineSystem({
167
+ id: "staffed-production",
168
+ tick: { type: "fixed", rate: 4 },
169
+ update(ctx, dt) {
170
+ room.update(ctx, previous => ({ ...previous,
171
+ production: tickProduction({ ...recipe,
172
+ rate: stationOutputRate(previous.staffing, {
173
+ base: 0, perStat: 0.5, efficiency: previous.efficiency,
174
+ }),
175
+ }, previous.production, { dt }),
176
+ }));
177
+ },
178
+ reset(ctx) { room.clear(ctx); },
179
+ });
180
+ ```
181
+
182
+ Install the system via `defineGame({ systems: [staffedProduction] })`; write the
183
+ caller-resolved worker snapshot with `room.update`. Production input buffers,
184
+ output counts, partial-cycle seconds, staffing, and efficiency remain plain data
185
+ in the same store. `ctx.state()`/`ctx.restore()` save and replace that data; reset
186
+ restores the declared initial room. Persist progress, not just staffing, to avoid
187
+ restarting an in-flight batch. Input reservation and power gating continue to use
188
+ `feedProduction` and `tickProduction({ ...recipe, rate }, state, { dt, powered })`.
@@ -9,30 +9,42 @@ description: Build spatial runtime, movement, interaction, AI, and environments.
9
9
 
10
10
  This skill owns runtime spatial behavior: authored-scene consumption, environments, movement, input mapping, interaction, AI, navigation, physics, visibility, time, and spatial audio. Scene creation and placement stay in `jgengine-editor`; presentation stays in `jgengine-ui`.
11
11
 
12
- Search [capabilities.md](capabilities.md) by intent before designing a primitive. Use [api.md](api.md) for exact exports and [reference.md](reference.md) for environment, camera, navigation, physics, audio, and authored-scene recipes.
12
+ Search [capabilities.md](capabilities.md) by intent before designing a primitive. Use [api.md](api.md) for exact exports and [reference.md](reference.md) for environment, camera, navigation, physics, audio, and authored-scene recipes. Culling and streaming overrides are in [visibility.md](visibility.md).
13
13
 
14
14
  For a *connected* walkthrough that wires several primitives into a running loop, read the goal-oriented recipes under [recipes/](recipes/) — organized by composition seam (what connects to what), never by genre. Start there before reading a game's source to learn how pieces fit; a hybrid game is just a different composition of the same primitives.
15
15
 
16
16
  - [recipes/commanding-entities.md](recipes/commanding-entities.md) — select → order → tick → resolve: direct command over a group of entities (the command loop behind squad control, base-defense, herding, autobattle, or a mutating game's real-time phase).
17
+ - [recipes/npc-senses.md](recipes/npc-senses.md) — perceive → remember → decide → route: perception memory written into a decision-graph blackboard, with nav-mesh routing (guards, mobs, pedestrians, police response).
17
18
  - [recipes/building-kit.md](recipes/building-kit.md) — bind the facade generator's part slots to real models: one massing, swappable art per style, blocks where the kit is silent.
19
+ - [recipes/vehicle-feel.md](recipes/vehicle-feel.md) — feel target → handling metrics → physical knobs for a ground vehicle, plus the camera, sound and rumble hooks that hang off its telemetry.
20
+ - [recipes/flight-feel.md](recipes/flight-feel.md) — an aircraft as physical numbers: surfaces, inertia and engine, with the symptom → knob table for how it flies.
21
+ - [recipes/controls.md](recipes/controls.md) — actions → layered contexts that rebind live → keyboard, touch and gamepad on the same actions → per-axis feel.
22
+ - [recipes/character-animation.md](recipes/character-animation.md) — clips → graph → rig → ground: modular instance visibility, data-driven state machines, triggers and clip events, root motion, foot IK that keeps feet on slopes, and instanced crowds.
18
23
 
19
24
  ## Canonical workflows
20
25
 
21
26
  ### Declare the place
22
27
 
23
- A world is the place you play in: substrate + laws, via `world()` from `@jgengine/core/world/place` — `{ id, ground: { mode: flat|round|voxel|board, size, surface?, generator? }, physics? }`. Thin is complete: flat with `Infinity` axes for 3D, `board` for 2D, or omit `world` for pure UI/rules games. Never put seed, sky, or vegetation in a world definition — seeds derive from world id + save/run (`seedForPlace`); sky look and foliage scatter are editor-authored scene content, with the engine default sky when the document has none. `ground.surface` carries matter/feel laws (metal vs slime vs felt) that the same rule systems read — swap the surface, not the rules. See [reference.md](reference.md) for the full shape; `environment()` is the legacy consumption path for editor/preset-written scene data, never the starter.
28
+ A world is the place you play in: substrate + laws, via `world()` from `@jgengine/core/world/place` — `{ id, ground: { mode: flat|round|voxel|board, size, surface?, generator? }, physics? }`. Thin is complete: flat with `Infinity` axes for 3D, `board` for 2D, or omit `world` for pure UI/rules games. Never put seed, sky, or vegetation in a world definition — seeds derive from world id + save/run (`seedForPlace`); sky look and foliage scatter are editor-authored scene content, with the engine default sky when the document has none. `ground.surface` carries matter/feel laws (metal vs slime vs felt) that the same rule systems read — swap the surface, not the rules. See [reference.md](reference.md) for the full shape; `environment()` is the consumption path for editor/preset-written scene data: a created 3D game's `world.ts` passes it the document's sculpt, sky, and clearings through `environmentContentFromDocument`, never code-declared noise or coordinates.
24
29
 
25
30
  ### Authored world
26
31
 
27
32
  1. Load the scene document through the shared authored-scene feature.
28
33
  2. Render objects, paths, terrain, foliage, and markers generically.
29
- 3. Query the same ids/layers for spawns, routes, plots, and interaction.
30
- 4. Keep derived caches rebuildable; the document remains authoritative.
34
+ 3. Query the same ids/layers for spawns, routes, plots, and interaction. The shell batches compatible static catalog props above eight placements per 24 m cell, preserving chosen models, material groups, shadows, measured colliders and object ids for picking. Interactive/custom props, per-object visual/style overrides, and animated, rigged, composed, transparent or mirrored models keep individual renderers. Runtime compatibility changes return a placement to its individual renderer. Visibility compacts each batch to the current visible placements.
35
+ 4. Collision for generated and studio content comes from its data through `ctx.world.solids`; never hand-place invisible blockers for it (see reference.md, World solids).
36
+ 5. Keep derived caches rebuildable; the document remains authoritative.
37
+
38
+ For existing `environment()` consumers, `defineGame` overlays only defined editor sky fields on the legacy sky, retaining settings the editor cannot represent; an explicit `backdrop.sky` remains authoritative.
39
+
40
+ For environment-driven surface appearance, sample only selected targets through `material/appearanceSignals`; wetness already includes shelter. Capture the assigned material's dry baseline, apply explicit wet endpoints, and restore it on unbinding. Keep wind in geometry/simulation consumers and local card backlighting separate from scene exposure. See [reference.md](reference.md#environment-fields-weather-hooks--realm-composition).
31
41
 
32
42
  ### Movement and interaction
33
43
 
34
44
  Choose input intent, controller/motor, collision/navigation, and camera as separate seams. Commands express game intent; world systems resolve motion. Interaction targets come from bounded spatial/sensor queries, not full-world scans.
35
45
 
46
+ Walk feel is data, not code. `movement.feel` sets `groundAcceleration`, `airAcceleration` and `groundFriction` (response rates, 1/s) plus `runMultiplier`, `crouchMultiplier`, jump forgiveness (`jumpBufferMs`, `coyoteMs`) and jump shape (`jumpCutFactor`, `apexGravityScale`, `fallGravityScale`, `landingRecoveryMs`), and `physics` sets `gravity` and `jumpVelocity`. The heightfield and capsule paths share these feel controls; voxel jumping retains its press-frame policy. Crouch follows supported catalog poses, and capsule standing requires headroom. Pin numeric movement behavior with `measureMovement` (`movement/movementProbe`) in a test.
47
+
36
48
  ### Stateful placed objects
37
49
 
38
50
  Per-instance state belongs on the placement, not in a game-owned map keyed by `instanceId`. Set `SceneObject.state` (opaque) through `ctx.scene.object.setState`/`patchState`; declare `slotInventory` on the catalog entry and mutate contents through `ctx.scene.object.slots`, which enforces the declared capacity and `accepts`. Both replicate and save with the object through the always-on `objects` snapshot module, and `toRuntimeObjectRow`/`fromRuntimeObjectRow` (`@jgengine/core/multiplayer`) convert to and from the host's persisted rows.
@@ -41,6 +53,14 @@ Per-instance state belongs on the placement, not in a game-owned map keyed by `i
41
53
 
42
54
  Compose perception, selection, planning/behavior, movement, and lifecycle independently. Inject randomness and scheduling. Use spatial indexes, interest tiers, or bounded candidate sets for scale.
43
55
 
56
+ For chase-to-reach and cooldown effects, attach `pursue({ aggroRadius, reach, leashRange, speed, attack })` as behavior data. The host schedules acquisition and solid-aware movement; `behaviorControl` exposes pause/reset and optional threat. Pursuit progress survives GameContext save/replication without a game-local home/cooldown map. For allies or neutral players, configure `defineGame({ pursuit: { eligible(ctx, selfId, candidateId) { /* bounded caller policy */ } } })`; the predicate receives the current world and constrains nearest, held, explicit and forced targets. Bind the receiving world's policy data before advancing after a cold restore. Omission keeps the all-player default; see the reference for faction composition. Use a decision graph and navigation actions when a route or richer perception policy is required.
57
+
58
+ NPC decisions are a `decisionGraph` behavior: the graph and its blackboard are data, actions are registered by name, and perception or game systems write facts into `behaviorControl(ctx).blackboard(id)` rather than actions querying the world. Set `thinkInterval` so crowds think a few times a second, not every frame, and release movement or claims in `onAbort`.
59
+
60
+ For a bounded local detour over movement collision geometry, use `planSolidRoute` (`nav/solidRoute`) with an indexed `solidObstaclesNear` or `sourceObstaclesNear` query. Handle `no-path` and `budget` separately; retain caller movement, goals, terrain and retry policy. See [reference.md](reference.md#local-collision-routes) for limits.
61
+
62
+ Route on a polygon nav mesh through one `createNavMeshQuery(mesh)` per mesh; price terrain and gate doors with `areaCosts` via `retune`, and keep `maxNodes` bounded so a long request returns a `partial` route instead of stalling a frame.
63
+
44
64
  ### Fallback-seam diagnostics
45
65
 
46
66
  Render seams fall back to placeholders when content is unauthored: default green ground (no environment), primitive capsule/box actors (no `entityModels`/`objectModels` mapping), stylized proxy foliage (no scatter `resolveItem`). These placeholders are sometimes intended, so runtime never changes — but a dev-only, opt-in probe (`@jgengine/core/devtools/fallbackSeams`) tells "unauthored/misconfigured" apart from "intended". The shell arms it via `armFallbackSeams(devtoolsEnabled)`; each seam reports at its choice site (`reportFallbackSeam`), and counts surface through the devtools `fallbacks` probe. Disarmed (production) it is a pure, allocation-free no-op.
@@ -52,6 +72,7 @@ Render seams fall back to placeholders when content is unauthored: default green
52
72
  - Do not duplicate editor coordinates in runtime state.
53
73
  - Public APIs accept semantic policies and caller data, not renderer mechanics or internal tuning rolls.
54
74
  - Generated environments still need deterministic data assertions; authored environments need scene-document assertions.
75
+ - Bound SFX through `PlayableGame.audio.maxVoices` and game-owned `SoundDef.priority`/`maxVoices`; choose reject or deterministic stealing with `voiceOverflow`. See the spatial audio reference for custom hosts and cleanup.
55
76
  - Audio files and licensing belong to `jgengine-assets`; spatial playback policy belongs here.
56
77
 
57
78