@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,4 +1,5 @@
1
1
  import { type CollisionObstacle } from "../movement/movementModel.js";
2
+ import type { KinematicVehicleOptions } from "./kinematicVehicle.js";
2
3
  /**
3
4
  * A single blocked-move event a car can react to (#1051): crash damage, screen shake, a metal-crunch
4
5
  * cue. Reported once, when a move is first vetoed, then consumed by {@link VehicleObstacleClamp.takeImpact}.
@@ -17,8 +18,8 @@ export interface VehicleImpact {
17
18
  * {@link takeImpact} once per tick for the crash it produced.
18
19
  */
19
20
  export interface VehicleObstacleClamp {
20
- /** Resolve an attempted `from`→`to` XZ move to the destination actually allowed (slide-along). */
21
- clampMove(from: readonly [number, number], to: readonly [number, number]): readonly [number, number];
21
+ /** Resolve an attempted XZ move; recovery endpoints carry permitted world-unit displacement in `motion`. */
22
+ clampMove: NonNullable<KinematicVehicleOptions["clampMove"]>;
22
23
  /** Impact recorded since last take, consumed on read (null when none). Closing speed is the velocity component into the obstacle at block time, units/s. */
23
24
  takeImpact(): VehicleImpact | null;
24
25
  }
@@ -106,11 +106,30 @@ export function createVehicleObstacleClamp(options) {
106
106
  return to;
107
107
  const attemptedX = to[0] - from[0];
108
108
  const attemptedZ = to[1] - from[1];
109
- const step = resolveObstacleStep([from[0], CAR_BODY_MID_Y, from[1]], attemptedX, attemptedZ, vehicleView(obstacles), radius);
110
- const blockedX = attemptedX - step.stepX;
111
- const blockedZ = attemptedZ - step.stepZ;
112
- if (blockedX === 0 && blockedZ === 0)
109
+ const current = [from[0], CAR_BODY_MID_Y, from[1]];
110
+ const solids = vehicleView(obstacles);
111
+ const step = resolveObstacleStep(current, attemptedX, attemptedZ, solids, radius);
112
+ if (attemptedX === step.stepX && attemptedZ === step.stepZ)
113
113
  return to;
114
+ // The resolver's zero-step escape is the same positional recovery included in `step`.
115
+ // Separate it from motion using this tick's already sampled solids, never a second callback.
116
+ // This preserves the resolver's tangential projection, including diagonal/compound contacts.
117
+ const escape = resolveObstacleStep(current, 0, 0, solids, radius);
118
+ const recovering = escape.stepX !== 0 || escape.stepZ !== 0;
119
+ // Recover first, then collide the motor move at that safe origin. Otherwise the resolver
120
+ // excludes the penetrated box and permits driving straight back into it on every tick.
121
+ const motion = recovering
122
+ ? resolveObstacleStep([from[0] + escape.stepX, CAR_BODY_MID_Y, from[1] + escape.stepZ], attemptedX, attemptedZ, solids, radius)
123
+ : step;
124
+ // One bounded recovery pass may meet another overlapping solid. Keep that second escape
125
+ // positional too; overlapping/inconsistent solids never become an unbounded recovery loop.
126
+ const secondaryEscape = recovering
127
+ ? resolveObstacleStep([from[0] + escape.stepX, CAR_BODY_MID_Y, from[1] + escape.stepZ], 0, 0, solids, radius)
128
+ : { stepX: 0, stepZ: 0 };
129
+ const motionX = motion.stepX - secondaryEscape.stepX;
130
+ const motionZ = motion.stepZ - secondaryEscape.stepZ;
131
+ const blockedX = attemptedX - motionX;
132
+ const blockedZ = attemptedZ - motionZ;
114
133
  const blockedMag = Math.hypot(blockedX, blockedZ);
115
134
  if (blockedMag > BLOCK_EPSILON) {
116
135
  const dt = options.dt();
@@ -123,7 +142,12 @@ export function createVehicleObstacleClamp(options) {
123
142
  };
124
143
  }
125
144
  }
126
- return [from[0] + step.stepX, from[1] + step.stepZ];
145
+ const result = [from[0] + escape.stepX + motion.stepX, from[1] + escape.stepZ + motion.stepZ];
146
+ if (recovering) {
147
+ // Per-result tuples stay stable if a host retains a prior result for diagnostics.
148
+ return Object.assign(result, { motion: [motionX, motionZ] });
149
+ }
150
+ return result;
127
151
  },
128
152
  takeImpact() {
129
153
  const impact = pending;
@@ -7,7 +7,7 @@ export interface WorldColliderSync {
7
7
  /** Remove all bodies owned by this synchronizer and stop reacting to scene changes. */
8
8
  dispose(): void;
9
9
  }
10
- /** Mirrors static scene-object physical colliders and the context's ground field into a physics backend.
10
+ /** Mirrors static scene-object physical colliders, `ctx.world.solids` and the context's ground field into a physics backend.
11
11
  * @capability world-physics-colliders Synchronize terrain and authored static colliders with a physics backend.
12
12
  */
13
13
  export declare function syncWorldColliders(backend: PhysicsBackend, ctx: GameContext): WorldColliderSync;
@@ -10,11 +10,13 @@ function bodyShape(shape) {
10
10
  function bodyPosition(shape, position, rotationY) {
11
11
  return colliderWorldCenter({ name: "body", purpose: "physical", shape, damageEligible: false, blocks: true }, position, rotationY);
12
12
  }
13
- /** Mirrors static scene-object physical colliders and the context's ground field into a physics backend.
13
+ /** Mirrors static scene-object physical colliders, `ctx.world.solids` and the context's ground field into a physics backend.
14
14
  * @capability world-physics-colliders Synchronize terrain and authored static colliders with a physics backend.
15
15
  */
16
16
  export function syncWorldColliders(backend, ctx) {
17
17
  const objectBodies = new Map();
18
+ const solidBodies = [];
19
+ let solidsVersion = -1;
18
20
  let terrainBody = null;
19
21
  let disposed = false;
20
22
  function rebuildTerrain() {
@@ -62,10 +64,32 @@ export function syncWorldColliders(backend, ctx) {
62
64
  });
63
65
  objectBodies.set(objectId, handle);
64
66
  }
67
+ function syncSolids() {
68
+ const solids = ctx.world.solids;
69
+ if (solids.version() === solidsVersion)
70
+ return;
71
+ solidsVersion = solids.version();
72
+ for (const handle of solidBodies)
73
+ backend.removeBody(handle);
74
+ solidBodies.length = 0;
75
+ for (const layer of solids.layers()) {
76
+ for (const solid of solids.layer(layer)) {
77
+ const yaw = solid.rotationY ?? 0;
78
+ solidBodies.push(backend.addBody({
79
+ shape: { kind: "box", halfExtents: [solid.halfExtents[0], solid.halfExtents[1], solid.halfExtents[2]] },
80
+ position: [solid.center[0], solid.center[1], solid.center[2]],
81
+ rotation: [0, Math.sin(yaw / 2), 0, Math.cos(yaw / 2)],
82
+ kind: "static",
83
+ userData: { kind: "solid", layer },
84
+ }));
85
+ }
86
+ }
87
+ }
65
88
  function sync() {
66
89
  if (disposed)
67
90
  return;
68
91
  rebuildTerrain();
92
+ syncSolids();
69
93
  const ids = new Set(ctx.scene.object.ids());
70
94
  for (const [objectId, handle] of objectBodies) {
71
95
  if (!ids.has(objectId)) {
@@ -76,7 +100,11 @@ export function syncWorldColliders(backend, ctx) {
76
100
  for (const objectId of ids)
77
101
  syncObject(objectId);
78
102
  }
79
- const unsubscribe = ctx.scene.object.subscribe(sync);
103
+ const unsubscribeObjects = ctx.scene.object.subscribe(sync);
104
+ const unsubscribeSolids = ctx.world.solids.subscribe(() => {
105
+ if (!disposed)
106
+ syncSolids();
107
+ });
80
108
  sync();
81
109
  return {
82
110
  sync,
@@ -84,7 +112,11 @@ export function syncWorldColliders(backend, ctx) {
84
112
  if (disposed)
85
113
  return;
86
114
  disposed = true;
87
- unsubscribe();
115
+ unsubscribeObjects();
116
+ unsubscribeSolids();
117
+ for (const handle of solidBodies)
118
+ backend.removeBody(handle);
119
+ solidBodies.length = 0;
88
120
  if (terrainBody !== null)
89
121
  backend.removeBody(terrainBody);
90
122
  terrainBody = null;
@@ -1,8 +1,10 @@
1
+ /** A fixed-size 2D board of cells, row-major from the top-left; `null` is an empty cell. Plain data, so it serializes and restores as-is. */
1
2
  export interface CellGrid<T> {
2
3
  readonly width: number;
3
4
  readonly height: number;
4
5
  readonly cells: readonly (T | null)[];
5
6
  }
7
+ /** A straight line of matching cells found by {@link findRuns}. */
6
8
  export interface CellRun<T> {
7
9
  readonly value: T;
8
10
  readonly cells: readonly {
@@ -11,25 +13,29 @@ export interface CellRun<T> {
11
13
  }[];
12
14
  readonly direction: "row" | "column";
13
15
  }
14
- /** @internal */
16
+ /**
17
+ * An empty `width` × `height` board. Every helper here returns a new grid, so a store slot can hold it
18
+ * and undo, replay, and save/restore work without copying.
19
+ * @capability cell-grid immutable 2D board of cells with row clears, gravity collapse, and match runs
20
+ */
15
21
  export declare function createCellGrid<T>(width: number, height: number): CellGrid<T>;
16
- /** @internal */
22
+ /** Whether `(x, y)` lies on the board. */
17
23
  export declare function inGridBounds<T>(grid: CellGrid<T>, x: number, y: number): boolean;
18
- /** @internal */
24
+ /** The value at `(x, y)`, or `null` when empty or off the board. */
19
25
  export declare function cellAt<T>(grid: CellGrid<T>, x: number, y: number): T | null;
20
- /** @internal */
26
+ /** A copy with `(x, y)` set to `value`; off-board writes return the grid unchanged. */
21
27
  export declare function withCell<T>(grid: CellGrid<T>, x: number, y: number, value: T | null): CellGrid<T>;
22
- /** @internal */
28
+ /** A copy with every in-bounds entry written; one allocation for a whole piece or stamp. */
23
29
  export declare function withCells<T>(grid: CellGrid<T>, entries: readonly {
24
30
  readonly x: number;
25
31
  readonly y: number;
26
32
  readonly value: T | null;
27
33
  }[]): CellGrid<T>;
28
- /** @internal */
34
+ /** Indices of rows with no empty cell, top to bottom. */
29
35
  export declare function fullRows<T>(grid: CellGrid<T>): number[];
30
- /** @internal */
36
+ /** A copy with `rows` removed and the rows above shifted down, refilling empty rows at the top. */
31
37
  export declare function clearRows<T>(grid: CellGrid<T>, rows: readonly number[]): CellGrid<T>;
32
- /** @internal */
38
+ /** A copy where every column's cells fall to the bottom, keeping their order. */
33
39
  export declare function collapseColumns<T>(grid: CellGrid<T>): CellGrid<T>;
34
- /** @internal */
40
+ /** Horizontal and vertical runs of at least `minLength` cells whose values `matches` (default `===`). */
35
41
  export declare function findRuns<T>(grid: CellGrid<T>, minLength: number, matches?: (a: T, b: T) => boolean): CellRun<T>[];
@@ -1,18 +1,22 @@
1
- /** @internal */
1
+ /**
2
+ * An empty `width` × `height` board. Every helper here returns a new grid, so a store slot can hold it
3
+ * and undo, replay, and save/restore work without copying.
4
+ * @capability cell-grid immutable 2D board of cells with row clears, gravity collapse, and match runs
5
+ */
2
6
  export function createCellGrid(width, height) {
3
7
  return { width, height, cells: new Array(width * height).fill(null) };
4
8
  }
5
- /** @internal */
9
+ /** Whether `(x, y)` lies on the board. */
6
10
  export function inGridBounds(grid, x, y) {
7
11
  return x >= 0 && x < grid.width && y >= 0 && y < grid.height;
8
12
  }
9
- /** @internal */
13
+ /** The value at `(x, y)`, or `null` when empty or off the board. */
10
14
  export function cellAt(grid, x, y) {
11
15
  if (!inGridBounds(grid, x, y))
12
16
  return null;
13
17
  return grid.cells[y * grid.width + x] ?? null;
14
18
  }
15
- /** @internal */
19
+ /** A copy with `(x, y)` set to `value`; off-board writes return the grid unchanged. */
16
20
  export function withCell(grid, x, y, value) {
17
21
  if (!inGridBounds(grid, x, y))
18
22
  return grid;
@@ -20,7 +24,7 @@ export function withCell(grid, x, y, value) {
20
24
  cells[y * grid.width + x] = value;
21
25
  return { width: grid.width, height: grid.height, cells };
22
26
  }
23
- /** @internal */
27
+ /** A copy with every in-bounds entry written; one allocation for a whole piece or stamp. */
24
28
  export function withCells(grid, entries) {
25
29
  const cells = grid.cells.slice();
26
30
  for (const entry of entries) {
@@ -29,7 +33,7 @@ export function withCells(grid, entries) {
29
33
  }
30
34
  return { width: grid.width, height: grid.height, cells };
31
35
  }
32
- /** @internal */
36
+ /** Indices of rows with no empty cell, top to bottom. */
33
37
  export function fullRows(grid) {
34
38
  const rows = [];
35
39
  for (let y = 0; y < grid.height; y += 1) {
@@ -45,7 +49,7 @@ export function fullRows(grid) {
45
49
  }
46
50
  return rows;
47
51
  }
48
- /** @internal */
52
+ /** A copy with `rows` removed and the rows above shifted down, refilling empty rows at the top. */
49
53
  export function clearRows(grid, rows) {
50
54
  const removed = new Set(rows);
51
55
  const kept = [];
@@ -62,7 +66,7 @@ export function clearRows(grid, rows) {
62
66
  cells.push(...row);
63
67
  return { width: grid.width, height: grid.height, cells };
64
68
  }
65
- /** @internal */
69
+ /** A copy where every column's cells fall to the bottom, keeping their order. */
66
70
  export function collapseColumns(grid) {
67
71
  const cells = grid.cells.slice();
68
72
  for (let x = 0; x < grid.width; x += 1) {
@@ -96,7 +100,7 @@ function scanRuns(length, cellAtIndex, minLength, matches) {
96
100
  }
97
101
  return runs;
98
102
  }
99
- /** @internal */
103
+ /** Horizontal and vertical runs of at least `minLength` cells whose values `matches` (default `===`). */
100
104
  export function findRuns(grid, minLength, matches = (a, b) => a === b) {
101
105
  const runs = [];
102
106
  for (let y = 0; y < grid.height; y += 1) {
@@ -6,12 +6,15 @@ import type { PostProcessingConfig } from "./postProcessing.js";
6
6
  * `"neutral"` (the default when unset) keeps presentation unstyled; `"cinematic"` draws a scene lit like a shipped game — a real day sky
7
7
  * with a view-following shadow-casting sun + hemisphere fill, a network-free image-based-lighting
8
8
  * environment so PBR surfaces catch soft reflections, and a tuned tone-map/bloom/AO/vignette post
9
- * stack. `"flat"` opts out of the sky/IBL/post rig to the bare ambient+directional default (pre-#773).
9
+ * stack. `"comic"` adds ink outlines and cel bands over a saturated grade (Borderlands-style);
10
+ * `"retro"` pixelates and posterizes the frame. `"flat"` opts out of the sky/IBL/post rig to the bare ambient+directional default (pre-#773).
10
11
  * The upgraded default primitive materials — tuned roughness/metalness plus subtle procedural surface
11
12
  * detail so un-modeled boxes/capsules stop reading as flat plastic — apply under both presets.
12
13
  * @capability default-look one field that lights a scene like a shipped game (opt out with "flat")
13
14
  */
14
- export type LookPreset = "neutral" | "photoreal" | "toon" | "cinematic" | "flat";
15
+ export type LookPreset = "neutral" | "photoreal" | "toon" | "comic" | "retro" | "cinematic" | "flat";
16
+ /** Every look preset name, for pickers and validating a preset read from a URL or file. */
17
+ export declare const LOOK_PRESETS: readonly LookPreset[];
15
18
  /** Explicit graphics knobs a game may set; the preset only fills the ones left undefined. */
16
19
  export interface GameLookInput {
17
20
  look?: LookPreset;
@@ -37,6 +40,10 @@ export declare const NEUTRAL_POST_PROCESSING: PostProcessingConfig;
37
40
  export declare const PHOTOREAL_POST_PROCESSING: PostProcessingConfig;
38
41
  /** Clean graphic presentation; toon materials remain game-owned while this sets the grade. */
39
42
  export declare const TOON_POST_PROCESSING: PostProcessingConfig;
43
+ /** Ink outlines, four cel bands and a punchy grade — a hand-inked comic look on any model. */
44
+ export declare const COMIC_POST_PROCESSING: PostProcessingConfig;
45
+ /** Chunky pixels and posterized colour with no smoothing — a low-resolution retro look. */
46
+ export declare const RETRO_POST_PROCESSING: PostProcessingConfig;
40
47
  /**
41
48
  * Expand a game's `look` into concrete lighting/backdrop/post. The default is `"neutral"`;
42
49
  * `"flat"` passes the explicit knobs through untouched.
@@ -1,3 +1,5 @@
1
+ /** Every look preset name, for pickers and validating a preset read from a URL or file. */
2
+ export const LOOK_PRESETS = ["neutral", "photoreal", "cinematic", "toon", "comic", "retro", "flat"];
1
3
  /** A static day sky: a real dome plus the shell's view-following shadow-casting sun and hemisphere fill. */
2
4
  export const CINEMATIC_SKY = { preset: "day" };
3
5
  /** Tuned tone-map + bloom + gentle SSAO + vignette/grade stack — the shipped-game post look. */
@@ -28,6 +30,32 @@ export const TOON_POST_PROCESSING = {
28
30
  ao: { intensity: 0.8, radius: 1.2 },
29
31
  grade: { saturation: 1.18, gamma: 1, vignette: 0, grain: 0 },
30
32
  };
33
+ /** Ink outlines, four cel bands and a punchy grade — a hand-inked comic look on any model. */
34
+ export const COMIC_POST_PROCESSING = {
35
+ toneMapping: "aces",
36
+ exposure: 1.05,
37
+ aa: "msaa",
38
+ bloom: { strength: 0.12, radius: 0.4, threshold: 1 },
39
+ ao: { intensity: 1, radius: 1.2 },
40
+ stylize: { outline: { thickness: 1.5 }, bands: 4 },
41
+ grade: { saturation: 1.3, gamma: 0.94, vignette: 0.15, grain: 0 },
42
+ };
43
+ /** Chunky pixels and posterized colour with no smoothing — a low-resolution retro look. */
44
+ export const RETRO_POST_PROCESSING = {
45
+ toneMapping: "aces",
46
+ aa: false,
47
+ bloom: false,
48
+ ao: false,
49
+ stylize: { pixelSize: 3, bands: 6 },
50
+ grade: { saturation: 1.15, gamma: 1, vignette: 0, grain: 0 },
51
+ };
52
+ const PRESET_POST = {
53
+ photoreal: PHOTOREAL_POST_PROCESSING,
54
+ toon: TOON_POST_PROCESSING,
55
+ comic: COMIC_POST_PROCESSING,
56
+ retro: RETRO_POST_PROCESSING,
57
+ cinematic: CINEMATIC_POST_PROCESSING,
58
+ };
31
59
  /**
32
60
  * Expand a game's `look` into concrete lighting/backdrop/post. The default is `"neutral"`;
33
61
  * `"flat"` passes the explicit knobs through untouched.
@@ -48,7 +76,6 @@ export function resolveGameLook(input) {
48
76
  return {
49
77
  lighting: input.lighting,
50
78
  backdrop,
51
- postProcessing: input.postProcessing ??
52
- (look === "toon" ? TOON_POST_PROCESSING : look === "photoreal" ? PHOTOREAL_POST_PROCESSING : CINEMATIC_POST_PROCESSING),
79
+ postProcessing: input.postProcessing ?? PRESET_POST[look],
53
80
  };
54
81
  }
@@ -55,6 +55,34 @@ export interface DofConfig {
55
55
  /** Maximum blur radius, 0..1. Default 0.01. */
56
56
  maxBlur?: number;
57
57
  }
58
+ /** Ink outlines traced from depth and surface-normal edges — silhouettes plus interior creases. */
59
+ export interface OutlineConfig {
60
+ /** Line colour (CSS). Default near-black "#101014". */
61
+ color?: string;
62
+ /** Line thickness in render pixels. Default 1. */
63
+ thickness?: number;
64
+ /** Line opacity, 0..1. Default 1. */
65
+ opacity?: number;
66
+ /** Relative depth jump that counts as a silhouette edge. Lower draws more lines. Default 0.08. */
67
+ depthThreshold?: number;
68
+ /** Normal difference (1 − cos angle) that counts as a crease. Lower draws more lines. Default 0.35. */
69
+ normalThreshold?: number;
70
+ /** Distance in world units at which lines have faded out, so far scenery stays clean. Default 160. */
71
+ fadeDistance?: number;
72
+ }
73
+ /**
74
+ * Art-style stage that turns the same models and lighting into a different look without
75
+ * touching materials: ink outlines (comic / Borderlands), cel bands (cartoon), pixelation (retro).
76
+ * Runs after tone mapping, before the grade.
77
+ */
78
+ export interface StylizeConfig {
79
+ /** Ink outlines. Omitted or `false` draws none. */
80
+ outline?: OutlineConfig | false;
81
+ /** Quantize brightness into this many cel-shading bands, keeping hue. 0 or omitted is off; 3–6 reads as cartoon. */
82
+ bands?: number;
83
+ /** Snap the frame to blocks of this many render pixels for a retro look. 0, 1 or omitted is off. */
84
+ pixelSize?: number;
85
+ }
58
86
  /**
59
87
  * Edge antialiasing for the post chain. SMAA runs in linear-sRGB before the output
60
88
  * tone-map and cleans alpha-tested foliage/particles that MSAA samples alone leave crawling.
@@ -86,6 +114,8 @@ export interface PostProcessingConfig {
86
114
  /** Depth-of-field / bokeh. Heavier stage — omit or `false` to skip. Default off (omitted). */
87
115
  dof?: DofConfig | false;
88
116
  grade?: GradeConfig | false;
117
+ /** Art-style stage: outlines, cel bands, pixelation. Default off (omitted). */
118
+ stylize?: StylizeConfig | false;
89
119
  }
90
120
  /**
91
121
  * A cinematic "product shot" post preset — the full chain on (contact-AO, soft bloom, a warm film
@@ -8,7 +8,7 @@ export const STUDIO_STAGE_POST = {
8
8
  toneMapping: "aces",
9
9
  exposure: 1.05,
10
10
  bloom: { strength: 0.28, radius: 0.6, threshold: 0.8 },
11
- ao: { radius: 1.4, intensity: 2.2, distanceFalloff: 3, blend: 1 },
11
+ ao: { radius: 1.1, intensity: 1.5, distanceFalloff: 3, blend: 1 },
12
12
  grade: {
13
13
  lift: [0.008, 0.008, 0.014],
14
14
  gain: [1.05, 1.02, 0.98],
@@ -1,16 +1,67 @@
1
- import type { ChaseCameraConfig, CinematicCameraConfig } from "../game/playableGame.js";
2
- /** Runtime patch over the static `camera.chase` config — distance/height/fov retuning from gameplay events (#286.11), or a whole driving-feel overlay (speed→FOV, lead, bank, speed shake, drift-lag) applied only while a vehicle is piloted (#1299). */
3
- export type ChaseCameraTuning = Partial<Pick<ChaseCameraConfig, "distance" | "height" | "lookHeight" | "springDamping" | "fov" | "lead" | "bank" | "shakePerSpeed" | "velocityYaw" | "yawResponse">>;
1
+ import type { CameraRigKind, ChaseCameraConfig, ChaseView, CinematicCameraConfig, GameCameraConfig } from "../game/playableGame.js";
2
+ import type { GameContext } from "./gameContext.js";
3
+ /** Data overlay for an existing rig; callbacks and Canvas projection/preferences remain configured by the game. */
4
+ export type CameraRigConfig = Omit<GameCameraConfig, "rig" | "projection" | "pixelPerfect" | "frustum" | "playerFov" | "weapon" | "onCameraFollow">;
5
+ /** Runtime rig selection and detached data overlay over the configured camera. */
6
+ export interface CameraRigOverride {
7
+ kind: CameraRigKind;
8
+ config: CameraRigConfig;
9
+ }
10
+ /** Camera policy state before the JSON-safe snapshot number encoding. */
11
+ export interface CameraDirectorState {
12
+ followEntityId?: string | null;
13
+ rig: CameraRigOverride | null;
14
+ cinematic: CinematicCameraConfig | null;
15
+ chase: ChaseCameraTuning | null;
16
+ }
17
+ type CameraSerialized<T> = T extends number ? number | {
18
+ $cameraNumber: "Infinity";
19
+ } : T extends object ? {
20
+ [Key in keyof T]: CameraSerialized<T[Key]>;
21
+ } : T;
22
+ /** JSON-safe camera policy; documented instant chase responses use an explicit Infinity marker. */
23
+ export type CameraDirectorSnapshot = CameraSerialized<CameraDirectorState>;
24
+ /** @internal */
25
+ export declare function validateCameraRig(kind: CameraRigKind, config?: CameraRigConfig): void;
26
+ /** @internal */
27
+ export declare function validateChaseCameraTuning(tuning: ChaseCameraTuning | null): void;
28
+ /** Runtime patch over the static `camera.chase` config — distance/height/fov retuning from gameplay events (#286.11), a whole driving-feel overlay applied only while a vehicle is piloted (#1299), or a `view` switch between chase and seat cameras. */
29
+ export type ChaseCameraTuning = Partial<Pick<ChaseCameraConfig, "distance" | "height" | "lookHeight" | "springDamping" | "fov" | "lead" | "bank" | "shakePerSpeed" | "velocityYaw" | "yawResponse" | "headingSource" | "distanceBySpeed" | "pitchFollow" | "fovKick" | "lookBackAction" | "collision" | "view">>;
30
+ /** Default order {@link nextChaseView} cycles through. */
31
+ export declare const CHASE_VIEWS: readonly ChaseView[];
32
+ /**
33
+ * The view after `current` in `views`, wrapping at the end; a view missing from the list starts the cycle over.
34
+ * Pair with `setChaseTuning` to bind a "change camera" key:
35
+ * `ctx.camera.setChaseTuning({ ...ctx.camera.chaseTuning(), view: nextChaseView(view) })`.
36
+ *
37
+ * @capability chase-view-cycle cycle a vehicle camera between chase, hood and cockpit views at runtime
38
+ */
39
+ export declare function nextChaseView(current: ChaseView, views?: readonly ChaseView[]): ChaseView;
4
40
  export interface CameraDirector {
5
41
  follow(entityId: string | null): void;
6
42
  /** `undefined` means no runtime override — the shell falls back to the static `playable.camera.followEntityId`. `null` means explicitly follow nothing. */
7
43
  followedEntityId(): string | null | undefined;
44
+ /** Replace the runtime rig overlay; `null` restores the game's configured rig/config. Existing chase tuning remains independent. */
45
+ setRig(kind: CameraRigKind | null, config?: CameraRigConfig): void;
46
+ rig(): CameraRigOverride | null;
8
47
  setCinematic(config: CinematicCameraConfig | null): void;
9
48
  cinematic(): CinematicCameraConfig | null;
10
49
  /** Overlay a runtime patch on the chase rig's config — a boss-intro pull-back, drift zoom-out; `null` restores the static config. */
11
50
  setChaseTuning(tuning: ChaseCameraTuning | null): void;
12
51
  chaseTuning(): ChaseCameraTuning | null;
52
+ /** Add a transient FOV impulse in degrees (a landing, a hit, a boost) that the chase rig layers on and decays per `camera.chase.fovKick`. Kicks from one frame sum. */
53
+ kickFov(degrees: number): void;
54
+ /** Drain the FOV impulses queued since the last call; the shell's chase rig calls this once per frame. */
55
+ takeFovKick(): number;
56
+ snapshot(): CameraDirectorSnapshot;
57
+ /** Invalid state throws before changing any camera field. */
58
+ restore(state: CameraDirectorSnapshot): void;
59
+ /** Clear runtime policy and transient FOV kicks; configured camera data remains untouched. */
60
+ reset(): void;
13
61
  subscribe(listener: () => void): () => void;
14
62
  }
15
63
  /** @internal */
16
64
  export declare function createCameraDirector(): CameraDirector;
65
+ /** Local camera policy is saved, never broadcast to another player's presentation. @internal */
66
+ export declare function installCameraPersistence(ctx: GameContext): void;
67
+ export {};