@jgengine/core 0.18.0 → 0.19.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 (318) hide show
  1. package/CHANGELOG.md +265 -2
  2. package/dist/ai/decisionGraph.d.ts +96 -0
  3. package/dist/ai/decisionGraph.js +212 -0
  4. package/dist/ai/groupAssist.d.ts +10 -0
  5. package/dist/ai/groupAssist.js +11 -0
  6. package/dist/ai/mobBrainGraph.d.ts +3 -0
  7. package/dist/ai/mobBrainGraph.js +25 -0
  8. package/dist/ai/pursuit.d.ts +1 -1
  9. package/dist/ai/pursuit.js +1 -1
  10. package/dist/ai/tacticalQueries.d.ts +30 -0
  11. package/dist/ai/tacticalQueries.js +45 -0
  12. package/dist/ai/threat.d.ts +8 -0
  13. package/dist/ai/threat.js +10 -0
  14. package/dist/anim/animGraph.d.ts +155 -0
  15. package/dist/anim/animGraph.js +414 -0
  16. package/dist/anim/boneTexture.d.ts +55 -0
  17. package/dist/anim/boneTexture.js +43 -0
  18. package/dist/anim/footPlacement.d.ts +57 -0
  19. package/dist/anim/footPlacement.js +67 -0
  20. package/dist/anim/ikSolver.d.ts +51 -0
  21. package/dist/anim/ikSolver.js +124 -0
  22. package/dist/anim/locomotionGraph.d.ts +35 -0
  23. package/dist/anim/locomotionGraph.js +62 -0
  24. package/dist/assets/spriteAtlas.d.ts +21 -0
  25. package/dist/assets/spriteAtlas.js +103 -0
  26. package/dist/audio/audioFalloff.d.ts +12 -0
  27. package/dist/audio/doppler.d.ts +21 -0
  28. package/dist/audio/doppler.js +32 -0
  29. package/dist/audio/engineLayers.d.ts +83 -0
  30. package/dist/audio/engineLayers.js +115 -0
  31. package/dist/combat/abilityKit.d.ts +1 -0
  32. package/dist/combat/abilityKit.js +1 -0
  33. package/dist/combat/death.d.ts +7 -0
  34. package/dist/combat/shotOrigin.d.ts +6 -0
  35. package/dist/combat/shotOrigin.js +6 -0
  36. package/dist/combat/weaponFeedback.d.ts +36 -0
  37. package/dist/combat/weaponFeedback.js +42 -0
  38. package/dist/combat/weaponHandling.d.ts +161 -0
  39. package/dist/combat/weaponHandling.js +202 -0
  40. package/dist/combat/weaponPresentation.d.ts +115 -0
  41. package/dist/combat/weaponPresentation.js +96 -0
  42. package/dist/devtools/warnOnce.d.ts +8 -0
  43. package/dist/devtools/warnOnce.js +18 -0
  44. package/dist/economy/currency.d.ts +16 -2
  45. package/dist/economy/currency.js +55 -14
  46. package/dist/economy/wallet.d.ts +5 -4
  47. package/dist/economy/wallet.js +8 -4
  48. package/dist/editor/commandApply.js +1 -0
  49. package/dist/editor/commands.d.ts +4 -1
  50. package/dist/editor/document.d.ts +2 -1
  51. package/dist/editor/document.js +92 -1
  52. package/dist/editor/environment.d.ts +3 -0
  53. package/dist/editor/environment.js +24 -0
  54. package/dist/editor/index.d.ts +4 -2
  55. package/dist/editor/index.js +1 -1
  56. package/dist/editor/types.d.ts +20 -0
  57. package/dist/faction/reputation.d.ts +6 -0
  58. package/dist/faction/reputation.js +11 -0
  59. package/dist/game/cameraConfig.d.ts +59 -1
  60. package/dist/game/chat.d.ts +22 -1
  61. package/dist/game/chat.js +48 -19
  62. package/dist/game/controlGate.d.ts +6 -0
  63. package/dist/game/controlGate.js +30 -1
  64. package/dist/game/defineGame.d.ts +10 -1
  65. package/dist/game/events.d.ts +14 -1
  66. package/dist/game/lootTable.d.ts +4 -0
  67. package/dist/game/lootTable.js +16 -0
  68. package/dist/game/pixelPerfect.d.ts +25 -0
  69. package/dist/game/pixelPerfect.js +29 -0
  70. package/dist/game/playableGame.d.ts +167 -6
  71. package/dist/game/systemRuntime.js +6 -1
  72. package/dist/game/toasts.d.ts +8 -0
  73. package/dist/game/toasts.js +7 -0
  74. package/dist/game/vfxInstance.d.ts +9 -0
  75. package/dist/game/vfxInstance.js +12 -1
  76. package/dist/game/viewports.d.ts +43 -0
  77. package/dist/game/viewports.js +46 -0
  78. package/dist/game/worldItem.d.ts +5 -1
  79. package/dist/game/worldItem.js +0 -1
  80. package/dist/input/actionBindings.d.ts +17 -2
  81. package/dist/input/actionBindings.js +24 -11
  82. package/dist/input/actionContexts.d.ts +45 -0
  83. package/dist/input/actionContexts.js +113 -0
  84. package/dist/input/axisInput.d.ts +4 -0
  85. package/dist/input/axisInput.js +4 -0
  86. package/dist/input/axisShaper.d.ts +73 -0
  87. package/dist/input/axisShaper.js +105 -0
  88. package/dist/input/gamepadModel.d.ts +79 -0
  89. package/dist/input/gamepadModel.js +108 -0
  90. package/dist/input/haptics.d.ts +50 -0
  91. package/dist/input/haptics.js +74 -0
  92. package/dist/input/inputBuffer.d.ts +40 -0
  93. package/dist/input/inputBuffer.js +59 -0
  94. package/dist/input/lookChannel.d.ts +10 -0
  95. package/dist/input/lookChannel.js +6 -0
  96. package/dist/input/pointer.d.ts +2 -0
  97. package/dist/input/pointer.js +4 -0
  98. package/dist/item/affix.d.ts +6 -0
  99. package/dist/item/affix.js +6 -0
  100. package/dist/meta/changelog.d.ts +1 -1
  101. package/dist/meta/changelog.js +196 -1
  102. package/dist/movement/characterController.d.ts +76 -0
  103. package/dist/movement/characterController.js +216 -0
  104. package/dist/movement/freeFlight.d.ts +119 -0
  105. package/dist/movement/freeFlight.js +294 -0
  106. package/dist/movement/glideModel.d.ts +3 -0
  107. package/dist/movement/glideModel.js +6 -0
  108. package/dist/movement/grappleSwing.d.ts +2 -0
  109. package/dist/movement/grappleSwing.js +5 -1
  110. package/dist/movement/movementModel.d.ts +39 -0
  111. package/dist/movement/movementModel.js +62 -19
  112. package/dist/movement/movementProbe.d.ts +51 -0
  113. package/dist/movement/movementProbe.js +119 -0
  114. package/dist/movement/playerMovement.d.ts +30 -3
  115. package/dist/movement/playerMovement.js +304 -7
  116. package/dist/movement/serverStep.d.ts +5 -0
  117. package/dist/movement/serverStep.js +6 -0
  118. package/dist/movement/solidObstacles.d.ts +39 -8
  119. package/dist/movement/solidObstacles.js +71 -6
  120. package/dist/movement/voxelController.js +7 -7
  121. package/dist/multiplayer/poseSyncGate.d.ts +3 -1
  122. package/dist/multiplayer/poseSyncGate.js +9 -1
  123. package/dist/multiplayer/presenceContract.d.ts +6 -0
  124. package/dist/multiplayer/presenceModel.d.ts +2 -0
  125. package/dist/multiplayer/presenceModel.js +11 -0
  126. package/dist/nav/navFromEnvironment.d.ts +9 -3
  127. package/dist/nav/navFromEnvironment.js +18 -12
  128. package/dist/nav/navMesh.d.ts +74 -0
  129. package/dist/nav/navMesh.js +570 -0
  130. package/dist/physics/aircraftDynamics.d.ts +390 -0
  131. package/dist/physics/aircraftDynamics.js +704 -0
  132. package/dist/physics/boatDynamics.d.ts +116 -0
  133. package/dist/physics/boatDynamics.js +160 -0
  134. package/dist/physics/drivableVehicle.d.ts +22 -8
  135. package/dist/physics/drivableVehicle.js +4 -2
  136. package/dist/physics/flightDynamics.d.ts +29 -4
  137. package/dist/physics/flightDynamics.js +28 -5
  138. package/dist/physics/handlingProbe.d.ts +249 -0
  139. package/dist/physics/handlingProbe.js +606 -0
  140. package/dist/physics/kinematicVehicle.d.ts +37 -2
  141. package/dist/physics/kinematicVehicle.js +15 -0
  142. package/dist/physics/physicsBackend.d.ts +203 -0
  143. package/dist/physics/physicsBackend.js +49 -0
  144. package/dist/physics/physicsBackendConformance.d.ts +27 -0
  145. package/dist/physics/physicsBackendConformance.js +151 -0
  146. package/dist/physics/physicsWorldBackend.d.ts +45 -0
  147. package/dist/physics/physicsWorldBackend.js +518 -0
  148. package/dist/physics/vehicleBackendLink.d.ts +49 -0
  149. package/dist/physics/vehicleBackendLink.js +102 -0
  150. package/dist/physics/vehicleDynamics.d.ts +374 -0
  151. package/dist/physics/vehicleDynamics.js +737 -0
  152. package/dist/physics/worldColliders.d.ts +13 -0
  153. package/dist/physics/worldColliders.js +128 -0
  154. package/dist/puzzle/cellGrid.d.ts +15 -9
  155. package/dist/puzzle/cellGrid.js +13 -9
  156. package/dist/random/rng.d.ts +12 -1
  157. package/dist/random/rng.js +20 -3
  158. package/dist/render/environment.d.ts +23 -0
  159. package/dist/render/environment.js +1 -0
  160. package/dist/render/lookPreset.d.ts +19 -6
  161. package/dist/render/lookPreset.js +56 -4
  162. package/dist/render/postProcessing.d.ts +40 -1
  163. package/dist/render/postProcessing.js +1 -1
  164. package/dist/render/sprite2d.d.ts +38 -0
  165. package/dist/render/sprite2d.js +40 -0
  166. package/dist/runtime/adapter.d.ts +20 -1
  167. package/dist/runtime/adapter.js +8 -1
  168. package/dist/runtime/cameraDirector.d.ts +17 -3
  169. package/dist/runtime/cameraDirector.js +25 -0
  170. package/dist/runtime/commandInput.d.ts +52 -0
  171. package/dist/runtime/commandInput.js +71 -0
  172. package/dist/runtime/commandRunner.d.ts +39 -7
  173. package/dist/runtime/commandRunner.js +35 -5
  174. package/dist/runtime/context/combat.d.ts +1 -0
  175. package/dist/runtime/context/combat.js +2 -1
  176. package/dist/runtime/context/deathLoot.d.ts +2 -0
  177. package/dist/runtime/context/deathLoot.js +1 -0
  178. package/dist/runtime/gameContext.js +18 -1
  179. package/dist/runtime/gameContextTypes.d.ts +33 -7
  180. package/dist/runtime/gameRuntime.d.ts +23 -5
  181. package/dist/runtime/gameRuntime.js +21 -4
  182. package/dist/runtime/headlessRunner.d.ts +10 -0
  183. package/dist/runtime/headlessRunner.js +26 -8
  184. package/dist/runtime/hostPolicy.d.ts +3 -2
  185. package/dist/runtime/hostPolicy.js +8 -10
  186. package/dist/runtime/hostedGameRunner.js +34 -6
  187. package/dist/runtime/hostedWorldSession.d.ts +12 -16
  188. package/dist/runtime/hostedWorldSession.js +29 -6
  189. package/dist/runtime/hostedWorldStore.d.ts +20 -0
  190. package/dist/runtime/hostedWorldStore.js +1 -0
  191. package/dist/runtime/inputRecorder.d.ts +30 -0
  192. package/dist/runtime/inputRecorder.js +59 -0
  193. package/dist/runtime/inputSnapshot.d.ts +14 -0
  194. package/dist/runtime/inputSnapshot.js +11 -0
  195. package/dist/runtime/localPlayers.d.ts +73 -0
  196. package/dist/runtime/localPlayers.js +119 -0
  197. package/dist/runtime/poseInterpolation.d.ts +36 -0
  198. package/dist/runtime/poseInterpolation.js +91 -0
  199. package/dist/runtime/prediction.d.ts +45 -0
  200. package/dist/runtime/prediction.js +62 -0
  201. package/dist/runtime/simContext.d.ts +45 -0
  202. package/dist/runtime/simContext.js +65 -0
  203. package/dist/runtime/simLoop.d.ts +52 -0
  204. package/dist/runtime/simLoop.js +72 -0
  205. package/dist/runtime/simSnapshot.d.ts +32 -0
  206. package/dist/runtime/simSnapshot.js +60 -0
  207. package/dist/runtime/snapshot.d.ts +8 -0
  208. package/dist/runtime/snapshotBuffer.d.ts +33 -0
  209. package/dist/runtime/snapshotBuffer.js +58 -0
  210. package/dist/runtime/transport.d.ts +41 -2
  211. package/dist/runtime/transport.js +7 -1
  212. package/dist/runtime/worldChunks.d.ts +2 -0
  213. package/dist/runtime/worldChunks.js +14 -0
  214. package/dist/runtime/worldProjection.d.ts +9 -0
  215. package/dist/runtime/worldProjection.js +17 -1
  216. package/dist/runtime/worldSnapshot.d.ts +6 -0
  217. package/dist/runtime/worldSnapshot.js +3 -0
  218. package/dist/scene/behaviorRuntime.d.ts +29 -1
  219. package/dist/scene/behaviorRuntime.js +71 -4
  220. package/dist/scene/behaviors.d.ts +12 -1
  221. package/dist/scene/builtinSceneKinds.js +10 -0
  222. package/dist/scene/sceneKinds.d.ts +9 -0
  223. package/dist/scene/vehicleSeat.d.ts +5 -1
  224. package/dist/scene/vehicleSeat.js +5 -1
  225. package/dist/sensor/concealment.d.ts +6 -0
  226. package/dist/sensor/concealment.js +8 -0
  227. package/dist/sensor/freezeMonitor.d.ts +6 -0
  228. package/dist/sensor/freezeMonitor.js +8 -0
  229. package/dist/sensor/perception.d.ts +70 -0
  230. package/dist/sensor/perception.js +189 -0
  231. package/dist/sensor/recordingBuffer.d.ts +3 -0
  232. package/dist/sensor/recordingBuffer.js +8 -0
  233. package/dist/session/roundState.d.ts +4 -0
  234. package/dist/session/roundState.js +11 -0
  235. package/dist/settings/frameRateLimit.d.ts +16 -0
  236. package/dist/settings/frameRateLimit.js +37 -0
  237. package/dist/settings/graphicsProfile.d.ts +21 -0
  238. package/dist/settings/graphicsProfile.js +48 -0
  239. package/dist/settings/graphicsSettings.d.ts +40 -0
  240. package/dist/settings/graphicsSettings.js +81 -0
  241. package/dist/settings/settingsModel.d.ts +9 -1
  242. package/dist/settings/settingsModel.js +10 -0
  243. package/dist/stats/eventMeter.d.ts +1 -1
  244. package/dist/stats/eventMeter.js +1 -1
  245. package/dist/time/accrueSince.d.ts +10 -0
  246. package/dist/time/accrueSince.js +9 -0
  247. package/dist/time/rateWindow.d.ts +16 -0
  248. package/dist/time/rateWindow.js +14 -0
  249. package/dist/time/serverTick.d.ts +21 -3
  250. package/dist/time/serverTick.js +14 -13
  251. package/dist/vfx/feedbackMixer.d.ts +61 -0
  252. package/dist/vfx/feedbackMixer.js +106 -0
  253. package/dist/vfx/particleDirector.d.ts +68 -0
  254. package/dist/vfx/particleDirector.js +81 -0
  255. package/dist/visibility/simulationCulling.d.ts +8 -1
  256. package/dist/visibility/simulationCulling.js +7 -0
  257. package/dist/visibility/spatialIndex.d.ts +21 -0
  258. package/dist/visibility/spatialIndex.js +16 -0
  259. package/dist/world/authoredSolids.d.ts +46 -0
  260. package/dist/world/authoredSolids.js +75 -0
  261. package/dist/world/buildingGenerator.js +2 -2
  262. package/dist/world/buildingKit.d.ts +3 -1
  263. package/dist/world/buildings.d.ts +46 -2
  264. package/dist/world/buildings.js +53 -3
  265. package/dist/world/cityContent.js +103 -25
  266. package/dist/world/cityKind.d.ts +139 -0
  267. package/dist/world/cityKind.js +367 -16
  268. package/dist/world/features.d.ts +56 -3
  269. package/dist/world/features.js +13 -2
  270. package/dist/world/footprintGrid.d.ts +7 -0
  271. package/dist/world/footprintGrid.js +16 -0
  272. package/dist/world/interiors.d.ts +1 -0
  273. package/dist/world/interiors.js +5 -3
  274. package/dist/world/lod.d.ts +6 -0
  275. package/dist/world/lod.js +8 -0
  276. package/dist/world/placement.d.ts +7 -0
  277. package/dist/world/placement.js +2 -0
  278. package/dist/world/placementController.d.ts +1 -1
  279. package/dist/world/placementController.js +7 -0
  280. package/dist/world/raceCircuit.d.ts +168 -0
  281. package/dist/world/raceCircuit.js +797 -0
  282. package/dist/world/terraform.d.ts +8 -0
  283. package/dist/world/terraform.js +7 -0
  284. package/dist/world/terrain.d.ts +5 -1
  285. package/dist/world/terrain.js +5 -0
  286. package/dist/world/territory.d.ts +97 -0
  287. package/dist/world/territory.js +182 -0
  288. package/dist/world/walls.d.ts +7 -0
  289. package/dist/world/walls.js +7 -0
  290. package/dist/world/worldSolids.d.ts +84 -0
  291. package/dist/world/worldSolids.js +240 -0
  292. package/dist/world.d.ts +5 -3
  293. package/dist/world.js +4 -2
  294. package/package.json +1 -1
  295. package/skills/ce-handoff/SKILL.md +2 -2
  296. package/skills/game-design/SKILL.md +11 -1
  297. package/skills/jgengine/SKILL.md +9 -5
  298. package/skills/jgengine/api.md +205 -101
  299. package/skills/jgengine/capabilities.md +56 -0
  300. package/skills/jgengine/recipes/minimal-game.md +3 -0
  301. package/skills/jgengine-combat/SKILL.md +5 -0
  302. package/skills/jgengine-combat/api.md +138 -103
  303. package/skills/jgengine-combat/capabilities.md +29 -1
  304. package/skills/jgengine-combat/recipes/weapon-feel.md +50 -0
  305. package/skills/jgengine-gameplay/SKILL.md +10 -0
  306. package/skills/jgengine-gameplay/api.md +501 -453
  307. package/skills/jgengine-gameplay/capabilities.md +36 -0
  308. package/skills/jgengine-gameplay/reference-systems.md +4 -0
  309. package/skills/jgengine-world/SKILL.md +21 -3
  310. package/skills/jgengine-world/api.md +1172 -625
  311. package/skills/jgengine-world/capabilities.md +229 -3
  312. package/skills/jgengine-world/recipes/character-animation.md +39 -0
  313. package/skills/jgengine-world/recipes/controls.md +44 -0
  314. package/skills/jgengine-world/recipes/flight-feel.md +76 -0
  315. package/skills/jgengine-world/recipes/npc-senses.md +43 -0
  316. package/skills/jgengine-world/recipes/vehicle-feel.md +85 -0
  317. package/skills/jgengine-world/reference.md +31 -2
  318. package/skills/jgengine-world/visibility.md +112 -0
@@ -7,44 +7,44 @@
7
7
  - `Behaviour` (class): class Behaviour — Subclass and override the lifecycle hooks. A behaviour only joins the per-frame update dispatch if it actually overrides `onUpdate` (prototype-identity check at each activation), so hook-only behaviours cost nothing per frame.
8
8
  - `BehaviourModule` (class): class BehaviourModule — A world-lifetime service with typed sibling access via `this.modules`. Modules awake and start before any behaviour during `world.start()`, subscribe to update dispatch first (their `onUpdate` fires before every behaviour's), and have no disable/destroy — they live as long as the world.
9
9
  - `BehaviourModules` (type): type BehaviourModules = RegisterField<"modules", Record<string, BehaviourModule>> — Resolves to the augmented module map when `JGEngineRegister` declares one.
10
- - `BehaviourWorld` (interface): interface BehaviourWorld — ⚠ undocumented
10
+ - `BehaviourWorld` (interface): interface BehaviourWorld { add(id: string, parentId?: string): void; has(id: string): boolean; parentOf(id: string): string | null; childrenOf(id: string): readonly string[]; setParent(id: string, parentId: string | null): void; attach<T extends Behaviour>(nodeId: … — ⚠ undocumented
11
11
  - `JGEngineRegister` (interface): interface JGEngineRegister — Unity-style behaviour lifecycle over a headless id-keyed node tree, ported from vladkrutenyuk/three-start (MIT) and adapted to run without three.js: nodes are plain string ids (use entity instance ids to pair with `entityStore`), and the shell binds render-side hooks separately.
12
12
  - `RegisterField` (type): type RegisterField<TKey extends string, TFallback = unknown> = TKey extends keyof JGEngineRegister ? JGEngineRegister[TKey] : TFallback — ⚠ undocumented
13
13
  - `createBehaviourWorld` (function): function createBehaviourWorld(): BehaviourWorld — ⚠ undocumented
14
14
 
15
15
  ## @jgengine/core/board/laneBoard
16
16
 
17
- - `LaneAggregate` (interface): interface LaneAggregate — ⚠ undocumented
18
- - `LaneBoard` (interface): interface LaneBoard<C> — ⚠ undocumented
19
- - `LaneBoardConfig` (interface): interface LaneBoardConfig<C> — ⚠ undocumented
20
- - `LaneBoardState` (interface): interface LaneBoardState<C> — ⚠ undocumented
21
- - `LaneCells` (interface): interface LaneCells<C> — ⚠ undocumented
22
- - `LaneOutcome` (interface): interface LaneOutcome — ⚠ undocumented
23
- - `LanePlaceRejected` (interface): interface LanePlaceRejected — ⚠ undocumented
24
- - `LanePlaceResult` (interface): interface LanePlaceResult<C> — ⚠ undocumented
17
+ - `LaneAggregate` (interface): interface LaneAggregate { lane: number; side: Side; subtotal: number; total: number; count: number } — ⚠ undocumented
18
+ - `LaneBoard` (interface): interface LaneBoard<C> { state(): LaneBoardState<C>; place(lane: number, side: Side, card: C): LaneResult<C>; remove(lane: number, side: Side, predicate: (card: C, index: number) => boolean): LaneResult<C>; aggregate(lane: number, side: Side): LaneAggregate; outc… — ⚠ undocumented
19
+ - `LaneBoardConfig` (interface): interface LaneBoardConfig<C> { laneCount: number; sides: readonly Side[]; power: (card: C) => number; laneRules?: readonly (LaneRule<C> | null | undefined)[] } — ⚠ undocumented
20
+ - `LaneBoardState` (interface): interface LaneBoardState<C> { readonly lanes: readonly LaneCells<C>[] } — ⚠ undocumented
21
+ - `LaneCells` (interface): interface LaneCells<C> { readonly [side: Side]: readonly C[] } — ⚠ undocumented
22
+ - `LaneOutcome` (interface): interface LaneOutcome { lane: number; totals: Readonly<Record<Side, number>>; winner: Side | null } — ⚠ undocumented
23
+ - `LanePlaceRejected` (interface): interface LanePlaceRejected { status: "rejected"; reason: LaneRejection } — ⚠ undocumented
24
+ - `LanePlaceResult` (interface): interface LanePlaceResult<C> { status: "ok"; state: LaneBoardState<C> } — ⚠ undocumented
25
25
  - `LaneRejection` (type): type LaneRejection = "invalid-lane" | "invalid-side" — ⚠ undocumented
26
26
  - `LaneResult` (type): type LaneResult<C> = LanePlaceResult<C> | LanePlaceRejected — ⚠ undocumented
27
- - `LaneRule` (interface): interface LaneRule<C> — ⚠ undocumented
28
- - `LaneRuleInput` (interface): interface LaneRuleInput<C> — ⚠ undocumented
27
+ - `LaneRule` (interface): interface LaneRule<C> { id: string; apply: (input: LaneRuleInput<C>) => number } — ⚠ undocumented
28
+ - `LaneRuleInput` (interface): interface LaneRuleInput<C> { lane: number; side: Side; cards: readonly C[]; subtotal: number } — ⚠ undocumented
29
29
  - `Side` (type): type Side = string — ⚠ undocumented
30
30
 
31
31
  ## @jgengine/core/board/timelineBoard
32
32
 
33
- - `TimelineBoard` (interface): interface TimelineBoard — ⚠ undocumented
34
- - `TimelineBoardState` (interface): interface TimelineBoardState — ⚠ undocumented
35
- - `TimelineFire` (interface): interface TimelineFire — ⚠ undocumented
36
- - `TimelineSlot` (interface): interface TimelineSlot — ⚠ undocumented
37
- - `TimelineSlotConfig` (interface): interface TimelineSlotConfig — ⚠ undocumented
38
- - `TimelineTickResult` (interface): interface TimelineTickResult — ⚠ undocumented
33
+ - `TimelineBoard` (interface): interface TimelineBoard { state(): TimelineBoardState; tick(dtMs: number): readonly TimelineFire[]; setEnabled(slotId: string, enabled: boolean): void; reset(slotId?: string, remainingMs?: number): void } — ⚠ undocumented
34
+ - `TimelineBoardState` (interface): interface TimelineBoardState { readonly slots: readonly TimelineSlot[]; readonly elapsedMs: number } — ⚠ undocumented
35
+ - `TimelineFire` (interface): interface TimelineFire { slotId: string; slotIndex: number; atMs: number } — ⚠ undocumented
36
+ - `TimelineSlot` (interface): interface TimelineSlot { readonly id: string; readonly cooldownMs: number; readonly remainingMs: number; readonly enabled: boolean } — ⚠ undocumented
37
+ - `TimelineSlotConfig` (interface): interface TimelineSlotConfig { id: string; cooldownMs: number; enabled?: boolean; offsetMs?: number } — ⚠ undocumented
38
+ - `TimelineTickResult` (interface): interface TimelineTickResult { state: TimelineBoardState; fires: readonly TimelineFire[] } — ⚠ undocumented
39
39
 
40
40
  ## @jgengine/core/cards/cardPile
41
41
 
42
- - `CardPile` (interface): interface CardPile — ⚠ undocumented
43
- - `CardPileConfig` (interface): interface CardPileConfig — ⚠ undocumented
44
- - `CardPileState` (interface): interface CardPileState — ⚠ undocumented
45
- - `DrawResult` (interface): interface DrawResult — ⚠ undocumented
46
- - `PileMoveRejected` (interface): interface PileMoveRejected — ⚠ undocumented
47
- - `PileMoveResult` (interface): interface PileMoveResult — ⚠ undocumented
42
+ - `CardPile` (interface): interface CardPile { state(): CardPileState; zones(): readonly ZoneName[]; count(zone: ZoneName): number; peek(zone: ZoneName, n?: number): readonly string[]; zoneOf(cardId: string): ZoneName | null; shuffle(zone: ZoneName | undefined, seed: string | number):… — ⚠ undocumented
43
+ - `CardPileConfig` (interface): interface CardPileConfig { zones: readonly ZoneName[]; drawFrom?: ZoneName; discardTo?: ZoneName; handZone?: ZoneName; handLimit?: number; reshuffleFrom?: ZoneName; onChange?: () => void } — ⚠ undocumented
44
+ - `CardPileState` (interface): interface CardPileState { readonly zones: Readonly<Record<ZoneName, readonly string[]>> } — ⚠ undocumented · used by `CardStack` (@jgengine/react): `StackedPile` bound to a headless `CardPileState` zone: reads the ordered card ids from `pile.zones[zone]` and resolves each to a `PlayingCa…
45
+ - `DrawResult` (interface): interface DrawResult { state: CardPileState; drawn: readonly string[]; reshuffled: boolean } — ⚠ undocumented
46
+ - `PileMoveRejected` (interface): interface PileMoveRejected { status: "rejected"; reason: PileRejection; detail?: string } — ⚠ undocumented
47
+ - `PileMoveResult` (interface): interface PileMoveResult { status: "ok"; state: CardPileState } — ⚠ undocumented
48
48
  - `PileRejection` (type): type PileRejection = | "unknown-zone" | "card-not-in-zone" | "hand-limit" | "empty-source" — ⚠ undocumented
49
49
  - `PileResult` (type): type PileResult = PileMoveResult | PileMoveRejected — ⚠ undocumented
50
50
  - `ZoneName` (type): type ZoneName = string — ⚠ undocumented
@@ -61,23 +61,23 @@
61
61
 
62
62
  ## @jgengine/core/cards/modifierPipeline
63
63
 
64
- - `Modifier` (interface): interface Modifier<V> — ⚠ undocumented
65
- - `ModifierPipeline` (interface): interface ModifierPipeline<V> — ⚠ undocumented
66
- - `PipelineContext` (interface): interface PipelineContext<V> — ⚠ undocumented
67
- - `PipelineResult` (interface): interface PipelineResult<V> — ⚠ undocumented
68
- - `TraceStep` (interface): interface TraceStep<V> — ⚠ undocumented
64
+ - `Modifier` (interface): interface Modifier<V> { id: string; source?: string; apply: (value: V, context: PipelineContext<V>) => V } — ⚠ undocumented
65
+ - `ModifierPipeline` (interface): interface ModifierPipeline<V> { add(modifier: Modifier<V>): void; insertAt(index: number, modifier: Modifier<V>): void; remove(id: string): boolean; clear(): void; list(): readonly Modifier<V>[]; run(base: V): PipelineResult<V> } — ⚠ undocumented
66
+ - `PipelineContext` (interface): interface PipelineContext<V> { base: V; index: number; trace: readonly TraceStep<V>[] } — ⚠ undocumented
67
+ - `PipelineResult` (interface): interface PipelineResult<V> { base: V; value: V; trace: readonly TraceStep<V>[] } — ⚠ undocumented
68
+ - `TraceStep` (interface): interface TraceStep<V> { id: string; source?: string; index: number; before: V; after: V; changed: boolean } — ⚠ undocumented
69
69
  - `createModifierPipeline` (function): function createModifierPipeline<V>(initial: readonly Modifier<V>[] = [], equals: (a: V, b: V) => boolean = Object.is): ModifierPipeline<V> — ⚠ undocumented
70
70
  - `runPipeline` (function): function runPipeline<V>(base: V, modifiers: readonly Modifier<V>[], equals: (a: V, b: V) => boolean = Object.is): PipelineResult<V> — ⚠ undocumented
71
71
 
72
72
  ## @jgengine/core/crafting/crop
73
73
 
74
- - `ApplyToolResult` (interface): interface ApplyToolResult — ⚠ undocumented
74
+ - `ApplyToolResult` (interface): interface ApplyToolResult { tiles: Map<string, CropTileState>; changed: TileCoord[] } — ⚠ undocumented
75
75
  - `CropCatalog` (type): type CropCatalog = (cropId: string) => CropDef | null — ⚠ undocumented
76
- - `CropDef` (interface): interface CropDef — ⚠ undocumented
77
- - `CropField` (interface): interface CropField — ⚠ undocumented
78
- - `CropTileState` (interface): interface CropTileState — ⚠ undocumented
79
- - `DayTicker` (interface): interface DayTicker — ⚠ undocumented
80
- - `HarvestResult` (interface): interface HarvestResult — ⚠ undocumented
76
+ - `CropDef` (interface): interface CropDef { id: string; stages: readonly number[]; regrowDays?: number; needsDailyWater?: boolean; harvest?: RecipeItem } — ⚠ undocumented
77
+ - `CropField` (interface): interface CropField { get(coord: TileCoord): CropTileState; till(coord: TileCoord, pattern?: TilePattern): TileCoord[]; plant(coord: TileCoord, cropId: string): boolean; water(coord: TileCoord, pattern?: TilePattern): TileCoord[]; harvest(coord: TileCoord): Re… — ⚠ undocumented
78
+ - `CropTileState` (interface): interface CropTileState { soil: SoilState; watered: boolean; cropId: string | null; stage: number; stageProgress: number; harvestable: boolean } — ⚠ undocumented
79
+ - `DayTicker` (interface): interface DayTicker { tick(currentDay: number): number; day(): number } — ⚠ undocumented
80
+ - `HarvestResult` (interface): interface HarvestResult { state: CropTileState; yield: RecipeItem | null } — ⚠ undocumented
81
81
  - `SoilState` (type): type SoilState = "untilled" | "tilled" — ⚠ undocumented
82
82
  - `TileCoord` (type): type TileCoord = readonly [number, number] — ⚠ undocumented
83
83
  - `TilePattern` (type): type TilePattern = readonly TileCoord[] — ⚠ undocumented
@@ -85,14 +85,14 @@
85
85
  ## @jgengine/core/crafting/production
86
86
 
87
87
  - `ItemCounts` (type): type ItemCounts = Readonly<Record<string, number>> — ⚠ undocumented
88
- - `PowerConsumer` (interface): interface PowerConsumer — ⚠ undocumented
89
- - `PowerGridResult` (interface): interface PowerGridResult — ⚠ undocumented
90
- - `ProductionBuildingConfig` (interface): interface ProductionBuildingConfig — ⚠ undocumented
91
- - `ProductionBuildingDef` (interface): interface ProductionBuildingDef — ⚠ undocumented
92
- - `ProductionState` (interface): interface ProductionState — ⚠ undocumented
93
- - `ProductionTickInput` (interface): interface ProductionTickInput — ⚠ undocumented
94
- - `TransportItem` (interface): interface TransportItem — ⚠ undocumented
95
- - `TransportPath` (interface): interface TransportPath — ⚠ undocumented
88
+ - `PowerConsumer` (interface): interface PowerConsumer { id: string; demand: number } — ⚠ undocumented
89
+ - `PowerGridResult` (interface): interface PowerGridResult { powered: ReadonlySet<string>; supply: number; demand: number; deficit: number } — ⚠ undocumented
90
+ - `ProductionBuildingConfig` (interface): interface ProductionBuildingConfig { id: string; inputs?: readonly RecipeItem[]; outputs: readonly RecipeItem[]; rate: number; power?: number; bufferMultiplier?: number } — ⚠ undocumented
91
+ - `ProductionBuildingDef` (interface): interface ProductionBuildingDef { id: string; inputs: readonly RecipeItem[]; outputs: readonly RecipeItem[]; rate: number; power?: number; bufferMultiplier?: number } — ⚠ undocumented
92
+ - `ProductionState` (interface): interface ProductionState { buffer: ItemCounts; output: ItemCounts; progress: number; active: boolean } — ⚠ undocumented · used by `createProductionState`: A production building that converts input items into outputs over time — factory/crafting station.
93
+ - `ProductionTickInput` (interface): interface ProductionTickInput { dt: number; powered?: boolean } — ⚠ undocumented
94
+ - `TransportItem` (interface): interface TransportItem { itemId: string; count: number; position: number } — ⚠ undocumented
95
+ - `TransportPath` (interface): interface TransportPath { length: number; speed: number } — ⚠ undocumented
96
96
  - `acceptsInput` (function): function acceptsInput(def: ProductionBuildingDef, state: ProductionState, itemId: string): boolean — ⚠ undocumented
97
97
  - `advanceTransport` (function): function advanceTransport(path: TransportPath, items: readonly TransportItem[], dt: number): { items: TransportItem[]; delivered: TransportItem[] } — ⚠ undocumented
98
98
  - `createProductionState` (function): function createProductionState(): ProductionState — A production building that converts input items into outputs over time — factory/crafting station.
@@ -105,13 +105,13 @@
105
105
  ## @jgengine/core/crafting/recipe
106
106
 
107
107
  - `CraftCheck` (type): type CraftCheck = { ok: true } | ({ ok: false } & CraftRejection) — ⚠ undocumented
108
- - `CraftContext` (interface): interface CraftContext — ⚠ undocumented
108
+ - `CraftContext` (interface): interface CraftContext { origin?: Vec2; stations?: readonly StationInstance[]; unlocked?: (id: string) => boolean } — ⚠ undocumented
109
109
  - `CraftRejection` (type): type CraftRejection = | { reason: "missing-inputs"; missing: readonly RecipeItem[] } | { reason: "no-station"; station: string } | { reason: "locked"; requires: readonly string[] } | { reason: "no-output-space" } — ⚠ undocumented
110
110
  - `CraftResult` (type): type CraftResult = { status: "ok"; state: InventoryState } | ({ status: "rejected" } & CraftRejection) — ⚠ undocumented
111
- - `RecipeDef` (interface): interface RecipeDef — ⚠ undocumented
112
- - `RecipeGraph` (interface): interface RecipeGraph — ⚠ undocumented
113
- - `RecipeItem` (interface): interface RecipeItem — ⚠ undocumented
114
- - `StationInstance` (interface): interface StationInstance — ⚠ undocumented
111
+ - `RecipeDef` (interface): interface RecipeDef { id: string; inputs: readonly RecipeItem[]; outputs: readonly RecipeItem[]; seconds?: number; station?: string; stationRange?: number; requires?: readonly string[]; category?: string } — ⚠ undocumented
112
+ - `RecipeGraph` (interface): interface RecipeGraph { all(): readonly RecipeDef[]; get(id: string): RecipeDef | null; producing(itemId: string): RecipeDef[]; using(itemId: string): RecipeDef[]; category(categoryId: string): RecipeDef[] } — ⚠ undocumented
113
+ - `RecipeItem` (interface): interface RecipeItem { itemId: string; count: number } — ⚠ undocumented
114
+ - `StationInstance` (interface): interface StationInstance { catalogId: string; position: Vec2 } — ⚠ undocumented
115
115
  - `canCraft` (function): function canCraft(state: InventoryState, layout: InventoryLayout, traits: ItemTraits, recipe: RecipeDef, context: CraftContext = {}): CraftCheck — ⚠ undocumented
116
116
  - `craft` (function): function craft(state: InventoryState, layout: InventoryLayout, traits: ItemTraits, recipe: RecipeDef, context: CraftContext = {}): CraftResult — ⚠ undocumented
117
117
  - `craftSeconds` (function): function craftSeconds(recipe: RecipeDef): number — ⚠ undocumented
@@ -122,26 +122,26 @@
122
122
 
123
123
  ## @jgengine/core/data/dataSource
124
124
 
125
- - `DataSource` (interface): interface DataSource<T> — ⚠ undocumented
126
- - `DataSourceClock` (interface): interface DataSourceClock — ⚠ undocumented
127
- - `DataSourceOptions` (interface): interface DataSourceOptions — ⚠ undocumented
128
- - `DataSourceState` (interface): interface DataSourceState<T> — ⚠ undocumented
125
+ - `DataSource` (interface): interface DataSource<T> { getState(): DataSourceState<T>; subscribe(listener: (state: DataSourceState<T>) => void): () => void; refresh(options?: RefreshOptions): Promise<void>; startPolling(intervalMs?: number): void; stopPolling(): void; dispose(): void } — ⚠ undocumented
126
+ - `DataSourceClock` (interface): interface DataSourceClock { setInterval(handler: () => void, intervalMs: number): unknown; clearInterval(handle: unknown): void } — ⚠ undocumented
127
+ - `DataSourceOptions` (interface): interface DataSourceOptions { intervalMs?: number; clock?: DataSourceClock } — ⚠ undocumented
128
+ - `DataSourceState` (interface): interface DataSourceState<T> { readonly status: DataSourceStatus; readonly data: T | undefined; readonly error: Error | undefined } — ⚠ undocumented
129
129
  - `DataSourceStatus` (type): type DataSourceStatus = "idle" | "loading" | "ready" | "error" — ⚠ undocumented
130
- - `RefreshOptions` (interface): interface RefreshOptions — ⚠ undocumented
130
+ - `RefreshOptions` (interface): interface RefreshOptions { force?: boolean } — ⚠ undocumented
131
131
  - `createDataSource` (function): function createDataSource<T>(load: (signal: AbortSignal) => Promise<T>, options: DataSourceOptions = {}): DataSource<T> — ⚠ undocumented
132
132
 
133
133
  ## @jgengine/core/data/devProxy
134
134
 
135
135
  - `DEFAULT_DEV_PROXY_PREFIX` (const): const DEFAULT_DEV_PROXY_PREFIX: "/proxy" — ⚠ undocumented
136
- - `DevProxyTable` (interface): interface DevProxyTable — ⚠ undocumented
137
- - `ProxiedUrlOptions` (interface): interface ProxiedUrlOptions — ⚠ undocumented
136
+ - `DevProxyTable` (interface): interface DevProxyTable { readonly [routeName: string]: string } — ⚠ undocumented
137
+ - `ProxiedUrlOptions` (interface): interface ProxiedUrlOptions { dev?: boolean; table?: DevProxyTable; prefix?: string } — ⚠ undocumented
138
138
  - `parseDevProxyTable` (function): function parseDevProxyTable(raw: string | undefined): DevProxyTable — ⚠ undocumented
139
139
  - `proxiedUrl` (function): function proxiedUrl(target: string, options: ProxiedUrlOptions = {}): string — ⚠ undocumented
140
140
 
141
141
  ## @jgengine/core/data/fetchJson
142
142
 
143
143
  - `FetchImpl` (type): type FetchImpl = typeof fetch — ⚠ undocumented
144
- - `FetchJsonOptions` (interface): interface FetchJsonOptions — ⚠ undocumented
144
+ - `FetchJsonOptions` (interface): interface FetchJsonOptions { method?: string; headers?: Record<string, string>; body?: string; signal?: AbortSignal; fetchImpl?: FetchImpl } — ⚠ undocumented
145
145
  - `HttpStatusError` (class): class HttpStatusError extends Error — ⚠ undocumented
146
146
  - `JsonParseError` (class): class JsonParseError extends Error — ⚠ undocumented
147
147
  - `fetchJson` (function): function fetchJson<T>(url: string, options: FetchJsonOptions = {}): Promise<T> — ⚠ undocumented
@@ -169,8 +169,11 @@
169
169
  ## @jgengine/core/economy/currency
170
170
 
171
171
  - `CurrencyAdjustment` (type): type CurrencyAdjustment = | { success: true; newBalance: number; appliedDelta: number } | { success: false; reason: string } — ⚠ undocumented
172
- - `CurrencyDefinition` (interface): interface CurrencyDefinition<TCurrencyId extends string = string> — ⚠ undocumented
172
+ - `CurrencyDefinition` (interface): interface CurrencyDefinition<TCurrencyId extends string = string> { id: TCurrencyId; name: string; decimals?: number; symbol?: string; unit?: string } — ⚠ undocumented · used by `formatCurrency`: Format a major-unit value using the currency's declared precision.
173
173
  - `CurrencyOperation` (type): type CurrencyOperation = "add" | "deduct" — ⚠ undocumented
174
+ - `formatCurrency` (function): function formatCurrency(currency: CurrencyDefinition, value: number): string — Format a major-unit value using the currency's declared precision.
175
+ - `fromMinorUnits` (function): function fromMinorUnits(currency: Pick<CurrencyDefinition, "decimals"> | undefined, value: number): number — Convert stored integer minor units to major units for display or existing balance records.
176
+ - `toMinorUnits` (function): function toMinorUnits(currency: Pick<CurrencyDefinition, "decimals"> | undefined, value: number): number — Convert major units to integer minor units, rounding once at the write boundary.
174
177
 
175
178
  ## @jgengine/core/economy/listingBook
176
179
 
@@ -229,7 +232,7 @@
229
232
  ## @jgengine/core/economy/sharedWallet
230
233
 
231
234
  - `BookChargeResult` (type): type BookChargeResult = | { status: "ok"; book: WalletBook } | { status: "rejected"; reason: "insufficient-funds" } — ⚠ undocumented
232
- - `WalletBook` (interface): interface WalletBook — ⚠ undocumented
235
+ - `WalletBook` (interface): interface WalletBook { scopes: Readonly<Record<string, WalletState>>; contributions: Readonly<Record<string, Readonly<Record<string, Readonly<Record<string, number>>>>>> } — ⚠ undocumented
233
236
  - `WalletScope` (type): type WalletScope = | { kind: "user"; userId: string } | { kind: "group"; groupId: string } — ⚠ undocumented
234
237
 
235
238
  ## @jgengine/core/economy/shopStock
@@ -248,10 +251,10 @@
248
251
  ## @jgengine/core/economy/techTree
249
252
 
250
253
  - `TechCheck` (type): type TechCheck = { ok: true } | ({ ok: false } & TechRejection) — ⚠ undocumented
251
- - `TechNodeDef` (interface): interface TechNodeDef extends UnlockDef — ⚠ undocumented
254
+ - `TechNodeDef` (interface): interface TechNodeDef extends UnlockDef { requires?: readonly string[]; cost?: Readonly<Record<string, number>>; grants?: readonly string[]; recipe?: string } — ⚠ undocumented
252
255
  - `TechRejection` (type): type TechRejection = | { reason: "unknown-node" } | { reason: "already-unlocked" } | { reason: "missing-prerequisites"; missing: readonly string[] } — ⚠ undocumented
253
256
  - `TechState` (type): type TechState = UnlockState — ⚠ undocumented
254
- - `TechTree` (interface): interface TechTree — ⚠ undocumented
257
+ - `TechTree` (interface): interface TechTree { has(userId: string, id: string): boolean; canUnlock(userId: string, id: string): TechCheck; unlock(userId: string, id: string): TechCheck; available(userId: string): TechNodeDef[]; recipes(userId: string): string[]; list(userId: string): … — ⚠ undocumented
255
258
 
256
259
  ## @jgengine/core/economy/unlockPoints
257
260
 
@@ -268,14 +271,14 @@
268
271
  - `ChargeOptions` (interface): interface ChargeOptions — Options for {@link charge}/{@link chargeAll}: opt one call into overdraft debt via `overdraft`.
269
272
  - `ChargeResult` (type): type ChargeResult = { status: "ok"; state: WalletState } | { status: "rejected"; reason: "insufficient-funds" } — Outcome of a {@link charge}/{@link chargeAll} attempt: `status: "ok"` carries the debited {@link WalletState}, while `status: "rejected"` leaves the wallet untouched and reports why (currently only `"insufficient-funds"`). Discriminate on `status` before reading `state`.
270
273
  - `Overdraft` (type): type Overdraft = boolean | { max: number } — Opt-in debt affordance for {@link charge}/{@link chargeAll}: `true` allows the balance to go arbitrarily negative, a number caps how far into the red it may go (the charge is rejected once `balance - amount` would fall below `-max`). Omitted (the default) keeps the strict no-debt rule.
271
- - `WalletState` (interface): interface WalletState — ⚠ undocumented
272
- - `balance` (function): function balance(state: WalletState, currency: string): number — ⚠ undocumented
274
+ - `WalletState` (interface): interface WalletState { balances: Readonly<Record<string, number>> } — ⚠ undocumented · used by `canAfford`: True when every currency in `costs` has at least that much balance (a pure, non-mutating check).
275
+ - `balance` (function): function balance(state: WalletState, currency: string | CurrencyDefinition): number — ⚠ undocumented
273
276
  - `canAfford` (function): function canAfford(state: WalletState, costs: Readonly<Record<string, number>>): boolean — True when every currency in `costs` has at least that much balance (a pure, non-mutating check).
274
- - `charge` (function): function charge(state: WalletState, currency: string, amount: number, options?: ChargeOptions): ChargeResult — Deduct `amount`, rejecting when it would leave the balance negative unless `options.overdraft` opts into carrying debt (`true` unlimited, `{ max }` capped) — the strict same-tick affordability check stays the default with `options` omitted.
277
+ - `charge` (function): function charge(state: WalletState, currency: string | CurrencyDefinition, amount: number, options?: ChargeOptions): ChargeResult — Deduct `amount`, rejecting when it would leave the balance negative unless `options.overdraft` opts into carrying debt (`true` unlimited, `{ max }` capped) — the strict same-tick affordability check stays the default with `options` omitted.
275
278
  - `chargeAll` (function): function chargeAll(state: WalletState, costs: Readonly<Record<string, number>>, options?: ChargeOptions): ChargeResult — ⚠ undocumented
276
279
  - `createEmptyWallet` (function): function createEmptyWallet(): WalletState — Hold per-currency balances with affordability checks and charge/grant operations.
277
- - `grant` (function): function grant(state: WalletState, currency: string, amount: number): WalletState — ⚠ undocumented
278
- - `isOverdrawn` (function): function isOverdrawn(state: WalletState, currency: string): boolean — True once `balance(state, currency)` has gone negative under an overdraft-enabled charge.
280
+ - `grant` (function): function grant(state: WalletState, currency: string | CurrencyDefinition, amount: number): WalletState — ⚠ undocumented
281
+ - `isOverdrawn` (function): function isOverdrawn(state: WalletState, currency: string | CurrencyDefinition): boolean — True once `balance(state, currency)` has gone negative under an overdraft-enabled charge.
279
282
 
280
283
  ## @jgengine/core/game/achievements
281
284
 
@@ -309,20 +312,22 @@
309
312
  ## @jgengine/core/game/cameraConfig
310
313
 
311
314
  - `CAMERA_FRUSTUM_DEFAULTS` (const): const CAMERA_FRUSTUM_DEFAULTS: { readonly fov: 55; readonly near: 0.1; readonly far: 300; readonly zoom: 50; } — ⚠ undocumented
312
- - `CameraFollowState` (interface): interface CameraFollowState — ⚠ undocumented
315
+ - `CameraFollowState` (interface): interface CameraFollowState { entityId: string; target: {x: number; y: number; z: number}; camera: {x: number; y: number; z: number}; distance: number } — ⚠ undocumented
313
316
  - `CameraKeyframe` (interface): interface CameraKeyframe — One stop on a scripted camera path (#29).
314
317
  - `CameraProjection` (type): type CameraProjection = "perspective" | "orthographic" — Canvas camera projection. "orthographic" renders a flat 2D-style view (side-scrollers, falling-block puzzles) — pair with `rig: "sideScroll"`; default "perspective".
315
318
  - `CameraRigKind` (type): type CameraRigKind = | "orbit" | "first" | "topDown" | "rts" | "shoulder" | "lockOn" | "chase" | "observer" | "turntable" | "sideScroll" | "inspection" | "none" — Which camera rig the shell mounts. Every rig accepts `followEntityId: null` (avatar-less games — city-builders, card games, auto-battlers — still get a camera). Rigs are tuned through their config block below, never by writing camera positions from `onTick`. - `orbit` — third-person chase (the historical default; `perspective: "third"`). - `first` — pointer-lock mouse-look (`perspective: "first"`). - `topDown` — fixed height/pitch/yaw with decoupled follow (ARPG iso, top-down). - `rts` — free-pan / edge-scroll / rotate / zoom, optional follow. - `shoulder` — over-the-shoulder with ADS transition + shoulder swap. - `lockOn` — yaw bound to the player→target vector; move axis becomes strafe. - `chase` — speed-reactive vehicle chase (speed→FOV, spring arm, shake) + cockpit/hood/rear views. - `observer` — detached spectator/photo cam bound to any entity or fixed point; never reads player input. - `turntable` — slow auto-orbit of a fixed point: a rotating display stand for a scene. The friendly, flat spelling of `observer`'s point-orbit mode; providing `camera.turntable` selects it without an explicit `rig`. - `sideScroll` — fixed lateral follow (2.5D platformer/beat-'em-up side view); reads no player input. - `inspection` — model-viewer / editor rig (#207.7, #866): middle-drag pan, right-drag orbit, scroll zoom toward a configurable anchor; orbits a fixed point, reads no player/entity input. - `none` — no camera rig is mounted; use for HUD-only presentations or a game that manages its own camera.
316
319
  - `CameraShakeConfig` (interface): interface CameraShakeConfig — Camera-shake / trauma defaults (#28). Any rig reads the trauma channel; game systems feed it via `cameraShake()`.
320
+ - `CameraWeaponView` (interface): interface CameraWeaponView — What a camera rig reads about the held weapon each frame; see `GameCameraConfig.weapon`.
317
321
  - `ChaseCameraConfig` (interface): interface ChaseCameraConfig — Speed-reactive vehicle chase rig (#27) — speed→FOV, spring arm, procedural shake, interior views.
318
322
  - `ChaseView` (type): type ChaseView = "chase" | "cockpit" | "hood" | "rear" — Fixed interior view for the chase rig (#27).
319
323
  - `CinematicCameraConfig` (interface): interface CinematicCameraConfig — Scripted keyframe / path player (#29). When set it overrides the active rig.
320
- - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig — ⚠ undocumented
324
+ - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig { eyeHeight?: number; sensitivity?: number; maxPitch?: number; reticle?: boolean; viewmodel?: boolean } — ⚠ undocumented
321
325
  - `GameCameraConfig` (interface): interface GameCameraConfig — Camera tuning for the shell's rig stack: pick the rig via `rig`, then tune it through its matching config block. All fields optional — the default is the third-person orbit rig.
322
326
  - `InspectionCameraConfig` (interface): interface InspectionCameraConfig — Model-viewer / inspection rig (#207.7) — orbit + pan + anchored zoom around a fixed point, never reads player input.
323
327
  - `InspectionZoomAnchor` (type): type InspectionZoomAnchor = "target" | "cursor" | "center" — How scroll-zoom re-anchors the view for the inspection rig (#207.7): - `target` — dolly toward the orbit target (classic OrbitControls behavior). - `cursor` — dolly toward the point under the pointer. - `center` — dolly toward the viewport center; equivalent to `target` for an OrbitControls-driven rig, since the camera always faces `target` and that point already projects to the exact center of the viewport.
324
328
  - `LockOnCameraConfig` (interface): interface LockOnCameraConfig — Lock-on / strafe rig (#26) — yaw bound to player→target, move axis becomes strafe.
325
329
  - `ObserverCameraConfig` (interface): interface ObserverCameraConfig — Detached spectator/photo cam (#120) — binds to any entity or fixed point, never reads player input.
330
+ - `PixelPerfectCameraConfig` (interface): interface PixelPerfectCameraConfig — Pixel-art orthographic camera tuning. `pixelsPerUnit` is the authored pixel density.
326
331
  - `PlayerFovConfig` (interface): interface PlayerFovConfig — Player-facing FOV preference applied across every perspective camera rig. Orthographic projections ignore it.
327
332
  - `RtsCameraConfig` (interface): interface RtsCameraConfig extends TopDownCameraConfig — Free-pan / edge-scroll RTS rig (#24) — pan/rotate/zoom independent of any avatar.
328
333
  - `ShoulderCameraConfig` (interface): interface ShoulderCameraConfig — Over-the-shoulder combat rig (#25) — offset, ADS, shoulder swap, decoupled reticle.
@@ -332,30 +337,32 @@
332
337
 
333
338
  ## @jgengine/core/game/chat
334
339
 
335
- - `Chat` (interface): interface Chat — ⚠ undocumented
336
- - `ChatChannelDef` (interface): interface ChatChannelDef — ⚠ undocumented
340
+ - `Chat` (interface): interface Chat { register(def: ChatChannelDef): void; channels(): ChatChannelDef[]; send(fromUserId: string, body: string): ChatSendResult; send(fromUserId: string, channelId: string, body: string): ChatSendResult; recent(options?: {limit?: number; channe… — ⚠ undocumented
341
+ - `ChatChannelDef` (interface): interface ChatChannelDef { id: string; kind: ChatChannelKind; radius?: number; historyLimit?: number; rateLimit?: ChatRateLimit } — ⚠ undocumented
337
342
  - `ChatChannelKind` (type): type ChatChannelKind = "global" | "party" | "proximity" — ⚠ undocumented
338
- - `ChatDeps` (interface): interface ChatDeps — ⚠ undocumented
339
- - `ChatMessage` (interface): interface ChatMessage — ⚠ undocumented
340
- - `ChatRateLimit` (interface): interface ChatRateLimit — ⚠ undocumented
341
- - `ChatRateLimiter` (interface): interface ChatRateLimiter — ⚠ undocumented
343
+ - `ChatDeps` (interface): interface ChatDeps { events: GameEvents; now?: () => number; party?: {membersOf(userId: string): string[]}; proximity?: EmotesDeps; blockedBy?: (userId: string) => readonly string[]; maxBodyLength?: number; defaultRateLimit?: ChatRateLimit; filter?: ChatFilte… — ⚠ undocumented
344
+ - `ChatMessage` (interface): interface ChatMessage { id: string; channelId: string; fromUserId: string; body: string; at: number } — ⚠ undocumented · used by `createConvexChatTransport` (@jgengine/convex): Wires a game's Convex chat functions into the engine's ChatTransport contract: one live query per subscribed channel (the channel's recent h…
345
+ - `ChatRateLimit` (interface): interface ChatRateLimit { count: number; perMs: number } — ⚠ undocumented
346
+ - `ChatRateLimiter` (interface): interface ChatRateLimiter { allow(key: string, atMs: number): boolean; snapshot(): Record<string, number[]>; restore(state: Record<string, number[]>): void } — ⚠ undocumented
342
347
  - `ChatRecipients` (type): type ChatRecipients = readonly string[] | "all" — ⚠ undocumented
343
348
  - `ChatSendResult` (type): type ChatSendResult = | { message: ChatMessage; recipients: ChatRecipients } | { reason: string } — ⚠ undocumented
344
- - `ChatSnapshot` (interface): interface ChatSnapshot — ⚠ undocumented
345
- - `DEFAULT_CHAT_BODY_LENGTH` (const): const DEFAULT_CHAT_BODY_LENGTH: 500 — ⚠ undocumented
349
+ - `ChatSnapshot` (interface): interface ChatSnapshot { messages: Record<string, ChatMessage[]>; counter: number; rateWindows?: Record<string, Record<string, number[]>> } — ⚠ undocumented
350
+ - `ChatValidation` (type): type ChatValidation = { ok: true; text: string } | { ok: false; reason: string } — Sanitized chat text or a displayable validation failure.
351
+ - `DEFAULT_CHAT_BODY_LENGTH` (const): const DEFAULT_CHAT_BODY_LENGTH: 240 — ⚠ undocumented
346
352
  - `DEFAULT_CHAT_HISTORY_LIMIT` (const): const DEFAULT_CHAT_HISTORY_LIMIT: 100 — ⚠ undocumented
347
353
  - `DEFAULT_CHAT_RATE_LIMIT` (const): const DEFAULT_CHAT_RATE_LIMIT: ChatRateLimit — ⚠ undocumented
348
354
  - `DEFAULT_PROXIMITY_CHAT_RADIUS` (const): const DEFAULT_PROXIMITY_CHAT_RADIUS: 20 — ⚠ undocumented
349
355
  - `WHISPER_CHANNEL_PREFIX` (const): const WHISPER_CHANNEL_PREFIX: "whisper:" — ⚠ undocumented
350
356
  - `createChat` (function): function createChat(deps: ChatDeps): Chat — ⚠ undocumented
351
357
  - `createChatRateLimiter` (function): function createChatRateLimiter(limit: ChatRateLimit): ChatRateLimiter — ⚠ undocumented
358
+ - `validateChatMessage` (function): function validateChatMessage(value: unknown, options: { maxLength?: number } = {}): ChatValidation — Strip control characters and enforce the shared chat message policy before storage or broadcast.
352
359
  - `whisperChannelId` (function): function whisperChannelId(a: string, b: string): string — ⚠ undocumented
353
360
 
354
361
  ## @jgengine/core/game/chatFilter
355
362
 
356
- - `ChatFilter` (interface): interface ChatFilter — ⚠ undocumented
357
- - `ChatFilterConfig` (interface): interface ChatFilterConfig — ⚠ undocumented
358
- - `ChatFilterResult` (interface): interface ChatFilterResult — ⚠ undocumented
363
+ - `ChatFilter` (interface): interface ChatFilter { apply(body: string): ChatFilterResult } — ⚠ undocumented
364
+ - `ChatFilterConfig` (interface): interface ChatFilterConfig { blockedWords: readonly string[]; mode?: "mask" | "reject"; mask?: string } — ⚠ undocumented
365
+ - `ChatFilterResult` (interface): interface ChatFilterResult { ok: boolean; body: string; matched: readonly string[] } — ⚠ undocumented
359
366
  - `createChatFilter` (function): function createChatFilter(config: ChatFilterConfig): ChatFilter — ⚠ undocumented
360
367
  - `normalizeChatText` (function): function normalizeChatText(text: string): string — ⚠ undocumented
361
368
 
@@ -387,16 +394,18 @@
387
394
  ## @jgengine/core/game/controlGate
388
395
 
389
396
  - `PLAY_CONTROLS_STORE_KEY` (const): const PLAY_CONTROLS_STORE_KEY: "jg.playControls" — ⚠ undocumented
397
+ - `actionContextStack` (function): function actionContextStack(ctx: GameContext): ActionContextStack — Returns the context stack associated with a game context.
398
+ - `activeActionCodes` (function): function activeActionCodes(ctx: GameContext, base: ActionCodesMap): ActionCodesMap — Applies active contexts to a base action map for shell input tracking.
390
399
  - `playControlsActive` (function): function playControlsActive(ctx: GameContext): boolean — ⚠ undocumented
391
400
  - `setPlayControlsActive` (function): function setPlayControlsActive(ctx: GameContext, active: boolean): void — ⚠ undocumented
392
401
 
393
402
  ## @jgengine/core/game/cosmetics
394
403
 
395
- - `CosmeticLoadoutDef` (interface): interface CosmeticLoadoutDef — ⚠ undocumented
396
- - `Cosmetics` (interface): interface Cosmetics — ⚠ undocumented
397
- - `CosmeticsChangedEvent` (interface): interface CosmeticsChangedEvent — ⚠ undocumented
398
- - `CosmeticsDeps` (interface): interface CosmeticsDeps — ⚠ undocumented
399
- - `CosmeticsEvents` (interface): interface CosmeticsEvents — ⚠ undocumented
404
+ - `CosmeticLoadoutDef` (interface): interface CosmeticLoadoutDef { slots: Record<string, string> } — ⚠ undocumented
405
+ - `Cosmetics` (interface): interface Cosmetics { register(defs: Record<string, CosmeticLoadoutDef>): void; has(loadoutId: string): boolean; apply(userId: string, loadoutId: string): {reason: string} | null; equip(userId: string, slot: string, cosmeticId: string | null): void; get(userId… — ⚠ undocumented · used by `createCosmetics`: Equip cosmetic skins and customizations by slot, independent of gameplay stats.
406
+ - `CosmeticsChangedEvent` (interface): interface CosmeticsChangedEvent { userId: string; slots: Record<string, string> } — ⚠ undocumented
407
+ - `CosmeticsDeps` (interface): interface CosmeticsDeps { events?: CosmeticsEvents } — ⚠ undocumented · used by `createCosmetics`: Equip cosmetic skins and customizations by slot, independent of gameplay stats.
408
+ - `CosmeticsEvents` (interface): interface CosmeticsEvents { emit(name: "cosmetics.changed", payload: CosmeticsChangedEvent): void } — ⚠ undocumented
400
409
  - `createCosmetics` (function): function createCosmetics(deps: CosmeticsDeps = {}): Cosmetics — Equip cosmetic skins and customizations by slot, independent of gameplay stats.
401
410
 
402
411
  ## @jgengine/core/game/credits
@@ -419,7 +428,7 @@
419
428
  - `LifecycleConfig` (interface): interface LifecycleConfig<TState = unknown> — Declarative start/restart run lifecycle: the state transitions a game's run phase every genre repeats (title screen → live run → live run → title screen again), expressed as pure functions over one typed {@link StoreHandle} slot instead of hand-rolled `commands.define("start"/"restart")` glue that re-derives phase after every mutation. `start`/`restart` receive the store's own value type — the store's `TState`, never `ctx.game.store.get(key) as T` — and return the next value; the runtime writes it back and derives {@link GamePhase} from it via `phaseOf` in one place, so every adopting game gets identical, correct phase-sync for free.
420
429
  - `LoopPlayer` (interface): interface LoopPlayer — Identity of a player joining or leaving a hosted world — passed to the multiplayer loop hooks.
421
430
  - `PersistConfig` (interface): interface PersistConfig — Tunes offline whole-world save (`defineGameDefinition({ persist })`). Offline games already autosave to `localStorage` by default — pass this only to tune it (or `persist: false` to opt out). Defaults: continuous `autosave` to `localStorage`, one slot, no version.
422
- - `PhysicsConfig` (interface): interface PhysicsConfig — World gravity and jump tuning, plus scene-object collision opt-ins, for the game's physics step.
431
+ - `PhysicsConfig` (interface): interface PhysicsConfig — World gravity and jump tuning, plus the optional rigid-body backend and character capsule.
423
432
  - `defineGameDefinition` (function): function defineGameDefinition<TAssetRef extends ModelAssetRef, TMultiplayer>(config: GameDefinitionConfig<TAssetRef, TMultiplayer>): GameDefinition<TAssetRef, TMultiplayer> — Host-level constructor for a bare `GameDefinition`: fills in `scene` and default `assets`, validates `name`, OR-merges `features` from installed systems, and composes `loop` from `systems` + any classic hooks. Games author through `defineGame` from `@jgengine/shell/defineGame`, which calls this and adds the presentation layer; call this directly only from headless hosts that mount no shell.
424
433
 
425
434
  ## @jgengine/core/game/defineSystem
@@ -460,55 +469,56 @@
460
469
 
461
470
  ## @jgengine/core/game/events
462
471
 
472
+ - `AnimationClipEvent` (interface): interface AnimationClipEvent — A named clip moment (`AnimGraph.events`) the rig just crossed — foot plant, hit frame, reload point. Audio and combat listen by `name`.
463
473
  - `AudioLoopSetEvent` (interface): interface AudioLoopSetEvent — Live-update the retained loop `id`: `rate` re-pitches it (1 = authored, the shell clamps to 0.25–4), `gain` rescales its volume (0–1), and `at` repositions its emitter. Emitted every tick to track a live signal (RPM, tire slip); the shell smooths rate/gain and ignores an unknown `id` (#1051).
464
474
  - `AudioLoopStartEvent` (interface): interface AudioLoopStartEvent — Start (or idempotently keep) the retained, id-keyed audio loop `id` from catalog `sound`, optionally anchored at world `at`. Restarting with the same `sound` does not restart the source (no click); a different `sound` replaces it. Drives RPM-pitched engine loops and slip-scaled tire squeal (#1051).
465
475
  - `AudioLoopStopEvent` (interface): interface AudioLoopStopEvent — Stop and dispose the retained loop `id`; an unknown `id` is ignored (#1051).
466
476
  - `AudioMusicEvent` (interface): interface AudioMusicEvent — Crossfade the procedural soundtrack to `theme` (null fades out), optionally transposing the incoming theme by `transpose` semitones.
467
- - `AudioPlayEvent` (interface): interface AudioPlayEvent — ⚠ undocumented
477
+ - `AudioPlayEvent` (interface): interface AudioPlayEvent { sound: string; at?: readonly [number, number, number] } — ⚠ undocumented
468
478
  - `AudioResumeEvent` (type): type AudioResumeEvent = Record<string, never> — Request that the shell's audio engine resume its (browser-gesture-suspended) context; carries no payload.
469
- - `ChatMessageEvent` (interface): interface ChatMessageEvent — ⚠ undocumented
470
- - `CombatHitReactionEvent` (interface): interface CombatHitReactionEvent — ⚠ undocumented
471
- - `CombatTelegraphCancelledEvent` (interface): interface CombatTelegraphCancelledEvent — ⚠ undocumented
472
- - `CombatTelegraphEvent` (interface): interface CombatTelegraphEvent — ⚠ undocumented
479
+ - `ChatMessageEvent` (interface): interface ChatMessageEvent { id: string; channelId: string; fromUserId: string; body: string; at: number; recipients?: readonly string[] } — ⚠ undocumented
480
+ - `CombatHitReactionEvent` (interface): interface CombatHitReactionEvent { instanceId?: string; position: [number, number, number]; hitstopMs: number; shake?: CameraShake; trauma?: number } — ⚠ undocumented
481
+ - `CombatTelegraphCancelledEvent` (interface): interface CombatTelegraphCancelledEvent { id: number } — ⚠ undocumented
482
+ - `CombatTelegraphEvent` (interface): interface CombatTelegraphEvent { id: number; shape: TelegraphShape; position: [number, number, number]; dir?: number; windupMs: number; kind: string } — ⚠ undocumented
473
483
  - `CombatVfxEvent` (interface): interface CombatVfxEvent — A transient sprite-particle effect the shell renders once and expires — one burst of `kind`, tinted `color`, anchored at `from` (and `to` for travel/beam effects).
474
- - `CosmeticsChangedEvent` (interface): interface CosmeticsChangedEvent — ⚠ undocumented
484
+ - `CosmeticsChangedEvent` (interface): interface CosmeticsChangedEvent { userId: string; slots: Record<string, string> } — ⚠ undocumented
475
485
  - `DeathReason` (type): type DeathReason = | { kind: "player_kill"; killerUserId: string; via?: { item?: string } } | { kind: "environment"; source: string } | { kind: "self"; source: string } — Why an entity died — who or what gets credit, for drop/command rules and the `entity.died` event.
476
- - `EmotePlayedEvent` (interface): interface EmotePlayedEvent — ⚠ undocumented
477
- - `EntityAnimationEvent` (interface): interface EntityAnimationEvent — Request that an entity's rig play a one-shot animation clip bound to `event` in its `animation.oneShots` (e.g. an "attack" swing); the shell resolves the clip and plays it once over the locomotion state.
478
- - `EntityDiedEvent` (interface): interface EntityDiedEvent — ⚠ undocumented
479
- - `EntityFloatTextEvent` (interface): interface EntityFloatTextEvent — ⚠ undocumented
480
- - `FormChangedEvent` (interface): interface FormChangedEvent — ⚠ undocumented
486
+ - `EmotePlayedEvent` (interface): interface EmotePlayedEvent { from: string; emoteId: string; at: readonly [number, number, number]; recipients: readonly string[] } — ⚠ undocumented
487
+ - `EntityAnimationEvent` (interface): interface EntityAnimationEvent — Request that an entity's rig play a one-shot animation clip bound to `event` in its `animation.oneShots` (e.g. an "attack" swing); the shell resolves the clip and plays it once over the locomotion state. With an `animation.graph`, `event` arms the trigger of that name.
488
+ - `EntityDiedEvent` (interface): interface EntityDiedEvent { instanceId: string; catalogId: string; userId?: string; displayName?: string; reason: DeathReason; position: [number, number, number]; serverId?: string } — ⚠ undocumented
489
+ - `EntityFloatTextEvent` (interface): interface EntityFloatTextEvent { instanceId?: string; position: [number, number, number]; text: string; kind: string; amount?: number; hitType?: string; element?: string; crit?: boolean; scale?: number } — ⚠ undocumented
490
+ - `FormChangedEvent` (interface): interface FormChangedEvent { instanceId: string; formId: string | null } — ⚠ undocumented
481
491
  - `GameEventHandler` (type): type GameEventHandler<TPayload> = (payload: TPayload) => void — ⚠ undocumented
482
- - `GameEventMap` (interface): interface GameEventMap — ⚠ undocumented
483
- - `GameEvents` (interface): interface GameEvents<TMap extends GameEventMap = GameEventMap> — ⚠ undocumented
484
- - `InventoryAddedEvent` (interface): interface InventoryAddedEvent — ⚠ undocumented
492
+ - `GameEventMap` (interface): interface GameEventMap { "entity.died": EntityDiedEvent; "entity.floatText": EntityFloatTextEvent; "combat.telegraph": CombatTelegraphEvent; "combat.vfx": CombatVfxEvent; "combat.vfxInstance": CombatVfxInstanceEvent; "combat.telegraphCancelled": CombatTelegraphCa… — ⚠ undocumented · used by `createGameEvents`: A typed publish/subscribe bus for gameplay events that systems and HUDs subscribe to.
493
+ - `GameEvents` (interface): interface GameEvents<TMap extends GameEventMap = GameEventMap> { on<TName extends keyof TMap>(name: TName, handler: GameEventHandler<TMap[TName]>): () => void; subscribe<TName extends keyof TMap>(name: TName, handler: GameEventHandler<TMap[TName]>): () => void; emit<TName extends keyof TMap>(name: TNam… — ⚠ undocumented · used by `createGameEvents`: A typed publish/subscribe bus for gameplay events that systems and HUDs subscribe to.
494
+ - `InventoryAddedEvent` (interface): interface InventoryAddedEvent { userId: string; item: string; count: number; source?: string } — ⚠ undocumented
485
495
  - `LootDrop` (interface): interface LootDrop — One granted reward: an inventory `item` id or a `currency` id, plus how many. Named because every consumer of `loot.granted` needs it — a toast renderer, a loot log, a session summary — and each one that re-declares the shape inline is a cast the compiler cannot check.
486
- - `LootGrantedEvent` (interface): interface LootGrantedEvent — ⚠ undocumented
487
- - `PossessionSwappedEvent` (interface): interface PossessionSwappedEvent — ⚠ undocumented
488
- - `ProjectileSettledEvent` (interface): interface ProjectileSettledEvent — ⚠ undocumented
489
- - `QuestAcceptedEvent` (interface): interface QuestAcceptedEvent — ⚠ undocumented
490
- - `QuestCompletedEvent` (interface): interface QuestCompletedEvent — ⚠ undocumented
491
- - `QuestUpdatedEvent` (interface): interface QuestUpdatedEvent — ⚠ undocumented
496
+ - `LootGrantedEvent` (interface): interface LootGrantedEvent { userId: string; drops: LootDrop[]; source?: string } — ⚠ undocumented
497
+ - `PossessionSwappedEvent` (interface): interface PossessionSwappedEvent { userId: string; entityId: string; previousEntityId: string } — ⚠ undocumented
498
+ - `ProjectileSettledEvent` (interface): interface ProjectileSettledEvent { from: string; origin: [number, number, number]; at: [number, number, number]; effect: string; hit: boolean; ballistic: boolean } — ⚠ undocumented
499
+ - `QuestAcceptedEvent` (interface): interface QuestAcceptedEvent { userId: string; questId: string } — ⚠ undocumented
500
+ - `QuestCompletedEvent` (interface): interface QuestCompletedEvent { userId: string; questId: string } — ⚠ undocumented
501
+ - `QuestUpdatedEvent` (interface): interface QuestUpdatedEvent { userId: string; questId: string; objectiveId?: string; progress?: number } — ⚠ undocumented
492
502
  - `RetainedVfxKind` (type): type RetainedVfxKind = string — The archetype of a retained (long-lived, updatable) VFX effect — an open string, not a closed union, so a renderer registers new kinds (beam, tether, zone, target line, looping emitter) without a central branch. `"beam"` is the first shipped retained renderer.
493
- - `SocialFriendAddedEvent` (interface): interface SocialFriendAddedEvent — ⚠ undocumented
494
- - `SocialPartyJoinedEvent` (interface): interface SocialPartyJoinedEvent — ⚠ undocumented
495
- - `SocialPartyLeftEvent` (interface): interface SocialPartyLeftEvent — ⚠ undocumented
496
- - `SocialWorldAcceptedEvent` (interface): interface SocialWorldAcceptedEvent — ⚠ undocumented
497
- - `SocialWorldInvitedEvent` (interface): interface SocialWorldInvitedEvent — ⚠ undocumented
498
- - `StatLevelUpEvent` (interface): interface StatLevelUpEvent — ⚠ undocumented
503
+ - `SocialFriendAddedEvent` (interface): interface SocialFriendAddedEvent { userId: string; friendUserId: string } — ⚠ undocumented
504
+ - `SocialPartyJoinedEvent` (interface): interface SocialPartyJoinedEvent { userId: string; partyId: string } — ⚠ undocumented
505
+ - `SocialPartyLeftEvent` (interface): interface SocialPartyLeftEvent { userId: string; partyId: string } — ⚠ undocumented
506
+ - `SocialWorldAcceptedEvent` (interface): interface SocialWorldAcceptedEvent { inviteId: string; userId: string; fromUserId: string; serverId: string; joinCode?: string } — ⚠ undocumented
507
+ - `SocialWorldInvitedEvent` (interface): interface SocialWorldInvitedEvent { inviteId: string; fromUserId: string; toUserId: string; serverId: string; joinCode?: string } — ⚠ undocumented
508
+ - `StatLevelUpEvent` (interface): interface StatLevelUpEvent { userId: string; stat: string; level: number } — ⚠ undocumented
499
509
  - `VfxKind` (type): type VfxKind = "projectile" | "beam" | "nova" | "glow" | "spark" — The visual archetype of a spell/ability effect burst: a traveling bolt, a connecting beam, an expanding ground nova, a soft aura glow, or a scattering impact spark.
500
510
  - `VfxRef` (type): type VfxRef = string | readonly [number, number, number] — An endpoint of a retained VFX instance: either an entity instance id (a renderer resolves and follows its live pose each frame) or a fixed `[x, y, z]` world point. Kept serializable so the effect replicates as plain data.
501
- - `WorldItemDroppedEvent` (interface): interface WorldItemDroppedEvent — ⚠ undocumented
502
- - `WorldItemPickedUpEvent` (interface): interface WorldItemPickedUpEvent — ⚠ undocumented
511
+ - `WorldItemDroppedEvent` (interface): interface WorldItemDroppedEvent { instanceId: string; itemId: string; rarity: string; count: number; position: [number, number, number]; source?: string } — ⚠ undocumented
512
+ - `WorldItemPickedUpEvent` (interface): interface WorldItemPickedUpEvent { instanceId: string; userId: string; itemId: string; rarity: string; count: number } — ⚠ undocumented
503
513
  - `createGameEvents` (function): function createGameEvents<TMap extends GameEventMap = GameEventMap>(): GameEvents<TMap> — A typed publish/subscribe bus for gameplay events that systems and HUDs subscribe to.
504
514
  - `lootDropsOf` (function): function lootDropsOf(data: unknown): readonly LootDrop[] — Read the drops out of a `loot.granted` payload that arrived as `unknown` — a `FeedEntry.data`, a replicated event, a persisted log row. Returns `[]` for anything that is not shaped like a loot grant, so a renderer never has to guard the payload itself: `entry.data as { drops?: ... }` is the cast four separate call sites were writing, and the one that omitted the `| undefined` would have thrown on a payload-less entry.
505
515
 
506
516
  ## @jgengine/core/game/feed
507
517
 
508
- - `FeedEntry` (interface): interface FeedEntry<T = unknown> — ⚠ undocumented
518
+ - `FeedEntry` (interface): interface FeedEntry<T = unknown> { at: number; data: T } — ⚠ undocumented · used by `ToastStack` (@jgengine/react): Render `ctx.game.feed`'s entries for `action` as a newest-first toast stack — the feed-backed sibling of `@jgengine/core/game/toasts`' `crea…
509
519
  - `FeedWindow` (interface): interface FeedWindow — Bounds for {@link appendFeed} / {@link pruneFeed}: newest-`limit` cap and/or `ttl` age window.
510
- - `GameFeed` (interface): interface GameFeed — ⚠ undocumented
511
- - `GameFeedOptions` (interface): interface GameFeedOptions — ⚠ undocumented
520
+ - `GameFeed` (interface): interface GameFeed { bind<TName extends keyof GameEventMap>(action: TName, events: GameEvents): () => void; push(action: string, entry: unknown): void; recent(action: string, options?: {limit?: number}): FeedEntry[]; subscribe(action: string, listener: (entry… — ⚠ undocumented · used by `createGameFeed`: A rolling per-action feed of recent gameplay events, bindable to the event bus — the HUD ticker and killfeed history.
521
+ - `GameFeedOptions` (interface): interface GameFeedOptions { limit?: number } — ⚠ undocumented · used by `createGameFeed`: A rolling per-action feed of recent gameplay events, bindable to the event bus — the HUD ticker and killfeed history.
512
522
  - `TimedFeedEntry` (interface): interface TimedFeedEntry — Any feed entry carrying a game-time (or wall-clock) `at` stamp for age-based pruning.
513
523
  - `appendFeed` (function): function appendFeed<T extends TimedFeedEntry>(list: readonly T[], entry: T, options?: FeedWindow): T[] — Append `entry` to a flat, serializable feed list, then bound it by age (`ttl`, relative to the appended entry's `at`) and/or count (`limit`, newest kept). Works on the game's own flat entry shape — anything with an `at` stamp — so `{ id, text, tone, at }`-style notice lists and event logs drop into serialized state with no `{ at, data }` envelope. Returns a new array.
514
524
  - `appendFeedEntry` (function): function appendFeedEntry<T>(buffer: readonly FeedEntry<T>[], entry: FeedEntry<T>, limit: number): FeedEntry<T>[] — ⚠ undocumented
@@ -535,10 +545,10 @@
535
545
  ## @jgengine/core/game/leaderboard
536
546
 
537
547
  - `IncrementResult` (type): type IncrementResult = { status: "ok"; value: number } | { status: "rejected"; reason: "not-tracked" } — ⚠ undocumented
538
- - `Leaderboard` (interface): interface Leaderboard — ⚠ undocumented
539
- - `LeaderboardRow` (interface): interface LeaderboardRow — ⚠ undocumented
548
+ - `Leaderboard` (interface): interface Leaderboard { track(def: LeaderboardTrackDef): void; tracked(): {stat: string; scope: LeaderboardScope}[]; increment(userId: string, stat: string, options: {scope: LeaderboardScope; serverId?: string; by?: number}): IncrementResult; getTop(stat: string… — ⚠ undocumented · used by `createLeaderboard`: Ranked score tracking across global, server, and per-profile scopes, with top-N queries and per-profile lookups.
549
+ - `LeaderboardRow` (interface): interface LeaderboardRow { stat: string; scope: LeaderboardScope; serverId?: string; userId: string; value: number } — ⚠ undocumented · used by `createLeaderboard`: Ranked score tracking across global, server, and per-profile scopes, with top-N queries and per-profile lookups.
540
550
  - `LeaderboardScope` (type): type LeaderboardScope = "global" | "server" | "profile" — ⚠ undocumented
541
- - `LeaderboardTrackDef` (interface): interface LeaderboardTrackDef — ⚠ undocumented
551
+ - `LeaderboardTrackDef` (interface): interface LeaderboardTrackDef { stat?: string; currency?: string; scope: LeaderboardScope } — ⚠ undocumented
542
552
  - `createLeaderboard` (function): function createLeaderboard(sink?: { onIncrement?(row: LeaderboardRow): void }): Leaderboard — Ranked score tracking across global, server, and per-profile scopes, with top-N queries and per-profile lookups.
543
553
 
544
554
  ## @jgengine/core/game/leaderboardRank
@@ -552,31 +562,31 @@
552
562
 
553
563
  ## @jgengine/core/game/levelSequence
554
564
 
555
- - `CurrentLevel` (interface): interface CurrentLevel<TLevelConfig> — ⚠ undocumented
556
- - `LevelDescriptor` (interface): interface LevelDescriptor<TLevelConfig> — ⚠ undocumented
565
+ - `CurrentLevel` (interface): interface CurrentLevel<TLevelConfig> { id: string; index: number; config: TLevelConfig; attempt: number } — ⚠ undocumented
566
+ - `LevelDescriptor` (interface): interface LevelDescriptor<TLevelConfig> { id: string; config: TLevelConfig } — ⚠ undocumented
557
567
  - `LevelRecord` (interface): interface LevelRecord — Persisted per-level outcome: whether it has ever been cleared and the best star rating achieved.
558
- - `LevelSequence` (interface): interface LevelSequence<TLevelConfig> — ⚠ undocumented
559
- - `LevelSequenceConfig` (interface): interface LevelSequenceConfig<TLevelConfig> — ⚠ undocumented
560
- - `LevelSequenceProgress` (interface): interface LevelSequenceProgress — ⚠ undocumented
568
+ - `LevelSequence` (interface): interface LevelSequence<TLevelConfig> { current(): CurrentLevel<TLevelConfig> | null; status(): LevelSequenceStatus; start(): void; clear(stars?: LevelStars): void; fail(): "retry" | "failed"; retry(): boolean; advance(): boolean; select(level: string): boolean; isUnlocked(leve… — ⚠ undocumented · used by `createLevelSequence`: A pure, deterministic level campaign: an ordered list of levels, each with its own opaque config, played through a `start` → (`clear` → `adv…
569
+ - `LevelSequenceConfig` (interface): interface LevelSequenceConfig<TLevelConfig> { levels: readonly LevelDescriptor<TLevelConfig>[]; retriesPerLevel?: number; key?: string; storage?: KeyValueStorage | null } — ⚠ undocumented · used by `createLevelSequence`: A pure, deterministic level campaign: an ordered list of levels, each with its own opaque config, played through a `start` → (`clear` → `adv…
570
+ - `LevelSequenceProgress` (interface): interface LevelSequenceProgress { index: number; total: number; cleared: readonly string[] } — ⚠ undocumented
561
571
  - `LevelSequenceStatus` (type): type LevelSequenceStatus = "idle" | "playing" | "cleared" | "failed" | "complete" — ⚠ undocumented
562
572
  - `LevelStars` (type): type LevelStars = 0 | 1 | 2 | 3 — A level's star rating, 0 (cleared, no stars) to 3.
563
573
  - `createLevelSequence` (function): function createLevelSequence<TLevelConfig>(config: LevelSequenceConfig<TLevelConfig>): LevelSequence<TLevelConfig> — A pure, deterministic level campaign: an ordered list of levels, each with its own opaque config, played through a `start` → (`clear` → `advance`)* → `complete` happy path, with `fail`/`retry` handling per-level attempts. Mirrors the reducer style of `game/race.ts` and `ai/spawnDirector.ts` — no I/O, no timers, just state transitions driven by the caller.
564
574
 
565
575
  ## @jgengine/core/game/loadout
566
576
 
567
- - `LoadoutDef` (interface): interface LoadoutDef — ⚠ undocumented
568
- - `LoadoutDeps` (interface): interface LoadoutDeps — ⚠ undocumented
569
- - `LoadoutInventoryTransaction` (interface): interface LoadoutInventoryTransaction — ⚠ undocumented
570
- - `LoadoutItemEntry` (interface): interface LoadoutItemEntry — ⚠ undocumented
571
- - `Loadouts` (interface): interface Loadouts — ⚠ undocumented
577
+ - `LoadoutDef` (interface): interface LoadoutDef { inventories?: Record<string, LoadoutItemEntry[]>; stats?: Record<string, {current: number; max?: number; min?: number}>; economy?: Record<string, number>; unlocks?: string[] } — ⚠ undocumented
578
+ - `LoadoutDeps` (interface): interface LoadoutDeps { inventory: {begin(userId: string): LoadoutInventoryTransaction}; stats: {seed(userId: string, statId: string, pool: {current: number; max?: number; min?: number}): void}; economy: {grant(userId: string, currencyId: string, amount: number)… — ⚠ undocumented · used by `createLoadouts`: Save, name, and swap equipment loadouts.
579
+ - `LoadoutInventoryTransaction` (interface): interface LoadoutInventoryTransaction { put(inventoryId: string, itemId: string, count: number, slot?: number): {reason: string} | null; commit(): void } — ⚠ undocumented
580
+ - `LoadoutItemEntry` (interface): interface LoadoutItemEntry { item: string; count: number; slot?: number } — ⚠ undocumented
581
+ - `Loadouts` (interface): interface Loadouts { register(defs: Record<string, LoadoutDef>): void; has(loadoutId: string): boolean; applyLoadout(userId: string, loadoutId: string): {reason: string} | null } — ⚠ undocumented · used by `createLoadouts`: Save, name, and swap equipment loadouts.
572
582
  - `createLoadouts` (function): function createLoadouts(deps: LoadoutDeps): Loadouts — Save, name, and swap equipment loadouts.
573
583
 
574
584
  ## @jgengine/core/game/lootFilter
575
585
 
576
- - `LootFilterCondition` (interface): interface LootFilterCondition — ⚠ undocumented
577
- - `LootFilterItem` (interface): interface LootFilterItem — ⚠ undocumented
578
- - `LootFilterOverride` (interface): interface LootFilterOverride — ⚠ undocumented
579
- - `LootFilterRule` (interface): interface LootFilterRule — ⚠ undocumented
586
+ - `LootFilterCondition` (interface): interface LootFilterCondition { rarity?: string | readonly string[]; baseType?: string | readonly string[]; minAffixTier?: number; maxAffixTier?: number } — ⚠ undocumented
587
+ - `LootFilterItem` (interface): interface LootFilterItem { rarity: string; baseType: string; affixTier?: number } — ⚠ undocumented · used by `evaluateLootFilter`: First matching rule wins (PoE/Last Epoch block semantics) — later rules never override an earlier match.
588
+ - `LootFilterOverride` (interface): interface LootFilterOverride { hidden?: boolean; color?: string; beam?: boolean; label?: string } — ⚠ undocumented · used by `evaluateLootFilter`: First matching rule wins (PoE/Last Epoch block semantics) — later rules never override an earlier match.
589
+ - `LootFilterRule` (interface): interface LootFilterRule { id: string; when: LootFilterCondition; hide?: boolean; color?: string; beam?: boolean; label?: string } — ⚠ undocumented · used by `evaluateLootFilter`: First matching rule wins (PoE/Last Epoch block semantics) — later rules never override an earlier match.
580
590
  - `evaluateLootFilter` (function): function evaluateLootFilter(rules: readonly LootFilterRule[], item: LootFilterItem): LootFilterOverride — First matching rule wins (PoE/Last Epoch block semantics) — later rules never override an earlier match. Returns overrides only; fields the rule doesn't set are left for the caller's baseline (rarity style) to fill in.
581
591
  - `lootFilter` (function): function lootFilter(rules: readonly LootFilterRule[]): readonly LootFilterRule[] — Validating factory — rule ids must be unique so authoring mistakes fail loudly.
582
592
 
@@ -602,7 +612,7 @@
602
612
 
603
613
  - `Drop` (interface): interface Drop — A resolved loot outcome — one item or currency grant with its rolled count.
604
614
  - `LootEntry` (interface): interface LootEntry — One possible drop in a {@link LootTableDef} — an item, currency, or generated item, its count range, and its odds.
605
- - `LootRegistry` (interface): interface LootRegistry — ⚠ undocumented
615
+ - `LootRegistry` (interface): interface LootRegistry { register(def: LootTableDef): void; has(id: string): boolean; roll(id: string, rng?: () => number): Drop[]; snapshot(): LootTableDef[]; restore(next: readonly LootTableDef[]): void } — ⚠ undocumented · used by `createLootRegistry`: Register named loot tables and roll weighted randomized drops from them.
606
616
  - `LootRegistryOptions` (interface): interface LootRegistryOptions — Options for {@link createLootRegistry} — inject a default RNG so bare `roll(id)` uses the world stream.
607
617
  - `LootTableDef` (interface): interface LootTableDef — A named, validated loot table — its roll count, weighted-vs-independent mode, and candidate entries.
608
618
  - `createLootRegistry` (function): function createLootRegistry(options: LootRegistryOptions = {}): LootRegistry — Register named loot tables and roll weighted randomized drops from them.
@@ -665,39 +675,48 @@
665
675
 
666
676
  - `DEFAULT_PING_CATEGORIES` (const): const DEFAULT_PING_CATEGORIES: Record<PingCategory, PingCategoryDef> — Content-agnostic default ping wheel: enemy / loot / location / danger.
667
677
  - `PING_FEED_ACTION` (const): const PING_FEED_ACTION: "party.ping" — ⚠ undocumented
668
- - `PingCategory` (type): type PingCategory = string — ⚠ undocumented
669
- - `PingCategoryDef` (interface): interface PingCategoryDef — ⚠ undocumented
670
- - `PingClassifyDeps` (interface): interface PingClassifyDeps — ⚠ undocumented
671
- - `PingClassifyOptions` (interface): interface PingClassifyOptions — ⚠ undocumented
672
- - `PingFeedSink` (interface): interface PingFeedSink — ⚠ undocumented
673
- - `PingParty` (interface): interface PingParty — ⚠ undocumented
674
- - `PingPayload` (interface): interface PingPayload — ⚠ undocumented
675
- - `PingSystem` (interface): interface PingSystem — ⚠ undocumented
676
- - `PingSystemDeps` (interface): interface PingSystemDeps — ⚠ undocumented
678
+ - `PingCategory` (type): type PingCategory = string — ⚠ undocumented · used by `DEFAULT_PING_CATEGORIES`: Content-agnostic default ping wheel: enemy / loot / location / danger.
679
+ - `PingCategoryDef` (interface): interface PingCategoryDef { id: PingCategory; markerKind: string; label: string; callout: string } — ⚠ undocumented · used by `DEFAULT_PING_CATEGORIES`: Content-agnostic default ping wheel: enemy / loot / location / danger.
680
+ - `PingClassifyDeps` (interface): interface PingClassifyDeps { roleOf?(entityId: string): string | null | undefined; categoryOf?(objectId: string): PingCategory | null | undefined } — ⚠ undocumented · used by `classifyPing`: Classify what a pointer/aim ray hit into a ping category.
681
+ - `PingClassifyOptions` (interface): interface PingClassifyOptions { hostileRoles?: readonly string[]; enemyCategory?: PingCategory; lootCategory?: PingCategory; locationCategory?: PingCategory; dangerCategory?: PingCategory } — ⚠ undocumented · used by `classifyPing`: Classify what a pointer/aim ray hit into a ping category.
682
+ - `PingFeedSink` (interface): interface PingFeedSink { push(action: string, entry: unknown): void } — ⚠ undocumented
683
+ - `PingParty` (interface): interface PingParty { membersOf(userId: string): string[] } — ⚠ undocumented
684
+ - `PingPayload` (interface): interface PingPayload { id: string; from: string; category: PingCategory; position: MarkerPosition; entityId: string | null; objectId: string | null; at: number; callout: string; recipients: readonly string[] } — ⚠ undocumented
685
+ - `PingSystem` (interface): interface PingSystem { classify(hit: PointerHit): PingCategory; buildPayload(from: string, hit: PointerHit, category?: PingCategory): PingPayload; broadcast(payload: PingPayload): MapMarker; ping(from: string, hit: PointerHit, category?: PingCategory): PingPayl… — ⚠ undocumented · used by `createPingSystem`: Contextual ping/marker communication between teammates, classified by what was pinged.
686
+ - `PingSystemDeps` (interface): interface PingSystemDeps { markers: MarkerSet; feed: PingFeedSink; party?: PingParty; categories?: Record<PingCategory, PingCategoryDef>; now?(): number; ttlMs?: number; feedAction?: string; classify?: PingClassifyDeps; classifyOptions?: PingClassifyOptions } — ⚠ undocumented · used by `createPingSystem`: Contextual ping/marker communication between teammates, classified by what was pinged.
677
687
  - `classifyPing` (function): function classifyPing(hit: PointerHit, deps: PingClassifyDeps = {}, options: PingClassifyOptions = {}): PingCategory — Classify what a pointer/aim ray hit into a ping category. Entity hits resolve by catalog role (hostile → enemy, else location); object hits by an optional catalog category tag; open ground is a location ping.
678
688
  - `createPingSystem` (function): function createPingSystem(deps: PingSystemDeps): PingSystem — Contextual ping/marker communication between teammates, classified by what was pinged.
679
689
 
690
+ ## @jgengine/core/game/pixelPerfect
691
+
692
+ - `PixelPerfectFrustum` (interface): interface PixelPerfectFrustum — The orthographic bounds and scale derived from a pixel-perfect camera config.
693
+ - `PixelPerfectViewport` (interface): interface PixelPerfectViewport — Viewport dimensions in device-independent canvas pixels.
694
+ - `pixelPerfectFrustum` (function): function pixelPerfectFrustum(viewport: PixelPerfectViewport, pixelsPerUnit: number, integerScale = false): PixelPerfectFrustum — Computes an orthographic frustum whose world units map to the requested pixel density. Integer scaling chooses the largest whole-number density multiplier available in the viewport.
695
+ - `snapPixelPerfectPosition` (function): function snapPixelPerfectPosition<T extends { x: number; y: number; z: number }>(position: T, pixelsPerUnit: number): T — Snaps a camera position to the authored pixel grid without changing its orientation.
696
+
680
697
  ## @jgengine/core/game/playableGame
681
698
 
682
- - `AmbientLightingConfig` (interface): interface AmbientLightingConfig — ⚠ undocumented
699
+ - `AmbientLightingConfig` (interface): interface AmbientLightingConfig { color?: string; intensity?: number } — ⚠ undocumented
683
700
  - `BackdropConfig` (interface): interface BackdropConfig — Generic sky/background/fog for ANY world kind, including a custom `environment` component (#207.6).
684
- - `BackdropFogConfig` (interface): interface BackdropFogConfig — ⚠ undocumented
701
+ - `BackdropFogConfig` (interface): interface BackdropFogConfig { color?: string; near?: number; far?: number; density?: number } — ⚠ undocumented
685
702
  - `CAMERA_FRUSTUM_DEFAULTS` (const): const CAMERA_FRUSTUM_DEFAULTS: { readonly fov: 55; readonly near: 0.1; readonly far: 300; readonly zoom: 50; } — ⚠ undocumented
686
- - `CameraFollowState` (interface): interface CameraFollowState — ⚠ undocumented
703
+ - `CameraFollowState` (interface): interface CameraFollowState { entityId: string; target: {x: number; y: number; z: number}; camera: {x: number; y: number; z: number}; distance: number } — ⚠ undocumented
687
704
  - `CameraKeyframe` (interface): interface CameraKeyframe — One stop on a scripted camera path (#29).
688
705
  - `CameraProjection` (type): type CameraProjection = "perspective" | "orthographic" — Canvas camera projection. "orthographic" renders a flat 2D-style view (side-scrollers, falling-block puzzles) — pair with `rig: "sideScroll"`; default "perspective".
689
706
  - `CameraRigKind` (type): type CameraRigKind = | "orbit" | "first" | "topDown" | "rts" | "shoulder" | "lockOn" | "chase" | "observer" | "turntable" | "sideScroll" | "inspection" | "none" — Which camera rig the shell mounts. Every rig accepts `followEntityId: null` (avatar-less games — city-builders, card games, auto-battlers — still get a camera). Rigs are tuned through their config block below, never by writing camera positions from `onTick`. - `orbit` — third-person chase (the historical default; `perspective: "third"`). - `first` — pointer-lock mouse-look (`perspective: "first"`). - `topDown` — fixed height/pitch/yaw with decoupled follow (ARPG iso, top-down). - `rts` — free-pan / edge-scroll / rotate / zoom, optional follow. - `shoulder` — over-the-shoulder with ADS transition + shoulder swap. - `lockOn` — yaw bound to the player→target vector; move axis becomes strafe. - `chase` — speed-reactive vehicle chase (speed→FOV, spring arm, shake) + cockpit/hood/rear views. - `observer` — detached spectator/photo cam bound to any entity or fixed point; never reads player input. - `turntable` — slow auto-orbit of a fixed point: a rotating display stand for a scene. The friendly, flat spelling of `observer`'s point-orbit mode; providing `camera.turntable` selects it without an explicit `rig`. - `sideScroll` — fixed lateral follow (2.5D platformer/beat-'em-up side view); reads no player input. - `inspection` — model-viewer / editor rig (#207.7, #866): middle-drag pan, right-drag orbit, scroll zoom toward a configurable anchor; orbits a fixed point, reads no player/entity input. - `none` — no camera rig is mounted; use for HUD-only presentations or a game that manages its own camera.
690
707
  - `CameraShakeConfig` (interface): interface CameraShakeConfig — Camera-shake / trauma defaults (#28). Any rig reads the trauma channel; game systems feed it via `cameraShake()`.
708
+ - `CameraWeaponView` (interface): interface CameraWeaponView — What a camera rig reads about the held weapon each frame; see `GameCameraConfig.weapon`.
691
709
  - `ChaseCameraConfig` (interface): interface ChaseCameraConfig — Speed-reactive vehicle chase rig (#27) — speed→FOV, spring arm, procedural shake, interior views.
692
710
  - `ChaseView` (type): type ChaseView = "chase" | "cockpit" | "hood" | "rear" — Fixed interior view for the chase rig (#27).
693
711
  - `CinematicCameraConfig` (interface): interface CinematicCameraConfig — Scripted keyframe / path player (#29). When set it overrides the active rig.
694
- - `DirectionalLightingConfig` (interface): interface DirectionalLightingConfig — ⚠ undocumented
695
- - `EntitySpriteConfig` (interface): interface EntitySpriteConfig — ⚠ undocumented
696
- - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig — ⚠ undocumented
712
+ - `DirectionalLightingConfig` (interface): interface DirectionalLightingConfig { color?: string; intensity?: number; position: readonly [number, number, number]; castShadow?: boolean; shadowMapSize?: number; shadowCameraSize?: number; cascades?: number; shadowMaxFar?: number; shadowBias?: number; shadowNormalBias?: nu… — ⚠ undocumented
713
+ - `EntitySpriteConfig` (interface): interface EntitySpriteConfig { url: string; width: number; height: number; y: number; clip?: {atlas: SpriteAtlas; animation: string} } — ⚠ undocumented
714
+ - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig { eyeHeight?: number; sensitivity?: number; maxPitch?: number; reticle?: boolean; viewmodel?: boolean } — ⚠ undocumented
715
+ - `FlightConfig` (interface): interface FlightConfig — Free-flight families moved into the walk controller so one seam covers ground + air — creative/spectator/noclip/hover are weightless, aircraft, rotorcraft and rockets use `physics/aircraftDynamics`.
697
716
  - `GameCameraConfig` (interface): interface GameCameraConfig — Camera tuning for the shell's rig stack: pick the rig via `rig`, then tune it through its matching config block. All fields optional — the default is the third-person orbit rig.
698
717
  - `GameCaptureConfig` (interface): interface GameCaptureConfig — How a game makes itself screenshottable: the commands that reach live play or a named screen, the framings worth re-capturing, and the progress metrics a bot playtest samples. Declaring these once is what lets a capture host reproduce a view instead of re-deriving it by hand every run.
699
718
  - `GameCaptureView` (interface): interface GameCaptureView — How a screenshot host reaches live gameplay in this game — the data behind `shoot --mode play`.
700
- - `HemisphereLightingConfig` (interface): interface HemisphereLightingConfig — ⚠ undocumented
719
+ - `HemisphereLightingConfig` (interface): interface HemisphereLightingConfig { skyColor?: string; groundColor?: string; intensity?: number } — ⚠ undocumented
701
720
  - `InspectionCameraConfig` (interface): interface InspectionCameraConfig — Model-viewer / inspection rig (#207.7) — orbit + pan + anchored zoom around a fixed point, never reads player input.
702
721
  - `InspectionZoomAnchor` (type): type InspectionZoomAnchor = "target" | "cursor" | "center" — How scroll-zoom re-anchors the view for the inspection rig (#207.7): - `target` — dolly toward the orbit target (classic OrbitControls behavior). - `cursor` — dolly toward the point under the pointer. - `center` — dolly toward the viewport center; equivalent to `target` for an OrbitControls-driven rig, since the camera always faces `target` and that point already projects to the exact center of the viewport.
703
722
  - `LightingConfig` (interface): interface LightingConfig — Declarative lighting replacing the shell's hardcoded ambient/directional default (#207.5); mounts regardless of world kind, only when supplied.
@@ -705,26 +724,30 @@
705
724
  - `ModelAnimationConfig` (interface): interface ModelAnimationConfig — Rig playback for a `ModelConfig`'s GLTF animation clips — looping idles, one-shots, and held poses.
706
725
  - `ModelAnimationStates` (interface): interface ModelAnimationStates — Movement-state clip set for `ModelAnimationConfig.states`: the shell reads the entity's live speed each frame and crossfades between these clips, so a walking mob animates without any game-side driver.
707
726
  - `ModelAttachment` (interface): interface ModelAttachment — Parents a prop/weapon model to a named bone or node on the host model's rig — a sword on `handslot.r`, a spellbook offhand — following the bone's animated transform each frame.
708
- - `ModelConfig` (interface): interface ModelConfig — ⚠ undocumented
727
+ - `ModelConfig` (interface): interface ModelConfig { url: string; scale?: number; targetHeight?: number; y?: number; anchor?: "center" | "origin"; dims?: ModelDims; collisionMesh?: CollisionMeshData; material?: ModelMaterialOverride; shadows?: "cast" | "receive" | "both" | "none"; animation… — ⚠ undocumented · used by `PartMotionRig` (@jgengine/shell/render/PartMotion): Procedural motion rig for a rig-less part-composed character (`ModelPart.role` — see `@jgengine/core/game/partAnimation`).
728
+ - `ModelIkConfig` (interface): interface ModelIkConfig — Bone names and limits for {@link ModelConfig.ik}.
709
729
  - `ModelMaterialMaps` (interface): interface ModelMaterialMaps — Real PBR map URLs (e.g. `buildMaterialCatalog(...).resolve(id)!.maps` from `@jgengine/assets`) layered onto a model's material — the seam for texturing an otherwise-flat/untextured GLB. Any role may be omitted to keep the model's own map.
710
- - `ModelMaterialOverride` (interface): interface ModelMaterialOverride — Per-entity PBR material override (#151.3) applied to every `MeshStandardMaterial` in the model's cloned scene graph.
730
+ - `ModelMaterialOverride` (interface): interface ModelMaterialOverride — Per-entity PBR material override (#151.3) applied to every standard or physical material in the model's cloned scene graph.
711
731
  - `ModelPart` (interface): interface ModelPart — Static child model stacked at a fixed local offset under its parent's transform — no bone/rig resolution, unlike `ModelAttachment`. Assembles a compound entity (e.g. a modular castle wall + tower + roof) from several single-mesh kit pieces.
712
732
  - `ModelRimLight` (interface): interface ModelRimLight — Fresnel rim-light term added on top of a model's lighting — see {@link ModelMaterialOverride.rim}.
713
733
  - `MovementCommitFrame` (interface): interface MovementCommitFrame — One frame's movement resolution handed to `PlayerMovementConfig.beforeCommit`.
714
- - `ObjectStyle` (interface): interface ObjectStyle — ⚠ undocumented
734
+ - `MovementFeelConfig` (interface): interface MovementFeelConfig — Feel knobs for the built-in walk controller; see {@link PlayerMovementConfig.feel}.
735
+ - `ObjectStyle` (interface): interface ObjectStyle { color?: string; opacity?: number; hidden?: boolean } — ⚠ undocumented
715
736
  - `ObserverCameraConfig` (interface): interface ObserverCameraConfig — Detached spectator/photo cam (#120) — binds to any entity or fixed point, never reads player input.
716
- - `PlayableGame` (interface): interface PlayableGame<TUi = unknown, TWorldOverlay = unknown, TRenderEntity = never, TRenderObject = never, TViewmodel = unknown, TOverlay = TWorldOverlay> — ⚠ undocumented
737
+ - `PlayableGame` (interface): interface PlayableGame<TUi = unknown, TWorldOverlay = unknown, TRenderEntity = never, TRenderObject = never, TViewmodel = unknown, TOverlay = TWorldOverlay> { game: GameDefinition; content: GameContextContent; loop: Required<Omit<GameLoop<GameContext>, "onPlayerLeave">> & Pick<GameLoop<GameContext>, "onPlayerLeave">; GameUI: TUi; presentation?: "3d" | "hud"; WorldOverlay?: TOverlay; environment… — ⚠ undocumented · used by `defineGame` (@jgengine/shell/defineGame): The one public authoring entry point: compose engine fields (systems, world, physics, input) and presentation fields (camera, HUD, audio, au…
717
738
  - `PlayerFovConfig` (interface): interface PlayerFovConfig — Player-facing FOV preference applied across every perspective camera rig. Orthographic projections ignore it.
718
739
  - `PlayerMovementConfig` (interface): interface PlayerMovementConfig — Movement-control levers for the shell-driven local player walk controller.
719
- - `PointerConfig` (interface): interface PointerConfig — ⚠ undocumented
740
+ - `PointLightingConfig` (interface): interface PointLightingConfig — A bounded dynamic point light in world space.
741
+ - `PointerConfig` (interface): interface PointerConfig — Mouse/touch pointer bindings for `defineGame({ pointer })`.
720
742
  - `PresentationEffectsConfig` (interface): interface PresentationEffectsConfig — Per-channel combat presentation toggles for the 3D shell canvas. Missing keys default to enabled when the parent `presentationEffects` is an object.
721
743
  - `RtsCameraConfig` (interface): interface RtsCameraConfig extends TopDownCameraConfig — Free-pan / edge-scroll RTS rig (#24) — pan/rotate/zoom independent of any avatar.
722
744
  - `ShoulderCameraConfig` (interface): interface ShoulderCameraConfig — Over-the-shoulder combat rig (#25) — offset, ADS, shoulder swap, decoupled reticle.
723
745
  - `SideScrollCameraConfig` (interface): interface SideScrollCameraConfig — Fixed lateral 2.5D follow (side-on platformer cam): the camera sits perpendicular to the travel axis, tracks the followed entity, and never reads player look input.
746
+ - `SpotLightingConfig` (interface): interface SpotLightingConfig extends PointLightingConfig — A bounded dynamic spot light in world space.
724
747
  - `TopDownCameraConfig` (interface): interface TopDownCameraConfig — Fixed top-down / isometric rig (#23) — height/pitch/yaw + decoupled follow.
725
748
  - `TurntableCameraConfig` (interface): interface TurntableCameraConfig — Turntable / showcase rig — slowly auto-orbits a fixed world point (no player input), the way a museum turntable rotates an object on display. A flat, self-describing spelling of `observer`'s point-orbit mode: `target` names the point directly instead of `bind: { kind: "point", position }`. Set `camera.turntable` and the rig is inferred — you don't also write `rig`.
726
749
  - `VoxelCollisionConfig` (interface): interface VoxelCollisionConfig — Player-vs-world collision for the first-person controller. Without this the shell keeps the player on flat ground at y=0. With `voxel: true` the shell resolves the player as a box against placed scene objects (each treated as a solid unit cell), so they stand on blocks, fall into holes, and are stopped by walls — the controller a block-building/mining game needs.
727
- - `WorldItemRenderConfig` (interface): interface WorldItemRenderConfig — ⚠ undocumented
750
+ - `WorldItemRenderConfig` (interface): interface WorldItemRenderConfig { rarityStyle?: Record<string, RarityStyle>; filter?: readonly LootFilterRule[]; pickupRadius?: number; beamHeight?: number; autoPickup?: boolean | {radius?: number} } — ⚠ undocumented · used by `WorldItems` (@jgengine/shell/world/WorldItems): Rarity→beam/color/label render binding + loot-filter overlay (#32/#33) for every dropped `worldItem`.
728
751
  - `WorldOverlayProps` (interface): interface WorldOverlayProps — Props handed to a `WorldOverlay` component (#542): explicit `ctx` access so canvas-layer VFX read live engine state directly, without an extra hook or a module-global workaround.
729
752
  - `worldHealthBarAllowsRole` (function): function worldHealthBarAllowsRole(roles: readonly CatalogEntityRole[] | undefined, role: CatalogEntityRole | undefined): boolean — ⚠ undocumented
730
753
 
@@ -743,18 +766,18 @@
743
766
 
744
767
  ## @jgengine/core/game/quest
745
768
 
746
- - `QuestAcceptOptions` (interface): interface QuestAcceptOptions — ⚠ undocumented
747
- - `QuestDef` (interface): interface QuestDef — ⚠ undocumented
748
- - `QuestEvaluator` (interface): interface QuestEvaluator — ⚠ undocumented
749
- - `QuestInstance` (interface): interface QuestInstance — ⚠ undocumented
750
- - `QuestJournal` (interface): interface QuestJournal — ⚠ undocumented
751
- - `QuestJournalDeps` (interface): interface QuestJournalDeps — ⚠ undocumented
752
- - `QuestObjective` (interface): interface QuestObjective — ⚠ undocumented
753
- - `QuestObjectiveProgress` (interface): interface QuestObjectiveProgress — ⚠ undocumented
754
- - `QuestRewards` (interface): interface QuestRewards — ⚠ undocumented
769
+ - `QuestAcceptOptions` (interface): interface QuestAcceptOptions { hasUnlock?(id: string): boolean } — ⚠ undocumented
770
+ - `QuestDef` (interface): interface QuestDef { id: string; title: string; description?: string; giver?: string; turnIn?: string; requires?: string[]; objectives: QuestObjective[]; rewards?: QuestRewards } — ⚠ undocumented · used by `describeTrackedQuest`: Join a quest's static {@link QuestDef} with a player's live {@link QuestInstance} into a flat, renderer-free view a HUD tracker draws (title…
771
+ - `QuestEvaluator` (interface): interface QuestEvaluator { has(questId: string): boolean; get(questId: string): QuestDef | null; canAccept(state: readonly QuestSnapshotEntry[], questId: string, options?: QuestAcceptOptions): {reason: string} | null; accept(state: readonly QuestSnapshotEntry[], qu… — ⚠ undocumented
772
+ - `QuestInstance` (interface): interface QuestInstance { questId: string; status: QuestStatus; objectives: QuestObjectiveProgress[] } — ⚠ undocumented · used by `describeTrackedQuest`: Join a quest's static {@link QuestDef} with a player's live {@link QuestInstance} into a flat, renderer-free view a HUD tracker draws (title…
773
+ - `QuestJournal` (interface): interface QuestJournal { register(catalog: readonly QuestDef[] | Record<string, QuestDef>): void; has(questId: string): boolean; canAccept(userId: string, questId: string): {reason: string} | null; accept(userId: string, questId: string): {reason: string} | null;… — ⚠ undocumented · used by `createQuestJournal`: Track accepted quests and their per-objective progress, granting rewards on completion.
774
+ - `QuestJournalDeps` (interface): interface QuestJournalDeps { events: GameEvents; rewards: {grantXp(userId: string, amount: number): void; grantEconomy(userId: string, currencyId: string, amount: number): void; grantItem(userId: string, inventoryId: string, itemId: string, count: number): {reason: s… — ⚠ undocumented · used by `createQuestJournal`: Track accepted quests and their per-objective progress, granting rewards on completion.
775
+ - `QuestObjective` (interface): interface QuestObjective { id: string; kind: "kill" | "collect" | string; target?: string; item?: string; count: number; partyShare?: {radius: number; credit: "all" | "tagger"} } — ⚠ undocumented · used by `defaultObjectiveLabel`: Default objective label: a readable "verb count noun" from a {@link QuestObjective}.
776
+ - `QuestObjectiveProgress` (interface): interface QuestObjectiveProgress { id: string; kind: string; count: number; progress: number; complete: boolean } — ⚠ undocumented
777
+ - `QuestRewards` (interface): interface QuestRewards { xp?: {amount: number}; economy?: Record<string, number>; items?: {item: string; count: number; inventory: string}[]; unlocks?: string[]; quests?: string[] } — ⚠ undocumented
755
778
  - `QuestSnapshotEntry` (type): type QuestSnapshotEntry = { questId: string; status: QuestStatus; progress: Record<string, number>; } — ⚠ undocumented
756
779
  - `QuestStatus` (type): type QuestStatus = "active" | "completed" — ⚠ undocumented
757
- - `QuestTurnIn` (interface): interface QuestTurnIn — ⚠ undocumented
780
+ - `QuestTurnIn` (interface): interface QuestTurnIn { state: QuestSnapshotEntry[]; rewards: QuestRewards | null } — ⚠ undocumented
758
781
  - `TrackedObjectiveView` (interface): interface TrackedObjectiveView — One objective as a tracker/HUD reads it — label + progress toward its count.
759
782
  - `TrackedQuestView` (interface): interface TrackedQuestView — A quest as a tracker/HUD reads it — title, status, and per-objective progress.
760
783
  - `applyQuestRewards` (function): function applyQuestRewards(rewards: QuestRewards, appliers: { grantXp?(amount: number): void; grantEconomy?(currencyId: string, amount: number): void; grantItem?(inventoryId: string, itemId: string, count: number): { reason: string } | null | void; grantUnlock?(unlockId: string): void; }): { reason:… — ⚠ undocumented
@@ -765,24 +788,24 @@
765
788
 
766
789
  ## @jgengine/core/game/race
767
790
 
768
- - `Checkpoint` (interface): interface Checkpoint — ⚠ undocumented
791
+ - `Checkpoint` (interface): interface Checkpoint { id: string; center: readonly [number, number, number]; half: readonly [number, number, number] } — ⚠ undocumented
769
792
  - `LapTimer` (interface): interface LapTimer — Wall-clock lap timer complementing {@link RaceState}: feed it `tick(dt)` each frame and call `completeLap()` when the race emits a player `lap.completed` event. It accumulates the current lap, carries best/last, banks splits, and `penalize()` folds a time penalty into the running lap — the timing bookkeeping every racer reimplemented on top of the position-only race state.
770
793
  - `LapTimerSnapshot` (interface): interface LapTimerSnapshot — Wall-clock lap timing: the current/last/best/total split-book every racing HUD reads.
771
794
  - `PlacementOptions` (interface): interface PlacementOptions — Options for {@link racePlacements} / {@link placementOf} / {@link raceOutcomeOf}.
772
795
  - `RaceCountdownOptions` (interface): interface RaceCountdownOptions — Options for {@link startRaceCountdown}.
773
796
  - `RaceEvent` (type): type RaceEvent = | { type: "checkpoint.hit"; racerId: string; checkpoint: number; lap: number; time: number; /** Set when the hit is a fork-route checkpoint (`checkpoint` is then the fork's `afterIndex`). */ fork?: { forkId: string; routeId: string; index: number }; } | { type: "fork.taken"; racerId… — ⚠ undocumented
774
797
  - `RaceFork` (interface): interface RaceFork — An alternate-route section (#286.3): after passing mainline checkpoint `afterIndex`, a racer commits to whichever route's first checkpoint they hit, runs its checkpoints in order, and rejoins at mainline `afterIndex + 1`. Every completed route contributes exactly one checkpoint of `progress` regardless of length, and each hit records a split — so route time accounting comes for free.
775
- - `RaceForkRoute` (interface): interface RaceForkRoute — ⚠ undocumented
798
+ - `RaceForkRoute` (interface): interface RaceForkRoute { id: string; checkpoints: readonly Checkpoint[] } — ⚠ undocumented
776
799
  - `RaceOutcome` (type): type RaceOutcome = "win" | "lose" — Whether a racer won or lost, derived from where they placed against the winning-places cutoff.
777
800
  - `RacePhase` (type): type RacePhase = "idle" | "countdown" | "racing" | "finished" — The lifecycle every race runs through before, during, and after the clock: `idle` on the grid, `countdown` on the lights, `racing` once they go green, `finished` at the flag. A pure value driven by the transition functions below — it carries no track, racer, or lap data, so it composes with {@link RaceState} (position/laps) and {@link LapTimer} (wall-clock) rather than duplicating them.
778
801
  - `RacePlacement` (interface): interface RacePlacement — A racer's finishing position (`place`, 1-based) in a finish order, and the {@link RaceOutcome} it earns.
779
802
  - `RaceSessionState` (interface): interface RaceSessionState — Immutable lifecycle snapshot: the current {@link RacePhase} plus the two clocks it owns.
780
803
  - `RaceState` (class): class RaceState — Race state machine (issue #87). Drive it each tick with `update(now, positions)` — `now` is game time (`ctx.time`), `positions` maps each racer to a world point tested against the ordered checkpoint volumes. It emits `checkpoint.hit` / `lap.completed` / `position.changed` / `race.finished`, keeps cumulative split times for PB deltas, resolves a pluggable win condition (first-past-post, round-cut, derby last-standing), and `resetToCheckpoint` hands back a respawn pose at the racer's last checkpoint. `removeRacer` drops a racer mid-race and `reset` returns the whole instance to its pre-race state for reuse.
781
- - `RaceStateConfig` (interface): interface RaceStateConfig — ⚠ undocumented
782
- - `RaceTrack` (interface): interface RaceTrack — ⚠ undocumented
783
- - `RaceTrackConfig` (interface): interface RaceTrackConfig — ⚠ undocumented
784
- - `RaceWinCondition` (type): type RaceWinCondition = (standings: readonly RacerProgress[], track: RaceTrack) => readonly string[] | null — ⚠ undocumented
785
- - `RacerProgress` (interface): interface RacerProgress — ⚠ undocumented
804
+ - `RaceStateConfig` (interface): interface RaceStateConfig { track: RaceTrack; win?: RaceWinCondition } — ⚠ undocumented · used by `createRaceState`: A checkpoint race state machine — laps, forks, live standings, splits, and pluggable win conditions.
805
+ - `RaceTrack` (interface): interface RaceTrack { readonly checkpoints: readonly Checkpoint[]; readonly laps: number; readonly forks: readonly RaceFork[] } — ⚠ undocumented · used by `raceTrack`: A race track is an ordered ring of checkpoint trigger volumes plus a lap count.
806
+ - `RaceTrackConfig` (interface): interface RaceTrackConfig { checkpoints: readonly Checkpoint[]; laps?: number; forks?: readonly RaceFork[] } — ⚠ undocumented · used by `raceTrack`: A race track is an ordered ring of checkpoint trigger volumes plus a lap count.
807
+ - `RaceWinCondition` (type): type RaceWinCondition = (standings: readonly RacerProgress[], track: RaceTrack) => readonly string[] | null — ⚠ undocumented · used by `everyoneFinishes`: Every non-eliminated racer must finish.
808
+ - `RacerProgress` (interface): interface RacerProgress { racerId: string; lap: number; nextCheckpoint: number; lastCheckpoint: number; progress: number; position: number; finished: boolean; finishTime: number | null; eliminated: boolean; splits: readonly number[]; routesTaken: Readonly<Record<s… — ⚠ undocumented
786
809
  - `createLapTimer` (function): function createLapTimer(): LapTimer — Create a {@link LapTimer} starting at lap 0 with no splits, best, or last time recorded.
787
810
  - `createRaceState` (function): function createRaceState(config: RaceStateConfig): RaceState — A checkpoint race state machine — laps, forks, live standings, splits, and pluggable win conditions.
788
811
  - `everyoneFinishes` (function): function everyoneFinishes(): RaceWinCondition — Every non-eliminated racer must finish.
@@ -803,11 +826,11 @@
803
826
 
804
827
  ## @jgengine/core/game/recordBook
805
828
 
806
- - `RecordBook` (interface): interface RecordBook<K extends string> — ⚠ undocumented
807
- - `RecordBookConfig` (interface): interface RecordBookConfig<K extends string> — ⚠ undocumented
829
+ - `RecordBook` (interface): interface RecordBook<K extends string> { best(): Readonly<Partial<Record<K, number>>>; bestOf(field: K): number | null; submit(run: Readonly<Partial<Record<K, number>>>): RecordSubmission<K>; clear(): void } — ⚠ undocumented · used by `createRecordBook`: A personal-best record book: named numeric fields each racing toward "lower" (times) or "higher" (scores, streaks), persisted through a stru…
830
+ - `RecordBookConfig` (interface): interface RecordBookConfig<K extends string> { readonly key: string; readonly fields: Readonly<Record<K, RecordDirection>>; readonly storage?: RecordStorage | null } — ⚠ undocumented · used by `createRecordBook`: A personal-best record book: named numeric fields each racing toward "lower" (times) or "higher" (scores, streaks), persisted through a stru…
808
831
  - `RecordDirection` (type): type RecordDirection = "lower" | "higher" — ⚠ undocumented
809
832
  - `RecordStorage` (type): type RecordStorage = KeyValueStorage — The structural storage backend a record book persists through — an alias of the shared {@link KeyValueStorage} seam (browser `localStorage`, a test stub, or `null`).
810
- - `RecordSubmission` (interface): interface RecordSubmission<K extends string> — ⚠ undocumented
833
+ - `RecordSubmission` (interface): interface RecordSubmission<K extends string> { readonly improved: readonly K[]; readonly best: Readonly<Partial<Record<K, number>>> } — ⚠ undocumented
811
834
  - `createRecordBook` (function): function createRecordBook<K extends string>(config: RecordBookConfig<K>): RecordBook<K> — A personal-best record book: named numeric fields each racing toward "lower" (times) or "higher" (scores, streaks), persisted through a structural key-value storage (pass `localStorage` in a browser, a stub in tests, or `null` for in-memory only). Corrupt or unavailable storage degrades to an empty book — a record write never throws into a game tick.
812
835
 
813
836
  ## @jgengine/core/game/ruleSelection
@@ -822,11 +845,11 @@
822
845
 
823
846
  ## @jgengine/core/game/runDraft
824
847
 
825
- - `RunDraft` (interface): interface RunDraft<TStat extends string = string, TData = unknown> — ⚠ undocumented
826
- - `RunDraftConfig` (interface): interface RunDraftConfig<TStat extends string = string, TData = unknown> — ⚠ undocumented
827
- - `RunModifierOffer` (interface): interface RunModifierOffer<TStat extends string = string, TData = unknown> — ⚠ undocumented
828
- - `RunModifierPick` (interface): interface RunModifierPick — ⚠ undocumented
829
- - `RunModifierStack` (interface): interface RunModifierStack<TStat extends string = string, TData = unknown> — ⚠ undocumented
848
+ - `RunDraft` (interface): interface RunDraft<TStat extends string = string, TData = unknown> { present(count: number, rng?: () => number): RunModifierOffer<TStat, TData>[]; choose(offerId: string): boolean; stack(): RunModifierStack<TStat, TData> } — ⚠ undocumented · used by `createRunDraft`: A roguelike run built from stacking drafted modifier picks that reshape the run.
849
+ - `RunDraftConfig` (interface): interface RunDraftConfig<TStat extends string = string, TData = unknown> { offers: readonly RunModifierOffer<TStat, TData>[]; rng?: () => number } — ⚠ undocumented · used by `createRunDraft`: A roguelike run built from stacking drafted modifier picks that reshape the run.
850
+ - `RunModifierOffer` (interface): interface RunModifierOffer<TStat extends string = string, TData = unknown> { id: string; weight: number; maxStacks?: number; label?: string; stats?: StatModifierSet<TStat>; data?: TData } — ⚠ undocumented
851
+ - `RunModifierPick` (interface): interface RunModifierPick { id: string; stacks: number } — ⚠ undocumented
852
+ - `RunModifierStack` (interface): interface RunModifierStack<TStat extends string = string, TData = unknown> { add(offerId: string): boolean; count(offerId: string): number; atMax(offerId: string): boolean; picks(): RunModifierPick[]; offer(offerId: string): RunModifierOffer<TStat, TData> | null; total(stat: TStat): StatModifier; apply(stats: Stat… — ⚠ undocumented
830
853
  - `createRunDraft` (function): function createRunDraft<TStat extends string = string, TData = unknown>(config: RunDraftConfig<TStat, TData>): RunDraft<TStat, TData> — A roguelike run built from stacking drafted modifier picks that reshape the run.
831
854
  - `createRunModifierStack` (function): function createRunModifierStack<TStat extends string = string, TData = unknown>(offers: readonly RunModifierOffer<TStat, TData>[]): RunModifierStack<TStat, TData> — ⚠ undocumented
832
855
 
@@ -862,35 +885,35 @@
862
885
  ## @jgengine/core/game/social
863
886
 
864
887
  - `DEFAULT_EMOTE_RADIUS` (const): const DEFAULT_EMOTE_RADIUS: 20 — ⚠ undocumented
865
- - `EmoteBroadcastResult` (interface): interface EmoteBroadcastResult — ⚠ undocumented
866
- - `EmoteEntityLookup` (interface): interface EmoteEntityLookup — ⚠ undocumented
867
- - `EmoteSpatialLookup` (interface): interface EmoteSpatialLookup — ⚠ undocumented
868
- - `Emotes` (interface): interface Emotes — ⚠ undocumented
869
- - `EmotesDeps` (interface): interface EmotesDeps — ⚠ undocumented
870
- - `FriendEntry` (interface): interface FriendEntry — ⚠ undocumented
871
- - `FriendRequestEntry` (interface): interface FriendRequestEntry — ⚠ undocumented
872
- - `Friends` (interface): interface Friends — ⚠ undocumented
873
- - `FriendsSnapshot` (interface): interface FriendsSnapshot — ⚠ undocumented
874
- - `Party` (interface): interface Party — ⚠ undocumented
875
- - `PartyConfig` (interface): interface PartyConfig — ⚠ undocumented
876
- - `PartyInviteEntry` (interface): interface PartyInviteEntry — ⚠ undocumented
877
- - `PartyMemberEntry` (interface): interface PartyMemberEntry — ⚠ undocumented
888
+ - `EmoteBroadcastResult` (interface): interface EmoteBroadcastResult { from: string; emoteId: string; at: readonly [number, number, number]; recipients: readonly string[] } — ⚠ undocumented
889
+ - `EmoteEntityLookup` (interface): interface EmoteEntityLookup { get(id: string): {position: readonly [number, number, number]; role: string} | null } — ⚠ undocumented
890
+ - `EmoteSpatialLookup` (interface): interface EmoteSpatialLookup { inRadius(center: readonly [number, number, number], radius: number, filter?: (id: string) => boolean): readonly string[] } — ⚠ undocumented
891
+ - `Emotes` (interface): interface Emotes { play(fromUserId: string, emoteId: string, radius?: number): EmoteBroadcastResult | {reason: string} } — ⚠ undocumented
892
+ - `EmotesDeps` (interface): interface EmotesDeps { entities: EmoteEntityLookup; spatial: EmoteSpatialLookup } — ⚠ undocumented
893
+ - `FriendEntry` (interface): interface FriendEntry { userId: string; online: boolean } — ⚠ undocumented
894
+ - `FriendRequestEntry` (interface): interface FriendRequestEntry { requestId: string; fromUserId: string } — ⚠ undocumented
895
+ - `Friends` (interface): interface Friends { canRequest(fromUserId: string, toUserId: string): {reason: string} | null; request(fromUserId: string, toUserId: string): {requestId: string} | {reason: string}; accept(userId: string, requestId: string): {reason: string} | null; decline(… — ⚠ undocumented
896
+ - `FriendsSnapshot` (interface): interface FriendsSnapshot { friends: string[]; blocked: string[] } — ⚠ undocumented
897
+ - `Party` (interface): interface Party { register(config: PartyConfig): void; canInvite(fromUserId: string, toUserId: string): {reason: string} | null; invite(fromUserId: string, toUserId: string): {inviteId: string} | {reason: string}; accept(userId: string, inviteId: string): … — ⚠ undocumented
898
+ - `PartyConfig` (interface): interface PartyConfig { maxMembers: number; inviteTtlMs?: number } — ⚠ undocumented
899
+ - `PartyInviteEntry` (interface): interface PartyInviteEntry { inviteId: string; fromUserId: string; createdAt: number } — ⚠ undocumented
900
+ - `PartyMemberEntry` (interface): interface PartyMemberEntry { userId: string; role: PartyRole } — ⚠ undocumented
878
901
  - `PartyRole` (type): type PartyRole = "leader" | "member" — ⚠ undocumented
879
- - `PresenceInfo` (interface): interface PresenceInfo — ⚠ undocumented
880
- - `Social` (interface): interface Social — ⚠ undocumented
881
- - `SocialDeps` (interface): interface SocialDeps — ⚠ undocumented
902
+ - `PresenceInfo` (interface): interface PresenceInfo { online: boolean; serverId?: string; zoneId?: string; instanceId?: string } — ⚠ undocumented
903
+ - `Social` (interface): interface Social { friends: Friends; party: Party; presence: {get(userId: string): PresenceInfo}; emotes: Emotes; worldInvites: WorldInvites; snapshot(): SocialSnapshot; hydrate(data: SocialSnapshot): void } — ⚠ undocumented · used by `createSocial`: Emotes and lightweight social interactions between nearby players.
904
+ - `SocialDeps` (interface): interface SocialDeps { events: GameEvents; presence?: (userId: string) => PresenceInfo; now?: () => number; emotes?: EmotesDeps; worldInviteTtlMs?: number } — ⚠ undocumented · used by `createSocial`: Emotes and lightweight social interactions between nearby players.
882
905
  - `SocialPartySnapshot` (interface): interface SocialPartySnapshot — One party's replicated membership — id, current leader, and ordered member ids.
883
906
  - `SocialSnapshot` (interface): interface SocialSnapshot — Full friends/party/world-invite state as one serializable baseline — the host→client replication payload behind the `social` snapshot module. Presence and emotes are derived from live deps, not stored.
884
- - `WorldInvite` (interface): interface WorldInvite extends WorldInviteTarget — ⚠ undocumented
885
- - `WorldInviteTarget` (interface): interface WorldInviteTarget — ⚠ undocumented
886
- - `WorldInvites` (interface): interface WorldInvites — ⚠ undocumented
907
+ - `WorldInvite` (interface): interface WorldInvite extends WorldInviteTarget { id: string; fromUserId: string; toUserId: string; createdAt: number } — ⚠ undocumented
908
+ - `WorldInviteTarget` (interface): interface WorldInviteTarget { serverId: string; joinCode?: string } — ⚠ undocumented
909
+ - `WorldInvites` (interface): interface WorldInvites { canInvite(fromUserId: string, toUserId: string): {reason: string} | null; invite(fromUserId: string, toUserId: string, target: WorldInviteTarget): {inviteId: string} | {reason: string}; accept(userId: string, inviteId: string): {target: W… — ⚠ undocumented
887
910
  - `createSocial` (function): function createSocial(deps: SocialDeps): Social — Emotes and lightweight social interactions between nearby players.
888
911
 
889
912
  ## @jgengine/core/game/spawnPoints
890
913
 
891
- - `RespawnTarget` (interface): interface RespawnTarget — ⚠ undocumented
892
- - `SpawnPointPose` (interface): interface SpawnPointPose — ⚠ undocumented
893
- - `SpawnPoints` (interface): interface SpawnPoints — ⚠ undocumented
914
+ - `RespawnTarget` (interface): interface RespawnTarget { setPose(id: string, pose: EntityPose): boolean } — ⚠ undocumented
915
+ - `SpawnPointPose` (interface): interface SpawnPointPose { x: number; y: number; z: number; rotationY?: number } — ⚠ undocumented
916
+ - `SpawnPoints` (interface): interface SpawnPoints { record(id: string, pose: SpawnPointPose): void; get(id: string): SpawnPointPose | undefined; list(): readonly (SpawnPointPose & {id: string})[]; respawn(entities: RespawnTarget, entityId: string, spawnId: string): boolean } — ⚠ undocumented · used by `createSpawnPoints`: Register spawn locations and choose where entities spawn or respawn.
894
917
  - `createSpawnPoints` (function): function createSpawnPoints(): SpawnPoints — Register spawn locations and choose where entities spawn or respawn.
895
918
 
896
919
  ## @jgengine/core/game/systemRuntime
@@ -917,14 +940,14 @@
917
940
 
918
941
  ## @jgengine/core/game/talents
919
942
 
920
- - `ResolvedTalents` (interface): interface ResolvedTalents<TStat extends string = string> — ⚠ undocumented
943
+ - `ResolvedTalents` (interface): interface ResolvedTalents<TStat extends string = string> { stats: StatModifierSet<TStat>; abilities: readonly string[] } — ⚠ undocumented
921
944
  - `TalentAllocateReason` (type): type TalentAllocateReason = "unknown-node" | "max-rank" | "no-points" | "requires" | "branch-points" — ⚠ undocumented
922
945
  - `TalentAllocateResult` (type): type TalentAllocateResult = { ok: true } | { ok: false; reason: TalentAllocateReason } — ⚠ undocumented
923
- - `TalentNodeDef` (interface): interface TalentNodeDef<TStat extends string = string> — ⚠ undocumented
946
+ - `TalentNodeDef` (interface): interface TalentNodeDef<TStat extends string = string> { id: string; branch?: string; maxRank: number; requires?: readonly TalentRequirement[]; requiresPointsInBranch?: number; modifiersPerRank?: StatModifierSet<TStat>; grantsAbilities?: readonly string[] } — ⚠ undocumented · used by `talentTreeView` (@jgengine/core/game/talentTreeView): Project the existing talent model (`createTalentTree`) into a flat, serializable render view: every node placed by branch + prerequisite-dep…
924
947
  - `TalentRequirement` (type): type TalentRequirement = string | { nodeId: string; rank: number } — ⚠ undocumented
925
- - `TalentSnapshot` (interface): interface TalentSnapshot — ⚠ undocumented
926
- - `TalentTree` (interface): interface TalentTree<TStat extends string = string> — ⚠ undocumented
927
- - `TalentTreeConfig` (interface): interface TalentTreeConfig<TStat extends string = string> — ⚠ undocumented
948
+ - `TalentSnapshot` (interface): interface TalentSnapshot { points: number; ranks: Record<string, number> } — ⚠ undocumented
949
+ - `TalentTree` (interface): interface TalentTree<TStat extends string = string> { rank(nodeId: string): number; pointsAvailable(): number; pointsSpent(): number; pointsInBranch(branch: string): number; grantPoints(amount: number): void; canAllocate(nodeId: string): TalentAllocateResult; allocate(nodeId: string): Talent… — ⚠ undocumented · used by `talentTreeView` (@jgengine/core/game/talentTreeView): Project the existing talent model (`createTalentTree`) into a flat, serializable render view: every node placed by branch + prerequisite-dep…
950
+ - `TalentTreeConfig` (interface): interface TalentTreeConfig<TStat extends string = string> { nodes: readonly TalentNodeDef<TStat>[]; points?: number } — ⚠ undocumented
928
951
  - `createTalentTree` (function): function createTalentTree<TStat extends string = string>(config: TalentTreeConfig<TStat>): TalentTree<TStat> — ⚠ undocumented
929
952
 
930
953
  ## @jgengine/core/game/toasts
@@ -932,21 +955,22 @@
932
955
  - `Toast` (interface): interface Toast<T = string> — A transient HUD message that expires on its own — banner, pickup note, alert.
933
956
  - `ToastQueue` (interface): interface ToastQueue<T = string> — Stateful transient-toast list with a size cap and time-to-live eviction.
934
957
  - `ToastQueueOptions` (interface): interface ToastQueueOptions — Options for {@link createToastQueue}.
958
+ - `ToastQueueState` (interface): interface ToastQueueState<T = string> — Plain JSON state of a {@link ToastQueue}: live toasts plus the id counter.
935
959
  - `appendToast` (function): function appendToast<T>(toasts: readonly Toast<T>[], toast: Toast<T>, cap: number): readonly Toast<T>[] — Append `toast`, keeping only the newest `cap` entries.
936
960
  - `createToastQueue` (function): function createToastQueue<T = string>(options: ToastQueueOptions = {}): ToastQueue<T> — A capped, self-expiring toast queue — the append-with-limit plus TTL-prune list every HUD hand-rolled on top of a plain array. Feed it game time: `push` raises a message, `prune(now)` drops expired ones, `list()` is what the HUD renders. Unlike the append-only event feed, toasts evict themselves.
937
961
  - `pruneToasts` (function): function pruneToasts<T>(toasts: readonly Toast<T>[], now: number): readonly Toast<T>[] — Drop every toast whose `expiresAt` is at or before `now`. Returns the same array when nothing expired.
938
962
 
939
963
  ## @jgengine/core/game/trade
940
964
 
941
- - `TradeField` (interface): interface TradeField — ⚠ undocumented
942
- - `TradeInventory` (interface): interface TradeInventory — ⚠ undocumented
943
- - `TradeOutcome` (interface): interface TradeOutcome — ⚠ undocumented
944
- - `TradeParty` (interface): interface TradeParty — ⚠ undocumented
945
- - `TradeRejection` (interface): interface TradeRejection — ⚠ undocumented
965
+ - `TradeField` (interface): interface TradeField { buy?: Record<string, number>; sell?: Record<string, number>; shops?: string[] } — ⚠ undocumented
966
+ - `TradeInventory` (interface): interface TradeInventory { put(inventoryId: string, itemId: string, count: number): TradeRejection | null; take(inventoryId: string, itemId: string, count: number): TradeRejection | null; count(inventoryId: string, itemId: string): number } — ⚠ undocumented
967
+ - `TradeOutcome` (interface): interface TradeOutcome { itemId: string; count: number; currency: Record<string, number> } — ⚠ undocumented
968
+ - `TradeParty` (interface): interface TradeParty { shop: string; inventoryId: string } — ⚠ undocumented
969
+ - `TradeRejection` (interface): interface TradeRejection { reason: string } — ⚠ undocumented
946
970
  - `TradeResolution` (type): type TradeResolution = | { status: "ok"; outcome: TradeOutcome } | { status: "rejected"; reason: string } — ⚠ undocumented
947
- - `TradeSystem` (interface): interface TradeSystem — ⚠ undocumented
948
- - `TradeSystemDeps` (interface): interface TradeSystemDeps — ⚠ undocumented
949
- - `TradeWallet` (interface): interface TradeWallet — ⚠ undocumented
971
+ - `TradeSystem` (interface): interface TradeSystem { canBuy(itemId: string, shopId: string, count?: number): string | null; canSell(itemId: string, count?: number): string | null; buy(itemId: string, count: number | undefined, party: TradeParty): TradeRejection | null; sell(itemId: string, … — ⚠ undocumented
972
+ - `TradeSystemDeps` (interface): interface TradeSystemDeps { resolveTrade(itemId: string): TradeField | null | undefined; wallet: TradeWallet; inventory: TradeInventory } — ⚠ undocumented
973
+ - `TradeWallet` (interface): interface TradeWallet { canAfford(costs: Record<string, number>): string | null; charge(costs: Record<string, number>): void; grant(gains: Record<string, number>): void } — ⚠ undocumented
950
974
 
951
975
  ## @jgengine/core/game/tribe
952
976
 
@@ -970,10 +994,10 @@
970
994
 
971
995
  ## @jgengine/core/game/unlocks
972
996
 
973
- - `UnlockCatalog` (interface): interface UnlockCatalog — ⚠ undocumented
974
- - `UnlockDef` (interface): interface UnlockDef — ⚠ undocumented
997
+ - `UnlockCatalog` (interface): interface UnlockCatalog { has(unlockId: string): boolean; tree(categoryId: string): UnlockDef[] } — ⚠ undocumented · used by `createUnlockCatalog`: A catalog of unlockable content gated behind conditions the player earns, tracking what is unlocked.
998
+ - `UnlockDef` (interface): interface UnlockDef { id: string; category?: string } — ⚠ undocumented · used by `createUnlockCatalog`: A catalog of unlockable content gated behind conditions the player earns, tracking what is unlocked.
975
999
  - `UnlockState` (type): type UnlockState = readonly string[] — ⚠ undocumented
976
- - `Unlocks` (interface): interface Unlocks — ⚠ undocumented
1000
+ - `Unlocks` (interface): interface Unlocks { has(userId: string, unlockId: string): boolean; grant(userId: string, unlockId: string): void; list(userId: string): string[]; tree(categoryId: string): UnlockDef[]; snapshot(userId: string): string[]; hydrate(userId: string, ids: string[… — ⚠ undocumented
977
1001
  - `createUnlockCatalog` (function): function createUnlockCatalog(defs: readonly UnlockDef[] = []): UnlockCatalog — A catalog of unlockable content gated behind conditions the player earns, tracking what is unlocked.
978
1002
  - `createUnlocks` (function): function createUnlocks(defs: UnlockDef[] = []): Unlocks — ⚠ undocumented
979
1003
  - `grantUnlock` (function): function grantUnlock(granted: UnlockState, unlockId: string): string[] — ⚠ undocumented
@@ -989,23 +1013,35 @@
989
1013
  - `VfxInstanceStopOptions` (interface): interface VfxInstanceStopOptions — Options for {@link VfxInstanceStore.stop}.
990
1014
  - `VfxInstanceStore` (interface): interface VfxInstanceStore — A headless registry of retained VFX instances: create/replace, partially update, and stop long-lived effects addressed by stable id, independent of any renderer. It owns the authoritative serializable state and exposes inspection counts; wire {@link VfxInstanceStoreOptions.onOp} to a renderer (via the `combat.vfxInstance` event) to drive visuals.
991
1015
  - `VfxInstanceStoreOptions` (interface): interface VfxInstanceStoreOptions — Options for {@link createVfxInstanceStore}.
1016
+ - `VfxInstanceStoreState` (interface): interface VfxInstanceStoreState — Plain JSON state of a {@link VfxInstanceStore}.
992
1017
  - `createVfxInstanceStore` (function): function createVfxInstanceStore(options: VfxInstanceStoreOptions = {}): VfxInstanceStore — Build a headless retained-VFX registry. The store is the serializable source of truth for long-lived effects (beams, tethers, zones, target lines, looping emitters) that must move and mutate without one-shot re-emit flicker: `upsert` creates or replaces by stable id, `update` nudges dynamic params, `stop` disposes with an optional fade, and `tick` enforces TTL heartbeats. It stays independent of renderer availability, so simulation and tests run without a shell; a wired `onOp` sink turns each op into a `combat.vfxInstance` event the shell binds to render resources.
993
1018
 
1019
+ ## @jgengine/core/game/viewports
1020
+
1021
+ - `ViewportCameraConfig` (interface): interface ViewportCameraConfig — The follow camera an extra viewport runs; the primary seat keeps the game's main camera rig.
1022
+ - `ViewportDef` (interface): interface ViewportDef — One viewport: which local seat it shows and where.
1023
+ - `ViewportPixels` (interface): interface ViewportPixels — A viewport in canvas pixels with a bottom-left origin, ready for `gl.setViewport`/`setScissor`.
1024
+ - `ViewportRect` (type): type ViewportRect = readonly [number, number, number, number] — A screen region as fractions of the canvas, `[x, y, width, height]` in `0..1` with the origin at the top left.
1025
+ - `ViewportsConfig` (interface): interface ViewportsConfig — `defineGame({ viewports })`: split-screen layout for local seats.
1026
+ - `resolveViewports` (function): function resolveViewports(config: ViewportsConfig | undefined, slots: readonly string[]): ViewportDef[] — The viewports to draw for the seats currently joined: the explicit layout filtered to joined seats, or an even split.
1027
+ - `splitViewports` (function): function splitViewports(slots: readonly string[], split: "vertical" | "horizontal" = "vertical"): ViewportDef[] — Even split-screen rects for seats in order: one fills the screen, two split side by side (or stacked), three put the first on a full-width top half, four make a 2×2 grid, more fill a grid row by row.
1028
+ - `viewportPixels` (function): function viewportPixels(rect: ViewportRect, width: number, height: number): ViewportPixels — Convert a top-left fractional rect into whole canvas pixels with a bottom-left origin; neighbours share edges exactly.
1029
+
994
1030
  ## @jgengine/core/game/worldItem
995
1031
 
996
1032
  - `DEFAULT_PICKUP_RADIUS` (const): const DEFAULT_PICKUP_RADIUS: 2 — ⚠ undocumented
997
1033
  - `DEFAULT_RARITY` (const): const DEFAULT_RARITY: "common" — ⚠ undocumented
998
1034
  - `DEFAULT_SCATTER` (const): const DEFAULT_SCATTER: ScatterOptions — ⚠ undocumented
999
- - `RarityStyle` (interface): interface RarityStyle — ⚠ undocumented
1000
- - `ResolveDeathDropsOptions` (interface): interface ResolveDeathDropsOptions — ⚠ undocumented
1001
- - `ResolvedDeathDrops` (interface): interface ResolvedDeathDrops — ⚠ undocumented
1002
- - `ScatterOptions` (interface): interface ScatterOptions — ⚠ undocumented
1035
+ - `RarityStyle` (interface): interface RarityStyle — Per-rarity look of a dropped item: beam, color and label. Set via `defineGame({ worldItem: { rarityStyle } })`.
1036
+ - `ResolveDeathDropsOptions` (interface): interface ResolveDeathDropsOptions { mode: "grant" | "world"; origin: EntityPosition; resolveRarity(itemId: string): string; resolveBaseType?(itemId: string): string; scatter?: ScatterOptions; rng?(): number; source?: string } — ⚠ undocumented
1037
+ - `ResolvedDeathDrops` (interface): interface ResolvedDeathDrops { worldSpawns: WorldItemSpawnInput[]; grants: Drop[] } — ⚠ undocumented
1038
+ - `ScatterOptions` (interface): interface ScatterOptions { radius: number; minRadius?: number; height?: number } — ⚠ undocumented
1003
1039
  - `WORLD_ITEM_ENTITY_NAME` (const): const WORLD_ITEM_ENTITY_NAME: "world_item" — Scene-entity catalog name every dropped-item instance spawns under (see the three buckets: worldItem is an entity, never an inventory item or object).
1004
- - `WorldItemPresentation` (interface): interface WorldItemPresentation — ⚠ undocumented
1005
- - `WorldItemRecord` (interface): interface WorldItemRecord — ⚠ undocumented
1006
- - `WorldItemSpawnInput` (interface): interface WorldItemSpawnInput — ⚠ undocumented
1007
- - `WorldItemStore` (interface): interface WorldItemStore — ⚠ undocumented
1008
- - `WorldItemStoreDeps` (interface): interface WorldItemStoreDeps — ⚠ undocumented
1040
+ - `WorldItemPresentation` (interface): interface WorldItemPresentation { hidden: boolean; color?: string; beam: boolean; label?: string } — ⚠ undocumented
1041
+ - `WorldItemRecord` (interface): interface WorldItemRecord { instanceId: string; itemId: string; rarity: string; baseType: string; count: number; affixTier?: number; source?: string; droppedAt: number } — ⚠ undocumented · used by `useNearestWorldItem` (@jgengine/react): Nearest ground item within `radius` of the local player — drives a pickup prompt/highlight.
1042
+ - `WorldItemSpawnInput` (interface): interface WorldItemSpawnInput { itemId: string; position: EntityPosition; rarity?: string; baseType?: string; count?: number; affixTier?: number; source?: string } — ⚠ undocumented
1043
+ - `WorldItemStore` (interface): interface WorldItemStore { spawn(input: WorldItemSpawnInput): WorldItemRecord; get(instanceId: string): WorldItemRecord | null; list(): readonly WorldItemRecord[]; nearestInRadius(from: EntityPosition, radius: number, filter?: (record: WorldItemRecord) => boolean):… — ⚠ undocumented
1044
+ - `WorldItemStoreDeps` (interface): interface WorldItemStoreDeps { spawnEntity(position: EntityPosition): string; despawnEntity(instanceId: string): boolean; resolvePosition(instanceId: string): EntityPosition | undefined; now?(): number } — ⚠ undocumented
1009
1045
 
1010
1046
  ## @jgengine/core/gameplay
1011
1047
 
@@ -1016,41 +1052,41 @@
1016
1052
  - `AchievementUnlock` (interface): interface AchievementUnlock — Emitted the instant an achievement unlocks — wire to a toast, feed, or sound.
1017
1053
  - `AchievementView` (interface): interface AchievementView extends AchievementDef — A definition plus its live unlock/progress state — what UI renders.
1018
1054
  - `ActionCodes` (type): type ActionCodes<TCode extends string = string> = | readonly TCode[] | { hold?: readonly TCode[]; toggle?: readonly TCode[]; repeatMs?: number } — ⚠ undocumented
1019
- - `ActionCodesMap` (type): type ActionCodesMap<TAction extends string = string, TCode extends string = string> = Record< TAction, ActionCodes<TCode> > — Maps each game action name to the input codes (hold/toggle keys, repeat rate) that trigger it.
1020
- - `ActionStateTracker` (interface): interface ActionStateTracker<TAction extends string> — ⚠ undocumented
1055
+ - `ActionCodesMap` (type): type ActionCodesMap<TAction extends string = string, TCode extends string = string> = Record< TAction, ActionCodes<TCode> > — Maps each game action name to the input codes (hold/toggle keys, repeat rate) that trigger it. In a `defineGame({ input })`, pressing an action runs the same-named command with `{ yaw, pitch, aim }`; `repeatMs` re-fires it while held (automatic weapons).
1056
+ - `ActionStateTracker` (interface): interface ActionStateTracker<TAction extends string> { handleDown(code: string): TAction | null; handleUp(code: string): TAction | null; isDown(action: TAction): boolean; wasPressed(action: TAction): boolean; endFrame(): void; reset(): void; rebind(map: ActionStateBindingMap<TAction, string>)… — ⚠ undocumented · used by `rebindGamepadPoll` (@jgengine/shell/input/gamepadPoll): Swap the pad bindings mid-game (a context push) without touching keyboard state: release the codes of pad-held actions whose pad codes chang…
1021
1057
  - `ActiveEffect` (interface): interface ActiveEffect — A live timed effect an engine is tracking until it expires or is cleaned up.
1022
1058
  - `AdvanceOptions` (interface): interface AdvanceOptions — Per-advance settings: the policy pipeline, caller context, rounding, and safety bounds.
1023
1059
  - `AdvanceResult` (interface): interface AdvanceResult — The outcome of {@link advanceLedger}: the new ledger plus applied transactions and events.
1024
- - `AffixPool` (interface): interface AffixPool — ⚠ undocumented
1060
+ - `AffixPool` (interface): interface AffixPool { id: string; affixes: readonly AffixDef[] } — ⚠ undocumented
1025
1061
  - `AppliedTransaction` (type): type AppliedTransaction = ResourceTransaction — A {@link ResourceTransaction} after policies and rounding, as actually applied to balances.
1026
1062
  - `Auction` (interface): interface Auction — One live timed auction in an {@link AuctionBook}: an item stack under open bidding until it closes.
1027
1063
  - `AuctionSettlement` (type): type AuctionSettlement = | { status: "sold"; auction: Auction; winnerId: string; price: number; houseCut: number; sellerProceeds: number; } | { status: "returned"; auction: Auction } — How one closed auction resolved during {@link AuctionBook.settleExpired}.
1028
- - `AxisBindingMap` (type): type AxisBindingMap = Record<AxisName, AxisBinding> — ⚠ undocumented
1029
- - `AxisChannelConfig` (interface): interface AxisChannelConfig — ⚠ undocumented
1030
- - `AxisInput` (interface): interface AxisInput — ⚠ undocumented
1064
+ - `AxisBindingMap` (type): type AxisBindingMap = Record<AxisName, AxisBinding> — ⚠ undocumented · used by `DRIVE_AXIS_BINDINGS` (@jgengine/core/input/axisInput): Car axes bound to raw key codes, for an {@link AxisChannel} sampled with a key-code `isDown`.
1065
+ - `AxisChannelConfig` (interface): interface AxisChannelConfig { bindings: AxisBindingMap; smoothing?: number } — ⚠ undocumented · used by `useAxisChannel` (@jgengine/react): Wires useHeldKeys into a fresh AxisChannel, ready for a per-frame `channel.sample(dt, isDown)`.
1066
+ - `AxisInput` (interface): interface AxisInput { throttle: number; brake: number; steer: number; handbrake: number } — ⚠ undocumented · used by `tickDrivableVehicle` (@jgengine/core/physics/drivableVehicle): Connects an `AxisInput` sample straight through a ground-vehicle sim (`KinematicVehicle` or `VehicleDynamics`) to a scene entity's pose for …
1031
1067
  - `BackdropConfig` (interface): interface BackdropConfig — Generic sky/background/fog for ANY world kind, including a custom `environment` component (#207.6).
1032
1068
  - `BehaviorConfig` (type): type BehaviorConfig = Record<string, unknown> — Per-behavior configuration stored on an item as plain data (e.g. charge time, projectile id). Kept opaque here so no game noun leaks into item core.
1033
1069
  - `BehaviorState` (type): type BehaviorState = Record<string, unknown> — A single behavior's mutable, serializable runtime state (e.g. current charge, rounds queued). Composed state is a map of these keyed by behavior id.
1034
1070
  - `Behaviour` (class): class Behaviour — Subclass and override the lifecycle hooks. A behaviour only joins the per-frame update dispatch if it actually overrides `onUpdate` (prototype-identity check at each activation), so hook-only behaviours cost nothing per frame.
1035
1071
  - `BehaviourModule` (class): class BehaviourModule — A world-lifetime service with typed sibling access via `this.modules`. Modules awake and start before any behaviour during `world.start()`, subscribe to update dispatch first (their `onUpdate` fires before every behaviour's), and have no disable/destroy — they live as long as the world.
1036
- - `BehaviourWorld` (interface): interface BehaviourWorld — ⚠ undocumented
1072
+ - `BehaviourWorld` (interface): interface BehaviourWorld { add(id: string, parentId?: string): void; has(id: string): boolean; parentOf(id: string): string | null; childrenOf(id: string): readonly string[]; setParent(id: string, parentId: string | null): void; attach<T extends Behaviour>(nodeId: … — ⚠ undocumented
1037
1073
  - `BindingOverrides` (type): type BindingOverrides = Record<string, ActionCodes> — Player-rebound keys, keyed by action name. Values mirror an `ActionCodes` entry so hold/toggle/repeat semantics survive a rebind — the settings menu only swaps which physical codes drive the action.
1038
1074
  - `CAMERA_FRUSTUM_DEFAULTS` (const): const CAMERA_FRUSTUM_DEFAULTS: { readonly fov: 55; readonly near: 0.1; readonly far: 300; readonly zoom: 50; } — ⚠ undocumented
1039
1075
  - `CameraKeyframe` (interface): interface CameraKeyframe — One stop on a scripted camera path (#29).
1040
1076
  - `CameraRigKind` (type): type CameraRigKind = | "orbit" | "first" | "topDown" | "rts" | "shoulder" | "lockOn" | "chase" | "observer" | "turntable" | "sideScroll" | "inspection" | "none" — Which camera rig the shell mounts. Every rig accepts `followEntityId: null` (avatar-less games — city-builders, card games, auto-battlers — still get a camera). Rigs are tuned through their config block below, never by writing camera positions from `onTick`. - `orbit` — third-person chase (the historical default; `perspective: "third"`). - `first` — pointer-lock mouse-look (`perspective: "first"`). - `topDown` — fixed height/pitch/yaw with decoupled follow (ARPG iso, top-down). - `rts` — free-pan / edge-scroll / rotate / zoom, optional follow. - `shoulder` — over-the-shoulder with ADS transition + shoulder swap. - `lockOn` — yaw bound to the player→target vector; move axis becomes strafe. - `chase` — speed-reactive vehicle chase (speed→FOV, spring arm, shake) + cockpit/hood/rear views. - `observer` — detached spectator/photo cam bound to any entity or fixed point; never reads player input. - `turntable` — slow auto-orbit of a fixed point: a rotating display stand for a scene. The friendly, flat spelling of `observer`'s point-orbit mode; providing `camera.turntable` selects it without an explicit `rig`. - `sideScroll` — fixed lateral follow (2.5D platformer/beat-'em-up side view); reads no player input. - `inspection` — model-viewer / editor rig (#207.7, #866): middle-drag pan, right-drag orbit, scroll zoom toward a configurable anchor; orbits a fixed point, reads no player/entity input. - `none` — no camera rig is mounted; use for HUD-only presentations or a game that manages its own camera.
1041
1077
  - `CancelResult` (type): type CancelResult<TSpec, TReserve = undefined> = | { readonly ok: true; readonly state: WorkQueueState<TSpec, TReserve>; readonly job: Job<TSpec, TReserve>; readonly refund: TReserve | null; } | { readonly ok: false; readonly state: WorkQueueState<TSpec, TReserve>; readonly reason: string } — Outcome of {@link cancelJob}, carrying the removed job and its computed refund.
1042
1078
  - `CandidatePlacement` (interface): interface CandidatePlacement — A part proposed for a slot during generation, before it is committed to an identity. Used by the backtracking contract to test a placement in isolation.
1043
- - `CardPile` (interface): interface CardPile — ⚠ undocumented
1044
- - `CardPileState` (interface): interface CardPileState — ⚠ undocumented
1079
+ - `CardPile` (interface): interface CardPile { state(): CardPileState; zones(): readonly ZoneName[]; count(zone: ZoneName): number; peek(zone: ZoneName, n?: number): readonly string[]; zoneOf(cardId: string): ZoneName | null; shuffle(zone: ZoneName | undefined, seed: string | number):… — ⚠ undocumented
1080
+ - `CardPileState` (interface): interface CardPileState { readonly zones: Readonly<Record<ZoneName, readonly string[]>> } — ⚠ undocumented · used by `CardStack` (@jgengine/react): `StackedPile` bound to a headless `CardPileState` zone: reads the ordered card ids from `pile.zones[zone]` and resolves each to a `PlayingCa…
1045
1081
  - `CatchUpPolicy` (type): type CatchUpPolicy = "each" | "sum" | "skip" — How cycles that came due between two {@link advanceLedger} calls are settled: - `"each"` — replay every missed cycle as its own transaction (bounded by the limits below); - `"sum"` — collapse the missed cycles into one transaction of the combined amount; - `"skip"` — apply only the most recent cycle and discard the rest (idle income that does not bank).
1046
1082
  - `Cell` (type): type Cell = readonly [number, number] — ⚠ undocumented
1047
- - `CellGrid` (interface): interface CellGrid<T> — ⚠ undocumented
1083
+ - `CellGrid` (interface): interface CellGrid<T> — 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.
1048
1084
  - `ChargeOptions` (interface): interface ChargeOptions — Options for {@link charge}/{@link chargeAll}: opt one call into overdraft debt via `overdraft`.
1049
1085
  - `ChargeResult` (type): type ChargeResult = { status: "ok"; state: WalletState } | { status: "rejected"; reason: "insufficient-funds" } — Outcome of a {@link charge}/{@link chargeAll} attempt: `status: "ok"` carries the debited {@link WalletState}, while `status: "rejected"` leaves the wallet untouched and reports why (currently only `"insufficient-funds"`). Discriminate on `status` before reading `state`.
1050
1086
  - `ChaseCameraConfig` (interface): interface ChaseCameraConfig — Speed-reactive vehicle chase rig (#27) — speed→FOV, spring arm, procedural shake, interior views.
1051
- - `Chat` (interface): interface Chat — ⚠ undocumented
1052
- - `ChatMessage` (interface): interface ChatMessage — ⚠ undocumented
1053
- - `ChatRateLimit` (interface): interface ChatRateLimit — ⚠ undocumented
1087
+ - `Chat` (interface): interface Chat { register(def: ChatChannelDef): void; channels(): ChatChannelDef[]; send(fromUserId: string, body: string): ChatSendResult; send(fromUserId: string, channelId: string, body: string): ChatSendResult; recent(options?: {limit?: number; channe… — ⚠ undocumented
1088
+ - `ChatMessage` (interface): interface ChatMessage { id: string; channelId: string; fromUserId: string; body: string; at: number } — ⚠ undocumented · used by `createConvexChatTransport` (@jgengine/convex): Wires a game's Convex chat functions into the engine's ChatTransport contract: one live query per subscribed channel (the channel's recent h…
1089
+ - `ChatRateLimit` (interface): interface ChatRateLimit { count: number; perMs: number } — ⚠ undocumented
1054
1090
  - `ChatSendResult` (type): type ChatSendResult = | { message: ChatMessage; recipients: ChatRecipients } | { reason: string } — ⚠ undocumented
1055
1091
  - `CinematicCameraConfig` (interface): interface CinematicCameraConfig — Scripted keyframe / path player (#29). When set it overrides the active rig.
1056
1092
  - `Codex` (interface): interface Codex<TMeta = unknown> — A codex/bestiary of defined entries with per-player discovery tracking.
@@ -1058,7 +1094,7 @@
1058
1094
  - `CodexEntryView` (interface): interface CodexEntryView<TMeta = unknown> extends CodexEntryDef<TMeta> — A definition plus its discovery state — what UI renders.
1059
1095
  - `CodexOptions` (interface): interface CodexOptions<TMeta = unknown> — Options for {@link createCodex}.
1060
1096
  - `CodexSnapshot` (interface): interface CodexSnapshot — Serializable discovery state — a save blob.
1061
- - `CombatTelegraphEvent` (interface): interface CombatTelegraphEvent — ⚠ undocumented
1097
+ - `CombatTelegraphEvent` (interface): interface CombatTelegraphEvent { id: number; shape: TelegraphShape; position: [number, number, number]; dir?: number; windupMs: number; kind: string } — ⚠ undocumented
1062
1098
  - `CombatVfxEvent` (interface): interface CombatVfxEvent — A transient sprite-particle effect the shell renders once and expires — one burst of `kind`, tinted `color`, anchored at `from` (and `to` for travel/beam effects).
1063
1099
  - `CombatVfxInstanceEvent` (interface): interface CombatVfxInstanceEvent — The lifecycle op a {@link VfxInstanceStore} emits to its renderer sink. `upsert`/`update` carry the full merged {@link VfxInstanceState} (the renderer applies it directly, no merge); `stop` carries the id plus a fade duration. This is the payload of the `combat.vfxInstance` game event when the store is wired to the event bus.
1064
1100
  - `CompatibilityRule` (type): type CompatibilityRule = RequireRule | ForbidRule — A cross-slot compatibility rule constraining which part/tag/family combinations a modular item may hold.
@@ -1066,11 +1102,11 @@
1066
1102
  - `ComposedUse` (interface): interface ComposedUse<TWorld> — A resolved, ordered composition of behaviors for one item. Dispatch is transactional: `apply` commits the folded world only if every behavior in the chain succeeds, otherwise it returns the original world and state plus the first error.
1067
1103
  - `CompositionResult` (type): type CompositionResult<TWorld> = | { status: "ok"; composed: ComposedUse<TWorld> } | { status: "error"; reason: "unknown-behavior"; id: string } | { status: "error"; reason: "duplicate-behavior"; id: string } | { status: "error"; reason: "missing-capability"; id: string; capability: string } | { sta… — The outcome of composing an item's behavior refs: either a ready {@link ComposedUse} or a structured error naming the offending behavior.
1068
1104
  - `ConstraintViolation` (interface): interface ConstraintViolation — One failed {@link CompatibilityRule}, carrying the rule id, its kind, and a human-readable message for UI or generator diagnostics.
1069
- - `CropDef` (interface): interface CropDef — ⚠ undocumented
1070
- - `CropTileState` (interface): interface CropTileState — ⚠ undocumented
1105
+ - `CropDef` (interface): interface CropDef { id: string; stages: readonly number[]; regrowDays?: number; needsDailyWater?: boolean; harvest?: RecipeItem } — ⚠ undocumented
1106
+ - `CropTileState` (interface): interface CropTileState { soil: SoilState; watered: boolean; cropId: string | null; stage: number; stageProgress: number; harvestable: boolean } — ⚠ undocumented
1071
1107
  - `CrossThresholdsOptions` (interface): interface CrossThresholdsOptions — Exact-boundary and dead-band policy for {@link crossThresholds}.
1072
1108
  - `Curve` (type): type Curve = CurveDef & CurveShape — A fully specified progression curve — a {@link CurveDef} growth shape plus optional {@link CurveShape} rounding/clamp.
1073
- - `DEFAULT_CHAT_BODY_LENGTH` (const): const DEFAULT_CHAT_BODY_LENGTH: 500 — ⚠ undocumented
1109
+ - `DEFAULT_CHAT_BODY_LENGTH` (const): const DEFAULT_CHAT_BODY_LENGTH: 240 — ⚠ undocumented
1074
1110
  - `DEFAULT_CHAT_HISTORY_LIMIT` (const): const DEFAULT_CHAT_HISTORY_LIMIT: 100 — ⚠ undocumented
1075
1111
  - `DEFAULT_CHAT_RATE_LIMIT` (const): const DEFAULT_CHAT_RATE_LIMIT: ChatRateLimit — ⚠ undocumented
1076
1112
  - `DEFAULT_FIXED_STAGES` (const): const DEFAULT_FIXED_STAGES: readonly ["input", "movement", "combat", "ai", "activities", "cleanup"] — Default fixed-sim stage order — systems pick a stage; most need only this.
@@ -1081,8 +1117,8 @@
1081
1117
  - `DecayMeterSet` (interface): interface DecayMeterSet — Set of named survival meters (hunger/thirst/…) that drain and refill over game time.
1082
1118
  - `DecayMeterValues` (type): type DecayMeterValues = Record<string, number> — Plain-data meter values: `meter id → current value`. This is the whole serialized form — it drops straight into a `defineGame` state record and round-trips through save/load and multiplayer sync with no closure to rebuild.
1083
1119
  - `DecayModifier` (type): type DecayModifier = number | Record<string, number> — Rate multiplier for {@link decayMeters}: one scalar applied to every meter (a member's metabolism, a game-mode harshness dial) or a per-meter record (cold biome → warmth only). `1` / omitted leaves the base rates unscaled.
1084
- - `DeliveryEntry` (interface): interface DeliveryEntry — ⚠ undocumented
1085
- - `DeliveryQueue` (interface): interface DeliveryQueue — ⚠ undocumented
1120
+ - `DeliveryEntry` (interface): interface DeliveryEntry { id: string; userId: string; inventoryId: string; items: readonly ItemStack[]; deliverAt: number } — ⚠ undocumented
1121
+ - `DeliveryQueue` (interface): interface DeliveryQueue { schedule(entry: ScheduledDelivery & {id?: string}): DeliveryEntry; due(now: number): readonly DeliveryEntry[]; claimDue(now: number): readonly DeliveryEntry[]; pending(userId?: string): readonly DeliveryEntry[]; cancel(id: string): boolea… — ⚠ undocumented
1086
1122
  - `DialogueGraph` (interface): interface DialogueGraph — A serializable branching conversation: a start node id and the nodes it can reach.
1087
1123
  - `DialogueGraphChoice` (interface): interface DialogueGraphChoice — One selectable response on a conversation node — the text a player clicks and the node it advances to. `kind` is a free style tag the presenter interprets; the model never reads it (no genre baked in).
1088
1124
  - `DialogueGraphNode` (interface): interface DialogueGraphNode — One conversation node: who is speaking, the line they say, and the branches out of it. `speaker`/`speakerKind`/`portrait` are opaque display data — the model never interprets them.
@@ -1090,35 +1126,35 @@
1090
1126
  - `DialogueGraphView` (interface): interface DialogueGraphView — The render-ready snapshot of a conversation at one node — everything a view needs to draw speaker, line, and choice buttons, with no traversal logic in the component.
1091
1127
  - `DialogueRun` (interface): interface DialogueRun — An observable walk through a {@link DialogueGraph}: current view, choose to advance, serialize.
1092
1128
  - `DialogueRunOptions` (interface): interface DialogueRunOptions — Options for {@link createDialogueRun}.
1093
- - `DirectionalLightingConfig` (interface): interface DirectionalLightingConfig — ⚠ undocumented
1129
+ - `DirectionalLightingConfig` (interface): interface DirectionalLightingConfig { color?: string; intensity?: number; position: readonly [number, number, number]; castShadow?: boolean; shadowMapSize?: number; shadowCameraSize?: number; cascades?: number; shadowMaxFar?: number; shadowBias?: number; shadowNormalBias?: nu… — ⚠ undocumented
1094
1130
  - `Drop` (interface): interface Drop — A resolved loot outcome — one item or currency grant with its rolled count.
1095
- - `DurabilitySpec` (interface): interface DurabilitySpec — ⚠ undocumented
1096
- - `DurabilityState` (interface): interface DurabilityState — ⚠ undocumented
1131
+ - `DurabilitySpec` (interface): interface DurabilitySpec { max: number; wearPerUse?: number; wearPerHit?: number; disableAtZero?: boolean; repair?: RepairSpec } — ⚠ undocumented
1132
+ - `DurabilityState` (interface): interface DurabilityState { current: number; max: number } — ⚠ undocumented · used by `applyWear`: Apply wear to an item, tracking breakage and repair eligibility.
1097
1133
  - `EffectRef` (interface): interface EffectRef — A reference to an effect the game knows how to apply — id plus JSON-safe params, no closures.
1098
1134
  - `EnqueueOptions` (interface): interface EnqueueOptions — Optional per-enqueue overrides.
1099
1135
  - `EnqueueResult` (type): type EnqueueResult<TSpec, TReserve = undefined> = | { readonly ok: true; readonly state: WorkQueueState<TSpec, TReserve>; readonly job: Job<TSpec, TReserve> } | { readonly ok: false; readonly state: WorkQueueState<TSpec, TReserve>; readonly reason: string } — Outcome of {@link enqueue}. On rejection the state is returned unchanged.
1100
- - `EntityDiedEvent` (interface): interface EntityDiedEvent — ⚠ undocumented
1101
- - `EntityFloatTextEvent` (interface): interface EntityFloatTextEvent — ⚠ undocumented
1102
- - `EntitySpriteConfig` (interface): interface EntitySpriteConfig — ⚠ undocumented
1136
+ - `EntityDiedEvent` (interface): interface EntityDiedEvent { instanceId: string; catalogId: string; userId?: string; displayName?: string; reason: DeathReason; position: [number, number, number]; serverId?: string } — ⚠ undocumented
1137
+ - `EntityFloatTextEvent` (interface): interface EntityFloatTextEvent { instanceId?: string; position: [number, number, number]; text: string; kind: string; amount?: number; hitType?: string; element?: string; crit?: boolean; scale?: number } — ⚠ undocumented
1138
+ - `EntitySpriteConfig` (interface): interface EntitySpriteConfig { url: string; width: number; height: number; y: number; clip?: {atlas: SpriteAtlas; animation: string} } — ⚠ undocumented
1103
1139
  - `EventTicker` (interface): interface EventTicker — A live, observable event/kill-feed ticker.
1104
1140
  - `EventTickerEntry` (interface): interface EventTickerEntry extends TimedFeedEntry — A stored ticker entry — an {@link EventTickerInput} stamped with an id and clock time.
1105
1141
  - `EventTickerInput` (interface): interface EventTickerInput — One event pushed onto the ticker. `kind` and `icon` are free strings the game owns and the model never interprets — they only ride through to the renderer so a game can color, icon, and group each entry however it likes ("kill", "assist", "info", …).
1106
1142
  - `EventTickerOptions` (interface): interface EventTickerOptions — Options for {@link createEventTicker}.
1107
1143
  - `EventTickerSnapshot` (interface): interface EventTickerSnapshot — Serializable state of the ticker, for save/restore.
1108
1144
  - `EventTickerView` (interface): interface EventTickerView extends EventTickerEntry — A live ticker entry as handed to the renderer: the stored entry plus a `fade` value `0..1` (age / `ttlMs`) — `0` for a fresh entry, approaching `1` as it nears expiry — so the UI can drop opacity as an entry ages out. `fade` is always `0` when no `ttlMs` is configured.
1109
- - `FeedEntry` (interface): interface FeedEntry<T = unknown> — ⚠ undocumented
1145
+ - `FeedEntry` (interface): interface FeedEntry<T = unknown> { at: number; data: T } — ⚠ undocumented · used by `ToastStack` (@jgengine/react): Render `ctx.game.feed`'s entries for `action` as a newest-first toast stack — the feed-backed sibling of `@jgengine/core/game/toasts`' `crea…
1110
1146
  - `FeedWindow` (interface): interface FeedWindow — Bounds for {@link appendFeed} / {@link pruneFeed}: newest-`limit` cap and/or `ttl` age window.
1111
1147
  - `FiringBlock` (type): type FiringBlock = "predicate" | "no-target" | "cooldown" | "rate-limit" | "no-charges" | "stack-ignored" — Reason a firing did not produce an effect — surfaced for debug inspection, never thrown.
1112
- - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig — ⚠ undocumented
1148
+ - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig { eyeHeight?: number; sensitivity?: number; maxPitch?: number; reticle?: boolean; viewmodel?: boolean } — ⚠ undocumented
1113
1149
  - `ForbidRule` (interface): interface ForbidRule — A rule that forbids a combination — e.g. "an incendiary barrel cannot pair with a cryo core". A forbid rule can never become satisfiable by adding more parts, so it is the check a backtracking generator runs on each candidate.
1114
- - `FriendEntry` (interface): interface FriendEntry — ⚠ undocumented
1115
- - `FriendRequestEntry` (interface): interface FriendRequestEntry — ⚠ undocumented
1116
- - `Friends` (interface): interface Friends — ⚠ undocumented
1150
+ - `FriendEntry` (interface): interface FriendEntry { userId: string; online: boolean } — ⚠ undocumented
1151
+ - `FriendRequestEntry` (interface): interface FriendRequestEntry { requestId: string; fromUserId: string } — ⚠ undocumented
1152
+ - `Friends` (interface): interface Friends { canRequest(fromUserId: string, toUserId: string): {reason: string} | null; request(fromUserId: string, toUserId: string): {requestId: string} | {reason: string}; accept(userId: string, requestId: string): {reason: string} | null; decline(… — ⚠ undocumented
1117
1153
  - `GameCameraConfig` (interface): interface GameCameraConfig — Camera tuning for the shell's rig stack: pick the rig via `rig`, then tune it through its matching config block. All fields optional — the default is the third-person orbit rig.
1118
1154
  - `GameDefinition` (interface): interface GameDefinition<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> — Fully-resolved game description produced by {@link defineGameDefinition} — assets, scene, and opted-in subsystems.
1119
1155
  - `GameDefinitionConfig` (type): type GameDefinitionConfig<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> = Omit<GameDefinition<TAssetRef, TMultiplayer>, "scene" | "assets" | "lifecycle"> & { assets?: AssetCatalog<TAssetRef>; /** * The game's run-phase story — a {@link LifecycleConfig} or the `"always-live… — Input to {@link defineGameDefinition} — a `GameDefinition` with `scene` derived and `assets` optional.
1120
- - `GameEventMap` (interface): interface GameEventMap — ⚠ undocumented
1121
- - `GameEvents` (interface): interface GameEvents<TMap extends GameEventMap = GameEventMap> — ⚠ undocumented
1156
+ - `GameEventMap` (interface): interface GameEventMap { "entity.died": EntityDiedEvent; "entity.floatText": EntityFloatTextEvent; "combat.telegraph": CombatTelegraphEvent; "combat.vfx": CombatVfxEvent; "combat.vfxInstance": CombatVfxInstanceEvent; "combat.telegraphCancelled": CombatTelegraphCa… — ⚠ undocumented · used by `createGameEvents`: A typed publish/subscribe bus for gameplay events that systems and HUDs subscribe to.
1157
+ - `GameEvents` (interface): interface GameEvents<TMap extends GameEventMap = GameEventMap> { on<TName extends keyof TMap>(name: TName, handler: GameEventHandler<TMap[TName]>): () => void; subscribe<TName extends keyof TMap>(name: TName, handler: GameEventHandler<TMap[TName]>): () => void; emit<TName extends keyof TMap>(name: TNam… — ⚠ undocumented · used by `createGameEvents`: A typed publish/subscribe bus for gameplay events that systems and HUDs subscribe to.
1122
1158
  - `GameLifecycle` (type): type GameLifecycle<TState = unknown> = LifecycleConfig<TState> | "always-live" — How a game declares its run-phase story to {@link defineGameDefinition}. Every game states this explicitly so the shell never has to guess — a silent game used to default to `"playing"`, which painted the touch dock over title/menu/results screens (#1337, Vice Isle #1329).
1123
1159
  - `GameLoop` (interface): interface GameLoop<TContext = unknown> — Lifecycle hooks a game implements to drive init, per-tick simulation, and player join/leave.
1124
1160
  - `GamePhase` (type): type GamePhase = "menu" | "playing" | "paused" | "ended" — Canonical run phase every game moves through. `menu` (title/main menu), `playing` (live), `paused` (mid-run pause), `ended` (win/lose/results). Touch controls are shown only while `playing`; menus and results never paint the touch dock over themselves.
@@ -1139,40 +1175,40 @@
1139
1175
  - `IdentityQuery` (interface): interface IdentityQuery — A predicate over an {@link ItemIdentity}, expressed as data so a whole rule set round-trips through JSON. An empty query matches every identity; each present field narrows the match and all present fields must hold (AND).
1140
1176
  - `InspectionCameraConfig` (interface): interface InspectionCameraConfig — Model-viewer / inspection rig (#207.7) — orbit + pan + anchored zoom around a fixed point, never reads player input.
1141
1177
  - `InspectionZoomAnchor` (type): type InspectionZoomAnchor = "target" | "cursor" | "center" — How scroll-zoom re-anchors the view for the inspection rig (#207.7): - `target` — dolly toward the orbit target (classic OrbitControls behavior). - `cursor` — dolly toward the point under the pointer. - `center` — dolly toward the viewport center; equivalent to `target` for an OrbitControls-driven rig, since the camera always faces `target` and that point already projects to the exact center of the viewport.
1142
- - `InstalledPart` (interface): interface InstalledPart — ⚠ undocumented
1178
+ - `InstalledPart` (interface): interface InstalledPart { slotId: string; part: PartDef } — ⚠ undocumented · used by `identityOf`: Assemble an {@link ItemIdentity} from a family, tags, and installed parts.
1143
1179
  - `InventoryDeclaration` (interface): interface InventoryDeclaration — Shape of one named inventory a game declares — slot count, accepted item types, HUD binding.
1144
1180
  - `InventorySlot` (type): type InventorySlot = { itemId: string; count: number } | null — ⚠ undocumented
1145
- - `InventoryState` (interface): interface InventoryState — ⚠ undocumented
1181
+ - `InventoryState` (interface): interface InventoryState { slots: InventorySlot[] } — ⚠ undocumented · used by `countItem` (@jgengine/core/inventory/inventoryModel): Total quantity of `itemId` summed across every stack in the inventory.
1146
1182
  - `ItemIdentity` (interface): interface ItemIdentity — The declarative identity of a built modular item: a caller-named family, its provenance tags, and the parts occupying its slots. This is the "what an item is" layer above the raw stat rollup in ./modularItem — a plain, serializable value with no game noun baked in ("gun", "manufacturer", "potion" are all caller data in `family`/`tags`).
1147
1183
  - `ItemProvenance` (interface): interface ItemProvenance — The serializable record of how an item was generated: its family, tags, per-slot part selection, applied set-bonus ids, and the deterministic seed. Enough for UI provenance display and byte-exact regeneration.
1148
- - `ItemUseHandler` (interface): interface ItemUseHandler<TState> — ⚠ undocumented
1149
- - `ItemUseInput` (interface): interface ItemUseInput — ⚠ undocumented
1184
+ - `ItemUseHandler` (interface): interface ItemUseHandler<TState> { can?(state: TState, input: ItemUseInput): ItemUseRejection | null; apply(state: TState, input: ItemUseInput): ItemUseResult<TState> } — ⚠ undocumented
1185
+ - `ItemUseInput` (interface): interface ItemUseInput { from: string; itemId: string; inventoryId?: string; aim?: Aim } — ⚠ undocumented
1150
1186
  - `Job` (interface): interface Job<TSpec, TReserve = undefined> — One unit of timed work. Plain serializable data (given serializable `TSpec`/`TReserve`).
1151
1187
  - `JobId` (type): type JobId = string — Generic timed work queue — a pure-data model for discrete jobs that reserve inputs, advance over game time, can be paused/cancelled, and emit an output on completion. It backs unit training, crafting jobs, construction, research, respawns, downloads, and fabrication without any of them re-implementing the reservation → progress → completion → output-routing loop.
1152
1188
  - `JobOrdering` (type): type JobOrdering<TSpec, TReserve = undefined> = ( a: Job<TSpec, TReserve>, b: Job<TSpec, TReserve>, ) => number — Comparator over jobs; negative means the first job runs sooner.
1153
1189
  - `JobStatus` (type): type JobStatus = "queued" | "active" | "paused" — Lifecycle phase of a single queued job. Terminal jobs are removed from state.
1154
1190
  - `JobValidation` (interface): interface JobValidation — Result of pre-enqueue validation (population caps, prerequisites, affordability).
1155
1191
  - `KeyValueStorage` (interface): interface KeyValueStorage — Structural, DOM-free storage backend: the browser `localStorage` satisfies it, as does a test stub or `null`. The one storage seam core primitives target so persistence code never needs the DOM `Storage` lib.
1156
- - `LaneRule` (interface): interface LaneRule<C> — ⚠ undocumented
1192
+ - `LaneRule` (interface): interface LaneRule<C> { id: string; apply: (input: LaneRuleInput<C>) => number } — ⚠ undocumented
1157
1193
  - `LayerConflict` (interface): interface LayerConflict — A single conflict surfaced by {@link validateLayers}.
1158
1194
  - `LayerOps` (type): type LayerOps = Readonly<Record<string, ParamOp | readonly ParamOp[]>> — Per-parameter ops contributed by one layer — a single op or an ordered list folded in sequence.
1159
1195
  - `LayerRegistry` (interface): interface LayerRegistry — Registered lookup of {@link ParamLayer}s by stable id, resolving serialized selections and unknowns.
1160
1196
  - `LayerSelection` (type): type LayerSelection = readonly string[] — A serializable, ordered reference to layers by stable id — what a save file or session setup stores.
1161
- - `LeaderboardRow` (interface): interface LeaderboardRow — ⚠ undocumented
1197
+ - `LeaderboardRow` (interface): interface LeaderboardRow { stat: string; scope: LeaderboardScope; serverId?: string; userId: string; value: number } — ⚠ undocumented · used by `createLeaderboard`: Ranked score tracking across global, server, and per-profile scopes, with top-N queries and per-profile lookups.
1162
1198
  - `LeaderboardScope` (type): type LeaderboardScope = "global" | "server" | "profile" — ⚠ undocumented
1163
1199
  - `LedgerEvent` (interface): interface LedgerEvent — Lifecycle signal emitted by {@link advanceLedger}.
1164
1200
  - `LedgerEventKind` (type): type LedgerEventKind = "started" | "fired" | "skipped" | "depleted" | "ended" — The kinds of lifecycle signal {@link advanceLedger} can emit for a rule.
1165
1201
  - `LevelProgress` (interface): interface LevelProgress — Result of resolving a level+xp pair: the settled `level`, leftover `xp` into the current level, the `xpMax` threshold for the next level, and how many `levelsGained` this resolution produced.
1166
- - `LevelSequence` (interface): interface LevelSequence<TLevelConfig> — ⚠ undocumented
1202
+ - `LevelSequence` (interface): interface LevelSequence<TLevelConfig> { current(): CurrentLevel<TLevelConfig> | null; status(): LevelSequenceStatus; start(): void; clear(stars?: LevelStars): void; fail(): "retry" | "failed"; retry(): boolean; advance(): boolean; select(level: string): boolean; isUnlocked(leve… — ⚠ undocumented · used by `createLevelSequence`: A pure, deterministic level campaign: an ordered list of levels, each with its own opaque config, played through a `start` → (`clear` → `adv…
1167
1203
  - `LevelingConfig` (interface): interface LevelingConfig — Configuration for a {@link leveling} track: the `xpForLevel` {@link Curve}, the `maxLevel` cap, and optional `startLevel`, stat ids (`xpStat`/`levelStat`, default `"xp"`/`"level"`), and `thresholdMode` — `"perLevel"` (each level costs its own curve value) or `"cumulative"` (curve gives the total xp to reach a level).
1168
1204
  - `LevelingTrack` (interface): interface LevelingTrack — A resolved leveling track: the immutable `maxLevel`/`startLevel`, the `xpForLevel` threshold lookup, a pure `resolve`, and `grantXp` which writes back through a {@link LevelingStatAccess} and fires `onLevelUp` once for every reached level in ascending order.
1169
1205
  - `LifecycleConfig` (interface): interface LifecycleConfig<TState = unknown> — Declarative start/restart run lifecycle: the state transitions a game's run phase every genre repeats (title screen → live run → live run → title screen again), expressed as pure functions over one typed {@link StoreHandle} slot instead of hand-rolled `commands.define("start"/"restart")` glue that re-derives phase after every mutation. `start`/`restart` receive the store's own value type — the store's `TState`, never `ctx.game.store.get(key) as T` — and return the next value; the runtime writes it back and derives {@link GamePhase} from it via `phaseOf` in one place, so every adopting game gets identical, correct phase-sync for free.
1170
1206
  - `LightingConfig` (interface): interface LightingConfig — Declarative lighting replacing the shell's hardcoded ambient/directional default (#207.5); mounts regardless of world kind, only when supplied.
1171
1207
  - `Listing` (interface): interface Listing — One active post in a {@link ListingBook}: an item stack a seller offered at a fixed price until it expires.
1172
- - `LoadoutDef` (interface): interface LoadoutDef — ⚠ undocumented
1208
+ - `LoadoutDef` (interface): interface LoadoutDef { inventories?: Record<string, LoadoutItemEntry[]>; stats?: Record<string, {current: number; max?: number; min?: number}>; economy?: Record<string, number>; unlocks?: string[] } — ⚠ undocumented
1173
1209
  - `LockOnCameraConfig` (interface): interface LockOnCameraConfig — Lock-on / strafe rig (#26) — yaw bound to player→target, move axis becomes strafe.
1174
1210
  - `LootDropProvenance` (interface): interface LootDropProvenance — Why one drop is in the result: the stage/table/entry that produced it, its weights, and the modifiers that shaped it.
1175
- - `LootFilterRule` (interface): interface LootFilterRule — ⚠ undocumented
1211
+ - `LootFilterRule` (interface): interface LootFilterRule { id: string; when: LootFilterCondition; hide?: boolean; color?: string; beam?: boolean; label?: string } — ⚠ undocumented · used by `evaluateLootFilter`: First matching rule wins (PoE/Last Epoch block semantics) — later rules never override an earlier match.
1176
1212
  - `LootModifier` (interface): interface LootModifier<TCtx = unknown> — A registered, id-tagged loot policy applied to one stage. `plan` transforms eligibility, weights, and roll counts before rolling (luck, difficulty, gating); `drops` post-processes the rolled drops (quantity multipliers, dedupe, caps). Neither hook mutates table definitions, and the id is recorded in provenance so a resolved drop can be traced back to the policies that shaped it.
1177
1213
  - `LootPipeline` (interface): interface LootPipeline<TCtx = unknown> — A resolved, reusable loot pipeline. Call {@link LootPipeline.resolve} with a per-drop context and RNG.
1178
1214
  - `LootPipelineDef` (interface): interface LootPipelineDef<TCtx = unknown> — A named, ordered loot-resolution pipeline: the stages to run plus result-shaping policy (duplicate stacking, a total drop cap). Serializable except for its stage gate/modifier functions, mirroring how {@link LootTableDef} entries may carry a `generate` function.
@@ -1186,13 +1222,13 @@
1186
1222
  - `LootStageStatus` (type): type LootStageStatus = "rolled" | "skipped" | "empty" | "replaced" | "fell-through" — The disposition of a stage after resolution — did it roll, get gated, fall through, override, or find nothing.
1187
1223
  - `LootStageTrace` (interface): interface LootStageTrace — Per-stage record of what happened during resolution, for debugging and replay auditing.
1188
1224
  - `LootTableDef` (interface): interface LootTableDef — A named, validated loot table — its roll count, weighted-vs-independent mode, and candidate entries.
1189
- - `ModelConfig` (interface): interface ModelConfig — ⚠ undocumented
1225
+ - `ModelConfig` (interface): interface ModelConfig { url: string; scale?: number; targetHeight?: number; y?: number; anchor?: "center" | "origin"; dims?: ModelDims; collisionMesh?: CollisionMeshData; material?: ModelMaterialOverride; shadows?: "cast" | "receive" | "both" | "none"; animation… — ⚠ undocumented · used by `PartMotionRig` (@jgengine/shell/render/PartMotion): Procedural motion rig for a rig-less part-composed character (`ModelPart.role` — see `@jgengine/core/game/partAnimation`).
1190
1226
  - `ModelMaterialMaps` (interface): interface ModelMaterialMaps — Real PBR map URLs (e.g. `buildMaterialCatalog(...).resolve(id)!.maps` from `@jgengine/assets`) layered onto a model's material — the seam for texturing an otherwise-flat/untextured GLB. Any role may be omitted to keep the model's own map.
1191
- - `ModelMaterialOverride` (interface): interface ModelMaterialOverride — Per-entity PBR material override (#151.3) applied to every `MeshStandardMaterial` in the model's cloned scene graph.
1192
- - `ModularItemDef` (interface): interface ModularItemDef — ⚠ undocumented
1227
+ - `ModelMaterialOverride` (interface): interface ModelMaterialOverride — Per-entity PBR material override (#151.3) applied to every standard or physical material in the model's cloned scene graph.
1228
+ - `ModularItemDef` (interface): interface ModularItemDef { id: string; baseStats: Record<string, number>; slots: readonly MountSlotDef[] } — ⚠ undocumented
1193
1229
  - `Moodle` (interface): interface Moodle — One survival moodle (status icon) — severity, source, and label for HUD chips.
1194
1230
  - `MoodleStack` (interface): interface MoodleStack — Ordered stack of active moodles derived from meters/ailments/buffs.
1195
- - `MountSlotDef` (interface): interface MountSlotDef — ⚠ undocumented
1231
+ - `MountSlotDef` (interface): interface MountSlotDef { id: string; accepts: string | readonly string[]; required?: boolean } — ⚠ undocumented · used by `slotAccepts`: Attach parts into an item's mount slots and resolve the combined stats.
1196
1232
  - `MultiRegionHealth` (interface): interface MultiRegionHealth — Per-limb / per-region health track with treat/damage/heal APIs.
1197
1233
  - `NEUTRAL_AXIS` (const): const NEUTRAL_AXIS: AxisInput — ⚠ undocumented
1198
1234
  - `NotificationCenterOptions` (interface): interface NotificationCenterOptions — Options for {@link createNotificationCenter}.
@@ -1201,7 +1237,7 @@
1201
1237
  - `NotificationInput` (interface): interface NotificationInput<TMeta = unknown> — Fields accepted by {@link NotificationStore.push}.
1202
1238
  - `NotificationStore` (interface): interface NotificationStore<TMeta = unknown> — Serializable, observable log of persistent notifications with read tracking.
1203
1239
  - `NumericBounds` (interface): interface NumericBounds — Optional inclusive `[min, max]` clamp applied after a write. Omit an edge for unbounded.
1204
- - `ObjectStyle` (interface): interface ObjectStyle — ⚠ undocumented
1240
+ - `ObjectStyle` (interface): interface ObjectStyle { color?: string; opacity?: number; hidden?: boolean } — ⚠ undocumented
1205
1241
  - `ObserverCameraConfig` (interface): interface ObserverCameraConfig — Detached spectator/photo cam (#120) — binds to any entity or fixed point, never reads player input.
1206
1242
  - `Overdraft` (type): type Overdraft = boolean | { max: number } — Opt-in debt affordance for {@link charge}/{@link chargeAll}: `true` allows the balance to go arbitrarily negative, a number caps how far into the red it may go (the charge is rejected once `balance - amount` would fall below `-max`). Omitted (the default) keeps the strict no-debt rule.
1207
1243
  - `PING_FEED_ACTION` (const): const PING_FEED_ACTION: "party.ping" — ⚠ undocumented
@@ -1212,18 +1248,18 @@
1212
1248
  - `ParamLayer` (interface): interface ParamLayer — A named, serializable bundle of parameter transforms with a stable id and precedence. `label` is an optional display name that may intentionally differ from the applied ops (e.g. a tier shown as "Mayhem 4" whose real multipliers are data). Higher `priority` applies later — on top — and ties break by the layer's index in the active list, so ordering is deterministic.
1213
1249
  - `ParamOp` (type): type ParamOp = | { readonly kind: "set"; readonly value: number } | { readonly kind: "add"; readonly value: number } | { readonly kind: "multiply"; readonly value: number } | { readonly kind: "clamp"; readonly min?: number; readonly max?: number } | { readonly kind: "curve"; readonly curve: Curve } — A single transform applied to one numeric parameter. `set` overrides, `add`/`multiply` accumulate, `clamp` bounds, and `curve` remaps the running value through a {@link Curve} (the same curve primitive progression tracks use), so a caller can reshape a value non-linearly mid-stack.
1214
1250
  - `ParamSnapshot` (interface): interface ParamSnapshot — A resolved effective-parameter snapshot: final `values` plus the ordered op trace per parameter.
1215
- - `PartDef` (interface): interface PartDef — ⚠ undocumented
1216
- - `Party` (interface): interface Party — ⚠ undocumented
1217
- - `PartyInviteEntry` (interface): interface PartyInviteEntry — ⚠ undocumented
1218
- - `PartyMemberEntry` (interface): interface PartyMemberEntry — ⚠ undocumented
1219
- - `PhysicsConfig` (interface): interface PhysicsConfig — World gravity and jump tuning, plus scene-object collision opt-ins, for the game's physics step.
1220
- - `PingCategory` (type): type PingCategory = string — ⚠ undocumented
1221
- - `PingSystem` (interface): interface PingSystem — ⚠ undocumented
1222
- - `PlayableGame` (interface): interface PlayableGame<TUi = unknown, TWorldOverlay = unknown, TRenderEntity = never, TRenderObject = never, TViewmodel = unknown, TOverlay = TWorldOverlay> — ⚠ undocumented
1223
- - `PointerAxisState` (interface): interface PointerAxisState — ⚠ undocumented
1224
- - `PointerConfig` (interface): interface PointerConfig — ⚠ undocumented
1251
+ - `PartDef` (interface): interface PartDef { id: string; category: string; stats?: Record<string, number>; multipliers?: Record<string, number> } — ⚠ undocumented
1252
+ - `Party` (interface): interface Party { register(config: PartyConfig): void; canInvite(fromUserId: string, toUserId: string): {reason: string} | null; invite(fromUserId: string, toUserId: string): {inviteId: string} | {reason: string}; accept(userId: string, inviteId: string): … — ⚠ undocumented
1253
+ - `PartyInviteEntry` (interface): interface PartyInviteEntry { inviteId: string; fromUserId: string; createdAt: number } — ⚠ undocumented
1254
+ - `PartyMemberEntry` (interface): interface PartyMemberEntry { userId: string; role: PartyRole } — ⚠ undocumented
1255
+ - `PhysicsConfig` (interface): interface PhysicsConfig — World gravity and jump tuning, plus the optional rigid-body backend and character capsule.
1256
+ - `PingCategory` (type): type PingCategory = string — ⚠ undocumented · used by `DEFAULT_PING_CATEGORIES`: Content-agnostic default ping wheel: enemy / loot / location / danger.
1257
+ - `PingSystem` (interface): interface PingSystem { classify(hit: PointerHit): PingCategory; buildPayload(from: string, hit: PointerHit, category?: PingCategory): PingPayload; broadcast(payload: PingPayload): MapMarker; ping(from: string, hit: PointerHit, category?: PingCategory): PingPayl… — ⚠ undocumented · used by `createPingSystem`: Contextual ping/marker communication between teammates, classified by what was pinged.
1258
+ - `PlayableGame` (interface): interface PlayableGame<TUi = unknown, TWorldOverlay = unknown, TRenderEntity = never, TRenderObject = never, TViewmodel = unknown, TOverlay = TWorldOverlay> { game: GameDefinition; content: GameContextContent; loop: Required<Omit<GameLoop<GameContext>, "onPlayerLeave">> & Pick<GameLoop<GameContext>, "onPlayerLeave">; GameUI: TUi; presentation?: "3d" | "hud"; WorldOverlay?: TOverlay; environment… — ⚠ undocumented · used by `defineGame` (@jgengine/shell/defineGame): The one public authoring entry point: compose engine fields (systems, world, physics, input) and presentation fields (camera, HUD, audio, au…
1259
+ - `PointerAxisState` (interface): interface PointerAxisState { x: number; y: number; active: boolean } — ⚠ undocumented · used by `normalizePointerToAxis`: Normalize client coordinates against a surface rect into a `PointerAxisState`, clamped to `[-1, 1]` per axis.
1260
+ - `PointerConfig` (interface): interface PointerConfig — Mouse/touch pointer bindings for `defineGame({ pointer })`.
1225
1261
  - `PointerHit` (interface): interface PointerHit — Renderer-free result of a screen→world raycast. The shell's pointer service produces this from the cursor; core-side gameplay (item.use aim, click-to-move, ground-target abilities, pings) consumes it without touching three.js.
1226
- - `PointerVec3` (type): type PointerVec3 = readonly [number, number, number] — ⚠ undocumented
1262
+ - `PointerVec3` (type): type PointerVec3 = readonly [number, number, number] — ⚠ undocumented · used by `aimToPoint`: Build an `origin → point` aim for `item.use` / projectiles, firing toward the cursor.
1227
1263
  - `PolicyContext` (interface): interface PolicyContext — Read-only context handed to every {@link ResourcePolicy} for a transaction.
1228
1264
  - `PolicyRead` (type): type PolicyRead = string | ((ctx: PolicyContext) => number) — Reader over policy context: a `vars` key or a function of the context.
1229
1265
  - `Precision` (interface): interface Precision — Deterministic rounding applied to every transaction amount before it touches balances.
@@ -1231,16 +1267,16 @@
1231
1267
  - `PredicateFacts` (type): type PredicateFacts = Record<string, unknown> — Plain, serializable bag of facts a predicate reads by dot path.
1232
1268
  - `PredicatePath` (type): type PredicatePath = string — Dot path into a fact bag, e.g. `"hit.crit"` or `"attacker.team"`.
1233
1269
  - `PredicateValue` (type): type PredicateValue = string | number | boolean | null — A declarative, serializable predicate AST evaluated against a plain fact bag. Predicates carry no closures, so they survive save/load and stay deterministic — the reusable condition seam that event-conditioned rules, quests, perks, and reactive AI gate on instead of hand-rolled callbacks.
1234
- - `PresenceInfo` (interface): interface PresenceInfo — ⚠ undocumented
1270
+ - `PresenceInfo` (interface): interface PresenceInfo { online: boolean; serverId?: string; zoneId?: string; instanceId?: string } — ⚠ undocumented
1235
1271
  - `PriceStats` (interface): interface PriceStats — Aggregated market stats for one item over the retained samples.
1236
- - `QuestDef` (interface): interface QuestDef — ⚠ undocumented
1237
- - `QuestInstance` (interface): interface QuestInstance — ⚠ undocumented
1238
- - `QuestRewards` (interface): interface QuestRewards — ⚠ undocumented
1272
+ - `QuestDef` (interface): interface QuestDef { id: string; title: string; description?: string; giver?: string; turnIn?: string; requires?: string[]; objectives: QuestObjective[]; rewards?: QuestRewards } — ⚠ undocumented · used by `describeTrackedQuest`: Join a quest's static {@link QuestDef} with a player's live {@link QuestInstance} into a flat, renderer-free view a HUD tracker draws (title…
1273
+ - `QuestInstance` (interface): interface QuestInstance { questId: string; status: QuestStatus; objectives: QuestObjectiveProgress[] } — ⚠ undocumented · used by `describeTrackedQuest`: Join a quest's static {@link QuestDef} with a player's live {@link QuestInstance} into a flat, renderer-free view a HUD tracker draws (title…
1274
+ - `QuestRewards` (interface): interface QuestRewards { xp?: {amount: number}; economy?: Record<string, number>; items?: {item: string; count: number; inventory: string}[]; unlocks?: string[]; quests?: string[] } — ⚠ undocumented
1239
1275
  - `RaceState` (class): class RaceState — Race state machine (issue #87). Drive it each tick with `update(now, positions)` — `now` is game time (`ctx.time`), `positions` maps each racer to a world point tested against the ordered checkpoint volumes. It emits `checkpoint.hit` / `lap.completed` / `position.changed` / `race.finished`, keeps cumulative split times for PB deltas, resolves a pluggable win condition (first-past-post, round-cut, derby last-standing), and `resetToCheckpoint` hands back a respawn pose at the racer's last checkpoint. `removeRacer` drops a racer mid-race and `reset` returns the whole instance to its pre-race state for reuse.
1240
1276
  - `RankLeaderboardOptions` (interface): interface RankLeaderboardOptions — Options for {@link rankLeaderboard}. All optional.
1241
1277
  - `RankableRow` (interface): interface RankableRow — A single input score to rank. Accepts the raw shape produced by {@link LeaderboardRow} (a `LeaderboardRow` is assignable to this) as well as a minimal `{ userId, value }` pair with an optional display `label` the game owns.
1242
1278
  - `RankedEntry` (interface): interface RankedEntry — One render-ready row of the ranked table produced by {@link rankLeaderboard}.
1243
- - `RarityStyle` (interface): interface RarityStyle — ⚠ undocumented
1279
+ - `RarityStyle` (interface): interface RarityStyle — Per-rarity look of a dropped item: beam, color and label. Set via `defineGame({ worldItem: { rarityStyle } })`.
1244
1280
  - `RateLimit` (interface): interface RateLimit — Bounded firing budget over a sliding time window.
1245
1281
  - `RebindActionConfig` (interface): interface RebindActionConfig — One rebindable action as declared to {@link createRebindSession}. The `id` and `label` are FREE strings the session never interprets — the game owns their meaning and display text. `defaultCodes` is the authored binding the session resets back to.
1246
1282
  - `RebindConflict` (interface): interface RebindConflict — A group of actions bound to the same normalized code — the conflict this session detects.
@@ -1250,21 +1286,21 @@
1250
1286
  - `RebindSessionConfig` (type): type RebindSessionConfig = RebindSessionActionsConfig | RebindSessionMapConfig — Config for {@link createRebindSession}: an explicit action list, or an {@link ActionCodesMap} + labels.
1251
1287
  - `RebindSessionMapConfig` (interface): interface RebindSessionMapConfig extends RebindSessionCommon — Declare actions from an authored {@link ActionCodesMap}, labelled by `labels` (falling back to the id).
1252
1288
  - `RebindSessionSnapshot` (interface): interface RebindSessionSnapshot — Serializable session state for save/restore.
1253
- - `RecipeDef` (interface): interface RecipeDef — ⚠ undocumented
1254
- - `RecipeItem` (interface): interface RecipeItem — ⚠ undocumented
1289
+ - `RecipeDef` (interface): interface RecipeDef { id: string; inputs: readonly RecipeItem[]; outputs: readonly RecipeItem[]; seconds?: number; station?: string; stationRange?: number; requires?: readonly string[]; category?: string } — ⚠ undocumented
1290
+ - `RecipeItem` (interface): interface RecipeItem { itemId: string; count: number } — ⚠ undocumented
1255
1291
  - `RequireRule` (interface): interface RequireRule — A rule that requires a second condition to hold whenever the first matches — e.g. "a scoped rifle requires a stock". Checked at completeness time, not during incremental placement, because the `then` side may be satisfied by a part chosen later in a generation pass.
1256
1292
  - `ResourceCost` (type): type ResourceCost = Readonly<Record<string, number>> — Resource costs keyed by currency/resource id.
1257
1293
  - `ResourceLedger` (interface): interface ResourceLedger — Fully serializable scheduled-transaction state: clock, balances, rule definitions, and cursors.
1258
1294
  - `ResourcePolicy` (type): type ResourcePolicy = ( txn: ResourceTransaction, ctx: PolicyContext, ) => readonly ResourceTransaction[] — A composable transform over one transaction. Return the transactions to keep: `[]` rejects it, `[txn]` passes/transforms it, and multiple entries split it.
1259
1295
  - `ResourceTransaction` (interface): interface ResourceTransaction — One resource movement produced by a due cycle, before it is applied to balances.
1260
1296
  - `RetainedVfxKind` (type): type RetainedVfxKind = string — The archetype of a retained (long-lived, updatable) VFX effect — an open string, not a closed union, so a renderer registers new kinds (beam, tether, zone, target line, looping emitter) without a central branch. `"beam"` is the first shipped retained renderer.
1261
- - `Ring` (interface): interface Ring — ⚠ undocumented
1262
- - `RingConfig` (interface): interface RingConfig — ⚠ undocumented
1263
- - `RingPhase` (interface): interface RingPhase — ⚠ undocumented
1264
- - `RoleSpec` (interface): interface RoleSpec — ⚠ undocumented
1297
+ - `Ring` (interface): interface Ring { at(time: number): RingSample; isOutside(time: number, position: RingPoint): boolean; distanceOutside(time: number, position: RingPoint): number; damageOutside(time: number, dt: number, positions: Iterable<{id: string; position: RingPoint}… — ⚠ undocumented
1298
+ - `RingConfig` (interface): interface RingConfig { center: RingPoint; phases: readonly RingPhase[] } — ⚠ undocumented
1299
+ - `RingPhase` (interface): interface RingPhase { startTime: number; shrinkDuration: number; fromRadius: number; toRadius: number; damagePerSecond: number; center?: RingPoint } — ⚠ undocumented
1300
+ - `RoleSpec` (interface): interface RoleSpec { id: string; count?: number; ratio?: number } — ⚠ undocumented
1265
1301
  - `Rotation` (type): type Rotation = 0 | 1 | 2 | 3 — ⚠ undocumented
1266
- - `RoundConfig` (interface): interface RoundConfig<TPhase extends string = RoundPhase> — ⚠ undocumented
1267
- - `RoundSnapshot` (interface): interface RoundSnapshot<TPhase extends string = RoundPhase> — ⚠ undocumented
1302
+ - `RoundConfig` (interface): interface RoundConfig<TPhase extends string = RoundPhase> { phases: Record<TPhase, number>; teams: readonly string[] | readonly RoundTeam[]; phaseOrder?: readonly TPhase[]; winCondition?: (state: RoundSnapshot<TPhase>) => string | null; maxRounds?: number; winReward?: number; lossBonus?: LossBonus… — ⚠ undocumented
1303
+ - `RoundSnapshot` (interface): interface RoundSnapshot<TPhase extends string = RoundPhase> { round: number; phase: TPhase; timeLeft: number; scores: Record<string, number>; lossStreaks: Record<string, number>; roles: Record<string, string | undefined>; matchOver: boolean; pendingWinner: string | null } — ⚠ undocumented
1268
1304
  - `RtsCameraConfig` (interface): interface RtsCameraConfig extends TopDownCameraConfig — Free-pan / edge-scroll RTS rig (#24) — pan/rotate/zoom independent of any avatar.
1269
1305
  - `RuleCursor` (interface): interface RuleCursor — Mutable per-rule progress, kept separate from the immutable {@link ScheduledRule} definition.
1270
1306
  - `RuleDef` (interface): interface RuleDef<TPayload = unknown> — A selectable rule over a tagged pool. `tags` classify it for include/exclude filtering and for `requires`/`conflicts` matching (which match either another rule's id or one of its tags). `layers` are the parameter layers this rule contributes when active; `payload` is opaque caller data.
@@ -1274,8 +1310,8 @@
1274
1310
  - `RuleRegistry` (interface): interface RuleRegistry<TPayload = unknown> — Registered pool of {@link RuleDef}s — the install seam games register mutators/modes/events into.
1275
1311
  - `RuleSelection` (interface): interface RuleSelection<TPayload = unknown> — The result of a selection — the chosen rules and their ids (a serializable {@link LayerSelection}-style list).
1276
1312
  - `RuleSelectionConfig` (interface): interface RuleSelectionConfig — Deterministic selection inputs — plain serializable data a host can persist and replay.
1277
- - `RunDraft` (interface): interface RunDraft<TStat extends string = string, TData = unknown> — ⚠ undocumented
1278
- - `RunModifierOffer` (interface): interface RunModifierOffer<TStat extends string = string, TData = unknown> — ⚠ undocumented
1313
+ - `RunDraft` (interface): interface RunDraft<TStat extends string = string, TData = unknown> { present(count: number, rng?: () => number): RunModifierOffer<TStat, TData>[]; choose(offerId: string): boolean; stack(): RunModifierStack<TStat, TData> } — ⚠ undocumented · used by `createRunDraft`: A roguelike run built from stacking drafted modifier picks that reshape the run.
1314
+ - `RunModifierOffer` (interface): interface RunModifierOffer<TStat extends string = string, TData = unknown> { id: string; weight: number; maxStacks?: number; label?: string; stats?: StatModifierSet<TStat>; data?: TData } — ⚠ undocumented
1279
1315
  - `SaleRecord` (interface): interface SaleRecord — One completed sale recorded into a {@link PriceHistory}.
1280
1316
  - `SaveBackend` (interface): interface SaveBackend — The one async storage seam a save store persists through. Every backend satisfies this same three-method shape — the browser's `localStorage` (offline), an in-memory map (tests/SSR), or a database/Convex/HTTP endpoint (cloud) — so a game switches offline saves for cloud saves by swapping the backend and changing nothing else. Keys are opaque namespaced strings; values are already-serialized strings, so a backend never needs to know the save shape.
1281
1317
  - `SaveSlotMeta` (interface): interface SaveSlotMeta — One entry in a {@link SaveSlots} index: a save/profile slot's *display* metadata, not its payload. The real save data lives in a `createSaveStore` slot; this record is only what a save-select menu renders — an id, an optional player-facing `name`, whether the slot is `empty`, when it was last written (`savedAt`), and a free-string `meta` bag the game fills with whatever the menu should show (level, playtime, location, chapter, a thumbnail ref, …). `meta` keys are opaque to this model — it never reads or branches on them.
@@ -1285,7 +1321,7 @@
1285
1321
  - `SaveSlotsSnapshot` (interface): interface SaveSlotsSnapshot — Serializable state of a {@link SaveSlots} index, for save/restore.
1286
1322
  - `SaveStatus` (type): type SaveStatus = "idle" | "loading" | "saving" | "saved" | "error" — Lifecycle of the last save/load — drive a "Saving…"/"Saved" indicator or a loading gate off it. `"error"` means the backend rejected a read or write.
1287
1323
  - `SaveStore` (interface): interface SaveStore<T> — A pluggable-backend game save with autosave, named slots, and versioned migration. `value()`/`patch()` hold the live state; `load()` hydrates it from the backend; `save()` (or autosave) writes it back. Backend failures surface as `"error"` status and through `onError` — a save never throws into a tick.
1288
- - `ScheduledDelivery` (interface): interface ScheduledDelivery — ⚠ undocumented
1324
+ - `ScheduledDelivery` (interface): interface ScheduledDelivery { userId: string; inventoryId: string; items: readonly ItemStack[]; deliverAt: number } — ⚠ undocumented
1289
1325
  - `ScheduledRule` (interface): interface ScheduledRule — A serializable recurring resource flow. Every field is plain JSON so the whole {@link ResourceLedger} round-trips through `structuredClone`/`JSON`. Dynamic, context-aware behaviour (providers, tax curves, affordability caps) lives in the runtime {@link ResourcePolicy} pipeline, never in this data.
1290
1326
  - `SerializedBehaviorState` (type): type SerializedBehaviorState = Record<string, BehaviorState> — A serialized snapshot of every behavior's state on one item, keyed by behavior id. Round-trips through JSON so it can live in a saved game.
1291
1327
  - `SetBonus` (interface): interface SetBonus — A match/set bonus: extra stats granted when enough parts (or a tag) of a given kind are present — e.g. "3 Blackwood parts grant +recoil control". Counting is declarative (`countBy`/`value`) so the whole catalog is data.
@@ -1302,8 +1338,8 @@
1302
1338
  - `ShoulderCameraConfig` (interface): interface ShoulderCameraConfig — Over-the-shoulder combat rig (#25) — offset, ADS, shoulder swap, decoupled reticle.
1303
1339
  - `SideScrollCameraConfig` (interface): interface SideScrollCameraConfig — Fixed lateral 2.5D follow (side-on platformer cam): the camera sits perpendicular to the travel axis, tracks the followed entity, and never reads player look input.
1304
1340
  - `SlotGrid` (type): type SlotGrid<T> = readonly Slot<T>[] — ⚠ undocumented
1305
- - `Social` (interface): interface Social — ⚠ undocumented
1306
- - `SocialDeps` (interface): interface SocialDeps — ⚠ undocumented
1341
+ - `Social` (interface): interface Social { friends: Friends; party: Party; presence: {get(userId: string): PresenceInfo}; emotes: Emotes; worldInvites: WorldInvites; snapshot(): SocialSnapshot; hydrate(data: SocialSnapshot): void } — ⚠ undocumented · used by `createSocial`: Emotes and lightweight social interactions between nearby players.
1342
+ - `SocialDeps` (interface): interface SocialDeps { events: GameEvents; presence?: (userId: string) => PresenceInfo; now?: () => number; emotes?: EmotesDeps; worldInviteTtlMs?: number } — ⚠ undocumented · used by `createSocial`: Emotes and lightweight social interactions between nearby players.
1307
1343
  - `StackPolicy` (type): type StackPolicy = "refresh" | "stack" | "independent" | "ignore" — How a repeated application of the same rule's effect on the same target combines with a live one: `refresh` re-arms the timer at one stack, `stack` adds a stack up to `maxStacks` and re-arms, `independent` keeps each application as its own instance with its own expiry, `ignore` drops the new application while one is already active.
1308
1344
  - `StatContribution` (interface): interface StatContribution — One folded contribution to a value, retained so a sheet can explain "why is this value 42?" — every step carries the source that produced it.
1309
1345
  - `StatContributionStep` (interface): interface StatContributionStep extends StatContribution — One line of a provenance trace: a contribution plus the running total after it folds in.
@@ -1313,7 +1349,7 @@
1313
1349
  - `StatGraph` (interface): interface StatGraph — A compiled, immutable stat-graph schema that mints per-entity {@link StatSheet}s from base values or saved state.
1314
1350
  - `StatGraphDef` (interface): interface StatGraphDef — The full schema of a stat graph: its named inputs and caller-authored derived formulas.
1315
1351
  - `StatInputDef` (interface): interface StatInputDef — A game-owned named input value. The engine ships no attribute vocabulary — ids, bounds, defaults, and metadata are entirely caller data, so the same graph can model STR/AGI/INT, SPECIAL scores, skills, difficulty knobs, or anything else.
1316
- - `StatLevelUpEvent` (interface): interface StatLevelUpEvent — ⚠ undocumented
1352
+ - `StatLevelUpEvent` (interface): interface StatLevelUpEvent { userId: string; stat: string; level: number } — ⚠ undocumented
1317
1353
  - `StatModEntry` (type): type StatModEntry = StatContribution | readonly StatContribution[] — A modifier entry targeting one stat: a single contribution or an ordered list.
1318
1354
  - `StatOp` (type): type StatOp = "add" | "mul" | "override" | "clampMin" | "clampMax" — How a single contribution folds into a running value.
1319
1355
  - `StatSheet` (interface): interface StatSheet — A live per-entity instance of a {@link StatGraph}: mutable base values and modifier sources over a shared schema.
@@ -1324,16 +1360,16 @@
1324
1360
  - `TOUCH_STYLES` (const): const TOUCH_STYLES: readonly TouchStyle[] — Every touch skin id, in menu order.
1325
1361
  - `TOUCH_STYLE_OPTIONS` (const): const TOUCH_STYLE_OPTIONS: readonly { value: TouchStyle; label: string }[] — Touch skins as `{ value, label }` rows for the Settings → Controls selector.
1326
1362
  - `TalentEdgeView` (interface): interface TalentEdgeView — One prerequisite edge into a node — the source node, the rank it demands, and whether that is met.
1327
- - `TalentNodeDef` (interface): interface TalentNodeDef<TStat extends string = string> — ⚠ undocumented
1363
+ - `TalentNodeDef` (interface): interface TalentNodeDef<TStat extends string = string> { id: string; branch?: string; maxRank: number; requires?: readonly TalentRequirement[]; requiresPointsInBranch?: number; modifiersPerRank?: StatModifierSet<TStat>; grantsAbilities?: readonly string[] } — ⚠ undocumented · used by `talentTreeView`: Project the existing talent model (`createTalentTree`) into a flat, serializable render view: every node placed by branch + prerequisite-dep…
1328
1364
  - `TalentNodeState` (type): type TalentNodeState = "locked" | "available" | "learned" | "maxed" — Render state of a talent node, derived from its rank and prerequisite satisfaction. - `locked` — rank 0 and at least one prerequisite unmet; cannot be trained yet. - `available` — rank 0, every prerequisite met; ready to take a first point. - `learned` — at least one rank invested, but below `maxRank`. - `maxed` — fully invested (`rank === maxRank`).
1329
1365
  - `TalentNodeStatus` (interface): interface TalentNodeStatus — Per-node status a game supplies to build a view from *any* unlock rule — not just point-spend. A game computes these from whatever it wants (a currency threshold, a level, a quest flag, a skill-point pool, nothing at all) so the same widget renders a buy-with-points talent tree, a money-gated upgrade tree, or a condition-unlocked ability web without changing the renderer.
1330
1366
  - `TalentNodeView` (interface): interface TalentNodeView — A per-node view for rendering: grid placement (tier/branch), rank, state, and inbound prerequisite edges.
1331
1367
  - `TalentPointTotals` (interface): interface TalentPointTotals — Optional overall point totals for the view header; omit (or 0) for trees that spend no point currency.
1332
- - `TalentTree` (interface): interface TalentTree<TStat extends string = string> — ⚠ undocumented
1368
+ - `TalentTree` (interface): interface TalentTree<TStat extends string = string> { rank(nodeId: string): number; pointsAvailable(): number; pointsSpent(): number; pointsInBranch(branch: string): number; grantPoints(amount: number): void; canAllocate(nodeId: string): TalentAllocateResult; allocate(nodeId: string): Talent… — ⚠ undocumented · used by `talentTreeView`: Project the existing talent model (`createTalentTree`) into a flat, serializable render view: every node placed by branch + prerequisite-dep…
1333
1369
  - `TalentTreeView` (interface): interface TalentTreeView — A whole-tree render view: placed nodes plus branch/tier extents and point totals.
1334
1370
  - `TargetRole` (type): type TargetRole = "subject" | "object" | "source" | "owner" — Role slots an event exposes; a target selector resolves one of these to a concrete id.
1335
1371
  - `TargetSelector` (type): type TargetSelector = | { readonly role: TargetRole } | { readonly path: string } | { readonly literal: string } — How a rule picks the id its effect lands on: a fixed event role, a dot path into the event facts, or a literal id. Data-only so it saves with the rule.
1336
- - `TechNodeDef` (interface): interface TechNodeDef extends UnlockDef — ⚠ undocumented
1372
+ - `TechNodeDef` (interface): interface TechNodeDef extends UnlockDef { requires?: readonly string[]; cost?: Readonly<Record<string, number>>; grants?: readonly string[]; recipe?: string } — ⚠ undocumented
1337
1373
  - `ThresholdBand` (interface): interface ThresholdBand — A `{ min, factor }` band for {@link thresholdScale}; the highest band whose `min` is met wins.
1338
1374
  - `ThresholdBoundary` (interface): interface ThresholdBoundary<Id = string> — A labelled cut point on the value axis. `Id` is caller-owned (string, enum, or a policy object).
1339
1375
  - `ThresholdCrossing` (interface): interface ThresholdCrossing<Id = string> — A single boundary transition between a `before` and `after` value.
@@ -1344,12 +1380,12 @@
1344
1380
  - `Toast` (interface): interface Toast<T = string> — A transient HUD message that expires on its own — banner, pickup note, alert.
1345
1381
  - `TopDownCameraConfig` (interface): interface TopDownCameraConfig — Fixed top-down / isometric rig (#23) — height/pitch/yaw + decoupled follow.
1346
1382
  - `TouchAnchor` (type): type TouchAnchor = | "bottom-left" | "bottom-center" | "bottom-right" | "left" | "right" | "top-left" | "top-center" | "top-right" — Screen zone a touch cluster or button docks to. The four corners plus the mid `left`/`right` rails (vertical stacks, MMO-style hotbars) and the `bottom-center` / `top-center` strips let controls use the whole viewport instead of piling into one bottom bar.
1347
- - `TouchButton` (interface): interface TouchButton — ⚠ undocumented
1383
+ - `TouchButton` (interface): interface TouchButton { action: string; label: string; icon: string | false | null; kind: TouchButtonKind; shape: TouchButtonShape; anchor: TouchAnchor | null; image: string | null } — ⚠ undocumented
1348
1384
  - `TouchButtonShape` (type): type TouchButtonShape = "circle" | "square" | "pedal" | "lever" | "trigger" | "wheel" | "tab" — Physical silhouette a touch button wears. The capture layer draws each as its own shape — a `pedal` reads as a foot pedal, a `lever` as a pull handle, a `trigger` as a firing paddle — so a control looks like the thing it does instead of a labelled circle. `circle`/`square` are the neutral fallbacks.
1349
1385
  - `TouchControlsConfig` (interface): interface TouchControlsConfig — Game-authored refinement of the derived touch scheme on `defineGame({ touch })` — gestures, curated buttons, hidden actions, cluster layout, skin, and per-context `modes`.
1350
1386
  - `TouchControlsModeConfig` (type): type TouchControlsModeConfig = Omit<TouchControlsConfig, "modes"> — One named control context's touch config — the same shape as the base config, minus nested modes.
1351
- - `TouchJoystick` (interface): interface TouchJoystick — ⚠ undocumented
1352
- - `TouchScheme` (interface): interface TouchScheme — ⚠ undocumented
1387
+ - `TouchJoystick` (interface): interface TouchJoystick { up: string | null; down: string | null; left: string | null; right: string | null } — ⚠ undocumented
1388
+ - `TouchScheme` (interface): interface TouchScheme { joystick: TouchJoystick | null; buttons: readonly TouchButton[]; gestures: TouchGestureBindings | null; look: boolean; lookSensitivity: number; layout: ResolvedTouchLayout; style: TouchStyle } — ⚠ undocumented · used by `deriveTouchScheme`: Null means "render no touch controls" — either the game opted out or there is nothing to synthesize.
1353
1389
  - `TouchStyle` (type): type TouchStyle = "glass" | "arcade" | "mechanical" | "minimal" — Player-selectable skin for the whole touch layer. A style is a material + geometry preset (not just colours), chosen in Settings → Controls and persisted; `glass` is the translucent default, the rest are opt-in looks.
1354
1390
  - `TrackedObjectiveView` (interface): interface TrackedObjectiveView — One objective as a tracker/HUD reads it — label + progress toward its count.
1355
1391
  - `TrackedQuestView` (interface): interface TrackedQuestView — A quest as a tracker/HUD reads it — title, status, and per-objective progress.
@@ -1358,12 +1394,12 @@
1358
1394
  - `TriggeredRule` (interface): interface TriggeredRule — A declarative subscription from an event to an effect. Everything here is serializable content — the runtime reads it, it never embeds behavior. `effect` names an effect the game resolves; core only routes and gates.
1359
1395
  - `TriggeredRuleEngine` (interface): interface TriggeredRuleEngine — A running set of triggered rules with gating, timed lifetimes, stacking, cleanup, and save/load.
1360
1396
  - `TriggeredRuleState` (interface): interface TriggeredRuleState — Serializable runtime state — everything that changes future triggers. Rules travel with it.
1361
- - `TurnLoop` (interface): interface TurnLoop<TAction = unknown> — ⚠ undocumented
1397
+ - `TurnLoop` (interface): interface TurnLoop<TAction = unknown> { readonly commit: CommitController<TAction>; state(): TurnState; order(): readonly string[]; active(): string | null; phase(): string | null; round(): number; setOrder(order: readonly string[], keepActive?: boolean): TurnState; addParticip… — ⚠ undocumented
1362
1398
  - `UnitReservation` (interface): interface UnitReservation — Reservation stored on a training job — the inputs to charge and refund.
1363
1399
  - `UnitSpawnOrder` (interface): interface UnitSpawnOrder — Completion payload: everything a spawn/rally adapter needs, and nothing it doesn't.
1364
1400
  - `UnitTrainingOptions` (interface): interface UnitTrainingOptions — Config knobs for {@link unitTrainingConfig}.
1365
1401
  - `UnitTrainingSpec` (interface): interface UnitTrainingSpec — What the caller asks the queue to build.
1366
- - `UnlockDef` (interface): interface UnlockDef — ⚠ undocumented
1402
+ - `UnlockDef` (interface): interface UnlockDef { id: string; category?: string } — ⚠ undocumented · used by `createUnlockCatalog`: A catalog of unlockable content gated behind conditions the player earns, tracking what is unlocked.
1367
1403
  - `UseBehaviorContext` (interface): interface UseBehaviorContext<TWorld> — The context handed to each behavior hook: the shared folded `world`, this behavior's own `config` and `state` slice, and the triggering use input.
1368
1404
  - `UseBehaviorDef` (interface): interface UseBehaviorDef<TWorld> — A registered behavior implementation. The combat/game side registers these (charge, thrown-reload, projectile-replacement, …); the item core only ever stores a {@link UseBehaviorRef} to one by id. Hooks are the lifecycle: `init` builds serializable state, `can` gates, `apply` folds the world.
1369
1405
  - `UseBehaviorOutcome` (interface): interface UseBehaviorOutcome<TWorld> — The result of applying one behavior: the (possibly advanced) world, this behavior's updated state, an optional error that aborts the chain, and an optional `stop` that ends the chain after a successful apply.
@@ -1382,10 +1418,10 @@
1382
1418
  - `WorkQueueConfig` (interface): interface WorkQueueConfig<TSpec, TReserve = undefined, TOutput = undefined> — Injected policy for a queue. Never serialized — pass the same config to every {@link enqueue}/{@link tick}/{@link cancelJob} call for a given queue.
1383
1419
  - `WorkQueueEvent` (type): type WorkQueueEvent<TSpec, TReserve = undefined, TOutput = undefined> = | { readonly type: "started"; readonly job: Job<TSpec, TReserve> } | { readonly type: "completed"; readonly job: Job<TSpec, TReserve>; readonly output: TOutput } — Typed lifecycle event emitted from {@link tick}.
1384
1420
  - `WorkQueueState` (interface): interface WorkQueueState<TSpec, TReserve = undefined> — Serializable queue state. Holds only non-terminal jobs, so it stays bounded.
1385
- - `WorldInvite` (interface): interface WorldInvite extends WorldInviteTarget — ⚠ undocumented
1386
- - `WorldInviteTarget` (interface): interface WorldInviteTarget — ⚠ undocumented
1387
- - `WorldItemRecord` (interface): interface WorldItemRecord — ⚠ undocumented
1388
- - `WorldItemRenderConfig` (interface): interface WorldItemRenderConfig — ⚠ undocumented
1421
+ - `WorldInvite` (interface): interface WorldInvite extends WorldInviteTarget { id: string; fromUserId: string; toUserId: string; createdAt: number } — ⚠ undocumented
1422
+ - `WorldInviteTarget` (interface): interface WorldInviteTarget { serverId: string; joinCode?: string } — ⚠ undocumented
1423
+ - `WorldItemRecord` (interface): interface WorldItemRecord { instanceId: string; itemId: string; rarity: string; baseType: string; count: number; affixTier?: number; source?: string; droppedAt: number } — ⚠ undocumented · used by `useNearestWorldItem` (@jgengine/react): Nearest ground item within `radius` of the local player — drives a pickup prompt/highlight.
1424
+ - `WorldItemRenderConfig` (interface): interface WorldItemRenderConfig { rarityStyle?: Record<string, RarityStyle>; filter?: readonly LootFilterRule[]; pickupRadius?: number; beamHeight?: number; autoPickup?: boolean | {radius?: number} } — ⚠ undocumented · used by `WorldItems` (@jgengine/shell/world/WorldItems): Rarity→beam/color/label render binding + loot-filter overlay (#32/#33) for every dropped `worldItem`.
1389
1425
  - `WorldOverlayProps` (interface): interface WorldOverlayProps — Props handed to a `WorldOverlay` component (#542): explicit `ctx` access so canvas-layer VFX read live engine state directly, without an extra hook or a module-global workaround.
1390
1426
  - `activeJobs` (function): function activeJobs<TSpec, TReserve>(state: WorkQueueState<TSpec, TReserve>): Job<TSpec, TReserve>[] — Jobs currently progressing.
1391
1427
  - `activeSetBonuses` (function): function activeSetBonuses(identity: ItemIdentity, bonuses: readonly SetBonus[]): SetBonus[] — Select the set bonuses whose membership count meets their threshold, in the order they were declared.
@@ -1401,7 +1437,7 @@
1401
1437
  - `applyBindingOverrides` (function): function applyBindingOverrides<TAction extends string, TCode extends string>(input: ActionCodesMap<TAction, TCode>, overrides: BindingOverrides): ActionCodesMap<TAction, TCode> — Merge player rebinds over a game's authored `input` map. Only actions the game already declares can be overridden; unknown override keys are ignored so a stale localStorage entry can't inject phantom actions.
1402
1438
  - `applySetBonuses` (function): function applySetBonuses(stats: Record<string, number>, bonuses: readonly SetBonus[]): Record<string, number> — Fold a set of active bonuses' additive stats onto a stat map, returning a new map (the input is not mutated).
1403
1439
  - `applyWear` (function): function applyWear(state: DurabilityState, amount: number): DurabilityState — Apply wear to an item, tracking breakage and repair eligibility.
1404
- - `balance` (function): function balance(state: WalletState, currency: string): number — ⚠ undocumented
1440
+ - `balance` (function): function balance(state: WalletState, currency: string | CurrencyDefinition): number — ⚠ undocumented
1405
1441
  - `balanceOf` (function): function balanceOf(ledger: ResourceLedger, account: string, currency: string): number — Read a single balance; unknown account/currency pairs read as `0`.
1406
1442
  - `canAfford` (function): function canAfford(state: WalletState, costs: Readonly<Record<string, number>>): boolean — True when every currency in `costs` has at least that much balance (a pure, non-mutating check).
1407
1443
  - `canCraft` (function): function canCraft(state: InventoryState, layout: InventoryLayout, traits: ItemTraits, recipe: RecipeDef, context: CraftContext = {}): CraftCheck — ⚠ undocumented
@@ -1410,7 +1446,7 @@
1410
1446
  - `candidateViolatesForbid` (function): function candidateViolatesForbid(partial: ItemIdentity, candidate: CandidatePlacement, rules: readonly CompatibilityRule[]): ForbidRule | null — The generic backtracking contract for procedural generation (see #908): given a partial identity and a candidate part, return the first forbid rule the placement would violate, or null if it stays viable. Require rules are ignored here because they may still be satisfied by a later placement.
1411
1447
  - `capAmount` (function): function capAmount(max: number | ((ctx: PolicyContext) => number)): ResourcePolicy — Clamp a transaction's amount to at most `max` (a fixed number or a function of context).
1412
1448
  - `captureProvenance` (function): function captureProvenance(identity: ItemIdentity, activeBonuses: readonly SetBonus[], seed?: number): ItemProvenance — Capture the provenance of a generated item — family, tags, per-slot parts, active bonus ids, and optional seed — as a JSON-safe record.
1413
- - `charge` (function): function charge(state: WalletState, currency: string, amount: number, options?: ChargeOptions): ChargeResult — Deduct `amount`, rejecting when it would leave the balance negative unless `options.overdraft` opts into carrying debt (`true` unlimited, `{ max }` capped) — the strict same-tick affordability check stays the default with `options` omitted.
1449
+ - `charge` (function): function charge(state: WalletState, currency: string | CurrencyDefinition, amount: number, options?: ChargeOptions): ChargeResult — Deduct `amount`, rejecting when it would leave the balance negative unless `options.overdraft` opts into carrying debt (`true` unlimited, `{ max }` capped) — the strict same-tick affordability check stays the default with `options` omitted.
1414
1450
  - `chargeAll` (function): function chargeAll(state: WalletState, costs: Readonly<Record<string, number>>, options?: ChargeOptions): ChargeResult — ⚠ undocumented
1415
1451
  - `clampValue` (function): function clampValue(value: number, bounds?: NumericBounds): number — Clamp a scalar to `bounds` (identity when `bounds` is omitted). Pure — touches no record.
1416
1452
  - `clearBindingOverride` (function): function clearBindingOverride(gameId: string, action: string, storage: Pick<WebStorageLike, "getItem" | "setItem" | "removeItem"> | null | undefined = defaultStorage()): BindingOverrides — ⚠ undocumented
@@ -1421,7 +1457,7 @@
1421
1457
  - `craft` (function): function craft(state: InventoryState, layout: InventoryLayout, traits: ItemTraits, recipe: RecipeDef, context: CraftContext = {}): CraftResult — ⚠ undocumented
1422
1458
  - `craftSeconds` (function): function craftSeconds(recipe: RecipeDef): number — ⚠ undocumented
1423
1459
  - `createAchievementTracker` (function): function createAchievementTracker(options: AchievementTrackerOptions): AchievementTracker — Tracks achievement/trophy unlocks over caller-driven events — counter goals (`progress`/`setProgress`) and boolean flags (`unlock`) — with score, completion, an `onUnlock` seam, and serializable `snapshot`/`restore`. State is plain data; the view list keeps a stable identity between changes so React can read it through `useSyncExternalStore` without re-projecting every frame.
1424
- - `createAffixRoller` (function): function createAffixRoller(config: RollerConfig): AffixRoller — ⚠ undocumented
1460
+ - `createAffixRoller` (function): function createAffixRoller(config: RollerConfig): AffixRoller — Rolls randomized gear from a base item: a weighted rarity tier scales base stats and picks prefix/suffix affixes that name and modify the item. Deterministic for a given `rng`.
1425
1461
  - `createAuctionBook` (function): function createAuctionBook(config: AuctionBookConfig): AuctionBook — Timed-bid auctions in the WoW/BDO auction-house mold: post an item with a start price, minimum increment, and optional buyout; bids escrow currency, outbid players are refunded into their collection box, bids near the close extend it (anti-snipe), and settlement pays the seller minus the house cut while the item lands in the winner's collection box. Unsold auctions return the goods to the seller's box. Wallet and inventory movement is the caller's job (mirrors `economy/listingBook`) — this primitive owns the auction lifecycle and the escrowed collection-box bookkeeping behind it.
1426
1462
  - `createBehaviourWorld` (function): function createBehaviourWorld(): BehaviourWorld — ⚠ undocumented
1427
1463
  - `createCardPile` (function): function createCardPile(config: CardPileConfig, initial?: Partial<Record<ZoneName, readonly string[]>>): CardPile — ⚠ undocumented
@@ -1519,7 +1555,7 @@
1519
1555
  - `generate` (function): function generate(schema: GenSchema, rng: () => number, options: GenerateOptions = {}): GenOutcome — Run a caller-defined {@link GenSchema} against an injected `rng` into a deterministic, serializable {@link GenResult} with full provenance. Composes weighted/uniform choice, dependent choice, constraints with bounded backtracking, field transforms, and validation reroll over plain data — the generic seam procedural loot, affix, and modular-part rollers assemble on. Identical schema, seed, and pins reproduce an identical result across server/client and save/load.
1520
1556
  - `getRuleEffect` (function): function getRuleEffect(id: string): RuleEffectDefinition | undefined — Look up a declared rule effect, or `undefined` when the id was never registered — lets callers reject unknown effect references in authored content.
1521
1557
  - `getValue` (function): function getValue(record: Record<string, number>, key: string, fallback = 0): number — Current value for `key`, or `fallback` (default `0`) when the record has no entry.
1522
- - `grant` (function): function grant(state: WalletState, currency: string, amount: number): WalletState — ⚠ undocumented
1558
+ - `grant` (function): function grant(state: WalletState, currency: string | CurrencyDefinition, amount: number): WalletState — ⚠ undocumented
1523
1559
  - `identityOf` (function): function identityOf(family: string, tags: readonly string[], parts: readonly InstalledPart[]): ItemIdentity — Assemble an {@link ItemIdentity} from a family, tags, and installed parts.
1524
1560
  - `idleRaceSession` (function): function idleRaceSession(): RaceSessionState — The pre-race session on the grid: `idle`, both clocks at zero. Call {@link startRaceCountdown} to light the lights, or hold here until the field is ready.
1525
1561
  - `initDecayMeters` (function): function initDecayMeters(defs: readonly DecayMeterConfig[]): DecayMeterValues — Starting values for `defs` — each meter's `start ?? max`, clamped to its range. Seed a serialized state record with this instead of holding a {@link createDecayMeterSet} closure.
@@ -1528,7 +1564,7 @@
1528
1564
  - `isComplete` (function): function isComplete(def: ModularItemDef, installed: readonly InstalledPart[]): boolean — ⚠ undocumented
1529
1565
  - `isDisabled` (function): function isDisabled(spec: DurabilitySpec, state: DurabilityState): boolean — ⚠ undocumented
1530
1566
  - `isIdentityValid` (function): function isIdentityValid(identity: ItemIdentity, rules: readonly CompatibilityRule[]): boolean — Convenience predicate: true when {@link validateIdentity} finds no violations.
1531
- - `isOverdrawn` (function): function isOverdrawn(state: WalletState, currency: string): boolean — True once `balance(state, currency)` has gone negative under an overdraft-enabled charge.
1567
+ - `isOverdrawn` (function): function isOverdrawn(state: WalletState, currency: string | CurrencyDefinition): boolean — True once `balance(state, currency)` has gone negative under an overdraft-enabled charge.
1532
1568
  - `jobById` (function): function jobById<TSpec, TReserve>(state: WorkQueueState<TSpec, TReserve>, id: JobId): Job<TSpec, TReserve> | null — Look up a job by id, or `null` if absent/terminal.
1533
1569
  - `jobProgress` (function): function jobProgress<TSpec, TReserve>(job: Job<TSpec, TReserve>): number — Fractional progress of a job (0…1); a zero-duration job reads as complete.
1534
1570
  - `lapDurations` (function): function lapDurations(splits: readonly number[], gatesPerLap: number): number[] — Per-lap durations from a cumulative split book with `gatesPerLap` checkpoints per lap — each lap's time is its finish-gate split minus the previous lap's finish. Only complete laps are returned.
@@ -1585,7 +1621,7 @@
1585
1621
  - `ringSampleAt` (function): function ringSampleAt(config: RingConfig, time: number): RingSample — ⚠ undocumented
1586
1622
  - `runPipeline` (function): function runPipeline<V>(base: V, modifiers: readonly Modifier<V>[], equals: (a: V, b: V) => boolean = Object.is): PipelineResult<V> — ⚠ undocumented
1587
1623
  - `saveBindingOverride` (function): function saveBindingOverride(gameId: string, action: string, codes: ActionCodes, storage: Pick<WebStorageLike, "getItem" | "setItem" | "removeItem"> | null | undefined = defaultStorage()): BindingOverrides — ⚠ undocumented
1588
- - `seededRng` (function): function seededRng(seed: string | number): () => number — Deterministic pseudo-random generator seeded from a string or number — same seed, same sequence.
1624
+ - `seededRng` (function): function seededRng(seed: string | number): SeededRng — Deterministic pseudo-random generator seeded from a string or number — same seed, same sequence.
1589
1625
  - `seededStreams` (function): function seededStreams(seed: string | number): (stream: string) => () => number — Derives independent, deterministic {@link seededRng} streams from one base seed, keyed by stream name.
1590
1626
  - `selectDialogueView` (function): function selectDialogueView(graph: DialogueGraph, nodeId: string): DialogueGraphView | null — Project a {@link DialogueGraph} node id to its render-ready {@link DialogueGraphView} — the pure "current view" selector a stateless renderer reads (speaker, line, choices, done). Returns `null` when the id is not in the graph. No traversal or mutation.
1591
1627
  - `selectRules` (function): function selectRules<TPayload = unknown>(pool: readonly RuleDef<TPayload>[], config: RuleSelectionConfig): RuleSelection<TPayload> — Select up to `count` rules from `pool` deterministically from `config.seed`. Locked ids are placed first (in order), then remaining slots are filled by weighted draw from tag-filtered, still-eligible candidates, honoring `requires`/`conflicts` after each pick. Each slot draws from an independent seed stream keyed by slot index, so a later slot's outcome never shifts an earlier one. Selection stops early when no compatible candidate remains. Pure given `pool` + `config`.
@@ -1631,15 +1667,15 @@
1631
1667
 
1632
1668
  ## @jgengine/core/inventory/inventoryModel
1633
1669
 
1634
- - `InventoryLayout` (interface): interface InventoryLayout — ⚠ undocumented
1635
- - `InventorySet` (interface): interface InventorySet<TId extends string> — ⚠ undocumented
1670
+ - `InventoryLayout` (interface): interface InventoryLayout { slots: number; accepts?: string | readonly string[] } — ⚠ undocumented · used by `createEmptyInventory`: A bag of stackable items supporting add, remove, count, and move — the base inventory model.
1671
+ - `InventorySet` (interface): interface InventorySet<TId extends string> { put(id: TId, itemId: string, count: number, options?: {slot?: number}): PutResult; take(id: TId, itemId: string, count: number): TakeResult; move(fromId: TId, fromSlot: number, toId: TId, toSlot?: number): MoveResult; count(id: TId, itemI… — ⚠ undocumented · used by `createInventorySet`: Build a keyed set of named inventories from their `layouts`, sharing one `traits` table — the stateful façade over put/take/move/count.
1636
1672
  - `InventorySlot` (type): type InventorySlot = { itemId: string; count: number } | null — ⚠ undocumented
1637
- - `InventoryState` (interface): interface InventoryState — ⚠ undocumented
1638
- - `ItemTraits` (interface): interface ItemTraits — ⚠ undocumented
1639
- - `MoveResult` (type): type MoveResult = | { status: "ok"; from: InventoryState; to: InventoryState } | { status: "rejected"; reason: "invalid-slot" | "empty-slot" | "wrong-kind" | "no-space" } — ⚠ undocumented
1640
- - `PutResult` (type): type PutResult = | { status: "ok"; state: InventoryState } | { status: "rejected"; reason: "no-space" | "wrong-kind" | "slot-occupied" | "invalid-slot" } — ⚠ undocumented
1673
+ - `InventoryState` (interface): interface InventoryState { slots: InventorySlot[] } — ⚠ undocumented · used by `countItem`: Total quantity of `itemId` summed across every stack in the inventory.
1674
+ - `ItemTraits` (interface): interface ItemTraits { stackLimit(itemId: string): number; kind?(itemId: string): string | null } — ⚠ undocumented · used by `createInventorySet`: Build a keyed set of named inventories from their `layouts`, sharing one `traits` table — the stateful façade over put/take/move/count.
1675
+ - `MoveResult` (type): type MoveResult = | { status: "ok"; from: InventoryState; to: InventoryState } | { status: "rejected"; reason: "invalid-slot" | "empty-slot" | "wrong-kind" | "no-space" } — ⚠ undocumented · used by `moveItem`: Move the stack at `fromSlot` to `toSlot` (or auto-stack when omitted) — swapping, merging with remainder, or relocating across two inventori…
1676
+ - `PutResult` (type): type PutResult = | { status: "ok"; state: InventoryState } | { status: "rejected"; reason: "no-space" | "wrong-kind" | "slot-occupied" | "invalid-slot" } — ⚠ undocumented · used by `putItem`: Add `count` of `itemId` — into a specific `options.slot`, or auto-stacked across free/partial slots.
1641
1677
  - `SplitResult` (type): type SplitResult = | { status: "ok"; state: InventoryState } | { status: "rejected"; reason: "invalid-slot" | "empty-slot" | "invalid-amount" | "no-space" | "slot-occupied" } — Outcome of {@link splitStack}: the new state, or a rejection reason.
1642
- - `TakeResult` (type): type TakeResult = { status: "ok"; state: InventoryState } | { status: "rejected"; reason: "insufficient" } — ⚠ undocumented
1678
+ - `TakeResult` (type): type TakeResult = { status: "ok"; state: InventoryState } | { status: "rejected"; reason: "insufficient" } — ⚠ undocumented · used by `takeItem`: Remove `count` of `itemId`, draining from the last matching stacks first.
1643
1679
  - `countItem` (function): function countItem(state: InventoryState, itemId: string): number — Total quantity of `itemId` summed across every stack in the inventory.
1644
1680
  - `createEmptyInventory` (function): function createEmptyInventory(layout: InventoryLayout): InventoryState — A bag of stackable items supporting add, remove, count, and move — the base inventory model.
1645
1681
  - `createInventorySet` (function): function createInventorySet<TId extends string>(layouts: Record<TId, InventoryLayout>, traits: ItemTraits): InventorySet<TId> — Build a keyed set of named inventories from their `layouts`, sharing one `traits` table — the stateful façade over put/take/move/count.
@@ -1652,14 +1688,14 @@
1652
1688
  ## @jgengine/core/inventory/shapedGrid
1653
1689
 
1654
1690
  - `Cell` (type): type Cell = readonly [number, number] — ⚠ undocumented
1655
- - `Footprint` (type): type Footprint = readonly Cell[] — ⚠ undocumented
1656
- - `GridAdjacencyQuery` (interface): interface GridAdjacencyQuery — ⚠ undocumented
1657
- - `Placement` (interface): interface Placement<T> — ⚠ undocumented
1691
+ - `Footprint` (type): type Footprint = readonly Cell[] — ⚠ undocumented · used by `rotatedFootprint` (@jgengine/core/scene/assetSpace): The axis-aligned footprint extent after rotating a rectangular {@link Footprint} by `headingDegrees` — footprint-aware placement: a 90-degre…
1692
+ - `GridAdjacencyQuery` (interface): interface GridAdjacencyQuery { cellsOf(id: string): readonly Cell[]; neighborsOf(id: string): readonly string[]; touching(idA: string, idB: string): boolean; adjacentCells(cells: readonly Cell[]): readonly Cell[] } — ⚠ undocumented
1693
+ - `Placement` (interface): interface Placement<T> { id: string; value: T; footprint: Footprint; origin: Cell; rotation: Rotation } — ⚠ undocumented
1658
1694
  - `Rotation` (type): type Rotation = 0 | 1 | 2 | 3 — ⚠ undocumented
1659
- - `ShapedGrid` (interface): interface ShapedGrid<T> — ⚠ undocumented
1660
- - `ShapedItem` (interface): interface ShapedItem<T> — ⚠ undocumented
1661
- - `ShapedPlaceResult` (interface): interface ShapedPlaceResult<T> — ⚠ undocumented
1662
- - `ShapedRejected` (interface): interface ShapedRejected — ⚠ undocumented
1695
+ - `ShapedGrid` (interface): interface ShapedGrid<T> { readonly width: number; readonly height: number; readonly placements: readonly Placement<T>[] } — ⚠ undocumented
1696
+ - `ShapedItem` (interface): interface ShapedItem<T> { id: string; value: T; footprint: Footprint } — ⚠ undocumented
1697
+ - `ShapedPlaceResult` (interface): interface ShapedPlaceResult<T> { status: "ok"; grid: ShapedGrid<T> } — ⚠ undocumented
1698
+ - `ShapedRejected` (interface): interface ShapedRejected { status: "rejected"; reason: ShapedRejection; detail?: string } — ⚠ undocumented
1663
1699
  - `ShapedRejection` (type): type ShapedRejection = "out-of-bounds" | "overlap" | "duplicate-id" | "unknown-id" — ⚠ undocumented
1664
1700
  - `ShapedResult` (type): type ShapedResult<T> = ShapedPlaceResult<T> | ShapedRejected — ⚠ undocumented
1665
1701
 
@@ -1671,14 +1707,14 @@
1671
1707
 
1672
1708
  ## @jgengine/core/inventory/storageTier
1673
1709
 
1674
- - `ConsolationPolicy` (interface): interface ConsolationPolicy — ⚠ undocumented
1675
- - `ContainerSnapshot` (interface): interface ContainerSnapshot — ⚠ undocumented
1676
- - `DeathPartition` (interface): interface DeathPartition — ⚠ undocumented
1677
- - `DeliveryEntry` (interface): interface DeliveryEntry — ⚠ undocumented
1678
- - `DeliveryQueue` (interface): interface DeliveryQueue — ⚠ undocumented
1679
- - `InsurancePolicy` (interface): interface InsurancePolicy — ⚠ undocumented
1680
- - `ItemStack` (interface): interface ItemStack — ⚠ undocumented
1681
- - `ScheduledDelivery` (interface): interface ScheduledDelivery — ⚠ undocumented
1710
+ - `ConsolationPolicy` (interface): interface ConsolationPolicy { loadoutId: string; when?: "always" | "if-carried-empty" } — ⚠ undocumented
1711
+ - `ContainerSnapshot` (interface): interface ContainerSnapshot { inventoryId: string; tier: StorageTier; items: readonly ItemStack[] } — ⚠ undocumented
1712
+ - `DeathPartition` (interface): interface DeathPartition { kept: readonly ItemStack[]; lost: readonly ItemStack[] } — ⚠ undocumented
1713
+ - `DeliveryEntry` (interface): interface DeliveryEntry { id: string; userId: string; inventoryId: string; items: readonly ItemStack[]; deliverAt: number } — ⚠ undocumented
1714
+ - `DeliveryQueue` (interface): interface DeliveryQueue { schedule(entry: ScheduledDelivery & {id?: string}): DeliveryEntry; due(now: number): readonly DeliveryEntry[]; claimDue(now: number): readonly DeliveryEntry[]; pending(userId?: string): readonly DeliveryEntry[]; cancel(id: string): boolea… — ⚠ undocumented
1715
+ - `InsurancePolicy` (interface): interface InsurancePolicy { isInsured(itemId: string): boolean; returnInventoryId: string; delaySeconds: number | [number, number] } — ⚠ undocumented
1716
+ - `ItemStack` (interface): interface ItemStack { itemId: string; count: number } — ⚠ undocumented
1717
+ - `ScheduledDelivery` (interface): interface ScheduledDelivery { userId: string; inventoryId: string; items: readonly ItemStack[]; deliverAt: number } — ⚠ undocumented
1682
1718
  - `StorageTier` (type): type StorageTier = "carried" | "banked" — ⚠ undocumented
1683
1719
  - `createDeliveryQueue` (function): function createDeliveryQueue(): DeliveryQueue — ⚠ undocumented
1684
1720
  - `insureLost` (function): function insureLost(lost: readonly ItemStack[], policy: InsurancePolicy, userId: string, now: number, rng?: () => number): ScheduledDelivery | null — ⚠ undocumented
@@ -1688,27 +1724,27 @@
1688
1724
 
1689
1725
  ## @jgengine/core/item/affix
1690
1726
 
1691
- - `AffixDef` (interface): interface AffixDef — ⚠ undocumented
1727
+ - `AffixDef` (interface): interface AffixDef { id: string; stat: string; op?: AffixOp; roll: number | [number, number]; weight: number; namePart?: {position: "prefix" | "suffix"; text: string} } — ⚠ undocumented
1692
1728
  - `AffixOp` (type): type AffixOp = "add" | "mul" — ⚠ undocumented
1693
- - `AffixPool` (interface): interface AffixPool — ⚠ undocumented
1694
- - `AffixRoller` (interface): interface AffixRoller — ⚠ undocumented
1695
- - `ItemBaseDef` (interface): interface ItemBaseDef — ⚠ undocumented
1696
- - `RarityTier` (interface): interface RarityTier — ⚠ undocumented
1697
- - `RolledAffix` (interface): interface RolledAffix — ⚠ undocumented
1698
- - `RolledItem` (interface): interface RolledItem — ⚠ undocumented
1699
- - `RollerConfig` (interface): interface RollerConfig — ⚠ undocumented
1700
- - `createAffixRoller` (function): function createAffixRoller(config: RollerConfig): AffixRoller — ⚠ undocumented
1701
- - `seededRng` (function): function seededRng(seed: string | number): () => number — Deterministic pseudo-random generator seeded from a string or number — same seed, same sequence.
1729
+ - `AffixPool` (interface): interface AffixPool { id: string; affixes: readonly AffixDef[] } — ⚠ undocumented
1730
+ - `AffixRoller` (interface): interface AffixRoller { rollRarity(rng: () => number): RarityTier; roll(base: ItemBaseDef, rarityId: string, rng: () => number): RolledItem; rollRandom(base: ItemBaseDef, rng: () => number): RolledItem } — ⚠ undocumented · used by `createAffixRoller`: Rolls randomized gear from a base item: a weighted rarity tier scales base stats and picks prefix/suffix affixes that name and modify the it…
1731
+ - `ItemBaseDef` (interface): interface ItemBaseDef { id: string; name: string; baseStats: Record<string, number>; pools: readonly string[] } — ⚠ undocumented
1732
+ - `RarityTier` (interface): interface RarityTier { id: string; weight: number; affixCount: number | [number, number]; statScale?: number; namePart?: string; pools?: readonly string[] } — ⚠ undocumented
1733
+ - `RolledAffix` (interface): interface RolledAffix { id: string; stat: string; op: AffixOp; value: number } — ⚠ undocumented
1734
+ - `RolledItem` (interface): interface RolledItem { baseId: string; rarity: string; name: string; affixes: readonly RolledAffix[]; stats: Record<string, number> } — ⚠ undocumented
1735
+ - `RollerConfig` (interface): interface RollerConfig { pools: readonly AffixPool[]; rarities: readonly RarityTier[] } — ⚠ undocumented · used by `createAffixRoller`: Rolls randomized gear from a base item: a weighted rarity tier scales base stats and picks prefix/suffix affixes that name and modify the it…
1736
+ - `createAffixRoller` (function): function createAffixRoller(config: RollerConfig): AffixRoller — Rolls randomized gear from a base item: a weighted rarity tier scales base stats and picks prefix/suffix affixes that name and modify the item. Deterministic for a given `rng`.
1737
+ - `seededRng` (function): function seededRng(seed: string | number): SeededRng — Deterministic pseudo-random generator seeded from a string or number — same seed, same sequence.
1702
1738
 
1703
1739
  ## @jgengine/core/item/durability
1704
1740
 
1705
- - `DurabilitySpec` (interface): interface DurabilitySpec — ⚠ undocumented
1706
- - `DurabilityState` (interface): interface DurabilityState — ⚠ undocumented
1707
- - `DurabilityTracker` (interface): interface DurabilityTracker — ⚠ undocumented
1708
- - `RepairCost` (interface): interface RepairCost — ⚠ undocumented
1709
- - `RepairMaterial` (interface): interface RepairMaterial — ⚠ undocumented
1710
- - `RepairQuote` (interface): interface RepairQuote — ⚠ undocumented
1711
- - `RepairSpec` (interface): interface RepairSpec — ⚠ undocumented
1741
+ - `DurabilitySpec` (interface): interface DurabilitySpec { max: number; wearPerUse?: number; wearPerHit?: number; disableAtZero?: boolean; repair?: RepairSpec } — ⚠ undocumented
1742
+ - `DurabilityState` (interface): interface DurabilityState { current: number; max: number } — ⚠ undocumented · used by `applyWear`: Apply wear to an item, tracking breakage and repair eligibility.
1743
+ - `DurabilityTracker` (interface): interface DurabilityTracker { init(instanceId: string, spec: DurabilitySpec): DurabilityState; get(instanceId: string): DurabilityState | null; set(instanceId: string, state: DurabilityState): void; wear(instanceId: string, spec: DurabilitySpec, kind: WearKind, times?… — ⚠ undocumented
1744
+ - `RepairCost` (interface): interface RepairCost { item: string; count: number } — ⚠ undocumented
1745
+ - `RepairMaterial` (interface): interface RepairMaterial { item: string; perPoint: number } — ⚠ undocumented
1746
+ - `RepairQuote` (interface): interface RepairQuote { materials: readonly RepairCost[]; restored: number; state: DurabilityState } — ⚠ undocumented
1747
+ - `RepairSpec` (interface): interface RepairSpec { materials: readonly RepairMaterial[]; station?: string; qualityLossPerRepair?: number } — ⚠ undocumented
1712
1748
  - `WearKind` (type): type WearKind = "use" | "hit" — ⚠ undocumented
1713
1749
  - `applyWear` (function): function applyWear(state: DurabilityState, amount: number): DurabilityState — Apply wear to an item, tracking breakage and repair eligibility.
1714
1750
  - `canRepairAt` (function): function canRepairAt(spec: DurabilitySpec, stationId?: string): boolean — ⚠ undocumented
@@ -1770,11 +1806,11 @@
1770
1806
  ## @jgengine/core/item/modularItem
1771
1807
 
1772
1808
  - `InstallResult` (type): type InstallResult = | { status: "ok"; installed: readonly InstalledPart[] } | { status: "rejected"; reason: "unknown-slot" | "wrong-category" | "slot-occupied" } — ⚠ undocumented
1773
- - `InstalledPart` (interface): interface InstalledPart — ⚠ undocumented
1774
- - `ModularItem` (interface): interface ModularItem — ⚠ undocumented
1775
- - `ModularItemDef` (interface): interface ModularItemDef — ⚠ undocumented
1776
- - `MountSlotDef` (interface): interface MountSlotDef — ⚠ undocumented
1777
- - `PartDef` (interface): interface PartDef — ⚠ undocumented
1809
+ - `InstalledPart` (interface): interface InstalledPart { slotId: string; part: PartDef } — ⚠ undocumented · used by `identityOf` (@jgengine/core/gameplay): Assemble an {@link ItemIdentity} from a family, tags, and installed parts.
1810
+ - `ModularItem` (interface): interface ModularItem { readonly def: ModularItemDef; parts(): readonly InstalledPart[]; install(slotId: string, part: PartDef): InstallResult; uninstall(slotId: string): readonly InstalledPart[]; partInSlot(slotId: string): PartDef | null; effectiveStats(): Rec… — ⚠ undocumented
1811
+ - `ModularItemDef` (interface): interface ModularItemDef { id: string; baseStats: Record<string, number>; slots: readonly MountSlotDef[] } — ⚠ undocumented
1812
+ - `MountSlotDef` (interface): interface MountSlotDef { id: string; accepts: string | readonly string[]; required?: boolean } — ⚠ undocumented · used by `slotAccepts`: Attach parts into an item's mount slots and resolve the combined stats.
1813
+ - `PartDef` (interface): interface PartDef { id: string; category: string; stats?: Record<string, number>; multipliers?: Record<string, number> } — ⚠ undocumented
1778
1814
  - `computeEffectiveStats` (function): function computeEffectiveStats(def: ModularItemDef, installed: readonly InstalledPart[]): Record<string, number> — ⚠ undocumented
1779
1815
  - `createModularItem` (function): function createModularItem(def: ModularItemDef, initial: readonly InstalledPart[] = []): ModularItem — ⚠ undocumented
1780
1816
  - `install` (function): function install(def: ModularItemDef, installed: readonly InstalledPart[], slotId: string, part: PartDef): InstallResult — ⚠ undocumented
@@ -1787,11 +1823,11 @@
1787
1823
 
1788
1824
  ## @jgengine/core/item/use
1789
1825
 
1790
- - `ItemUse` (interface): interface ItemUse<TState> — ⚠ undocumented
1791
- - `ItemUseHandler` (interface): interface ItemUseHandler<TState> — ⚠ undocumented
1792
- - `ItemUseInput` (interface): interface ItemUseInput — ⚠ undocumented
1793
- - `ItemUseRejection` (interface): interface ItemUseRejection — ⚠ undocumented
1794
- - `ItemUseResult` (interface): interface ItemUseResult<TState> — ⚠ undocumented
1826
+ - `ItemUse` (interface): interface ItemUse<TState> { register(handlers: Record<string, ItemUseHandler<TState>>): void; registered(): string[]; can(state: TState, input: ItemUseInput): ItemUseRejection | null; use(state: TState, input: ItemUseInput): ItemUseResult<TState> } — ⚠ undocumented · used by `createItemUse`: Use or consume items, applying their effects and per-item cooldowns.
1827
+ - `ItemUseHandler` (interface): interface ItemUseHandler<TState> { can?(state: TState, input: ItemUseInput): ItemUseRejection | null; apply(state: TState, input: ItemUseInput): ItemUseResult<TState> } — ⚠ undocumented
1828
+ - `ItemUseInput` (interface): interface ItemUseInput { from: string; itemId: string; inventoryId?: string; aim?: Aim } — ⚠ undocumented
1829
+ - `ItemUseRejection` (interface): interface ItemUseRejection { reason: string } — ⚠ undocumented
1830
+ - `ItemUseResult` (interface): interface ItemUseResult<TState> { state: TState; error?: string } — ⚠ undocumented
1795
1831
  - `createItemUse` (function): function createItemUse<TState>(resolveUse: (itemId: string) => string | null | undefined): ItemUse<TState> — Use or consume items, applying their effects and per-item cooldowns.
1796
1832
 
1797
1833
  ## @jgengine/core/item/useBehavior
@@ -1811,8 +1847,8 @@
1811
1847
 
1812
1848
  ## @jgengine/core/item/weapon
1813
1849
 
1814
- - `WeaponEntry` (interface): interface WeaponEntry — ⚠ undocumented
1815
- - `WeaponStats` (interface): interface WeaponStats — ⚠ undocumented
1850
+ - `WeaponEntry` (interface): interface WeaponEntry { weapon?: Record<string, unknown> } — ⚠ undocumented · used by `createWeaponStats`: Resolve per-weapon stat values — damage, fire rate, spread — for combat math.
1851
+ - `WeaponStats` (interface): interface WeaponStats { getStat(itemId: string, stat: string): number | null } — ⚠ undocumented · used by `createWeaponStats`: Resolve per-weapon stat values — damage, fire rate, spread — for combat math.
1816
1852
  - `createWeaponStats` (function): function createWeaponStats(resolveEntry: (itemId: string) => WeaponEntry | null | undefined): WeaponStats — Resolve per-weapon stat values — damage, fire rate, spread — for combat math.
1817
1853
  - `getWeaponStat` (function): function getWeaponStat(entry: WeaponEntry | null | undefined, stat: string): number | null — ⚠ undocumented
1818
1854
 
@@ -1835,13 +1871,22 @@
1835
1871
 
1836
1872
  ## @jgengine/core/puzzle/cellGrid
1837
1873
 
1838
- - `CellGrid` (interface): interface CellGrid<T> — ⚠ undocumented
1839
- - `CellRun` (interface): interface CellRun<T> — ⚠ undocumented
1874
+ - `CellGrid` (interface): interface CellGrid<T> — 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.
1875
+ - `CellRun` (interface): interface CellRun<T> — A straight line of matching cells found by {@link findRuns}.
1876
+ - `cellAt` (function): function cellAt<T>(grid: CellGrid<T>, x: number, y: number): T | null — The value at `(x, y)`, or `null` when empty or off the board.
1877
+ - `clearRows` (function): function clearRows<T>(grid: CellGrid<T>, rows: readonly number[]): CellGrid<T> — A copy with `rows` removed and the rows above shifted down, refilling empty rows at the top.
1878
+ - `collapseColumns` (function): function collapseColumns<T>(grid: CellGrid<T>): CellGrid<T> — A copy where every column's cells fall to the bottom, keeping their order.
1879
+ - `createCellGrid` (function): function createCellGrid<T>(width: number, height: number): CellGrid<T> — An empty `width` × `height` board. Every helper here returns a new grid, so a store slot can hold it and undo, replay, and save/restore work without copying.
1880
+ - `findRuns` (function): function findRuns<T>(grid: CellGrid<T>, minLength: number, matches: (a: T, b: T) => boolean = (a, b) => a === b): CellRun<T>[] — Horizontal and vertical runs of at least `minLength` cells whose values `matches` (default `===`).
1881
+ - `fullRows` (function): function fullRows<T>(grid: CellGrid<T>): number[] — Indices of rows with no empty cell, top to bottom.
1882
+ - `inGridBounds` (function): function inGridBounds<T>(grid: CellGrid<T>, x: number, y: number): boolean — Whether `(x, y)` lies on the board.
1883
+ - `withCell` (function): function withCell<T>(grid: CellGrid<T>, x: number, y: number, value: T | null): CellGrid<T> — A copy with `(x, y)` set to `value`; off-board writes return the grid unchanged.
1884
+ - `withCells` (function): function withCells<T>(grid: CellGrid<T>, entries: readonly { readonly x: number; readonly y: number; readonly value: T | null }[]): CellGrid<T> — A copy with every in-bounds entry written; one allocation for a whole piece or stamp.
1840
1885
 
1841
1886
  ## @jgengine/core/puzzle/fallingPiece
1842
1887
 
1843
- - `FallingPiece` (interface): interface FallingPiece<TShape extends string = string> — ⚠ undocumented
1844
- - `LockDelayState` (interface): interface LockDelayState — ⚠ undocumented
1888
+ - `FallingPiece` (interface): interface FallingPiece<TShape extends string = string> { readonly shape: TShape; readonly rotation: number; readonly x: number; readonly y: number } — ⚠ undocumented
1889
+ - `LockDelayState` (interface): interface LockDelayState { readonly delaySeconds: number; readonly elapsed: number } — ⚠ undocumented
1845
1890
  - `ShapeTable` (type): type ShapeTable<TShape extends string = string> = Record< TShape, readonly (readonly (readonly [number, number])[])[] > — ⚠ undocumented
1846
1891
 
1847
1892
  ## @jgengine/core/puzzle/nonogram
@@ -1853,9 +1898,9 @@
1853
1898
 
1854
1899
  ## @jgengine/core/random/nameGen
1855
1900
 
1856
- - `NameGenerator` (interface): interface NameGenerator — ⚠ undocumented
1857
- - `NameGeneratorOptions` (interface): interface NameGeneratorOptions — ⚠ undocumented
1858
- - `SyllableBank` (interface): interface SyllableBank — ⚠ undocumented
1901
+ - `NameGenerator` (interface): interface NameGenerator { name(): string } — ⚠ undocumented · used by `createNameGenerator`: Generate procedural names from templates and word banks with an injected random source.
1902
+ - `NameGeneratorOptions` (interface): interface NameGeneratorOptions { rng: () => number; syllables: SyllableBank; minSyllables?: number; maxSyllables?: number; capitalize?: boolean } — ⚠ undocumented · used by `createNameGenerator`: Generate procedural names from templates and word banks with an injected random source.
1903
+ - `SyllableBank` (interface): interface SyllableBank { onset?: readonly string[]; nucleus: readonly string[]; coda?: readonly string[] } — ⚠ undocumented
1859
1904
  - `createNameGenerator` (function): function createNameGenerator(options: NameGeneratorOptions): NameGenerator — Generate procedural names from templates and word banks with an injected random source.
1860
1905
  - `fillTemplate` (function): function fillTemplate(template: string, vars: Record<string, () => string> | Record<string, string>): string — ⚠ undocumented
1861
1906
  - `pickFrom` (function): function pickFrom(rng: () => number, bank: readonly string[]): string — ⚠ undocumented
@@ -1873,9 +1918,12 @@
1873
1918
  ## @jgengine/core/random/rng
1874
1919
 
1875
1920
  - `RandomSeed` (type): type RandomSeed = number & { readonly __randomSeed: unique symbol } — Opaque, serializable PRNG cursor for state machines that must persist their own random stream (a spawn director, a heat/pursuit meter) instead of holding a closure — the state round-trips through save/load and multiplayer sync, so it can't carry a function. Never read or do arithmetic on the raw value directly; thread it through {@link stepRandomSeed} only.
1921
+ - `SeededRng` (interface): interface SeededRng — A {@link seededRng} stream: callable like any `() => number`, with its cursor readable and restorable for snapshots and replay.
1876
1922
  - `hashString` (function): function hashString(text: string): number — Deterministic 32-bit FNV-1a hash of a string → unsigned int. Same text, same number, on every platform — the stable seed behind per-id jitter, spread offsets, and content-addressed variation.
1877
1923
  - `randomSeedFrom` (function): function randomSeedFrom(seed: number): RandomSeed — Wraps an already-integer seed (e.g. a `config.seed`) as a {@link RandomSeed} — no hashing.
1878
- - `seededRng` (function): function seededRng(seed: string | number): () => number — Deterministic pseudo-random generator seeded from a string or number — same seed, same sequence.
1924
+ - `restoreRng` (function): function restoreRng(rng: () => number, cursor: number): void — Restore a seeded stream's cursor; a no-op for generators that carry no state.
1925
+ - `rngStateOf` (function): function rngStateOf(rng: () => number): number | null — The cursor of a seeded stream, or `null` for a generator that carries no state (an injected closure, `Math.random`).
1926
+ - `seededRng` (function): function seededRng(seed: string | number): SeededRng — Deterministic pseudo-random generator seeded from a string or number — same seed, same sequence.
1879
1927
  - `seededStreams` (function): function seededStreams(seed: string | number): (stream: string) => () => number — Derives independent, deterministic {@link seededRng} streams from one base seed, keyed by stream name.
1880
1928
  - `stepRandomSeed` (function): function stepRandomSeed(seed: RandomSeed): readonly [value: number, next: RandomSeed] — One step of the {@link seededRng} recurrence in pure (seed in, seed out) form — the same mulberry32-style generator, shared by every state machine that persists its own PRNG cursor instead of closing over a generator.
1881
1929
 
@@ -1940,51 +1988,51 @@
1940
1988
  ## @jgengine/core/session/contestedChannel
1941
1989
 
1942
1990
  - `ContestReaction` (type): type ContestReaction = "pause" | "decay" — ⚠ undocumented
1943
- - `ContestedChannel` (interface): interface ContestedChannel — ⚠ undocumented
1944
- - `ContestedChannelConfig` (interface): interface ContestedChannelConfig — ⚠ undocumented
1945
- - `ContestedEvent` (interface): interface ContestedEvent — ⚠ undocumented
1991
+ - `ContestedChannel` (interface): interface ContestedChannel { start(team: string): ContestedEvent | null; tick(dt: number, occupants?: Record<string, number>): ContestedEvent[]; damage(reason?: string): ContestedEvent | null; reset(): void; progress(): number; phase(): ContestedPhase; owner(): strin… — ⚠ undocumented
1992
+ - `ContestedChannelConfig` (interface): interface ContestedChannelConfig { duration: number; interruptOnDamage?: boolean; resetOnInterrupt?: boolean; favorability?: Record<string, number>; ratePerOccupant?: boolean; contested?: ContestReaction; decayRate?: number } — ⚠ undocumented
1993
+ - `ContestedEvent` (interface): interface ContestedEvent { kind: ContestedEventKind; owner: string | null; progress: number; reason?: string } — ⚠ undocumented
1946
1994
  - `ContestedEventKind` (type): type ContestedEventKind = "start" | "tick" | "contested" | "paused" | "complete" | "interrupted" — ⚠ undocumented
1947
1995
  - `ContestedPhase` (type): type ContestedPhase = "idle" | "active" | "paused" | "contested" | "complete" | "interrupted" — ⚠ undocumented
1948
- - `ContestedSnapshot` (interface): interface ContestedSnapshot — ⚠ undocumented
1996
+ - `ContestedSnapshot` (interface): interface ContestedSnapshot { phase: ContestedPhase; progress: number; owner: string | null; remaining: number } — ⚠ undocumented
1949
1997
 
1950
1998
  ## @jgengine/core/session/extraction
1951
1999
 
1952
- - `DeathResult` (interface): interface DeathResult — ⚠ undocumented
1953
- - `ExtractPoint` (interface): interface ExtractPoint — ⚠ undocumented
1954
- - `ExtractionAttempt` (interface): interface ExtractionAttempt — ⚠ undocumented
1955
- - `ExtractionResult` (interface): interface ExtractionResult — ⚠ undocumented
1956
- - `RaidPlayerSnapshot` (interface): interface RaidPlayerSnapshot — ⚠ undocumented
1957
- - `RaidSession` (interface): interface RaidSession — ⚠ undocumented
1958
- - `RaidSessionConfig` (interface): interface RaidSessionConfig — ⚠ undocumented
2000
+ - `DeathResult` (interface): interface DeathResult { userId: string; kept: readonly ItemStack[]; lost: readonly ItemStack[]; scheduled: DeliveryEntry | null; consolationLoadoutId: string | null } — ⚠ undocumented
2001
+ - `ExtractPoint` (interface): interface ExtractPoint { id: string; center: RingPoint; radius: number; holdSeconds: number; favorability?: Record<string, number>; interruptOnDamage?: boolean } — ⚠ undocumented
2002
+ - `ExtractionAttempt` (interface): interface ExtractionAttempt { extractId: string; channel: ContestedChannel } — ⚠ undocumented
2003
+ - `ExtractionResult` (interface): interface ExtractionResult { userId: string; extractId: string; banked: readonly ItemStack[] } — ⚠ undocumented
2004
+ - `RaidPlayerSnapshot` (interface): interface RaidPlayerSnapshot { status: RaidStatus; extractId: string | null; progress: number; remaining: number } — ⚠ undocumented
2005
+ - `RaidSession` (interface): interface RaidSession { beginExtract(userId: string, extractId: string, position: RingPoint, team?: string): ContestedEvent | null; tickExtract(userId: string, dt: number, occupants?: Record<string, number>): ContestedEvent[]; damage(userId: string, reason?: str… — ⚠ undocumented
2006
+ - `RaidSessionConfig` (interface): interface RaidSessionConfig { extracts: readonly ExtractPoint[]; insurance?: InsurancePolicy; consolation?: ConsolationPolicy } — ⚠ undocumented
1959
2007
  - `RaidStatus` (type): type RaidStatus = "in-raid" | "extracting" | "extracted" | "dead" — ⚠ undocumented
1960
2008
 
1961
2009
  ## @jgengine/core/session/ring
1962
2010
 
1963
- - `Ring` (interface): interface Ring — ⚠ undocumented
1964
- - `RingConfig` (interface): interface RingConfig — ⚠ undocumented
1965
- - `RingHit` (interface): interface RingHit — ⚠ undocumented
1966
- - `RingPhase` (interface): interface RingPhase — ⚠ undocumented
2011
+ - `Ring` (interface): interface Ring { at(time: number): RingSample; isOutside(time: number, position: RingPoint): boolean; distanceOutside(time: number, position: RingPoint): number; damageOutside(time: number, dt: number, positions: Iterable<{id: string; position: RingPoint}… — ⚠ undocumented
2012
+ - `RingConfig` (interface): interface RingConfig { center: RingPoint; phases: readonly RingPhase[] } — ⚠ undocumented
2013
+ - `RingHit` (interface): interface RingHit { id: string; damage: number; distanceOutside: number } — ⚠ undocumented
2014
+ - `RingPhase` (interface): interface RingPhase { startTime: number; shrinkDuration: number; fromRadius: number; toRadius: number; damagePerSecond: number; center?: RingPoint } — ⚠ undocumented
1967
2015
  - `RingPoint` (type): type RingPoint = [number, number] — ⚠ undocumented
1968
- - `RingSample` (interface): interface RingSample — ⚠ undocumented
2016
+ - `RingSample` (interface): interface RingSample { center: RingPoint; radius: number; damagePerSecond: number; phase: number; shrinking: boolean } — ⚠ undocumented
1969
2017
  - `createRing` (function): function createRing(config: RingConfig): Ring — ⚠ undocumented
1970
2018
  - `ringSampleAt` (function): function ringSampleAt(config: RingConfig, time: number): RingSample — ⚠ undocumented
1971
2019
 
1972
2020
  ## @jgengine/core/session/roles
1973
2021
 
1974
- - `RoleSpec` (interface): interface RoleSpec — ⚠ undocumented
2022
+ - `RoleSpec` (interface): interface RoleSpec { id: string; count?: number; ratio?: number } — ⚠ undocumented
1975
2023
 
1976
2024
  ## @jgengine/core/session/roundState
1977
2025
 
1978
- - `LossBonusRule` (interface): interface LossBonusRule — ⚠ undocumented
2026
+ - `LossBonusRule` (interface): interface LossBonusRule { base: number; step: number; max: number } — ⚠ undocumented
1979
2027
  - `PhaseEndHook` (type): type PhaseEndHook<TPhase extends string = RoundPhase> = ( endingPhase: TPhase, nextPhase: TPhase, round: number, ) => void — ⚠ undocumented
1980
- - `RoundConfig` (interface): interface RoundConfig<TPhase extends string = RoundPhase> — ⚠ undocumented
1981
- - `RoundEconomy` (interface): interface RoundEconomy — ⚠ undocumented
1982
- - `RoundEvent` (interface): interface RoundEvent<TPhase extends string = RoundPhase> — ⚠ undocumented
2028
+ - `RoundConfig` (interface): interface RoundConfig<TPhase extends string = RoundPhase> { phases: Record<TPhase, number>; teams: readonly string[] | readonly RoundTeam[]; phaseOrder?: readonly TPhase[]; winCondition?: (state: RoundSnapshot<TPhase>) => string | null; maxRounds?: number; winReward?: number; lossBonus?: LossBonus… — ⚠ undocumented
2029
+ - `RoundEconomy` (interface): interface RoundEconomy { team: string; reward: number; won: boolean; lossStreak: number } — ⚠ undocumented
2030
+ - `RoundEvent` (interface): interface RoundEvent<TPhase extends string = RoundPhase> { kind: RoundEventKind; round: number; phase?: TPhase; nextPhase?: TPhase; winner?: string; economy?: RoundEconomy[] } — ⚠ undocumented
1983
2031
  - `RoundEventKind` (type): type RoundEventKind = | "phase.start" | "phase.end" | "round.win" | "round.economy" | "match.end" — ⚠ undocumented
1984
2032
  - `RoundPhase` (type): type RoundPhase = string — ⚠ undocumented
1985
2033
  - `RoundPhaseDurations` (interface): interface RoundPhaseDurations — Default phase-duration shape for the built-in buy/live/end cycle; pass a wider `Record<string, number>` when using a custom `phaseOrder`.
1986
- - `RoundSnapshot` (interface): interface RoundSnapshot<TPhase extends string = RoundPhase> — ⚠ undocumented
1987
- - `RoundState` (interface): interface RoundState<TPhase extends string = RoundPhase> — ⚠ undocumented
2034
+ - `RoundSnapshot` (interface): interface RoundSnapshot<TPhase extends string = RoundPhase> { round: number; phase: TPhase; timeLeft: number; scores: Record<string, number>; lossStreaks: Record<string, number>; roles: Record<string, string | undefined>; matchOver: boolean; pendingWinner: string | null } — ⚠ undocumented
2035
+ - `RoundState` (interface): interface RoundState<TPhase extends string = RoundPhase> { tick(dt: number): RoundEvent<TPhase>[]; concludeRound(winner: string): RoundEvent<TPhase>[]; evaluate(): RoundEvent<TPhase>[]; onPhaseEnd(hook: PhaseEndHook<TPhase>): () => void; phase(): TPhase; round(): number; timeLeft(): number; score… — ⚠ undocumented
1988
2036
  - `RoundTeam` (interface): interface RoundTeam — A team entry with an optional role tag (e.g. "attacker", "defender") retrievable via `RoundState.roleOf`.
1989
2037
 
1990
2038
  ## @jgengine/core/store/defineKeyedStore
@@ -1999,12 +2047,12 @@
1999
2047
 
2000
2048
  ## @jgengine/core/survival/decayMeter
2001
2049
 
2002
- - `DecayMeterConfig` (interface): interface DecayMeterConfig — ⚠ undocumented
2050
+ - `DecayMeterConfig` (interface): interface DecayMeterConfig { id: string; max: number; min?: number; start?: number; rate: number; thresholds?: readonly MeterThreshold[] } — ⚠ undocumented · used by `createDecayMeterSet`: Named decay meters — hunger, thirst, oxygen, sanity, warmth, stamina.
2003
2051
  - `DecayMeterSet` (interface): interface DecayMeterSet — Set of named survival meters (hunger/thirst/…) that drain and refill over game time.
2004
- - `DecayMeterState` (interface): interface DecayMeterState — ⚠ undocumented
2052
+ - `DecayMeterState` (interface): interface DecayMeterState { id: string; value: number; max: number; min: number; fraction: number } — ⚠ undocumented · used by `decayMeterSnapshot`: Numeric state for every meter, keyed by id — the pure counterpart to {@link DecayMeterSet.snapshot}.
2005
2053
  - `DecayMeterValues` (type): type DecayMeterValues = Record<string, number> — Plain-data meter values: `meter id → current value`. This is the whole serialized form — it drops straight into a `defineGame` state record and round-trips through save/load and multiplayer sync with no closure to rebuild.
2006
2054
  - `DecayModifier` (type): type DecayModifier = number | Record<string, number> — Rate multiplier for {@link decayMeters}: one scalar applied to every meter (a member's metabolism, a game-mode harshness dial) or a per-meter record (cold biome → warmth only). `1` / omitted leaves the base rates unscaled.
2007
- - `MeterThreshold` (interface): interface MeterThreshold — ⚠ undocumented
2055
+ - `MeterThreshold` (interface): interface MeterThreshold { id: string; label: string; at: number; when: "below" | "above"; severity?: MoodleSeverity; icon?: string } — ⚠ undocumented
2008
2056
  - `createDecayMeterSet` (function): function createDecayMeterSet(configs: readonly DecayMeterConfig[]): DecayMeterSet — Named decay meters — hunger, thirst, oxygen, sanity, warmth, stamina. Each drains (or recovers) on game-time `dt` at a configurable rate, refills from consumables or actions, and raises moodle statuses at thresholds. Rate modifiers let the environment drive them (colder → faster warmth loss; toxic biome → oxygen drops), so a game reads an environment field then calls `setRateModifier`.
2009
2057
  - `decayMeterMoodles` (function): function decayMeterMoodles(values: DecayMeterValues, defs: readonly DecayMeterConfig[]): Moodle[] — Moodles for every crossed threshold, worst-first per meter in declared order.
2010
2058
  - `decayMeterSnapshot` (function): function decayMeterSnapshot(values: DecayMeterValues, defs: readonly DecayMeterConfig[]): Record<string, DecayMeterState> — Numeric state for every meter, keyed by id — the pure counterpart to {@link DecayMeterSet.snapshot}.
@@ -2020,97 +2068,97 @@
2020
2068
  - `MoodleSeverity` (type): type MoodleSeverity = "good" | "neutral" | "warning" | "critical" — ⚠ undocumented
2021
2069
  - `MoodleSource` (type): type MoodleSource = "meter" | "ailment" | "buff" — ⚠ undocumented
2022
2070
  - `MoodleStack` (interface): interface MoodleStack — Ordered stack of active moodles derived from meters/ailments/buffs.
2023
- - `TimedMoodleInput` (interface): interface TimedMoodleInput — ⚠ undocumented
2071
+ - `TimedMoodleInput` (interface): interface TimedMoodleInput { id: string; label: string; severity?: MoodleSeverity; icon?: string; note?: string; stacks?: number; duration?: number } — ⚠ undocumented
2024
2072
  - `createMoodleStack` (function): function createMoodleStack(): MoodleStack — A stateful holder for timed status moodles (food buffs, temporary shelter, warmth). Meters and multi-region health derive their own moodles on read; combine all three through `stackMoodles(stack.list(), meterMoodles, ailmentMoodles)` for one display.
2025
2073
  - `stackMoodles` (function): function stackMoodles(...groups: readonly (readonly Moodle[])[]): Moodle[] — Merge any number of moodle groups into one stack — meters, ailments, and buffs share this display. Same-id moodles fold together (stacks add, worst severity wins); the result is ordered worst-first so the HUD reads critical statuses at a glance.
2026
2074
 
2027
2075
  ## @jgengine/core/survival/regionHealth
2028
2076
 
2029
- - `AilmentConfig` (interface): interface AilmentConfig — ⚠ undocumented
2030
- - `AilmentInstance` (interface): interface AilmentInstance — ⚠ undocumented
2031
- - `DamageResult` (interface): interface DamageResult — ⚠ undocumented
2032
- - `HealthRegionConfig` (interface): interface HealthRegionConfig — ⚠ undocumented
2077
+ - `AilmentConfig` (interface): interface AilmentConfig { id: string; label: string; region?: string; severity?: MoodleSeverity; icon?: string; drainPerSecond?: number; stacking?: boolean; treatedBy?: readonly string[] } — ⚠ undocumented
2078
+ - `AilmentInstance` (interface): interface AilmentInstance { id: string; stacks: number } — ⚠ undocumented
2079
+ - `DamageResult` (interface): interface DamageResult { region: RegionHealthState; applied: number; dead: boolean } — ⚠ undocumented
2080
+ - `HealthRegionConfig` (interface): interface HealthRegionConfig { id: string; label: string; max: number; vital?: boolean; vulnerability?: number } — ⚠ undocumented
2033
2081
  - `MultiRegionHealth` (interface): interface MultiRegionHealth — Per-limb / per-region health track with treat/damage/heal APIs.
2034
- - `MultiRegionHealthConfig` (interface): interface MultiRegionHealthConfig — ⚠ undocumented
2035
- - `RegionHealthState` (interface): interface RegionHealthState — ⚠ undocumented
2036
- - `TreatResult` (interface): interface TreatResult — ⚠ undocumented
2082
+ - `MultiRegionHealthConfig` (interface): interface MultiRegionHealthConfig { regions: readonly HealthRegionConfig[]; ailments?: Record<string, AilmentConfig> } — ⚠ undocumented · used by `createMultiRegionHealth`: Per-region/limb health tracked separately, so each body part takes and heals damage on its own.
2083
+ - `RegionHealthState` (interface): interface RegionHealthState { id: string; label: string; current: number; max: number; fraction: number; vital: boolean } — ⚠ undocumented
2084
+ - `TreatResult` (interface): interface TreatResult { treated: readonly string[] } — ⚠ undocumented
2037
2085
  - `createMultiRegionHealth` (function): function createMultiRegionHealth(config: MultiRegionHealthConfig): MultiRegionHealth — Per-region/limb health tracked separately, so each body part takes and heals damage on its own.
2038
2086
 
2039
2087
  ## @jgengine/core/tactics/fallingGrid
2040
2088
 
2041
- - `FallingGrid` (interface): interface FallingGrid<TCell> — ⚠ undocumented
2089
+ - `FallingGrid` (interface): interface FallingGrid<TCell> { readonly cols: number; readonly rows: number; occupied(col: number, row: number): boolean; cellAt(col: number, row: number): TCell | null; setCell(col: number, row: number, value: TCell): void; clearCell(col: number, row: number): void; c… — ⚠ undocumented
2042
2090
  - `FallingGridCell` (type): type FallingGridCell = readonly [number, number] — ⚠ undocumented
2043
- - `FallingGridConfig` (interface): interface FallingGridConfig — ⚠ undocumented
2044
- - `FallingGridSnapshot` (interface): interface FallingGridSnapshot<TCell> — ⚠ undocumented
2045
- - `GravityIntervalConfig` (interface): interface GravityIntervalConfig — ⚠ undocumented
2091
+ - `FallingGridConfig` (interface): interface FallingGridConfig { cols: number; rows: number; lockDelayMs?: number } — ⚠ undocumented
2092
+ - `FallingGridSnapshot` (interface): interface FallingGridSnapshot<TCell> { cols: number; rows: number; cells: readonly (TCell | null)[] } — ⚠ undocumented
2093
+ - `GravityIntervalConfig` (interface): interface GravityIntervalConfig { baseMs?: number; perLevel?: number; minMs?: number } — ⚠ undocumented
2046
2094
  - `LockState` (interface): interface LockState — Elapsed grounded time for the lock-delay state machine. `null` means airborne / not timing.
2047
2095
 
2048
2096
  ## @jgengine/core/tactics/predictiveQuery
2049
2097
 
2050
- - `ArcPredictInput` (interface): interface ArcPredictInput — ⚠ undocumented
2051
- - `AreaPredictInput` (interface): interface AreaPredictInput extends AreaTargetInput — ⚠ undocumented
2052
- - `PredictedTarget` (interface): interface PredictedTarget — ⚠ undocumented
2053
- - `PredictiveDeps` (interface): interface PredictiveDeps — ⚠ undocumented
2054
- - `TilePredictInput` (interface): interface TilePredictInput — ⚠ undocumented
2098
+ - `ArcPredictInput` (interface): interface ArcPredictInput { from: string; aim: Aim; radius: number; halfAngleDeg?: number; effect?: string; requireReceive?: boolean } — ⚠ undocumented
2099
+ - `AreaPredictInput` (interface): interface AreaPredictInput extends AreaTargetInput { effect?: string; requireReceive?: boolean } — ⚠ undocumented
2100
+ - `PredictedTarget` (interface): interface PredictedTarget { instanceId: string; scale: number } — ⚠ undocumented
2101
+ - `PredictiveDeps` (interface): interface PredictiveDeps { spatial: CombatSpatialDeps; queryArc(options: QueryArcOptions): string[]; canReceive?(instanceId: string, effect: string): string | null } — ⚠ undocumented
2102
+ - `TilePredictInput` (interface): interface TilePredictInput { at: EntityPosition; radius: number; originTile: Tile; tileSize: number } — ⚠ undocumented
2055
2103
 
2056
2104
  ## @jgengine/core/tactics/snapshot
2057
2105
 
2058
2106
  - `Snapshot` (type): type Snapshot = Record<string, unknown> — ⚠ undocumented
2059
- - `SnapshotSlice` (interface): interface SnapshotSlice<T = unknown> — ⚠ undocumented
2060
- - `SnapshotStore` (interface): interface SnapshotStore — ⚠ undocumented
2107
+ - `SnapshotSlice` (interface): interface SnapshotSlice<T = unknown> { capture(): T; restore(state: T): void } — ⚠ undocumented
2108
+ - `SnapshotStore` (interface): interface SnapshotStore { register<T>(id: string, slice: SnapshotSlice<T>): void; unregister(id: string): void; capture(): Snapshot; restore(snapshot: Snapshot): void; push(): Snapshot; pop(): boolean; peek(): Snapshot | null; depth(): number; clear(): void } — ⚠ undocumented
2061
2109
 
2062
2110
  ## @jgengine/core/tactics/surface
2063
2111
 
2064
- - `SurfaceCell` (interface): interface SurfaceCell — ⚠ undocumented
2065
- - `SurfaceCellKind` (interface): interface SurfaceCellKind — ⚠ undocumented
2112
+ - `SurfaceCell` (interface): interface SurfaceCell { tile: Tile; kinds: SurfaceCellKind[] } — ⚠ undocumented
2113
+ - `SurfaceCellKind` (interface): interface SurfaceCellKind { surface: string; remaining: number | null } — ⚠ undocumented
2066
2114
  - `SurfaceEvent` (type): type SurfaceEvent = | { kind: "apply"; tile: Tile; surface: string } | { kind: "react"; tile: Tile; consumed: readonly [string, string]; produced: string | null } | { kind: "expire"; tile: Tile; surface: string } — ⚠ undocumented
2067
- - `SurfaceKindDef` (interface): interface SurfaceKindDef — ⚠ undocumented
2068
- - `SurfaceLayer` (interface): interface SurfaceLayer — ⚠ undocumented
2069
- - `SurfaceLayerConfig` (interface): interface SurfaceLayerConfig — ⚠ undocumented
2115
+ - `SurfaceKindDef` (interface): interface SurfaceKindDef { id: string; duration?: number } — ⚠ undocumented
2116
+ - `SurfaceLayer` (interface): interface SurfaceLayer { apply(tile: Tile, surface: string, patch?: SurfacePatch): SurfaceEvent[]; has(tile: Tile, surface: string): boolean; kindsAt(tile: Tile): string[]; remove(tile: Tile, surface: string): void; clearTile(tile: Tile): void; clear(): void; tic… — ⚠ undocumented
2117
+ - `SurfaceLayerConfig` (interface): interface SurfaceLayerConfig { kinds: readonly SurfaceKindDef[]; reactions?: readonly SurfaceReaction[] } — ⚠ undocumented
2070
2118
  - `SurfaceLayerSnapshot` (type): type SurfaceLayerSnapshot = Record<string, Record<string, number | null>> — ⚠ undocumented
2071
- - `SurfacePatch` (interface): interface SurfacePatch — ⚠ undocumented
2072
- - `SurfaceReaction` (interface): interface SurfaceReaction — ⚠ undocumented
2119
+ - `SurfacePatch` (interface): interface SurfacePatch { duration?: number } — ⚠ undocumented
2120
+ - `SurfaceReaction` (interface): interface SurfaceReaction { when: readonly [string, string]; result: string | null } — ⚠ undocumented
2073
2121
 
2074
2122
  ## @jgengine/core/tactics/tacticalGrid
2075
2123
 
2076
- - `PushCollision` (interface): interface PushCollision — ⚠ undocumented
2077
- - `PushMove` (interface): interface PushMove — ⚠ undocumented
2124
+ - `PushCollision` (interface): interface PushCollision { mover: string; into: string | PushObstacle; at: Tile } — ⚠ undocumented
2125
+ - `PushMove` (interface): interface PushMove { id: string; from: Tile; to: Tile } — ⚠ undocumented
2078
2126
  - `PushObstacle` (type): type PushObstacle = "wall" | "edge" — ⚠ undocumented
2079
- - `PushOptions` (interface): interface PushOptions — ⚠ undocumented
2080
- - `PushResult` (interface): interface PushResult — ⚠ undocumented
2081
- - `ReachableOptions` (interface): interface ReachableOptions — ⚠ undocumented
2082
- - `ReachableTile` (interface): interface ReachableTile — ⚠ undocumented
2083
- - `TacticalGrid` (interface): interface TacticalGrid — ⚠ undocumented
2084
- - `TacticalGridConfig` (interface): interface TacticalGridConfig — ⚠ undocumented
2085
- - `TacticalGridSnapshot` (interface): interface TacticalGridSnapshot — ⚠ undocumented
2127
+ - `PushOptions` (interface): interface PushOptions { distance?: number; chain?: boolean } — ⚠ undocumented
2128
+ - `PushResult` (interface): interface PushResult { moves: PushMove[]; collisions: PushCollision[] } — ⚠ undocumented
2129
+ - `ReachableOptions` (interface): interface ReachableOptions { passThrough?: readonly string[]; diagonal?: boolean } — ⚠ undocumented
2130
+ - `ReachableTile` (interface): interface ReachableTile { tile: Tile; cost: number } — ⚠ undocumented
2131
+ - `TacticalGrid` (interface): interface TacticalGrid { readonly width: number; readonly height: number; inBounds(tile: Tile): boolean; isBlocked(tile: Tile): boolean; setBlocked(tile: Tile, blocked: boolean): void; occupantAt(tile: Tile): string | null; tileOf(id: string): Tile | null; place(… — ⚠ undocumented
2132
+ - `TacticalGridConfig` (interface): interface TacticalGridConfig { width: number; height: number; blocked?: readonly Tile[]; diagonal?: boolean; world?: TacticalGridWorldConfig } — ⚠ undocumented
2133
+ - `TacticalGridSnapshot` (interface): interface TacticalGridSnapshot { blocked: string[]; occupants: Record<string, string> } — ⚠ undocumented
2086
2134
  - `TacticalGridWorldConfig` (interface): interface TacticalGridWorldConfig — Maps abstract `[col, row]` tiles onto world-space `[x, z]`, mirroring `navGrid`'s bounds+cellSize convention.
2087
2135
  - `Tile` (type): type Tile = readonly [number, number] — ⚠ undocumented
2088
2136
 
2089
2137
  ## @jgengine/core/turn/commit
2090
2138
 
2091
- - `CommitController` (interface): interface CommitController<TAction> — ⚠ undocumented
2092
- - `CommitControllerConfig` (interface): interface CommitControllerConfig — ⚠ undocumented
2139
+ - `CommitController` (interface): interface CommitController<TAction> { readonly mode: CommitMode; submit(participant: string, action: TAction): CommitOutcome<TAction>; expected(participants: readonly string[]): void; hasSubmitted(participant: string): boolean; allReady(): boolean; pending(): SubmittedAction<… — ⚠ undocumented
2140
+ - `CommitControllerConfig` (interface): interface CommitControllerConfig { mode: CommitMode; participants?: readonly string[] } — ⚠ undocumented
2093
2141
  - `CommitMode` (type): type CommitMode = "immediate" | "simultaneous" | "resealable" — ⚠ undocumented
2094
- - `CommitOutcome` (interface): interface CommitOutcome<TAction> — ⚠ undocumented
2095
- - `SubmittedAction` (interface): interface SubmittedAction<TAction> — ⚠ undocumented
2142
+ - `CommitOutcome` (interface): interface CommitOutcome<TAction> { status: "committed" | "sealed" | "pending" | "rejected"; committed: SubmittedAction<TAction>[]; reason?: string } — ⚠ undocumented
2143
+ - `SubmittedAction` (interface): interface SubmittedAction<TAction> { participant: string; action: TAction } — ⚠ undocumented
2096
2144
  - `createCommitController` (function): function createCommitController<TAction>(config: CommitControllerConfig): CommitController<TAction> — ⚠ undocumented
2097
2145
 
2098
2146
  ## @jgengine/core/turn/intent
2099
2147
 
2100
- - `DeclaredIntent` (interface): interface DeclaredIntent<TKind extends string = string> — ⚠ undocumented
2101
- - `IntentBoard` (interface): interface IntentBoard<TKind extends string = string> — ⚠ undocumented
2148
+ - `DeclaredIntent` (interface): interface DeclaredIntent<TKind extends string = string> { kind: TKind; magnitude?: number; targetId?: string; note?: string } — ⚠ undocumented
2149
+ - `IntentBoard` (interface): interface IntentBoard<TKind extends string = string> { declare(participantId: string, intent: DeclaredIntent<TKind>): void; peek(participantId: string): DeclaredIntent<TKind> | null; all(): readonly [string, DeclaredIntent<TKind>][]; consume(participantId: string): DeclaredIntent<TKind> | nul… — ⚠ undocumented
2102
2150
  - `createIntentBoard` (function): function createIntentBoard<TKind extends string = string>(): IntentBoard<TKind> — ⚠ undocumented
2103
2151
 
2104
2152
  ## @jgengine/core/turn/turnLoop
2105
2153
 
2106
- - `CommitController` (interface): interface CommitController<TAction> — ⚠ undocumented
2154
+ - `CommitController` (interface): interface CommitController<TAction> { readonly mode: CommitMode; submit(participant: string, action: TAction): CommitOutcome<TAction>; expected(participants: readonly string[]): void; hasSubmitted(participant: string): boolean; allReady(): boolean; pending(): SubmittedAction<… — ⚠ undocumented
2107
2155
  - `CommitMode` (type): type CommitMode = "immediate" | "simultaneous" | "resealable" — ⚠ undocumented
2108
- - `PoolConfig` (interface): interface PoolConfig — ⚠ undocumented
2109
- - `PoolState` (interface): interface PoolState — ⚠ undocumented
2110
- - `TurnLoop` (interface): interface TurnLoop<TAction = unknown> — ⚠ undocumented
2111
- - `TurnLoopConfig` (interface): interface TurnLoopConfig — ⚠ undocumented
2112
- - `TurnLoopSnapshot` (interface): interface TurnLoopSnapshot — ⚠ undocumented
2113
- - `TurnState` (interface): interface TurnState — ⚠ undocumented
2156
+ - `PoolConfig` (interface): interface PoolConfig { id: string; max: number; start?: number } — ⚠ undocumented
2157
+ - `PoolState` (interface): interface PoolState { id: string; current: number; max: number } — ⚠ undocumented
2158
+ - `TurnLoop` (interface): interface TurnLoop<TAction = unknown> { readonly commit: CommitController<TAction>; state(): TurnState; order(): readonly string[]; active(): string | null; phase(): string | null; round(): number; setOrder(order: readonly string[], keepActive?: boolean): TurnState; addParticip… — ⚠ undocumented
2159
+ - `TurnLoopConfig` (interface): interface TurnLoopConfig { order: readonly string[]; phases?: readonly string[]; pools?: readonly PoolConfig[]; commit?: {mode: CommitMode}; onTurnStart?(participantId: string): void; onTurnEnd?(participantId: string): void } — ⚠ undocumented
2160
+ - `TurnLoopSnapshot` (interface): interface TurnLoopSnapshot { round: number; order: string[]; activeIndex: number; phaseIndex: number; pools: Record<string, Record<string, number>> } — ⚠ undocumented
2161
+ - `TurnState` (interface): interface TurnState { round: number; order: readonly string[]; activeIndex: number; active: string | null; phaseIndex: number; phase: string | null } — ⚠ undocumented
2114
2162
  - `createTurnLoop` (function): function createTurnLoop<TAction = unknown>(config: TurnLoopConfig): TurnLoop<TAction> — ⚠ undocumented
2115
2163
 
2116
2164
  ## @jgengine/core/work/jobQueue