@jgengine/core 0.27.0 → 0.28.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 (108) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/dist/ai/policeResponse.d.ts +253 -0
  3. package/dist/ai/policeResponse.js +421 -0
  4. package/dist/anim/actionLayer.d.ts +47 -0
  5. package/dist/anim/actionLayer.js +63 -0
  6. package/dist/anim/ikSolver.d.ts +14 -0
  7. package/dist/anim/ikSolver.js +37 -0
  8. package/dist/anim/locomotionGraph.d.ts +58 -3
  9. package/dist/anim/locomotionGraph.js +142 -15
  10. package/dist/anim/ragdollRig.d.ts +53 -0
  11. package/dist/anim/ragdollRig.js +132 -0
  12. package/dist/anim/skeletonStandard.d.ts +140 -0
  13. package/dist/anim/skeletonStandard.js +326 -0
  14. package/dist/combat/damageRuntime.d.ts +14 -1
  15. package/dist/combat/damageRuntime.js +62 -4
  16. package/dist/combat/death.js +7 -3
  17. package/dist/combat/deathReason.d.ts +7 -1
  18. package/dist/combat/effects.d.ts +25 -0
  19. package/dist/combat/effects.js +16 -0
  20. package/dist/combat/statusRuntime.d.ts +2 -0
  21. package/dist/combat/statusRuntime.js +1 -0
  22. package/dist/economy/loanBook.d.ts +182 -0
  23. package/dist/economy/loanBook.js +303 -0
  24. package/dist/economy/market.d.ts +161 -0
  25. package/dist/economy/market.js +248 -0
  26. package/dist/economy/transactionLedger.d.ts +162 -0
  27. package/dist/economy/transactionLedger.js +301 -0
  28. package/dist/editor/creatorStorage.js +3 -1
  29. package/dist/editor/simulation.d.ts +5 -2
  30. package/dist/editor/simulation.js +29 -19
  31. package/dist/game/cameraConfig.d.ts +14 -0
  32. package/dist/game/clipRoles.d.ts +5 -4
  33. package/dist/game/clipRoles.js +34 -4
  34. package/dist/game/events.d.ts +27 -0
  35. package/dist/game/gameSave.d.ts +142 -0
  36. package/dist/game/gameSave.js +174 -0
  37. package/dist/game/playableGame.d.ts +55 -4
  38. package/dist/game/saveSlotIndex.d.ts +54 -0
  39. package/dist/game/saveSlotIndex.js +71 -0
  40. package/dist/game/saveSlots.d.ts +2 -0
  41. package/dist/game/saveSlots.js +1 -1
  42. package/dist/game/saveStore.d.ts +8 -0
  43. package/dist/game/saveStore.js +16 -0
  44. package/dist/gameplay.d.ts +12 -2
  45. package/dist/gameplay.js +10 -0
  46. package/dist/meta/changelog.d.ts +1 -1
  47. package/dist/meta/changelog.js +120 -1
  48. package/dist/mission/compositions.d.ts +85 -0
  49. package/dist/mission/compositions.js +130 -0
  50. package/dist/mission/mission.d.ts +435 -0
  51. package/dist/mission/mission.js +770 -0
  52. package/dist/mission/triggers.d.ts +61 -0
  53. package/dist/mission/triggers.js +108 -0
  54. package/dist/nav/traffic.d.ts +0 -1
  55. package/dist/nav/traffic.js +1 -2
  56. package/dist/runtime/context/combat.js +11 -0
  57. package/dist/settings/accessibilitySettings.d.ts +81 -0
  58. package/dist/settings/accessibilitySettings.js +152 -0
  59. package/dist/settings/graphicsProfile.d.ts +3 -0
  60. package/dist/settings/graphicsProfile.js +4 -0
  61. package/dist/settings/settingsModel.d.ts +1 -1
  62. package/dist/settings/settingsModel.js +1 -0
  63. package/dist/sim/nearAgents.d.ts +8 -1
  64. package/dist/sim/nearAgents.js +34 -17
  65. package/dist/sim/offScreen.d.ts +2 -1
  66. package/dist/sim/offScreen.js +14 -3
  67. package/dist/sim/population.d.ts +147 -0
  68. package/dist/sim/population.js +182 -0
  69. package/dist/sim/queue.d.ts +90 -0
  70. package/dist/sim/queue.js +171 -0
  71. package/dist/sim/rides.d.ts +287 -0
  72. package/dist/sim/rides.js +471 -0
  73. package/dist/sim/routine.js +19 -11
  74. package/dist/ui/loadingTips.d.ts +41 -0
  75. package/dist/ui/loadingTips.js +64 -0
  76. package/dist/ui/menuNav.d.ts +79 -0
  77. package/dist/ui/menuNav.js +147 -0
  78. package/dist/ui/menuTransition.d.ts +50 -0
  79. package/dist/ui/menuTransition.js +67 -0
  80. package/dist/ui.d.ts +2 -0
  81. package/dist/ui.js +2 -0
  82. package/dist/vfx/effectLibrary.d.ts +98 -0
  83. package/dist/vfx/effectLibrary.js +181 -0
  84. package/dist/vfx/particleBudget.d.ts +40 -0
  85. package/dist/vfx/particleBudget.js +39 -0
  86. package/dist/vfx/particleDirector.d.ts +16 -0
  87. package/dist/vfx/particleDirector.js +18 -0
  88. package/dist/world/authoredSimulation.js +7 -1
  89. package/dist/world/captureCamera.d.ts +30 -0
  90. package/dist/world/captureCamera.js +19 -0
  91. package/dist/world/features.d.ts +15 -4
  92. package/dist/world/terrain.d.ts +1 -0
  93. package/dist/world/terrain.js +2 -0
  94. package/dist/world.d.ts +2 -1
  95. package/dist/world.js +1 -0
  96. package/package.json +1 -1
  97. package/skills/jgengine/api.md +2 -2
  98. package/skills/jgengine-combat/SKILL.md +6 -0
  99. package/skills/jgengine-combat/api.md +5 -4
  100. package/skills/jgengine-combat/reference.md +4 -0
  101. package/skills/jgengine-gameplay/SKILL.md +55 -0
  102. package/skills/jgengine-gameplay/api.md +335 -10
  103. package/skills/jgengine-gameplay/capabilities.md +83 -1
  104. package/skills/jgengine-world/SKILL.md +4 -0
  105. package/skills/jgengine-world/api.md +128 -6
  106. package/skills/jgengine-world/capabilities.md +41 -1
  107. package/skills/jgengine-world/recipes/character-animation.md +25 -2
  108. package/skills/jgengine-world/reference.md +1 -1
@@ -194,6 +194,37 @@
194
194
  - `PostListingResult` (type): type PostListingResult = | { status: "ok"; listing: Listing } | { status: "rejected"; reason: PostListingReason } — Result of {@link ListingBook.post}.
195
195
  - `createListingBook` (function): function createListingBook(config: ListingBookConfig): ListingBook — A player-driven listing marketplace: post/cancel/buy against a shared book with a house cut on every sale, an expiry sweep that pulls unsold goods out of circulation, and a per-seller collection box holding sale proceeds and returned items until claimed. Buyer/seller wallet and inventory movement is the caller's job (mirrors `game/trade`'s split) — this primitive owns only the listing lifecycle and the escrowed collection-box bookkeeping behind it.
196
196
 
197
+ ## @jgengine/core/economy/loanBook
198
+
199
+ - `LoanAdvanceResult` (interface): interface LoanAdvanceResult — What one {@link LoanBook.advance} settled, and what it could not.
200
+ - `LoanBook` (interface): interface LoanBook — The loans a business owes: schedules, interest, arrears and default, posted to a ledger.
201
+ - `LoanBookOptions` (interface): interface LoanBookOptions — Options for {@link createLoanBook}.
202
+ - `LoanBookState` (interface): interface LoanBookState — Serializable loan-book state.
203
+ - `LoanBookStats` (interface): interface LoanBookStats — Counters of a loan book, for a probe or a summary line.
204
+ - `LoanPayment` (interface): interface LoanPayment — One scheduled repayment, in integer minor units.
205
+ - `LoanRecord` (interface): interface LoanRecord — One live loan: its plan plus how far it has been paid.
206
+ - `LoanRepayment` (interface): interface LoanRepayment — Outcome of an early repayment.
207
+ - `LoanSchedule` (interface): interface LoanSchedule — A full repayment plan: every payment, its interest/principal split and the running balance.
208
+ - `LoanState` (interface): interface LoanState — Saved progress of one loan; the schedule is rebuilt from its terms on restore.
209
+ - `LoanTerms` (interface): interface LoanTerms — Money in this module is an integer count of **minor units** — cents when the currency has two decimals, whole coins when it has none. Principal, interest, payments and balances are safe integers, so a schedule adds up exactly.
210
+ - `buildLoanSchedule` (function): function buildLoanSchedule(terms: LoanTerms): LoanSchedule — Build a loan's repayment schedule: one entry per period with its due time, interest/principal split and the balance left, in integer minor units. An amortized loan levels the payment over the outstanding balance (`P·i / (1 − (1+i)^−n)`); a flat loan charges interest on the original principal. Either way the final payment absorbs the rounding, so the principal parts sum to the principal exactly and the balance ends at zero. Deterministic and pure.
211
+ - `createLoanBook` (function): function createLoanBook(options: LoanBookOptions): LoanBook — The loans a business owes, over a {@link TransactionLedger}: each draw posts the principal to the borrower's account, each settled payment posts its interest (`"loan-interest"`) and principal (`"loan-principal"`) as separate reason-tagged entries, and an early repayment posts `"loan-repayment"`. A payment that comes due with no funds is left in arrears and counted once per advance; after `maxMissed` the loan is defaulted and stops being advanced. State is plain data — `snapshot()` stores terms and progress, and the schedule is rebuilt from the terms.
212
+
213
+ ## @jgengine/core/economy/market
214
+
215
+ - `Market` (interface): interface Market — A live market: prices from supply and demand over finite stock, with serializable state.
216
+ - `MarketConfig` (interface): interface MarketConfig — Options for {@link createMarket}: the goods and the price/demand policy they share.
217
+ - `MarketGoodDef` (interface): interface MarketGoodDef — Money in this module is an integer count of **minor units** — cents when the currency has two decimals, whole coins when it has none. Every price, cost and total is a safe integer, so a simulation never accumulates float drift; the caller converts at the display boundary.
218
+ - `MarketGoodState` (interface): interface MarketGoodState — The mutable half of a good: what a save stores, with the definition kept as authored data.
219
+ - `MarketPriceInput` (interface): interface MarketPriceInput — Everything a price curve reads: the good's resolved policy plus its live stock and demand.
220
+ - `MarketQuote` (interface): interface MarketQuote — A non-mutating read of what a sale would cost and how it would move the price.
221
+ - `MarketSale` (interface): interface MarketSale — A served sale: what the buyer paid per unit and in total, in minor units.
222
+ - `MarketSaleRejection` (interface): interface MarketSaleRejection — Why a sale could not be served.
223
+ - `MarketSaleResult` (type): type MarketSaleResult = MarketSale | MarketSaleRejection — A sale outcome: the price the buyers paid, or why it could not be served.
224
+ - `MarketSnapshot` (interface): interface MarketSnapshot — Serializable market state: the mutable half of every good plus the running counters.
225
+ - `MarketStats` (interface): interface MarketStats — Counters and stocks of a market, for a probe or a summary line.
226
+ - `createMarket` (function): function createMarket(config: MarketConfig = {}): Market — A market whose price comes from supply and demand over finite stock, as plain serializable state.
227
+
197
228
  ## @jgengine/core/economy/priceHistory
198
229
 
199
230
  - `PriceHistory` (interface): interface PriceHistory — A bounded rolling record of completed sales per item. See {@link createPriceHistory}.
@@ -261,6 +292,22 @@
261
292
  - `TechState` (type): type TechState = UnlockState — ⚠ undocumented
262
293
  - `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
263
294
 
295
+ ## @jgengine/core/economy/transactionLedger
296
+
297
+ - `ChargeCursor` (interface): interface ChargeCursor — Mutable per-charge progress, kept apart from the {@link RecurringCharge} definition.
298
+ - `LedgerAdvanceResult` (interface): interface LedgerAdvanceResult — What one {@link TransactionLedger.chargeDue} settled, and what it could not.
299
+ - `LedgerEntry` (interface): interface LedgerEntry — Money in this module is an integer count of **minor units** — cents when the currency has two decimals, whole coins when it has none. Every posted amount and every balance is a safe integer, so a long simulation never accumulates float drift. `currency` is a free string the game owns.
300
+ - `LedgerEntryFilter` (interface): interface LedgerEntryFilter — A filter over the journal.
301
+ - `LedgerPostInput` (interface): interface LedgerPostInput — A post to attempt.
302
+ - `LedgerPostResult` (type): type LedgerPostResult = | { ok: true; entry: LedgerEntry } | { ok: false; reason: "unknown-account" | "invalid-amount" | "invalid-reason" | "insufficient-funds" } — Outcome of {@link TransactionLedger.post}. A rejection leaves every balance untouched.
303
+ - `LedgerState` (interface): interface LedgerState — Fully serializable ledger state: clock, balances, journal, totals, charges and cursors.
304
+ - `LedgerStats` (interface): interface LedgerStats — Counters of a ledger, for a probe or a summary line.
305
+ - `LedgerTotals` (interface): interface LedgerTotals — What one reason code did to the books, kept across entry trimming.
306
+ - `RecurringCharge` (interface): interface RecurringCharge — A recurring charge — upkeep, rent, a subscription — settled by {@link TransactionLedger.chargeDue}.
307
+ - `TransactionLedger` (interface): interface TransactionLedger — The books: balances with a reason-tagged journal, and recurring charges on a cadence.
308
+ - `TransactionLedgerOptions` (interface): interface TransactionLedgerOptions — Options for {@link createTransactionLedger}.
309
+ - `createTransactionLedger` (function): function createTransactionLedger(options: TransactionLedgerOptions = {}): TransactionLedger — The books a business keeps: per-account, per-currency balances in integer minor units with a journal that records every movement, the balance it produced and the reason it happened. {@link TransactionLedger.post} is the one money path — sales, purchases, upkeep and loan payments all go through it, so nothing moves without a reason on the record. {@link TransactionLedger.chargeDue} settles recurring charges (upkeep, rent) on their own cadence, bounded per advance; a cycle with no funds is counted as missed instead of overdrawing. Journal memory is bounded by `maxEntries`, with `totals()` keeping the per-reason summary beyond it.
310
+
264
311
  ## @jgengine/core/economy/unlockPoints
265
312
 
266
313
  - `SpendOptions` (interface): interface SpendOptions — Options for {@link UnlockPoints.spend}.
@@ -326,7 +373,8 @@
326
373
  - `ChaseCameraConfig` (interface): interface ChaseCameraConfig — Speed-reactive vehicle chase rig (#27) — speed→FOV, spring arm, procedural shake, interior views.
327
374
  - `ChaseView` (type): type ChaseView = "chase" | "cockpit" | "hood" | "rear" — Fixed interior view for the chase rig (#27).
328
375
  - `CinematicCameraConfig` (interface): interface CinematicCameraConfig — Scripted keyframe / path player (#29). When set it overrides the active rig.
329
- - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig { eyeHeight?: number; sensitivity?: number; maxPitch?: number; reticle?: boolean; viewmodel?: boolean } — ⚠ undocumented
376
+ - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig { eyeHeight?: number; sensitivity?: number; maxPitch?: number; reticle?: boolean; viewmodel?: boolean; collision?: false | FirstPersonCollisionConfig } — ⚠ undocumented
377
+ - `FirstPersonCollisionConfig` (interface): interface FirstPersonCollisionConfig — Clearance tuning for the first-person camera's collision pull-in.
330
378
  - `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.
331
379
  - `InspectionCameraConfig` (interface): interface InspectionCameraConfig — Model-viewer / inspection rig (#207.7) — orbit + pan + anchored zoom around a fixed point, never reads player input.
332
380
  - `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.
@@ -373,11 +421,11 @@
373
421
 
374
422
  ## @jgengine/core/game/clipRoles
375
423
 
376
- - `ClipRole` (type): type ClipRole = | "idle" | "walk" | "run" | "attack" | "hit" | "death" | "jump" | "spawn" | "interact" | "cheer" — Semantic animation roles a GLB clip name can map to. Rigged packs name the same motion differently (`Idle` / `Walking_A` / `Armature|Run`); roles are the pack-agnostic vocabulary the engine defaults from.
424
+ - `ClipRole` (type): type ClipRole = | "idle" | "walk" | "run" | "strafe" | "backward" | "attack" | "hit" | "death" | "jump" | "spawn" | "interact" | "cheer" — Semantic animation roles a GLB clip name can map to. Rigged packs name the same motion differently (`Idle` / `Walking_A` / `Armature|Run`); roles are the pack-agnostic vocabulary the engine defaults from.
377
425
  - `ClipRoleTable` (interface): interface ClipRoleTable — Keyword table driving {@link classifyClip}: lowercase keywords matched against a clip name's tokens (exact token match beats prefix match). Extend or replace per game/pack — the table is plain data, no genre assumptions.
378
426
  - `DEFAULT_CLIP_ROLE_TABLE` (const): const DEFAULT_CLIP_ROLE_TABLE: ClipRoleTable — Default vocabulary covering KayKit, Quaternius, and Mixamo-style clip naming.
379
427
  - `classifyClip` (function): function classifyClip(name: string, table: ClipRoleTable = DEFAULT_CLIP_ROLE_TABLE): ClipRole | null — Classify a single GLB clip name into a {@link ClipRole}, or `null` when nothing matches (or an exclusion token like `pose` disqualifies it). Deterministic: exact token matches beat prefix matches; remaining ties resolve by fixed role priority (death > hit > attack > … > idle).
380
- - `defaultAnimationForClips` (function): function defaultAnimationForClips(clips: readonly string[], table: ClipRoleTable = DEFAULT_CLIP_ROLE_TABLE): ModelAnimationConfig | undefined — Build the default `ModelConfig.animation` for a rigged asset from its catalog clip names: speed-driven idle/walk/run states plus hit/death/attack one-shots where identifiable. Returns `undefined` when no idle clip is identifiable — an ambiguous rig renders its bind pose rather than guessing. Walk falls back to idle when the pack has no walk clip.
428
+ - `defaultAnimationForClips` (function): function defaultAnimationForClips(clips: readonly string[], table: ClipRoleTable = DEFAULT_CLIP_ROLE_TABLE): ModelAnimationConfig | undefined — Build the default `ModelConfig.animation` for a rigged asset from its catalog clip names: speed-driven idle/walk/run states plus hit/death/attack one-shots where identifiable, and the lateral/backward states when the pack names them (KayKit's `Running_Strafe_Left`, `Walking_Backwards`). Returns `undefined` when no idle clip is identifiable - an ambiguous rig renders its bind pose rather than guessing. Walk falls back to idle when the pack has no walk clip.
381
429
  - `resolveAnimationConfig` (function): function resolveAnimationConfig(animation: ModelAnimationConfig | "auto" | "none" | undefined, clips: readonly string[] | undefined, table: ClipRoleTable = DEFAULT_CLIP_ROLE_TABLE): ModelAnimationConfig | undefined — Collapse `ModelConfig.animation`'s widened union to a concrete playback config: explicit configs pass through, `"none"`/absent render the bind pose, and `"auto"` derives states and one-shots from the model's clip names via {@link defaultAnimationForClips}. The shell calls this with the loaded GLB's actual clip names, so `"auto"` works on any rigged model — catalog-resolved ids are stamped `"auto"` automatically. An object with `auto: true` derives the same defaults, then replaces each explicitly supplied field whole, including empty maps.
382
430
  - `rolesFromClips` (function): function rolesFromClips(clips: readonly string[], table: ClipRoleTable = DEFAULT_CLIP_ROLE_TABLE): Partial<Record<ClipRole, string[]>> — Group a GLB's clip names by role. Each role's variants are sorted simplest-first — fewest name tokens, then lexicographic — so the canonical variant (`Idle` over `2H_Melee_Idle`, KayKit `Walking_A` over `Walking_B`) is always first: stable output for the same clip set regardless of source order.
383
431
 
@@ -504,14 +552,15 @@
504
552
  - `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).
505
553
  - `CommandRefusedEvent` (interface): interface CommandRefusedEvent — A command run through `ctx.game.commands` (or a bound host) was refused. `reason` is the machine code; `message` is the player-facing text the command's `validate` returned, when it gave one.
506
554
  - `CosmeticsChangedEvent` (interface): interface CosmeticsChangedEvent { userId: string; slots: Record<string, string> } — ⚠ undocumented
507
- - `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.
555
+ - `DamageAppliedEvent` (interface): interface DamageAppliedEvent — One application of damage to one target: what hit it, for how much, and where its health stands. `target` is always the thing that took the blow, so a hero and a keep hit in the same frame raise two separate events and a HUD reads only the one whose `target` it owns.
556
+ - `DeathReason` (type): type DeathReason = | { kind: "player_kill"; killerUserId: string; source?: string; via?: { item?: string } } | { kind: "environment"; source: string; attacker?: string } | { kind: "self"; source: string } — Why an entity died — who or what gets credit, for drop/command rules and the `entity.died` event. `source` names what dealt it: a player kill's killer instance id, or the hazard/item of an environment death; `attacker` carries the non-player entity's instance id when one dealt it.
508
557
  - `EmotePlayedEvent` (interface): interface EmotePlayedEvent { from: string; emoteId: string; at: readonly [number, number, number]; recipients: readonly string[] } — ⚠ undocumented
509
558
  - `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.
510
- - `EntityDiedEvent` (interface): interface EntityDiedEvent { instanceId: string; catalogId: string; userId?: string; displayName?: string; reason: DeathReason; position: [number, number, number]; serverId?: string } — ⚠ undocumented
559
+ - `EntityDiedEvent` (interface): interface EntityDiedEvent { instanceId: string; catalogId: string; userId?: string; displayName?: string; reason: DeathReason; source?: string; position: [number, number, number]; serverId?: string } — ⚠ undocumented
511
560
  - `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
512
561
  - `FormChangedEvent` (interface): interface FormChangedEvent { instanceId: string; formId: string | null } — ⚠ undocumented
513
562
  - `GameEventHandler` (type): type GameEventHandler<TPayload> = (payload: TPayload) => void — ⚠ undocumented
514
- - `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.
563
+ - `GameEventMap` (interface): interface GameEventMap { "entity.died": EntityDiedEvent; "combat.damage": DamageAppliedEvent; "entity.floatText": EntityFloatTextEvent; "combat.telegraph": CombatTelegraphEvent; "combat.vfx": CombatVfxEvent; "combat.vfxInstance": CombatVfxInstanceEvent; "combat.t… — ⚠ undocumented · used by `createGameEvents`: A typed publish/subscribe bus for gameplay events that systems and HUDs subscribe to.
515
564
  - `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.
516
565
  - `InventoryAddedEvent` (interface): interface InventoryAddedEvent { userId: string; item: string; count: number; source?: string } — ⚠ undocumented
517
566
  - `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.
@@ -556,6 +605,18 @@
556
605
  - `isPlaying` (function): function isPlaying(ctx: GameContext): boolean — ⚠ undocumented
557
606
  - `setGamePhase` (function): function setGamePhase(ctx: GameContext, phase: GamePhase): void — Set the current phase. Publishes it to `ctx.game.store` (React reads it via `useGamePhase`) and gates the shell's on-screen touch controls in one call — `playing` shows them, every other phase hides them. This is the whole "main menu shouldn't show touch controls" wiring: call it once per phase transition and the dock follows.
558
607
 
608
+ ## @jgengine/core/game/gameSave
609
+
610
+ - `GAME_SAVE_VERSION` (const): const GAME_SAVE_VERSION: 1 — Current save-format version of {@link GameSaveDocument}. Bump it with {@link GameSaveConfig.migrate} when the shape changes.
611
+ - `GameSave` (interface): interface GameSave — A pluggable-backend game save: one versioned document holding a section per system, with named slots, caller-policy autosave, migration and a state digest. `capture()` builds the document from the live systems; `save()`/`touch()` write it (directly or on the autosave debounce); `load()` reads a slot and applies every section back through its system's `restore`. The shared RNG's cursor rides along, so the seed survives the save and a reloaded run continues the same sequence.
612
+ - `GameSaveConfig` (interface): interface GameSaveConfig — How a {@link createGameSave} is wired. Storage is the narrow injected {@link SaveBackend}, never `localStorage` welded in.
613
+ - `GameSaveDocument` (interface): interface GameSaveDocument — The one save document: a format `version`, the game and clock metadata a save-select menu shows, the world's shared RNG cursor, and one section per registered system. There is deliberately no second per-system format — every system's state lives under `systems[<name>]`.
614
+ - `GameSaveRng` (interface): interface GameSaveRng — The world's shared injected RNG: its `seed` and the live `stream` whose cursor is persisted.
615
+ - `GameSaveRngState` (interface): interface GameSaveRngState — The persisted cursor of the world's shared injected RNG, plus the seed that produced it.
616
+ - `GameSaveSystem` (interface): interface GameSaveSystem<T = unknown> — One stateful system inside a game save: a stable `name` (its section key in the document) and the `snapshot()`/`restore()` pair every Lane B module exposes. The name is the contract — a document written by one build restores into the next build's system with the same name. `reset` runs when a loaded slot has no section for this system (a fresh slot), so switching to an empty slot starts a new game instead of leaving the previous one's state behind; a system without it is left as-is.
617
+ - `createGameSave` (function): function createGameSave(config: GameSaveConfig): GameSave — Create a {@link GameSave}. Register every stateful system once; `capture()` writes one versioned document with a section per system, `save()`/`touch()` persist it through the injected backend (autosave cadence is the caller's), `load()` restores every section and the shared RNG cursor, and `digest()`/`digests()` give a determinism test a hash over the whole state.
618
+ - `gameSaveDigest` (function): function gameSaveDigest(document: GameSaveDocument): string — A stable hash over the state-bearing part of a document — every system section, the world clock and the shared RNG cursor — excluding the wall-clock `savedAt`, which is not state.
619
+
559
620
  ## @jgengine/core/game/keyValueStore
560
621
 
561
622
  - `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.
@@ -763,7 +824,8 @@
763
824
  - `CinematicCameraConfig` (interface): interface CinematicCameraConfig — Scripted keyframe / path player (#29). When set it overrides the active rig.
764
825
  - `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 · used by `FALLBACK_KEY_LIGHT` (@jgengine/core/render/lightingBalance): Soft key added when authored lighting has no directional light: high, off to one side, shadowless.
765
826
  - `EntitySpriteConfig` (interface): interface EntitySpriteConfig { url: string; width: number; height: number; y: number; clip?: {atlas: SpriteAtlas; animation: string} } — ⚠ undocumented
766
- - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig { eyeHeight?: number; sensitivity?: number; maxPitch?: number; reticle?: boolean; viewmodel?: boolean } — ⚠ undocumented
827
+ - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig { eyeHeight?: number; sensitivity?: number; maxPitch?: number; reticle?: boolean; viewmodel?: boolean; collision?: false | FirstPersonCollisionConfig } — ⚠ undocumented
828
+ - `FirstPersonCollisionConfig` (interface): interface FirstPersonCollisionConfig — Clearance tuning for the first-person camera's collision pull-in.
767
829
  - `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`.
768
830
  - `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.
769
831
  - `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.
@@ -778,6 +840,8 @@
778
840
  - `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.
779
841
  - `ModelConfig` (interface): interface ModelConfig { url: string; scale?: number; targetHeight?: number; y?: number; anchor?: "center" | "origin"; dims?: ModelDims; collisionMesh?: CollisionMeshData; material?: ModelMaterialOverride; surfaceDetail?: boolean; wind?: ModelWindConfig | false; … — ⚠ 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`).
780
842
  - `ModelIkConfig` (interface): interface ModelIkConfig — Bone names and limits for {@link ModelConfig.ik}.
843
+ - `ModelLodConfig` (interface): interface ModelLodConfig — Distance tiers for one character model. Distances are metres from the camera; every field is data so a game can set its own thresholds per model and retune them without touching the engine.
844
+ - `ModelLookAtConfig` (interface): interface ModelLookAtConfig — {@link ModelIkConfig.lookAt}: the bone that turns, and what it turns toward.
781
845
  - `ModelMaterialMaps` (interface): interface ModelMaterialMaps extends Partial<Record<MaterialTextureRole, string>> — 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 supported MaterialTextureRole may be omitted to keep the model's own map. Physical roles use the renderer's physical material; map URLs and response parameters remain caller-owned.
782
846
  - `ModelMaterialOverride` (interface): interface ModelMaterialOverride extends MaterialSurfaceParameters — Per-entity PBR material override (#151.3) applied to every standard or physical material in the model's cloned scene graph.
783
847
  - `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.
@@ -915,6 +979,16 @@
915
979
  - `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.
916
980
  - `createRunModifierStack` (function): function createRunModifierStack<TStat extends string = string, TData = unknown>(offers: readonly RunModifierOffer<TStat, TData>[]): RunModifierStack<TStat, TData> — ⚠ undocumented
917
981
 
982
+ ## @jgengine/core/game/saveSlotIndex
983
+
984
+ - `SaveSlotMetaOptions` (interface): interface SaveSlotMetaOptions — Bridging the versioned save document (`createGameSave`) to the save-select index (`createSaveSlots`): the document already carries `savedAt`, `time` and `playtime`, so a menu built on the index can show real saves instead of hand-maintained metadata.
985
+ - `SaveSlotSource` (interface): interface SaveSlotSource — The source a slot list is refreshed from — a `GameSave`, or a narrower reader.
986
+ - `SaveSlotsRefresh` (interface): interface SaveSlotsRefresh — The result of a refresh: what the menu should show now.
987
+ - `formatSavePlaytime` (function): function formatSavePlaytime(seconds: number): string — "4h 12m" / "12m" / "< 1m" — the playtime chip every save menu wants.
988
+ - `gameSaveSlotSource` (function): function gameSaveSlotSource(save: GameSave): SaveSlotSource — Adapt a {@link GameSave} as a {@link SaveSlotSource}. Kept separate so a host can supply its own reader (a cloud endpoint listing saves) with the same shape.
989
+ - `refreshSaveSlots` (function): function refreshSaveSlots(source: SaveSlotSource, model: SaveSlots, options: SaveSlotMetaOptions = {}): Promise<SaveSlotsRefresh> — Read every written slot's document and write the display metadata into a `SaveSlots` index — the glue between B5.3's save document and a save-select menu. Slots the index already knows that have no document are cleared, so a deleted save stops showing a stale Continue.
990
+ - `saveSlotMeta` (function): function saveSlotMeta(slot: string, document: GameSaveDocument, options: SaveSlotMetaOptions = {}): SaveSlotMeta — Project one save document onto the index's display metadata: name, last-saved time and a playtime chip (plus any caller `metaOf` fields). Pure, so a menu can build its list from documents a host fetched for it.
991
+
918
992
  ## @jgengine/core/game/saveSlots
919
993
 
920
994
  - `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.
@@ -1143,9 +1217,11 @@
1143
1217
  - `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).
1144
1218
  - `Cell` (type): type Cell = readonly [number, number] — ⚠ undocumented · used by `canPlace` (@jgengine/core/inventory/shapedGrid): Check bounds and overlap for a discrete footprint, optionally ignoring the item being moved.
1145
1219
  - `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.
1220
+ - `ChargeCursor` (interface): interface ChargeCursor — Mutable per-charge progress, kept apart from the {@link RecurringCharge} definition.
1146
1221
  - `ChargeOptions` (interface): interface ChargeOptions — Options for {@link charge}/{@link chargeAll}: opt one call into overdraft debt via `overdraft`.
1147
1222
  - `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`.
1148
1223
  - `ChaseCameraConfig` (interface): interface ChaseCameraConfig — Speed-reactive vehicle chase rig (#27) — speed→FOV, spring arm, procedural shake, interior views.
1224
+ - `ChaseMissionOptions` (interface): interface ChaseMissionOptions extends ComposedMissionOptions — Options for {@link chaseMission}: a target kept close until it is caught.
1149
1225
  - `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
1150
1226
  - `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…
1151
1227
  - `ChatRateLimit` (interface): interface ChatRateLimit { count: number; perMs: number } — ⚠ undocumented
@@ -1161,6 +1237,7 @@
1161
1237
  - `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.
1162
1238
  - `CompatibilityRule` (type): type CompatibilityRule = RequireRule | ForbidRule — A cross-slot compatibility rule constraining which part/tag/family combinations a modular item may hold.
1163
1239
  - `CompiledSystemSchedule` (interface): interface CompiledSystemSchedule — Deterministic compiled schedule: stage buckets, multi-subscribe channels, dependency validation. Order never depends on import order — only stage tables + explicit before/after constraints.
1240
+ - `ComposedMissionOptions` (interface): interface ComposedMissionOptions — Options shared by every composed mission.
1164
1241
  - `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.
1165
1242
  - `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.
1166
1243
  - `ConstraintViolation` (interface): interface ConstraintViolation — One failed {@link CompatibilityRule}, carrying the rule id, its kind, and a human-readable message for UI or generator diagnostics.
@@ -1171,14 +1248,23 @@
1171
1248
  - `DEFAULT_CHAT_BODY_LENGTH` (const): const DEFAULT_CHAT_BODY_LENGTH: 240 — ⚠ undocumented
1172
1249
  - `DEFAULT_CHAT_HISTORY_LIMIT` (const): const DEFAULT_CHAT_HISTORY_LIMIT: 100 — ⚠ undocumented
1173
1250
  - `DEFAULT_CHAT_RATE_LIMIT` (const): const DEFAULT_CHAT_RATE_LIMIT: ChatRateLimit — ⚠ undocumented
1251
+ - `DEFAULT_ESCAPE_MULTIPLE` (const): const DEFAULT_ESCAPE_MULTIPLE: 3 — A pursuit escapes at this multiple of its keep-close distance when none is declared.
1174
1252
  - `DEFAULT_FIXED_STAGES` (const): const DEFAULT_FIXED_STAGES: readonly ["input", "movement", "combat", "ai", "activities", "cleanup"] — Default fixed-sim stage order — systems pick a stage; most need only this.
1175
1253
  - `DEFAULT_FRAME_STAGES` (const): const DEFAULT_FRAME_STAGES: readonly ["input", "movement", "combat", "ai", "activities", "cleanup", "animation", "camera", "effects"] — Default frame stage order. Gameplay stages mirror the fixed table so once-per-frame systems (`type: "frame"`) can pick `combat`/`ai`/… without falling into the unknown-stage bucket; presentation stages follow.
1176
1254
  - `DEFAULT_PICKUP_RADIUS` (const): const DEFAULT_PICKUP_RADIUS: 2 — ⚠ undocumented
1177
1255
  - `DEFAULT_PING_CATEGORIES` (const): const DEFAULT_PING_CATEGORIES: Record<PingCategory, PingCategoryDef> — Content-agnostic default ping wheel: enemy / loot / location / danger.
1256
+ - `DEFAULT_PURSUE_DISTANCE` (const): const DEFAULT_PURSUE_DISTANCE: 3 — Default keep-close distance (m) for a `pursue` objective.
1257
+ - `DEFAULT_QUEUE_SEED_SERVICE_SECONDS` (const): const DEFAULT_QUEUE_SEED_SERVICE_SECONDS: 8 — Seconds one guest occupies the head of the line before any boarding interval has been measured. A bootstrap only: the estimate switches to the queue's own measured throughput as soon as two boardings have been observed.
1258
+ - `DEFAULT_QUEUE_WINDOW` (const): const DEFAULT_QUEUE_WINDOW: 8 — Boarding events the throughput window keeps.
1259
+ - `DEFAULT_REACH_RADIUS` (const): const DEFAULT_REACH_RADIUS: 2.5 — Default proximity radius (m) for a `reach` / `interact` objective.
1260
+ - `DEFAULT_RIDE_BREAKDOWN` (const): const DEFAULT_RIDE_BREAKDOWN: RideBreakdown — A ride's breakdown curve a park starts from when it has none and retunes only part of one.
1261
+ - `DEFAULT_RIDE_FUN_CURVE` (const): const DEFAULT_RIDE_FUN_CURVE: ResponseCurve — How empty a bored guest's fun need has to be before a ride starts to pull, by default.
1262
+ - `DEFAULT_RIDE_RATING_RANGE` (const): const DEFAULT_RIDE_RATING_RANGE: RideRatingRange — A 0–10 rating scale, the usual shape of a ride catalog. Override it when a park rates differently.
1178
1263
  - `DEFAULT_TOUCH_STYLE` (const): const DEFAULT_TOUCH_STYLE: TouchStyle — Skin used when neither the game nor the player picks one.
1179
1264
  - `DecayMeterSet` (interface): interface DecayMeterSet — Set of named survival meters (hunger/thirst/…) that drain and refill over game time.
1180
1265
  - `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.
1181
1266
  - `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.
1267
+ - `DefendMissionOptions` (interface): interface DefendMissionOptions extends ComposedMissionOptions — Options for {@link defendMission}: hold a position, scored by what is left standing.
1182
1268
  - `DeliveryEntry` (interface): interface DeliveryEntry { id: string; userId: string; inventoryId: string; items: readonly ItemStack[]; deliverAt: number } — ⚠ undocumented
1183
1269
  - `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
1184
1270
  - `DialogueGraph` (interface): interface DialogueGraph — A serializable branching conversation: a start node id and the nodes it can reach.
@@ -1195,9 +1281,10 @@
1195
1281
  - `EffectRef` (interface): interface EffectRef — A reference to an effect the game knows how to apply — id plus JSON-safe params, no closures.
1196
1282
  - `EnqueueOptions` (interface): interface EnqueueOptions — Optional per-enqueue overrides.
1197
1283
  - `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.
1198
- - `EntityDiedEvent` (interface): interface EntityDiedEvent { instanceId: string; catalogId: string; userId?: string; displayName?: string; reason: DeathReason; position: [number, number, number]; serverId?: string } — ⚠ undocumented
1284
+ - `EntityDiedEvent` (interface): interface EntityDiedEvent { instanceId: string; catalogId: string; userId?: string; displayName?: string; reason: DeathReason; source?: string; position: [number, number, number]; serverId?: string } — ⚠ undocumented
1199
1285
  - `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
1200
1286
  - `EntitySpriteConfig` (interface): interface EntitySpriteConfig { url: string; width: number; height: number; y: number; clip?: {atlas: SpriteAtlas; animation: string} } — ⚠ undocumented
1287
+ - `EscortMissionOptions` (interface): interface EscortMissionOptions extends ComposedMissionOptions — Options for {@link escortMission}: a protected actor that must reach a destination alive.
1201
1288
  - `EventTicker` (interface): interface EventTicker — A live, observable event/kill-feed ticker.
1202
1289
  - `EventTickerEntry` (interface): interface EventTickerEntry extends TimedFeedEntry — A stored ticker entry — an {@link EventTickerInput} stamped with an id and clock time.
1203
1290
  - `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", …).
@@ -1213,19 +1300,27 @@
1213
1300
  - `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…
1214
1301
  - `FeedWindow` (interface): interface FeedWindow — Bounds for {@link appendFeed} / {@link pruneFeed}: newest-`limit` cap and/or `ttl` age window.
1215
1302
  - `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.
1216
- - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig { eyeHeight?: number; sensitivity?: number; maxPitch?: number; reticle?: boolean; viewmodel?: boolean } — ⚠ undocumented
1303
+ - `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig { eyeHeight?: number; sensitivity?: number; maxPitch?: number; reticle?: boolean; viewmodel?: boolean; collision?: false | FirstPersonCollisionConfig } — ⚠ undocumented
1304
+ - `FirstPersonCollisionConfig` (interface): interface FirstPersonCollisionConfig — Clearance tuning for the first-person camera's collision pull-in.
1217
1305
  - `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.
1218
1306
  - `FriendEntry` (interface): interface FriendEntry { userId: string; online: boolean } — ⚠ undocumented
1219
1307
  - `FriendRequestEntry` (interface): interface FriendRequestEntry { requestId: string; fromUserId: string } — ⚠ undocumented
1220
1308
  - `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
1309
+ - `GAME_SAVE_VERSION` (const): const GAME_SAVE_VERSION: 1 — Current save-format version of {@link GameSaveDocument}. Bump it with {@link GameSaveConfig.migrate} when the shape changes.
1221
1310
  - `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.
1222
1311
  - `GameDefinition` (interface): interface GameDefinition<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> — Fully-resolved game description produced by {@link defineGameDefinition} — assets, scene, and opted-in subsystems.
1223
1312
  - `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.
1224
- - `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.
1313
+ - `GameEventMap` (interface): interface GameEventMap { "entity.died": EntityDiedEvent; "combat.damage": DamageAppliedEvent; "entity.floatText": EntityFloatTextEvent; "combat.telegraph": CombatTelegraphEvent; "combat.vfx": CombatVfxEvent; "combat.vfxInstance": CombatVfxInstanceEvent; "combat.t… — ⚠ undocumented · used by `createGameEvents`: A typed publish/subscribe bus for gameplay events that systems and HUDs subscribe to.
1225
1314
  - `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.
1226
1315
  - `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, Harbor Heat #1329).
1227
1316
  - `GameLoop` (interface): interface GameLoop<TContext = unknown> — Lifecycle hooks a game implements to drive init, per-tick simulation, and player join/leave.
1228
1317
  - `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.
1318
+ - `GameSave` (interface): interface GameSave — A pluggable-backend game save: one versioned document holding a section per system, with named slots, caller-policy autosave, migration and a state digest. `capture()` builds the document from the live systems; `save()`/`touch()` write it (directly or on the autosave debounce); `load()` reads a slot and applies every section back through its system's `restore`. The shared RNG's cursor rides along, so the seed survives the save and a reloaded run continues the same sequence.
1319
+ - `GameSaveConfig` (interface): interface GameSaveConfig — How a {@link createGameSave} is wired. Storage is the narrow injected {@link SaveBackend}, never `localStorage` welded in.
1320
+ - `GameSaveDocument` (interface): interface GameSaveDocument — The one save document: a format `version`, the game and clock metadata a save-select menu shows, the world's shared RNG cursor, and one section per registered system. There is deliberately no second per-system format — every system's state lives under `systems[<name>]`.
1321
+ - `GameSaveRng` (interface): interface GameSaveRng — The world's shared injected RNG: its `seed` and the live `stream` whose cursor is persisted.
1322
+ - `GameSaveRngState` (interface): interface GameSaveRngState — The persisted cursor of the world's shared injected RNG, plus the seed that produced it.
1323
+ - `GameSaveSystem` (interface): interface GameSaveSystem<T = unknown> — One stateful system inside a game save: a stable `name` (its section key in the document) and the `snapshot()`/`restore()` pair every Lane B module exposes. The name is the contract — a document written by one build restores into the next build's system with the same name. `reset` runs when a loaded slot has no section for this system (a fresh slot), so switching to an empty slot starts a new game instead of leaving the previous one's state behind; a system without it is left as-is.
1229
1324
  - `GearScore` (interface): interface GearScore — A scored loadout: the total, each slot's share, each stat's signed contribution, and how complete it is.
1230
1325
  - `GearScoreOptions` (interface): interface GearScoreOptions extends Pick<LootComparisonOptions, "weights" | "lowerIsBetter"> — Caller policy for a loadout score: stat weights, which stats read better small, and what level, rarity and an empty slot are worth.
1231
1326
  - `GearSlotItem` (interface): interface GearSlotItem — The least a worn item must expose to be scored: its stat block, plus optional level and rarity for the gear-score terms.
@@ -1267,8 +1362,16 @@
1267
1362
  - `LayerSelection` (type): type LayerSelection = readonly string[] — A serializable, ordered reference to layers by stable id — what a save file or session setup stores.
1268
1363
  - `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.
1269
1364
  - `LeaderboardScope` (type): type LeaderboardScope = "global" | "server" | "profile" — ⚠ undocumented
1365
+ - `LedgerAdvanceResult` (interface): interface LedgerAdvanceResult — What one {@link TransactionLedger.chargeDue} settled, and what it could not.
1366
+ - `LedgerEntry` (interface): interface LedgerEntry — Money in this module is an integer count of **minor units** — cents when the currency has two decimals, whole coins when it has none. Every posted amount and every balance is a safe integer, so a long simulation never accumulates float drift. `currency` is a free string the game owns.
1367
+ - `LedgerEntryFilter` (interface): interface LedgerEntryFilter — A filter over the journal.
1270
1368
  - `LedgerEvent` (interface): interface LedgerEvent — Lifecycle signal emitted by {@link advanceLedger}.
1271
1369
  - `LedgerEventKind` (type): type LedgerEventKind = "started" | "fired" | "skipped" | "depleted" | "ended" — The kinds of lifecycle signal {@link advanceLedger} can emit for a rule.
1370
+ - `LedgerPostInput` (interface): interface LedgerPostInput — A post to attempt.
1371
+ - `LedgerPostResult` (type): type LedgerPostResult = | { ok: true; entry: LedgerEntry } | { ok: false; reason: "unknown-account" | "invalid-amount" | "invalid-reason" | "insufficient-funds" } — Outcome of {@link TransactionLedger.post}. A rejection leaves every balance untouched.
1372
+ - `LedgerState` (interface): interface LedgerState — Fully serializable ledger state: clock, balances, journal, totals, charges and cursors.
1373
+ - `LedgerStats` (interface): interface LedgerStats — Counters of a ledger, for a probe or a summary line.
1374
+ - `LedgerTotals` (interface): interface LedgerTotals — What one reason code did to the books, kept across entry trimming.
1272
1375
  - `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.
1273
1376
  - `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…
1274
1377
  - `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).
@@ -1277,6 +1380,17 @@
1277
1380
  - `LightingConfig` (interface): interface LightingConfig — Declarative lighting replacing the shell's hardcoded ambient/directional default (#207.5); mounts regardless of world kind, only when supplied.
1278
1381
  - `Listing` (interface): interface Listing — One active post in a {@link ListingBook}: an item stack a seller offered at a fixed price until it expires.
1279
1382
  - `LoadoutDef` (interface): interface LoadoutDef { inventories?: Record<string, LoadoutItemEntry[]>; stats?: Record<string, {current: number; max?: number; min?: number}>; economy?: Record<string, number>; unlocks?: string[] } — ⚠ undocumented
1383
+ - `LoanAdvanceResult` (interface): interface LoanAdvanceResult — What one {@link LoanBook.advance} settled, and what it could not.
1384
+ - `LoanBook` (interface): interface LoanBook — The loans a business owes: schedules, interest, arrears and default, posted to a ledger.
1385
+ - `LoanBookOptions` (interface): interface LoanBookOptions — Options for {@link createLoanBook}.
1386
+ - `LoanBookState` (interface): interface LoanBookState — Serializable loan-book state.
1387
+ - `LoanBookStats` (interface): interface LoanBookStats — Counters of a loan book, for a probe or a summary line.
1388
+ - `LoanPayment` (interface): interface LoanPayment — One scheduled repayment, in integer minor units.
1389
+ - `LoanRecord` (interface): interface LoanRecord — One live loan: its plan plus how far it has been paid.
1390
+ - `LoanRepayment` (interface): interface LoanRepayment — Outcome of an early repayment.
1391
+ - `LoanSchedule` (interface): interface LoanSchedule — A full repayment plan: every payment, its interest/principal split and the running balance.
1392
+ - `LoanState` (interface): interface LoanState — Saved progress of one loan; the schedule is rebuilt from its terms on restore.
1393
+ - `LoanTerms` (interface): interface LoanTerms — Money in this module is an integer count of **minor units** — cents when the currency has two decimals, whole coins when it has none. Principal, interest, payments and balances are safe integers, so a schedule adds up exactly.
1280
1394
  - `LockOnCameraConfig` (interface): interface LockOnCameraConfig — Lock-on / strafe rig (#26) — yaw bound to player→target, move axis becomes strafe.
1281
1395
  - `LootBaseDef` (interface): interface LootBaseDef extends ItemBaseDef — A base family (frame, housing, chassis — caller nouns) with its slots, stats and affix pools.
1282
1396
  - `LootCatalog` (interface): interface LootCatalog — Everything a roll reads: bases, parts, affixes, rarity odds, makers and the level curve.
@@ -1311,6 +1425,44 @@
1311
1425
  - `LootWeaponProjection` (interface): interface LootWeaponProjection — A base weapon definition plus the stat map a rolled item overrides.
1312
1426
  - `LootWeaponStatMap` (interface): interface LootWeaponStatMap — Which rolled stat feeds which part of a {@link WeaponDefinition}. Every field is a stat id from the item; an omitted field keeps the template's value, so a catalog only maps what it rolls.
1313
1427
  - `MAX_LOOT_AFFIXES` (const): const MAX_LOOT_AFFIXES: 8 — Cap on affixes one item may roll, so a bad catalog cannot make a drop cost unbounded work.
1428
+ - `MISSION_COUNTER_KINDS` (const): const MISSION_COUNTER_KINDS: readonly MissionObjectiveKind[] — Objective kinds that are satisfied only by a counter — a mission made of these alone is a lint error.
1429
+ - `MISSION_TRIGGER_ACTIONS` (const): const MISSION_TRIGGER_ACTIONS: readonly TriggerActionDefinition[] — The mission actions a game registers so the editor inspector can assign them to a marker or volume. Params land flat on the object's `meta` beside `on`/`action`, like any authored trigger.
1430
+ - `Market` (interface): interface Market — A live market: prices from supply and demand over finite stock, with serializable state.
1431
+ - `MarketConfig` (interface): interface MarketConfig — Options for {@link createMarket}: the goods and the price/demand policy they share.
1432
+ - `MarketGoodDef` (interface): interface MarketGoodDef — Money in this module is an integer count of **minor units** — cents when the currency has two decimals, whole coins when it has none. Every price, cost and total is a safe integer, so a simulation never accumulates float drift; the caller converts at the display boundary.
1433
+ - `MarketGoodState` (interface): interface MarketGoodState — The mutable half of a good: what a save stores, with the definition kept as authored data.
1434
+ - `MarketPriceInput` (interface): interface MarketPriceInput — Everything a price curve reads: the good's resolved policy plus its live stock and demand.
1435
+ - `MarketQuote` (interface): interface MarketQuote — A non-mutating read of what a sale would cost and how it would move the price.
1436
+ - `MarketSale` (interface): interface MarketSale — A served sale: what the buyer paid per unit and in total, in minor units.
1437
+ - `MarketSaleRejection` (interface): interface MarketSaleRejection — Why a sale could not be served.
1438
+ - `MarketSaleResult` (type): type MarketSaleResult = MarketSale | MarketSaleRejection — A sale outcome: the price the buyers paid, or why it could not be served.
1439
+ - `MarketSnapshot` (interface): interface MarketSnapshot — Serializable market state: the mutable half of every good plus the running counters.
1440
+ - `MarketStats` (interface): interface MarketStats — Counters and stocks of a market, for a probe or a summary line.
1441
+ - `MissionActorFact` (interface): interface MissionActorFact — A live actor the machine tracks: whether it is alive and, when needed, where it is.
1442
+ - `MissionBranch` (interface): interface MissionBranch — One outgoing edge of an objective: the first branch whose `when` matches wins over `next`.
1443
+ - `MissionDef` (interface): interface MissionDef — A whole mission: the objective graph plus its fail states and rewards.
1444
+ - `MissionEvent` (type): type MissionEvent = | { kind: "started"; missionId: string; mission: MissionDef } | { kind: "objective"; missionId: string; objectiveId: string; label: string } | { kind: "branch"; missionId: string; from: string; to: string; label?: string } | { kind: "timeout"; missionId: string; objectiveId: stri… — Emitted as the machine advances.
1445
+ - `MissionEventFilter` (interface): interface MissionEventFilter — Which world events an objective counts or a fail condition reacts to. Absent fields do not filter.
1446
+ - `MissionFactCondition` (interface): interface MissionFactCondition — A readable fact test a branch or a `fact` fail condition reads. All comparators are optional.
1447
+ - `MissionFailCondition` (interface): interface MissionFailCondition — A condition that fails the mission while the objective is active. `to` names a {@link MissionFailDef}; with no `to` the mission fails with the generic `"failed"` state.
1448
+ - `MissionFailDef` (interface): interface MissionFailDef — A named fail state an objective, timer or branch can land in.
1449
+ - `MissionIssue` (interface): interface MissionIssue — A located mission-catalog problem; `path` is a JSON Pointer into the supplied catalog.
1450
+ - `MissionObjectiveDef` (interface): interface MissionObjectiveDef — One objective. Every field is content; the machine reads only these.
1451
+ - `MissionObjectiveKind` (type): type MissionObjectiveKind = "reach" | "interact" | "survive" | "pursue" | "kill" | "collect" — The primitive goals an objective can have. Escort, chase and defend are not kinds — they are compositions of these plus fail conditions and timers (see `compositions.ts`).
1452
+ - `MissionRewardAppliers` (interface): interface MissionRewardAppliers — Appliers a mission reward routes through — the same shape quests use, plus a loot-table hook.
1453
+ - `MissionRewards` (interface): interface MissionRewards extends QuestRewards — What a mission pays. Economy/XP/items/unlocks flow through the quest appliers; loot names tables.
1454
+ - `MissionRuntime` (interface): interface MissionRuntime — The mission state machine over one active mission.
1455
+ - `MissionRuntimeConfig` (interface): interface MissionRuntimeConfig — Everything a mission runtime needs.
1456
+ - `MissionRuntimeSnapshot` (interface): interface MissionRuntimeSnapshot — Serializable runtime state for a save.
1457
+ - `MissionState` (interface): interface MissionState — Serializable mission state — one active mission's position in its graph.
1458
+ - `MissionStats` (interface): interface MissionStats — Counters a devtools probe or a test reads.
1459
+ - `MissionStatus` (type): type MissionStatus = "active" | "completed" | "failed" — Where a mission is in its life.
1460
+ - `MissionTickInput` (interface): interface MissionTickInput — Everything the machine reads for one tick. All optional; a mission only touches what it declares.
1461
+ - `MissionTriggerBridge` (interface): interface MissionTriggerBridge — Watches a document's authored mission triggers against moving actors.
1462
+ - `MissionValidationOptions` (interface): interface MissionValidationOptions — Declarations a mission catalog is validated against.
1463
+ - `MissionView` (interface): interface MissionView — Pooled per-frame readout a HUD tracker renders.
1464
+ - `MissionWorldEvent` (interface): interface MissionWorldEvent — One thing that happened in the world this tick, reported by the game. A constrained objective counts matching events and an `event` fail condition reacts to them, so the machine judges the world instead of the game polling its own counters.
1465
+ - `MissionWorldEventKind` (type): type MissionWorldEventKind = "kill" | "collect" | "deliver" — What a reported world event is.
1314
1466
  - `ModelConfig` (interface): interface ModelConfig { url: string; scale?: number; targetHeight?: number; y?: number; anchor?: "center" | "origin"; dims?: ModelDims; collisionMesh?: CollisionMeshData; material?: ModelMaterialOverride; surfaceDetail?: boolean; wind?: ModelWindConfig | false; … — ⚠ 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`).
1315
1467
  - `ModelMaterialMaps` (interface): interface ModelMaterialMaps extends Partial<Record<MaterialTextureRole, string>> — 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 supported MaterialTextureRole may be omitted to keep the model's own map. Physical roles use the renderer's physical material; map URLs and response parameters remain caller-owned.
1316
1468
  - `ModelMaterialOverride` (interface): interface ModelMaterialOverride extends MaterialSurfaceParameters — Per-entity PBR material override (#151.3) applied to every standard or physical material in the model's cloned scene graph.
@@ -1381,6 +1533,8 @@
1381
1533
  - `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…
1382
1534
  - `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…
1383
1535
  - `QuestRewards` (interface): interface QuestRewards { xp?: {amount: number}; economy?: Record<string, number>; items?: {item: string; count: number; inventory: string}[]; unlocks?: string[]; quests?: string[] } — ⚠ undocumented · used by `applyQuestRewards` (@jgengine/core/game/quest): Apply items before XP, currency, and unlocks.
1536
+ - `QueueEntry` (interface): interface QueueEntry — One guest waiting their turn, and when they joined the line.
1537
+ - `QueueWait` (interface): interface QueueWait — A wait estimate read off the queue's own measured throughput.
1384
1538
  - `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.
1385
1539
  - `RankLeaderboardOptions` (interface): interface RankLeaderboardOptions — Options for {@link rankLeaderboard}. All optional.
1386
1540
  - `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.
@@ -1397,12 +1551,33 @@
1397
1551
  - `RebindSessionSnapshot` (interface): interface RebindSessionSnapshot — Serializable session state for save/restore.
1398
1552
  - `RecipeDef` (interface): interface RecipeDef { id: string; inputs: readonly RecipeItem[]; outputs: readonly RecipeItem[]; seconds?: number; station?: string; stationRange?: number; requires?: readonly string[]; category?: string } — ⚠ undocumented · used by `validateRecipeCatalog` (@jgengine/core/crafting/recipeCatalog): Validate native recipes before registration: ids, counts, timing and caller-catalog references.
1399
1553
  - `RecipeItem` (interface): interface RecipeItem { itemId: string; count: number } — ⚠ undocumented
1554
+ - `RecurringCharge` (interface): interface RecurringCharge — A recurring charge — upkeep, rent, a subscription — settled by {@link TransactionLedger.chargeDue}.
1400
1555
  - `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.
1401
1556
  - `ResourceCost` (type): type ResourceCost = Readonly<Record<string, number>> — Resource costs keyed by currency/resource id.
1402
1557
  - `ResourceLedger` (interface): interface ResourceLedger — Fully serializable scheduled-transaction state: clock, balances, rule definitions, and cursors.
1403
1558
  - `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.
1404
1559
  - `ResourceTransaction` (interface): interface ResourceTransaction — One resource movement produced by a due cycle, before it is applied to balances.
1405
1560
  - `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.
1561
+ - `RideBreakdown` (interface): interface RideBreakdown — Breakdown curve and money for one ride. All data, so a park tunes its own economy.
1562
+ - `RideChoicePolicy` (interface): interface RideChoicePolicy — Policy a park might vary when it turns taste and ride data into utility options.
1563
+ - `RideChooser` (interface): interface RideChooser — One guest's ride choice over one park: taste becomes utility options, each ride is costed by its own line's wait, and the pick comes from the shared utility brain — so the same brain that picks food picks rides, and a guest's queue tolerance is a weight rather than a rule.
1564
+ - `RideChooserConfig` (interface): interface RideChooserConfig — Everything a ride chooser needs: the park, the guest's taste, and the guest's needs.
1565
+ - `RideChooserSnapshot` (interface): interface RideChooserSnapshot — Serializable chooser state: the guest's taste and the brain's held pick.
1566
+ - `RideDefinition` (interface): interface RideDefinition — Everything a ride is: its ratings, its cycle and its wear. Content, not code.
1567
+ - `RidePhase` (type): type RidePhase = "idle" | "loading" | "riding" | "unloading" | "broken" — Where a ride is in its cycle.
1568
+ - `RideQueueView` (interface): interface RideQueueView — A ride's line as a game or the devtools overlay reads it.
1569
+ - `RideRatingRange` (interface): interface RideRatingRange — The rating scale a park's taste curves are normalized against.
1570
+ - `RideRatings` (interface): interface RideRatings — What a ride is worth to a guest. All three come from the ride's own data.
1571
+ - `RideRetune` (interface): interface RideRetune — In-play dials a ride accepts from {@link RideSystem.retune}.
1572
+ - `RideServiceResult` (interface): interface RideServiceResult — What a service cost the caller.
1573
+ - `RideStats` (interface): interface RideStats — Counters a devtools probe or test reads.
1574
+ - `RideSystem` (interface): interface RideSystem — The park's rides: each runs its own load → ride → unload cycle at its own capacity, takes guests off its own line, wears out against its own breakdown curve, and reports its own repairs and services. The clock is internal and only `tick` moves it, so a replay, a save and a test read the same cycle.
1575
+ - `RideSystemConfig` (interface): interface RideSystemConfig — Everything a ride system needs.
1576
+ - `RideSystemSnapshot` (interface): interface RideSystemSnapshot — Serializable park state: the clock, each ride's cycle position, wear and line.
1577
+ - `RideTaste` (interface): interface RideTaste — What one guest wants from a ride: the intensity and nausea they are comfortable with, and how long they will stand in line. All three are the guest's own data.
1578
+ - `RideTickSink` (interface): interface RideTickSink — Where a ride's boardings, alightings and breakdowns are announced. Every hook is optional.
1579
+ - `RideView` (interface): interface RideView — One ride's live state.
1580
+ - `RideWaitSource` (interface): interface RideWaitSource — The live queue a ride-choice candidate is costed against. {@link RideSystem} satisfies this.
1406
1581
  - `Ring` (interface): interface Ring — ⚠ undocumented
1407
1582
  - `RingConfig` (interface): interface RingConfig { center: RingPoint; phases: readonly RingPhase[] } — ⚠ undocumented
1408
1583
  - `RingPhase` (interface): interface RingPhase { startTime: number; shrinkDuration: number; fromRadius: number; toRadius: number; damagePerSecond: number; center?: RingPoint } — ⚠ undocumented
@@ -1427,6 +1602,7 @@
1427
1602
  - `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.
1428
1603
  - `RunModifierOffer` (interface): interface RunModifierOffer<TStat extends string = string, TData = unknown> { id: string; weight: number; maxStacks?: number; label?: string; stats?: StatModifierSet<TStat>; data?: TData } — ⚠ undocumented
1429
1604
  - `SaleRecord` (interface): interface SaleRecord — One completed sale recorded into a {@link PriceHistory}.
1605
+ - `SaveAutoConfig` (interface): interface SaveAutoConfig — Autosave cadence: debounce writes `debounceMs` after the last edit, but never wait longer than `maxWaitMs` while edits keep coming (`0` removes the ceiling). `autosave: true` uses `{ debounceMs: 1000, maxWaitMs: 15000 }`.
1430
1606
  - `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.
1431
1607
  - `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.
1432
1608
  - `SaveSlotWrite` (interface): interface SaveSlotWrite — What a {@link SaveSlots.write} stamps onto a slot — a name and/or a fresh `meta` bag.
@@ -1435,6 +1611,7 @@
1435
1611
  - `SaveSlotsSnapshot` (interface): interface SaveSlotsSnapshot — Serializable state of a {@link SaveSlots} index, for save/restore.
1436
1612
  - `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"` includes rejected reads, writes, removals and slot metadata updates; metadata failure can follow a successful payload write.
1437
1613
  - `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.
1614
+ - `SaveTimers` (interface): interface SaveTimers — The timer seam autosave schedules through — defaults to the ambient `setTimeout`/`clearTimeout`; inject fakes in tests.
1438
1615
  - `ScheduledDelivery` (interface): interface ScheduledDelivery { userId: string; inventoryId: string; items: readonly ItemStack[]; deliverAt: number } — ⚠ undocumented
1439
1616
  - `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.
1440
1617
  - `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.
@@ -1518,6 +1695,8 @@
1518
1695
  - `TrackedObjectiveView` (interface): interface TrackedObjectiveView — One objective as a tracker/HUD reads it — label + progress toward its count.
1519
1696
  - `TrackedQuestView` (interface): interface TrackedQuestView — A quest as a tracker/HUD reads it — title, status, and per-objective progress.
1520
1697
  - `TrainableUnitDef` (interface): interface TrainableUnitDef — A unit the producer can train.
1698
+ - `TransactionLedger` (interface): interface TransactionLedger — The books: balances with a reason-tagged journal, and recurring charges on a cadence.
1699
+ - `TransactionLedgerOptions` (interface): interface TransactionLedgerOptions — Options for {@link createTransactionLedger}.
1521
1700
  - `TransformApi` (interface): interface TransformApi — Mutation surface a {@link GenTransform} uses to derive numeric fields after choices resolve. Every `set`/`add`/`mul` is captured as a {@link GenFieldRecord}, and `rng` is the same injected stream the choices drew from, so rolled derivations stay deterministic and explainable.
1522
1701
  - `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.
1523
1702
  - `TriggeredRuleEngine` (interface): interface TriggeredRuleEngine — A running set of triggered rules with gating, timed lifetimes, stacking, cleanup, and save/load.
@@ -1542,7 +1721,19 @@
1542
1721
  - `VfxInstanceStoreOptions` (interface): interface VfxInstanceStoreOptions — Options for {@link createVfxInstanceStore}.
1543
1722
  - `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.
1544
1723
  - `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.
1724
+ - `Visitor` (interface): interface Visitor — One visitor on site: the id its body, its needs and its money are keyed by.
1725
+ - `VisitorFlow` (interface): interface VisitorFlow — What a flow policy reads to decide how many arrive and when one has had enough.
1726
+ - `VisitorPolicy` (interface): interface VisitorPolicy — The game's flow policy: what draws visitors in, how many fit, and when one has had enough.
1727
+ - `VisitorPolicyPatch` (interface): interface VisitorPolicyPatch — Flow policy fields a scenario can change in play.
1728
+ - `VisitorPopulation` (interface): interface VisitorPopulation — The crowd a scene reports. Every visitor is a member with a body the game's world made, so the on-site figure is the member count and the daily figure is the sum of admissions the world accepted — there is no second tally to drift from what is on the ground. Arrivals, capacity and leaving are the game's policy; ids, day rollover and counting are this seam's.
1729
+ - `VisitorPopulationOptions` (interface): interface VisitorPopulationOptions — Options for {@link createVisitorPopulation}.
1730
+ - `VisitorPopulationSnapshot` (interface): interface VisitorPopulationSnapshot — Serializable state. No on-site count is stored: it is the restored visitor list.
1731
+ - `VisitorPopulationStats` (interface): interface VisitorPopulationStats — Counters a HUD, a probe or a test reads. The on-site figure is the visitor list's length.
1732
+ - `VisitorWorld` (interface): interface VisitorWorld — The game's world behind every counted visitor: it creates and removes the body.
1545
1733
  - `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).
1734
+ - `WaitQueue` (interface): interface WaitQueue — A real line: guests join the back, leave the head, and the wait a new arrival faces comes from how fast this queue has actually been boarding — not from a configured constant. A broken ride stops boarding, the line grows, and the estimate grows with it.
1735
+ - `WaitQueueOptions` (interface): interface WaitQueueOptions — Tunables for {@link createWaitQueue}, every one retunable through a restore.
1736
+ - `WaitQueueSnapshot` (interface): interface WaitQueueSnapshot — Serializable line state: who is waiting, and the boardings the estimate is measured from.
1546
1737
  - `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.
1547
1738
  - `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}.
1548
1739
  - `WorkQueueState` (interface): interface WorkQueueState<TSpec, TReserve = undefined> — Serializable queue state. Holds only non-terminal jobs, so it stays bounded.
@@ -1567,6 +1758,7 @@
1567
1758
  - `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.
1568
1759
  - `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.
1569
1760
  - `applyBindingOverrides` (function): function applyBindingOverrides<TAction extends string, TCode extends string>(input: ActionCodesMap<TAction, TCode>, overrides: BindingOverrides): ActionCodesMap<TAction, TCode> — Merge player rebinds over a game's authored `input` map. Only actions the game already declares can be overridden; unknown override keys are ignored so a stale localStorage entry can't inject phantom actions.
1761
+ - `applyMissionRewards` (function): function applyMissionRewards(rewards: MissionRewards, appliers: MissionRewardAppliers): { reason: string } | null — Apply a mission's rewards through the same appliers quests use, then roll any named loot tables. Economy, XP, items and unlocks go through {@link applyQuestRewards}; loot is a table id the game's loot registry resolves, so a mission never grows its own reward path.
1570
1762
  - `applySetBonuses` (function): function applySetBonuses(stats: Record<string, number>, bonuses: readonly SetBonus[]): Record<string, number> — Fold a set of active bonuses' additive stats onto a stat map, returning a new map (the input is not mutated).
1571
1763
  - `applyWear` (function): function applyWear(state: DurabilityState, amount: number): DurabilityState — Apply wear to an item, tracking breakage and repair eligibility.
1572
1764
  - `assertLootCatalog` (function): function assertLootCatalog(catalog: LootCatalog): void — Check a catalog before rolling; throws `RangeError` naming the offending entry.
@@ -1574,6 +1766,7 @@
1574
1766
  - `assertXpCurve` (function): function assertXpCurve(def: XpCurveDef): void — Check curve data before use; throws `RangeError` naming the offending field.
1575
1767
  - `balance` (function): function balance(state: WalletState, currency: string | CurrencyDefinition): number — ⚠ undocumented
1576
1768
  - `balanceOf` (function): function balanceOf(ledger: ResourceLedger, account: string, currency: string): number — Read a single balance; unknown account/currency pairs read as `0`.
1769
+ - `buildLoanSchedule` (function): function buildLoanSchedule(terms: LoanTerms): LoanSchedule — Build a loan's repayment schedule: one entry per period with its due time, interest/principal split and the balance left, in integer minor units. An amortized loan levels the payment over the outstanding balance (`P·i / (1 − (1+i)^−n)`); a flat loan charges interest on the original principal. Either way the final payment absorbs the rounding, so the principal parts sum to the principal exactly and the balance ends at zero. Deterministic and pure.
1577
1770
  - `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).
1578
1771
  - `canCraft` (function): function canCraft(state: InventoryState, layout: InventoryLayout, traits: ItemTraits, recipe: RecipeDef, context: CraftContext = {}): CraftCheck — ⚠ undocumented
1579
1772
  - `cancelJob` (function): function cancelJob<TSpec, TReserve, TOutput>(state: WorkQueueState<TSpec, TReserve>, config: WorkQueueConfig<TSpec, TReserve, TOutput>, id: JobId): CancelResult<TSpec, TReserve> — Cancel a job and compute its refund. Removes the job from the queue and returns a refund payload (full reservation by default, or `config.refund` applied to the job's progress for partial/no refund). Applying the refund is the caller's job.
@@ -1583,6 +1776,7 @@
1583
1776
  - `captureProvenance` (function): function captureProvenance(identity: ItemIdentity, activeBonuses: readonly SetBonus[], seed?: number): ItemProvenance — Capture the provenance of a generated item — family, tags, per-slot parts, active bonus ids, and optional seed — as a JSON-safe record.
1584
1777
  - `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.
1585
1778
  - `chargeAll` (function): function chargeAll(state: WalletState, costs: Readonly<Record<string, number>>, options?: ChargeOptions): ChargeResult — ⚠ undocumented
1779
+ - `chaseMission` (function): function chaseMission(options: ChaseMissionOptions): MissionDef — A target kept close until it is caught: a `pursue` objective with an escape distance and grace, and an optional `reach` objective to close the chase. The pursuit is the same primitive a bodyguard detail uses; only the numbers differ.
1586
1780
  - `clampValue` (function): function clampValue(value: number, bounds?: NumericBounds): number — Clamp a scalar to `bounds` (identity when `bounds` is omitted). Pure — touches no record.
1587
1781
  - `clearBindingOverride` (function): function clearBindingOverride(gameId: string, action: string, storage: Pick<WebStorageLike, "getItem" | "setItem" | "removeItem"> | null | undefined = defaultStorage()): BindingOverrides — ⚠ undocumented
1588
1782
  - `compareGearSets` (function): function compareGearSets(a: Readonly<Record<string, GearSlotItem | null | undefined>>, b: Readonly<Record<string, GearSlotItem | null | undefined>>, options: GearScoreOptions = {}): { a: GearScore; b: GearScore; delta: number; better: "a" | "b" | "equal" } — Compare two loadouts; negative means `a` scores lower.
@@ -1613,6 +1807,7 @@
1613
1807
  - `createGameDialogue` (function): function createGameDialogue(store: DialogueStore): GameDialogue — Build a {@link GameDialogue} over one keyed-store slot. Writes flow through the reactive store, so opening or closing bumps `ctx.version()` and a `useOpenDialogueId` selector re-renders.
1614
1808
  - `createGameEvents` (function): function createGameEvents<TMap extends GameEventMap = GameEventMap>(): GameEvents<TMap> — A typed publish/subscribe bus for gameplay events that systems and HUDs subscribe to.
1615
1809
  - `createGameFeed` (function): function createGameFeed(options?: GameFeedOptions): GameFeed — A rolling per-action feed of recent gameplay events, bindable to the event bus — the HUD ticker and killfeed history.
1810
+ - `createGameSave` (function): function createGameSave(config: GameSaveConfig): GameSave — Create a {@link GameSave}. Register every stateful system once; `capture()` writes one versioned document with a section per system, `save()`/`touch()` persist it through the injected backend (autosave cadence is the caller's), `load()` restores every section and the shared RNG cursor, and `digest()`/`digests()` give a determinism test a hash over the whole state.
1616
1811
  - `createGestureSurfaceTracker` (function): function createGestureSurfaceTracker(bindings: TouchGestureBindings, tuning: GestureSurfaceTuning = DEFAULT_GESTURE_TUNING): GestureSurfaceTracker — ⚠ undocumented
1617
1812
  - `createIntentBoard` (function): function createIntentBoard<TKind extends string = string>(): IntentBoard<TKind> — ⚠ undocumented
1618
1813
  - `createItemInstanceRegistry` (function): function createItemInstanceRegistry<TDef>(prefix = "item", options: ItemInstanceRegistryOptions<TDef> = {}): ItemInstanceRegistry<TDef> — Builds an {@link ItemInstanceRegistry}; generated ids are `"<prefix>:<baseId>:<n>"`, unique per registry instance.
@@ -1624,9 +1819,13 @@
1624
1819
  - `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.
1625
1820
  - `createListingBook` (function): function createListingBook(config: ListingBookConfig): ListingBook — A player-driven listing marketplace: post/cancel/buy against a shared book with a house cut on every sale, an expiry sweep that pulls unsold goods out of circulation, and a per-seller collection box holding sale proceeds and returned items until claimed. Buyer/seller wallet and inventory movement is the caller's job (mirrors `game/trade`'s split) — this primitive owns only the listing lifecycle and the escrowed collection-box bookkeeping behind it.
1626
1821
  - `createLoadouts` (function): function createLoadouts(deps: LoadoutDeps): Loadouts — Save, name, and swap equipment loadouts.
1822
+ - `createLoanBook` (function): function createLoanBook(options: LoanBookOptions): LoanBook — The loans a business owes, over a {@link TransactionLedger}: each draw posts the principal to the borrower's account, each settled payment posts its interest (`"loan-interest"`) and principal (`"loan-principal"`) as separate reason-tagged entries, and an early repayment posts `"loan-repayment"`. A payment that comes due with no funds is left in arrears and counted once per advance; after `maxMissed` the loan is defaulted and stops being advanced. State is plain data — `snapshot()` stores terms and progress, and the schedule is rebuilt from the terms.
1627
1823
  - `createLootPipeline` (function): function createLootPipeline<TCtx = unknown>(def: LootPipelineDef<TCtx>, deps: LootPipelineDeps = {}): LootPipeline<TCtx> — Build a composable loot-resolution pipeline: ordered source pools, context gates, fallbacks when a pool yields nothing, roll modifiers (luck, quantity, difficulty) applied as registered policies, and full provenance for every drop (stage, table, entry, original vs effective weights, modifier ids, seed). Rolling consumes the injected RNG in the same order as the base loot table, so a seeded resolution is deterministic and server-authoritatively replayable. Genre concepts (world, dedicated, boss, luck, rarity, pity) stay out of core and ship as stage/modifier compositions.
1628
1824
  - `createLootRegistry` (function): function createLootRegistry(options: LootRegistryOptions = {}): LootRegistry — Register named loot tables and roll weighted randomized drops from them.
1629
1825
  - `createLootRoller` (function): function createLootRoller(catalog: LootCatalog, options: LootRollerOptions = {}): LootRoller — Wrap a catalog in a roll counter: same results as {@link rollLoot}, plus counts by rarity for a debug overlay, snapshot/restore of those counts, and an optional devtools probe.
1826
+ - `createMarket` (function): function createMarket(config: MarketConfig = {}): Market — A market whose price comes from supply and demand over finite stock, as plain serializable state.
1827
+ - `createMissionRuntime` (function): function createMissionRuntime(config: MissionRuntimeConfig): MissionRuntime — Run missions as a state machine. One mission is active at a time; `tick` advances it against the world the caller supplies, moving through objectives on completion, branching on facts, and landing in a named fail state on a fail condition, an expiry or a `minSurvivors` breach. Completion pays rewards through {@link applyMissionRewards} appliers the caller wires, and a mission's `next` chains the follow-up. Escort, chase and defend are compositions of the same objective kinds (`compositions.ts`), never three bespoke systems.
1828
+ - `createMissionTriggerBridge` (function): function createMissionTriggerBridge(options: { runtime: MissionRuntime; document: SceneDocumentLike; triggers?: readonly AuthoredTrigger[]; }): MissionTriggerBridge — Wire authored markers to a {@link MissionRuntime}: an actor entering a `mission_start` marker starts the named mission, `mission_objective` completes the named objective, and `mission_fail` lands the named fail state. Pure membership math over the document, exactly like any other authored trigger.
1630
1829
  - `createModularItem` (function): function createModularItem(def: ModularItemDef, initial: readonly InstalledPart[] = []): ModularItem — ⚠ undocumented
1631
1830
  - `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.
1632
1831
  - `createMultiRegionHealth` (function): function createMultiRegionHealth(config: MultiRegionHealthConfig): MultiRegionHealth — Per-region/limb health tracked separately, so each body part takes and heals damage on its own.
@@ -1645,6 +1844,8 @@
1645
1844
  - `createRecipeGraph` (function): function createRecipeGraph(defs: readonly RecipeDef[] = []): RecipeGraph — ⚠ undocumented
1646
1845
  - `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.
1647
1846
  - `createResourceLedger` (function): function createResourceLedger(init?: Partial<ResourceLedger>): ResourceLedger — Create an empty scheduled-transaction ledger, or hydrate one from a saved snapshot. State is plain data: production, depletion, tax, and upkeep are all expressed as {@link ScheduledRule}s settled deterministically by {@link advanceLedger}.
1847
+ - `createRideChooser` (function): function createRideChooser(config: RideChooserConfig): RideChooser — Create one guest's ride choice over a park. Options are rebuilt when the park is retuned, so a coaster whose track changes its ratings is re-scored without rebuilding the guest.
1848
+ - `createRideSystem` (function): function createRideSystem(config: RideSystemConfig): RideSystem — Create the rides a park runs. Each ride cycles on its own data, boards from its own line up to its own capacity, wears against its own breakdown curve and reports its repairs through the sink, so the caller keeps the wallet, the bodies and the visuals.
1648
1849
  - `createRing` (function): function createRing(config: RingConfig): Ring — ⚠ undocumented
1649
1850
  - `createRuleRegistry` (function): function createRuleRegistry<TPayload = unknown>(initial?: readonly RuleDef<TPayload>[]): RuleRegistry<TPayload> — Create a {@link RuleRegistry}. Rules install through `register` (duplicate ids throw); selection and `layersFor` are data-driven, so the core never branches on which mutators exist.
1650
1851
  - `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.
@@ -1658,12 +1859,15 @@
1658
1859
  - `createTalentTree` (function): function createTalentTree<TStat extends string = string>(config: TalentTreeConfig<TStat>): TalentTree<TStat> — ⚠ undocumented
1659
1860
  - `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.
1660
1861
  - `createTouchGestureTracker` (function): function createTouchGestureTracker(tuning: TouchGestureTuning): TouchGestureTracker — ⚠ undocumented
1862
+ - `createTransactionLedger` (function): function createTransactionLedger(options: TransactionLedgerOptions = {}): TransactionLedger — The books a business keeps: per-account, per-currency balances in integer minor units with a journal that records every movement, the balance it produced and the reason it happened. {@link TransactionLedger.post} is the one money path — sales, purchases, upkeep and loan payments all go through it, so nothing moves without a reason on the record. {@link TransactionLedger.chargeDue} settles recurring charges (upkeep, rent) on their own cadence, bounded per advance; a cycle with no funds is counted as missed instead of overdrawing. Journal memory is bounded by `maxEntries`, with `totals()` keeping the per-reason summary beyond it.
1661
1863
  - `createTriggeredRuleEngine` (function): function createTriggeredRuleEngine(rules: readonly TriggeredRule[] = []): TriggeredRuleEngine — Create an empty triggered-rule engine. Rules are added as data; dispatching an event returns the firings the caller applies to its own effect system. Time is caller-supplied (`now` in ms), so the engine is deterministic and drives equally from a fixed-step loop or a save-restored timeline.
1662
1864
  - `createTurnLoop` (function): function createTurnLoop<TAction = unknown>(config: TurnLoopConfig): TurnLoop<TAction> — ⚠ undocumented
1663
1865
  - `createUnlockCatalog` (function): function createUnlockCatalog(defs: readonly UnlockDef[] = []): UnlockCatalog — A catalog of unlockable content gated behind conditions the player earns, tracking what is unlocked.
1664
1866
  - `createUnlocks` (function): function createUnlocks(defs: UnlockDef[] = []): Unlocks — ⚠ undocumented
1665
1867
  - `createUseBehaviorRegistry` (function): function createUseBehaviorRegistry<TWorld>(): UseBehaviorRegistry<TWorld> — Create an empty use-behavior registry. Games register their behaviors, then compose each item's stored refs into a dispatcher whose serializable state lives with the item.
1666
1868
  - `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.
1869
+ - `createVisitorPopulation` (function): function createVisitorPopulation(options: VisitorPopulationOptions): VisitorPopulation — Create the population a scene reports, with the game owning arrival and leaving policy. A visitor only exists once the world has made its body, so the HUD's count and the bodies on screen are the same list: `admit` returning `null` is a refused arrival, not a number.
1870
+ - `createWaitQueue` (function): function createWaitQueue(options: WaitQueueOptions = {}): WaitQueue — Create a line whose wait estimate is derived from its own throughput. The queue owns the order and the measurement; the ride owns how fast guests are taken off the head, so a slower cycle raises the estimate without the queue being told a cycle time.
1667
1871
  - `createWeaponStats` (function): function createWeaponStats(resolveEntry: (itemId: string) => WeaponEntry | null | undefined): WeaponStats — Resolve per-weapon stat values — damage, fire rate, spread — for combat math.
1668
1872
  - `createWorkQueue` (function): function createWorkQueue<TSpec, TReserve = undefined>(): WorkQueueState<TSpec, TReserve> — Create an empty timed work queue.
1669
1873
  - `crossThresholds` (function): function crossThresholds<Id>(boundaries: readonly ThresholdBoundary<Id>[], before: number, after: number, options: CrossThresholdsOptions = {}): ThresholdCrossing<Id>[] — Report every boundary crossed moving from `before` to `after`.
@@ -1674,6 +1878,7 @@
1674
1878
  - `decayMeterState` (function): function decayMeterState(values: DecayMeterValues, defs: readonly DecayMeterConfig[], id: string): DecayMeterState — Numeric state (value, bounds, 0..1 fraction) for one meter. Throws on an unknown id.
1675
1879
  - `decayMeters` (function): function decayMeters(values: DecayMeterValues, defs: readonly DecayMeterConfig[], dt: number, modifier?: DecayModifier): DecayMeterValues — Pure per-tick decay over plain data: drain (or fill) every meter by `rate * modifier * dt`, clamped to its range, returning a new `id → value` record. Returns `values` unchanged when `dt <= 0`. The serializable counterpart to {@link DecayMeterSet.tick}.
1676
1880
  - `defaultObjectiveLabel` (function): function defaultObjectiveLabel(objective: QuestObjective): string — Default objective label: a readable "verb count noun" from a {@link QuestObjective}.
1881
+ - `defendMission` (function): function defendMission(options: DefendMissionOptions): MissionDef — Hold a position for a duration, scored by what is left standing: one `survive` objective whose `minSurvivors` gate is the fail condition and whose completion banks the survivors as the mission score. Same primitive a timed delivery uses, with a guard.
1677
1882
  - `defineLootPipeline` (function): function defineLootPipeline<TCtx = unknown>(def: LootPipelineDef<TCtx>): LootPipelineDef<TCtx> — Validate a loot pipeline definition and return it unchanged, for use with {@link createLootPipeline}.
1678
1883
  - `defineSystem` (function): function defineSystem(definition: SystemDefinition): SystemDefinition — Declare a composable game system. Pure data + hooks — the engine compiles the schedule and installs lifecycle when the game boots.
1679
1884
  - `defineXpCurve` (function): function defineXpCurve(def: XpCurveDef): XpCurve — Resolve authored XP curve data: the threshold per level, the lifetime XP it sits at, a plain-words growth rule, and the level an XP total reaches under the cap. One data record with one growth rule keeps a rebalance in the save-visible definition rather than in formulas scattered across a game.
@@ -1687,6 +1892,7 @@
1687
1892
  - `driftValue` (function): function driftValue(record: Record<string, number>, key: string, rate: number, rest = 0, bounds?: NumericBounds): number — Decay `key` toward a `rest` value (default `0`) by `rate` per call — the common "relationships cool off" / "heat fades" drift. Thin wrapper over {@link towardValue}.
1688
1893
  - `durabilityFraction` (function): function durabilityFraction(state: DurabilityState): number — ⚠ undocumented
1689
1894
  - `enqueue` (function): function enqueue<TSpec, TReserve, TOutput>(state: WorkQueueState<TSpec, TReserve>, config: WorkQueueConfig<TSpec, TReserve, TOutput>, spec: TSpec, options?: EnqueueOptions): EnqueueResult<TSpec, TReserve> — Enqueue a new job. Validates capacity and the injected `validate` policy, then computes and stores the reservation. Charging the reservation (now or later) is the caller's responsibility using {@link EnqueueResult.job}'s `reservation`.
1895
+ - `escortMission` (function): function escortMission(options: EscortMissionOptions): MissionDef — A protected actor that must reach a destination: a `reach` objective for the escortee, a `actor-died` fail condition on the escortee, and an optional timer. No escort system — the same `reach` objective a "go here" mission uses, plus the guard data.
1690
1896
  - `evalCurve` (function): function evalCurve(spec: Curve, x: number): number — Evaluate a progression {@link Curve} at position `x`, applying its rounding mode and min/max clamp. This is the shared numeric backbone for XP-per-level, cost ramps, difficulty scaling, and any other level/rank → value mapping — use it instead of hand-rolling growth formulas.
1691
1897
  - `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.
1692
1898
  - `evaluateObjective` (function): function evaluateObjective(objective: ThresholdObjective, value: number): ObjectiveStatus — Evaluate a single live-metric objective: is `value` at least (or at most) the target, and how far along. Unlike an event counter, this reads a continuously-changing metric — population, approval, pollution — the objective shape city-builders and management sims track every tick.
@@ -1696,6 +1902,7 @@
1696
1902
  - `finishRaceSession` (function): function finishRaceSession(session: RaceSessionState): RaceSessionState — Cross the flag: move a `racing` session to `finished`, freezing its `elapsed`. A no-op in any other phase.
1697
1903
  - `firstPastPost` (function): function firstPastPost(count = 1): RaceWinCondition — Race ends when `count` racers have crossed the finish; ranking is the current standings order.
1698
1904
  - `gamePhase` (function): function gamePhase(ctx: GameContext): GamePhase — Current phase; defaults to `playing` when unset — a game that runs live from boot declares that intent explicitly with `defineGame({ lifecycle: "always-live" })` rather than relying on the silent default.
1905
+ - `gameSaveDigest` (function): function gameSaveDigest(document: GameSaveDocument): string — A stable hash over the state-bearing part of a document — every system section, the world clock and the shared RNG cursor — excluding the wall-clock `savedAt`, which is not state.
1699
1906
  - `gearScore` (function): function gearScore(set: Readonly<Record<string, GearSlotItem | null | undefined>>, options: GearScoreOptions = {}): GearScore — Score a whole loadout with one documented formula:
1700
1907
  - `generate` (function): function generate(schema: GenSchema, rng: () => number, options: GenerateOptions = {}): GenOutcome — Run a caller-defined {@link GenSchema} against an injected `rng` into a deterministic, serializable {@link GenResult} with full provenance. Composes weighted/uniform choice, dependent choice, constraints with bounded backtracking, field transforms, and validation reroll over plain data — the generic seam procedural loot, affix, and modular-part rollers assemble on. Identical schema, seed, and pins reproduce an identical result across server/client and save/load.
1701
1908
  - `getRuleEffect` (function): function getRuleEffect(id: string): RuleEffectDefinition | undefined — Look up a declared rule effect, or `undefined` when the id was never registered — lets callers reject unknown effect references in authored content.
@@ -1707,6 +1914,7 @@
1707
1914
  - `install` (function): function install(def: ModularItemDef, installed: readonly InstalledPart[], slotId: string, part: PartDef): InstallResult — ⚠ undocumented
1708
1915
  - `insureLost` (function): function insureLost(lost: readonly ItemStack[], policy: InsurancePolicy, userId: string, now: number, rng?: () => number): ScheduledDelivery | null — ⚠ undocumented
1709
1916
  - `isComplete` (function): function isComplete(def: ModularItemDef, installed: readonly InstalledPart[]): boolean — ⚠ undocumented
1917
+ - `isCounterObjective` (function): function isCounterObjective(kind: MissionObjectiveKind): boolean — True when an objective kind completes from a counter rather than a world condition — the test the counter-only lint is built on.
1710
1918
  - `isDisabled` (function): function isDisabled(spec: DurabilitySpec, state: DurabilityState): boolean — ⚠ undocumented
1711
1919
  - `isIdentityValid` (function): function isIdentityValid(identity: ItemIdentity, rules: readonly CompatibilityRule[]): boolean — Convenience predicate: true when {@link validateIdentity} finds no violations.
1712
1920
  - `isOverdrawn` (function): function isOverdrawn(state: WalletState, currency: string | CurrencyDefinition): boolean — True once `balance(state, currency)` has gone negative under an overdraft-enabled charge.
@@ -1726,6 +1934,7 @@
1726
1934
  - `medalFor` (function): function medalFor(rank: number): "gold" | "silver" | "bronze" | null — A free-string medal token for the top-three ranks — `"gold"` (1), `"silver"` (2), `"bronze"` (3) — or `null` for any other rank. It is a semantic token, not a color: the UI maps it to an icon/color/theme, and the model never styles. Feed it a {@link RankedEntry.rank}.
1727
1935
  - `memorySaveBackend` (function): function memorySaveBackend(): SaveBackend — A memory-only {@link SaveBackend} — saves survive a reload only within the same session. For tests, SSR, or a "no persistence" mode that still exercises the same save code path.
1728
1936
  - `missingRequiredSlots` (function): function missingRequiredSlots(def: ModularItemDef, installed: readonly InstalledPart[]): string[] — ⚠ undocumented
1937
+ - `missionMarkers` (function): function missionMarkers(document: SceneDocumentLike): Record<string, ScenePoint3> — Marker positions from an authored scene, keyed by marker id — what a positional objective reads.
1729
1938
  - `moveCards` (function): function moveCards(state: CardPileState, ids: readonly string[], from: ZoneName, to: ZoneName, position: "top" | "bottom" = "top"): PileResult — ⚠ undocumented
1730
1939
  - `normalizePointerToAxis` (function): function normalizePointerToAxis(clientX: number, clientY: number, rect: PointerSurfaceRect): PointerAxisState — Normalize client coordinates against a surface rect into a `PointerAxisState`, clamped to `[-1, 1]` per axis.
1731
1940
  - `orderLayers` (function): function orderLayers(layers: readonly ParamLayer[]): readonly ParamLayer[] — Order layers into their well-defined application sequence: ascending `priority`, ties broken by the layer's index in `layers` (a stable sort). Same input, same order, on every platform.
@@ -1755,6 +1964,7 @@
1755
1964
  - `recallExpedition` (function): function recallExpedition<TCtx>(config: ExpeditionConfig<TCtx>, state: ExpeditionState, nowMs: number): ExpeditionState — Settle first, then recall safely. If the catch-up budget leaves due exploring ticks, return that state without recalling; repeat at the same target until the frontier catches up. Dead state never revives.
1756
1965
  - `redirect` (function): function redirect(endpoints: { source?: string; recipient?: string }): ResourcePolicy — Override the source and/or recipient accounts of a transaction.
1757
1966
  - `refillMeter` (function): function refillMeter(values: DecayMeterValues, defs: readonly DecayMeterConfig[], id: string, amount: number): DecayMeterValues — Refill (or drain, if negative) one meter by `amount`, clamped to its range. Returns a new record; throws on an unknown id. The pure counterpart to {@link DecayMeterSet.refill}.
1967
+ - `registerMissionTriggerActions` (function): function registerMissionTriggerActions(): void — Register {@link MISSION_TRIGGER_ACTIONS} so the editor lists them. Idempotent; call at module load next to the game's catalogs.
1758
1968
  - `registerRuleEffect` (function): function registerRuleEffect(definition: RuleEffectDefinition): void — Declare a rule effect id. Idempotent per id (last registration wins); call at module load next to catalogs so authored content and inspectors share one vocabulary.
1759
1969
  - `rejectWhen` (function): function rejectWhen(predicate: (txn: ResourceTransaction, ctx: PolicyContext) => boolean): ResourcePolicy — Drop a transaction when `predicate` holds — the reject arm of the pipeline.
1760
1970
  - `remoteSaveBackend` (function): function remoteSaveBackend(backend: SaveBackend): SaveBackend — Adopt any async `read`/`write`/`remove` trio as a {@link SaveBackend} — the seam for cloud saves backed by a database, an HTTP endpoint, or Convex (see `@jgengine/convex/convexSaveBackend`). Reads/writes may reject; the save store surfaces the failure as `"error"` status instead of throwing.
@@ -1769,6 +1979,10 @@
1769
1979
  - `resumeJob` (function): function resumeJob<TSpec, TReserve>(state: WorkQueueState<TSpec, TReserve>, id: JobId): WorkQueueState<TSpec, TReserve> — Resume a paused job; it re-enters the queue and competes for a slot by ordering.
1770
1980
  - `resumeRule` (function): function resumeRule(ledger: ResourceLedger, ruleId: string): ResourceLedger — Resume a paused rule. Its `nextDueSeconds` is unchanged, so the paused span counts as missed cycles that the rule's {@link CatchUpPolicy} decides how to settle on the next advance.
1771
1981
  - `returnExpeditionNow` (function): function returnExpeditionNow<TCtx>(config: ExpeditionConfig<TCtx>, state: ExpeditionState, nowMs: number): ExpeditionState — Settle first, then complete a live return instantly. Caller owns payment/authorization; pending ticks remain unsettled when the budget is exhausted, and dead/home state is never changed.
1982
+ - `rideAppeal` (function): function rideAppeal(ratings: RideRatings, taste: RideTaste, range: RideRatingRange = DEFAULT_RIDE_RATING_RANGE): number — One ride's standing appeal to one guest, before queue cost. Excitement draws, force and nausea push back — what a guest's own card or thought bubble can show.
1983
+ - `rideChoiceCandidates` (function): function rideChoiceCandidates(source: RideWaitSource, out: UtilityCandidate[] = []): UtilityCandidate[] — Cost each ride by the wait its own line reports, so a guest weighs a ride by seconds in line rather than by a fixed order. `out` is reused for the array; the candidate records are not.
1984
+ - `rideChoiceOptions` (function): function rideChoiceOptions(rides: readonly RideDefinition[], taste: RideTaste, policy: RideChoicePolicy = {}): UtilityOption[] — Compile a guest's taste and the park's ride data into utility options, so the guest's pick comes from `createUtilityBrain` like every other decision it makes. Ride choice is one more set of options a guest can score, not a separate scoring function.
1985
+ - `rideQueueCostWeight` (function): function rideQueueCostWeight(taste: RideTaste): number — Score points per second of queue wait: a guest's own tolerance is the denominator. A guest who merges rides into a brain that also scores food and exits uses this as its `costWeight`.
1772
1986
  - `ringSampleAt` (function): function ringSampleAt(config: RingConfig, time: number): RingSample — ⚠ undocumented
1773
1987
  - `rollLoot` (function): function rollLoot(catalog: LootCatalog, rng: () => number, options: LootRollOptions = {}): LootItem — Roll one item from a catalog: a base and maker, a weighted rarity, one part per slot, rarity-count affixes, level-scaled stats and a name composed from maker, rarity, part, affix words and base. Deterministic for a given `rng`; every field it reads is caller data. Validate a catalog built outside {@link createLootRoller} once with {@link assertLootCatalog} before rolling from it.
1774
1988
  - `runPipeline` (function): function runPipeline<V>(base: V, modifiers: readonly Modifier<V>[], equals: (a: V, b: V) => boolean = Object.is): PipelineResult<V> — ⚠ undocumented
@@ -1807,6 +2021,7 @@
1807
2021
  - `validateIdentity` (function): function validateIdentity(identity: ItemIdentity, rules: readonly CompatibilityRule[]): ConstraintViolation[] — Collect every compatibility rule a completed identity violates. An empty result means the identity is legal.
1808
2022
  - `validateLayers` (function): function validateLayers(layers: readonly ParamLayer[]): readonly LayerConflict[] — Detect design conflicts in a layer set before resolving: duplicate ids, and competing `set` ops on the same parameter at the same priority (order-dependent, so worth surfacing). Returns an empty array when the set is clean, so callers can gate a difficulty/session build on it.
1809
2023
  - `validateLootItem` (function): function validateLootItem(item: LootItem, catalog: LootCatalog): LootValidationIssue[] — Check one rolled item against its catalog: base, maker and rarity exist, every slot holds an eligible part, affixes belong to the base's pools, stats are finite and the item is named.
2024
+ - `validateMissionCatalog` (function): function validateMissionCatalog(missions: readonly MissionDef[], options: MissionValidationOptions = {}): MissionIssue[] — Validate a mission catalog without mutation: duplicate ids, unknown branch/next targets, unknown fail states and markers, per-kind required fields, unreachable objectives, and the counter-only rule — a mission that has a completion path made entirely of `kill`/`collect` objectives is an error, because it can be won on a counter alone.
1810
2025
  - `wear` (function): function wear(spec: DurabilitySpec, state: DurabilityState, kind: WearKind, times = 1): DurabilityState — ⚠ undocumented
1811
2026
  - `withTouchCodes` (function): function withTouchCodes(map: ActionCodesMap | undefined): ActionCodesMap — Every action gains a synthetic touch code alongside its physical codes.
1812
2027
  - `worldHealthBarAllowsRole` (function): function worldHealthBarAllowsRole(roles: readonly CatalogEntityRole[] | undefined, role: CatalogEntityRole | undefined): boolean — ⚠ undocumented
@@ -2081,6 +2296,59 @@
2081
2296
  - `LootWeaponStatMap` (interface): interface LootWeaponStatMap — Which rolled stat feeds which part of a {@link WeaponDefinition}. Every field is a stat id from the item; an omitted field keeps the template's value, so a catalog only maps what it rolls.
2082
2297
  - `lootWeaponDefinition` (function): function lootWeaponDefinition(item: LootItem, projection: LootWeaponProjection): WeaponDefinition — Project a rolled item onto a plain weapon definition: copy the template, then write the mapped stats into rate, damage, magazine, spread, range and projectile speed. The result is a {@link WeaponDefinition}, so `assertWeaponDefinition` and `createWeaponSystem` accept it unchanged.
2083
2298
 
2299
+ ## @jgengine/core/mission/compositions
2300
+
2301
+ - `ChaseMissionOptions` (interface): interface ChaseMissionOptions extends ComposedMissionOptions — Options for {@link chaseMission}: a target kept close until it is caught.
2302
+ - `ComposedMissionOptions` (interface): interface ComposedMissionOptions — Options shared by every composed mission.
2303
+ - `DefendMissionOptions` (interface): interface DefendMissionOptions extends ComposedMissionOptions — Options for {@link defendMission}: hold a position, scored by what is left standing.
2304
+ - `EscortMissionOptions` (interface): interface EscortMissionOptions extends ComposedMissionOptions — Options for {@link escortMission}: a protected actor that must reach a destination alive.
2305
+ - `chaseMission` (function): function chaseMission(options: ChaseMissionOptions): MissionDef — A target kept close until it is caught: a `pursue` objective with an escape distance and grace, and an optional `reach` objective to close the chase. The pursuit is the same primitive a bodyguard detail uses; only the numbers differ.
2306
+ - `defendMission` (function): function defendMission(options: DefendMissionOptions): MissionDef — Hold a position for a duration, scored by what is left standing: one `survive` objective whose `minSurvivors` gate is the fail condition and whose completion banks the survivors as the mission score. Same primitive a timed delivery uses, with a guard.
2307
+ - `escortMission` (function): function escortMission(options: EscortMissionOptions): MissionDef — A protected actor that must reach a destination: a `reach` objective for the escortee, a `actor-died` fail condition on the escortee, and an optional timer. No escort system — the same `reach` objective a "go here" mission uses, plus the guard data.
2308
+
2309
+ ## @jgengine/core/mission/mission
2310
+
2311
+ - `DEFAULT_ESCAPE_MULTIPLE` (const): const DEFAULT_ESCAPE_MULTIPLE: 3 — A pursuit escapes at this multiple of its keep-close distance when none is declared.
2312
+ - `DEFAULT_PURSUE_DISTANCE` (const): const DEFAULT_PURSUE_DISTANCE: 3 — Default keep-close distance (m) for a `pursue` objective.
2313
+ - `DEFAULT_REACH_RADIUS` (const): const DEFAULT_REACH_RADIUS: 2.5 — Default proximity radius (m) for a `reach` / `interact` objective.
2314
+ - `MISSION_COUNTER_KINDS` (const): const MISSION_COUNTER_KINDS: readonly MissionObjectiveKind[] — Objective kinds that are satisfied only by a counter — a mission made of these alone is a lint error.
2315
+ - `MissionActorFact` (interface): interface MissionActorFact — A live actor the machine tracks: whether it is alive and, when needed, where it is.
2316
+ - `MissionBranch` (interface): interface MissionBranch — One outgoing edge of an objective: the first branch whose `when` matches wins over `next`.
2317
+ - `MissionDef` (interface): interface MissionDef — A whole mission: the objective graph plus its fail states and rewards.
2318
+ - `MissionEvent` (type): type MissionEvent = | { kind: "started"; missionId: string; mission: MissionDef } | { kind: "objective"; missionId: string; objectiveId: string; label: string } | { kind: "branch"; missionId: string; from: string; to: string; label?: string } | { kind: "timeout"; missionId: string; objectiveId: stri… — Emitted as the machine advances.
2319
+ - `MissionEventFilter` (interface): interface MissionEventFilter — Which world events an objective counts or a fail condition reacts to. Absent fields do not filter.
2320
+ - `MissionFactCondition` (interface): interface MissionFactCondition — A readable fact test a branch or a `fact` fail condition reads. All comparators are optional.
2321
+ - `MissionFailCondition` (interface): interface MissionFailCondition — A condition that fails the mission while the objective is active. `to` names a {@link MissionFailDef}; with no `to` the mission fails with the generic `"failed"` state.
2322
+ - `MissionFailDef` (interface): interface MissionFailDef — A named fail state an objective, timer or branch can land in.
2323
+ - `MissionIssue` (interface): interface MissionIssue — A located mission-catalog problem; `path` is a JSON Pointer into the supplied catalog.
2324
+ - `MissionObjectiveDef` (interface): interface MissionObjectiveDef — One objective. Every field is content; the machine reads only these.
2325
+ - `MissionObjectiveKind` (type): type MissionObjectiveKind = "reach" | "interact" | "survive" | "pursue" | "kill" | "collect" — The primitive goals an objective can have. Escort, chase and defend are not kinds — they are compositions of these plus fail conditions and timers (see `compositions.ts`).
2326
+ - `MissionRewardAppliers` (interface): interface MissionRewardAppliers — Appliers a mission reward routes through — the same shape quests use, plus a loot-table hook.
2327
+ - `MissionRewards` (interface): interface MissionRewards extends QuestRewards — What a mission pays. Economy/XP/items/unlocks flow through the quest appliers; loot names tables.
2328
+ - `MissionRuntime` (interface): interface MissionRuntime — The mission state machine over one active mission.
2329
+ - `MissionRuntimeConfig` (interface): interface MissionRuntimeConfig — Everything a mission runtime needs.
2330
+ - `MissionRuntimeSnapshot` (interface): interface MissionRuntimeSnapshot — Serializable runtime state for a save.
2331
+ - `MissionState` (interface): interface MissionState — Serializable mission state — one active mission's position in its graph.
2332
+ - `MissionStats` (interface): interface MissionStats — Counters a devtools probe or a test reads.
2333
+ - `MissionStatus` (type): type MissionStatus = "active" | "completed" | "failed" — Where a mission is in its life.
2334
+ - `MissionTickInput` (interface): interface MissionTickInput — Everything the machine reads for one tick. All optional; a mission only touches what it declares.
2335
+ - `MissionValidationOptions` (interface): interface MissionValidationOptions — Declarations a mission catalog is validated against.
2336
+ - `MissionView` (interface): interface MissionView — Pooled per-frame readout a HUD tracker renders.
2337
+ - `MissionWorldEvent` (interface): interface MissionWorldEvent — One thing that happened in the world this tick, reported by the game. A constrained objective counts matching events and an `event` fail condition reacts to them, so the machine judges the world instead of the game polling its own counters.
2338
+ - `MissionWorldEventKind` (type): type MissionWorldEventKind = "kill" | "collect" | "deliver" — What a reported world event is.
2339
+ - `applyMissionRewards` (function): function applyMissionRewards(rewards: MissionRewards, appliers: MissionRewardAppliers): { reason: string } | null — Apply a mission's rewards through the same appliers quests use, then roll any named loot tables. Economy, XP, items and unlocks go through {@link applyQuestRewards}; loot is a table id the game's loot registry resolves, so a mission never grows its own reward path.
2340
+ - `createMissionRuntime` (function): function createMissionRuntime(config: MissionRuntimeConfig): MissionRuntime — Run missions as a state machine. One mission is active at a time; `tick` advances it against the world the caller supplies, moving through objectives on completion, branching on facts, and landing in a named fail state on a fail condition, an expiry or a `minSurvivors` breach. Completion pays rewards through {@link applyMissionRewards} appliers the caller wires, and a mission's `next` chains the follow-up. Escort, chase and defend are compositions of the same objective kinds (`compositions.ts`), never three bespoke systems.
2341
+ - `isCounterObjective` (function): function isCounterObjective(kind: MissionObjectiveKind): boolean — True when an objective kind completes from a counter rather than a world condition — the test the counter-only lint is built on.
2342
+ - `validateMissionCatalog` (function): function validateMissionCatalog(missions: readonly MissionDef[], options: MissionValidationOptions = {}): MissionIssue[] — Validate a mission catalog without mutation: duplicate ids, unknown branch/next targets, unknown fail states and markers, per-kind required fields, unreachable objectives, and the counter-only rule — a mission that has a completion path made entirely of `kill`/`collect` objectives is an error, because it can be won on a counter alone.
2343
+
2344
+ ## @jgengine/core/mission/triggers
2345
+
2346
+ - `MISSION_TRIGGER_ACTIONS` (const): const MISSION_TRIGGER_ACTIONS: readonly TriggerActionDefinition[] — The mission actions a game registers so the editor inspector can assign them to a marker or volume. Params land flat on the object's `meta` beside `on`/`action`, like any authored trigger.
2347
+ - `MissionTriggerBridge` (interface): interface MissionTriggerBridge — Watches a document's authored mission triggers against moving actors.
2348
+ - `createMissionTriggerBridge` (function): function createMissionTriggerBridge(options: { runtime: MissionRuntime; document: SceneDocumentLike; triggers?: readonly AuthoredTrigger[]; }): MissionTriggerBridge — Wire authored markers to a {@link MissionRuntime}: an actor entering a `mission_start` marker starts the named mission, `mission_objective` completes the named objective, and `mission_fail` lands the named fail state. Pure membership math over the document, exactly like any other authored trigger.
2349
+ - `missionMarkers` (function): function missionMarkers(document: SceneDocumentLike): Record<string, ScenePoint3> — Marker positions from an authored scene, keyed by marker id — what a positional objective reads.
2350
+ - `registerMissionTriggerActions` (function): function registerMissionTriggerActions(): void — Register {@link MISSION_TRIGGER_ACTIONS} so the editor lists them. Idempotent; call at module load next to the game's catalogs.
2351
+
2084
2352
  ## @jgengine/core/progression/gearScore
2085
2353
 
2086
2354
  - `GearScore` (interface): interface GearScore — A scored loadout: the total, each slot's share, each stat's signed contribution, and how complete it is.
@@ -2328,6 +2596,63 @@
2328
2596
  - `OffScreenWorld` (interface): interface OffScreenWorld — The off-screen world: every resident exists, but only the ones within the policy radius are simulated. The rest are a position, a routine phase and a needs record that only move when the clock crosses a routine boundary — no navigation, no utility scoring, no per-frame need decay.
2329
2597
  - `createOffScreenWorld` (function): function createOffScreenWorld(options: OffScreenOptions): OffScreenWorld — Create the world that decides which agents deserve a simulation. Residents are cheap state until they come near, and cheap again when they leave; the cheap state is the schedule, the needs and the last place, so a returning resident never pops in at the origin.
2330
2598
 
2599
+ ## @jgengine/core/sim/population
2600
+
2601
+ - `Visitor` (interface): interface Visitor — One visitor on site: the id its body, its needs and its money are keyed by.
2602
+ - `VisitorAdoption` (interface): interface VisitorAdoption — How a body the game made itself joins the population.
2603
+ - `VisitorFlow` (interface): interface VisitorFlow — What a flow policy reads to decide how many arrive and when one has had enough.
2604
+ - `VisitorPolicy` (interface): interface VisitorPolicy — The game's flow policy: what draws visitors in, how many fit, and when one has had enough.
2605
+ - `VisitorPolicyPatch` (interface): interface VisitorPolicyPatch — Flow policy fields a scenario can change in play.
2606
+ - `VisitorPopulation` (interface): interface VisitorPopulation — The crowd a scene reports. Every visitor is a member with a body the game's world made, so the on-site figure is the member count and the daily figure is the sum of admissions the world accepted — there is no second tally to drift from what is on the ground. Arrivals, capacity and leaving are the game's policy; ids, day rollover and counting are this seam's.
2607
+ - `VisitorPopulationOptions` (interface): interface VisitorPopulationOptions — Options for {@link createVisitorPopulation}.
2608
+ - `VisitorPopulationSnapshot` (interface): interface VisitorPopulationSnapshot — Serializable state. No on-site count is stored: it is the restored visitor list.
2609
+ - `VisitorPopulationStats` (interface): interface VisitorPopulationStats — Counters a HUD, a probe or a test reads. The on-site figure is the visitor list's length.
2610
+ - `VisitorWorld` (interface): interface VisitorWorld — The game's world behind every counted visitor: it creates and removes the body.
2611
+ - `createVisitorPopulation` (function): function createVisitorPopulation(options: VisitorPopulationOptions): VisitorPopulation — Create the population a scene reports, with the game owning arrival and leaving policy. A visitor only exists once the world has made its body, so the HUD's count and the bodies on screen are the same list: `admit` returning `null` is a refused arrival, not a number.
2612
+
2613
+ ## @jgengine/core/sim/queue
2614
+
2615
+ - `DEFAULT_QUEUE_SEED_SERVICE_SECONDS` (const): const DEFAULT_QUEUE_SEED_SERVICE_SECONDS: 8 — Seconds one guest occupies the head of the line before any boarding interval has been measured. A bootstrap only: the estimate switches to the queue's own measured throughput as soon as two boardings have been observed.
2616
+ - `DEFAULT_QUEUE_WINDOW` (const): const DEFAULT_QUEUE_WINDOW: 8 — Boarding events the throughput window keeps.
2617
+ - `QueueEntry` (interface): interface QueueEntry — One guest waiting their turn, and when they joined the line.
2618
+ - `QueueWait` (interface): interface QueueWait — A wait estimate read off the queue's own measured throughput.
2619
+ - `WaitQueue` (interface): interface WaitQueue — A real line: guests join the back, leave the head, and the wait a new arrival faces comes from how fast this queue has actually been boarding — not from a configured constant. A broken ride stops boarding, the line grows, and the estimate grows with it.
2620
+ - `WaitQueueOptions` (interface): interface WaitQueueOptions — Tunables for {@link createWaitQueue}, every one retunable through a restore.
2621
+ - `WaitQueueSnapshot` (interface): interface WaitQueueSnapshot — Serializable line state: who is waiting, and the boardings the estimate is measured from.
2622
+ - `createWaitQueue` (function): function createWaitQueue(options: WaitQueueOptions = {}): WaitQueue — Create a line whose wait estimate is derived from its own throughput. The queue owns the order and the measurement; the ride owns how fast guests are taken off the head, so a slower cycle raises the estimate without the queue being told a cycle time.
2623
+
2624
+ ## @jgengine/core/sim/rides
2625
+
2626
+ - `DEFAULT_RIDE_BREAKDOWN` (const): const DEFAULT_RIDE_BREAKDOWN: RideBreakdown — A ride's breakdown curve a park starts from when it has none and retunes only part of one.
2627
+ - `DEFAULT_RIDE_FUN_CURVE` (const): const DEFAULT_RIDE_FUN_CURVE: ResponseCurve — How empty a bored guest's fun need has to be before a ride starts to pull, by default.
2628
+ - `DEFAULT_RIDE_RATING_RANGE` (const): const DEFAULT_RIDE_RATING_RANGE: RideRatingRange — A 0–10 rating scale, the usual shape of a ride catalog. Override it when a park rates differently.
2629
+ - `RideBreakdown` (interface): interface RideBreakdown — Breakdown curve and money for one ride. All data, so a park tunes its own economy.
2630
+ - `RideChoicePolicy` (interface): interface RideChoicePolicy — Policy a park might vary when it turns taste and ride data into utility options.
2631
+ - `RideChooser` (interface): interface RideChooser — One guest's ride choice over one park: taste becomes utility options, each ride is costed by its own line's wait, and the pick comes from the shared utility brain — so the same brain that picks food picks rides, and a guest's queue tolerance is a weight rather than a rule.
2632
+ - `RideChooserConfig` (interface): interface RideChooserConfig — Everything a ride chooser needs: the park, the guest's taste, and the guest's needs.
2633
+ - `RideChooserSnapshot` (interface): interface RideChooserSnapshot — Serializable chooser state: the guest's taste and the brain's held pick.
2634
+ - `RideDefinition` (interface): interface RideDefinition — Everything a ride is: its ratings, its cycle and its wear. Content, not code.
2635
+ - `RidePhase` (type): type RidePhase = "idle" | "loading" | "riding" | "unloading" | "broken" — Where a ride is in its cycle.
2636
+ - `RideQueueView` (interface): interface RideQueueView — A ride's line as a game or the devtools overlay reads it.
2637
+ - `RideRatingRange` (interface): interface RideRatingRange — The rating scale a park's taste curves are normalized against.
2638
+ - `RideRatings` (interface): interface RideRatings — What a ride is worth to a guest. All three come from the ride's own data.
2639
+ - `RideRetune` (interface): interface RideRetune — In-play dials a ride accepts from {@link RideSystem.retune}.
2640
+ - `RideServiceResult` (interface): interface RideServiceResult — What a service cost the caller.
2641
+ - `RideStats` (interface): interface RideStats — Counters a devtools probe or test reads.
2642
+ - `RideSystem` (interface): interface RideSystem — The park's rides: each runs its own load → ride → unload cycle at its own capacity, takes guests off its own line, wears out against its own breakdown curve, and reports its own repairs and services. The clock is internal and only `tick` moves it, so a replay, a save and a test read the same cycle.
2643
+ - `RideSystemConfig` (interface): interface RideSystemConfig — Everything a ride system needs.
2644
+ - `RideSystemSnapshot` (interface): interface RideSystemSnapshot — Serializable park state: the clock, each ride's cycle position, wear and line.
2645
+ - `RideTaste` (interface): interface RideTaste — What one guest wants from a ride: the intensity and nausea they are comfortable with, and how long they will stand in line. All three are the guest's own data.
2646
+ - `RideTickSink` (interface): interface RideTickSink — Where a ride's boardings, alightings and breakdowns are announced. Every hook is optional.
2647
+ - `RideView` (interface): interface RideView — One ride's live state.
2648
+ - `RideWaitSource` (interface): interface RideWaitSource — The live queue a ride-choice candidate is costed against. {@link RideSystem} satisfies this.
2649
+ - `createRideChooser` (function): function createRideChooser(config: RideChooserConfig): RideChooser — Create one guest's ride choice over a park. Options are rebuilt when the park is retuned, so a coaster whose track changes its ratings is re-scored without rebuilding the guest.
2650
+ - `createRideSystem` (function): function createRideSystem(config: RideSystemConfig): RideSystem — Create the rides a park runs. Each ride cycles on its own data, boards from its own line up to its own capacity, wears against its own breakdown curve and reports its repairs through the sink, so the caller keeps the wallet, the bodies and the visuals.
2651
+ - `rideAppeal` (function): function rideAppeal(ratings: RideRatings, taste: RideTaste, range: RideRatingRange = DEFAULT_RIDE_RATING_RANGE): number — One ride's standing appeal to one guest, before queue cost. Excitement draws, force and nausea push back — what a guest's own card or thought bubble can show.
2652
+ - `rideChoiceCandidates` (function): function rideChoiceCandidates(source: RideWaitSource, out: UtilityCandidate[] = []): UtilityCandidate[] — Cost each ride by the wait its own line reports, so a guest weighs a ride by seconds in line rather than by a fixed order. `out` is reused for the array; the candidate records are not.
2653
+ - `rideChoiceOptions` (function): function rideChoiceOptions(rides: readonly RideDefinition[], taste: RideTaste, policy: RideChoicePolicy = {}): UtilityOption[] — Compile a guest's taste and the park's ride data into utility options, so the guest's pick comes from `createUtilityBrain` like every other decision it makes. Ride choice is one more set of options a guest can score, not a separate scoring function.
2654
+ - `rideQueueCostWeight` (function): function rideQueueCostWeight(taste: RideTaste): number — Score points per second of queue wait: a guest's own tolerance is the denominator. A guest who merges rides into a brain that also scores food and exits uses this as its `costWeight`.
2655
+
2331
2656
  ## @jgengine/core/sim/routine
2332
2657
 
2333
2658
  - `RoutineConfig` (interface): interface RoutineConfig — Everything needed to resolve a routine: its authored stops, its cycle, and how far apart places are.