@jgengine/core 0.18.1 → 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 (220) hide show
  1. package/CHANGELOG.md +158 -7
  2. package/dist/ai/decisionGraph.d.ts +48 -4
  3. package/dist/ai/decisionGraph.js +153 -23
  4. package/dist/ai/groupAssist.d.ts +10 -0
  5. package/dist/ai/groupAssist.js +11 -0
  6. package/dist/ai/pursuit.d.ts +1 -1
  7. package/dist/ai/pursuit.js +1 -1
  8. package/dist/ai/threat.d.ts +8 -0
  9. package/dist/ai/threat.js +10 -0
  10. package/dist/anim/animGraph.d.ts +11 -0
  11. package/dist/anim/animGraph.js +128 -0
  12. package/dist/anim/boneTexture.d.ts +55 -0
  13. package/dist/anim/boneTexture.js +43 -0
  14. package/dist/anim/footPlacement.d.ts +57 -0
  15. package/dist/anim/footPlacement.js +67 -0
  16. package/dist/anim/locomotionGraph.d.ts +9 -0
  17. package/dist/anim/locomotionGraph.js +29 -0
  18. package/dist/audio/audioFalloff.d.ts +2 -0
  19. package/dist/audio/doppler.d.ts +21 -0
  20. package/dist/audio/doppler.js +32 -0
  21. package/dist/audio/engineLayers.d.ts +83 -0
  22. package/dist/audio/engineLayers.js +115 -0
  23. package/dist/combat/abilityKit.d.ts +1 -0
  24. package/dist/combat/abilityKit.js +1 -0
  25. package/dist/combat/death.d.ts +7 -0
  26. package/dist/combat/shotOrigin.d.ts +6 -0
  27. package/dist/combat/shotOrigin.js +6 -0
  28. package/dist/combat/weaponFeedback.d.ts +36 -0
  29. package/dist/combat/weaponFeedback.js +42 -0
  30. package/dist/combat/weaponHandling.d.ts +161 -0
  31. package/dist/combat/weaponHandling.js +202 -0
  32. package/dist/combat/weaponPresentation.d.ts +115 -0
  33. package/dist/combat/weaponPresentation.js +96 -0
  34. package/dist/devtools/warnOnce.d.ts +8 -0
  35. package/dist/devtools/warnOnce.js +18 -0
  36. package/dist/editor/document.js +3 -1
  37. package/dist/editor/environment.js +8 -0
  38. package/dist/editor/types.d.ts +4 -0
  39. package/dist/faction/reputation.d.ts +6 -0
  40. package/dist/faction/reputation.js +11 -0
  41. package/dist/game/cameraConfig.d.ts +51 -1
  42. package/dist/game/events.d.ts +6 -0
  43. package/dist/game/lootTable.d.ts +4 -0
  44. package/dist/game/lootTable.js +16 -0
  45. package/dist/game/playableGame.d.ts +84 -17
  46. package/dist/game/toasts.d.ts +8 -0
  47. package/dist/game/toasts.js +7 -0
  48. package/dist/game/vfxInstance.d.ts +9 -0
  49. package/dist/game/vfxInstance.js +12 -1
  50. package/dist/game/viewports.d.ts +43 -0
  51. package/dist/game/viewports.js +46 -0
  52. package/dist/game/worldItem.d.ts +5 -1
  53. package/dist/game/worldItem.js +0 -1
  54. package/dist/input/actionBindings.d.ts +15 -1
  55. package/dist/input/actionBindings.js +14 -3
  56. package/dist/input/actionContexts.d.ts +25 -1
  57. package/dist/input/actionContexts.js +82 -25
  58. package/dist/input/axisInput.d.ts +4 -0
  59. package/dist/input/axisInput.js +4 -0
  60. package/dist/input/axisShaper.d.ts +73 -0
  61. package/dist/input/axisShaper.js +105 -0
  62. package/dist/input/gamepadModel.d.ts +36 -2
  63. package/dist/input/gamepadModel.js +69 -30
  64. package/dist/input/haptics.d.ts +50 -0
  65. package/dist/input/haptics.js +74 -0
  66. package/dist/input/inputBuffer.d.ts +40 -0
  67. package/dist/input/inputBuffer.js +59 -0
  68. package/dist/input/lookChannel.d.ts +10 -0
  69. package/dist/input/lookChannel.js +6 -0
  70. package/dist/input/pointer.d.ts +2 -0
  71. package/dist/input/pointer.js +4 -0
  72. package/dist/item/affix.d.ts +6 -0
  73. package/dist/item/affix.js +6 -0
  74. package/dist/meta/changelog.d.ts +1 -1
  75. package/dist/meta/changelog.js +112 -1
  76. package/dist/movement/glideModel.d.ts +3 -0
  77. package/dist/movement/glideModel.js +6 -0
  78. package/dist/movement/grappleSwing.d.ts +2 -0
  79. package/dist/movement/grappleSwing.js +5 -1
  80. package/dist/movement/movementModel.d.ts +39 -0
  81. package/dist/movement/movementModel.js +62 -19
  82. package/dist/movement/movementProbe.d.ts +51 -0
  83. package/dist/movement/movementProbe.js +119 -0
  84. package/dist/movement/playerMovement.d.ts +21 -2
  85. package/dist/movement/playerMovement.js +89 -6
  86. package/dist/movement/solidObstacles.d.ts +9 -1
  87. package/dist/movement/solidObstacles.js +44 -2
  88. package/dist/movement/voxelController.js +7 -7
  89. package/dist/nav/navFromEnvironment.d.ts +9 -3
  90. package/dist/nav/navFromEnvironment.js +18 -12
  91. package/dist/nav/navMesh.d.ts +43 -2
  92. package/dist/nav/navMesh.js +534 -128
  93. package/dist/physics/aircraftDynamics.d.ts +390 -0
  94. package/dist/physics/aircraftDynamics.js +704 -0
  95. package/dist/physics/boatDynamics.d.ts +116 -0
  96. package/dist/physics/boatDynamics.js +160 -0
  97. package/dist/physics/drivableVehicle.d.ts +22 -8
  98. package/dist/physics/drivableVehicle.js +4 -2
  99. package/dist/physics/flightDynamics.d.ts +21 -4
  100. package/dist/physics/flightDynamics.js +28 -5
  101. package/dist/physics/handlingProbe.d.ts +249 -0
  102. package/dist/physics/handlingProbe.js +606 -0
  103. package/dist/physics/kinematicVehicle.d.ts +32 -2
  104. package/dist/physics/kinematicVehicle.js +15 -0
  105. package/dist/physics/physicsBackend.d.ts +12 -0
  106. package/dist/physics/physicsBackendConformance.js +34 -0
  107. package/dist/physics/physicsWorldBackend.d.ts +1 -0
  108. package/dist/physics/physicsWorldBackend.js +33 -0
  109. package/dist/physics/vehicleBackendLink.d.ts +49 -0
  110. package/dist/physics/vehicleBackendLink.js +102 -0
  111. package/dist/physics/vehicleDynamics.d.ts +374 -0
  112. package/dist/physics/vehicleDynamics.js +737 -0
  113. package/dist/physics/worldColliders.d.ts +1 -1
  114. package/dist/physics/worldColliders.js +35 -3
  115. package/dist/puzzle/cellGrid.d.ts +15 -9
  116. package/dist/puzzle/cellGrid.js +13 -9
  117. package/dist/render/lookPreset.d.ts +9 -2
  118. package/dist/render/lookPreset.js +29 -2
  119. package/dist/render/postProcessing.d.ts +30 -0
  120. package/dist/render/postProcessing.js +1 -1
  121. package/dist/runtime/cameraDirector.d.ts +17 -3
  122. package/dist/runtime/cameraDirector.js +25 -0
  123. package/dist/runtime/commandInput.d.ts +37 -0
  124. package/dist/runtime/commandInput.js +58 -0
  125. package/dist/runtime/commandRunner.d.ts +27 -0
  126. package/dist/runtime/commandRunner.js +31 -3
  127. package/dist/runtime/context/combat.d.ts +1 -0
  128. package/dist/runtime/context/combat.js +2 -1
  129. package/dist/runtime/context/deathLoot.d.ts +2 -0
  130. package/dist/runtime/context/deathLoot.js +1 -0
  131. package/dist/runtime/gameContext.js +7 -0
  132. package/dist/runtime/gameContextTypes.d.ts +19 -3
  133. package/dist/runtime/gameRuntime.d.ts +3 -1
  134. package/dist/runtime/gameRuntime.js +4 -0
  135. package/dist/runtime/inputSnapshot.d.ts +6 -0
  136. package/dist/runtime/inputSnapshot.js +10 -0
  137. package/dist/runtime/localPlayers.d.ts +73 -0
  138. package/dist/runtime/localPlayers.js +119 -0
  139. package/dist/runtime/transport.d.ts +9 -0
  140. package/dist/runtime/transport.js +7 -1
  141. package/dist/scene/behaviorRuntime.d.ts +12 -2
  142. package/dist/scene/behaviorRuntime.js +30 -14
  143. package/dist/scene/behaviors.d.ts +5 -1
  144. package/dist/scene/sceneKinds.d.ts +9 -0
  145. package/dist/scene/vehicleSeat.d.ts +5 -1
  146. package/dist/scene/vehicleSeat.js +5 -1
  147. package/dist/sensor/concealment.d.ts +6 -0
  148. package/dist/sensor/concealment.js +8 -0
  149. package/dist/sensor/freezeMonitor.d.ts +6 -0
  150. package/dist/sensor/freezeMonitor.js +8 -0
  151. package/dist/sensor/perception.d.ts +11 -1
  152. package/dist/sensor/perception.js +57 -10
  153. package/dist/sensor/recordingBuffer.d.ts +3 -0
  154. package/dist/sensor/recordingBuffer.js +8 -0
  155. package/dist/session/roundState.d.ts +4 -0
  156. package/dist/session/roundState.js +11 -0
  157. package/dist/settings/frameRateLimit.d.ts +16 -0
  158. package/dist/settings/frameRateLimit.js +37 -0
  159. package/dist/settings/graphicsProfile.d.ts +2 -0
  160. package/dist/settings/graphicsProfile.js +12 -0
  161. package/dist/settings/graphicsSettings.d.ts +40 -0
  162. package/dist/settings/graphicsSettings.js +81 -0
  163. package/dist/settings/settingsModel.d.ts +9 -1
  164. package/dist/settings/settingsModel.js +10 -0
  165. package/dist/stats/eventMeter.d.ts +1 -1
  166. package/dist/stats/eventMeter.js +1 -1
  167. package/dist/vfx/feedbackMixer.d.ts +61 -0
  168. package/dist/vfx/feedbackMixer.js +106 -0
  169. package/dist/visibility/simulationCulling.d.ts +8 -1
  170. package/dist/visibility/simulationCulling.js +7 -0
  171. package/dist/visibility/spatialIndex.d.ts +21 -0
  172. package/dist/visibility/spatialIndex.js +16 -0
  173. package/dist/world/authoredSolids.d.ts +46 -0
  174. package/dist/world/authoredSolids.js +75 -0
  175. package/dist/world/buildingGenerator.js +2 -2
  176. package/dist/world/buildingKit.d.ts +3 -1
  177. package/dist/world/buildings.d.ts +34 -2
  178. package/dist/world/buildings.js +11 -1
  179. package/dist/world/cityKind.d.ts +7 -0
  180. package/dist/world/cityKind.js +52 -1
  181. package/dist/world/features.d.ts +29 -2
  182. package/dist/world/features.js +6 -0
  183. package/dist/world/footprintGrid.d.ts +7 -0
  184. package/dist/world/footprintGrid.js +16 -0
  185. package/dist/world/interiors.d.ts +1 -0
  186. package/dist/world/interiors.js +5 -3
  187. package/dist/world/lod.d.ts +6 -0
  188. package/dist/world/lod.js +8 -0
  189. package/dist/world/terraform.d.ts +8 -0
  190. package/dist/world/terraform.js +7 -0
  191. package/dist/world/walls.d.ts +7 -0
  192. package/dist/world/walls.js +7 -0
  193. package/dist/world/worldSolids.d.ts +84 -0
  194. package/dist/world/worldSolids.js +240 -0
  195. package/dist/world.d.ts +2 -2
  196. package/dist/world.js +1 -1
  197. package/package.json +1 -1
  198. package/skills/ce-handoff/SKILL.md +1 -1
  199. package/skills/game-design/SKILL.md +2 -2
  200. package/skills/jgengine/SKILL.md +7 -5
  201. package/skills/jgengine/api.md +118 -89
  202. package/skills/jgengine/capabilities.md +28 -0
  203. package/skills/jgengine/recipes/minimal-game.md +3 -0
  204. package/skills/jgengine-combat/SKILL.md +5 -0
  205. package/skills/jgengine-combat/api.md +138 -103
  206. package/skills/jgengine-combat/capabilities.md +29 -1
  207. package/skills/jgengine-combat/recipes/weapon-feel.md +50 -0
  208. package/skills/jgengine-gameplay/api.md +462 -436
  209. package/skills/jgengine-gameplay/capabilities.md +24 -0
  210. package/skills/jgengine-gameplay/reference-systems.md +4 -0
  211. package/skills/jgengine-world/SKILL.md +15 -3
  212. package/skills/jgengine-world/api.md +873 -626
  213. package/skills/jgengine-world/capabilities.md +130 -6
  214. package/skills/jgengine-world/recipes/character-animation.md +39 -0
  215. package/skills/jgengine-world/recipes/controls.md +44 -0
  216. package/skills/jgengine-world/recipes/flight-feel.md +76 -0
  217. package/skills/jgengine-world/recipes/npc-senses.md +43 -0
  218. package/skills/jgengine-world/recipes/vehicle-feel.md +85 -0
  219. package/skills/jgengine-world/reference.md +31 -2
  220. 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,7 +169,7 @@
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
174
  - `formatCurrency` (function): function formatCurrency(currency: CurrencyDefinition, value: number): string — Format a major-unit value using the currency's declared precision.
175
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.
@@ -232,7 +232,7 @@
232
232
  ## @jgengine/core/economy/sharedWallet
233
233
 
234
234
  - `BookChargeResult` (type): type BookChargeResult = | { status: "ok"; book: WalletBook } | { status: "rejected"; reason: "insufficient-funds" } — ⚠ undocumented
235
- - `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
236
236
  - `WalletScope` (type): type WalletScope = | { kind: "user"; userId: string } | { kind: "group"; groupId: string } — ⚠ undocumented
237
237
 
238
238
  ## @jgengine/core/economy/shopStock
@@ -251,10 +251,10 @@
251
251
  ## @jgengine/core/economy/techTree
252
252
 
253
253
  - `TechCheck` (type): type TechCheck = { ok: true } | ({ ok: false } & TechRejection) — ⚠ undocumented
254
- - `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
255
255
  - `TechRejection` (type): type TechRejection = | { reason: "unknown-node" } | { reason: "already-unlocked" } | { reason: "missing-prerequisites"; missing: readonly string[] } — ⚠ undocumented
256
256
  - `TechState` (type): type TechState = UnlockState — ⚠ undocumented
257
- - `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
258
258
 
259
259
  ## @jgengine/core/economy/unlockPoints
260
260
 
@@ -271,7 +271,7 @@
271
271
  - `ChargeOptions` (interface): interface ChargeOptions — Options for {@link charge}/{@link chargeAll}: opt one call into overdraft debt via `overdraft`.
272
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`.
273
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.
274
- - `WalletState` (interface): interface WalletState — ⚠ 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
275
  - `balance` (function): function balance(state: WalletState, currency: string | CurrencyDefinition): number — ⚠ undocumented
276
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).
277
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.
@@ -312,15 +312,16 @@
312
312
  ## @jgengine/core/game/cameraConfig
313
313
 
314
314
  - `CAMERA_FRUSTUM_DEFAULTS` (const): const CAMERA_FRUSTUM_DEFAULTS: { readonly fov: 55; readonly near: 0.1; readonly far: 300; readonly zoom: 50; } — ⚠ undocumented
315
- - `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
316
316
  - `CameraKeyframe` (interface): interface CameraKeyframe — One stop on a scripted camera path (#29).
317
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".
318
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.
319
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`.
320
321
  - `ChaseCameraConfig` (interface): interface ChaseCameraConfig — Speed-reactive vehicle chase rig (#27) — speed→FOV, spring arm, procedural shake, interior views.
321
322
  - `ChaseView` (type): type ChaseView = "chase" | "cockpit" | "hood" | "rear" — Fixed interior view for the chase rig (#27).
322
323
  - `CinematicCameraConfig` (interface): interface CinematicCameraConfig — Scripted keyframe / path player (#29). When set it overrides the active rig.
323
- - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig — ⚠ undocumented
324
+ - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig { eyeHeight?: number; sensitivity?: number; maxPitch?: number; reticle?: boolean; viewmodel?: boolean } — ⚠ undocumented
324
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.
325
326
  - `InspectionCameraConfig` (interface): interface InspectionCameraConfig — Model-viewer / inspection rig (#207.7) — orbit + pan + anchored zoom around a fixed point, never reads player input.
326
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.
@@ -336,16 +337,16 @@
336
337
 
337
338
  ## @jgengine/core/game/chat
338
339
 
339
- - `Chat` (interface): interface Chat — ⚠ undocumented
340
- - `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
341
342
  - `ChatChannelKind` (type): type ChatChannelKind = "global" | "party" | "proximity" — ⚠ undocumented
342
- - `ChatDeps` (interface): interface ChatDeps — ⚠ undocumented
343
- - `ChatMessage` (interface): interface ChatMessage — ⚠ undocumented
344
- - `ChatRateLimit` (interface): interface ChatRateLimit — ⚠ undocumented
345
- - `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
346
347
  - `ChatRecipients` (type): type ChatRecipients = readonly string[] | "all" — ⚠ undocumented
347
348
  - `ChatSendResult` (type): type ChatSendResult = | { message: ChatMessage; recipients: ChatRecipients } | { reason: string } — ⚠ undocumented
348
- - `ChatSnapshot` (interface): interface ChatSnapshot — ⚠ undocumented
349
+ - `ChatSnapshot` (interface): interface ChatSnapshot { messages: Record<string, ChatMessage[]>; counter: number; rateWindows?: Record<string, Record<string, number[]>> } — ⚠ undocumented
349
350
  - `ChatValidation` (type): type ChatValidation = { ok: true; text: string } | { ok: false; reason: string } — Sanitized chat text or a displayable validation failure.
350
351
  - `DEFAULT_CHAT_BODY_LENGTH` (const): const DEFAULT_CHAT_BODY_LENGTH: 240 — ⚠ undocumented
351
352
  - `DEFAULT_CHAT_HISTORY_LIMIT` (const): const DEFAULT_CHAT_HISTORY_LIMIT: 100 — ⚠ undocumented
@@ -359,9 +360,9 @@
359
360
 
360
361
  ## @jgengine/core/game/chatFilter
361
362
 
362
- - `ChatFilter` (interface): interface ChatFilter — ⚠ undocumented
363
- - `ChatFilterConfig` (interface): interface ChatFilterConfig — ⚠ undocumented
364
- - `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
365
366
  - `createChatFilter` (function): function createChatFilter(config: ChatFilterConfig): ChatFilter — ⚠ undocumented
366
367
  - `normalizeChatText` (function): function normalizeChatText(text: string): string — ⚠ undocumented
367
368
 
@@ -400,11 +401,11 @@
400
401
 
401
402
  ## @jgengine/core/game/cosmetics
402
403
 
403
- - `CosmeticLoadoutDef` (interface): interface CosmeticLoadoutDef — ⚠ undocumented
404
- - `Cosmetics` (interface): interface Cosmetics — ⚠ undocumented
405
- - `CosmeticsChangedEvent` (interface): interface CosmeticsChangedEvent — ⚠ undocumented
406
- - `CosmeticsDeps` (interface): interface CosmeticsDeps — ⚠ undocumented
407
- - `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
408
409
  - `createCosmetics` (function): function createCosmetics(deps: CosmeticsDeps = {}): Cosmetics — Equip cosmetic skins and customizations by slot, independent of gameplay stats.
409
410
 
410
411
  ## @jgengine/core/game/credits
@@ -473,51 +474,51 @@
473
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).
474
475
  - `AudioLoopStopEvent` (interface): interface AudioLoopStopEvent — Stop and dispose the retained loop `id`; an unknown `id` is ignored (#1051).
475
476
  - `AudioMusicEvent` (interface): interface AudioMusicEvent — Crossfade the procedural soundtrack to `theme` (null fades out), optionally transposing the incoming theme by `transpose` semitones.
476
- - `AudioPlayEvent` (interface): interface AudioPlayEvent — ⚠ undocumented
477
+ - `AudioPlayEvent` (interface): interface AudioPlayEvent { sound: string; at?: readonly [number, number, number] } — ⚠ undocumented
477
478
  - `AudioResumeEvent` (type): type AudioResumeEvent = Record<string, never> — Request that the shell's audio engine resume its (browser-gesture-suspended) context; carries no payload.
478
- - `ChatMessageEvent` (interface): interface ChatMessageEvent — ⚠ undocumented
479
- - `CombatHitReactionEvent` (interface): interface CombatHitReactionEvent — ⚠ undocumented
480
- - `CombatTelegraphCancelledEvent` (interface): interface CombatTelegraphCancelledEvent — ⚠ undocumented
481
- - `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
482
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).
483
- - `CosmeticsChangedEvent` (interface): interface CosmeticsChangedEvent — ⚠ undocumented
484
+ - `CosmeticsChangedEvent` (interface): interface CosmeticsChangedEvent { userId: string; slots: Record<string, string> } — ⚠ undocumented
484
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.
485
- - `EmotePlayedEvent` (interface): interface EmotePlayedEvent — ⚠ undocumented
486
+ - `EmotePlayedEvent` (interface): interface EmotePlayedEvent { from: string; emoteId: string; at: readonly [number, number, number]; recipients: readonly string[] } — ⚠ undocumented
486
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.
487
- - `EntityDiedEvent` (interface): interface EntityDiedEvent — ⚠ undocumented
488
- - `EntityFloatTextEvent` (interface): interface EntityFloatTextEvent — ⚠ undocumented
489
- - `FormChangedEvent` (interface): interface FormChangedEvent — ⚠ undocumented
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
490
491
  - `GameEventHandler` (type): type GameEventHandler<TPayload> = (payload: TPayload) => void — ⚠ undocumented
491
- - `GameEventMap` (interface): interface GameEventMap — ⚠ undocumented
492
- - `GameEvents` (interface): interface GameEvents<TMap extends GameEventMap = GameEventMap> — ⚠ undocumented
493
- - `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
494
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.
495
- - `LootGrantedEvent` (interface): interface LootGrantedEvent — ⚠ undocumented
496
- - `PossessionSwappedEvent` (interface): interface PossessionSwappedEvent — ⚠ undocumented
497
- - `ProjectileSettledEvent` (interface): interface ProjectileSettledEvent — ⚠ undocumented
498
- - `QuestAcceptedEvent` (interface): interface QuestAcceptedEvent — ⚠ undocumented
499
- - `QuestCompletedEvent` (interface): interface QuestCompletedEvent — ⚠ undocumented
500
- - `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
501
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.
502
- - `SocialFriendAddedEvent` (interface): interface SocialFriendAddedEvent — ⚠ undocumented
503
- - `SocialPartyJoinedEvent` (interface): interface SocialPartyJoinedEvent — ⚠ undocumented
504
- - `SocialPartyLeftEvent` (interface): interface SocialPartyLeftEvent — ⚠ undocumented
505
- - `SocialWorldAcceptedEvent` (interface): interface SocialWorldAcceptedEvent — ⚠ undocumented
506
- - `SocialWorldInvitedEvent` (interface): interface SocialWorldInvitedEvent — ⚠ undocumented
507
- - `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
508
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.
509
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.
510
- - `WorldItemDroppedEvent` (interface): interface WorldItemDroppedEvent — ⚠ undocumented
511
- - `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
512
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.
513
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.
514
515
 
515
516
  ## @jgengine/core/game/feed
516
517
 
517
- - `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…
518
519
  - `FeedWindow` (interface): interface FeedWindow — Bounds for {@link appendFeed} / {@link pruneFeed}: newest-`limit` cap and/or `ttl` age window.
519
- - `GameFeed` (interface): interface GameFeed — ⚠ undocumented
520
- - `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.
521
522
  - `TimedFeedEntry` (interface): interface TimedFeedEntry — Any feed entry carrying a game-time (or wall-clock) `at` stamp for age-based pruning.
522
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.
523
524
  - `appendFeedEntry` (function): function appendFeedEntry<T>(buffer: readonly FeedEntry<T>[], entry: FeedEntry<T>, limit: number): FeedEntry<T>[] — ⚠ undocumented
@@ -544,10 +545,10 @@
544
545
  ## @jgengine/core/game/leaderboard
545
546
 
546
547
  - `IncrementResult` (type): type IncrementResult = { status: "ok"; value: number } | { status: "rejected"; reason: "not-tracked" } — ⚠ undocumented
547
- - `Leaderboard` (interface): interface Leaderboard — ⚠ undocumented
548
- - `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.
549
550
  - `LeaderboardScope` (type): type LeaderboardScope = "global" | "server" | "profile" — ⚠ undocumented
550
- - `LeaderboardTrackDef` (interface): interface LeaderboardTrackDef — ⚠ undocumented
551
+ - `LeaderboardTrackDef` (interface): interface LeaderboardTrackDef { stat?: string; currency?: string; scope: LeaderboardScope } — ⚠ undocumented
551
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.
552
553
 
553
554
  ## @jgengine/core/game/leaderboardRank
@@ -561,31 +562,31 @@
561
562
 
562
563
  ## @jgengine/core/game/levelSequence
563
564
 
564
- - `CurrentLevel` (interface): interface CurrentLevel<TLevelConfig> — ⚠ undocumented
565
- - `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
566
567
  - `LevelRecord` (interface): interface LevelRecord — Persisted per-level outcome: whether it has ever been cleared and the best star rating achieved.
567
- - `LevelSequence` (interface): interface LevelSequence<TLevelConfig> — ⚠ undocumented
568
- - `LevelSequenceConfig` (interface): interface LevelSequenceConfig<TLevelConfig> — ⚠ undocumented
569
- - `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
570
571
  - `LevelSequenceStatus` (type): type LevelSequenceStatus = "idle" | "playing" | "cleared" | "failed" | "complete" — ⚠ undocumented
571
572
  - `LevelStars` (type): type LevelStars = 0 | 1 | 2 | 3 — A level's star rating, 0 (cleared, no stars) to 3.
572
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.
573
574
 
574
575
  ## @jgengine/core/game/loadout
575
576
 
576
- - `LoadoutDef` (interface): interface LoadoutDef — ⚠ undocumented
577
- - `LoadoutDeps` (interface): interface LoadoutDeps — ⚠ undocumented
578
- - `LoadoutInventoryTransaction` (interface): interface LoadoutInventoryTransaction — ⚠ undocumented
579
- - `LoadoutItemEntry` (interface): interface LoadoutItemEntry — ⚠ undocumented
580
- - `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.
581
582
  - `createLoadouts` (function): function createLoadouts(deps: LoadoutDeps): Loadouts — Save, name, and swap equipment loadouts.
582
583
 
583
584
  ## @jgengine/core/game/lootFilter
584
585
 
585
- - `LootFilterCondition` (interface): interface LootFilterCondition — ⚠ undocumented
586
- - `LootFilterItem` (interface): interface LootFilterItem — ⚠ undocumented
587
- - `LootFilterOverride` (interface): interface LootFilterOverride — ⚠ undocumented
588
- - `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.
589
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.
590
591
  - `lootFilter` (function): function lootFilter(rules: readonly LootFilterRule[]): readonly LootFilterRule[] — Validating factory — rule ids must be unique so authoring mistakes fail loudly.
591
592
 
@@ -611,7 +612,7 @@
611
612
 
612
613
  - `Drop` (interface): interface Drop — A resolved loot outcome — one item or currency grant with its rolled count.
613
614
  - `LootEntry` (interface): interface LootEntry — One possible drop in a {@link LootTableDef} — an item, currency, or generated item, its count range, and its odds.
614
- - `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.
615
616
  - `LootRegistryOptions` (interface): interface LootRegistryOptions — Options for {@link createLootRegistry} — inject a default RNG so bare `roll(id)` uses the world stream.
616
617
  - `LootTableDef` (interface): interface LootTableDef — A named, validated loot table — its roll count, weighted-vs-independent mode, and candidate entries.
617
618
  - `createLootRegistry` (function): function createLootRegistry(options: LootRegistryOptions = {}): LootRegistry — Register named loot tables and roll weighted randomized drops from them.
@@ -674,15 +675,15 @@
674
675
 
675
676
  - `DEFAULT_PING_CATEGORIES` (const): const DEFAULT_PING_CATEGORIES: Record<PingCategory, PingCategoryDef> — Content-agnostic default ping wheel: enemy / loot / location / danger.
676
677
  - `PING_FEED_ACTION` (const): const PING_FEED_ACTION: "party.ping" — ⚠ undocumented
677
- - `PingCategory` (type): type PingCategory = string — ⚠ undocumented
678
- - `PingCategoryDef` (interface): interface PingCategoryDef — ⚠ undocumented
679
- - `PingClassifyDeps` (interface): interface PingClassifyDeps — ⚠ undocumented
680
- - `PingClassifyOptions` (interface): interface PingClassifyOptions — ⚠ undocumented
681
- - `PingFeedSink` (interface): interface PingFeedSink — ⚠ undocumented
682
- - `PingParty` (interface): interface PingParty — ⚠ undocumented
683
- - `PingPayload` (interface): interface PingPayload — ⚠ undocumented
684
- - `PingSystem` (interface): interface PingSystem — ⚠ undocumented
685
- - `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.
686
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.
687
688
  - `createPingSystem` (function): function createPingSystem(deps: PingSystemDeps): PingSystem — Contextual ping/marker communication between teammates, classified by what was pinged.
688
689
 
@@ -695,26 +696,27 @@
695
696
 
696
697
  ## @jgengine/core/game/playableGame
697
698
 
698
- - `AmbientLightingConfig` (interface): interface AmbientLightingConfig — ⚠ undocumented
699
+ - `AmbientLightingConfig` (interface): interface AmbientLightingConfig { color?: string; intensity?: number } — ⚠ undocumented
699
700
  - `BackdropConfig` (interface): interface BackdropConfig — Generic sky/background/fog for ANY world kind, including a custom `environment` component (#207.6).
700
- - `BackdropFogConfig` (interface): interface BackdropFogConfig — ⚠ undocumented
701
+ - `BackdropFogConfig` (interface): interface BackdropFogConfig { color?: string; near?: number; far?: number; density?: number } — ⚠ undocumented
701
702
  - `CAMERA_FRUSTUM_DEFAULTS` (const): const CAMERA_FRUSTUM_DEFAULTS: { readonly fov: 55; readonly near: 0.1; readonly far: 300; readonly zoom: 50; } — ⚠ undocumented
702
- - `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
703
704
  - `CameraKeyframe` (interface): interface CameraKeyframe — One stop on a scripted camera path (#29).
704
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".
705
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.
706
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`.
707
709
  - `ChaseCameraConfig` (interface): interface ChaseCameraConfig — Speed-reactive vehicle chase rig (#27) — speed→FOV, spring arm, procedural shake, interior views.
708
710
  - `ChaseView` (type): type ChaseView = "chase" | "cockpit" | "hood" | "rear" — Fixed interior view for the chase rig (#27).
709
711
  - `CinematicCameraConfig` (interface): interface CinematicCameraConfig — Scripted keyframe / path player (#29). When set it overrides the active rig.
710
- - `DirectionalLightingConfig` (interface): interface DirectionalLightingConfig — ⚠ undocumented
711
- - `EntitySpriteConfig` (interface): interface EntitySpriteConfig — ⚠ undocumented
712
- - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig — ⚠ undocumented
713
- - `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 stay on `flightDynamics`.
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`.
714
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.
715
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.
716
718
  - `GameCaptureView` (interface): interface GameCaptureView — How a screenshot host reaches live gameplay in this game — the data behind `shoot --mode play`.
717
- - `HemisphereLightingConfig` (interface): interface HemisphereLightingConfig — ⚠ undocumented
719
+ - `HemisphereLightingConfig` (interface): interface HemisphereLightingConfig { skyColor?: string; groundColor?: string; intensity?: number } — ⚠ undocumented
718
720
  - `InspectionCameraConfig` (interface): interface InspectionCameraConfig — Model-viewer / inspection rig (#207.7) — orbit + pan + anchored zoom around a fixed point, never reads player input.
719
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.
720
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.
@@ -722,19 +724,21 @@
722
724
  - `ModelAnimationConfig` (interface): interface ModelAnimationConfig — Rig playback for a `ModelConfig`'s GLTF animation clips — looping idles, one-shots, and held poses.
723
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.
724
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.
725
- - `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}.
726
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.
727
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.
728
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.
729
732
  - `ModelRimLight` (interface): interface ModelRimLight — Fresnel rim-light term added on top of a model's lighting — see {@link ModelMaterialOverride.rim}.
730
733
  - `MovementCommitFrame` (interface): interface MovementCommitFrame — One frame's movement resolution handed to `PlayerMovementConfig.beforeCommit`.
731
- - `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
732
736
  - `ObserverCameraConfig` (interface): interface ObserverCameraConfig — Detached spectator/photo cam (#120) — binds to any entity or fixed point, never reads player input.
733
- - `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…
734
738
  - `PlayerFovConfig` (interface): interface PlayerFovConfig — Player-facing FOV preference applied across every perspective camera rig. Orthographic projections ignore it.
735
739
  - `PlayerMovementConfig` (interface): interface PlayerMovementConfig — Movement-control levers for the shell-driven local player walk controller.
736
740
  - `PointLightingConfig` (interface): interface PointLightingConfig — A bounded dynamic point light in world space.
737
- - `PointerConfig` (interface): interface PointerConfig — ⚠ undocumented
741
+ - `PointerConfig` (interface): interface PointerConfig — Mouse/touch pointer bindings for `defineGame({ pointer })`.
738
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.
739
743
  - `RtsCameraConfig` (interface): interface RtsCameraConfig extends TopDownCameraConfig — Free-pan / edge-scroll RTS rig (#24) — pan/rotate/zoom independent of any avatar.
740
744
  - `ShoulderCameraConfig` (interface): interface ShoulderCameraConfig — Over-the-shoulder combat rig (#25) — offset, ADS, shoulder swap, decoupled reticle.
@@ -743,7 +747,7 @@
743
747
  - `TopDownCameraConfig` (interface): interface TopDownCameraConfig — Fixed top-down / isometric rig (#23) — height/pitch/yaw + decoupled follow.
744
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`.
745
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.
746
- - `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`.
747
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.
748
752
  - `worldHealthBarAllowsRole` (function): function worldHealthBarAllowsRole(roles: readonly CatalogEntityRole[] | undefined, role: CatalogEntityRole | undefined): boolean — ⚠ undocumented
749
753
 
@@ -762,18 +766,18 @@
762
766
 
763
767
  ## @jgengine/core/game/quest
764
768
 
765
- - `QuestAcceptOptions` (interface): interface QuestAcceptOptions — ⚠ undocumented
766
- - `QuestDef` (interface): interface QuestDef — ⚠ undocumented
767
- - `QuestEvaluator` (interface): interface QuestEvaluator — ⚠ undocumented
768
- - `QuestInstance` (interface): interface QuestInstance — ⚠ undocumented
769
- - `QuestJournal` (interface): interface QuestJournal — ⚠ undocumented
770
- - `QuestJournalDeps` (interface): interface QuestJournalDeps — ⚠ undocumented
771
- - `QuestObjective` (interface): interface QuestObjective — ⚠ undocumented
772
- - `QuestObjectiveProgress` (interface): interface QuestObjectiveProgress — ⚠ undocumented
773
- - `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
774
778
  - `QuestSnapshotEntry` (type): type QuestSnapshotEntry = { questId: string; status: QuestStatus; progress: Record<string, number>; } — ⚠ undocumented
775
779
  - `QuestStatus` (type): type QuestStatus = "active" | "completed" — ⚠ undocumented
776
- - `QuestTurnIn` (interface): interface QuestTurnIn — ⚠ undocumented
780
+ - `QuestTurnIn` (interface): interface QuestTurnIn { state: QuestSnapshotEntry[]; rewards: QuestRewards | null } — ⚠ undocumented
777
781
  - `TrackedObjectiveView` (interface): interface TrackedObjectiveView — One objective as a tracker/HUD reads it — label + progress toward its count.
778
782
  - `TrackedQuestView` (interface): interface TrackedQuestView — A quest as a tracker/HUD reads it — title, status, and per-objective progress.
779
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
@@ -784,24 +788,24 @@
784
788
 
785
789
  ## @jgengine/core/game/race
786
790
 
787
- - `Checkpoint` (interface): interface Checkpoint — ⚠ undocumented
791
+ - `Checkpoint` (interface): interface Checkpoint { id: string; center: readonly [number, number, number]; half: readonly [number, number, number] } — ⚠ undocumented
788
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.
789
793
  - `LapTimerSnapshot` (interface): interface LapTimerSnapshot — Wall-clock lap timing: the current/last/best/total split-book every racing HUD reads.
790
794
  - `PlacementOptions` (interface): interface PlacementOptions — Options for {@link racePlacements} / {@link placementOf} / {@link raceOutcomeOf}.
791
795
  - `RaceCountdownOptions` (interface): interface RaceCountdownOptions — Options for {@link startRaceCountdown}.
792
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
793
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.
794
- - `RaceForkRoute` (interface): interface RaceForkRoute — ⚠ undocumented
798
+ - `RaceForkRoute` (interface): interface RaceForkRoute { id: string; checkpoints: readonly Checkpoint[] } — ⚠ undocumented
795
799
  - `RaceOutcome` (type): type RaceOutcome = "win" | "lose" — Whether a racer won or lost, derived from where they placed against the winning-places cutoff.
796
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.
797
801
  - `RacePlacement` (interface): interface RacePlacement — A racer's finishing position (`place`, 1-based) in a finish order, and the {@link RaceOutcome} it earns.
798
802
  - `RaceSessionState` (interface): interface RaceSessionState — Immutable lifecycle snapshot: the current {@link RacePhase} plus the two clocks it owns.
799
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.
800
- - `RaceStateConfig` (interface): interface RaceStateConfig — ⚠ undocumented
801
- - `RaceTrack` (interface): interface RaceTrack — ⚠ undocumented
802
- - `RaceTrackConfig` (interface): interface RaceTrackConfig — ⚠ undocumented
803
- - `RaceWinCondition` (type): type RaceWinCondition = (standings: readonly RacerProgress[], track: RaceTrack) => readonly string[] | null — ⚠ undocumented
804
- - `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
805
809
  - `createLapTimer` (function): function createLapTimer(): LapTimer — Create a {@link LapTimer} starting at lap 0 with no splits, best, or last time recorded.
806
810
  - `createRaceState` (function): function createRaceState(config: RaceStateConfig): RaceState — A checkpoint race state machine — laps, forks, live standings, splits, and pluggable win conditions.
807
811
  - `everyoneFinishes` (function): function everyoneFinishes(): RaceWinCondition — Every non-eliminated racer must finish.
@@ -822,11 +826,11 @@
822
826
 
823
827
  ## @jgengine/core/game/recordBook
824
828
 
825
- - `RecordBook` (interface): interface RecordBook<K extends string> — ⚠ undocumented
826
- - `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…
827
831
  - `RecordDirection` (type): type RecordDirection = "lower" | "higher" — ⚠ undocumented
828
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`).
829
- - `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
830
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.
831
835
 
832
836
  ## @jgengine/core/game/ruleSelection
@@ -841,11 +845,11 @@
841
845
 
842
846
  ## @jgengine/core/game/runDraft
843
847
 
844
- - `RunDraft` (interface): interface RunDraft<TStat extends string = string, TData = unknown> — ⚠ undocumented
845
- - `RunDraftConfig` (interface): interface RunDraftConfig<TStat extends string = string, TData = unknown> — ⚠ undocumented
846
- - `RunModifierOffer` (interface): interface RunModifierOffer<TStat extends string = string, TData = unknown> — ⚠ undocumented
847
- - `RunModifierPick` (interface): interface RunModifierPick — ⚠ undocumented
848
- - `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
849
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.
850
854
  - `createRunModifierStack` (function): function createRunModifierStack<TStat extends string = string, TData = unknown>(offers: readonly RunModifierOffer<TStat, TData>[]): RunModifierStack<TStat, TData> — ⚠ undocumented
851
855
 
@@ -881,35 +885,35 @@
881
885
  ## @jgengine/core/game/social
882
886
 
883
887
  - `DEFAULT_EMOTE_RADIUS` (const): const DEFAULT_EMOTE_RADIUS: 20 — ⚠ undocumented
884
- - `EmoteBroadcastResult` (interface): interface EmoteBroadcastResult — ⚠ undocumented
885
- - `EmoteEntityLookup` (interface): interface EmoteEntityLookup — ⚠ undocumented
886
- - `EmoteSpatialLookup` (interface): interface EmoteSpatialLookup — ⚠ undocumented
887
- - `Emotes` (interface): interface Emotes — ⚠ undocumented
888
- - `EmotesDeps` (interface): interface EmotesDeps — ⚠ undocumented
889
- - `FriendEntry` (interface): interface FriendEntry — ⚠ undocumented
890
- - `FriendRequestEntry` (interface): interface FriendRequestEntry — ⚠ undocumented
891
- - `Friends` (interface): interface Friends — ⚠ undocumented
892
- - `FriendsSnapshot` (interface): interface FriendsSnapshot — ⚠ undocumented
893
- - `Party` (interface): interface Party — ⚠ undocumented
894
- - `PartyConfig` (interface): interface PartyConfig — ⚠ undocumented
895
- - `PartyInviteEntry` (interface): interface PartyInviteEntry — ⚠ undocumented
896
- - `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
897
901
  - `PartyRole` (type): type PartyRole = "leader" | "member" — ⚠ undocumented
898
- - `PresenceInfo` (interface): interface PresenceInfo — ⚠ undocumented
899
- - `Social` (interface): interface Social — ⚠ undocumented
900
- - `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.
901
905
  - `SocialPartySnapshot` (interface): interface SocialPartySnapshot — One party's replicated membership — id, current leader, and ordered member ids.
902
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.
903
- - `WorldInvite` (interface): interface WorldInvite extends WorldInviteTarget — ⚠ undocumented
904
- - `WorldInviteTarget` (interface): interface WorldInviteTarget — ⚠ undocumented
905
- - `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
906
910
  - `createSocial` (function): function createSocial(deps: SocialDeps): Social — Emotes and lightweight social interactions between nearby players.
907
911
 
908
912
  ## @jgengine/core/game/spawnPoints
909
913
 
910
- - `RespawnTarget` (interface): interface RespawnTarget — ⚠ undocumented
911
- - `SpawnPointPose` (interface): interface SpawnPointPose — ⚠ undocumented
912
- - `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.
913
917
  - `createSpawnPoints` (function): function createSpawnPoints(): SpawnPoints — Register spawn locations and choose where entities spawn or respawn.
914
918
 
915
919
  ## @jgengine/core/game/systemRuntime
@@ -936,14 +940,14 @@
936
940
 
937
941
  ## @jgengine/core/game/talents
938
942
 
939
- - `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
940
944
  - `TalentAllocateReason` (type): type TalentAllocateReason = "unknown-node" | "max-rank" | "no-points" | "requires" | "branch-points" — ⚠ undocumented
941
945
  - `TalentAllocateResult` (type): type TalentAllocateResult = { ok: true } | { ok: false; reason: TalentAllocateReason } — ⚠ undocumented
942
- - `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…
943
947
  - `TalentRequirement` (type): type TalentRequirement = string | { nodeId: string; rank: number } — ⚠ undocumented
944
- - `TalentSnapshot` (interface): interface TalentSnapshot — ⚠ undocumented
945
- - `TalentTree` (interface): interface TalentTree<TStat extends string = string> — ⚠ undocumented
946
- - `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
947
951
  - `createTalentTree` (function): function createTalentTree<TStat extends string = string>(config: TalentTreeConfig<TStat>): TalentTree<TStat> — ⚠ undocumented
948
952
 
949
953
  ## @jgengine/core/game/toasts
@@ -951,21 +955,22 @@
951
955
  - `Toast` (interface): interface Toast<T = string> — A transient HUD message that expires on its own — banner, pickup note, alert.
952
956
  - `ToastQueue` (interface): interface ToastQueue<T = string> — Stateful transient-toast list with a size cap and time-to-live eviction.
953
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.
954
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.
955
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.
956
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.
957
962
 
958
963
  ## @jgengine/core/game/trade
959
964
 
960
- - `TradeField` (interface): interface TradeField — ⚠ undocumented
961
- - `TradeInventory` (interface): interface TradeInventory — ⚠ undocumented
962
- - `TradeOutcome` (interface): interface TradeOutcome — ⚠ undocumented
963
- - `TradeParty` (interface): interface TradeParty — ⚠ undocumented
964
- - `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
965
970
  - `TradeResolution` (type): type TradeResolution = | { status: "ok"; outcome: TradeOutcome } | { status: "rejected"; reason: string } — ⚠ undocumented
966
- - `TradeSystem` (interface): interface TradeSystem — ⚠ undocumented
967
- - `TradeSystemDeps` (interface): interface TradeSystemDeps — ⚠ undocumented
968
- - `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
969
974
 
970
975
  ## @jgengine/core/game/tribe
971
976
 
@@ -989,10 +994,10 @@
989
994
 
990
995
  ## @jgengine/core/game/unlocks
991
996
 
992
- - `UnlockCatalog` (interface): interface UnlockCatalog — ⚠ undocumented
993
- - `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.
994
999
  - `UnlockState` (type): type UnlockState = readonly string[] — ⚠ undocumented
995
- - `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
996
1001
  - `createUnlockCatalog` (function): function createUnlockCatalog(defs: readonly UnlockDef[] = []): UnlockCatalog — A catalog of unlockable content gated behind conditions the player earns, tracking what is unlocked.
997
1002
  - `createUnlocks` (function): function createUnlocks(defs: UnlockDef[] = []): Unlocks — ⚠ undocumented
998
1003
  - `grantUnlock` (function): function grantUnlock(granted: UnlockState, unlockId: string): string[] — ⚠ undocumented
@@ -1008,23 +1013,35 @@
1008
1013
  - `VfxInstanceStopOptions` (interface): interface VfxInstanceStopOptions — Options for {@link VfxInstanceStore.stop}.
1009
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.
1010
1015
  - `VfxInstanceStoreOptions` (interface): interface VfxInstanceStoreOptions — Options for {@link createVfxInstanceStore}.
1016
+ - `VfxInstanceStoreState` (interface): interface VfxInstanceStoreState — Plain JSON state of a {@link VfxInstanceStore}.
1011
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.
1012
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
+
1013
1030
  ## @jgengine/core/game/worldItem
1014
1031
 
1015
1032
  - `DEFAULT_PICKUP_RADIUS` (const): const DEFAULT_PICKUP_RADIUS: 2 — ⚠ undocumented
1016
1033
  - `DEFAULT_RARITY` (const): const DEFAULT_RARITY: "common" — ⚠ undocumented
1017
1034
  - `DEFAULT_SCATTER` (const): const DEFAULT_SCATTER: ScatterOptions — ⚠ undocumented
1018
- - `RarityStyle` (interface): interface RarityStyle — ⚠ undocumented
1019
- - `ResolveDeathDropsOptions` (interface): interface ResolveDeathDropsOptions — ⚠ undocumented
1020
- - `ResolvedDeathDrops` (interface): interface ResolvedDeathDrops — ⚠ undocumented
1021
- - `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
1022
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).
1023
- - `WorldItemPresentation` (interface): interface WorldItemPresentation — ⚠ undocumented
1024
- - `WorldItemRecord` (interface): interface WorldItemRecord — ⚠ undocumented
1025
- - `WorldItemSpawnInput` (interface): interface WorldItemSpawnInput — ⚠ undocumented
1026
- - `WorldItemStore` (interface): interface WorldItemStore — ⚠ undocumented
1027
- - `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
1028
1045
 
1029
1046
  ## @jgengine/core/gameplay
1030
1047
 
@@ -1035,41 +1052,41 @@
1035
1052
  - `AchievementUnlock` (interface): interface AchievementUnlock — Emitted the instant an achievement unlocks — wire to a toast, feed, or sound.
1036
1053
  - `AchievementView` (interface): interface AchievementView extends AchievementDef — A definition plus its live unlock/progress state — what UI renders.
1037
1054
  - `ActionCodes` (type): type ActionCodes<TCode extends string = string> = | readonly TCode[] | { hold?: readonly TCode[]; toggle?: readonly TCode[]; repeatMs?: number } — ⚠ undocumented
1038
- - `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.
1039
- - `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…
1040
1057
  - `ActiveEffect` (interface): interface ActiveEffect — A live timed effect an engine is tracking until it expires or is cleaned up.
1041
1058
  - `AdvanceOptions` (interface): interface AdvanceOptions — Per-advance settings: the policy pipeline, caller context, rounding, and safety bounds.
1042
1059
  - `AdvanceResult` (interface): interface AdvanceResult — The outcome of {@link advanceLedger}: the new ledger plus applied transactions and events.
1043
- - `AffixPool` (interface): interface AffixPool — ⚠ undocumented
1060
+ - `AffixPool` (interface): interface AffixPool { id: string; affixes: readonly AffixDef[] } — ⚠ undocumented
1044
1061
  - `AppliedTransaction` (type): type AppliedTransaction = ResourceTransaction — A {@link ResourceTransaction} after policies and rounding, as actually applied to balances.
1045
1062
  - `Auction` (interface): interface Auction — One live timed auction in an {@link AuctionBook}: an item stack under open bidding until it closes.
1046
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}.
1047
- - `AxisBindingMap` (type): type AxisBindingMap = Record<AxisName, AxisBinding> — ⚠ undocumented
1048
- - `AxisChannelConfig` (interface): interface AxisChannelConfig — ⚠ undocumented
1049
- - `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 …
1050
1067
  - `BackdropConfig` (interface): interface BackdropConfig — Generic sky/background/fog for ANY world kind, including a custom `environment` component (#207.6).
1051
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.
1052
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.
1053
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.
1054
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.
1055
- - `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
1056
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.
1057
1074
  - `CAMERA_FRUSTUM_DEFAULTS` (const): const CAMERA_FRUSTUM_DEFAULTS: { readonly fov: 55; readonly near: 0.1; readonly far: 300; readonly zoom: 50; } — ⚠ undocumented
1058
1075
  - `CameraKeyframe` (interface): interface CameraKeyframe — One stop on a scripted camera path (#29).
1059
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.
1060
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.
1061
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.
1062
- - `CardPile` (interface): interface CardPile — ⚠ undocumented
1063
- - `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…
1064
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).
1065
1082
  - `Cell` (type): type Cell = readonly [number, number] — ⚠ undocumented
1066
- - `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.
1067
1084
  - `ChargeOptions` (interface): interface ChargeOptions — Options for {@link charge}/{@link chargeAll}: opt one call into overdraft debt via `overdraft`.
1068
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`.
1069
1086
  - `ChaseCameraConfig` (interface): interface ChaseCameraConfig — Speed-reactive vehicle chase rig (#27) — speed→FOV, spring arm, procedural shake, interior views.
1070
- - `Chat` (interface): interface Chat — ⚠ undocumented
1071
- - `ChatMessage` (interface): interface ChatMessage — ⚠ undocumented
1072
- - `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
1073
1090
  - `ChatSendResult` (type): type ChatSendResult = | { message: ChatMessage; recipients: ChatRecipients } | { reason: string } — ⚠ undocumented
1074
1091
  - `CinematicCameraConfig` (interface): interface CinematicCameraConfig — Scripted keyframe / path player (#29). When set it overrides the active rig.
1075
1092
  - `Codex` (interface): interface Codex<TMeta = unknown> — A codex/bestiary of defined entries with per-player discovery tracking.
@@ -1077,7 +1094,7 @@
1077
1094
  - `CodexEntryView` (interface): interface CodexEntryView<TMeta = unknown> extends CodexEntryDef<TMeta> — A definition plus its discovery state — what UI renders.
1078
1095
  - `CodexOptions` (interface): interface CodexOptions<TMeta = unknown> — Options for {@link createCodex}.
1079
1096
  - `CodexSnapshot` (interface): interface CodexSnapshot — Serializable discovery state — a save blob.
1080
- - `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
1081
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).
1082
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.
1083
1100
  - `CompatibilityRule` (type): type CompatibilityRule = RequireRule | ForbidRule — A cross-slot compatibility rule constraining which part/tag/family combinations a modular item may hold.
@@ -1085,8 +1102,8 @@
1085
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.
1086
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.
1087
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.
1088
- - `CropDef` (interface): interface CropDef — ⚠ undocumented
1089
- - `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
1090
1107
  - `CrossThresholdsOptions` (interface): interface CrossThresholdsOptions — Exact-boundary and dead-band policy for {@link crossThresholds}.
1091
1108
  - `Curve` (type): type Curve = CurveDef & CurveShape — A fully specified progression curve — a {@link CurveDef} growth shape plus optional {@link CurveShape} rounding/clamp.
1092
1109
  - `DEFAULT_CHAT_BODY_LENGTH` (const): const DEFAULT_CHAT_BODY_LENGTH: 240 — ⚠ undocumented
@@ -1100,8 +1117,8 @@
1100
1117
  - `DecayMeterSet` (interface): interface DecayMeterSet — Set of named survival meters (hunger/thirst/…) that drain and refill over game time.
1101
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.
1102
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.
1103
- - `DeliveryEntry` (interface): interface DeliveryEntry — ⚠ undocumented
1104
- - `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
1105
1122
  - `DialogueGraph` (interface): interface DialogueGraph — A serializable branching conversation: a start node id and the nodes it can reach.
1106
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).
1107
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.
@@ -1109,35 +1126,35 @@
1109
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.
1110
1127
  - `DialogueRun` (interface): interface DialogueRun — An observable walk through a {@link DialogueGraph}: current view, choose to advance, serialize.
1111
1128
  - `DialogueRunOptions` (interface): interface DialogueRunOptions — Options for {@link createDialogueRun}.
1112
- - `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
1113
1130
  - `Drop` (interface): interface Drop — A resolved loot outcome — one item or currency grant with its rolled count.
1114
- - `DurabilitySpec` (interface): interface DurabilitySpec — ⚠ undocumented
1115
- - `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.
1116
1133
  - `EffectRef` (interface): interface EffectRef — A reference to an effect the game knows how to apply — id plus JSON-safe params, no closures.
1117
1134
  - `EnqueueOptions` (interface): interface EnqueueOptions — Optional per-enqueue overrides.
1118
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.
1119
- - `EntityDiedEvent` (interface): interface EntityDiedEvent — ⚠ undocumented
1120
- - `EntityFloatTextEvent` (interface): interface EntityFloatTextEvent — ⚠ undocumented
1121
- - `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
1122
1139
  - `EventTicker` (interface): interface EventTicker — A live, observable event/kill-feed ticker.
1123
1140
  - `EventTickerEntry` (interface): interface EventTickerEntry extends TimedFeedEntry — A stored ticker entry — an {@link EventTickerInput} stamped with an id and clock time.
1124
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", …).
1125
1142
  - `EventTickerOptions` (interface): interface EventTickerOptions — Options for {@link createEventTicker}.
1126
1143
  - `EventTickerSnapshot` (interface): interface EventTickerSnapshot — Serializable state of the ticker, for save/restore.
1127
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.
1128
- - `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…
1129
1146
  - `FeedWindow` (interface): interface FeedWindow — Bounds for {@link appendFeed} / {@link pruneFeed}: newest-`limit` cap and/or `ttl` age window.
1130
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.
1131
- - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig — ⚠ undocumented
1148
+ - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig { eyeHeight?: number; sensitivity?: number; maxPitch?: number; reticle?: boolean; viewmodel?: boolean } — ⚠ undocumented
1132
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.
1133
- - `FriendEntry` (interface): interface FriendEntry — ⚠ undocumented
1134
- - `FriendRequestEntry` (interface): interface FriendRequestEntry — ⚠ undocumented
1135
- - `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
1136
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.
1137
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.
1138
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.
1139
- - `GameEventMap` (interface): interface GameEventMap — ⚠ undocumented
1140
- - `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.
1141
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).
1142
1159
  - `GameLoop` (interface): interface GameLoop<TContext = unknown> — Lifecycle hooks a game implements to drive init, per-tick simulation, and player join/leave.
1143
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.
@@ -1158,40 +1175,40 @@
1158
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).
1159
1176
  - `InspectionCameraConfig` (interface): interface InspectionCameraConfig — Model-viewer / inspection rig (#207.7) — orbit + pan + anchored zoom around a fixed point, never reads player input.
1160
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.
1161
- - `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.
1162
1179
  - `InventoryDeclaration` (interface): interface InventoryDeclaration — Shape of one named inventory a game declares — slot count, accepted item types, HUD binding.
1163
1180
  - `InventorySlot` (type): type InventorySlot = { itemId: string; count: number } | null — ⚠ undocumented
1164
- - `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.
1165
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`).
1166
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.
1167
- - `ItemUseHandler` (interface): interface ItemUseHandler<TState> — ⚠ undocumented
1168
- - `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
1169
1186
  - `Job` (interface): interface Job<TSpec, TReserve = undefined> — One unit of timed work. Plain serializable data (given serializable `TSpec`/`TReserve`).
1170
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.
1171
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.
1172
1189
  - `JobStatus` (type): type JobStatus = "queued" | "active" | "paused" — Lifecycle phase of a single queued job. Terminal jobs are removed from state.
1173
1190
  - `JobValidation` (interface): interface JobValidation — Result of pre-enqueue validation (population caps, prerequisites, affordability).
1174
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.
1175
- - `LaneRule` (interface): interface LaneRule<C> — ⚠ undocumented
1192
+ - `LaneRule` (interface): interface LaneRule<C> { id: string; apply: (input: LaneRuleInput<C>) => number } — ⚠ undocumented
1176
1193
  - `LayerConflict` (interface): interface LayerConflict — A single conflict surfaced by {@link validateLayers}.
1177
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.
1178
1195
  - `LayerRegistry` (interface): interface LayerRegistry — Registered lookup of {@link ParamLayer}s by stable id, resolving serialized selections and unknowns.
1179
1196
  - `LayerSelection` (type): type LayerSelection = readonly string[] — A serializable, ordered reference to layers by stable id — what a save file or session setup stores.
1180
- - `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.
1181
1198
  - `LeaderboardScope` (type): type LeaderboardScope = "global" | "server" | "profile" — ⚠ undocumented
1182
1199
  - `LedgerEvent` (interface): interface LedgerEvent — Lifecycle signal emitted by {@link advanceLedger}.
1183
1200
  - `LedgerEventKind` (type): type LedgerEventKind = "started" | "fired" | "skipped" | "depleted" | "ended" — The kinds of lifecycle signal {@link advanceLedger} can emit for a rule.
1184
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.
1185
- - `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…
1186
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).
1187
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.
1188
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.
1189
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.
1190
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.
1191
- - `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
1192
1209
  - `LockOnCameraConfig` (interface): interface LockOnCameraConfig — Lock-on / strafe rig (#26) — yaw bound to player→target, move axis becomes strafe.
1193
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.
1194
- - `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.
1195
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.
1196
1213
  - `LootPipeline` (interface): interface LootPipeline<TCtx = unknown> — A resolved, reusable loot pipeline. Call {@link LootPipeline.resolve} with a per-drop context and RNG.
1197
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.
@@ -1205,13 +1222,13 @@
1205
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.
1206
1223
  - `LootStageTrace` (interface): interface LootStageTrace — Per-stage record of what happened during resolution, for debugging and replay auditing.
1207
1224
  - `LootTableDef` (interface): interface LootTableDef — A named, validated loot table — its roll count, weighted-vs-independent mode, and candidate entries.
1208
- - `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`).
1209
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.
1210
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.
1211
- - `ModularItemDef` (interface): interface ModularItemDef — ⚠ undocumented
1228
+ - `ModularItemDef` (interface): interface ModularItemDef { id: string; baseStats: Record<string, number>; slots: readonly MountSlotDef[] } — ⚠ undocumented
1212
1229
  - `Moodle` (interface): interface Moodle — One survival moodle (status icon) — severity, source, and label for HUD chips.
1213
1230
  - `MoodleStack` (interface): interface MoodleStack — Ordered stack of active moodles derived from meters/ailments/buffs.
1214
- - `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.
1215
1232
  - `MultiRegionHealth` (interface): interface MultiRegionHealth — Per-limb / per-region health track with treat/damage/heal APIs.
1216
1233
  - `NEUTRAL_AXIS` (const): const NEUTRAL_AXIS: AxisInput — ⚠ undocumented
1217
1234
  - `NotificationCenterOptions` (interface): interface NotificationCenterOptions — Options for {@link createNotificationCenter}.
@@ -1220,7 +1237,7 @@
1220
1237
  - `NotificationInput` (interface): interface NotificationInput<TMeta = unknown> — Fields accepted by {@link NotificationStore.push}.
1221
1238
  - `NotificationStore` (interface): interface NotificationStore<TMeta = unknown> — Serializable, observable log of persistent notifications with read tracking.
1222
1239
  - `NumericBounds` (interface): interface NumericBounds — Optional inclusive `[min, max]` clamp applied after a write. Omit an edge for unbounded.
1223
- - `ObjectStyle` (interface): interface ObjectStyle — ⚠ undocumented
1240
+ - `ObjectStyle` (interface): interface ObjectStyle { color?: string; opacity?: number; hidden?: boolean } — ⚠ undocumented
1224
1241
  - `ObserverCameraConfig` (interface): interface ObserverCameraConfig — Detached spectator/photo cam (#120) — binds to any entity or fixed point, never reads player input.
1225
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.
1226
1243
  - `PING_FEED_ACTION` (const): const PING_FEED_ACTION: "party.ping" — ⚠ undocumented
@@ -1231,18 +1248,18 @@
1231
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.
1232
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.
1233
1250
  - `ParamSnapshot` (interface): interface ParamSnapshot — A resolved effective-parameter snapshot: final `values` plus the ordered op trace per parameter.
1234
- - `PartDef` (interface): interface PartDef — ⚠ undocumented
1235
- - `Party` (interface): interface Party — ⚠ undocumented
1236
- - `PartyInviteEntry` (interface): interface PartyInviteEntry — ⚠ undocumented
1237
- - `PartyMemberEntry` (interface): interface PartyMemberEntry — ⚠ 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
1238
1255
  - `PhysicsConfig` (interface): interface PhysicsConfig — World gravity and jump tuning, plus the optional rigid-body backend and character capsule.
1239
- - `PingCategory` (type): type PingCategory = string — ⚠ undocumented
1240
- - `PingSystem` (interface): interface PingSystem — ⚠ undocumented
1241
- - `PlayableGame` (interface): interface PlayableGame<TUi = unknown, TWorldOverlay = unknown, TRenderEntity = never, TRenderObject = never, TViewmodel = unknown, TOverlay = TWorldOverlay> — ⚠ undocumented
1242
- - `PointerAxisState` (interface): interface PointerAxisState — ⚠ undocumented
1243
- - `PointerConfig` (interface): interface PointerConfig — ⚠ undocumented
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 })`.
1244
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.
1245
- - `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.
1246
1263
  - `PolicyContext` (interface): interface PolicyContext — Read-only context handed to every {@link ResourcePolicy} for a transaction.
1247
1264
  - `PolicyRead` (type): type PolicyRead = string | ((ctx: PolicyContext) => number) — Reader over policy context: a `vars` key or a function of the context.
1248
1265
  - `Precision` (interface): interface Precision — Deterministic rounding applied to every transaction amount before it touches balances.
@@ -1250,16 +1267,16 @@
1250
1267
  - `PredicateFacts` (type): type PredicateFacts = Record<string, unknown> — Plain, serializable bag of facts a predicate reads by dot path.
1251
1268
  - `PredicatePath` (type): type PredicatePath = string — Dot path into a fact bag, e.g. `"hit.crit"` or `"attacker.team"`.
1252
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.
1253
- - `PresenceInfo` (interface): interface PresenceInfo — ⚠ undocumented
1270
+ - `PresenceInfo` (interface): interface PresenceInfo { online: boolean; serverId?: string; zoneId?: string; instanceId?: string } — ⚠ undocumented
1254
1271
  - `PriceStats` (interface): interface PriceStats — Aggregated market stats for one item over the retained samples.
1255
- - `QuestDef` (interface): interface QuestDef — ⚠ undocumented
1256
- - `QuestInstance` (interface): interface QuestInstance — ⚠ undocumented
1257
- - `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
1258
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.
1259
1276
  - `RankLeaderboardOptions` (interface): interface RankLeaderboardOptions — Options for {@link rankLeaderboard}. All optional.
1260
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.
1261
1278
  - `RankedEntry` (interface): interface RankedEntry — One render-ready row of the ranked table produced by {@link rankLeaderboard}.
1262
- - `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 } })`.
1263
1280
  - `RateLimit` (interface): interface RateLimit — Bounded firing budget over a sliding time window.
1264
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.
1265
1282
  - `RebindConflict` (interface): interface RebindConflict — A group of actions bound to the same normalized code — the conflict this session detects.
@@ -1269,21 +1286,21 @@
1269
1286
  - `RebindSessionConfig` (type): type RebindSessionConfig = RebindSessionActionsConfig | RebindSessionMapConfig — Config for {@link createRebindSession}: an explicit action list, or an {@link ActionCodesMap} + labels.
1270
1287
  - `RebindSessionMapConfig` (interface): interface RebindSessionMapConfig extends RebindSessionCommon — Declare actions from an authored {@link ActionCodesMap}, labelled by `labels` (falling back to the id).
1271
1288
  - `RebindSessionSnapshot` (interface): interface RebindSessionSnapshot — Serializable session state for save/restore.
1272
- - `RecipeDef` (interface): interface RecipeDef — ⚠ undocumented
1273
- - `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
1274
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.
1275
1292
  - `ResourceCost` (type): type ResourceCost = Readonly<Record<string, number>> — Resource costs keyed by currency/resource id.
1276
1293
  - `ResourceLedger` (interface): interface ResourceLedger — Fully serializable scheduled-transaction state: clock, balances, rule definitions, and cursors.
1277
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.
1278
1295
  - `ResourceTransaction` (interface): interface ResourceTransaction — One resource movement produced by a due cycle, before it is applied to balances.
1279
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.
1280
- - `Ring` (interface): interface Ring — ⚠ undocumented
1281
- - `RingConfig` (interface): interface RingConfig — ⚠ undocumented
1282
- - `RingPhase` (interface): interface RingPhase — ⚠ undocumented
1283
- - `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
1284
1301
  - `Rotation` (type): type Rotation = 0 | 1 | 2 | 3 — ⚠ undocumented
1285
- - `RoundConfig` (interface): interface RoundConfig<TPhase extends string = RoundPhase> — ⚠ undocumented
1286
- - `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
1287
1304
  - `RtsCameraConfig` (interface): interface RtsCameraConfig extends TopDownCameraConfig — Free-pan / edge-scroll RTS rig (#24) — pan/rotate/zoom independent of any avatar.
1288
1305
  - `RuleCursor` (interface): interface RuleCursor — Mutable per-rule progress, kept separate from the immutable {@link ScheduledRule} definition.
1289
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.
@@ -1293,8 +1310,8 @@
1293
1310
  - `RuleRegistry` (interface): interface RuleRegistry<TPayload = unknown> — Registered pool of {@link RuleDef}s — the install seam games register mutators/modes/events into.
1294
1311
  - `RuleSelection` (interface): interface RuleSelection<TPayload = unknown> — The result of a selection — the chosen rules and their ids (a serializable {@link LayerSelection}-style list).
1295
1312
  - `RuleSelectionConfig` (interface): interface RuleSelectionConfig — Deterministic selection inputs — plain serializable data a host can persist and replay.
1296
- - `RunDraft` (interface): interface RunDraft<TStat extends string = string, TData = unknown> — ⚠ undocumented
1297
- - `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
1298
1315
  - `SaleRecord` (interface): interface SaleRecord — One completed sale recorded into a {@link PriceHistory}.
1299
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.
1300
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.
@@ -1304,7 +1321,7 @@
1304
1321
  - `SaveSlotsSnapshot` (interface): interface SaveSlotsSnapshot — Serializable state of a {@link SaveSlots} index, for save/restore.
1305
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.
1306
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.
1307
- - `ScheduledDelivery` (interface): interface ScheduledDelivery — ⚠ undocumented
1324
+ - `ScheduledDelivery` (interface): interface ScheduledDelivery { userId: string; inventoryId: string; items: readonly ItemStack[]; deliverAt: number } — ⚠ undocumented
1308
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.
1309
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.
1310
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.
@@ -1321,8 +1338,8 @@
1321
1338
  - `ShoulderCameraConfig` (interface): interface ShoulderCameraConfig — Over-the-shoulder combat rig (#25) — offset, ADS, shoulder swap, decoupled reticle.
1322
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.
1323
1340
  - `SlotGrid` (type): type SlotGrid<T> = readonly Slot<T>[] — ⚠ undocumented
1324
- - `Social` (interface): interface Social — ⚠ undocumented
1325
- - `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.
1326
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.
1327
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.
1328
1345
  - `StatContributionStep` (interface): interface StatContributionStep extends StatContribution — One line of a provenance trace: a contribution plus the running total after it folds in.
@@ -1332,7 +1349,7 @@
1332
1349
  - `StatGraph` (interface): interface StatGraph — A compiled, immutable stat-graph schema that mints per-entity {@link StatSheet}s from base values or saved state.
1333
1350
  - `StatGraphDef` (interface): interface StatGraphDef — The full schema of a stat graph: its named inputs and caller-authored derived formulas.
1334
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.
1335
- - `StatLevelUpEvent` (interface): interface StatLevelUpEvent — ⚠ undocumented
1352
+ - `StatLevelUpEvent` (interface): interface StatLevelUpEvent { userId: string; stat: string; level: number } — ⚠ undocumented
1336
1353
  - `StatModEntry` (type): type StatModEntry = StatContribution | readonly StatContribution[] — A modifier entry targeting one stat: a single contribution or an ordered list.
1337
1354
  - `StatOp` (type): type StatOp = "add" | "mul" | "override" | "clampMin" | "clampMax" — How a single contribution folds into a running value.
1338
1355
  - `StatSheet` (interface): interface StatSheet — A live per-entity instance of a {@link StatGraph}: mutable base values and modifier sources over a shared schema.
@@ -1343,16 +1360,16 @@
1343
1360
  - `TOUCH_STYLES` (const): const TOUCH_STYLES: readonly TouchStyle[] — Every touch skin id, in menu order.
1344
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.
1345
1362
  - `TalentEdgeView` (interface): interface TalentEdgeView — One prerequisite edge into a node — the source node, the rank it demands, and whether that is met.
1346
- - `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…
1347
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`).
1348
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.
1349
1366
  - `TalentNodeView` (interface): interface TalentNodeView — A per-node view for rendering: grid placement (tier/branch), rank, state, and inbound prerequisite edges.
1350
1367
  - `TalentPointTotals` (interface): interface TalentPointTotals — Optional overall point totals for the view header; omit (or 0) for trees that spend no point currency.
1351
- - `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…
1352
1369
  - `TalentTreeView` (interface): interface TalentTreeView — A whole-tree render view: placed nodes plus branch/tier extents and point totals.
1353
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.
1354
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.
1355
- - `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
1356
1373
  - `ThresholdBand` (interface): interface ThresholdBand — A `{ min, factor }` band for {@link thresholdScale}; the highest band whose `min` is met wins.
1357
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).
1358
1375
  - `ThresholdCrossing` (interface): interface ThresholdCrossing<Id = string> — A single boundary transition between a `before` and `after` value.
@@ -1363,12 +1380,12 @@
1363
1380
  - `Toast` (interface): interface Toast<T = string> — A transient HUD message that expires on its own — banner, pickup note, alert.
1364
1381
  - `TopDownCameraConfig` (interface): interface TopDownCameraConfig — Fixed top-down / isometric rig (#23) — height/pitch/yaw + decoupled follow.
1365
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.
1366
- - `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
1367
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.
1368
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`.
1369
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.
1370
- - `TouchJoystick` (interface): interface TouchJoystick — ⚠ undocumented
1371
- - `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.
1372
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.
1373
1390
  - `TrackedObjectiveView` (interface): interface TrackedObjectiveView — One objective as a tracker/HUD reads it — label + progress toward its count.
1374
1391
  - `TrackedQuestView` (interface): interface TrackedQuestView — A quest as a tracker/HUD reads it — title, status, and per-objective progress.
@@ -1377,12 +1394,12 @@
1377
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.
1378
1395
  - `TriggeredRuleEngine` (interface): interface TriggeredRuleEngine — A running set of triggered rules with gating, timed lifetimes, stacking, cleanup, and save/load.
1379
1396
  - `TriggeredRuleState` (interface): interface TriggeredRuleState — Serializable runtime state — everything that changes future triggers. Rules travel with it.
1380
- - `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
1381
1398
  - `UnitReservation` (interface): interface UnitReservation — Reservation stored on a training job — the inputs to charge and refund.
1382
1399
  - `UnitSpawnOrder` (interface): interface UnitSpawnOrder — Completion payload: everything a spawn/rally adapter needs, and nothing it doesn't.
1383
1400
  - `UnitTrainingOptions` (interface): interface UnitTrainingOptions — Config knobs for {@link unitTrainingConfig}.
1384
1401
  - `UnitTrainingSpec` (interface): interface UnitTrainingSpec — What the caller asks the queue to build.
1385
- - `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.
1386
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.
1387
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.
1388
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.
@@ -1401,10 +1418,10 @@
1401
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.
1402
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}.
1403
1420
  - `WorkQueueState` (interface): interface WorkQueueState<TSpec, TReserve = undefined> — Serializable queue state. Holds only non-terminal jobs, so it stays bounded.
1404
- - `WorldInvite` (interface): interface WorldInvite extends WorldInviteTarget — ⚠ undocumented
1405
- - `WorldInviteTarget` (interface): interface WorldInviteTarget — ⚠ undocumented
1406
- - `WorldItemRecord` (interface): interface WorldItemRecord — ⚠ undocumented
1407
- - `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`.
1408
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.
1409
1426
  - `activeJobs` (function): function activeJobs<TSpec, TReserve>(state: WorkQueueState<TSpec, TReserve>): Job<TSpec, TReserve>[] — Jobs currently progressing.
1410
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.
@@ -1440,7 +1457,7 @@
1440
1457
  - `craft` (function): function craft(state: InventoryState, layout: InventoryLayout, traits: ItemTraits, recipe: RecipeDef, context: CraftContext = {}): CraftResult — ⚠ undocumented
1441
1458
  - `craftSeconds` (function): function craftSeconds(recipe: RecipeDef): number — ⚠ undocumented
1442
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.
1443
- - `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`.
1444
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.
1445
1462
  - `createBehaviourWorld` (function): function createBehaviourWorld(): BehaviourWorld — ⚠ undocumented
1446
1463
  - `createCardPile` (function): function createCardPile(config: CardPileConfig, initial?: Partial<Record<ZoneName, readonly string[]>>): CardPile — ⚠ undocumented
@@ -1650,15 +1667,15 @@
1650
1667
 
1651
1668
  ## @jgengine/core/inventory/inventoryModel
1652
1669
 
1653
- - `InventoryLayout` (interface): interface InventoryLayout — ⚠ undocumented
1654
- - `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.
1655
1672
  - `InventorySlot` (type): type InventorySlot = { itemId: string; count: number } | null — ⚠ undocumented
1656
- - `InventoryState` (interface): interface InventoryState — ⚠ undocumented
1657
- - `ItemTraits` (interface): interface ItemTraits — ⚠ undocumented
1658
- - `MoveResult` (type): type MoveResult = | { status: "ok"; from: InventoryState; to: InventoryState } | { status: "rejected"; reason: "invalid-slot" | "empty-slot" | "wrong-kind" | "no-space" } — ⚠ undocumented
1659
- - `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.
1660
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.
1661
- - `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.
1662
1679
  - `countItem` (function): function countItem(state: InventoryState, itemId: string): number — Total quantity of `itemId` summed across every stack in the inventory.
1663
1680
  - `createEmptyInventory` (function): function createEmptyInventory(layout: InventoryLayout): InventoryState — A bag of stackable items supporting add, remove, count, and move — the base inventory model.
1664
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.
@@ -1671,14 +1688,14 @@
1671
1688
  ## @jgengine/core/inventory/shapedGrid
1672
1689
 
1673
1690
  - `Cell` (type): type Cell = readonly [number, number] — ⚠ undocumented
1674
- - `Footprint` (type): type Footprint = readonly Cell[] — ⚠ undocumented
1675
- - `GridAdjacencyQuery` (interface): interface GridAdjacencyQuery — ⚠ undocumented
1676
- - `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
1677
1694
  - `Rotation` (type): type Rotation = 0 | 1 | 2 | 3 — ⚠ undocumented
1678
- - `ShapedGrid` (interface): interface ShapedGrid<T> — ⚠ undocumented
1679
- - `ShapedItem` (interface): interface ShapedItem<T> — ⚠ undocumented
1680
- - `ShapedPlaceResult` (interface): interface ShapedPlaceResult<T> — ⚠ undocumented
1681
- - `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
1682
1699
  - `ShapedRejection` (type): type ShapedRejection = "out-of-bounds" | "overlap" | "duplicate-id" | "unknown-id" — ⚠ undocumented
1683
1700
  - `ShapedResult` (type): type ShapedResult<T> = ShapedPlaceResult<T> | ShapedRejected — ⚠ undocumented
1684
1701
 
@@ -1690,14 +1707,14 @@
1690
1707
 
1691
1708
  ## @jgengine/core/inventory/storageTier
1692
1709
 
1693
- - `ConsolationPolicy` (interface): interface ConsolationPolicy — ⚠ undocumented
1694
- - `ContainerSnapshot` (interface): interface ContainerSnapshot — ⚠ undocumented
1695
- - `DeathPartition` (interface): interface DeathPartition — ⚠ undocumented
1696
- - `DeliveryEntry` (interface): interface DeliveryEntry — ⚠ undocumented
1697
- - `DeliveryQueue` (interface): interface DeliveryQueue — ⚠ undocumented
1698
- - `InsurancePolicy` (interface): interface InsurancePolicy — ⚠ undocumented
1699
- - `ItemStack` (interface): interface ItemStack — ⚠ undocumented
1700
- - `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
1701
1718
  - `StorageTier` (type): type StorageTier = "carried" | "banked" — ⚠ undocumented
1702
1719
  - `createDeliveryQueue` (function): function createDeliveryQueue(): DeliveryQueue — ⚠ undocumented
1703
1720
  - `insureLost` (function): function insureLost(lost: readonly ItemStack[], policy: InsurancePolicy, userId: string, now: number, rng?: () => number): ScheduledDelivery | null — ⚠ undocumented
@@ -1707,27 +1724,27 @@
1707
1724
 
1708
1725
  ## @jgengine/core/item/affix
1709
1726
 
1710
- - `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
1711
1728
  - `AffixOp` (type): type AffixOp = "add" | "mul" — ⚠ undocumented
1712
- - `AffixPool` (interface): interface AffixPool — ⚠ undocumented
1713
- - `AffixRoller` (interface): interface AffixRoller — ⚠ undocumented
1714
- - `ItemBaseDef` (interface): interface ItemBaseDef — ⚠ undocumented
1715
- - `RarityTier` (interface): interface RarityTier — ⚠ undocumented
1716
- - `RolledAffix` (interface): interface RolledAffix — ⚠ undocumented
1717
- - `RolledItem` (interface): interface RolledItem — ⚠ undocumented
1718
- - `RollerConfig` (interface): interface RollerConfig — ⚠ undocumented
1719
- - `createAffixRoller` (function): function createAffixRoller(config: RollerConfig): AffixRoller — ⚠ undocumented
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`.
1720
1737
  - `seededRng` (function): function seededRng(seed: string | number): SeededRng — Deterministic pseudo-random generator seeded from a string or number — same seed, same sequence.
1721
1738
 
1722
1739
  ## @jgengine/core/item/durability
1723
1740
 
1724
- - `DurabilitySpec` (interface): interface DurabilitySpec — ⚠ undocumented
1725
- - `DurabilityState` (interface): interface DurabilityState — ⚠ undocumented
1726
- - `DurabilityTracker` (interface): interface DurabilityTracker — ⚠ undocumented
1727
- - `RepairCost` (interface): interface RepairCost — ⚠ undocumented
1728
- - `RepairMaterial` (interface): interface RepairMaterial — ⚠ undocumented
1729
- - `RepairQuote` (interface): interface RepairQuote — ⚠ undocumented
1730
- - `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
1731
1748
  - `WearKind` (type): type WearKind = "use" | "hit" — ⚠ undocumented
1732
1749
  - `applyWear` (function): function applyWear(state: DurabilityState, amount: number): DurabilityState — Apply wear to an item, tracking breakage and repair eligibility.
1733
1750
  - `canRepairAt` (function): function canRepairAt(spec: DurabilitySpec, stationId?: string): boolean — ⚠ undocumented
@@ -1789,11 +1806,11 @@
1789
1806
  ## @jgengine/core/item/modularItem
1790
1807
 
1791
1808
  - `InstallResult` (type): type InstallResult = | { status: "ok"; installed: readonly InstalledPart[] } | { status: "rejected"; reason: "unknown-slot" | "wrong-category" | "slot-occupied" } — ⚠ undocumented
1792
- - `InstalledPart` (interface): interface InstalledPart — ⚠ undocumented
1793
- - `ModularItem` (interface): interface ModularItem — ⚠ undocumented
1794
- - `ModularItemDef` (interface): interface ModularItemDef — ⚠ undocumented
1795
- - `MountSlotDef` (interface): interface MountSlotDef — ⚠ undocumented
1796
- - `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
1797
1814
  - `computeEffectiveStats` (function): function computeEffectiveStats(def: ModularItemDef, installed: readonly InstalledPart[]): Record<string, number> — ⚠ undocumented
1798
1815
  - `createModularItem` (function): function createModularItem(def: ModularItemDef, initial: readonly InstalledPart[] = []): ModularItem — ⚠ undocumented
1799
1816
  - `install` (function): function install(def: ModularItemDef, installed: readonly InstalledPart[], slotId: string, part: PartDef): InstallResult — ⚠ undocumented
@@ -1806,11 +1823,11 @@
1806
1823
 
1807
1824
  ## @jgengine/core/item/use
1808
1825
 
1809
- - `ItemUse` (interface): interface ItemUse<TState> — ⚠ undocumented
1810
- - `ItemUseHandler` (interface): interface ItemUseHandler<TState> — ⚠ undocumented
1811
- - `ItemUseInput` (interface): interface ItemUseInput — ⚠ undocumented
1812
- - `ItemUseRejection` (interface): interface ItemUseRejection — ⚠ undocumented
1813
- - `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
1814
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.
1815
1832
 
1816
1833
  ## @jgengine/core/item/useBehavior
@@ -1830,8 +1847,8 @@
1830
1847
 
1831
1848
  ## @jgengine/core/item/weapon
1832
1849
 
1833
- - `WeaponEntry` (interface): interface WeaponEntry — ⚠ undocumented
1834
- - `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.
1835
1852
  - `createWeaponStats` (function): function createWeaponStats(resolveEntry: (itemId: string) => WeaponEntry | null | undefined): WeaponStats — Resolve per-weapon stat values — damage, fire rate, spread — for combat math.
1836
1853
  - `getWeaponStat` (function): function getWeaponStat(entry: WeaponEntry | null | undefined, stat: string): number | null — ⚠ undocumented
1837
1854
 
@@ -1854,13 +1871,22 @@
1854
1871
 
1855
1872
  ## @jgengine/core/puzzle/cellGrid
1856
1873
 
1857
- - `CellGrid` (interface): interface CellGrid<T> — ⚠ undocumented
1858
- - `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.
1859
1885
 
1860
1886
  ## @jgengine/core/puzzle/fallingPiece
1861
1887
 
1862
- - `FallingPiece` (interface): interface FallingPiece<TShape extends string = string> — ⚠ undocumented
1863
- - `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
1864
1890
  - `ShapeTable` (type): type ShapeTable<TShape extends string = string> = Record< TShape, readonly (readonly (readonly [number, number])[])[] > — ⚠ undocumented
1865
1891
 
1866
1892
  ## @jgengine/core/puzzle/nonogram
@@ -1872,9 +1898,9 @@
1872
1898
 
1873
1899
  ## @jgengine/core/random/nameGen
1874
1900
 
1875
- - `NameGenerator` (interface): interface NameGenerator — ⚠ undocumented
1876
- - `NameGeneratorOptions` (interface): interface NameGeneratorOptions — ⚠ undocumented
1877
- - `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
1878
1904
  - `createNameGenerator` (function): function createNameGenerator(options: NameGeneratorOptions): NameGenerator — Generate procedural names from templates and word banks with an injected random source.
1879
1905
  - `fillTemplate` (function): function fillTemplate(template: string, vars: Record<string, () => string> | Record<string, string>): string — ⚠ undocumented
1880
1906
  - `pickFrom` (function): function pickFrom(rng: () => number, bank: readonly string[]): string — ⚠ undocumented
@@ -1962,51 +1988,51 @@
1962
1988
  ## @jgengine/core/session/contestedChannel
1963
1989
 
1964
1990
  - `ContestReaction` (type): type ContestReaction = "pause" | "decay" — ⚠ undocumented
1965
- - `ContestedChannel` (interface): interface ContestedChannel — ⚠ undocumented
1966
- - `ContestedChannelConfig` (interface): interface ContestedChannelConfig — ⚠ undocumented
1967
- - `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
1968
1994
  - `ContestedEventKind` (type): type ContestedEventKind = "start" | "tick" | "contested" | "paused" | "complete" | "interrupted" — ⚠ undocumented
1969
1995
  - `ContestedPhase` (type): type ContestedPhase = "idle" | "active" | "paused" | "contested" | "complete" | "interrupted" — ⚠ undocumented
1970
- - `ContestedSnapshot` (interface): interface ContestedSnapshot — ⚠ undocumented
1996
+ - `ContestedSnapshot` (interface): interface ContestedSnapshot { phase: ContestedPhase; progress: number; owner: string | null; remaining: number } — ⚠ undocumented
1971
1997
 
1972
1998
  ## @jgengine/core/session/extraction
1973
1999
 
1974
- - `DeathResult` (interface): interface DeathResult — ⚠ undocumented
1975
- - `ExtractPoint` (interface): interface ExtractPoint — ⚠ undocumented
1976
- - `ExtractionAttempt` (interface): interface ExtractionAttempt — ⚠ undocumented
1977
- - `ExtractionResult` (interface): interface ExtractionResult — ⚠ undocumented
1978
- - `RaidPlayerSnapshot` (interface): interface RaidPlayerSnapshot — ⚠ undocumented
1979
- - `RaidSession` (interface): interface RaidSession — ⚠ undocumented
1980
- - `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
1981
2007
  - `RaidStatus` (type): type RaidStatus = "in-raid" | "extracting" | "extracted" | "dead" — ⚠ undocumented
1982
2008
 
1983
2009
  ## @jgengine/core/session/ring
1984
2010
 
1985
- - `Ring` (interface): interface Ring — ⚠ undocumented
1986
- - `RingConfig` (interface): interface RingConfig — ⚠ undocumented
1987
- - `RingHit` (interface): interface RingHit — ⚠ undocumented
1988
- - `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
1989
2015
  - `RingPoint` (type): type RingPoint = [number, number] — ⚠ undocumented
1990
- - `RingSample` (interface): interface RingSample — ⚠ undocumented
2016
+ - `RingSample` (interface): interface RingSample { center: RingPoint; radius: number; damagePerSecond: number; phase: number; shrinking: boolean } — ⚠ undocumented
1991
2017
  - `createRing` (function): function createRing(config: RingConfig): Ring — ⚠ undocumented
1992
2018
  - `ringSampleAt` (function): function ringSampleAt(config: RingConfig, time: number): RingSample — ⚠ undocumented
1993
2019
 
1994
2020
  ## @jgengine/core/session/roles
1995
2021
 
1996
- - `RoleSpec` (interface): interface RoleSpec — ⚠ undocumented
2022
+ - `RoleSpec` (interface): interface RoleSpec { id: string; count?: number; ratio?: number } — ⚠ undocumented
1997
2023
 
1998
2024
  ## @jgengine/core/session/roundState
1999
2025
 
2000
- - `LossBonusRule` (interface): interface LossBonusRule — ⚠ undocumented
2026
+ - `LossBonusRule` (interface): interface LossBonusRule { base: number; step: number; max: number } — ⚠ undocumented
2001
2027
  - `PhaseEndHook` (type): type PhaseEndHook<TPhase extends string = RoundPhase> = ( endingPhase: TPhase, nextPhase: TPhase, round: number, ) => void — ⚠ undocumented
2002
- - `RoundConfig` (interface): interface RoundConfig<TPhase extends string = RoundPhase> — ⚠ undocumented
2003
- - `RoundEconomy` (interface): interface RoundEconomy — ⚠ undocumented
2004
- - `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
2005
2031
  - `RoundEventKind` (type): type RoundEventKind = | "phase.start" | "phase.end" | "round.win" | "round.economy" | "match.end" — ⚠ undocumented
2006
2032
  - `RoundPhase` (type): type RoundPhase = string — ⚠ undocumented
2007
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`.
2008
- - `RoundSnapshot` (interface): interface RoundSnapshot<TPhase extends string = RoundPhase> — ⚠ undocumented
2009
- - `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
2010
2036
  - `RoundTeam` (interface): interface RoundTeam — A team entry with an optional role tag (e.g. "attacker", "defender") retrievable via `RoundState.roleOf`.
2011
2037
 
2012
2038
  ## @jgengine/core/store/defineKeyedStore
@@ -2021,12 +2047,12 @@
2021
2047
 
2022
2048
  ## @jgengine/core/survival/decayMeter
2023
2049
 
2024
- - `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.
2025
2051
  - `DecayMeterSet` (interface): interface DecayMeterSet — Set of named survival meters (hunger/thirst/…) that drain and refill over game time.
2026
- - `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}.
2027
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.
2028
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.
2029
- - `MeterThreshold` (interface): interface MeterThreshold — ⚠ undocumented
2055
+ - `MeterThreshold` (interface): interface MeterThreshold { id: string; label: string; at: number; when: "below" | "above"; severity?: MoodleSeverity; icon?: string } — ⚠ undocumented
2030
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`.
2031
2057
  - `decayMeterMoodles` (function): function decayMeterMoodles(values: DecayMeterValues, defs: readonly DecayMeterConfig[]): Moodle[] — Moodles for every crossed threshold, worst-first per meter in declared order.
2032
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}.
@@ -2042,97 +2068,97 @@
2042
2068
  - `MoodleSeverity` (type): type MoodleSeverity = "good" | "neutral" | "warning" | "critical" — ⚠ undocumented
2043
2069
  - `MoodleSource` (type): type MoodleSource = "meter" | "ailment" | "buff" — ⚠ undocumented
2044
2070
  - `MoodleStack` (interface): interface MoodleStack — Ordered stack of active moodles derived from meters/ailments/buffs.
2045
- - `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
2046
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.
2047
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.
2048
2074
 
2049
2075
  ## @jgengine/core/survival/regionHealth
2050
2076
 
2051
- - `AilmentConfig` (interface): interface AilmentConfig — ⚠ undocumented
2052
- - `AilmentInstance` (interface): interface AilmentInstance — ⚠ undocumented
2053
- - `DamageResult` (interface): interface DamageResult — ⚠ undocumented
2054
- - `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
2055
2081
  - `MultiRegionHealth` (interface): interface MultiRegionHealth — Per-limb / per-region health track with treat/damage/heal APIs.
2056
- - `MultiRegionHealthConfig` (interface): interface MultiRegionHealthConfig — ⚠ undocumented
2057
- - `RegionHealthState` (interface): interface RegionHealthState — ⚠ undocumented
2058
- - `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
2059
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.
2060
2086
 
2061
2087
  ## @jgengine/core/tactics/fallingGrid
2062
2088
 
2063
- - `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
2064
2090
  - `FallingGridCell` (type): type FallingGridCell = readonly [number, number] — ⚠ undocumented
2065
- - `FallingGridConfig` (interface): interface FallingGridConfig — ⚠ undocumented
2066
- - `FallingGridSnapshot` (interface): interface FallingGridSnapshot<TCell> — ⚠ undocumented
2067
- - `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
2068
2094
  - `LockState` (interface): interface LockState — Elapsed grounded time for the lock-delay state machine. `null` means airborne / not timing.
2069
2095
 
2070
2096
  ## @jgengine/core/tactics/predictiveQuery
2071
2097
 
2072
- - `ArcPredictInput` (interface): interface ArcPredictInput — ⚠ undocumented
2073
- - `AreaPredictInput` (interface): interface AreaPredictInput extends AreaTargetInput — ⚠ undocumented
2074
- - `PredictedTarget` (interface): interface PredictedTarget — ⚠ undocumented
2075
- - `PredictiveDeps` (interface): interface PredictiveDeps — ⚠ undocumented
2076
- - `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
2077
2103
 
2078
2104
  ## @jgengine/core/tactics/snapshot
2079
2105
 
2080
2106
  - `Snapshot` (type): type Snapshot = Record<string, unknown> — ⚠ undocumented
2081
- - `SnapshotSlice` (interface): interface SnapshotSlice<T = unknown> — ⚠ undocumented
2082
- - `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
2083
2109
 
2084
2110
  ## @jgengine/core/tactics/surface
2085
2111
 
2086
- - `SurfaceCell` (interface): interface SurfaceCell — ⚠ undocumented
2087
- - `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
2088
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
2089
- - `SurfaceKindDef` (interface): interface SurfaceKindDef — ⚠ undocumented
2090
- - `SurfaceLayer` (interface): interface SurfaceLayer — ⚠ undocumented
2091
- - `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
2092
2118
  - `SurfaceLayerSnapshot` (type): type SurfaceLayerSnapshot = Record<string, Record<string, number | null>> — ⚠ undocumented
2093
- - `SurfacePatch` (interface): interface SurfacePatch — ⚠ undocumented
2094
- - `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
2095
2121
 
2096
2122
  ## @jgengine/core/tactics/tacticalGrid
2097
2123
 
2098
- - `PushCollision` (interface): interface PushCollision — ⚠ undocumented
2099
- - `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
2100
2126
  - `PushObstacle` (type): type PushObstacle = "wall" | "edge" — ⚠ undocumented
2101
- - `PushOptions` (interface): interface PushOptions — ⚠ undocumented
2102
- - `PushResult` (interface): interface PushResult — ⚠ undocumented
2103
- - `ReachableOptions` (interface): interface ReachableOptions — ⚠ undocumented
2104
- - `ReachableTile` (interface): interface ReachableTile — ⚠ undocumented
2105
- - `TacticalGrid` (interface): interface TacticalGrid — ⚠ undocumented
2106
- - `TacticalGridConfig` (interface): interface TacticalGridConfig — ⚠ undocumented
2107
- - `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
2108
2134
  - `TacticalGridWorldConfig` (interface): interface TacticalGridWorldConfig — Maps abstract `[col, row]` tiles onto world-space `[x, z]`, mirroring `navGrid`'s bounds+cellSize convention.
2109
2135
  - `Tile` (type): type Tile = readonly [number, number] — ⚠ undocumented
2110
2136
 
2111
2137
  ## @jgengine/core/turn/commit
2112
2138
 
2113
- - `CommitController` (interface): interface CommitController<TAction> — ⚠ undocumented
2114
- - `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
2115
2141
  - `CommitMode` (type): type CommitMode = "immediate" | "simultaneous" | "resealable" — ⚠ undocumented
2116
- - `CommitOutcome` (interface): interface CommitOutcome<TAction> — ⚠ undocumented
2117
- - `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
2118
2144
  - `createCommitController` (function): function createCommitController<TAction>(config: CommitControllerConfig): CommitController<TAction> — ⚠ undocumented
2119
2145
 
2120
2146
  ## @jgengine/core/turn/intent
2121
2147
 
2122
- - `DeclaredIntent` (interface): interface DeclaredIntent<TKind extends string = string> — ⚠ undocumented
2123
- - `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
2124
2150
  - `createIntentBoard` (function): function createIntentBoard<TKind extends string = string>(): IntentBoard<TKind> — ⚠ undocumented
2125
2151
 
2126
2152
  ## @jgengine/core/turn/turnLoop
2127
2153
 
2128
- - `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
2129
2155
  - `CommitMode` (type): type CommitMode = "immediate" | "simultaneous" | "resealable" — ⚠ undocumented
2130
- - `PoolConfig` (interface): interface PoolConfig — ⚠ undocumented
2131
- - `PoolState` (interface): interface PoolState — ⚠ undocumented
2132
- - `TurnLoop` (interface): interface TurnLoop<TAction = unknown> — ⚠ undocumented
2133
- - `TurnLoopConfig` (interface): interface TurnLoopConfig — ⚠ undocumented
2134
- - `TurnLoopSnapshot` (interface): interface TurnLoopSnapshot — ⚠ undocumented
2135
- - `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
2136
2162
  - `createTurnLoop` (function): function createTurnLoop<TAction = unknown>(config: TurnLoopConfig): TurnLoop<TAction> — ⚠ undocumented
2137
2163
 
2138
2164
  ## @jgengine/core/work/jobQueue