<!-- GENERATED by scripts/gen-skill-api.ts — do not edit. Regenerate: bun run gen:skill-api -->

# jgengine-gameplay — exported API surface

## @jgengine/core/agents/agent

- `Agent` (interface): interface Agent — Needs, mood, schedule and a chosen action, in one object a game ticks.
- `AgentAction` (interface): interface AgentAction — What the agent is doing.
- `AgentActionReason` (type): type AgentActionReason = UtilitySwitchReason | "fallback" | "schedule" | "cleared" — Why the action last changed.
- `AgentConfig` (interface): interface AgentConfig — Everything an agent is made of. Policy is data; nothing about a game is compiled in.
- `AgentFallback` (interface): interface AgentFallback — Where an agent goes when the thing it wanted is gone: a named option and a named place.
- `AgentFrame` (interface): interface AgentFrame — What one update produced: the action, the feeling, and where the day plan puts the agent.
- `AgentSnapshot` (interface): interface AgentSnapshot — Serializable whole agent: needs, feeling, held action, day-plan cursor and the far flag.
- `AgentTarget` (interface): interface AgentTarget — One reachable thing the agent could do this tick, as the game sees its own world.
- `AgentUpdate` (interface): interface AgentUpdate — One call per tick: the clock, and the targets the game's world currently offers.
- `createAgent` (function): function createAgent(config: AgentConfig): Agent — Create one agent. The same factory serves a park guest, a household being, a patrolling janitor and a soldier: `options` is what it can choose between, `schedule` is where its day puts it.

## @jgengine/core/agents/mood

- `DEFAULT_MOOD_TIERS` (const): const DEFAULT_MOOD_TIERS: readonly MoodTier[] — Five bands a park guest, a household being or a soldier can share. A game overrides them when its own tone needs different words; the numeric bands are what HUD counters and tests read.
- `Mood` (interface): interface Mood — What the agent feels right now, on the caller's own tier labels.
- `MoodReader` (interface): interface MoodReader — A mood reader that keeps the game-raised biases, so a queue or a litter patch moves mood too.
- `MoodSnapshot` (interface): interface MoodSnapshot — Serializable mood state: the game-raised biases that sit on top of need satisfaction.
- `MoodTier` (interface): interface MoodTier — One labelled band of the 0-100 mood score.
- `MoodWeight` (interface): interface MoodWeight — One need's say in the mood score; weights are relative, so they need no fixed total.
- `createMoodReader` (function): function createMoodReader(config: { readonly needs: Pick<NeedSet, "ids" | "fraction">; readonly weights?: readonly MoodWeight[]; readonly tiers?: readonly MoodTier[]; }): MoodReader — Create the mood an agent carries. Needs are the agent's own (shared with its utility brain), and every bias is named data the game can remove again - there is no decaying hidden penalty.
- `moodTierOf` (function): function moodTierOf(score: number, tiers: readonly MoodTier[] = DEFAULT_MOOD_TIERS): MoodTier — The band a score reads as, from tiers sorted by `at` descending. Unknown or unsorted tiers fall back to the lowest declared band rather than throwing, because a HUD reads this every frame.
- `readMood` (function): function readMood(needs: Pick<NeedSet, "ids" | "fraction">, weights: readonly MoodWeight[], tiers: readonly MoodTier[] = DEFAULT_MOOD_TIERS, sources?: Readonly<Record<string, number>>): Mood — A mood read from a need set: each declared need contributes its `0..1` satisfaction times its weight, normalized by the total weight, so an agent with four needs and one with six read on the same 0-100 scale. Pure and allocation-light - the per-frame read a HUD and a thought bubble share.

## @jgengine/core/agents/relationships

- `DEFAULT_RELATIONSHIP_MILESTONES` (const): const DEFAULT_RELATIONSHIP_MILESTONES: readonly RelationshipMilestone[] — The pair levels every game starts from; a game overrides the words and the cut points.
- `DEFAULT_SOCIAL_CONTACT` (const): const DEFAULT_SOCIAL_CONTACT: Required<SocialContact> — What a plain social action adds: a shared moment nudges both dials, never maxes either.
- `Relationship` (interface): interface Relationship — How one pair stands: how much time they have shared, and what they think of each other.
- `RelationshipBook` (interface): interface RelationshipBook — Everyone's view of everyone else: familiarity and opinion per pair, changed by social actions, with the pair levels that make a friendship a preference and a bond a refusal to split.
- `RelationshipBookSnapshot` (interface): interface RelationshipBookSnapshot — Serializable relationship state: every known pair plus the dials in play.
- `RelationshipMilestone` (interface): interface RelationshipMilestone — One labelled bond level on the opinion scale.
- `RelationshipPolicy` (interface): interface RelationshipPolicy — Tunables a game owns, every one reachable through {@link RelationshipBook.retune}.
- `SocialContact` (interface): interface SocialContact — Opinion and familiarity one interaction adds; a game passes its own for a hug, a row or a shift.
- `SocialOutcome` (interface): interface SocialOutcome — What one social action did to a pair.
- `createRelationshipBook` (function): function createRelationshipBook(policy: RelationshipPolicy = {}): RelationshipBook — Create the shared book of pair state. Keys are undirected and delimiter-safe through `createPairKeyCodec`, and milestone crossings come from `crossThresholds`, so a notice feed and a journal both read the same event.

## @jgengine/core/agents/schedule

- `AgentSchedule` (interface): interface AgentSchedule — A day plan resolved against the world clock. No state to tick: a far agent reads the same day.
- `AgentScheduleConfig` (interface): interface AgentScheduleConfig — An agent's whole day as data: what it does, where, and when.
- `AgentSchedulePhase` (interface): interface AgentSchedulePhase — Where a schedule puts an agent at one instant.
- `AgentScheduleStop` (interface): interface AgentScheduleStop extends RoutineStopSpec — One authored stop in an agent's day. The shape is the routine owner's (`sim/routine`) plus a beat: the places a working stop walks in order, so a janitor on patrol is an agent with a route rather than a special case.
- `createAgentSchedule` (function): function createAgentSchedule(config: AgentScheduleConfig): AgentSchedule — Resolve an authored day plan into a clock-driven schedule. Timing, travel and arrival slips come from `sim/routine`; this adds the work beat and the refills a stop carries, so an off-hours stop is just another authored stop and a patrol is not a second scheduler.

## @jgengine/core/behaviour/behaviour

- `Behaviour` (class): class Behaviour — Subclass and override the lifecycle hooks. A behaviour only joins the per-frame update dispatch if it actually overrides `onUpdate` (prototype-identity check at each activation), so hook-only behaviours cost nothing per frame.
- `BehaviourModule` (class): class BehaviourModule — A world-lifetime service with typed sibling access via `this.modules`. Modules awake and start before any behaviour during `world.start()`, subscribe to update dispatch first (their `onUpdate` fires before every behaviour's), and have no disable/destroy — they live as long as the world.
- `BehaviourModules` (type): type BehaviourModules = RegisterField<"modules", Record<string, BehaviourModule>> — Resolves to the augmented module map when `JGEngineRegister` declares one.
- `BehaviourWorld` (interface): interface BehaviourWorld { add(id: string, parentId?: string): void; has(id: string): boolean; parentOf(id: string): string | null; childrenOf(id: string): readonly string[]; setParent(id: string, parentId: string | null): void; attach<T extends Behaviour>(nodeId: … — ⚠ undocumented
- `JGEngineRegister` (interface): interface JGEngineRegister — Unity-style behaviour lifecycle over a headless id-keyed node tree, ported from vladkrutenyuk/three-start (MIT) and adapted to run without three.js: nodes are plain string ids (use entity instance ids to pair with `entityStore`), and the shell binds render-side hooks separately.
- `RegisterField` (type): type RegisterField<TKey extends string, TFallback = unknown> = TKey extends keyof JGEngineRegister ? JGEngineRegister[TKey] : TFallback — ⚠ undocumented
- `createBehaviourWorld` (function): function createBehaviourWorld(): BehaviourWorld — ⚠ undocumented

## @jgengine/core/board/laneBoard

- `LaneAggregate` (interface): interface LaneAggregate { lane: number; side: Side; subtotal: number; total: number; count: number } — ⚠ undocumented
- `LaneBoard` (interface): interface LaneBoard<C> { state(): LaneBoardState<C>; place(lane: number, side: Side, card: C): LaneResult<C>; remove(lane: number, side: Side, predicate: (card: C, index: number) => boolean): LaneResult<C>; aggregate(lane: number, side: Side): LaneAggregate; outc… — ⚠ undocumented
- `LaneBoardConfig` (interface): interface LaneBoardConfig<C> { laneCount: number; sides: readonly Side[]; power: (card: C) => number; laneRules?: readonly (LaneRule<C> | null | undefined)[] } — ⚠ undocumented
- `LaneBoardState` (interface): interface LaneBoardState<C> { readonly lanes: readonly LaneCells<C>[] } — ⚠ undocumented
- `LaneCells` (interface): interface LaneCells<C> { readonly [side: Side]: readonly C[] } — ⚠ undocumented
- `LaneOutcome` (interface): interface LaneOutcome { lane: number; totals: Readonly<Record<Side, number>>; winner: Side | null } — ⚠ undocumented
- `LanePlaceRejected` (interface): interface LanePlaceRejected { status: "rejected"; reason: LaneRejection } — ⚠ undocumented
- `LanePlaceResult` (interface): interface LanePlaceResult<C> { status: "ok"; state: LaneBoardState<C> } — ⚠ undocumented
- `LaneRejection` (type): type LaneRejection = "invalid-lane" | "invalid-side" — ⚠ undocumented
- `LaneResult` (type): type LaneResult<C> = LanePlaceResult<C> | LanePlaceRejected — ⚠ undocumented
- `LaneRule` (interface): interface LaneRule<C> { id: string; apply: (input: LaneRuleInput<C>) => number } — ⚠ undocumented
- `LaneRuleInput` (interface): interface LaneRuleInput<C> { lane: number; side: Side; cards: readonly C[]; subtotal: number } — ⚠ undocumented
- `Side` (type): type Side = string — ⚠ undocumented

## @jgengine/core/board/timelineBoard

- `TimelineBoard` (interface): interface TimelineBoard { state(): TimelineBoardState; tick(dtMs: number): readonly TimelineFire[]; setEnabled(slotId: string, enabled: boolean): void; reset(slotId?: string, remainingMs?: number): void } — ⚠ undocumented
- `TimelineBoardState` (interface): interface TimelineBoardState { readonly slots: readonly TimelineSlot[]; readonly elapsedMs: number } — ⚠ undocumented
- `TimelineFire` (interface): interface TimelineFire { slotId: string; slotIndex: number; atMs: number } — ⚠ undocumented
- `TimelineSlot` (interface): interface TimelineSlot { readonly id: string; readonly cooldownMs: number; readonly remainingMs: number; readonly enabled: boolean } — ⚠ undocumented
- `TimelineSlotConfig` (interface): interface TimelineSlotConfig { id: string; cooldownMs: number; enabled?: boolean; offsetMs?: number } — ⚠ undocumented
- `TimelineTickResult` (interface): interface TimelineTickResult { state: TimelineBoardState; fires: readonly TimelineFire[] } — ⚠ undocumented

## @jgengine/core/cards/cardPile

- `CardPile` (interface): interface CardPile { state(): CardPileState; zones(): readonly ZoneName[]; count(zone: ZoneName): number; peek(zone: ZoneName, n?: number): readonly string[]; zoneOf(cardId: string): ZoneName | null; shuffle(zone: ZoneName | undefined, seed: string | number):… — ⚠ undocumented
- `CardPileConfig` (interface): interface CardPileConfig { zones: readonly ZoneName[]; drawFrom?: ZoneName; discardTo?: ZoneName; handZone?: ZoneName; handLimit?: number; reshuffleFrom?: ZoneName; onChange?: () => void } — ⚠ undocumented
- `CardPileState` (interface): interface CardPileState { readonly zones: Readonly<Record<ZoneName, readonly string[]>> } — ⚠ undocumented · used by `CardStack` (@jgengine/react): `StackedPile` bound to a headless `CardPileState` zone: reads the ordered card ids from `pile.zones[zone]` and resolves each to a `PlayingCa…
- `DrawResult` (interface): interface DrawResult { state: CardPileState; drawn: readonly string[]; reshuffled: boolean } — ⚠ undocumented
- `PileMoveRejected` (interface): interface PileMoveRejected { status: "rejected"; reason: PileRejection; detail?: string } — ⚠ undocumented
- `PileMoveResult` (interface): interface PileMoveResult { status: "ok"; state: CardPileState } — ⚠ undocumented
- `PileRejection` (type): type PileRejection = | "unknown-zone" | "card-not-in-zone" | "hand-limit" | "empty-source" — ⚠ undocumented
- `PileResult` (type): type PileResult = PileMoveResult | PileMoveRejected — ⚠ undocumented
- `ZoneName` (type): type ZoneName = string — ⚠ undocumented
- `countIn` (function): function countIn(state: CardPileState, zone: ZoneName): number — ⚠ undocumented
- `createCardPile` (function): function createCardPile(config: CardPileConfig, initial?: Partial<Record<ZoneName, readonly string[]>>): CardPile — ⚠ undocumented
- `createCardPileState` (function): function createCardPileState(config: CardPileConfig, initial?: Partial<Record<ZoneName, readonly string[]>>): CardPileState — ⚠ undocumented
- `draw` (function): function draw(state: CardPileState, n: number, options: { from: ZoneName; to: ZoneName; handLimit?: number; reshuffleFrom?: ZoneName; seed?: string | number; }): DrawResult — ⚠ undocumented
- `moveCards` (function): function moveCards(state: CardPileState, ids: readonly string[], from: ZoneName, to: ZoneName, position: "top" | "bottom" = "top"): PileResult — ⚠ undocumented
- `peek` (function): function peek(state: CardPileState, zone: ZoneName, n = 1): readonly string[] — ⚠ undocumented
- `pileRng` (function): function pileRng(seed: string | number): () => number — ⚠ undocumented
- `shuffleWithRng` (function): function shuffleWithRng<T>(values: readonly T[], rng: () => number): T[] — ⚠ undocumented
- `shuffleZone` (function): function shuffleZone(state: CardPileState, zone: ZoneName, seed: string | number): CardPileState — ⚠ undocumented
- `zoneOf` (function): function zoneOf(state: CardPileState, cardId: string): ZoneName | null — ⚠ undocumented

## @jgengine/core/cards/modifierPipeline

- `Modifier` (interface): interface Modifier<V> { id: string; source?: string; apply: (value: V, context: PipelineContext<V>) => V } — ⚠ undocumented
- `ModifierPipeline` (interface): interface ModifierPipeline<V> { add(modifier: Modifier<V>): void; insertAt(index: number, modifier: Modifier<V>): void; remove(id: string): boolean; clear(): void; list(): readonly Modifier<V>[]; run(base: V): PipelineResult<V> } — ⚠ undocumented
- `PipelineContext` (interface): interface PipelineContext<V> { base: V; index: number; trace: readonly TraceStep<V>[] } — ⚠ undocumented
- `PipelineResult` (interface): interface PipelineResult<V> { base: V; value: V; trace: readonly TraceStep<V>[] } — ⚠ undocumented
- `TraceStep` (interface): interface TraceStep<V> { id: string; source?: string; index: number; before: V; after: V; changed: boolean } — ⚠ undocumented
- `createModifierPipeline` (function): function createModifierPipeline<V>(initial: readonly Modifier<V>[] = [], equals: (a: V, b: V) => boolean = Object.is): ModifierPipeline<V> — ⚠ undocumented
- `runPipeline` (function): function runPipeline<V>(base: V, modifiers: readonly Modifier<V>[], equals: (a: V, b: V) => boolean = Object.is): PipelineResult<V> — ⚠ undocumented

## @jgengine/core/crafting/crop

- `ApplyToolResult` (interface): interface ApplyToolResult { tiles: Map<string, CropTileState>; changed: TileCoord[] } — ⚠ undocumented
- `CropCatalog` (type): type CropCatalog = (cropId: string) => CropDef | null — ⚠ undocumented
- `CropDef` (interface): interface CropDef { id: string; stages: readonly number[]; regrowDays?: number; needsDailyWater?: boolean; harvest?: RecipeItem } — ⚠ undocumented
- `CropField` (interface): interface CropField { get(coord: TileCoord): CropTileState; till(coord: TileCoord, pattern?: TilePattern): TileCoord[]; plant(coord: TileCoord, cropId: string): boolean; water(coord: TileCoord, pattern?: TilePattern): TileCoord[]; harvest(coord: TileCoord): Re… — ⚠ undocumented
- `CropTileState` (interface): interface CropTileState { soil: SoilState; watered: boolean; cropId: string | null; stage: number; stageProgress: number; harvestable: boolean } — ⚠ undocumented
- `DayTicker` (interface): interface DayTicker { tick(currentDay: number): number; day(): number } — ⚠ undocumented
- `HarvestResult` (interface): interface HarvestResult { state: CropTileState; yield: RecipeItem | null } — ⚠ undocumented
- `SoilState` (type): type SoilState = "untilled" | "tilled" — ⚠ undocumented
- `TileCoord` (type): type TileCoord = readonly [number, number] — ⚠ undocumented
- `TilePattern` (type): type TilePattern = readonly TileCoord[] — ⚠ undocumented

## @jgengine/core/crafting/production

- `ItemCounts` (type): type ItemCounts = Readonly<Record<string, number>> — ⚠ undocumented
- `PowerConsumer` (interface): interface PowerConsumer { id: string; demand: number } — ⚠ undocumented
- `PowerGridResult` (interface): interface PowerGridResult { powered: ReadonlySet<string>; supply: number; demand: number; deficit: number } — ⚠ undocumented
- `ProductionBuildingConfig` (interface): interface ProductionBuildingConfig { id: string; inputs?: readonly RecipeItem[]; outputs: readonly RecipeItem[]; rate: number; power?: number; bufferMultiplier?: number } — ⚠ undocumented
- `ProductionBuildingDef` (interface): interface ProductionBuildingDef { id: string; inputs: readonly RecipeItem[]; outputs: readonly RecipeItem[]; rate: number; power?: number; bufferMultiplier?: number } — ⚠ undocumented
- `ProductionState` (interface): interface ProductionState { buffer: ItemCounts; output: ItemCounts; progress: number; active: boolean } — ⚠ undocumented · used by `createProductionState`: A production building that converts input items into outputs over time — factory/crafting station.
- `ProductionTickInput` (interface): interface ProductionTickInput { dt: number; powered?: boolean } — ⚠ undocumented
- `TransportItem` (interface): interface TransportItem { itemId: string; count: number; position: number } — ⚠ undocumented
- `TransportPath` (interface): interface TransportPath { length: number; speed: number } — ⚠ undocumented
- `acceptsInput` (function): function acceptsInput(def: ProductionBuildingDef, state: ProductionState, itemId: string): boolean — ⚠ undocumented
- `advanceTransport` (function): function advanceTransport(path: TransportPath, items: readonly TransportItem[], dt: number): { items: TransportItem[]; delivered: TransportItem[] } — ⚠ undocumented
- `createProductionState` (function): function createProductionState(): ProductionState — A production building that converts input items into outputs over time — factory/crafting station.
- `drainOutput` (function): function drainOutput(state: ProductionState, itemId: string, count?: number): { state: ProductionState; taken: number } — ⚠ undocumented
- `feedProduction` (function): function feedProduction(def: ProductionBuildingDef, state: ProductionState, itemId: string, count: number): { state: ProductionState; accepted: number } — ⚠ undocumented
- `productionBuilding` (function): function productionBuilding(config: ProductionBuildingConfig): ProductionBuildingDef — ⚠ undocumented
- `resolvePowerGrid` (function): function resolvePowerGrid(supply: number, consumers: readonly PowerConsumer[]): PowerGridResult — ⚠ undocumented
- `tickProduction` (function): function tickProduction(def: ProductionBuildingDef, state: ProductionState, input: ProductionTickInput): ProductionState — ⚠ undocumented

## @jgengine/core/crafting/recipe

- `CraftCheck` (type): type CraftCheck = { ok: true } | ({ ok: false } & CraftRejection) — ⚠ undocumented
- `CraftContext` (interface): interface CraftContext { origin?: Vec2; stations?: readonly StationInstance[]; unlocked?: (id: string) => boolean } — ⚠ undocumented
- `CraftRejection` (type): type CraftRejection = | { reason: "missing-inputs"; missing: readonly RecipeItem[] } | { reason: "no-station"; station: string } | { reason: "locked"; requires: readonly string[] } | { reason: "no-output-space" } — ⚠ undocumented
- `CraftResult` (type): type CraftResult = { status: "ok"; state: InventoryState } | ({ status: "rejected" } & CraftRejection) — ⚠ undocumented
- `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.
- `RecipeGraph` (interface): interface RecipeGraph { all(): readonly RecipeDef[]; get(id: string): RecipeDef | null; producing(itemId: string): RecipeDef[]; using(itemId: string): RecipeDef[]; category(categoryId: string): RecipeDef[] } — ⚠ undocumented
- `RecipeItem` (interface): interface RecipeItem { itemId: string; count: number } — ⚠ undocumented
- `StationInstance` (interface): interface StationInstance { catalogId: string; position: Vec2 } — ⚠ undocumented
- `canCraft` (function): function canCraft(state: InventoryState, layout: InventoryLayout, traits: ItemTraits, recipe: RecipeDef, context: CraftContext = {}): CraftCheck — ⚠ undocumented
- `craft` (function): function craft(state: InventoryState, layout: InventoryLayout, traits: ItemTraits, recipe: RecipeDef, context: CraftContext = {}): CraftResult — ⚠ undocumented
- `craftSeconds` (function): function craftSeconds(recipe: RecipeDef): number — ⚠ undocumented
- `createRecipeGraph` (function): function createRecipeGraph(defs: readonly RecipeDef[] = []): RecipeGraph — ⚠ undocumented
- `hasRecipeInputs` (function): function hasRecipeInputs(state: InventoryState, recipe: RecipeDef): boolean — ⚠ undocumented
- `missingInputs` (function): function missingInputs(state: InventoryState, recipe: RecipeDef): RecipeItem[] — ⚠ undocumented
- `stationSatisfied` (function): function stationSatisfied(recipe: RecipeDef, context: CraftContext): boolean — ⚠ undocumented

## @jgengine/core/crafting/recipeCatalog

- `RecipeCatalogValidationOptions` (interface): interface RecipeCatalogValidationOptions — Caller catalogs for native crafting references; omission leaves that namespace unchecked.
- `validateRecipeCatalog` (function): function validateRecipeCatalog(recipes: readonly RecipeDef[], options: RecipeCatalogValidationOptions = {}): ContentIssue[] — Validate native recipes before registration: ids, counts, timing and caller-catalog references. Empty outputs are valid for game-owned benefits; fractional and zero counts are allowed. Negative/nonfinite counts, durations and ranges reject. Duplicate input rows reject because the crafting input check does not aggregate them; consolidate their counts into one row. No price, scarcity, story or cycle policy is imposed. O(recipes + item rows + requirements).

## @jgengine/core/data/dataSource

- `DataSource` (interface): interface DataSource<T> { getState(): DataSourceState<T>; subscribe(listener: (state: DataSourceState<T>) => void): () => void; refresh(options?: RefreshOptions): Promise<void>; startPolling(intervalMs?: number): void; stopPolling(): void; dispose(): void } — ⚠ undocumented
- `DataSourceClock` (interface): interface DataSourceClock { setInterval(handler: () => void, intervalMs: number): unknown; clearInterval(handle: unknown): void } — ⚠ undocumented
- `DataSourceOptions` (interface): interface DataSourceOptions { intervalMs?: number; clock?: DataSourceClock } — ⚠ undocumented
- `DataSourceState` (interface): interface DataSourceState<T> { readonly status: DataSourceStatus; readonly data: T | undefined; readonly error: Error | undefined } — ⚠ undocumented
- `DataSourceStatus` (type): type DataSourceStatus = "idle" | "loading" | "ready" | "error" — ⚠ undocumented
- `RefreshOptions` (interface): interface RefreshOptions { force?: boolean } — ⚠ undocumented
- `createDataSource` (function): function createDataSource<T>(load: (signal: AbortSignal) => Promise<T>, options: DataSourceOptions = {}): DataSource<T> — ⚠ undocumented

## @jgengine/core/data/devProxy

- `DEFAULT_DEV_PROXY_PREFIX` (const): const DEFAULT_DEV_PROXY_PREFIX: "/proxy" — ⚠ undocumented
- `DevProxyTable` (interface): interface DevProxyTable { readonly [routeName: string]: string } — ⚠ undocumented
- `ProxiedUrlOptions` (interface): interface ProxiedUrlOptions { dev?: boolean; table?: DevProxyTable; prefix?: string } — ⚠ undocumented
- `parseDevProxyTable` (function): function parseDevProxyTable(raw: string | undefined): DevProxyTable — ⚠ undocumented
- `proxiedUrl` (function): function proxiedUrl(target: string, options: ProxiedUrlOptions = {}): string — ⚠ undocumented

## @jgengine/core/data/fetchJson

- `FetchImpl` (type): type FetchImpl = typeof fetch — ⚠ undocumented
- `FetchJsonOptions` (interface): interface FetchJsonOptions { method?: string; headers?: Record<string, string>; body?: string; signal?: AbortSignal; fetchImpl?: FetchImpl } — ⚠ undocumented
- `HttpStatusError` (class): class HttpStatusError extends Error — ⚠ undocumented
- `JsonParseError` (class): class JsonParseError extends Error — ⚠ undocumented
- `fetchJson` (function): function fetchJson<T>(url: string, options: FetchJsonOptions = {}): Promise<T> — ⚠ undocumented

## @jgengine/core/data/jsonDataSource

- `JsonDataSourceOptions` (type): type JsonDataSourceOptions = DataSourceOptions & Omit<FetchJsonOptions, "signal"> — ⚠ undocumented
- `createJsonDataSource` (function): function createJsonDataSource<T>(url: string, options: JsonDataSourceOptions = {}): DataSource<T> — ⚠ undocumented

## @jgengine/core/economy/auctionBook

- `Auction` (interface): interface Auction — One live timed auction in an {@link AuctionBook}: an item stack under open bidding until it closes.
- `AuctionBook` (interface): interface AuctionBook — A timed-bid auction marketplace plus the per-player collection boxes behind it. See {@link createAuctionBook}.
- `AuctionBookConfig` (interface): interface AuctionBookConfig — Tunables for {@link createAuctionBook} — per-seller auction cap, run length, house cut, and the anti-snipe window: a bid landing within `antiSnipeWindowSeconds` of the close pushes the close out so it ends at least `antiSnipeExtensionSeconds` after that bid.
- `AuctionSettlement` (type): type AuctionSettlement = | { status: "sold"; auction: Auction; winnerId: string; price: number; houseCut: number; sellerProceeds: number; } | { status: "returned"; auction: Auction } — How one closed auction resolved during {@link AuctionBook.settleExpired}.
- `BidReason` (type): type BidReason = | "not-found" | "ended" | "own-auction" | "already-leading" | "bid-too-low" | "invalid-amount" | "no-buyout" — Why {@link AuctionBook.bid} refused a bid.
- `BidResult` (type): type BidResult = | { status: "ok"; auction: Auction; escrowed: number; won: boolean } | { status: "rejected"; reason: BidReason } — Result of {@link AuctionBook.bid}. On `ok` the caller must escrow `escrowed` from the bidder's wallet; any previously escrowed leading bid has already been refunded to that bidder's collection box. `won` is true when the bid met the buyout price and settled the auction immediately.
- `CancelAuctionResult` (type): type CancelAuctionResult = | { status: "ok"; auction: Auction } | { status: "rejected"; reason: "not-found" | "not-owner" | "has-bids" } — Result of {@link AuctionBook.cancel}: a bid-on auction can no longer be withdrawn.
- `HighBid` (interface): interface HighBid — The current leading bid on an {@link Auction}.
- `PostAuctionInput` (interface): interface PostAuctionInput — Input to {@link AuctionBook.post} — the goods, opening terms, and current game-time.
- `PostAuctionReason` (type): type PostAuctionReason = | "invalid-count" | "invalid-price" | "invalid-increment" | "invalid-buyout" | "auction-cap-reached" | "duplicate-id" — Why {@link AuctionBook.post} refused an auction.
- `PostAuctionResult` (type): type PostAuctionResult = | { status: "ok"; auction: Auction } | { status: "rejected"; reason: PostAuctionReason } — Result of {@link AuctionBook.post}.
- `createAuctionBook` (function): function createAuctionBook(config: AuctionBookConfig): AuctionBook — Timed-bid auctions in the WoW/BDO auction-house mold: post an item with a start price, minimum increment, and optional buyout; bids escrow currency, outbid players are refunded into their collection box, bids near the close extend it (anti-snipe), and settlement pays the seller minus the house cut while the item lands in the winner's collection box. Unsold auctions return the goods to the seller's box. Wallet and inventory movement is the caller's job (mirrors `economy/listingBook`) — this primitive owns the auction lifecycle and the escrowed collection-box bookkeeping behind it.

## @jgengine/core/economy/currency

- `CurrencyAdjustment` (type): type CurrencyAdjustment = | { success: true; newBalance: number; appliedDelta: number } | { success: false; reason: string } — ⚠ undocumented
- `CurrencyDefinition` (interface): interface CurrencyDefinition<TCurrencyId extends string = string> { id: TCurrencyId; name: string; decimals?: number; symbol?: string; unit?: string } — ⚠ undocumented · used by `formatCurrency`: Format a major-unit value using the currency's declared precision.
- `CurrencyOperation` (type): type CurrencyOperation = "add" | "deduct" — ⚠ undocumented
- `formatCurrency` (function): function formatCurrency(currency: CurrencyDefinition, value: number): string — Format a major-unit value using the currency's declared precision.
- `fromMinorUnits` (function): function fromMinorUnits(currency: Pick<CurrencyDefinition, "decimals"> | undefined, value: number): number — Convert stored integer minor units to major units for display or existing balance records.
- `toMinorUnits` (function): function toMinorUnits(currency: Pick<CurrencyDefinition, "decimals"> | undefined, value: number): number — Convert major units to integer minor units, rounding once at the write boundary.

## @jgengine/core/economy/listingBook

- `BuyListingOutcome` (interface): interface BuyListingOutcome — The financial split of a completed sale: total price, the house's cut, and what the seller's collection box was credited.
- `BuyListingResult` (type): type BuyListingResult = | { status: "ok"; outcome: BuyListingOutcome } | { status: "rejected"; reason: "not-found" | "expired" | "own-listing" } — Result of {@link ListingBook.buy}.
- `CancelListingResult` (type): type CancelListingResult = | { status: "ok"; listing: Listing } | { status: "rejected"; reason: "not-found" | "not-owner" } — Result of {@link ListingBook.cancel}.
- `CollectionBoxSnapshot` (interface): interface CollectionBoxSnapshot — A read-only view of a seller's collection box — currency and item stacks waiting to be claimed.
- `Listing` (interface): interface Listing — One active post in a {@link ListingBook}: an item stack a seller offered at a fixed price until it expires.
- `ListingBook` (interface): interface ListingBook — A player-driven marketplace of {@link Listing}s plus the per-seller collection boxes behind it. See {@link createListingBook}.
- `ListingBookConfig` (interface): interface ListingBookConfig — Tunables for {@link createListingBook} — per-seller listing cap, expiry window, house cut, and optional price bounds.
- `PostListingInput` (interface): interface PostListingInput — Input to {@link ListingBook.post} — the goods, asking price, and current game-time to stamp the listing with.
- `PostListingReason` (type): type PostListingReason = | "invalid-count" | "invalid-price" | "price-too-low" | "price-too-high" | "listing-cap-reached" | "duplicate-id" — Why {@link ListingBook.post} refused a listing.
- `PostListingResult` (type): type PostListingResult = | { status: "ok"; listing: Listing } | { status: "rejected"; reason: PostListingReason } — Result of {@link ListingBook.post}.
- `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.

## @jgengine/core/economy/loanBook

- `LoanAdvanceResult` (interface): interface LoanAdvanceResult — What one {@link LoanBook.advance} settled, and what it could not.
- `LoanBook` (interface): interface LoanBook — The loans a business owes: schedules, interest, arrears and default, posted to a ledger.
- `LoanBookOptions` (interface): interface LoanBookOptions — Options for {@link createLoanBook}.
- `LoanBookState` (interface): interface LoanBookState — Serializable loan-book state.
- `LoanBookStats` (interface): interface LoanBookStats — Counters of a loan book, for a probe or a summary line.
- `LoanPayment` (interface): interface LoanPayment — One scheduled repayment, in integer minor units.
- `LoanRecord` (interface): interface LoanRecord — One live loan: its plan plus how far it has been paid.
- `LoanRepayment` (interface): interface LoanRepayment — Outcome of an early repayment.
- `LoanSchedule` (interface): interface LoanSchedule — A full repayment plan: every payment, its interest/principal split and the running balance.
- `LoanState` (interface): interface LoanState — Saved progress of one loan; the schedule is rebuilt from its terms on restore.
- `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.
- `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.
- `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.

## @jgengine/core/economy/market

- `Market` (interface): interface Market — A live market: prices from supply and demand over finite stock, with serializable state.
- `MarketConfig` (interface): interface MarketConfig — Options for {@link createMarket}: the goods and the price/demand policy they share.
- `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.
- `MarketGoodState` (interface): interface MarketGoodState — The mutable half of a good: what a save stores, with the definition kept as authored data.
- `MarketPriceInput` (interface): interface MarketPriceInput — Everything a price curve reads: the good's resolved policy plus its live stock and demand.
- `MarketQuote` (interface): interface MarketQuote — A non-mutating read of what a sale would cost and how it would move the price.
- `MarketSale` (interface): interface MarketSale — A served sale: what the buyer paid per unit and in total, in minor units.
- `MarketSaleRejection` (interface): interface MarketSaleRejection — Why a sale could not be served.
- `MarketSaleResult` (type): type MarketSaleResult = MarketSale | MarketSaleRejection — A sale outcome: the price the buyers paid, or why it could not be served.
- `MarketSnapshot` (interface): interface MarketSnapshot — Serializable market state: the mutable half of every good plus the running counters.
- `MarketStats` (interface): interface MarketStats — Counters and stocks of a market, for a probe or a summary line.
- `createMarket` (function): function createMarket(config: MarketConfig = {}): Market — A market whose price comes from supply and demand over finite stock, as plain serializable state.

## @jgengine/core/economy/priceHistory

- `PriceHistory` (interface): interface PriceHistory — A bounded rolling record of completed sales per item. See {@link createPriceHistory}.
- `PriceHistoryConfig` (interface): interface PriceHistoryConfig — Tunables for {@link createPriceHistory} — the per-item sample cap bounds memory; the optional window drops samples older than `windowSeconds` whenever the history is written or read with a newer timestamp.
- `PriceStats` (interface): interface PriceStats — Aggregated market stats for one item over the retained samples.
- `SaleRecord` (interface): interface SaleRecord — One completed sale recorded into a {@link PriceHistory}.
- `createPriceHistory` (function): function createPriceHistory(config: PriceHistoryConfig): PriceHistory — The "market price" readout behind every auction house: a bounded rolling record of completed sales per item, aggregated into min/max/volume-weighted-average/latest unit-price stats so games can show current value and recent trends. Memory is bounded by `maxSamplesPerItem` (oldest samples drop first) and optionally by a sliding time window; timestamps are injected by the caller so the history stays deterministic.

## @jgengine/core/economy/resourceLedger

- `AdvanceOptions` (interface): interface AdvanceOptions — Per-advance settings: the policy pipeline, caller context, rounding, and safety bounds.
- `AdvanceResult` (interface): interface AdvanceResult — The outcome of {@link advanceLedger}: the new ledger plus applied transactions and events.
- `AppliedTransaction` (type): type AppliedTransaction = ResourceTransaction — A {@link ResourceTransaction} after policies and rounding, as actually applied to balances.
- `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).
- `LedgerEvent` (interface): interface LedgerEvent — Lifecycle signal emitted by {@link advanceLedger}.
- `LedgerEventKind` (type): type LedgerEventKind = "started" | "fired" | "skipped" | "depleted" | "ended" — The kinds of lifecycle signal {@link advanceLedger} can emit for a rule.
- `PolicyContext` (interface): interface PolicyContext — Read-only context handed to every {@link ResourcePolicy} for a transaction.
- `PolicyRead` (type): type PolicyRead = string | ((ctx: PolicyContext) => number) — Reader over policy context: a `vars` key or a function of the context.
- `Precision` (interface): interface Precision — Deterministic rounding applied to every transaction amount before it touches balances.
- `ResourceLedger` (interface): interface ResourceLedger — Fully serializable scheduled-transaction state: clock, balances, rule definitions, and cursors.
- `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.
- `ResourceTransaction` (interface): interface ResourceTransaction — One resource movement produced by a due cycle, before it is applied to balances.
- `RuleCursor` (interface): interface RuleCursor — Mutable per-rule progress, kept separate from the immutable {@link ScheduledRule} definition.
- `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.
- `ThresholdBand` (interface): interface ThresholdBand — A `{ min, factor }` band for {@link thresholdScale}; the highest band whose `min` is met wins.
- `addScheduledRule` (function): function addScheduledRule(ledger: ResourceLedger, rule: ScheduledRule): ResourceLedger — Register a recurring rule and seed its cursor. Returns a new ledger; the rule's first cycle is due at `rule.startSeconds` (defaulting to the current clock).
- `advanceLedger` (function): function advanceLedger(ledger: ResourceLedger, toSeconds: number, options: AdvanceOptions = {}): AdvanceResult — Advance the ledger clock to `toSeconds`, settling every due cycle deterministically. Rules are processed in sorted-id order; cycle counts are integer math; large deltas are bounded by `catchUp`, `maxCatchUpCycles`, and `maxCyclesPerRule`. Every produced transaction flows through the policy pipeline (transform, cap, reject, split, redirect, annotate) before it is quantised and applied to balances.
- `annotate` (function): function annotate(tag: string): ResourcePolicy — Append a provenance tag to a transaction without changing its value.
- `balanceOf` (function): function balanceOf(ledger: ResourceLedger, account: string, currency: string): number — Read a single balance; unknown account/currency pairs read as `0`.
- `cancelRule` (function): function cancelRule(ledger: ResourceLedger, ruleId: string): ResourceLedger — Remove a rule and its cursor entirely (hard cancellation).
- `capAmount` (function): function capAmount(max: number | ((ctx: PolicyContext) => number)): ResourcePolicy — Clamp a transaction's amount to at most `max` (a fixed number or a function of context).
- `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}.
- `curveScale` (function): function curveScale(read: PolicyRead, shape: Curve): ResourcePolicy — Scale the amount by a {@link Curve} evaluated at the read value — a generic curve modifier (population upkeep, depletion falloff, difficulty income) over caller-provided context.
- `pauseRule` (function): function pauseRule(ledger: ResourceLedger, ruleId: string): ResourceLedger — Pause a rule: its cursor is retained but it fires nothing until {@link resumeRule}.
- `redirect` (function): function redirect(endpoints: { source?: string; recipient?: string }): ResourcePolicy — Override the source and/or recipient accounts of a transaction.
- `rejectWhen` (function): function rejectWhen(predicate: (txn: ResourceTransaction, ctx: PolicyContext) => boolean): ResourcePolicy — Drop a transaction when `predicate` holds — the reject arm of the pipeline.
- `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.
- `taxFraction` (function): function taxFraction(fraction: number, to?: string): ResourcePolicy — Take a fraction of the amount. With `to`, the taxed portion is split off into a second transaction toward that recipient (a transfer/tax); without it, the fraction is simply removed.
- `thresholdScale` (function): function thresholdScale(read: PolicyRead, bands: readonly ThresholdBand[]): ResourcePolicy — Scale the amount by the highest {@link ThresholdBand} whose `min` the read value meets — a generic bracket modifier (progressive tax, tiered upkeep) over caller data, with no built-in currencies or brackets.

## @jgengine/core/economy/sharedWallet

- `BookChargeResult` (type): type BookChargeResult = | { status: "ok"; book: WalletBook } | { status: "rejected"; reason: "insufficient-funds" } — ⚠ undocumented
- `WalletBook` (interface): interface WalletBook { scopes: Readonly<Record<string, WalletState>>; contributions: Readonly<Record<string, Readonly<Record<string, Readonly<Record<string, number>>>>>> } — ⚠ undocumented
- `WalletScope` (type): type WalletScope = | { kind: "user"; userId: string } | { kind: "group"; groupId: string } — ⚠ undocumented

## @jgengine/core/economy/shopStock

- `ShopBuyRejection` (type): type ShopBuyRejection = "unknown-item" | "out-of-stock" | "insufficient-funds" — Why a {@link ShopStock.buy} was refused.
- `ShopBuyResult` (type): type ShopBuyResult = | { ok: true; wallet: WalletState; entry: ShopStockEntry } | { ok: false; reason: ShopBuyRejection } — Result of {@link ShopStock.buy}: on success the caller receives the debited `wallet` to adopt and a snapshot of the purchased `entry` (post-decrement); on failure a `reason` and the wallet is untouched.
- `ShopPrice` (interface): interface ShopPrice — A price tag: how much of a free-string `currency` an entry costs (buy) or returns (sell). `amount` is a non-negative finite number; `0` means free (no wallet charge/grant happens).
- `ShopSellRejection` (type): type ShopSellRejection = "unknown-item" | "not-sellable" — Why a {@link ShopStock.sell} was refused.
- `ShopSellResult` (type): type ShopSellResult = | { ok: true; wallet: WalletState; entry: ShopStockEntry } | { ok: false; reason: ShopSellRejection } — Result of {@link ShopStock.sell}: on success the caller receives the credited `wallet` and a snapshot of the sold `entry` (post-restock); on failure a `reason` and the wallet is untouched.
- `ShopStock` (interface): interface ShopStock — A live, observable vendor/shop stock operating over a caller-owned wallet.
- `ShopStockConfig` (interface): interface ShopStockConfig — Config for {@link createShopStock}: the initial set of entries.
- `ShopStockEntry` (interface): interface ShopStockEntry — One item a vendor stocks. Fully serializable; `kind` and `currency` are free strings the model never branches on.
- `ShopStockSnapshot` (interface): interface ShopStockSnapshot — Serializable state of a shop's stock, for save/restore.
- `createShopStock` (function): function createShopStock(config: ShopStockConfig = {}): ShopStock — A serializable, observable vendor/shop stock. Each entry carries a game-owned free-string `kind`, a `price` in a free-string `currency`, a finite or unlimited (`qty: null`) count, and an optional `sellPrice` buy-back. All currency math is delegated to the existing pure `wallet` model — `buy` charges and `sell` grants a **caller-owned** {@link WalletState} (the shop never holds the wallet, it returns the new wallet for the caller to adopt), so the same stock composes with any wallet the game owns. Nothing here is genre-specific: `kind` and `currency` are free labels the game styles and the model never branches on. `restock`/`setPrice`/`add`/`remove` mutate the catalog, `subscribe` observes every change, and `snapshot`/`restore` round-trips the whole stock through a save.

## @jgengine/core/economy/techTree

- `TechCheck` (type): type TechCheck = { ok: true } | ({ ok: false } & TechRejection) — ⚠ undocumented
- `TechNodeDef` (interface): interface TechNodeDef extends UnlockDef { requires?: readonly string[]; cost?: Readonly<Record<string, number>>; grants?: readonly string[]; recipe?: string } — ⚠ undocumented
- `TechRejection` (type): type TechRejection = | { reason: "unknown-node" } | { reason: "already-unlocked" } | { reason: "missing-prerequisites"; missing: readonly string[] } — ⚠ undocumented
- `TechState` (type): type TechState = UnlockState — ⚠ undocumented
- `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

## @jgengine/core/economy/transactionLedger

- `ChargeCursor` (interface): interface ChargeCursor — Mutable per-charge progress, kept apart from the {@link RecurringCharge} definition.
- `LedgerAdvanceResult` (interface): interface LedgerAdvanceResult — What one {@link TransactionLedger.chargeDue} settled, and what it could not.
- `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.
- `LedgerEntryFilter` (interface): interface LedgerEntryFilter — A filter over the journal.
- `LedgerPostInput` (interface): interface LedgerPostInput — A post to attempt.
- `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.
- `LedgerState` (interface): interface LedgerState — Fully serializable ledger state: clock, balances, journal, totals, charges and cursors.
- `LedgerStats` (interface): interface LedgerStats — Counters of a ledger, for a probe or a summary line.
- `LedgerTotals` (interface): interface LedgerTotals — What one reason code did to the books, kept across entry trimming.
- `RecurringCharge` (interface): interface RecurringCharge — A recurring charge — upkeep, rent, a subscription — settled by {@link TransactionLedger.chargeDue}.
- `TransactionLedger` (interface): interface TransactionLedger — The books: balances with a reason-tagged journal, and recurring charges on a cadence.
- `TransactionLedgerOptions` (interface): interface TransactionLedgerOptions — Options for {@link createTransactionLedger}.
- `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.

## @jgengine/core/economy/unlockPoints

- `SpendOptions` (interface): interface SpendOptions — Options for {@link UnlockPoints.spend}.
- `SpendRejection` (type): type SpendRejection = | "invalid-cost" | "already-unlocked" | "missing-prerequisites" | "insufficient-points" — Why a {@link UnlockPoints.spend} was refused; the pool is left untouched on any rejection.
- `SpendResult` (type): type SpendResult = { ok: true; available: number } | { ok: false; reason: SpendRejection } — Result of {@link UnlockPoints.spend}: the new `available` balance on success, else a reason.
- `UnlockPoints` (interface): interface UnlockPoints — A spendable unlock-point economy: a pool you earn (per level or by direct grant) and spend to unlock nodes, with per-unlock refunds and a full respec.
- `UnlockPointsConfig` (interface): interface UnlockPointsConfig — Configuration for {@link createUnlockPoints}.
- `UnlockPointsState` (interface): interface UnlockPointsState — Plain, JSON-serializable snapshot of a point pool. `earned` is the lifetime total ever banked; every committed unlock lives in `unlocked` as `id → cost paid`. `spent` and `available` are always derived (`spent = Σ unlocked`, `available = earned − spent`) so the two can never drift out of sync across a serialize/hydrate round-trip.
- `createUnlockPoints` (function): function createUnlockPoints(config: UnlockPointsConfig = {}): UnlockPoints — Spendable unlock-point economy — the seam between leveling and a tech tree. Points are earned per level (via a configurable, possibly non-uniform grant curve) or granted directly, then spent to unlock nodes; spending can defer prerequisite checks to an injected predicate so it composes with `economy/techTree` (or any gate) without depending on it. Individual unlocks refund, and `respec` fully refunds a build while preserving lifetime earned points. All state is plain and JSON round-trips.

## @jgengine/core/economy/wallet

- `ChargeOptions` (interface): interface ChargeOptions — Options for {@link charge}/{@link chargeAll}: opt one call into overdraft debt via `overdraft`.
- `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`.
- `Overdraft` (type): type Overdraft = boolean | { max: number } — Opt-in debt affordance for {@link charge}/{@link chargeAll}: `true` allows the balance to go arbitrarily negative, a number caps how far into the red it may go (the charge is rejected once `balance - amount` would fall below `-max`). Omitted (the default) keeps the strict no-debt rule.
- `WalletState` (interface): interface WalletState { balances: Readonly<Record<string, number>> } — ⚠ undocumented · used by `canAfford`: True when every currency in `costs` has at least that much balance (a pure, non-mutating check).
- `balance` (function): function balance(state: WalletState, currency: string | CurrencyDefinition): number — ⚠ undocumented
- `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).
- `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.
- `chargeAll` (function): function chargeAll(state: WalletState, costs: Readonly<Record<string, number>>, options?: ChargeOptions): ChargeResult — ⚠ undocumented
- `createEmptyWallet` (function): function createEmptyWallet(): WalletState — Hold per-currency balances with affordability checks and charge/grant operations.
- `grant` (function): function grant(state: WalletState, currency: string | CurrencyDefinition, amount: number): WalletState — ⚠ undocumented
- `isOverdrawn` (function): function isOverdrawn(state: WalletState, currency: string | CurrencyDefinition): boolean — True once `balance(state, currency)` has gone negative under an overdraft-enabled charge.

## @jgengine/core/game/achievements

- `AchievementDef` (interface): interface AchievementDef — Definition of one achievement. Content-agnostic — the game supplies names, targets, and icons.
- `AchievementSnapshot` (interface): interface AchievementSnapshot — Whole serializable state of a tracker — drop into a save blob.
- `AchievementTracker` (interface): interface AchievementTracker — Live achievement state over a fixed definition set — drives progress, unlocks, score, and a UI view list.
- `AchievementTrackerOptions` (interface): interface AchievementTrackerOptions — Options for {@link createAchievementTracker}.
- `AchievementUnlock` (interface): interface AchievementUnlock — Emitted the instant an achievement unlocks — wire to a toast, feed, or sound.
- `AchievementView` (interface): interface AchievementView extends AchievementDef — A definition plus its live unlock/progress state — what UI renders.
- `createAchievementTracker` (function): function createAchievementTracker(options: AchievementTrackerOptions): AchievementTracker — Tracks achievement/trophy unlocks over caller-driven events — counter goals (`progress`/`setProgress`) and boolean flags (`unlock`) — with score, completion, an `onUnlock` seam, and serializable `snapshot`/`restore`. State is plain data; the view list keeps a stable identity between changes so React can read it through `useSyncExternalStore` without re-projecting every frame.

## @jgengine/core/game/breeding

- `BreedConfig` (interface): interface BreedConfig — Tuning for {@link breedOffspring}. Every field has an ARK-style default; all are optional.
- `BreedResult` (interface): interface BreedResult — Result of {@link breedOffspring}: the new genome plus the mutations that produced it.
- `Genome` (interface): interface Genome — A creature's heritable genome. `stats` are the inherited/mutated point values; `mutationCount` and `colorMutationCount` are the lineage counters that carry across generations and drive the mutation soft cap. Fully serializable — no methods or closures.
- `ImprintBonusConfig` (interface): interface ImprintBonusConfig — Options controlling how an imprint bonus is applied.
- `IncubationConfig` (interface): interface IncubationConfig — Temperature gate for {@link tickIncubation}.
- `IncubationState` (interface): interface IncubationState — Serializable incubation/gestation state advanced by {@link tickIncubation}.
- `MaturationStage` (interface): interface MaturationStage — A maturation stage keyed by the elapsed fraction (0..1) at which it begins.
- `MutationEvent` (interface): interface MutationEvent — One mutation that occurred while breeding a single offspring.
- `MutationSoftCap` (interface): interface MutationSoftCap — Soft-cap rule for mutation eligibility. When a parent's `mutationCount` exceeds `threshold` its lineage is considered "capped"; the per-roll mutation chance is then either zeroed (`mode: "block"`) or scaled by `reducedFactor` (`mode: "reduce"`). `scope` decides whether it takes `both` parents capped, or `either` one, to trigger.
- `StatBlock` (type): type StatBlock = Record<string, number> — Deterministic creature breeding & genetics — a genre-agnostic engine primitive for taming/husbandry games. Everything here operates over plain serializable records so a genome round-trips through save/load and multiplayer sync, and every random decision is driven by an injected `rng: () => number` (values in `[0, 1)`) so identical inputs and an identical rng stream always produce the identical offspring.
- `applyImprintBonus` (function): function applyImprintBonus(stats: StatBlock, imprint: number, config: ImprintBonusConfig = {}, options: { asOwner?: boolean } = {}): StatBlock — Apply the imprint rearing bonus to a stat block. Every stat is scaled by `1 + statBonusAtFull * imprint`; when `asOwner` is set, the imprinting handler additionally gets `1 + handlerBonusAtFull * imprint`. `imprint` is a 0..1 fraction (clamped) and scales both bonuses linearly, so half-imprint yields half the bonus. Returns a fresh stat block.
- `breedOffspring` (function): function breedOffspring(parentA: Genome, parentB: Genome, rng: () => number, config: BreedConfig = {}): BreedResult — Breed one offspring from two parents. For each stat present in either parent (iterated in sorted id order for a stable rng stream) the offspring independently inherits the higher parent's value with probability `higherStatChance` (default `0.55`), else the lower — a per-stat coin flip, so a strong parent does not guarantee a strong child. Then up to `mutationRolls` mutation rolls fire at the soft-capped chance; each success adds `mutationDelta` to a random stat, bumps the heritable `mutationCount`, and is flagged cosmetic with probability `colorMutationChance`. Lineage counters carry as the max of the two parents plus the new mutations, keeping them monotonic and heritable.
- `imprintIncrementPerRequest` (function): function imprintIncrementPerRequest(requestCount: number): number — Imprint gained per fulfilled care request when `requestCount` requests are scheduled over the maturation window: `1 / requestCount`, so fulfilling every request reaches full (1.0) imprint. Returns `0` for a non-positive request count.
- `incubationViable` (function): function incubationViable(state: IncubationState): boolean — True while the incubation still has health to hatch.
- `maturationStage` (function): function maturationStage(elapsed: number, duration: number, stages: readonly MaturationStage[]): string — Resolve the maturation stage for an elapsed time against a duration. Computes the clamped `elapsed / duration` fraction and returns the id of the last stage whose `at` threshold has been reached (boundaries inclusive). Stages need not be pre-sorted. Returns `""` when no stage qualifies (e.g. an empty list or all thresholds above the current fraction).
- `tickIncubation` (function): function tickIncubation(state: IncubationState, temperature: number, dt: number, config: IncubationConfig): IncubationState — Advance incubation one tick. While `temperature` is within `[minTemp, maxTemp]` the embryo makes progress (`elapsed += dt`) and keeps its health; outside the range it makes no progress and loses `healthLossPerTick * dt` health (clamped at `0`). Pure — returns a new state, never mutates the input.

## @jgengine/core/game/cameraConfig

- `CAMERA_FRUSTUM_DEFAULTS` (const): const CAMERA_FRUSTUM_DEFAULTS: { readonly fov: 55; readonly near: 0.1; readonly far: 300; readonly zoom: 50; } — ⚠ undocumented
- `CameraFollowState` (interface): interface CameraFollowState { entityId: string; target: {x: number; y: number; z: number}; camera: {x: number; y: number; z: number}; distance: number } — ⚠ undocumented
- `CameraKeyframe` (interface): interface CameraKeyframe — One stop on a scripted camera path (#29).
- `CameraProjection` (type): type CameraProjection = "perspective" | "orthographic" — Canvas camera projection. "orthographic" renders a flat 2D-style view (side-scrollers, falling-block puzzles) — pair with `rig: "sideScroll"`; default "perspective".
- `CameraRigKind` (type): type CameraRigKind = | "orbit" | "first" | "topDown" | "rts" | "shoulder" | "lockOn" | "chase" | "observer" | "turntable" | "sideScroll" | "inspection" | "none" — Which camera rig the shell mounts. Every rig accepts `followEntityId: null` (avatar-less games — city-builders, card games, auto-battlers — still get a camera). Rigs are tuned through their config block below, never by writing camera positions from `onTick`. - `orbit` — third-person chase (the historical default; `perspective: "third"`). - `first` — pointer-lock mouse-look (`perspective: "first"`). - `topDown` — fixed height/pitch/yaw with decoupled follow (ARPG iso, top-down). - `rts` — free-pan / edge-scroll / rotate / zoom, optional follow. - `shoulder` — over-the-shoulder with ADS transition + shoulder swap. - `lockOn` — yaw bound to the player→target vector; move axis becomes strafe. - `chase` — speed-reactive vehicle chase (speed→FOV, spring arm, shake) + cockpit/hood/rear views. - `observer` — detached spectator/photo cam bound to any entity or fixed point; never reads player input. - `turntable` — slow auto-orbit of a fixed point: a rotating display stand for a scene. The friendly, flat spelling of `observer`'s point-orbit mode; providing `camera.turntable` selects it without an explicit `rig`. - `sideScroll` — fixed lateral follow (2.5D platformer/beat-'em-up side view); reads no player input. - `inspection` — model-viewer / editor rig (#207.7, #866): middle-drag pan, right-drag orbit, scroll zoom toward a configurable anchor; orbits a fixed point, reads no player/entity input. - `none` — no camera rig is mounted; use for HUD-only presentations or a game that manages its own camera.
- `CameraShakeConfig` (interface): interface CameraShakeConfig — Camera-shake / trauma defaults (#28). Any rig reads the trauma channel; game systems feed it via `cameraShake()`.
- `CameraWeaponView` (interface): interface CameraWeaponView — What a camera rig reads about the held weapon each frame; see `GameCameraConfig.weapon`.
- `ChaseCameraConfig` (interface): interface ChaseCameraConfig — Speed-reactive vehicle chase rig (#27) — speed→FOV, spring arm, procedural shake, interior views.
- `ChaseView` (type): type ChaseView = "chase" | "cockpit" | "hood" | "rear" — Fixed interior view for the chase rig (#27).
- `CinematicCameraConfig` (interface): interface CinematicCameraConfig — Scripted keyframe / path player (#29). When set it overrides the active rig.
- `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig { eyeHeight?: number; sensitivity?: number; maxPitch?: number; reticle?: boolean; viewmodel?: boolean; collision?: false | FirstPersonCollisionConfig } — ⚠ undocumented
- `FirstPersonCollisionConfig` (interface): interface FirstPersonCollisionConfig — Clearance tuning for the first-person camera's collision pull-in.
- `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.
- `InspectionCameraConfig` (interface): interface InspectionCameraConfig — Model-viewer / inspection rig (#207.7) — orbit + pan + anchored zoom around a fixed point, never reads player input.
- `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.
- `LockOnCameraConfig` (interface): interface LockOnCameraConfig — Lock-on / strafe rig (#26) — yaw bound to player→target, move axis becomes strafe.
- `ObserverCameraConfig` (interface): interface ObserverCameraConfig — Detached spectator/photo cam (#120) — binds to any entity or fixed point, never reads player input.
- `PixelPerfectCameraConfig` (interface): interface PixelPerfectCameraConfig — Pixel-art orthographic camera tuning. `pixelsPerUnit` is the authored pixel density.
- `PlayerFovConfig` (interface): interface PlayerFovConfig — Player-facing FOV preference applied across every perspective camera rig. Orthographic projections ignore it.
- `RtsCameraConfig` (interface): interface RtsCameraConfig extends TopDownCameraConfig — Free-pan / edge-scroll RTS rig (#24) — pan/rotate/zoom independent of any avatar.
- `ShoulderCameraConfig` (interface): interface ShoulderCameraConfig — Over-the-shoulder combat rig (#25) — offset, ADS, shoulder swap, decoupled reticle.
- `SideScrollCameraConfig` (interface): interface SideScrollCameraConfig — Fixed lateral 2.5D follow (side-on platformer cam): the camera sits perpendicular to the travel axis, tracks the followed entity, and never reads player look input.
- `TopDownCameraConfig` (interface): interface TopDownCameraConfig — Fixed top-down / isometric rig (#23) — height/pitch/yaw + decoupled follow.
- `TurntableCameraConfig` (interface): interface TurntableCameraConfig — Turntable / showcase rig — slowly auto-orbits a fixed world point (no player input), the way a museum turntable rotates an object on display. A flat, self-describing spelling of `observer`'s point-orbit mode: `target` names the point directly instead of `bind: { kind: "point", position }`. Set `camera.turntable` and the rig is inferred — you don't also write `rig`.

## @jgengine/core/game/chat

- `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
- `ChatChannelDef` (interface): interface ChatChannelDef { id: string; kind: ChatChannelKind; radius?: number; historyLimit?: number; rateLimit?: ChatRateLimit } — ⚠ undocumented
- `ChatChannelKind` (type): type ChatChannelKind = "global" | "party" | "proximity" — ⚠ undocumented
- `ChatDeps` (interface): interface ChatDeps { events: GameEvents; now?: () => number; party?: {membersOf(userId: string): string[]}; proximity?: EmotesDeps; blockedBy?: (userId: string) => readonly string[]; maxBodyLength?: number; defaultRateLimit?: ChatRateLimit; filter?: ChatFilte… — ⚠ undocumented
- `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…
- `ChatRateLimit` (interface): interface ChatRateLimit { count: number; perMs: number } — ⚠ undocumented
- `ChatRateLimiter` (interface): interface ChatRateLimiter { allow(key: string, atMs: number): boolean; snapshot(): Record<string, number[]>; restore(state: Record<string, number[]>): void } — ⚠ undocumented
- `ChatRecipients` (type): type ChatRecipients = readonly string[] | "all" — ⚠ undocumented
- `ChatSendResult` (type): type ChatSendResult = | { message: ChatMessage; recipients: ChatRecipients } | { reason: string } — ⚠ undocumented
- `ChatSnapshot` (interface): interface ChatSnapshot { messages: Record<string, ChatMessage[]>; counter: number; rateWindows?: Record<string, Record<string, number[]>> } — ⚠ undocumented
- `ChatValidation` (type): type ChatValidation = { ok: true; text: string } | { ok: false; reason: string } — Sanitized chat text or a displayable validation failure.
- `DEFAULT_CHAT_BODY_LENGTH` (const): const DEFAULT_CHAT_BODY_LENGTH: 240 — ⚠ undocumented
- `DEFAULT_CHAT_HISTORY_LIMIT` (const): const DEFAULT_CHAT_HISTORY_LIMIT: 100 — ⚠ undocumented
- `DEFAULT_CHAT_RATE_LIMIT` (const): const DEFAULT_CHAT_RATE_LIMIT: ChatRateLimit — ⚠ undocumented
- `DEFAULT_PROXIMITY_CHAT_RADIUS` (const): const DEFAULT_PROXIMITY_CHAT_RADIUS: 20 — ⚠ undocumented
- `WHISPER_CHANNEL_PREFIX` (const): const WHISPER_CHANNEL_PREFIX: "whisper:" — ⚠ undocumented
- `createChat` (function): function createChat(deps: ChatDeps): Chat — ⚠ undocumented
- `createChatRateLimiter` (function): function createChatRateLimiter(limit: ChatRateLimit): ChatRateLimiter — ⚠ undocumented
- `validateChatMessage` (function): function validateChatMessage(value: unknown, options: { maxLength?: number } = {}): ChatValidation — Strip control characters and enforce the shared chat message policy before storage or broadcast.
- `whisperChannelId` (function): function whisperChannelId(a: string, b: string): string — ⚠ undocumented

## @jgengine/core/game/chatFilter

- `ChatFilter` (interface): interface ChatFilter { apply(body: string): ChatFilterResult } — ⚠ undocumented
- `ChatFilterConfig` (interface): interface ChatFilterConfig { blockedWords: readonly string[]; mode?: "mask" | "reject"; mask?: string } — ⚠ undocumented
- `ChatFilterResult` (interface): interface ChatFilterResult { ok: boolean; body: string; matched: readonly string[] } — ⚠ undocumented
- `createChatFilter` (function): function createChatFilter(config: ChatFilterConfig): ChatFilter — ⚠ undocumented
- `normalizeChatText` (function): function normalizeChatText(text: string): string — ⚠ undocumented

## @jgengine/core/game/clipRoles

- `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.
- `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.
- `DEFAULT_CLIP_ROLE_TABLE` (const): const DEFAULT_CLIP_ROLE_TABLE: ClipRoleTable — Default vocabulary covering KayKit, Quaternius, and Mixamo-style clip naming.
- `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).
- `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.
- `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.
- `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.

## @jgengine/core/game/codex

- `Codex` (interface): interface Codex<TMeta = unknown> — A codex/bestiary of defined entries with per-player discovery tracking.
- `CodexEntryDef` (interface): interface CodexEntryDef<TMeta = unknown> — A codex/bestiary/lorebook entry the game defines. Discovery state is tracked separately.
- `CodexEntryView` (interface): interface CodexEntryView<TMeta = unknown> extends CodexEntryDef<TMeta> — A definition plus its discovery state — what UI renders.
- `CodexOptions` (interface): interface CodexOptions<TMeta = unknown> — Options for {@link createCodex}.
- `CodexSnapshot` (interface): interface CodexSnapshot — Serializable discovery state — a save blob.
- `createCodex` (function): function createCodex<TMeta = unknown>(options: CodexOptions<TMeta>): Codex<TMeta> — A codex / bestiary / lorebook: a fixed set of defined entries plus per-player discovery tracking, with categories, secret masking, completion, an `onDiscover` seam, and serializable `snapshot`/`restore`. The view `list()` keeps a stable identity between changes so React reads it through `useSyncExternalStore` without re-projecting each frame.

## @jgengine/core/game/connectedPlayers

- `ConnectedPlayer` (interface): interface ConnectedPlayer — A player currently joined to a hosted world — the unit a shared-world loop iterates instead of `ctx.player`. Frozen by the registry (see {@link ConnectedPlayers.get}); fields are `readonly` so a caller can't edit its own copy and assume the change stuck.
- `ConnectedPlayers` (interface): interface ConnectedPlayers — The set of players connected to one hosted world. A single-player game uses `ctx.player`; a shared-world loop reads `ctx.game.players` so `onTick` can advance every connected hero, not just the one local player. The host (`HostedGameRunner`) drives `join`/`leave`/`setInput`; game code reads `list`/`ids`/`has`/`count`/`input`.
- `createConnectedPlayers` (function): function createConnectedPlayers(): ConnectedPlayers — Build an empty {@link ConnectedPlayers} registry — the host joins/leaves players; the game loop reads them.

## @jgengine/core/game/contentValidation

- `ContentEntry` (interface): interface ContentEntry — A definition in a game-owned namespace, located in its authored document.
- `ContentIssue` (interface): interface ContentIssue — A repairable authoring issue. Paths are caller document locations, usually JSON Pointers.
- `ContentProgressionInput` (interface): interface ContentProgressionInput — Explicit possible sources; opaque fact strings may represent items, unlocks or skill milestones.
- `ContentProgressionRequirement` (interface): interface ContentProgressionRequirement — A game-declared availability requirement, located at the content that needs it.
- `ContentProgressionResult` (interface): interface ContentProgressionResult — Potential availability and diagnostics in deterministic input/traversal order.
- `ContentProgressionRule` (interface): interface ContentProgressionRule — A possible source or action; all required facts must be reachable to provide its facts.
- `ContentReference` (interface): interface ContentReference extends ContentEntry — A located reference; namespaces can express game-owned roles such as questgiver.
- `validateContentProgression` (function): function validateContentProgression(input: ContentProgressionInput): ContentProgressionResult — Check declared potential progression using a dependency queue in O(facts + rules + edges). Alternatives are separate rules; every requirement within one rule is necessary. Seeded cycles are valid. An unseeded cycle is blocked only under the declared sources. Facts describe possible availability, not quantities, consumption, mutually exclusive choices, chronology, station proximity or economic balance. Encode those constraints in game-owned rules or playtests. Skill training caps must be explicitly translated into attainable milestones. This is offline authoring analysis, not a quest engine or a per-frame catalog scan.
- `validateContentReferences` (function): function validateContentReferences(entries: readonly ContentEntry[], references: readonly ContentReference[]): ContentIssue[] — Index definitions once and check references in input order, without mutating the catalog. Namespace strings and roles are game-owned; identical ids in different namespaces are valid. Typed input must be decoded before calling. Work is O(definitions + references + allowed ids).

## @jgengine/core/game/controlGate

- `PLAY_CONTROLS_STORE_KEY` (const): const PLAY_CONTROLS_STORE_KEY: "jg.playControls" — ⚠ undocumented
- `actionContextStack` (function): function actionContextStack(ctx: GameContext): ActionContextStack — Returns the context stack associated with a game context.
- `activeActionCodes` (function): function activeActionCodes(ctx: GameContext, base: ActionCodesMap): ActionCodesMap — Applies active contexts to a base action map for shell input tracking.
- `playControlsActive` (function): function playControlsActive(ctx: GameContext): boolean — ⚠ undocumented
- `setPlayControlsActive` (function): function setPlayControlsActive(ctx: GameContext, active: boolean): void — ⚠ undocumented
- `suspendPlayControls` (function): function suspendPlayControls(ctx: GameContext): () => void — Suspends this context's player controls until the returned release function is called. Independent owners compose; repeated release is safe and preserves the existing play gate. Dispose the lease when its menu closes or its owning context unmounts. Leases survive this context's binding restore and are excluded from saved binding state.

## @jgengine/core/game/cosmetics

- `CosmeticLoadoutDef` (interface): interface CosmeticLoadoutDef { slots: Record<string, string> } — ⚠ undocumented
- `Cosmetics` (interface): interface Cosmetics { register(defs: Record<string, CosmeticLoadoutDef>): void; has(loadoutId: string): boolean; apply(userId: string, loadoutId: string): {reason: string} | null; equip(userId: string, slot: string, cosmeticId: string | null): void; get(userId… — ⚠ undocumented · used by `createCosmetics`: Equip cosmetic skins and customizations by slot, independent of gameplay stats.
- `CosmeticsChangedEvent` (interface): interface CosmeticsChangedEvent { userId: string; slots: Record<string, string> } — ⚠ undocumented
- `CosmeticsDeps` (interface): interface CosmeticsDeps { events?: CosmeticsEvents } — ⚠ undocumented · used by `createCosmetics`: Equip cosmetic skins and customizations by slot, independent of gameplay stats.
- `CosmeticsEvents` (interface): interface CosmeticsEvents { emit(name: "cosmetics.changed", payload: CosmeticsChangedEvent): void } — ⚠ undocumented
- `createCosmetics` (function): function createCosmetics(deps: CosmeticsDeps = {}): Cosmetics — Equip cosmetic skins and customizations by slot, independent of gameplay stats.

## @jgengine/core/game/credits

- `CreditsDocument` (interface): interface CreditsDocument — Everything a credits screen shows. `notice` is the closing line (a license summary, a thank-you).
- `CreditsEntry` (interface): interface CreditsEntry — One credited line — a person, a studio, an asset pack, a tool.
- `CreditsSection` (interface): interface CreditsSection — A titled group of entries — "Design", "Music", "3D Assets".
- `groupCredits` (function): function groupCredits<T>(items: readonly T[], heading: (item: T) => string, entry: (item: T) => CreditsEntry): CreditsSection[] — Groups entries into sections by a caller-supplied key — the shape most generated credits arrive in (a flat list of things used, grouped by license, provider, or role). Section order follows first appearance, so a stable input gives a stable screen.
- `mergeCredits` (function): function mergeCredits(...documents: readonly (CreditsDocument | null | undefined)[]): CreditsDocument — Merges credit documents into one, concatenating same-heading sections in first-seen order and dropping exact duplicate entries. Use it to fold generated credits (asset packs, dependencies) into the game's hand-authored ones without curating the overlap by hand.

## @jgengine/core/game/defineGame

- `GameDefinition` (interface): interface GameDefinition<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> — Fully-resolved game description produced by {@link defineGameDefinition} — assets, scene, and opted-in subsystems.
- `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.
- `GameFeatures` (interface): interface GameFeatures — Opt-in `ctx.game.*` subsystems. Absent = off: the game doesn't carry (or expose) it, and `ctx.game.<name>` is `undefined`. Present (`true`) builds it. The universal base — `commands`, `events`, `store`, `feed` — is always on and not listed here. This is what keeps core genre-agnostic: a puzzle game isn't handed an MMO's leaderboard/roster/turn plumbing it never asked for.
- `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).
- `GameLoop` (interface): interface GameLoop<TContext = unknown> — Lifecycle hooks a game implements to drive init, per-tick simulation, and player join/leave.
- `GameProjectileTravelOptions` (interface): interface GameProjectileTravelOptions extends Pick<ProjectileTravelDeps, "maxActive" | "maxRetained"> — Context-aware projectile policy; callbacks are not included in saved shot state.
- `GameServerConfig` (type): type GameServerConfig = "persistent" | { mode: string; [key: string]: unknown } — Hosting mode for a game's multiplayer server: `"persistent"`, or a custom mode with its own options.
- `InventoryDeclaration` (interface): interface InventoryDeclaration — Shape of one named inventory a game declares — slot count, accepted item types, HUD binding.
- `LifecycleConfig` (interface): interface LifecycleConfig<TState = unknown> — Declarative start/restart run lifecycle: the state transitions a game's run phase every genre repeats (title screen → live run → live run → title screen again), expressed as pure functions over one typed {@link StoreHandle} slot instead of hand-rolled `commands.define("start"/"restart")` glue that re-derives phase after every mutation. `start`/`restart` receive the store's own value type — the store's `TState`, never `ctx.game.store.get(key) as T` — and return the next value; the runtime writes it back and derives {@link GamePhase} from it via `phaseOf` in one place, so every adopting game gets identical, correct phase-sync for free.
- `LoopPlayer` (interface): interface LoopPlayer — Identity of a player joining or leaving a hosted world — passed to the multiplayer loop hooks.
- `PersistConfig` (interface): interface PersistConfig — Tunes offline whole-world save (`defineGameDefinition({ persist })`). Offline games already autosave to `localStorage` by default — pass this only to tune it (or `persist: false` to opt out). Defaults: continuous `autosave` to `localStorage`, one slot, no version.
- `PhysicsConfig` (interface): interface PhysicsConfig — World gravity and jump tuning, plus the optional rigid-body backend and character capsule.
- `defineGameDefinition` (function): function defineGameDefinition<TAssetRef extends ModelAssetRef, TMultiplayer>(config: GameDefinitionConfig<TAssetRef, TMultiplayer>): GameDefinition<TAssetRef, TMultiplayer> — Host-level constructor for a bare `GameDefinition`: fills in `scene` and default `assets`, validates `name`, OR-merges `features` from installed systems, and composes `loop` from `systems` + any classic hooks. Games author through `defineGame` from `@jgengine/shell/defineGame`, which calls this and adds the presentation layer; call this directly only from headless hosts that mount no shell.

## @jgengine/core/game/defineSystem

- `SystemDefinition` (interface): interface SystemDefinition — A reusable game capability — lifecycle, timing, events, and optional save / replication / reset / disposal. Pass instances via `defineGame({ systems })`. Prefer one system per meaningful capability (`combat`, `quests`), not per micro-tick.
- `SystemEventHandlers` (type): type SystemEventHandlers = { readonly [eventName: string]: (ctx: GameContext, event: unknown) => void; } — Event name → handler. Payload is the engine event shape for that name.
- `SystemTick` (type): type SystemTick = | { type: "fixed"; /** Steps per game-second. Default 60. */ rate?: number; stage?: string; after?: string | readonly string[]; before?: string | readonly string[]; } | { type: "frame"; stage?: string; after?: string | readonly string[]; before?: string | readonly string[]; } | { t… — How a system is scheduled. Omit `tick` (or use only `events`) for event-driven systems. Multiple systems may share the same channel; order within a channel is deterministic by stage then optional `before`/`after` constraints — never import order.
- `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.

## @jgengine/core/game/dialogue

- `DIALOGUE_STORE_KEY` (const): const DIALOGUE_STORE_KEY: "jg.dialogue" — Store slot holding the id of the dialogue currently open, or absent when none is showing.
- `GameDialogue` (interface): interface GameDialogue — `ctx.game.dialogue` — the blessed open/close bridge for the `talkable`/`dialogue.open` prompt flow. A game opts in with `features.dialogue`, and the runtime both builds this surface and auto-registers the `dialogue.open`/`dialogue.close` commands a `talkable(id)` prompt dispatches, so no game re-implements the store, the command pair, or the open/close bookkeeping. React reads the open id via `useOpenDialogueId`.
- `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.
- `dialogueSlot` (const): const dialogueSlot: StoreHandle<string | undefined> — Typed handle onto the open-dialogue slot — React reads it via `useOpenDialogueId`; game code uses `ctx.game.dialogue`.

## @jgengine/core/game/dialogueGraph

- `DialogueGraph` (interface): interface DialogueGraph — A serializable branching conversation: a start node id and the nodes it can reach.
- `DialogueGraphChoice` (interface): interface DialogueGraphChoice — One selectable response on a conversation node — the text a player clicks and the node it advances to. `kind` is a free style tag the presenter interprets; the model never reads it (no genre baked in).
- `DialogueGraphIssue` (interface): interface DialogueGraphIssue — A structural authoring issue, located in the original graph's node/choice arrays.
- `DialogueGraphNode` (interface): interface DialogueGraphNode — One conversation node: who is speaking, the line they say, and the branches out of it. `speaker`/`speakerKind`/`portrait` are opaque display data — the model never interprets them.
- `DialogueGraphSnapshot` (interface): interface DialogueGraphSnapshot — Serializable run state — the current node id and the ids already visited.
- `DialogueGraphView` (interface): interface DialogueGraphView — The render-ready snapshot of a conversation at one node — everything a view needs to draw speaker, line, and choice buttons, with no traversal logic in the component.
- `DialogueRun` (interface): interface DialogueRun — An observable walk through a {@link DialogueGraph}: current view, choose to advance, serialize.
- `DialogueRunOptions` (interface): interface DialogueRunOptions — Options for {@link createDialogueRun}.
- `createDialogueRun` (function): function createDialogueRun(graph: DialogueGraph, options: DialogueRunOptions = {}): DialogueRun — Walk a branching {@link DialogueGraph}: hold the current node, expose its render-ready view, and advance by choosing one of the current node's responses (each choice names the node it leads to; a choice with no `to` ends the conversation). Purely a serializable model — a React host renders `current()` and calls `choose(index)` — so no game re-implements node lookup, choice-to-node traversal, or "am I at the end" bookkeeping. `snapshot`/`restore` round-trip the run through a save.
- `selectDialogueView` (function): function selectDialogueView(graph: DialogueGraph, nodeId: string): DialogueGraphView | null — Project a {@link DialogueGraph} node id to its render-ready {@link DialogueGraphView} — the pure "current view" selector a stateless renderer reads (speaker, line, choices, done). Returns `null` when the id is not in the graph. No traversal or mutation.
- `validateDialogueGraph` (function): function validateDialogueGraph(graph: DialogueGraph): DialogueGraphIssue[] — Check authored dialogue references, reachability, and routes to an ending in O(nodes + choices). A node without choices, or a choice with no target, is an ending. Loops with an exit are valid. Duplicate ids and missing references are errors; unreachable nodes and closed loops are warnings because games may jump to nodes or intentionally keep conversations open. Topology uses the first node for each id, matching {@link selectDialogueView}. This does not evaluate story semantics.

## @jgengine/core/game/eventTicker

- `EventTicker` (interface): interface EventTicker — A live, observable event/kill-feed ticker.
- `EventTickerEntry` (interface): interface EventTickerEntry extends TimedFeedEntry — A stored ticker entry — an {@link EventTickerInput} stamped with an id and clock time.
- `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", …).
- `EventTickerOptions` (interface): interface EventTickerOptions — Options for {@link createEventTicker}.
- `EventTickerSnapshot` (interface): interface EventTickerSnapshot — Serializable state of the ticker, for save/restore.
- `EventTickerView` (interface): interface EventTickerView extends EventTickerEntry — A live ticker entry as handed to the renderer: the stored entry plus a `fade` value `0..1` (age / `ttlMs`) — `0` for a fresh entry, approaching `1` as it nears expiry — so the UI can drop opacity as an entry ages out. `fade` is always `0` when no `ttlMs` is configured.
- `createEventTicker` (function): function createEventTicker(config: EventTickerOptions = {}): EventTicker — A thin, serializable, observable event/kill-feed ticker over the flat {@link appendFeed} / {@link pruneFeed} feed helpers: a single rolling, count-capped, time-fading list of free-string entries. A game calls `push({ kind, text, icon? })` and the ticker stamps and caps it; `recent()` prunes expired entries and returns the live list newest-first, each with a `fade` `0..1` (age / `ttlMs`) for the renderer to drop opacity as entries age out. Nothing here is genre-specific: `kind`, `text`, and `icon` are free strings the game owns and styles, and the model never interprets them. `snapshot`/`restore` round-trips the buffer through a save, re-anchoring ages so fades resume correctly.

## @jgengine/core/game/events

- `AnimationClipEvent` (interface): interface AnimationClipEvent — A named clip moment (`AnimGraph.events`) the rig just crossed — foot plant, hit frame, reload point. Audio and combat listen by `name`.
- `AudioLoopSetEvent` (interface): interface AudioLoopSetEvent — Live-update the retained loop `id`: `rate` re-pitches it (1 = authored, the shell clamps to 0.25–4), `gain` rescales its volume (0–1), and `at` repositions its emitter. Emitted every tick to track a live signal (RPM, tire slip); the shell smooths rate/gain and ignores an unknown `id` (#1051).
- `AudioLoopStartEvent` (interface): interface AudioLoopStartEvent — Start (or idempotently keep) the retained, id-keyed audio loop `id` from catalog `sound`, optionally anchored at world `at`. Restarting with the same `sound` does not restart the source (no click); a different `sound` replaces it. Drives RPM-pitched engine loops and slip-scaled tire squeal (#1051).
- `AudioLoopStopEvent` (interface): interface AudioLoopStopEvent — Stop and dispose the retained loop `id`; an unknown `id` is ignored (#1051).
- `AudioMusicEvent` (interface): interface AudioMusicEvent — Crossfade the procedural soundtrack to `theme` (null fades out), optionally transposing the incoming theme by `transpose` semitones.
- `AudioPlayEvent` (interface): interface AudioPlayEvent { sound: string; at?: readonly [number, number, number] } — ⚠ undocumented
- `AudioResumeEvent` (type): type AudioResumeEvent = Record<string, never> — Request that the shell's audio engine resume its (browser-gesture-suspended) context; carries no payload.
- `ChatMessageEvent` (interface): interface ChatMessageEvent { id: string; channelId: string; fromUserId: string; body: string; at: number; recipients?: readonly string[] } — ⚠ undocumented
- `CombatHitReactionEvent` (interface): interface CombatHitReactionEvent { instanceId?: string; position: [number, number, number]; hitstopMs: number; shake?: CameraShake; trauma?: number } — ⚠ undocumented
- `CombatTelegraphCancelledEvent` (interface): interface CombatTelegraphCancelledEvent { id: number } — ⚠ undocumented
- `CombatTelegraphEvent` (interface): interface CombatTelegraphEvent { id: number; shape: TelegraphShape; position: [number, number, number]; dir?: number; windupMs: number; kind: string } — ⚠ undocumented
- `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).
- `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.
- `CosmeticsChangedEvent` (interface): interface CosmeticsChangedEvent { userId: string; slots: Record<string, string> } — ⚠ undocumented
- `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.
- `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.
- `EmotePlayedEvent` (interface): interface EmotePlayedEvent { from: string; emoteId: string; at: readonly [number, number, number]; recipients: readonly string[] } — ⚠ undocumented
- `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.
- `EntityDiedEvent` (interface): interface EntityDiedEvent { instanceId: string; catalogId: string; userId?: string; displayName?: string; reason: DeathReason; source?: string; position: [number, number, number]; serverId?: string } — ⚠ undocumented
- `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
- `FeedbackCueEvent` (interface): interface FeedbackCueEvent — A gameplay moment the game announces itself, for the moments no engine event covers (a wave starting, a scripted beat). The shell reacts with the cue's sound, rumble, camera kick and caption.
- `FormChangedEvent` (interface): interface FormChangedEvent { instanceId: string; formId: string | null } — ⚠ undocumented
- `GameEventHandler` (type): type GameEventHandler<TPayload> = (payload: TPayload) => void — ⚠ undocumented
- `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.
- `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.
- `InventoryAddedEvent` (interface): interface InventoryAddedEvent { userId: string; item: string; count: number; source?: string } — ⚠ undocumented
- `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.
- `LootGrantedEvent` (interface): interface LootGrantedEvent { userId: string; drops: LootDrop[]; source?: string } — ⚠ undocumented
- `PossessionSwappedEvent` (interface): interface PossessionSwappedEvent { userId: string; entityId: string; previousEntityId: string } — ⚠ undocumented
- `ProjectileSettledEvent` (interface): interface ProjectileSettledEvent — Exactly-once projectile result for shot-specific game policy and presentation.
- `QuestAcceptedEvent` (interface): interface QuestAcceptedEvent { userId: string; questId: string } — ⚠ undocumented
- `QuestCompletedEvent` (interface): interface QuestCompletedEvent { userId: string; questId: string } — ⚠ undocumented
- `QuestUpdatedEvent` (interface): interface QuestUpdatedEvent { userId: string; questId: string; objectiveId?: string; progress?: number } — ⚠ undocumented
- `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.
- `SocialFriendAddedEvent` (interface): interface SocialFriendAddedEvent { userId: string; friendUserId: string } — ⚠ undocumented
- `SocialPartyJoinedEvent` (interface): interface SocialPartyJoinedEvent { userId: string; partyId: string } — ⚠ undocumented
- `SocialPartyLeftEvent` (interface): interface SocialPartyLeftEvent { userId: string; partyId: string } — ⚠ undocumented
- `SocialWorldAcceptedEvent` (interface): interface SocialWorldAcceptedEvent { inviteId: string; userId: string; fromUserId: string; serverId: string; joinCode?: string } — ⚠ undocumented
- `SocialWorldInvitedEvent` (interface): interface SocialWorldInvitedEvent { inviteId: string; fromUserId: string; toUserId: string; serverId: string; joinCode?: string } — ⚠ undocumented
- `StatLevelUpEvent` (interface): interface StatLevelUpEvent { userId: string; stat: string; level: number } — ⚠ undocumented
- `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.
- `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.
- `WorldItemDroppedEvent` (interface): interface WorldItemDroppedEvent { instanceId: string; itemId: string; rarity: string; count: number; position: [number, number, number]; source?: string } — ⚠ undocumented
- `WorldItemPickedUpEvent` (interface): interface WorldItemPickedUpEvent { instanceId: string; userId: string; itemId: string; rarity: string; count: number } — ⚠ undocumented
- `createGameEvents` (function): function createGameEvents<TMap extends GameEventMap = GameEventMap>(): GameEvents<TMap> — A typed publish/subscribe bus for gameplay events that systems and HUDs subscribe to.
- `lootDropsOf` (function): function lootDropsOf(data: unknown): readonly LootDrop[] — Read the drops out of a `loot.granted` payload that arrived as `unknown` — a `FeedEntry.data`, a replicated event, a persisted log row. Returns `[]` for anything that is not shaped like a loot grant, so a renderer never has to guard the payload itself: `entry.data as { drops?: ... }` is the cast four separate call sites were writing, and the one that omitted the `| undefined` would have thrown on a payload-less entry.

## @jgengine/core/game/feed

- `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…
- `FeedWindow` (interface): interface FeedWindow — Bounds for {@link appendFeed} / {@link pruneFeed}: newest-`limit` cap and/or `ttl` age window.
- `GameFeed` (interface): interface GameFeed { bind<TName extends keyof GameEventMap>(action: TName, events: GameEvents): () => void; push(action: string, entry: unknown): void; recent(action: string, options?: {limit?: number}): FeedEntry[]; subscribe(action: string, listener: (entry… — ⚠ undocumented · used by `createGameFeed`: A rolling per-action feed of recent gameplay events, bindable to the event bus — the HUD ticker and killfeed history.
- `GameFeedOptions` (interface): interface GameFeedOptions { limit?: number } — ⚠ undocumented · used by `createGameFeed`: A rolling per-action feed of recent gameplay events, bindable to the event bus — the HUD ticker and killfeed history.
- `TimedFeedEntry` (interface): interface TimedFeedEntry — Any feed entry carrying a game-time (or wall-clock) `at` stamp for age-based pruning.
- `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.
- `appendFeedEntry` (function): function appendFeedEntry<T>(buffer: readonly FeedEntry<T>[], entry: FeedEntry<T>, limit: number): FeedEntry<T>[] — ⚠ undocumented
- `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.
- `pruneFeed` (function): function pruneFeed<T extends TimedFeedEntry>(list: readonly T[], now: number, ttl: number): T[] — Drop feed entries older than `ttl` game-seconds before `now`. Returns the same array reference when nothing expired, so equality checks skip a redundant state write. The tick-time counterpart to {@link appendFeed}'s age bound.
- `recentFeedEntries` (function): function recentFeedEntries<T>(buffer: readonly FeedEntry<T>[], limit?: number): FeedEntry<T>[] — ⚠ undocumented

## @jgengine/core/game/gamePhase

- `GAME_PHASE_STORE_KEY` (const): const GAME_PHASE_STORE_KEY: "jg.phase" — ⚠ undocumented
- `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.
- `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.
- `isPlaying` (function): function isPlaying(ctx: GameContext): boolean — ⚠ undocumented
- `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.

## @jgengine/core/game/gameSave

- `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.
- `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.
- `GameSaveConfig` (interface): interface GameSaveConfig — How a {@link createGameSave} is wired. Storage is the narrow injected {@link SaveBackend}, never `localStorage` welded in.
- `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>]`.
- `GameSaveRng` (interface): interface GameSaveRng — The world's shared injected RNG: its `seed` and the live `stream` whose cursor is persisted.
- `GameSaveRngState` (interface): interface GameSaveRngState — The persisted cursor of the world's shared injected RNG, plus the seed that produced it.
- `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.
- `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.
- `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.

## @jgengine/core/game/keyValueStore

- `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.
- `KeyValueStorageErrorPolicy` (interface): interface KeyValueStorageErrorPolicy — Fallback keeps session state after a failed operation; throw exposes failure and preserves the previous cell value. Observers must not throw.
- `KeyValueStorageFailure` (interface): interface KeyValueStorageFailure — A failed storage operation, retaining the backend's original error and affected key.
- `KeyValueStore` (interface): interface KeyValueStore<T> — A single persisted, mutable cell: read the current value, overwrite it, or read-modify-write with {@link KeyValueStore.update}. Unlike a record book it has no monotonic guard — the value goes wherever you set it.
- `KeyValueStoreConfig` (interface): interface KeyValueStoreConfig<T> extends KeyValueStorageErrorPolicy — Config for {@link createKeyValueStore}: the storage `key`, the `initial` value used before anything is saved, an optional `storage` backend (defaults to `localStorage`, pass `null` for memory-only), and optional custom `serialize`/`deserialize` (default JSON).
- `createKeyValueStore` (function): function createKeyValueStore<T>(config: KeyValueStoreConfig<T>): KeyValueStore<T> — A mutable local save cell through {@link KeyValueStorage}. Default fallback keeps session state on failure; `errorMode: "throw"` exposes failed reads/writes/removals through the original error. `storage: null` deliberately uses memory only.
- `defaultKeyValueStorage` (function): function defaultKeyValueStorage(onError?: (error: unknown) => void): KeyValueStorage | null — The ambient `localStorage` when available, otherwise `null`. An optional observer receives denied getter errors; it may rethrow to reject fallback. Never references the DOM `Storage` type, so it is safe in core.

## @jgengine/core/game/leaderboard

- `IncrementResult` (type): type IncrementResult = { status: "ok"; value: number } | { status: "rejected"; reason: "not-tracked" } — ⚠ undocumented
- `Leaderboard` (interface): interface Leaderboard { track(def: LeaderboardTrackDef): void; tracked(): {stat: string; scope: LeaderboardScope}[]; increment(userId: string, stat: string, options: {scope: LeaderboardScope; serverId?: string; by?: number}): IncrementResult; getTop(stat: string… — ⚠ undocumented · used by `createLeaderboard`: Ranked score tracking across global, server, and per-profile scopes, with top-N queries and per-profile lookups.
- `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.
- `LeaderboardScope` (type): type LeaderboardScope = "global" | "server" | "profile" — ⚠ undocumented
- `LeaderboardTrackDef` (interface): interface LeaderboardTrackDef { stat?: string; currency?: string; scope: LeaderboardScope } — ⚠ undocumented
- `createLeaderboard` (function): function createLeaderboard(sink?: { onIncrement?(row: LeaderboardRow): void }): Leaderboard — Ranked score tracking across global, server, and per-profile scopes, with top-N queries and per-profile lookups.

## @jgengine/core/game/leaderboardRank

- `RankLeaderboardOptions` (interface): interface RankLeaderboardOptions — Options for {@link rankLeaderboard}. All optional.
- `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.
- `RankedEntry` (interface): interface RankedEntry — One render-ready row of the ranked table produced by {@link rankLeaderboard}.
- `TieMode` (type): type TieMode = "standard" | "dense" — How equal scores share ranks: - `"standard"` (competition ranking): ties share a rank and the next distinct score skips ahead — `1, 2, 2, 4`. - `"dense"`: ties share a rank and the next distinct score is the very next integer — `1, 2, 2, 3`.
- `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}.
- `rankLeaderboard` (function): function rankLeaderboard(rows: readonly RankableRow[], options: RankLeaderboardOptions = {}): RankedEntry[] — Turn raw leaderboard rows into a render-ready ranked table. Pure and allocation-bounded: it sorts a copy by `value` (descending by default), assigns 1-based ranks with correct tie handling (`"standard"` → `1, 2, 2, 4`; `"dense"` → `1, 2, 2, 3`), flags rows that share a score (`isTie`), marks the local player (`isLocal`, via `highlightUserId`), and finally applies `limit`. Sorting is stable, so rows with equal scores keep their input order. Nothing here styles or branches on game meaning — pair it with {@link medalFor} and a game-owned theme to render a reskinnable scoreboard. Accepts a {@link LeaderboardRow}`[]` straight from `leaderboard.snapshot()`/`getTop()` since those satisfy {@link RankableRow}.

## @jgengine/core/game/levelSequence

- `CurrentLevel` (interface): interface CurrentLevel<TLevelConfig> { id: string; index: number; config: TLevelConfig; attempt: number } — ⚠ undocumented
- `LevelDescriptor` (interface): interface LevelDescriptor<TLevelConfig> { id: string; config: TLevelConfig } — ⚠ undocumented
- `LevelRecord` (interface): interface LevelRecord — Persisted per-level outcome: whether it has ever been cleared and the best star rating achieved.
- `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…
- `LevelSequenceConfig` (interface): interface LevelSequenceConfig<TLevelConfig> { levels: readonly LevelDescriptor<TLevelConfig>[]; retriesPerLevel?: number; key?: string; storage?: KeyValueStorage | null } — ⚠ undocumented · used by `createLevelSequence`: A pure, deterministic level campaign: an ordered list of levels, each with its own opaque config, played through a `start` → (`clear` → `adv…
- `LevelSequenceProgress` (interface): interface LevelSequenceProgress { index: number; total: number; cleared: readonly string[] } — ⚠ undocumented
- `LevelSequenceStatus` (type): type LevelSequenceStatus = "idle" | "playing" | "cleared" | "failed" | "complete" — ⚠ undocumented
- `LevelStars` (type): type LevelStars = 0 | 1 | 2 | 3 — A level's star rating, 0 (cleared, no stars) to 3.
- `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.

## @jgengine/core/game/loadout

- `LoadoutDef` (interface): interface LoadoutDef { inventories?: Record<string, LoadoutItemEntry[]>; stats?: Record<string, {current: number; max?: number; min?: number}>; economy?: Record<string, number>; unlocks?: string[] } — ⚠ undocumented
- `LoadoutDeps` (interface): interface LoadoutDeps { inventory: {begin(userId: string): LoadoutInventoryTransaction}; stats: {seed(userId: string, statId: string, pool: {current: number; max?: number; min?: number}): void}; economy: {grant(userId: string, currencyId: string, amount: number)… — ⚠ undocumented · used by `createLoadouts`: Save, name, and swap equipment loadouts.
- `LoadoutInventoryTransaction` (interface): interface LoadoutInventoryTransaction { put(inventoryId: string, itemId: string, count: number, slot?: number): {reason: string} | null; commit(): void } — ⚠ undocumented
- `LoadoutItemEntry` (interface): interface LoadoutItemEntry { item: string; count: number; slot?: number } — ⚠ undocumented
- `Loadouts` (interface): interface Loadouts { register(defs: Record<string, LoadoutDef>): void; has(loadoutId: string): boolean; applyLoadout(userId: string, loadoutId: string): {reason: string} | null } — ⚠ undocumented · used by `createLoadouts`: Save, name, and swap equipment loadouts.
- `createLoadouts` (function): function createLoadouts(deps: LoadoutDeps): Loadouts — Save, name, and swap equipment loadouts.

## @jgengine/core/game/lootFilter

- `LootFilterCondition` (interface): interface LootFilterCondition { rarity?: string | readonly string[]; baseType?: string | readonly string[]; minAffixTier?: number; maxAffixTier?: number } — ⚠ undocumented
- `LootFilterItem` (interface): interface LootFilterItem { rarity: string; baseType: string; affixTier?: number } — ⚠ undocumented · used by `evaluateLootFilter`: First matching rule wins (PoE/Last Epoch block semantics) — later rules never override an earlier match.
- `LootFilterOverride` (interface): interface LootFilterOverride { hidden?: boolean; color?: string; beam?: boolean; label?: string } — ⚠ undocumented · used by `evaluateLootFilter`: First matching rule wins (PoE/Last Epoch block semantics) — later rules never override an earlier match.
- `LootFilterRule` (interface): interface LootFilterRule { id: string; when: LootFilterCondition; hide?: boolean; color?: string; beam?: boolean; label?: string } — ⚠ undocumented · used by `evaluateLootFilter`: First matching rule wins (PoE/Last Epoch block semantics) — later rules never override an earlier match.
- `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.
- `lootFilter` (function): function lootFilter(rules: readonly LootFilterRule[]): readonly LootFilterRule[] — Validating factory — rule ids must be unique so authoring mistakes fail loudly.

## @jgengine/core/game/lootModifiers

- `TimeScaledRarityOptions` (interface): interface TimeScaledRarityOptions — Caller-authored weighting curve; item ids, quality tiers and balance never live in the modifier.
- `timeScaledRarity` (function): function timeScaledRarity<TCtx extends { elapsedMs: number }>(options: TimeScaledRarityOptions): LootModifier<TCtx> — Multiply weighted odds (or independent chances, clamped to one) by a caller-authored elapsed-time curve. Keeps source tables unchanged and uses the existing pipeline's modifier provenance. Elapsed time and multipliers must be finite and nonnegative; invalid curves reject the roll.

## @jgengine/core/game/lootPipeline

- `LootDropProvenance` (interface): interface LootDropProvenance — Why one drop is in the result: the stage/table/entry that produced it, its weights, and the modifiers that shaped it.
- `LootModifier` (interface): interface LootModifier<TCtx = unknown> — A registered, id-tagged loot policy applied to one stage. `plan` transforms eligibility, weights, and roll counts before rolling (luck, difficulty, gating); `drops` post-processes the rolled drops (quantity multipliers, dedupe, caps). Neither hook mutates table definitions, and the id is recorded in provenance so a resolved drop can be traced back to the policies that shaped it.
- `LootPipeline` (interface): interface LootPipeline<TCtx = unknown> — A resolved, reusable loot pipeline. Call {@link LootPipeline.resolve} with a per-drop context and RNG.
- `LootPipelineDef` (interface): interface LootPipelineDef<TCtx = unknown> — A named, ordered loot-resolution pipeline: the stages to run plus result-shaping policy (duplicate stacking, a total drop cap). Serializable except for its stage gate/modifier functions, mirroring how {@link LootTableDef} entries may carry a `generate` function.
- `LootPipelineDeps` (interface): interface LootPipelineDeps — Dependencies a pipeline needs at build time — chiefly how to turn a table id into its definition.
- `LootPlanEntry` (interface): interface LootPlanEntry — One eligible entry inside a {@link LootRollPlan}: the original table entry plus its live eligibility and effective weight/chance. Modifiers rewrite these fields; the source `entry` object is never mutated, so table definitions stay shared and reusable.
- `LootResolution` (interface): interface LootResolution — The fully serializable outcome of a resolution: the drops, their provenance, per-stage traces, and the replay seed.
- `LootResolveContext` (interface): interface LootResolveContext<TCtx = unknown> — The caller-owned context, injected RNG, and optional seed threaded through a single resolution.
- `LootRollPlan` (interface): interface LootRollPlan — The mutable roll plan a stage derives from its table before rolling. Modifiers transform this — gating entries, reweighting them, or changing the roll count — instead of touching table defs.
- `LootStage` (interface): interface LootStage<TCtx = unknown> — One ordered step in a {@link LootPipelineDef}: a source pool (a table id or inline table), an optional context gate, a fold mode, and the modifiers that reshape its roll. Stages compose the genre concepts — world pool, dedicated pool, luck, pity — without any of them living in core.
- `LootStageKind` (type): type LootStageKind = "contribute" | "fallback" | "replace" — How a stage folds its rolled drops into the accumulating result: `"contribute"` appends, `"fallback"` rolls only when nothing has dropped yet, `"replace"` discards prior drops and overrides with its own (quest/boss overrides).
- `LootStageStatus` (type): type LootStageStatus = "rolled" | "skipped" | "empty" | "replaced" | "fell-through" — The disposition of a stage after resolution — did it roll, get gated, fall through, override, or find nothing.
- `LootStageTrace` (interface): interface LootStageTrace — Per-stage record of what happened during resolution, for debugging and replay auditing.
- `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.
- `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}.

## @jgengine/core/game/lootTable

- `Drop` (interface): interface Drop — A resolved loot outcome — one item or currency grant with its rolled count.
- `LootEntry` (interface): interface LootEntry — One possible drop in a {@link LootTableDef} — an item, currency, or generated item, its count range, and its odds.
- `LootRegistry` (interface): interface LootRegistry { register(def: LootTableDef): void; has(id: string): boolean; roll(id: string, rng?: () => number): Drop[]; snapshot(): LootTableDef[]; restore(next: readonly LootTableDef[]): void } — ⚠ undocumented · used by `createLootRegistry`: Register named loot tables and roll weighted randomized drops from them.
- `LootRegistryOptions` (interface): interface LootRegistryOptions — Options for {@link createLootRegistry} — inject a default RNG so bare `roll(id)` uses the world stream.
- `LootTableDef` (interface): interface LootTableDef — A named, validated loot table — its roll count, weighted-vs-independent mode, and candidate entries.
- `createLootRegistry` (function): function createLootRegistry(options: LootRegistryOptions = {}): LootRegistry — Register named loot tables and roll weighted randomized drops from them.
- `grantDrops` (function): function grantDrops(drops: Drop[], appliers: { putItem: (itemId: string, count: number) => unknown; grantCurrency: (currencyId: string, amount: number) => unknown; }): void — ⚠ undocumented
- `lootTable` (function): function lootTable(def: LootTableDef): LootTableDef — Validates a loot table definition and returns it unchanged, for use with {@link createLootRegistry}.

## @jgengine/core/game/modelAnimation

- `AUTO_ONE_SHOT_EVENTS` (const): const AUTO_ONE_SHOT_EVENTS: readonly ["hit", "death"] — The two one-shot events the shell fires automatically for an entity, from `combat.hitReaction` and `entity.died`.
- `resolveOneShotClip` (function): function resolveOneShotClip(oneShots: Record<string, string | readonly string[]> | undefined, event: string, roll: number): string | null — Resolves the clip name a one-shot `event` should play from a model's `animation.oneShots` map, or `null` if the event isn't bound. A `string[]` binding picks a variant by `roll` (a value in `[0, 1)`), so combat can vary attack swings. Pure and deterministic given `roll` — the shell supplies the randomness.

## @jgengine/core/game/narrativeAuthoring

- `NarrativeBatch` (interface): interface NarrativeBatch — A candidate batch never changes canon; accepted new facts need a separately reviewed revision.
- `NarrativeBatchLimits` (interface): interface NarrativeBatchLimits — Caller budgets across the entire batch, including graph branches and explicit assertions.
- `NarrativeCanon` (interface): interface NarrativeCanon — Caller-reviewed facts for one authoring revision; event ids are in strict chronological order.
- `NarrativeClaim` (type): type NarrativeClaim = { readonly nodeId: string } & ( | { readonly kind: "character"; readonly characterId: string } | { readonly kind: "fact"; readonly factId: string; readonly value: string } | { readonly kind: "before"; readonly earlier: string; readonly later: string } ) — An explicit assertion attached to a dialogue node; dialogue prose is never parsed.
- `NarrativeDialogue` (interface): interface NarrativeDialogue — Authored dialogue with optional structured assertions against canon.
- `NarrativeIssue` (interface): interface NarrativeIssue — A repair diagnostic with a JSON-pointer location in the candidate batch.
- `freezeNarrativeCanon` (function): function freezeNarrativeCanon(canon: NarrativeCanon): NarrativeCanon — Detach and freeze reviewed canon before passing it to an asynchronous authoring callback. Duplicate character/event ids and an empty revision throw; facts retain exact caller values.
- `validateNarrativeBatch` (function): function validateNarrativeBatch(canon: NarrativeCanon, batch: NarrativeBatch, limits: NarrativeBatchLimits): NarrativeIssue[] — Check a typed candidate against caller budgets, canon revision, explicit claims and graph topology. Stops at the first exceeded budget before topology work; stale revisions also stop immediately. Claims check exact fact values and the declared strict event order, never prose, speaker labels, motivations, branch consequences or story quality. O(canon + bounded nodes + choices + claims). Validate/parse external JSON before calling; this is not an untrusted JSON decoder.

## @jgengine/core/game/notices

- `Notice` (interface): interface Notice — A live notice as the HUD renders it.
- `NoticeFeed` (interface): interface NoticeFeed — A capped, self-expiring, deduping notice list every game reaches through `ctx.game.notices`.
- `NoticeFeedConfig` (interface): interface NoticeFeedConfig — Tunables for {@link createNoticeFeed}; all retunable at runtime.
- `NoticeFeedState` (interface): interface NoticeFeedState — Plain JSON state of a {@link NoticeFeed}.
- `NoticeInput` (interface): interface NoticeInput — What a caller pushes: plain text, or text with a tone, a dedupe key and a lifetime.
- `NoticeTone` (type): type NoticeTone = "info" | "success" | "warn" | "deny" — How a notice reads: neutral info, a win, a caution, or a refused action.
- `RefusalNoticeOptions` (interface): interface RefusalNoticeOptions — Options for {@link attachRefusalNotices}.
- `attachRefusalNotices` (function): function attachRefusalNotices(events: Pick<GameEvents, "on">, notices: Pick<NoticeFeed, "push">, options: RefusalNoticeOptions = {}): () => void — Show every player-facing command refusal (`validate` returned `{ reason, message }`) as a deny notice. Refusals without a `message` stay silent: `reason` is a machine string. Returns the detach function.
- `createNoticeFeed` (function): function createNoticeFeed(config: NoticeFeedConfig & { now?: () => number } = {}): NoticeFeed — Player-facing notice feed: info/success/warn/deny messages with stacking dedupe and TTL. Pure state with an injected clock, so it runs headless; the shell renders it and plays a UI cue per push.

## @jgengine/core/game/notifications

- `NotificationCenterOptions` (interface): interface NotificationCenterOptions — Options for {@link createNotificationCenter}.
- `NotificationEntry` (interface): interface NotificationEntry<TMeta = unknown> — One persistent notification — unlike a transient toast, it stays in the log until dismissed.
- `NotificationFilter` (interface): interface NotificationFilter — Filter for {@link NotificationStore.list}.
- `NotificationInput` (interface): interface NotificationInput<TMeta = unknown> — Fields accepted by {@link NotificationStore.push}.
- `NotificationStore` (interface): interface NotificationStore<TMeta = unknown> — Serializable, observable log of persistent notifications with read tracking.
- `createNotificationCenter` (function): function createNotificationCenter<TMeta = unknown>(options: NotificationCenterOptions = {}): NotificationStore<TMeta> — A persistent notification log with read/unread tracking — the "notification center" surface toasts don't cover. Newest-first, capped, serializable, and observable; a game pushes durable events (quest updates, trades, party news) here and a HUD renders the list + an unread badge. `snapshot`/`restore` round-trip through a save.

## @jgengine/core/game/objectives

- `ObjectiveStatus` (interface): interface ObjectiveStatus — Evaluated state of one {@link ThresholdObjective} against a current metric value.
- `ObjectiveSummary` (interface): interface ObjectiveSummary — Rolled-up state across a set of objectives.
- `ThresholdDirection` (type): type ThresholdDirection = "atLeast" | "atMost" — Whether a metric must reach up to a target or stay down under it.
- `ThresholdObjective` (interface): interface ThresholdObjective — A live-metric goal: hit `target` from the required `direction` (defaults to `atLeast`).
- `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.
- `evaluateObjectives` (function): function evaluateObjectives(objectives: readonly ThresholdObjective[], values: Readonly<Record<string, number>> | ((id: string) => number)): ObjectiveSummary — Evaluate every objective against current metric values (a lookup map or function) and roll them up into a met-count, completion flag, and mean progress — the brief/charter panel every sim renders.

## @jgengine/core/game/paramLayers

- `LayerConflict` (interface): interface LayerConflict — A single conflict surfaced by {@link validateLayers}.
- `LayerOps` (type): type LayerOps = Readonly<Record<string, ParamOp | readonly ParamOp[]>> — Per-parameter ops contributed by one layer — a single op or an ordered list folded in sequence.
- `LayerRegistry` (interface): interface LayerRegistry — Registered lookup of {@link ParamLayer}s by stable id, resolving serialized selections and unknowns.
- `LayerSelection` (type): type LayerSelection = readonly string[] — A serializable, ordered reference to layers by stable id — what a save file or session setup stores.
- `ParamContribution` (interface): interface ParamContribution — One recorded fold step — which layer's op ran and the value before/after. Contribution provenance.
- `ParamDelta` (interface): interface ParamDelta — One parameter's change between two value maps, for preview/diff surfaces.
- `ParamLayer` (interface): interface ParamLayer — A named, serializable bundle of parameter transforms with a stable id and precedence. `label` is an optional display name that may intentionally differ from the applied ops (e.g. a tier shown as "Mayhem 4" whose real multipliers are data). Higher `priority` applies later — on top — and ties break by the layer's index in the active list, so ordering is deterministic.
- `ParamOp` (type): type ParamOp = | { readonly kind: "set"; readonly value: number } | { readonly kind: "add"; readonly value: number } | { readonly kind: "multiply"; readonly value: number } | { readonly kind: "clamp"; readonly min?: number; readonly max?: number } | { readonly kind: "curve"; readonly curve: Curve } — A single transform applied to one numeric parameter. `set` overrides, `add`/`multiply` accumulate, `clamp` bounds, and `curve` remaps the running value through a {@link Curve} (the same curve primitive progression tracks use), so a caller can reshape a value non-linearly mid-stack.
- `ParamSnapshot` (interface): interface ParamSnapshot — A resolved effective-parameter snapshot: final `values` plus the ordered op trace per parameter.
- `createLayerRegistry` (function): function createLayerRegistry(initial?: readonly ParamLayer[]): LayerRegistry — Create a {@link LayerRegistry} — the registration seam difficulty tiers, mutators, and presets install into. Duplicate ids throw at registration; unknown ids at resolve time are reported, not fatal, which is what keeps saved sessions reproducible across content/version drift.
- `diffParams` (function): function diffParams(before: Readonly<Record<string, number>>, after: Readonly<Record<string, number>>): readonly ParamDelta[] — Compute the per-parameter deltas between two value maps — the preview/diff of applying a change, for showing a player what a difficulty tier or mutator will do before they commit.
- `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.
- `resolveParams` (function): function resolveParams(base: Readonly<Record<string, number>>, layers: readonly ParamLayer[]): ParamSnapshot — Fold an ordered stack of layers over `base` and return the effective {@link ParamSnapshot}. Layers apply in {@link orderLayers} sequence; within a layer each parameter's ops fold left-to-right. Every op is recorded in `contributions` for provenance/preview. Parameters a layer introduces but `base` omits start from `0`. Pure and deterministic — no ambient randomness or time.
- `resolveSelection` (function): function resolveSelection(base: Readonly<Record<string, number>>, registry: LayerRegistry, ids: LayerSelection): { readonly snapshot: ParamSnapshot; readonly unknown: readonly string[] } — Reproducible session setup in one call: resolve a saved {@link LayerSelection} through a registry, fold the found layers over `base`, and return the snapshot alongside any unknown ids. The same base + registry + selection always yields the same snapshot.
- `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.

## @jgengine/core/game/partAnimation

- `PartMotionInput` (interface): interface PartMotionInput — Live signals a driver feeds the samplers each frame. All values are render-side only.
- `PartMotionParams` (interface): interface PartMotionParams — Tuning for {@link samplePartPose}/{@link sampleBodyPose}; every field has a sensible default.
- `PartPose` (interface): interface PartPose — Sampled offsets to add onto a part's authored transform (or the character root). `scale` is multiplicative (1 = unchanged).
- `PartRole` (type): type PartRole = "head" | "arm.l" | "arm.r" | "leg.l" | "leg.r" | "tail" | "wing.l" | "wing.r" — Procedural animation for part-composed (rig-less) models — characters kit-bashed from primitives/`ModelPart`s with no skeleton or clips. Pure, deterministic curve sampling: the same (time, speed, phase, flinch, death) input always yields the same pose, so replays and multi-client renders stay in lockstep and the hot path allocates nothing when an `out` pose is reused.
- `createPartPose` (function): function createPartPose(): PartPose — A reusable identity pose (zero offsets, unit scale).
- `partMotionPhase` (function): function partMotionPhase(id: string): number — Deterministic per-character stride phase in [0, 1) from an id (e.g. the entity instance id), so a crowd of identical part-composed characters doesn't animate in lockstep.
- `sampleBodyPose` (function): function sampleBodyPose(input: PartMotionInput, params?: PartMotionParams, out: PartPose = createPartPose()): PartPose — Sample the character-root pose: walk bob, idle breathe/sway, backward hit flinch, and death — a sideways topple by default, or a flatten-out splat with `deathStyle: "splat"`. With `squashAmp > 0` the body also squashes and stretches (footfall squash, jelly idle breathe, flinch squash pulse), volume-conserving. A driver applies this to the group wrapping the whole composition (base model plus parts) — limbs ride along, as they would on a real torso.
- `samplePartPose` (function): function samplePartPose(role: PartRole, input: PartMotionInput, params?: PartMotionParams, out: PartPose = createPartPose()): PartPose — Sample one part's pose offset by role: counter-phase leg/arm swing driven by speed, a head counter-sway, tail wag, and wing flap. Offsets are added onto the part's authored position/rotation. Motion fades to zero as `death` ramps so the topple reads as one piece.

## @jgengine/core/game/ping

- `DEFAULT_PING_CATEGORIES` (const): const DEFAULT_PING_CATEGORIES: Record<PingCategory, PingCategoryDef> — Content-agnostic default ping wheel: enemy / loot / location / danger.
- `PING_FEED_ACTION` (const): const PING_FEED_ACTION: "party.ping" — ⚠ undocumented
- `PingCategory` (type): type PingCategory = string — ⚠ undocumented · used by `DEFAULT_PING_CATEGORIES`: Content-agnostic default ping wheel: enemy / loot / location / danger.
- `PingCategoryDef` (interface): interface PingCategoryDef { id: PingCategory; markerKind: string; label: string; callout: string } — ⚠ undocumented · used by `DEFAULT_PING_CATEGORIES`: Content-agnostic default ping wheel: enemy / loot / location / danger.
- `PingClassifyDeps` (interface): interface PingClassifyDeps { roleOf?(entityId: string): string | null | undefined; categoryOf?(objectId: string): PingCategory | null | undefined } — ⚠ undocumented · used by `classifyPing`: Classify what a pointer/aim ray hit into a ping category.
- `PingClassifyOptions` (interface): interface PingClassifyOptions { hostileRoles?: readonly string[]; enemyCategory?: PingCategory; lootCategory?: PingCategory; locationCategory?: PingCategory; dangerCategory?: PingCategory } — ⚠ undocumented · used by `classifyPing`: Classify what a pointer/aim ray hit into a ping category.
- `PingFeedSink` (interface): interface PingFeedSink { push(action: string, entry: unknown): void } — ⚠ undocumented
- `PingParty` (interface): interface PingParty { membersOf(userId: string): string[] } — ⚠ undocumented
- `PingPayload` (interface): interface PingPayload { id: string; from: string; category: PingCategory; position: MarkerPosition; entityId: string | null; objectId: string | null; at: number; callout: string; recipients: readonly string[] } — ⚠ undocumented
- `PingSystem` (interface): interface PingSystem { classify(hit: PointerHit): PingCategory; buildPayload(from: string, hit: PointerHit, category?: PingCategory): PingPayload; broadcast(payload: PingPayload): MapMarker; ping(from: string, hit: PointerHit, category?: PingCategory): PingPayl… — ⚠ undocumented · used by `createPingSystem`: Contextual ping/marker communication between teammates, classified by what was pinged.
- `PingSystemDeps` (interface): interface PingSystemDeps { markers: MarkerSet; feed: PingFeedSink; party?: PingParty; categories?: Record<PingCategory, PingCategoryDef>; now?(): number; ttlMs?: number; feedAction?: string; classify?: PingClassifyDeps; classifyOptions?: PingClassifyOptions } — ⚠ undocumented · used by `createPingSystem`: Contextual ping/marker communication between teammates, classified by what was pinged.
- `classifyPing` (function): function classifyPing(hit: PointerHit, deps: PingClassifyDeps = {}, options: PingClassifyOptions = {}): PingCategory — Classify what a pointer/aim ray hit into a ping category. Entity hits resolve by catalog role (hostile → enemy, else location); object hits by an optional catalog category tag; open ground is a location ping.
- `createPingSystem` (function): function createPingSystem(deps: PingSystemDeps): PingSystem — Contextual ping/marker communication between teammates, classified by what was pinged.

## @jgengine/core/game/pixelPerfect

- `PixelPerfectFrustum` (interface): interface PixelPerfectFrustum — The orthographic bounds and scale derived from a pixel-perfect camera config.
- `PixelPerfectViewport` (interface): interface PixelPerfectViewport — Viewport dimensions in device-independent canvas pixels.
- `pixelPerfectFrustum` (function): function pixelPerfectFrustum(viewport: PixelPerfectViewport, pixelsPerUnit: number, integerScale = false): PixelPerfectFrustum — Computes an orthographic frustum whose world units map to the requested pixel density. Integer scaling chooses the largest whole-number density multiplier available in the viewport.
- `snapPixelPerfectPosition` (function): function snapPixelPerfectPosition<T extends { x: number; y: number; z: number }>(position: T, pixelsPerUnit: number): T — Snaps a camera position to the authored pixel grid without changing its orientation.

## @jgengine/core/game/playableGame

- `AmbientLightingConfig` (interface): interface AmbientLightingConfig { color?: string; intensity?: number } — ⚠ undocumented
- `BackdropConfig` (interface): interface BackdropConfig — Generic sky/background/fog for ANY world kind, including a custom `environment` component (#207.6).
- `BackdropFogConfig` (interface): interface BackdropFogConfig { color?: string; near?: number; far?: number; density?: number } — ⚠ undocumented
- `CAMERA_FRUSTUM_DEFAULTS` (const): const CAMERA_FRUSTUM_DEFAULTS: { readonly fov: 55; readonly near: 0.1; readonly far: 300; readonly zoom: 50; } — ⚠ undocumented
- `CameraFollowState` (interface): interface CameraFollowState { entityId: string; target: {x: number; y: number; z: number}; camera: {x: number; y: number; z: number}; distance: number } — ⚠ undocumented
- `CameraKeyframe` (interface): interface CameraKeyframe — One stop on a scripted camera path (#29).
- `CameraProjection` (type): type CameraProjection = "perspective" | "orthographic" — Canvas camera projection. "orthographic" renders a flat 2D-style view (side-scrollers, falling-block puzzles) — pair with `rig: "sideScroll"`; default "perspective".
- `CameraRigKind` (type): type CameraRigKind = | "orbit" | "first" | "topDown" | "rts" | "shoulder" | "lockOn" | "chase" | "observer" | "turntable" | "sideScroll" | "inspection" | "none" — Which camera rig the shell mounts. Every rig accepts `followEntityId: null` (avatar-less games — city-builders, card games, auto-battlers — still get a camera). Rigs are tuned through their config block below, never by writing camera positions from `onTick`. - `orbit` — third-person chase (the historical default; `perspective: "third"`). - `first` — pointer-lock mouse-look (`perspective: "first"`). - `topDown` — fixed height/pitch/yaw with decoupled follow (ARPG iso, top-down). - `rts` — free-pan / edge-scroll / rotate / zoom, optional follow. - `shoulder` — over-the-shoulder with ADS transition + shoulder swap. - `lockOn` — yaw bound to the player→target vector; move axis becomes strafe. - `chase` — speed-reactive vehicle chase (speed→FOV, spring arm, shake) + cockpit/hood/rear views. - `observer` — detached spectator/photo cam bound to any entity or fixed point; never reads player input. - `turntable` — slow auto-orbit of a fixed point: a rotating display stand for a scene. The friendly, flat spelling of `observer`'s point-orbit mode; providing `camera.turntable` selects it without an explicit `rig`. - `sideScroll` — fixed lateral follow (2.5D platformer/beat-'em-up side view); reads no player input. - `inspection` — model-viewer / editor rig (#207.7, #866): middle-drag pan, right-drag orbit, scroll zoom toward a configurable anchor; orbits a fixed point, reads no player/entity input. - `none` — no camera rig is mounted; use for HUD-only presentations or a game that manages its own camera.
- `CameraShakeConfig` (interface): interface CameraShakeConfig — Camera-shake / trauma defaults (#28). Any rig reads the trauma channel; game systems feed it via `cameraShake()`.
- `CameraWeaponView` (interface): interface CameraWeaponView — What a camera rig reads about the held weapon each frame; see `GameCameraConfig.weapon`.
- `ChaseCameraConfig` (interface): interface ChaseCameraConfig — Speed-reactive vehicle chase rig (#27) — speed→FOV, spring arm, procedural shake, interior views.
- `ChaseView` (type): type ChaseView = "chase" | "cockpit" | "hood" | "rear" — Fixed interior view for the chase rig (#27).
- `CinematicCameraConfig` (interface): interface CinematicCameraConfig — Scripted keyframe / path player (#29). When set it overrides the active rig.
- `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.
- `EntitySpriteConfig` (interface): interface EntitySpriteConfig { url: string; width: number; height: number; y: number; clip?: {atlas: SpriteAtlas; animation: string} } — ⚠ undocumented
- `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig { eyeHeight?: number; sensitivity?: number; maxPitch?: number; reticle?: boolean; viewmodel?: boolean; collision?: false | FirstPersonCollisionConfig } — ⚠ undocumented
- `FirstPersonCollisionConfig` (interface): interface FirstPersonCollisionConfig — Clearance tuning for the first-person camera's collision pull-in.
- `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`.
- `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.
- `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.
- `GameCaptureView` (interface): interface GameCaptureView — How a screenshot host reaches live gameplay in this game — the data behind `shoot --mode play`.
- `HemisphereLightingConfig` (interface): interface HemisphereLightingConfig { skyColor?: string; groundColor?: string; intensity?: number } — ⚠ undocumented
- `InspectionCameraConfig` (interface): interface InspectionCameraConfig — Model-viewer / inspection rig (#207.7) — orbit + pan + anchored zoom around a fixed point, never reads player input.
- `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.
- `LightingConfig` (interface): interface LightingConfig — Declarative lighting replacing the shell's hardcoded ambient/directional default (#207.5); mounts regardless of world kind, only when supplied.
- `LockOnCameraConfig` (interface): interface LockOnCameraConfig — Lock-on / strafe rig (#26) — yaw bound to player→target, move axis becomes strafe.
- `ModelAnimationConfig` (interface): interface ModelAnimationConfig — Rig playback for a `ModelConfig`'s GLTF animation clips — looping idles, one-shots, and held poses.
- `ModelAnimationStates` (interface): interface ModelAnimationStates — Movement-state clip set for `ModelAnimationConfig.states`: the shell reads the entity's live speed each frame and crossfades between these clips, so a walking mob animates without any game-side driver.
- `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.
- `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`).
- `ModelIkConfig` (interface): interface ModelIkConfig — Bone names and limits for {@link ModelConfig.ik}.
- `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.
- `ModelLookAtConfig` (interface): interface ModelLookAtConfig — {@link ModelIkConfig.lookAt}: the bone that turns, and what it turns toward.
- `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.
- `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.
- `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.
- `ModelRimLight` (interface): interface ModelRimLight — Fresnel rim-light term added on top of a model's lighting — see {@link ModelMaterialOverride.rim}.
- `ModelWindConfig` (interface): interface ModelWindConfig — Wind sway for a foliage model; see {@link ModelConfig.wind}.
- `MovementCommitFrame` (interface): interface MovementCommitFrame — One frame's movement resolution handed to `PlayerMovementConfig.beforeCommit`.
- `MovementFeelConfig` (interface): interface MovementFeelConfig — Feel knobs for the built-in walk controller; see {@link PlayerMovementConfig.feel}.
- `NoticePresentationConfig` (interface): interface NoticePresentationConfig extends NoticeFeedConfig — How the shell presents `ctx.game.notices`; every field is optional.
- `ObjectStyle` (interface): interface ObjectStyle { color?: string; opacity?: number; hidden?: boolean } — ⚠ undocumented
- `ObserverCameraConfig` (interface): interface ObserverCameraConfig — Detached spectator/photo cam (#120) — binds to any entity or fixed point, never reads player input.
- `PlayableGame` (interface): interface PlayableGame<TUi = unknown, TWorldOverlay = unknown, TRenderEntity = never, TRenderObject = never, TViewmodel = unknown, TOverlay = TWorldOverlay> { game: GameDefinition; content: GameContextContent; loop: Required<Omit<GameLoop<GameContext>, "onPlayerLeave">> & Pick<GameLoop<GameContext>, "onPlayerLeave">; GameUI: TUi; presentation?: "3d" | "hud"; WorldOverlay?: TOverlay; environment… — ⚠ undocumented · used by `defineGame` (@jgengine/shell/defineGame): The one public authoring entry point: compose engine fields (systems, world, physics, input) and presentation fields (camera, HUD, audio, au…
- `PlayerFovConfig` (interface): interface PlayerFovConfig — Player-facing FOV preference applied across every perspective camera rig. Orthographic projections ignore it.
- `PlayerMovementConfig` (interface): interface PlayerMovementConfig — Movement-control levers for the shell-driven local player walk controller.
- `PointLightingConfig` (interface): interface PointLightingConfig — A bounded dynamic point light in world space.
- `PointerConfig` (interface): interface PointerConfig — Mouse/touch pointer bindings for `defineGame({ pointer })`.
- `PresentationEffectsConfig` (interface): interface PresentationEffectsConfig — Per-channel combat presentation toggles for the 3D shell canvas. Missing keys default to enabled when the parent `presentationEffects` is an object.
- `RtsCameraConfig` (interface): interface RtsCameraConfig extends TopDownCameraConfig — Free-pan / edge-scroll RTS rig (#24) — pan/rotate/zoom independent of any avatar.
- `ShoulderCameraConfig` (interface): interface ShoulderCameraConfig — Over-the-shoulder combat rig (#25) — offset, ADS, shoulder swap, decoupled reticle.
- `SideScrollCameraConfig` (interface): interface SideScrollCameraConfig — Fixed lateral 2.5D follow (side-on platformer cam): the camera sits perpendicular to the travel axis, tracks the followed entity, and never reads player look input.
- `SpotLightingConfig` (interface): interface SpotLightingConfig extends PointLightingConfig — A bounded dynamic spot light in world space.
- `TopDownCameraConfig` (interface): interface TopDownCameraConfig — Fixed top-down / isometric rig (#23) — height/pitch/yaw + decoupled follow.
- `TurntableCameraConfig` (interface): interface TurntableCameraConfig — Turntable / showcase rig — slowly auto-orbits a fixed world point (no player input), the way a museum turntable rotates an object on display. A flat, self-describing spelling of `observer`'s point-orbit mode: `target` names the point directly instead of `bind: { kind: "point", position }`. Set `camera.turntable` and the rig is inferred — you don't also write `rig`.
- `VoxelCollisionConfig` (interface): interface VoxelCollisionConfig — Player-vs-world collision for the first-person controller. Without this the shell keeps the player on flat ground at y=0. With `voxel: true` the shell resolves the player as a box against placed scene objects (each treated as a solid unit cell), so they stand on blocks, fall into holes, and are stopped by walls — the controller a block-building/mining game needs.
- `WorldItemRenderConfig` (interface): interface WorldItemRenderConfig { rarityStyle?: Record<string, RarityStyle>; filter?: readonly LootFilterRule[]; pickupRadius?: number; beamHeight?: number; autoPickup?: boolean | {radius?: number} } — ⚠ undocumented · used by `WorldItems` (@jgengine/shell/world/WorldItems): Rarity→beam/color/label render binding + loot-filter overlay (#32/#33) for every dropped `worldItem`.
- `WorldOverlayProps` (interface): interface WorldOverlayProps — Props handed to a `WorldOverlay` component (#542): explicit `ctx` access so canvas-layer VFX read live engine state directly, without an extra hook or a module-global workaround.
- `worldHealthBarAllowsRole` (function): function worldHealthBarAllowsRole(roles: readonly CatalogEntityRole[] | undefined, role: CatalogEntityRole | undefined): boolean — ⚠ undocumented

## @jgengine/core/game/progression

- `Curve` (type): type Curve = CurveDef & CurveShape — A fully specified progression curve — a {@link CurveDef} growth shape plus optional {@link CurveShape} rounding/clamp.
- `CurveDef` (type): type CurveDef = | { kind: "const"; value: number } | { kind: "linear"; base: number; per: number } | { kind: "power"; base: number; exponent: number } | { kind: "geometric"; base: number; ratio: number } | { kind: "steps"; values: number[] } | { kind: "piecewise"; points: [number, number][] } — The shape of a progression curve before rounding/clamping: a constant, a linear ramp, a `power` or `geometric` growth, discrete `steps`, or a `piecewise` interpolation between explicit points. Feed it to {@link evalCurve}.
- `CurveShape` (interface): interface CurveShape — Post-evaluation adjustments applied to a curve's raw output: rounding mode and min/max clamp.
- `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.
- `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).
- `LevelingStatAccess` (interface): interface LevelingStatAccess — Adapter a {@link LevelingTrack} uses to read and write a user's level/xp stats, so the track stays decoupled from any concrete stats store.
- `LevelingTrack` (interface): interface LevelingTrack — A resolved leveling track: the immutable `maxLevel`/`startLevel`, the `xpForLevel` threshold lookup, a pure `resolve`, and `grantXp` which writes back through a {@link LevelingStatAccess} and fires `onLevelUp` once for every reached level in ascending order.
- `curve` (function): function curve(spec: Curve): (x: number) => number — Bind a {@link Curve} into a reusable `(x) => value` evaluator — a partial application of {@link evalCurve}.
- `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.
- `leveling` (function): function leveling(config: LevelingConfig): LevelingTrack — Build a leveling track from an xp-per-level {@link Curve} and a max level. The returned {@link LevelingTrack} resolves how many levels a given xp total earns (rolling over surplus xp, capping at `maxLevel`) and, via `grantXp`, writes the new level/xp back through a {@link LevelingStatAccess} and fires `onLevelUp` for each level gained in ascending order. Reach for this instead of hand-tracking xp thresholds; pair it with `resource-pool` (mana/stamina) and `ability-bar` (cooldowns) for a hero.

## @jgengine/core/game/quest

- `QuestAcceptOptions` (interface): interface QuestAcceptOptions { hasUnlock?(id: string): boolean } — ⚠ undocumented
- `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…
- `QuestEvaluator` (interface): interface QuestEvaluator { has(questId: string): boolean; get(questId: string): QuestDef | null; canAccept(state: readonly QuestSnapshotEntry[], questId: string, options?: QuestAcceptOptions): {reason: string} | null; accept(state: readonly QuestSnapshotEntry[], qu… — ⚠ undocumented
- `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…
- `QuestJournal` (interface): interface QuestJournal { register(catalog: readonly QuestDef[] | Record<string, QuestDef>): void; has(questId: string): boolean; canAccept(userId: string, questId: string): {reason: string} | null; accept(userId: string, questId: string): {reason: string} | null;… — ⚠ undocumented · used by `createQuestJournal`: Track accepted quests and their per-objective progress, granting rewards on completion.
- `QuestJournalDeps` (interface): interface QuestJournalDeps { events: GameEvents; rewards: {grantXp(userId: string, amount: number): void; grantEconomy(userId: string, currencyId: string, amount: number): void; grantItem(userId: string, inventoryId: string, itemId: string, count: number): {reason: s… — ⚠ undocumented · used by `createQuestJournal`: Track accepted quests and their per-objective progress, granting rewards on completion.
- `QuestObjective` (interface): interface QuestObjective { id: string; kind: "kill" | "collect" | string; target?: string; item?: string; count: number; partyShare?: {radius: number; credit: "all" | "tagger"} } — ⚠ undocumented · used by `defaultObjectiveLabel`: Default objective label: a readable "verb count noun" from a {@link QuestObjective}.
- `QuestObjectiveProgress` (interface): interface QuestObjectiveProgress { id: string; kind: string; count: number; progress: number; complete: boolean } — ⚠ undocumented
- `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`: Apply items before XP, currency, and unlocks.
- `QuestSnapshotEntry` (type): type QuestSnapshotEntry = { questId: string; status: QuestStatus; progress: Record<string, number>; } — ⚠ undocumented
- `QuestStatus` (type): type QuestStatus = "active" | "completed" — ⚠ undocumented
- `QuestTurnIn` (interface): interface QuestTurnIn { state: QuestSnapshotEntry[]; rewards: QuestRewards | null } — ⚠ undocumented
- `TrackedObjectiveView` (interface): interface TrackedObjectiveView — One objective as a tracker/HUD reads it — label + progress toward its count.
- `TrackedQuestView` (interface): interface TrackedQuestView — A quest as a tracker/HUD reads it — title, status, and per-objective progress.
- `applyQuestRewards` (function): function applyQuestRewards(rewards: QuestRewards, appliers: { grantXp?(amount: number): void; grantEconomy?(currencyId: string, amount: number): void; grantItem?(inventoryId: string, itemId: string, count: number): { reason: string } | null | void; /** Grant every item, or reject without writes. Tak… — Apply items before XP, currency, and unlocks. Multiple items require an all-or-reject `grantItems` callback; legacy single-item appliers remain supported. Rejected callbacks must make no writes. Arbitrary callback side effects or thrown exceptions cannot be rolled back by this helper.
- `createQuestEvaluator` (function): function createQuestEvaluator(defs: QuestDef[] | Record<string, QuestDef>): QuestEvaluator — ⚠ undocumented
- `createQuestJournal` (function): function createQuestJournal(deps: QuestJournalDeps): QuestJournal — Track accepted quests and their per-objective progress, granting rewards on completion.
- `defaultObjectiveLabel` (function): function defaultObjectiveLabel(objective: QuestObjective): string — Default objective label: a readable "verb count noun" from a {@link QuestObjective}.
- `describeTrackedQuest` (function): function describeTrackedQuest(def: QuestDef, instance: QuestInstance, label: (objective: QuestObjective) => string = defaultObjectiveLabel): TrackedQuestView — 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, status, labelled objective progress). Pass `label` to override the derived objective text.

## @jgengine/core/game/questCatalog

- `QuestCatalogDefinition` (type): type QuestCatalogDefinition = Omit<Readonly<QuestDef>, "requires" | "objectives" | "rewards"> & { requires?: readonly string[]; objectives: readonly Readonly<QuestObjective>[]; rewards?: Omit<Readonly<QuestRewards>, "items" | "unlocks" | "quests"> & { items?: readonly Readonly<NonNullable<QuestRewar… — Readonly authoring input; mutable QuestDef catalogs also satisfy this shape.
- `QuestCatalogIssue` (interface): interface QuestCatalogIssue — A located structural issue; path is a JSON Pointer into the supplied catalog.
- `QuestCatalogReferenceKind` (type): type QuestCatalogReferenceKind = "item" | "target" | "inventory" | "currency" — Caller-owned reference namespaces; objective kinds remain unconstrained.
- `QuestCatalogValidationOptions` (interface): interface QuestCatalogValidationOptions — Declarations and optional lookups for a game's own authoring rules.
- `validateQuestCatalog` (function): function validateQuestCatalog(catalog: readonly QuestCatalogDefinition[] | Readonly<Record<string, QuestCatalogDefinition>>, options: QuestCatalogValidationOptions = {}): QuestCatalogIssue[] — Validate catalog ids, references, quantities, and potential prerequisite progression without mutation. Requirements are completed quest ids OR unlock ids; all requirements of a quest must be met. Any eligible quest may be accepted directly. External unlocks and granted quest starts are possible entry points, not claims about their timing. Blocked progression/cycles are warnings: game systems can bypass prerequisites. Topology uses the last duplicate, matching journal registration. Traversal is iterative and linear in definitions, requirements, and their producer edges. Objective and item counts may be fractional or zero; negative/nonfinite counts are invalid. This assumes objectives can be completed and does not evaluate narrative, chronology, or balance.

## @jgengine/core/game/race

- `Checkpoint` (interface): interface Checkpoint { id: string; center: readonly [number, number, number]; half: readonly [number, number, number] } — ⚠ undocumented
- `LapTimer` (interface): interface LapTimer — Wall-clock lap timer complementing {@link RaceState}: feed it `tick(dt)` each frame and call `completeLap()` when the race emits a player `lap.completed` event. It accumulates the current lap, carries best/last, banks splits, and `penalize()` folds a time penalty into the running lap — the timing bookkeeping every racer reimplemented on top of the position-only race state.
- `LapTimerSnapshot` (interface): interface LapTimerSnapshot — Wall-clock lap timing: the current/last/best/total split-book every racing HUD reads.
- `PlacementOptions` (interface): interface PlacementOptions — Options for {@link racePlacements} / {@link placementOf} / {@link raceOutcomeOf}.
- `RaceCountdownOptions` (interface): interface RaceCountdownOptions — Options for {@link startRaceCountdown}.
- `RaceEvent` (type): type RaceEvent = | { type: "checkpoint.hit"; racerId: string; checkpoint: number; lap: number; time: number; /** Set when the hit is a fork-route checkpoint (`checkpoint` is then the fork's `afterIndex`). */ fork?: { forkId: string; routeId: string; index: number }; } | { type: "fork.taken"; racerId… — ⚠ undocumented
- `RaceFork` (interface): interface RaceFork — An alternate-route section (#286.3): after passing mainline checkpoint `afterIndex`, a racer commits to whichever route's first checkpoint they hit, runs its checkpoints in order, and rejoins at mainline `afterIndex + 1`. Every completed route contributes exactly one checkpoint of `progress` regardless of length, and each hit records a split — so route time accounting comes for free.
- `RaceForkRoute` (interface): interface RaceForkRoute { id: string; checkpoints: readonly Checkpoint[] } — ⚠ undocumented
- `RaceOutcome` (type): type RaceOutcome = "win" | "lose" — Whether a racer won or lost, derived from where they placed against the winning-places cutoff.
- `RacePhase` (type): type RacePhase = "idle" | "countdown" | "racing" | "finished" — The lifecycle every race runs through before, during, and after the clock: `idle` on the grid, `countdown` on the lights, `racing` once they go green, `finished` at the flag. A pure value driven by the transition functions below — it carries no track, racer, or lap data, so it composes with {@link RaceState} (position/laps) and {@link LapTimer} (wall-clock) rather than duplicating them.
- `RacePlacement` (interface): interface RacePlacement — A racer's finishing position (`place`, 1-based) in a finish order, and the {@link RaceOutcome} it earns.
- `RaceSessionState` (interface): interface RaceSessionState — Immutable lifecycle snapshot: the current {@link RacePhase} plus the two clocks it owns.
- `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.
- `RaceStateConfig` (interface): interface RaceStateConfig { track: RaceTrack; win?: RaceWinCondition } — ⚠ undocumented · used by `createRaceState`: A checkpoint race state machine — laps, forks, live standings, splits, and pluggable win conditions.
- `RaceTrack` (interface): interface RaceTrack { readonly checkpoints: readonly Checkpoint[]; readonly laps: number; readonly forks: readonly RaceFork[] } — ⚠ undocumented · used by `raceTrack`: A race track is an ordered ring of checkpoint trigger volumes plus a lap count.
- `RaceTrackConfig` (interface): interface RaceTrackConfig { checkpoints: readonly Checkpoint[]; laps?: number; forks?: readonly RaceFork[] } — ⚠ undocumented · used by `raceTrack`: A race track is an ordered ring of checkpoint trigger volumes plus a lap count.
- `RaceWinCondition` (type): type RaceWinCondition = (standings: readonly RacerProgress[], track: RaceTrack) => readonly string[] | null — ⚠ undocumented · used by `everyoneFinishes`: Every non-eliminated racer must finish.
- `RacerProgress` (interface): interface RacerProgress { racerId: string; lap: number; nextCheckpoint: number; lastCheckpoint: number; progress: number; position: number; finished: boolean; finishTime: number | null; eliminated: boolean; splits: readonly number[]; routesTaken: Readonly<Record<s… — ⚠ undocumented
- `createLapTimer` (function): function createLapTimer(): LapTimer — Create a {@link LapTimer} starting at lap 0 with no splits, best, or last time recorded.
- `createRaceState` (function): function createRaceState(config: RaceStateConfig): RaceState — A checkpoint race state machine — laps, forks, live standings, splits, and pluggable win conditions.
- `everyoneFinishes` (function): function everyoneFinishes(): RaceWinCondition — Every non-eliminated racer must finish.
- `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.
- `firstPastPost` (function): function firstPastPost(count = 1): RaceWinCondition — Race ends when `count` racers have crossed the finish; ranking is the current standings order.
- `idleRaceSession` (function): function idleRaceSession(): RaceSessionState — The pre-race session on the grid: `idle`, both clocks at zero. Call {@link startRaceCountdown} to light the lights, or hold here until the field is ready.
- `lapDurations` (function): function lapDurations(splits: readonly number[], gatesPerLap: number): number[] — Per-lap durations from a cumulative split book with `gatesPerLap` checkpoints per lap — each lap's time is its finish-gate split minus the previous lap's finish. Only complete laps are returned.
- `lastStanding` (function): function lastStanding(): RaceWinCondition — Destruction-derby last-man-standing: ends when at most one racer is left un-eliminated.
- `parDelta` (function): function parDelta(splits: readonly number[], reference: readonly number[]): number[] — Elementwise delta of a cumulative split book against a `reference` book (a personal best or par lap): positive means behind the reference at that checkpoint. Compared up to the shorter length — the `+0.3s` / `−1.2s` gap every racing HUD shows against its ghost.
- `placementOf` (function): function placementOf(finishOrder: readonly string[], racerId: string, options?: PlacementOptions): RacePlacement | null — One racer's {@link RacePlacement} within a finish order, or `null` if they never crossed the line.
- `raceOutcomeOf` (function): function raceOutcomeOf(finishOrder: readonly string[], racerId: string, options?: PlacementOptions): RaceOutcome — The win/lose verdict for one racer in a finish order — `ranking[0] === player ? "win" : "lose"`, the check every racing game hand-rolls, generalized to a `winningPlaces` cutoff. A racer absent from the order counts as a `lose`.
- `racePlacements` (function): function racePlacements(finishOrder: readonly string[], options?: PlacementOptions): readonly RacePlacement[] — Turn a finish-order ranking (index 0 = winner, e.g. the `ranking` of a `race.finished` event) into per-racer {@link RacePlacement}s — the `1st/2nd/3rd` + win/lose every results screen shows.
- `raceTrack` (function): function raceTrack(config: RaceTrackConfig): RaceTrack — A race track is an ordered ring of checkpoint trigger volumes plus a lap count. The final checkpoint is the lap/finish line: a racer completes a lap by passing all checkpoints in order and hitting the last one. `forks` splice alternate route segments between mainline checkpoints.
- `splitSegments` (function): function splitSegments(splits: readonly number[], start = 0): number[] — Per-segment durations from a cumulative split book (`splits[i]` = elapsed time at checkpoint `i`): `segments[i] = splits[i] − splits[i−1]`, the first measured from `start` (default 0). Turns the cumulative splits {@link RacerProgress} records into the individual leg times a results screen shows.
- `startRaceCountdown` (function): function startRaceCountdown(options?: RaceCountdownOptions): RaceSessionState — Drop the lights: return a fresh `countdown` session of `seconds` (default 3). A non-positive length skips straight to `racing` for a standing start with no countdown.
- `tickRaceSession` (function): function tickRaceSession(session: RaceSessionState, dt: number): RaceSessionState — Advance the session by `dt` seconds: bleed the countdown down and flip to `racing` when it reaches zero, or accumulate `elapsed` while `racing`. `idle` and `finished` are inert. Overshoot past the countdown is dropped rather than banked into `elapsed`, so the race clock always starts from zero.
- `topK` (function): function topK(k: number): RaceWinCondition — Round-cut (Fall Guys): the first `k` finishers qualify; race resolves the moment `k` cross.

## @jgengine/core/game/recordBook

- `RecordBook` (interface): interface RecordBook<K extends string> { best(): Readonly<Partial<Record<K, number>>>; bestOf(field: K): number | null; submit(run: Readonly<Partial<Record<K, number>>>): RecordSubmission<K>; clear(): void } — ⚠ undocumented · used by `createRecordBook`: A personal-best record book: named numeric fields each racing toward "lower" (times) or "higher" (scores, streaks), persisted through a stru…
- `RecordBookConfig` (interface): interface RecordBookConfig<K extends string> { readonly key: string; readonly fields: Readonly<Record<K, RecordDirection>>; readonly storage?: RecordStorage | null } — ⚠ undocumented · used by `createRecordBook`: A personal-best record book: named numeric fields each racing toward "lower" (times) or "higher" (scores, streaks), persisted through a stru…
- `RecordDirection` (type): type RecordDirection = "lower" | "higher" — ⚠ undocumented
- `RecordStorage` (type): type RecordStorage = KeyValueStorage — The structural storage backend a record book persists through — an alias of the shared {@link KeyValueStorage} seam (browser `localStorage`, a test stub, or `null`).
- `RecordSubmission` (interface): interface RecordSubmission<K extends string> { readonly improved: readonly K[]; readonly best: Readonly<Partial<Record<K, number>>> } — ⚠ undocumented
- `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.

## @jgengine/core/game/ruleSelection

- `RuleDef` (interface): interface RuleDef<TPayload = unknown> — A selectable rule over a tagged pool. `tags` classify it for include/exclude filtering and for `requires`/`conflicts` matching (which match either another rule's id or one of its tags). `layers` are the parameter layers this rule contributes when active; `payload` is opaque caller data.
- `RuleRegistry` (interface): interface RuleRegistry<TPayload = unknown> — Registered pool of {@link RuleDef}s — the install seam games register mutators/modes/events into.
- `RuleSelection` (interface): interface RuleSelection<TPayload = unknown> — The result of a selection — the chosen rules and their ids (a serializable {@link LayerSelection}-style list).
- `RuleSelectionConfig` (interface): interface RuleSelectionConfig — Deterministic selection inputs — plain serializable data a host can persist and replay.
- `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.
- `rerollRules` (function): function rerollRules<TPayload = unknown>(pool: readonly RuleDef<TPayload>[], config: RuleSelectionConfig, keepIds: readonly string[], salt: string | number = 0): RuleSelection<TPayload> — Reroll a prior selection: keep `keepIds` (the locked slots) and re-draw the rest under a fresh, still-deterministic stream derived from `config.seed` and `salt`. The same seed + salt + keep set reproduce the same reroll, so reroll history stays replayable.
- `selectRules` (function): function selectRules<TPayload = unknown>(pool: readonly RuleDef<TPayload>[], config: RuleSelectionConfig): RuleSelection<TPayload> — Select up to `count` rules from `pool` deterministically from `config.seed`. Locked ids are placed first (in order), then remaining slots are filled by weighted draw from tag-filtered, still-eligible candidates, honoring `requires`/`conflicts` after each pick. Each slot draws from an independent seed stream keyed by slot index, so a later slot's outcome never shifts an earlier one. Selection stops early when no compatible candidate remains. Pure given `pool` + `config`.

## @jgengine/core/game/runDraft

- `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.
- `RunDraftConfig` (interface): interface RunDraftConfig<TStat extends string = string, TData = unknown> { offers: readonly RunModifierOffer<TStat, TData>[]; rng?: () => number } — ⚠ undocumented · used by `createRunDraft`: A roguelike run built from stacking drafted modifier picks that reshape the run.
- `RunModifierOffer` (interface): interface RunModifierOffer<TStat extends string = string, TData = unknown> { id: string; weight: number; maxStacks?: number; label?: string; stats?: StatModifierSet<TStat>; data?: TData } — ⚠ undocumented
- `RunModifierPick` (interface): interface RunModifierPick { id: string; stacks: number } — ⚠ undocumented
- `RunModifierStack` (interface): interface RunModifierStack<TStat extends string = string, TData = unknown> { add(offerId: string): boolean; count(offerId: string): number; atMax(offerId: string): boolean; picks(): RunModifierPick[]; offer(offerId: string): RunModifierOffer<TStat, TData> | null; total(stat: TStat): StatModifier; apply(stats: Stat… — ⚠ undocumented
- `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.
- `createRunModifierStack` (function): function createRunModifierStack<TStat extends string = string, TData = unknown>(offers: readonly RunModifierOffer<TStat, TData>[]): RunModifierStack<TStat, TData> — ⚠ undocumented

## @jgengine/core/game/saveSlotIndex

- `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.
- `SaveSlotSource` (interface): interface SaveSlotSource — The source a slot list is refreshed from — a `GameSave`, or a narrower reader.
- `SaveSlotsRefresh` (interface): interface SaveSlotsRefresh — The result of a refresh: what the menu should show now.
- `formatSavePlaytime` (function): function formatSavePlaytime(seconds: number): string — "4h 12m" / "12m" / "< 1m" — the playtime chip every save menu wants.
- `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.
- `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.
- `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.

## @jgengine/core/game/saveSlots

- `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.
- `SaveSlotWrite` (interface): interface SaveSlotWrite — What a {@link SaveSlots.write} stamps onto a slot — a name and/or a fresh `meta` bag.
- `SaveSlots` (interface): interface SaveSlots — A serializable, observable index of save/profile slot *metadata* that a save-select menu renders. It complements `createSaveStore` (which owns the actual save payload and named slots) by carrying the per-slot display fields the store does not: name, empty flag, last-saved time, and a free-string `meta` bag the game fills. Nothing here is genre-specific.
- `SaveSlotsConfig` (interface): interface SaveSlotsConfig — How a {@link createSaveSlots} index is wired.
- `SaveSlotsSnapshot` (interface): interface SaveSlotsSnapshot — Serializable state of a {@link SaveSlots} index, for save/restore.
- `createSaveSlots` (function): function createSaveSlots(config: SaveSlotsConfig = {}): SaveSlots — Create a {@link SaveSlots} index — the serializable, observable list of save/profile slot metadata a save-select menu renders. It is a thin companion to `createSaveStore`: the store owns the real save payload keyed by slot, this owns only the display fields (name, empty, last-saved, and a free-string `meta` bag) the menu shows. `write` stamps a slot saved on the injected clock, `clear` empties one, `rename` relabels one, `mostRecent()` returns the newest non-empty slot to power a "Continue" button, and `list()` feeds the New / Continue / Load / Delete grid. `meta` keys are free strings the game owns — the model never interprets them — and `snapshot`/`restore` round-trips the whole index through a save.

## @jgengine/core/game/saveStore

- `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 }`.
- `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.
- `SaveEnvelope` (interface): interface SaveEnvelope<T> — The versioned envelope written to the backend — `version` lets a later game build detect and {@link SaveStoreConfig.migrate | migrate} an older payload.
- `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.
- `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.
- `SaveStoreConfig` (interface): interface SaveStoreConfig<T> — How a {@link createSaveStore} is wired — the backend it persists through, the initial value, and optional slot/versioning/autosave/serialization knobs.
- `SaveTimers` (interface): interface SaveTimers — The timer seam autosave schedules through — defaults to the ambient `setTimeout`/`clearTimeout`; inject fakes in tests.
- `createSaveStore` (function): function createSaveStore<T>(config: SaveStoreConfig<T>): SaveStore<T> — Create a {@link SaveStore}. Same call for offline and cloud — only the `backend` differs (localStorage, memory, or an async DB/Convex endpoint). Turn on `autosave` and every `set`/`patch` persists on a debounce; leave it off and call `save()` at checkpoints. Bump `version` + pass `migrate` when the save shape changes so old players keep their progress.
- `localSaveBackend` (function): function localSaveBackend(storage?: KeyValueStorage | null, policy: KeyValueStorageErrorPolicy = {}): SaveBackend — A {@link SaveBackend} over a synchronous {@link KeyValueStorage} — the browser's `localStorage` by default (offline, on-device saves), a test stub, or `null` for a no-op backend. Default fallback ignores failures; `errorMode: "throw"` rejects failed operations and unavailable storage, so SaveStore status/onError can report them. Use {@link memorySaveBackend} for deliberate ephemeral persistence.
- `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.
- `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.

## @jgengine/core/game/snapshotHistory

- `HistoryStacks` (interface): interface HistoryStacks<T> — Bounded past/future snapshot stacks — a serializable undo/redo record for any state `T`.
- `HistoryStep` (interface): interface HistoryStep<T> — The snapshot an undo/redo restores plus the advanced stacks.
- `SnapshotHistory` (interface): interface SnapshotHistory<T> — Stateful undo/redo handle over {@link HistoryStacks}, holding the stacks in a closure.

## @jgengine/core/game/social

- `DEFAULT_EMOTE_RADIUS` (const): const DEFAULT_EMOTE_RADIUS: 20 — ⚠ undocumented
- `EmoteBroadcastResult` (interface): interface EmoteBroadcastResult { from: string; emoteId: string; at: readonly [number, number, number]; recipients: readonly string[] } — ⚠ undocumented
- `EmoteEntityLookup` (interface): interface EmoteEntityLookup { get(id: string): {position: readonly [number, number, number]; role: string} | null } — ⚠ undocumented
- `EmoteSpatialLookup` (interface): interface EmoteSpatialLookup { inRadius(center: readonly [number, number, number], radius: number, filter?: (id: string) => boolean): readonly string[] } — ⚠ undocumented
- `Emotes` (interface): interface Emotes { play(fromUserId: string, emoteId: string, radius?: number): EmoteBroadcastResult | {reason: string} } — ⚠ undocumented
- `EmotesDeps` (interface): interface EmotesDeps { entities: EmoteEntityLookup; spatial: EmoteSpatialLookup } — ⚠ undocumented
- `FriendEntry` (interface): interface FriendEntry { userId: string; online: boolean } — ⚠ undocumented
- `FriendRequestEntry` (interface): interface FriendRequestEntry { requestId: string; fromUserId: string } — ⚠ undocumented
- `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
- `FriendsSnapshot` (interface): interface FriendsSnapshot { friends: string[]; blocked: string[] } — ⚠ undocumented
- `Party` (interface): interface Party { register(config: PartyConfig): void; canInvite(fromUserId: string, toUserId: string): {reason: string} | null; invite(fromUserId: string, toUserId: string): {inviteId: string} | {reason: string}; accept(userId: string, inviteId: string): … — ⚠ undocumented
- `PartyConfig` (interface): interface PartyConfig { maxMembers: number; inviteTtlMs?: number } — ⚠ undocumented
- `PartyInviteEntry` (interface): interface PartyInviteEntry { inviteId: string; fromUserId: string; createdAt: number } — ⚠ undocumented
- `PartyMemberEntry` (interface): interface PartyMemberEntry { userId: string; role: PartyRole } — ⚠ undocumented
- `PartyRole` (type): type PartyRole = "leader" | "member" — ⚠ undocumented
- `PresenceInfo` (interface): interface PresenceInfo { online: boolean; serverId?: string; zoneId?: string; instanceId?: string } — ⚠ undocumented
- `Social` (interface): interface Social { friends: Friends; party: Party; presence: {get(userId: string): PresenceInfo}; emotes: Emotes; worldInvites: WorldInvites; snapshot(): SocialSnapshot; hydrate(data: SocialSnapshot): void } — ⚠ undocumented · used by `createSocial`: Emotes and lightweight social interactions between nearby players.
- `SocialDeps` (interface): interface SocialDeps { events: GameEvents; presence?: (userId: string) => PresenceInfo; now?: () => number; emotes?: EmotesDeps; worldInviteTtlMs?: number } — ⚠ undocumented · used by `createSocial`: Emotes and lightweight social interactions between nearby players.
- `SocialPartySnapshot` (interface): interface SocialPartySnapshot — One party's replicated membership — id, current leader, and ordered member ids.
- `SocialSnapshot` (interface): interface SocialSnapshot — Full friends/party/world-invite state as one serializable baseline — the host→client replication payload behind the `social` snapshot module. Presence and emotes are derived from live deps, not stored.
- `WorldInvite` (interface): interface WorldInvite extends WorldInviteTarget { id: string; fromUserId: string; toUserId: string; createdAt: number } — ⚠ undocumented
- `WorldInviteTarget` (interface): interface WorldInviteTarget { serverId: string; joinCode?: string } — ⚠ undocumented
- `WorldInvites` (interface): interface WorldInvites { canInvite(fromUserId: string, toUserId: string): {reason: string} | null; invite(fromUserId: string, toUserId: string, target: WorldInviteTarget): {inviteId: string} | {reason: string}; accept(userId: string, inviteId: string): {target: W… — ⚠ undocumented
- `createSocial` (function): function createSocial(deps: SocialDeps): Social — Emotes and lightweight social interactions between nearby players.

## @jgengine/core/game/spawnPoints

- `RespawnTarget` (interface): interface RespawnTarget { setPose(id: string, pose: EntityPose): boolean } — ⚠ undocumented
- `SpawnPointPose` (interface): interface SpawnPointPose { x: number; y: number; z: number; rotationY?: number } — ⚠ undocumented
- `SpawnPoints` (interface): interface SpawnPoints { record(id: string, pose: SpawnPointPose): void; get(id: string): SpawnPointPose | undefined; list(): readonly (SpawnPointPose & {id: string})[]; respawn(entities: RespawnTarget, entityId: string, spawnId: string): boolean } — ⚠ undocumented · used by `createSpawnPoints`: Register spawn locations and choose where entities spawn or respawn.
- `createSpawnPoints` (function): function createSpawnPoints(): SpawnPoints — Register spawn locations and choose where entities spawn or respawn.

## @jgengine/core/game/systemRuntime

- `composeGameLoop` (function): function composeGameLoop(systems: readonly SystemDefinition[] | undefined, loop: GameLoop<GameContext> | undefined, options?: ComposeGameLoopOptions): GameLoop<GameContext> — Merge a system list with an optional classic `GameLoop` into one loop the shell/runners drive. Systems install on first `onInit`; classic hooks still run for incremental migration.

## @jgengine/core/game/systemSchedule

- `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.
- `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.
- `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.
- `compileSystemSchedule` (function): function compileSystemSchedule(systems: readonly SystemDefinition[], options?: CompileSystemScheduleOptions): CompiledSystemSchedule — Compile system definitions into a deterministic schedule. Validates unique ids, `dependsOn`, and before/after cycles.

## @jgengine/core/game/talentTreeView

- `TalentEdgeView` (interface): interface TalentEdgeView — One prerequisite edge into a node — the source node, the rank it demands, and whether that is met.
- `TalentNodeState` (type): type TalentNodeState = "locked" | "available" | "learned" | "maxed" — Render state of a talent node, derived from its rank and prerequisite satisfaction. - `locked` — rank 0 and at least one prerequisite unmet; cannot be trained yet. - `available` — rank 0, every prerequisite met; ready to take a first point. - `learned` — at least one rank invested, but below `maxRank`. - `maxed` — fully invested (`rank === maxRank`).
- `TalentNodeStatus` (interface): interface TalentNodeStatus — Per-node status a game supplies to build a view from *any* unlock rule — not just point-spend. A game computes these from whatever it wants (a currency threshold, a level, a quest flag, a skill-point pool, nothing at all) so the same widget renders a buy-with-points talent tree, a money-gated upgrade tree, or a condition-unlocked ability web without changing the renderer.
- `TalentNodeView` (interface): interface TalentNodeView — A per-node view for rendering: grid placement (tier/branch), rank, state, and inbound prerequisite edges.
- `TalentPointTotals` (interface): interface TalentPointTotals — Optional overall point totals for the view header; omit (or 0) for trees that spend no point currency.
- `TalentTreeView` (interface): interface TalentTreeView — A whole-tree render view: placed nodes plus branch/tier extents and point totals.
- `talentTreeView` (function): function talentTreeView<TStat extends string = string>(nodes: readonly TalentNodeDef<TStat>[], tree: TalentTree<TStat>): TalentTreeView — Project the existing talent model (`createTalentTree`) into a flat, serializable render view: every node placed by branch + prerequisite-depth tier, tagged learned/available/locked/maxed, with its inbound prerequisite edges (and whether each is met) and whether a point can be spent right now. It is a pure read over the node defs plus a live {@link TalentTree}, so a React/canvas widget can lay out nodes, draw edges, and gate clicks without re-deriving topology or re-interpreting eligibility. The model still owns allocation, requirements, and point rules — this only reshapes them for drawing, and never interprets what a node *means* (ids, branches, and ranks stay opaque game data). This is the point-spend adapter over {@link talentTreeViewFrom}; pass a custom status to that builder instead to drive the tree from a currency, level, or any other unlock rule.
- `talentTreeViewFrom` (function): function talentTreeViewFrom<TStat extends string = string>(nodes: readonly TalentNodeDef<TStat>[], status: (node: TalentNodeDef<TStat>) => TalentNodeStatus, totals?: TalentPointTotals): TalentTreeView — Build a flat, serializable render view of a node graph from a caller-supplied per-node status, decoupled from any particular progression model. For each node the game returns its `rank` and whether it is `allocatable` *right now* under whatever rule it likes — a skill-point pool, a cash threshold, a level gate, a quest flag, or nothing. The builder places every node by branch + prerequisite-depth tier, tags it learned/available/locked/maxed (`available` when rank 0 and every prerequisite is met — see below), and resolves inbound prerequisite edges (each `met` when the source node's supplied rank meets the demand). This is the general escape hatch behind {@link talentTreeView}: it lets the same widget render a buy-with-points talent tree, a money-gated upgrade tree, or a condition-unlocked ability web without the renderer changing. It never interprets what a node *means* — ids, branches, and ranks stay opaque game data.

## @jgengine/core/game/talents

- `ResolvedTalents` (interface): interface ResolvedTalents<TStat extends string = string> { stats: StatModifierSet<TStat>; abilities: readonly string[] } — ⚠ undocumented
- `TalentAllocateReason` (type): type TalentAllocateReason = "unknown-node" | "max-rank" | "no-points" | "requires" | "branch-points" — ⚠ undocumented
- `TalentAllocateResult` (type): type TalentAllocateResult = { ok: true } | { ok: false; reason: TalentAllocateReason } — ⚠ undocumented
- `TalentNodeDef` (interface): interface TalentNodeDef<TStat extends string = string> { id: string; branch?: string; maxRank: number; requires?: readonly TalentRequirement[]; requiresPointsInBranch?: number; modifiersPerRank?: StatModifierSet<TStat>; grantsAbilities?: readonly string[] } — ⚠ undocumented · used by `talentTreeView` (@jgengine/core/game/talentTreeView): Project the existing talent model (`createTalentTree`) into a flat, serializable render view: every node placed by branch + prerequisite-dep…
- `TalentRequirement` (type): type TalentRequirement = string | { nodeId: string; rank: number } — ⚠ undocumented
- `TalentSnapshot` (interface): interface TalentSnapshot { points: number; ranks: Record<string, number> } — ⚠ undocumented
- `TalentTree` (interface): interface TalentTree<TStat extends string = string> { rank(nodeId: string): number; pointsAvailable(): number; pointsSpent(): number; pointsInBranch(branch: string): number; grantPoints(amount: number): void; canAllocate(nodeId: string): TalentAllocateResult; allocate(nodeId: string): Talent… — ⚠ undocumented · used by `talentTreeView` (@jgengine/core/game/talentTreeView): Project the existing talent model (`createTalentTree`) into a flat, serializable render view: every node placed by branch + prerequisite-dep…
- `TalentTreeConfig` (interface): interface TalentTreeConfig<TStat extends string = string> { nodes: readonly TalentNodeDef<TStat>[]; points?: number } — ⚠ undocumented
- `createTalentTree` (function): function createTalentTree<TStat extends string = string>(config: TalentTreeConfig<TStat>): TalentTree<TStat> — ⚠ undocumented

## @jgengine/core/game/toasts

- `Toast` (interface): interface Toast<T = string> — A transient HUD message that expires on its own — banner, pickup note, alert.
- `ToastQueue` (interface): interface ToastQueue<T = string> — Stateful transient-toast list with a size cap and time-to-live eviction.
- `ToastQueueOptions` (interface): interface ToastQueueOptions — Options for {@link createToastQueue}.
- `ToastQueueState` (interface): interface ToastQueueState<T = string> — Plain JSON state of a {@link ToastQueue}: live toasts plus the id counter.
- `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.
- `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.
- `pruneToasts` (function): function pruneToasts<T>(toasts: readonly Toast<T>[], now: number): readonly Toast<T>[] — Drop every toast whose `expiresAt` is at or before `now`. Returns the same array when nothing expired.

## @jgengine/core/game/trade

- `TradeField` (interface): interface TradeField { buy?: Record<string, number>; sell?: Record<string, number>; shops?: string[] } — ⚠ undocumented
- `TradeInventory` (interface): interface TradeInventory { put(inventoryId: string, itemId: string, count: number): TradeRejection | null; take(inventoryId: string, itemId: string, count: number): TradeRejection | null; count(inventoryId: string, itemId: string): number } — ⚠ undocumented
- `TradeOutcome` (interface): interface TradeOutcome { itemId: string; count: number; currency: Record<string, number> } — ⚠ undocumented
- `TradeParty` (interface): interface TradeParty { shop: string; inventoryId: string } — ⚠ undocumented
- `TradeRejection` (interface): interface TradeRejection { reason: string } — ⚠ undocumented
- `TradeResolution` (type): type TradeResolution = | { status: "ok"; outcome: TradeOutcome } | { status: "rejected"; reason: string } — ⚠ undocumented
- `TradeSystem` (interface): interface TradeSystem { canBuy(itemId: string, shopId: string, count?: number): string | null; canSell(itemId: string, count?: number): string | null; buy(itemId: string, count: number | undefined, party: TradeParty): TradeRejection | null; sell(itemId: string, … — ⚠ undocumented
- `TradeSystemDeps` (interface): interface TradeSystemDeps { resolveTrade(itemId: string): TradeField | null | undefined; wallet: TradeWallet; inventory: TradeInventory } — ⚠ undocumented
- `TradeWallet` (interface): interface TradeWallet { canAfford(costs: Record<string, number>): string | null; charge(costs: Record<string, number>): void; grant(gains: Record<string, number>): void } — ⚠ undocumented

## @jgengine/core/game/tribe

- `AssetAction` (type): type AssetAction = "inventory" | "use" | "command" — Per-asset action gated by rank on group-owned assets.
- `AssetOwnership` (type): type AssetOwnership = { scope: "group" } | { scope: "personal"; memberId: string } — Who inside the group owns an asset: the group as a whole, or a specific member personally.
- `AssetRef` (interface): interface AssetRef — Opaque reference to a shared thing (structure, creature, container) by kind + id.
- `Tribe` (interface): interface Tribe — A shared-ownership group — a tribe, guild, clan, or company — as one first-class aggregate. Unifies ranked membership, group-vs-personal asset ownership, mutual alliances, and a bounded event log that otherwise have to be hand-assembled from parties, factions, build permissions, and per-owner rosters.
- `TribeAssetRecord` (interface): interface TribeAssetRecord — An asset (structure/creature) owned within a tribe — group-shared or held by one member.
- `TribeConfig` (interface): interface TribeConfig — Construction options for {@link createTribe}: id, founder, rank ladder, and log cap.
- `TribeEvent` (interface): interface TribeEvent — One entry in a tribe's bounded event log. Optional fields present only when meaningful.
- `TribeEventType` (type): type TribeEventType = | "member-added" | "member-removed" | "member-left" | "rank-changed" | "founder-transferred" | "asset-registered" | "asset-unregistered" | "alliance-formed" | "alliance-broken" — The kind of change recorded in a tribe's event log (membership, ownership, or alliance).
- `TribeMemberRecord` (interface): interface TribeMemberRecord — A member of a tribe and the rank id that governs their permissions.
- `TribeRankDef` (interface): interface TribeRankDef — A rank within a group's hierarchy. Higher `level` means more authority: a member can only manage (kick, re-rank) members strictly below their own level, and cannot promote anyone to a level at or above their own. `permissions` are opaque, genre-agnostic capability slugs the game checks with {@link Tribe.can} (e.g. `"build"`, `"demolish"`, `"invite"`, `"kick"`, `"manage-ranks"`, plus the {@link AssetAction} slugs `"inventory"`, `"use"`, `"command"` for group-owned assets). A `bypass` rank (an admin) skips every permission check, exactly like the founder.
- `TribeRegistry` (interface): interface TribeRegistry — A collection of {@link Tribe tribes} with mutual alliance management and cross-member relation lookups. Alliances are kept symmetric here (both sides updated together), and member-to-member relations resolve through tribe membership + alliances, mirroring the `faction` graph vocabulary.
- `TribeRegistryDeps` (interface): interface TribeRegistryDeps — Injected dependencies for {@link createTribeRegistry} (e.g. a `now()` clock for event timestamps).
- `TribeRegistrySnapshot` (interface): interface TribeRegistrySnapshot — Full serializable state of a tribe registry — every tribe's snapshot in one payload.
- `TribeResult` (type): type TribeResult = { reason: string } | null — Standard `{ reason }`-on-failure / `null`-on-success result for authorized mutations.
- `TribeSnapshot` (interface): interface TribeSnapshot — Full serializable state of one tribe — the save/replication baseline.
- `createTribe` (function): function createTribe(config: TribeConfig): Tribe — Create a shared-ownership group aggregate (tribe / guild / clan / company). Members hold a {@link TribeRankDef rank} whose configurable permission slugs gate management actions and access to group-owned assets, while personally-owned assets stay with their member — and follow them out when they leave. Group↔group {@link Tribe.addAlly alliances} resolve allied tribes as friendly, and every membership / ownership / alliance change lands in a bounded ring-buffer {@link Tribe.events log}. All state is plain JSON via {@link Tribe.snapshot}/{@link Tribe.hydrate}; timestamps come from an injected clock for determinism. Compose many tribes with {@link createTribeRegistry} for mutual alliances and cross-member relation lookups.
- `createTribeRegistry` (function): function createTribeRegistry(deps: TribeRegistryDeps = {}): TribeRegistry — Create a registry that owns many tribes, keeps alliances mutual, and resolves member relations.

## @jgengine/core/game/unlocks

- `UnlockCatalog` (interface): interface UnlockCatalog { has(unlockId: string): boolean; tree(categoryId: string): UnlockDef[] } — ⚠ undocumented · used by `createUnlockCatalog`: A catalog of unlockable content gated behind conditions the player earns, tracking what is unlocked.
- `UnlockDef` (interface): interface UnlockDef { id: string; category?: string } — ⚠ undocumented · used by `createUnlockCatalog`: A catalog of unlockable content gated behind conditions the player earns, tracking what is unlocked.
- `UnlockState` (type): type UnlockState = readonly string[] — ⚠ undocumented
- `Unlocks` (interface): interface Unlocks { has(userId: string, unlockId: string): boolean; grant(userId: string, unlockId: string): void; list(userId: string): string[]; tree(categoryId: string): UnlockDef[]; snapshot(userId: string): string[]; hydrate(userId: string, ids: string[… — ⚠ undocumented
- `createUnlockCatalog` (function): function createUnlockCatalog(defs: readonly UnlockDef[] = []): UnlockCatalog — A catalog of unlockable content gated behind conditions the player earns, tracking what is unlocked.
- `createUnlocks` (function): function createUnlocks(defs: UnlockDef[] = []): Unlocks — ⚠ undocumented
- `grantUnlock` (function): function grantUnlock(granted: UnlockState, unlockId: string): string[] — ⚠ undocumented
- `hasUnlock` (function): function hasUnlock(granted: UnlockState, unlockId: string): boolean — ⚠ undocumented
- `unlockTree` (function): function unlockTree(defs: readonly UnlockDef[], categoryId: string): UnlockDef[] — ⚠ undocumented

## @jgengine/core/game/vfxInstance

- `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.
- `VfxInstancePatch` (interface): interface VfxInstancePatch — A partial update to a live retained VFX instance. Only the provided fields change; `params` is shallow-merged so a caller can nudge one knob without resending the whole bag. Setting a field to `undefined` clears it. Applying a patch refreshes the instance heartbeat.
- `VfxInstanceSpec` (interface): interface VfxInstanceSpec — The serializable specification for creating (or replacing) a retained VFX instance. Unlike a one-shot `combat.vfx` burst this describes a long-lived effect whose endpoints and parameters are updated over time. `id` is caller-stable so repeated `upsert` calls address the same effect; omit it to mint one. `from`/`to` are {@link VfxRef}s (an entity instance id or a world point) that a renderer resolves each frame, so an endpoint bound to a moving entity follows it without any per-frame command traffic.
- `VfxInstanceState` (interface): interface VfxInstanceState — The stored, fully-resolved form of a retained VFX instance. It is a plain serializable record so hosts can replicate it and debug tooling can inspect it; renderers receive it verbatim and never merge partial state themselves. `updatedAtMs` is the last create/update time and drives TTL heartbeat eviction.
- `VfxInstanceStopOptions` (interface): interface VfxInstanceStopOptions — Options for {@link VfxInstanceStore.stop}.
- `VfxInstanceStore` (interface): interface VfxInstanceStore — A headless registry of retained VFX instances: create/replace, partially update, and stop long-lived effects addressed by stable id, independent of any renderer. It owns the authoritative serializable state and exposes inspection counts; wire {@link VfxInstanceStoreOptions.onOp} to a renderer (via the `combat.vfxInstance` event) to drive visuals.
- `VfxInstanceStoreOptions` (interface): interface VfxInstanceStoreOptions — Options for {@link createVfxInstanceStore}.
- `VfxInstanceStoreState` (interface): interface VfxInstanceStoreState — Plain JSON state of a {@link VfxInstanceStore}.
- `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.

## @jgengine/core/game/viewports

- `ViewportCameraConfig` (interface): interface ViewportCameraConfig — The follow camera an extra viewport runs; the primary seat keeps the game's main camera rig.
- `ViewportDef` (interface): interface ViewportDef — One viewport: which local seat it shows and where.
- `ViewportPixels` (interface): interface ViewportPixels — A viewport in canvas pixels with a bottom-left origin, ready for `gl.setViewport`/`setScissor`.
- `ViewportRect` (type): type ViewportRect = readonly [number, number, number, number] — A screen region as fractions of the canvas, `[x, y, width, height]` in `0..1` with the origin at the top left.
- `ViewportsConfig` (interface): interface ViewportsConfig — `defineGame({ viewports })`: split-screen layout for local seats.
- `resolveViewports` (function): function resolveViewports(config: ViewportsConfig | undefined, slots: readonly string[]): ViewportDef[] — The viewports to draw for the seats currently joined: the explicit layout filtered to joined seats, or an even split.
- `splitViewports` (function): function splitViewports(slots: readonly string[], split: "vertical" | "horizontal" = "vertical"): ViewportDef[] — Even split-screen rects for seats in order: one fills the screen, two split side by side (or stacked), three put the first on a full-width top half, four make a 2×2 grid, more fill a grid row by row.
- `viewportPixels` (function): function viewportPixels(rect: ViewportRect, width: number, height: number): ViewportPixels — Convert a top-left fractional rect into whole canvas pixels with a bottom-left origin; neighbours share edges exactly.

## @jgengine/core/game/worldItem

- `DEFAULT_PICKUP_RADIUS` (const): const DEFAULT_PICKUP_RADIUS: 2 — ⚠ undocumented
- `DEFAULT_RARITY` (const): const DEFAULT_RARITY: "common" — ⚠ undocumented
- `DEFAULT_SCATTER` (const): const DEFAULT_SCATTER: ScatterOptions — ⚠ undocumented
- `RarityStyle` (interface): interface RarityStyle — Per-rarity look of a dropped item: beam, color and label. Set via `defineGame({ worldItem: { rarityStyle } })`.
- `ResolveDeathDropsOptions` (interface): interface ResolveDeathDropsOptions { mode: "grant" | "world"; origin: EntityPosition; resolveRarity(itemId: string): string; resolveBaseType?(itemId: string): string; scatter?: ScatterOptions; rng?(): number; source?: string } — ⚠ undocumented
- `ResolvedDeathDrops` (interface): interface ResolvedDeathDrops { worldSpawns: WorldItemSpawnInput[]; grants: Drop[] } — ⚠ undocumented
- `ScatterOptions` (interface): interface ScatterOptions { radius: number; minRadius?: number; height?: number } — ⚠ undocumented
- `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).
- `WorldItemPresentation` (interface): interface WorldItemPresentation { hidden: boolean; color?: string; beam: boolean; label?: string } — ⚠ undocumented
- `WorldItemRecord` (interface): interface WorldItemRecord { instanceId: string; itemId: string; rarity: string; baseType: string; count: number; affixTier?: number; source?: string; droppedAt: number } — ⚠ undocumented · used by `useNearestWorldItem` (@jgengine/react): Nearest ground item within `radius` of the local player — drives a pickup prompt/highlight.
- `WorldItemSpawnInput` (interface): interface WorldItemSpawnInput { itemId: string; position: EntityPosition; rarity?: string; baseType?: string; count?: number; affixTier?: number; source?: string } — ⚠ undocumented
- `WorldItemStore` (interface): interface WorldItemStore { spawn(input: WorldItemSpawnInput): WorldItemRecord; get(instanceId: string): WorldItemRecord | null; list(): readonly WorldItemRecord[]; nearestInRadius(from: EntityPosition, radius: number, filter?: (record: WorldItemRecord) => boolean):… — ⚠ undocumented
- `WorldItemStoreDeps` (interface): interface WorldItemStoreDeps { spawnEntity(position: EntityPosition): string; despawnEntity(instanceId: string): boolean; resolvePosition(instanceId: string): EntityPosition | undefined; now?(): number } — ⚠ undocumented

## @jgengine/core/gameplay

- `AchievementDef` (interface): interface AchievementDef — Definition of one achievement. Content-agnostic — the game supplies names, targets, and icons.
- `AchievementSnapshot` (interface): interface AchievementSnapshot — Whole serializable state of a tracker — drop into a save blob.
- `AchievementTracker` (interface): interface AchievementTracker — Live achievement state over a fixed definition set — drives progress, unlocks, score, and a UI view list.
- `AchievementTrackerOptions` (interface): interface AchievementTrackerOptions — Options for {@link createAchievementTracker}.
- `AchievementUnlock` (interface): interface AchievementUnlock — Emitted the instant an achievement unlocks — wire to a toast, feed, or sound.
- `AchievementView` (interface): interface AchievementView extends AchievementDef — A definition plus its live unlock/progress state — what UI renders.
- `ActionCodes` (type): type ActionCodes<TCode extends string = string> = | readonly TCode[] | { hold?: readonly TCode[]; toggle?: readonly TCode[]; repeatMs?: number } — ⚠ undocumented
- `ActionCodesMap` (type): type ActionCodesMap<TAction extends string = string, TCode extends string = string> = Record< TAction, ActionCodes<TCode> > — Maps each game action name to the input codes (hold/toggle keys, repeat rate) that trigger it. In a `defineGame({ input })`, pressing an action runs the same-named command with `{ yaw, pitch, aim }`; `repeatMs` re-fires it while held (automatic weapons).
- `ActionStateTracker` (interface): interface ActionStateTracker<TAction extends string> { handleDown(code: string): TAction | null; handleUp(code: string): TAction | null; isDown(action: TAction): boolean; wasPressed(action: TAction): boolean; endFrame(): void; reset(): void; rebind(map: ActionStateBindingMap<TAction, string>)… — ⚠ undocumented · used by `rebindGamepadPoll` (@jgengine/shell/input/gamepadPoll): Swap the pad bindings mid-game (a context push) without touching keyboard state: release the codes of pad-held actions whose pad codes chang…
- `ActiveEffect` (interface): interface ActiveEffect — A live timed effect an engine is tracking until it expires or is cleaned up.
- `AdvanceOptions` (interface): interface AdvanceOptions — Per-advance settings: the policy pipeline, caller context, rounding, and safety bounds.
- `AdvanceResult` (interface): interface AdvanceResult — The outcome of {@link advanceLedger}: the new ledger plus applied transactions and events.
- `AffixPool` (interface): interface AffixPool { id: string; affixes: readonly AffixDef[] } — ⚠ undocumented
- `AppliedTransaction` (type): type AppliedTransaction = ResourceTransaction — A {@link ResourceTransaction} after policies and rounding, as actually applied to balances.
- `Auction` (interface): interface Auction — One live timed auction in an {@link AuctionBook}: an item stack under open bidding until it closes.
- `AuctionSettlement` (type): type AuctionSettlement = | { status: "sold"; auction: Auction; winnerId: string; price: number; houseCut: number; sellerProceeds: number; } | { status: "returned"; auction: Auction } — How one closed auction resolved during {@link AuctionBook.settleExpired}.
- `AxisBindingMap` (type): type AxisBindingMap = Record<AxisName, AxisBinding> — ⚠ undocumented · used by `DRIVE_AXIS_BINDINGS` (@jgengine/core/input/axisInput): Car axes bound to raw key codes, for an {@link AxisChannel} sampled with a key-code `isDown`.
- `AxisChannelConfig` (interface): interface AxisChannelConfig { bindings: AxisBindingMap; smoothing?: number } — ⚠ undocumented · used by `useAxisChannel` (@jgengine/react): Wires useHeldKeys into a fresh AxisChannel, ready for a per-frame `channel.sample(dt, isDown)`.
- `AxisInput` (interface): interface AxisInput { throttle: number; brake: number; steer: number; handbrake: number } — ⚠ undocumented · used by `tickDrivableVehicle` (@jgengine/core/physics/drivableVehicle): Connects an `AxisInput` sample straight through a ground-vehicle sim (`KinematicVehicle` or `VehicleDynamics`) to a scene entity's pose for …
- `BackdropConfig` (interface): interface BackdropConfig — Generic sky/background/fog for ANY world kind, including a custom `environment` component (#207.6).
- `BehaviorConfig` (type): type BehaviorConfig = Record<string, unknown> — Per-behavior configuration stored on an item as plain data (e.g. charge time, projectile id). Kept opaque here so no game noun leaks into item core.
- `BehaviorState` (type): type BehaviorState = Record<string, unknown> — A single behavior's mutable, serializable runtime state (e.g. current charge, rounds queued). Composed state is a map of these keyed by behavior id.
- `Behaviour` (class): class Behaviour — Subclass and override the lifecycle hooks. A behaviour only joins the per-frame update dispatch if it actually overrides `onUpdate` (prototype-identity check at each activation), so hook-only behaviours cost nothing per frame.
- `BehaviourModule` (class): class BehaviourModule — A world-lifetime service with typed sibling access via `this.modules`. Modules awake and start before any behaviour during `world.start()`, subscribe to update dispatch first (their `onUpdate` fires before every behaviour's), and have no disable/destroy — they live as long as the world.
- `BehaviourWorld` (interface): interface BehaviourWorld { add(id: string, parentId?: string): void; has(id: string): boolean; parentOf(id: string): string | null; childrenOf(id: string): readonly string[]; setParent(id: string, parentId: string | null): void; attach<T extends Behaviour>(nodeId: … — ⚠ undocumented
- `BindingOverrides` (type): type BindingOverrides = Record<string, ActionCodes> — Player-rebound keys, keyed by action name. Values mirror an `ActionCodes` entry so hold/toggle/repeat semantics survive a rebind — the settings menu only swaps which physical codes drive the action.
- `CAMERA_FRUSTUM_DEFAULTS` (const): const CAMERA_FRUSTUM_DEFAULTS: { readonly fov: 55; readonly near: 0.1; readonly far: 300; readonly zoom: 50; } — ⚠ undocumented
- `CameraKeyframe` (interface): interface CameraKeyframe — One stop on a scripted camera path (#29).
- `CameraRigKind` (type): type CameraRigKind = | "orbit" | "first" | "topDown" | "rts" | "shoulder" | "lockOn" | "chase" | "observer" | "turntable" | "sideScroll" | "inspection" | "none" — Which camera rig the shell mounts. Every rig accepts `followEntityId: null` (avatar-less games — city-builders, card games, auto-battlers — still get a camera). Rigs are tuned through their config block below, never by writing camera positions from `onTick`. - `orbit` — third-person chase (the historical default; `perspective: "third"`). - `first` — pointer-lock mouse-look (`perspective: "first"`). - `topDown` — fixed height/pitch/yaw with decoupled follow (ARPG iso, top-down). - `rts` — free-pan / edge-scroll / rotate / zoom, optional follow. - `shoulder` — over-the-shoulder with ADS transition + shoulder swap. - `lockOn` — yaw bound to the player→target vector; move axis becomes strafe. - `chase` — speed-reactive vehicle chase (speed→FOV, spring arm, shake) + cockpit/hood/rear views. - `observer` — detached spectator/photo cam bound to any entity or fixed point; never reads player input. - `turntable` — slow auto-orbit of a fixed point: a rotating display stand for a scene. The friendly, flat spelling of `observer`'s point-orbit mode; providing `camera.turntable` selects it without an explicit `rig`. - `sideScroll` — fixed lateral follow (2.5D platformer/beat-'em-up side view); reads no player input. - `inspection` — model-viewer / editor rig (#207.7, #866): middle-drag pan, right-drag orbit, scroll zoom toward a configurable anchor; orbits a fixed point, reads no player/entity input. - `none` — no camera rig is mounted; use for HUD-only presentations or a game that manages its own camera.
- `CancelResult` (type): type CancelResult<TSpec, TReserve = undefined> = | { readonly ok: true; readonly state: WorkQueueState<TSpec, TReserve>; readonly job: Job<TSpec, TReserve>; readonly refund: TReserve | null; } | { readonly ok: false; readonly state: WorkQueueState<TSpec, TReserve>; readonly reason: string } — Outcome of {@link cancelJob}, carrying the removed job and its computed refund.
- `CandidatePlacement` (interface): interface CandidatePlacement — A part proposed for a slot during generation, before it is committed to an identity. Used by the backtracking contract to test a placement in isolation.
- `CardPile` (interface): interface CardPile { state(): CardPileState; zones(): readonly ZoneName[]; count(zone: ZoneName): number; peek(zone: ZoneName, n?: number): readonly string[]; zoneOf(cardId: string): ZoneName | null; shuffle(zone: ZoneName | undefined, seed: string | number):… — ⚠ undocumented
- `CardPileState` (interface): interface CardPileState { readonly zones: Readonly<Record<ZoneName, readonly string[]>> } — ⚠ undocumented · used by `CardStack` (@jgengine/react): `StackedPile` bound to a headless `CardPileState` zone: reads the ordered card ids from `pile.zones[zone]` and resolves each to a `PlayingCa…
- `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).
- `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.
- `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.
- `ChargeCursor` (interface): interface ChargeCursor — Mutable per-charge progress, kept apart from the {@link RecurringCharge} definition.
- `ChargeOptions` (interface): interface ChargeOptions — Options for {@link charge}/{@link chargeAll}: opt one call into overdraft debt via `overdraft`.
- `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`.
- `ChaseCameraConfig` (interface): interface ChaseCameraConfig — Speed-reactive vehicle chase rig (#27) — speed→FOV, spring arm, procedural shake, interior views.
- `ChaseMissionOptions` (interface): interface ChaseMissionOptions extends ComposedMissionOptions — Options for {@link chaseMission}: a target kept close until it is caught.
- `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
- `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…
- `ChatRateLimit` (interface): interface ChatRateLimit { count: number; perMs: number } — ⚠ undocumented
- `ChatSendResult` (type): type ChatSendResult = | { message: ChatMessage; recipients: ChatRecipients } | { reason: string } — ⚠ undocumented
- `CinematicCameraConfig` (interface): interface CinematicCameraConfig — Scripted keyframe / path player (#29). When set it overrides the active rig.
- `Codex` (interface): interface Codex<TMeta = unknown> — A codex/bestiary of defined entries with per-player discovery tracking.
- `CodexEntryDef` (interface): interface CodexEntryDef<TMeta = unknown> — A codex/bestiary/lorebook entry the game defines. Discovery state is tracked separately.
- `CodexEntryView` (interface): interface CodexEntryView<TMeta = unknown> extends CodexEntryDef<TMeta> — A definition plus its discovery state — what UI renders.
- `CodexOptions` (interface): interface CodexOptions<TMeta = unknown> — Options for {@link createCodex}.
- `CodexSnapshot` (interface): interface CodexSnapshot — Serializable discovery state — a save blob.
- `CombatTelegraphEvent` (interface): interface CombatTelegraphEvent { id: number; shape: TelegraphShape; position: [number, number, number]; dir?: number; windupMs: number; kind: string } — ⚠ undocumented
- `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).
- `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.
- `CompatibilityRule` (type): type CompatibilityRule = RequireRule | ForbidRule — A cross-slot compatibility rule constraining which part/tag/family combinations a modular item may hold.
- `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.
- `ComposedMissionOptions` (interface): interface ComposedMissionOptions — Options shared by every composed mission.
- `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.
- `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.
- `ConstraintViolation` (interface): interface ConstraintViolation — One failed {@link CompatibilityRule}, carrying the rule id, its kind, and a human-readable message for UI or generator diagnostics.
- `CropDef` (interface): interface CropDef { id: string; stages: readonly number[]; regrowDays?: number; needsDailyWater?: boolean; harvest?: RecipeItem } — ⚠ undocumented
- `CropTileState` (interface): interface CropTileState { soil: SoilState; watered: boolean; cropId: string | null; stage: number; stageProgress: number; harvestable: boolean } — ⚠ undocumented
- `CrossThresholdsOptions` (interface): interface CrossThresholdsOptions — Exact-boundary and dead-band policy for {@link crossThresholds}.
- `Curve` (type): type Curve = CurveDef & CurveShape — A fully specified progression curve — a {@link CurveDef} growth shape plus optional {@link CurveShape} rounding/clamp.
- `DEFAULT_CHAT_BODY_LENGTH` (const): const DEFAULT_CHAT_BODY_LENGTH: 240 — ⚠ undocumented
- `DEFAULT_CHAT_HISTORY_LIMIT` (const): const DEFAULT_CHAT_HISTORY_LIMIT: 100 — ⚠ undocumented
- `DEFAULT_CHAT_RATE_LIMIT` (const): const DEFAULT_CHAT_RATE_LIMIT: ChatRateLimit — ⚠ undocumented
- `DEFAULT_ESCAPE_MULTIPLE` (const): const DEFAULT_ESCAPE_MULTIPLE: 3 — A pursuit escapes at this multiple of its keep-close distance when none is declared.
- `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.
- `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.
- `DEFAULT_MARKER_TOLERANCE` (const): const DEFAULT_MARKER_TOLERANCE: 8 — Default vertical allowance (m) for a horizontal marker proximity test.
- `DEFAULT_PICKUP_RADIUS` (const): const DEFAULT_PICKUP_RADIUS: 2 — ⚠ undocumented
- `DEFAULT_PING_CATEGORIES` (const): const DEFAULT_PING_CATEGORIES: Record<PingCategory, PingCategoryDef> — Content-agnostic default ping wheel: enemy / loot / location / danger.
- `DEFAULT_PURSUE_DISTANCE` (const): const DEFAULT_PURSUE_DISTANCE: 3 — Default keep-close distance (m) for a `pursue` objective.
- `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.
- `DEFAULT_QUEUE_WINDOW` (const): const DEFAULT_QUEUE_WINDOW: 8 — Boarding events the throughput window keeps.
- `DEFAULT_REACH_RADIUS` (const): const DEFAULT_REACH_RADIUS: 2.5 — Default proximity radius (m) for a `reach` / `interact` objective.
- `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.
- `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.
- `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.
- `DEFAULT_TOUCH_STYLE` (const): const DEFAULT_TOUCH_STYLE: TouchStyle — Skin used when neither the game nor the player picks one.
- `DecayMeterSet` (interface): interface DecayMeterSet — Set of named survival meters (hunger/thirst/…) that drain and refill over game time.
- `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.
- `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.
- `DefendMissionOptions` (interface): interface DefendMissionOptions extends ComposedMissionOptions — Options for {@link defendMission}: hold a position, scored by what is left standing.
- `DeliveryEntry` (interface): interface DeliveryEntry { id: string; userId: string; inventoryId: string; items: readonly ItemStack[]; deliverAt: number } — ⚠ undocumented
- `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
- `DialogueGraph` (interface): interface DialogueGraph — A serializable branching conversation: a start node id and the nodes it can reach.
- `DialogueGraphChoice` (interface): interface DialogueGraphChoice — One selectable response on a conversation node — the text a player clicks and the node it advances to. `kind` is a free style tag the presenter interprets; the model never reads it (no genre baked in).
- `DialogueGraphNode` (interface): interface DialogueGraphNode — One conversation node: who is speaking, the line they say, and the branches out of it. `speaker`/`speakerKind`/`portrait` are opaque display data — the model never interprets them.
- `DialogueGraphSnapshot` (interface): interface DialogueGraphSnapshot — Serializable run state — the current node id and the ids already visited.
- `DialogueGraphView` (interface): interface DialogueGraphView — The render-ready snapshot of a conversation at one node — everything a view needs to draw speaker, line, and choice buttons, with no traversal logic in the component.
- `DialogueRun` (interface): interface DialogueRun — An observable walk through a {@link DialogueGraph}: current view, choose to advance, serialize.
- `DialogueRunOptions` (interface): interface DialogueRunOptions — Options for {@link createDialogueRun}.
- `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.
- `Drop` (interface): interface Drop — A resolved loot outcome — one item or currency grant with its rolled count.
- `DurabilitySpec` (interface): interface DurabilitySpec { max: number; wearPerUse?: number; wearPerHit?: number; disableAtZero?: boolean; repair?: RepairSpec } — ⚠ undocumented
- `DurabilityState` (interface): interface DurabilityState { current: number; max: number } — ⚠ undocumented · used by `applyWear`: Apply wear to an item, tracking breakage and repair eligibility.
- `EffectRef` (interface): interface EffectRef — A reference to an effect the game knows how to apply — id plus JSON-safe params, no closures.
- `EnqueueOptions` (interface): interface EnqueueOptions — Optional per-enqueue overrides.
- `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.
- `EntityDiedEvent` (interface): interface EntityDiedEvent { instanceId: string; catalogId: string; userId?: string; displayName?: string; reason: DeathReason; source?: string; position: [number, number, number]; serverId?: string } — ⚠ undocumented
- `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
- `EntitySpriteConfig` (interface): interface EntitySpriteConfig { url: string; width: number; height: number; y: number; clip?: {atlas: SpriteAtlas; animation: string} } — ⚠ undocumented
- `EscortMissionOptions` (interface): interface EscortMissionOptions extends ComposedMissionOptions — Options for {@link escortMission}: a protected actor that must reach a destination alive.
- `EventTicker` (interface): interface EventTicker — A live, observable event/kill-feed ticker.
- `EventTickerEntry` (interface): interface EventTickerEntry extends TimedFeedEntry — A stored ticker entry — an {@link EventTickerInput} stamped with an id and clock time.
- `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", …).
- `EventTickerOptions` (interface): interface EventTickerOptions — Options for {@link createEventTicker}.
- `EventTickerSnapshot` (interface): interface EventTickerSnapshot — Serializable state of the ticker, for save/restore.
- `EventTickerView` (interface): interface EventTickerView extends EventTickerEntry — A live ticker entry as handed to the renderer: the stored entry plus a `fade` value `0..1` (age / `ttlMs`) — `0` for a fresh entry, approaching `1` as it nears expiry — so the UI can drop opacity as an entry ages out. `fade` is always `0` when no `ttlMs` is configured.
- `ExpeditionConfig` (interface): interface ExpeditionConfig<TCtx> — Runtime policy, supplied on each transition and never saved. Callbacks must be pure.
- `ExpeditionDispatch` (interface): interface ExpeditionDispatch — Dispatch data, detached from the caller's supply record. All timestamps are epoch milliseconds.
- `ExpeditionEvent` (interface): interface ExpeditionEvent — Timestamped serializable event. `at` is epoch milliseconds, compatible with `appendFeed`.
- `ExpeditionHazard` (interface): interface ExpeditionHazard — One encounter's mechanical effects and optional caller-authored notices.
- `ExpeditionState` (interface): interface ExpeditionState — Plain saveable expedition data. Persist this whole value, including the RNG cursor and tick frontier.
- `ExpeditionSupplyRule` (interface): interface ExpeditionSupplyRule — Ordered auto-consumption rule: spends one finite supply only when its declared effect changes a vital.
- `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…
- `FeedWindow` (interface): interface FeedWindow — Bounds for {@link appendFeed} / {@link pruneFeed}: newest-`limit` cap and/or `ttl` age window.
- `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.
- `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig { eyeHeight?: number; sensitivity?: number; maxPitch?: number; reticle?: boolean; viewmodel?: boolean; collision?: false | FirstPersonCollisionConfig } — ⚠ undocumented
- `FirstPersonCollisionConfig` (interface): interface FirstPersonCollisionConfig — Clearance tuning for the first-person camera's collision pull-in.
- `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.
- `FriendEntry` (interface): interface FriendEntry { userId: string; online: boolean } — ⚠ undocumented
- `FriendRequestEntry` (interface): interface FriendRequestEntry { requestId: string; fromUserId: string } — ⚠ undocumented
- `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
- `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.
- `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.
- `GameDefinition` (interface): interface GameDefinition<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> — Fully-resolved game description produced by {@link defineGameDefinition} — assets, scene, and opted-in subsystems.
- `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.
- `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.
- `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.
- `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).
- `GameLoop` (interface): interface GameLoop<TContext = unknown> — Lifecycle hooks a game implements to drive init, per-tick simulation, and player join/leave.
- `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.
- `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.
- `GameSaveConfig` (interface): interface GameSaveConfig — How a {@link createGameSave} is wired. Storage is the narrow injected {@link SaveBackend}, never `localStorage` welded in.
- `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>]`.
- `GameSaveRng` (interface): interface GameSaveRng — The world's shared injected RNG: its `seed` and the live `stream` whose cursor is persisted.
- `GameSaveRngState` (interface): interface GameSaveRngState — The persisted cursor of the world's shared injected RNG, plus the seed that produced it.
- `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.
- `GearScore` (interface): interface GearScore — A scored loadout: the total, each slot's share, each stat's signed contribution, and how complete it is.
- `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.
- `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.
- `GenChoiceRecord` (interface): interface GenChoiceRecord — Provenance for one resolved step: which option stuck, its effective weight, how many options were eligible after constraints, and how many eligible options backtracking rejected before this one. A skipped optional step is recorded with an empty `optionId`.
- `GenChoices` (interface): interface GenChoices — Read-only view of the choices resolved so far, threaded into a later step's pool, constraint, weight function, or transform so a decision can depend on earlier picks (dependent choice).
- `GenDraft` (interface): interface GenDraft — The resolved-but-unvalidated draft passed to each {@link GenValidator}: the step choices, their values, and the transformed fields. Returning false from any validator rerolls the whole generation up to the attempt budget.
- `GenFieldRecord` (interface): interface GenFieldRecord — Provenance for one field mutation a transform made: which transform, field, op, and before/after.
- `GenOption` (interface): interface GenOption<V = unknown> — One selectable option in a generation step's pool: a stable `id` used in provenance and pinning, the payload `value` a chosen option contributes, and an optional relative `weight` (default 1).
- `GenOutcome` (type): type GenOutcome = | { ok: true; result: GenResult } | { ok: false; reason: "unsatisfiable" | "rejected"; attempts: number } — The outcome of {@link generate}: either a successful {@link GenResult}, or a failure carrying the reason (`"unsatisfiable"` — constraints left no valid assignment; `"rejected"` — validators kept rejecting drafts) and the attempts spent.
- `GenPool` (type): type GenPool<V = unknown> = readonly GenOption<V>[] | ((choices: GenChoices) => readonly GenOption<V>[]) — A step's candidate options: a fixed list, or a function of the choices resolved so far so pools can narrow to earlier picks (a slot pool that depends on a chosen category).
- `GenProvenance` (interface): interface GenProvenance — The full explanation of a generated result: how many whole-pipeline attempts it took, every step choice, and every field mutation. Plain, serializable data for UI, debugging, balancing, and regeneration.
- `GenResult` (interface): interface GenResult — A successful generation: the step-to-option map, step-to-value map, transformed numeric fields, and the {@link GenProvenance} that explains them. Entirely serializable; round-trips through save/load and multiplayer sync unchanged.
- `GenSchema` (interface): interface GenSchema — A caller-defined generation schema over plain data: ordered choice steps, optional field transforms, optional validators, and bounded reroll/backtracking budgets. Genre-agnostic — it carries no built-in notion of rarity, element, weapon, or name; those are caller step and option ids.
- `GenStep` (interface): interface GenStep<V = unknown> — One decision point in a {@link GenSchema}: pick a single option from a pool, honoring an optional constraint, dependent weighting, selection mode, and optionality. Steps resolve in array order.
- `GenTransform` (interface): interface GenTransform — A named derivation over the numeric field bag, applied in schema order after all choices resolve (affix rolls, level scaling, budget spend). Each field mutation it makes is recorded as provenance.
- `GenValidator` (type): type GenValidator = (draft: GenDraft) => boolean — A final-assembly check over a {@link GenDraft}; false triggers a whole-pipeline reroll.
- `GenerateOptions` (interface): interface GenerateOptions — Per-call options for {@link generate}.
- `IdentityQuery` (interface): interface IdentityQuery — A predicate over an {@link ItemIdentity}, expressed as data so a whole rule set round-trips through JSON. An empty query matches every identity; each present field narrows the match and all present fields must hold (AND).
- `InspectionCameraConfig` (interface): interface InspectionCameraConfig — Model-viewer / inspection rig (#207.7) — orbit + pan + anchored zoom around a fixed point, never reads player input.
- `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.
- `InstalledPart` (interface): interface InstalledPart { slotId: string; part: PartDef } — ⚠ undocumented · used by `identityOf`: Assemble an {@link ItemIdentity} from a family, tags, and installed parts.
- `InventoryDeclaration` (interface): interface InventoryDeclaration — Shape of one named inventory a game declares — slot count, accepted item types, HUD binding.
- `InventorySlot` (type): type InventorySlot = { itemId: string; count: number } | null — ⚠ undocumented
- `InventoryState` (interface): interface InventoryState { slots: InventorySlot[] } — ⚠ undocumented · used by `carriedEntries` (@jgengine/core/inventory/carryLoad): Every filled stack in the given inventories as load entries, in slot order.
- `ItemIdentity` (interface): interface ItemIdentity — The declarative identity of a built modular item: a caller-named family, its provenance tags, and the parts occupying its slots. This is the "what an item is" layer above the raw stat rollup in ./modularItem — a plain, serializable value with no game noun baked in ("gun", "manufacturer", "potion" are all caller data in `family`/`tags`).
- `ItemProvenance` (interface): interface ItemProvenance — The serializable record of how an item was generated: its family, tags, per-slot part selection, applied set-bonus ids, and the deterministic seed. Enough for UI provenance display and byte-exact regeneration.
- `ItemUseHandler` (interface): interface ItemUseHandler<TState> { can?(state: TState, input: ItemUseInput): ItemUseRejection | null; apply(state: TState, input: ItemUseInput): ItemUseResult<TState> } — ⚠ undocumented
- `ItemUseInput` (interface): interface ItemUseInput { from: string; itemId: string; inventoryId?: string; aim?: Aim } — ⚠ undocumented
- `Job` (interface): interface Job<TSpec, TReserve = undefined> — One unit of timed work. Plain serializable data (given serializable `TSpec`/`TReserve`).
- `JobId` (type): type JobId = string — Generic timed work queue — a pure-data model for discrete jobs that reserve inputs, advance over game time, can be paused/cancelled, and emit an output on completion. It backs unit training, crafting jobs, construction, research, respawns, downloads, and fabrication without any of them re-implementing the reservation → progress → completion → output-routing loop.
- `JobOrdering` (type): type JobOrdering<TSpec, TReserve = undefined> = ( a: Job<TSpec, TReserve>, b: Job<TSpec, TReserve>, ) => number — Comparator over jobs; negative means the first job runs sooner.
- `JobStatus` (type): type JobStatus = "queued" | "active" | "paused" — Lifecycle phase of a single queued job. Terminal jobs are removed from state.
- `JobValidation` (interface): interface JobValidation — Result of pre-enqueue validation (population caps, prerequisites, affordability).
- `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.
- `LaneRule` (interface): interface LaneRule<C> { id: string; apply: (input: LaneRuleInput<C>) => number } — ⚠ undocumented
- `LayerConflict` (interface): interface LayerConflict — A single conflict surfaced by {@link validateLayers}.
- `LayerOps` (type): type LayerOps = Readonly<Record<string, ParamOp | readonly ParamOp[]>> — Per-parameter ops contributed by one layer — a single op or an ordered list folded in sequence.
- `LayerRegistry` (interface): interface LayerRegistry — Registered lookup of {@link ParamLayer}s by stable id, resolving serialized selections and unknowns.
- `LayerSelection` (type): type LayerSelection = readonly string[] — A serializable, ordered reference to layers by stable id — what a save file or session setup stores.
- `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.
- `LeaderboardScope` (type): type LeaderboardScope = "global" | "server" | "profile" — ⚠ undocumented
- `LedgerAdvanceResult` (interface): interface LedgerAdvanceResult — What one {@link TransactionLedger.chargeDue} settled, and what it could not.
- `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.
- `LedgerEntryFilter` (interface): interface LedgerEntryFilter — A filter over the journal.
- `LedgerEvent` (interface): interface LedgerEvent — Lifecycle signal emitted by {@link advanceLedger}.
- `LedgerEventKind` (type): type LedgerEventKind = "started" | "fired" | "skipped" | "depleted" | "ended" — The kinds of lifecycle signal {@link advanceLedger} can emit for a rule.
- `LedgerPostInput` (interface): interface LedgerPostInput — A post to attempt.
- `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.
- `LedgerState` (interface): interface LedgerState — Fully serializable ledger state: clock, balances, journal, totals, charges and cursors.
- `LedgerStats` (interface): interface LedgerStats — Counters of a ledger, for a probe or a summary line.
- `LedgerTotals` (interface): interface LedgerTotals — What one reason code did to the books, kept across entry trimming.
- `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.
- `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…
- `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).
- `LevelingTrack` (interface): interface LevelingTrack — A resolved leveling track: the immutable `maxLevel`/`startLevel`, the `xpForLevel` threshold lookup, a pure `resolve`, and `grantXp` which writes back through a {@link LevelingStatAccess} and fires `onLevelUp` once for every reached level in ascending order.
- `LifecycleConfig` (interface): interface LifecycleConfig<TState = unknown> — Declarative start/restart run lifecycle: the state transitions a game's run phase every genre repeats (title screen → live run → live run → title screen again), expressed as pure functions over one typed {@link StoreHandle} slot instead of hand-rolled `commands.define("start"/"restart")` glue that re-derives phase after every mutation. `start`/`restart` receive the store's own value type — the store's `TState`, never `ctx.game.store.get(key) as T` — and return the next value; the runtime writes it back and derives {@link GamePhase} from it via `phaseOf` in one place, so every adopting game gets identical, correct phase-sync for free.
- `LightingConfig` (interface): interface LightingConfig — Declarative lighting replacing the shell's hardcoded ambient/directional default (#207.5); mounts regardless of world kind, only when supplied.
- `Listing` (interface): interface Listing — One active post in a {@link ListingBook}: an item stack a seller offered at a fixed price until it expires.
- `LoadoutDef` (interface): interface LoadoutDef { inventories?: Record<string, LoadoutItemEntry[]>; stats?: Record<string, {current: number; max?: number; min?: number}>; economy?: Record<string, number>; unlocks?: string[] } — ⚠ undocumented
- `LoanAdvanceResult` (interface): interface LoanAdvanceResult — What one {@link LoanBook.advance} settled, and what it could not.
- `LoanBook` (interface): interface LoanBook — The loans a business owes: schedules, interest, arrears and default, posted to a ledger.
- `LoanBookOptions` (interface): interface LoanBookOptions — Options for {@link createLoanBook}.
- `LoanBookState` (interface): interface LoanBookState — Serializable loan-book state.
- `LoanBookStats` (interface): interface LoanBookStats — Counters of a loan book, for a probe or a summary line.
- `LoanPayment` (interface): interface LoanPayment — One scheduled repayment, in integer minor units.
- `LoanRecord` (interface): interface LoanRecord — One live loan: its plan plus how far it has been paid.
- `LoanRepayment` (interface): interface LoanRepayment — Outcome of an early repayment.
- `LoanSchedule` (interface): interface LoanSchedule — A full repayment plan: every payment, its interest/principal split and the running balance.
- `LoanState` (interface): interface LoanState — Saved progress of one loan; the schedule is rebuilt from its terms on restore.
- `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.
- `LockOnCameraConfig` (interface): interface LockOnCameraConfig — Lock-on / strafe rig (#26) — yaw bound to player→target, move axis becomes strafe.
- `LootBaseDef` (interface): interface LootBaseDef extends ItemBaseDef — A base family (frame, housing, chassis — caller nouns) with its slots, stats and affix pools.
- `LootCatalog` (interface): interface LootCatalog — Everything a roll reads: bases, parts, affixes, rarity odds, makers and the level curve.
- `LootComparison` (interface): interface LootComparison — How two items compare: every stat delta plus one weighted score for each.
- `LootComparisonOptions` (interface): interface LootComparisonOptions — Caller policy for the comparison score.
- `LootDropProvenance` (interface): interface LootDropProvenance — Why one drop is in the result: the stage/table/entry that produced it, its weights, and the modifiers that shaped it.
- `LootFilterRule` (interface): interface LootFilterRule { id: string; when: LootFilterCondition; hide?: boolean; color?: string; beam?: boolean; label?: string } — ⚠ undocumented · used by `evaluateLootFilter`: First matching rule wins (PoE/Last Epoch block semantics) — later rules never override an earlier match.
- `LootInstalledPart` (interface): interface LootInstalledPart — One part occupying one slot of a rolled item.
- `LootIssueCode` (type): type LootIssueCode = | "invalid-level" | "unknown-base" | "level-gated-base" | "unknown-manufacturer" | "manufacturer-base" | "unknown-rarity" | "duplicate-slot" | "unknown-slot" | "missing-slot-part" | "unknown-part" | "part-category" | "unknown-affix" | "duplicate-affix" | "invalid-affix" | "non-f… — A defect found by {@link validateLootItem}.
- `LootItem` (interface): interface LootItem — One rolled item: the base, maker, rarity, level, composed name, chosen parts, rolled affixes and resolved stats. Plain JSON, so a save stores it and the instance registry can key it.
- `LootManufacturerDef` (interface): interface LootManufacturerDef — A maker with a stat personality: its mark goes in the name, `bias` shifts stats additively, `scale` multiplies them, and favored affix pools weigh more when this maker rolls the item.
- `LootModifier` (interface): interface LootModifier<TCtx = unknown> — A registered, id-tagged loot policy applied to one stage. `plan` transforms eligibility, weights, and roll counts before rolling (luck, difficulty, gating); `drops` post-processes the rolled drops (quantity multipliers, dedupe, caps). Neither hook mutates table definitions, and the id is recorded in provenance so a resolved drop can be traced back to the policies that shaped it.
- `LootPartDef` (interface): interface LootPartDef extends PartDef — A part a base can mount: its stats, a pick weight, and an optional word for the item name.
- `LootPipeline` (interface): interface LootPipeline<TCtx = unknown> — A resolved, reusable loot pipeline. Call {@link LootPipeline.resolve} with a per-drop context and RNG.
- `LootPipelineDef` (interface): interface LootPipelineDef<TCtx = unknown> — A named, ordered loot-resolution pipeline: the stages to run plus result-shaping policy (duplicate stacking, a total drop cap). Serializable except for its stage gate/modifier functions, mirroring how {@link LootTableDef} entries may carry a `generate` function.
- `LootPipelineDeps` (interface): interface LootPipelineDeps — Dependencies a pipeline needs at build time — chiefly how to turn a table id into its definition.
- `LootPlanEntry` (interface): interface LootPlanEntry — One eligible entry inside a {@link LootRollPlan}: the original table entry plus its live eligibility and effective weight/chance. Modifiers rewrite these fields; the source `entry` object is never mutated, so table definitions stay shared and reusable.
- `LootResolution` (interface): interface LootResolution — The fully serializable outcome of a resolution: the drops, their provenance, per-stage traces, and the replay seed.
- `LootResolveContext` (interface): interface LootResolveContext<TCtx = unknown> — The caller-owned context, injected RNG, and optional seed threaded through a single resolution.
- `LootRollOptions` (interface): interface LootRollOptions — Pin any part of a roll; omitted fields are drawn from the catalog.
- `LootRollPlan` (interface): interface LootRollPlan — The mutable roll plan a stage derives from its table before rolling. Modifiers transform this — gating entries, reweighting them, or changing the roll count — instead of touching table defs.
- `LootRoller` (interface): interface LootRoller — A roll counter over one catalog: every roll goes through {@link rollLoot}, and the handle keeps counters (a distribution readout in the debug overlay) that snapshot and restore as plain data.
- `LootRollerOptions` (interface): interface LootRollerOptions — Options for {@link createLootRoller}.
- `LootRollerState` (interface): interface LootRollerState — Saved counters of a {@link LootRoller}.
- `LootStage` (interface): interface LootStage<TCtx = unknown> — One ordered step in a {@link LootPipelineDef}: a source pool (a table id or inline table), an optional context gate, a fold mode, and the modifiers that reshape its roll. Stages compose the genre concepts — world pool, dedicated pool, luck, pity — without any of them living in core.
- `LootStageKind` (type): type LootStageKind = "contribute" | "fallback" | "replace" — How a stage folds its rolled drops into the accumulating result: `"contribute"` appends, `"fallback"` rolls only when nothing has dropped yet, `"replace"` discards prior drops and overrides with its own (quest/boss overrides).
- `LootStageStatus` (type): type LootStageStatus = "rolled" | "skipped" | "empty" | "replaced" | "fell-through" — The disposition of a stage after resolution — did it roll, get gated, fall through, override, or find nothing.
- `LootStageTrace` (interface): interface LootStageTrace — Per-stage record of what happened during resolution, for debugging and replay auditing.
- `LootStatDelta` (interface): interface LootStatDelta — A per-stat comparison entry; `delta` is `b - a`, so positive means the second item is larger.
- `LootTableDef` (interface): interface LootTableDef — A named, validated loot table — its roll count, weighted-vs-independent mode, and candidate entries.
- `LootValidationIssue` (interface): interface LootValidationIssue — One reason a rolled item is not legal against its catalog, with the offending value named.
- `LootWeaponProjection` (interface): interface LootWeaponProjection — A base weapon definition plus the stat map a rolled item overrides.
- `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.
- `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.
- `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.
- `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.
- `Market` (interface): interface Market — A live market: prices from supply and demand over finite stock, with serializable state.
- `MarketConfig` (interface): interface MarketConfig — Options for {@link createMarket}: the goods and the price/demand policy they share.
- `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.
- `MarketGoodState` (interface): interface MarketGoodState — The mutable half of a good: what a save stores, with the definition kept as authored data.
- `MarketPriceInput` (interface): interface MarketPriceInput — Everything a price curve reads: the good's resolved policy plus its live stock and demand.
- `MarketQuote` (interface): interface MarketQuote — A non-mutating read of what a sale would cost and how it would move the price.
- `MarketSale` (interface): interface MarketSale — A served sale: what the buyer paid per unit and in total, in minor units.
- `MarketSaleRejection` (interface): interface MarketSaleRejection — Why a sale could not be served.
- `MarketSaleResult` (type): type MarketSaleResult = MarketSale | MarketSaleRejection — A sale outcome: the price the buyers paid, or why it could not be served.
- `MarketSnapshot` (interface): interface MarketSnapshot — Serializable market state: the mutable half of every good plus the running counters.
- `MarketStats` (interface): interface MarketStats — Counters and stocks of a market, for a probe or a summary line.
- `MissionActorFact` (interface): interface MissionActorFact — A live actor the machine tracks: whether it is alive and, when needed, where it is.
- `MissionBranch` (interface): interface MissionBranch — One outgoing edge of an objective: the first branch whose `when` matches wins over `next`.
- `MissionDef` (interface): interface MissionDef — A whole mission: the objective graph plus its fail states and rewards.
- `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.
- `MissionEventFilter` (interface): interface MissionEventFilter — Which world events an objective counts or a fail condition reacts to. Absent fields do not filter.
- `MissionFactCondition` (interface): interface MissionFactCondition — A readable fact test a branch or a `fact` fail condition reads. All comparators are optional.
- `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.
- `MissionFailDef` (interface): interface MissionFailDef — A named fail state an objective, timer or branch can land in.
- `MissionIssue` (interface): interface MissionIssue — A located mission-catalog problem; `path` is a JSON Pointer into the supplied catalog.
- `MissionMarkerPlane` (type): type MissionMarkerPlane = "horizontal" | "spatial" — Which plane a marker proximity test compares in.
- `MissionMarkerProximity` (interface): interface MissionMarkerProximity — How a positional objective compares an actor to its authored marker.
- `MissionObjectiveDef` (interface): interface MissionObjectiveDef — One objective. Every field is content; the machine reads only these.
- `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`).
- `MissionRewardAppliers` (interface): interface MissionRewardAppliers — Appliers a mission reward routes through — the same shape quests use, plus a loot-table hook.
- `MissionRewards` (interface): interface MissionRewards extends QuestRewards — What a mission pays. Economy/XP/items/unlocks flow through the quest appliers; loot names tables.
- `MissionRuntime` (interface): interface MissionRuntime — The mission state machine over one active mission.
- `MissionRuntimeConfig` (interface): interface MissionRuntimeConfig — Everything a mission runtime needs.
- `MissionRuntimeSnapshot` (interface): interface MissionRuntimeSnapshot — Serializable runtime state for a save.
- `MissionState` (interface): interface MissionState — Serializable mission state — one active mission's position in its graph.
- `MissionStats` (interface): interface MissionStats — Counters a devtools probe or a test reads.
- `MissionStatus` (type): type MissionStatus = "active" | "completed" | "failed" — Where a mission is in its life.
- `MissionTickInput` (interface): interface MissionTickInput — Everything the machine reads for one tick. All optional; a mission only touches what it declares.
- `MissionTriggerBridge` (interface): interface MissionTriggerBridge — Watches a document's authored mission triggers against moving actors.
- `MissionValidationOptions` (interface): interface MissionValidationOptions — Declarations a mission catalog is validated against.
- `MissionView` (interface): interface MissionView — Pooled per-frame readout a HUD tracker renders.
- `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.
- `MissionWorldEventKind` (type): type MissionWorldEventKind = "kill" | "collect" | "deliver" — What a reported world event is.
- `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`).
- `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.
- `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.
- `ModularItemDef` (interface): interface ModularItemDef { id: string; baseStats: Record<string, number>; slots: readonly MountSlotDef[] } — ⚠ undocumented
- `Moodle` (interface): interface Moodle — One survival moodle (status icon) — severity, source, and label for HUD chips.
- `MoodleStack` (interface): interface MoodleStack — Ordered stack of active moodles derived from meters/ailments/buffs.
- `MountSlotDef` (interface): interface MountSlotDef { id: string; accepts: string | readonly string[]; required?: boolean } — ⚠ undocumented · used by `slotAccepts`: Attach parts into an item's mount slots and resolve the combined stats.
- `MultiRegionHealth` (interface): interface MultiRegionHealth — Per-limb / per-region health track with treat/damage/heal APIs.
- `NEUTRAL_AXIS` (const): const NEUTRAL_AXIS: AxisInput — ⚠ undocumented
- `NearAgentSnapshot` (interface): interface NearAgentSnapshot — Serializable state of one near agent: where it walks, what it needs, what it last chose.
- `NearAgentView` (interface): interface NearAgentView — Everything a near agent is doing, for a HUD, a probe or a test. Allocates.
- `NearAgents` (interface): interface NearAgents — The near half of the world: the game's real simulation. Only residents inside the radius are ever spawned here, which is what keeps far agents free of navigation and utility scoring.
- `NearAgentsOptions` (interface): interface NearAgentsOptions — What the near side needs from the game: a nav mesh, the shared need definitions, and what agents can do.
- `NearCrowdAgents` (interface): interface NearCrowdAgents extends NearAgents — The near half of the off-screen world: one nav crowd for movement, one need set and utility brain per agent for what it wants. Resident identity survives the handoff because the off-screen world spawns and despawns through this seam and keeps the saved state.
- `NearHandoff` (interface): interface NearHandoff — What a near-side simulator hands back when a resident leaves range.
- `NearSpawn` (interface): interface NearSpawn — Everything a near-side simulator is told when a resident crosses into range.
- `NeedDefinition` (type): type NeedDefinition = DecayMeterConfig — A decaying need is a survival decay meter (`max`/`min`/`start`/`rate`, optional moodle thresholds) whose satisfaction an agent brain reads to score actions. The meter owns the numbers; per-need appeal lives in the game's utility options.
- `NeedReading` (interface): interface NeedReading — One need's current satisfaction, worst-first ready: `fraction` is 0 (empty) … 1 (full).
- `NeedSet` (interface): interface NeedSet — Named needs that drain or recover on game time — hunger, energy, hygiene, bladder, fun. Reads are index-addressed (`indexOf` once, `fractionAt` per tick) so a thousand-agent loop never re-resolves ids; the whole set round-trips through {@link NeedSnapshot}.
- `NeedSnapshot` (interface): interface NeedSnapshot — Serializable need state: values plus any in-play retuning, so a save keeps the dials.
- `NotificationCenterOptions` (interface): interface NotificationCenterOptions — Options for {@link createNotificationCenter}.
- `NotificationEntry` (interface): interface NotificationEntry<TMeta = unknown> — One persistent notification — unlike a transient toast, it stays in the log until dismissed.
- `NotificationFilter` (interface): interface NotificationFilter — Filter for {@link NotificationStore.list}.
- `NotificationInput` (interface): interface NotificationInput<TMeta = unknown> — Fields accepted by {@link NotificationStore.push}.
- `NotificationStore` (interface): interface NotificationStore<TMeta = unknown> — Serializable, observable log of persistent notifications with read tracking.
- `NumericBounds` (interface): interface NumericBounds — Optional inclusive `[min, max]` clamp applied after a write. Omit an edge for unbounded.
- `ObjectStyle` (interface): interface ObjectStyle { color?: string; opacity?: number; hidden?: boolean } — ⚠ undocumented
- `ObserverCameraConfig` (interface): interface ObserverCameraConfig — Detached spectator/photo cam (#120) — binds to any entity or fixed point, never reads player input.
- `OffScreenAgentView` (interface): interface OffScreenAgentView — A resident as a game or the devtools overlay reads it. Allocates a need copy — debug and tests.
- `OffScreenMode` (type): type OffScreenMode = "near" | "far" — Which side of the distance policy a resident is on: simulated near the viewer, or cheap state.
- `OffScreenOptions` (interface): interface OffScreenOptions — Options for {@link createOffScreenWorld}.
- `OffScreenPolicy` (interface): interface OffScreenPolicy — Where the near/far boundary is and what it costs. The radius, the cost model and the budget are the game's call — a city block and a haunted-house hallway do not share a number.
- `OffScreenPolicyPatch` (interface): interface OffScreenPolicyPatch — A policy change that stays reachable in play.
- `OffScreenResidentSpec` (interface): interface OffScreenResidentSpec — One resident of the world: an identity, where it belongs, and the day it follows.
- `OffScreenSnapshot` (interface): interface OffScreenSnapshot — Serializable world state: the policy and every resident, near ones included.
- `OffScreenStats` (interface): interface OffScreenStats — Counters a devtools probe or a test reads to prove far agents cost nothing.
- `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.
- `Overdraft` (type): type Overdraft = boolean | { max: number } — Opt-in debt affordance for {@link charge}/{@link chargeAll}: `true` allows the balance to go arbitrarily negative, a number caps how far into the red it may go (the charge is rejected once `balance - amount` would fall below `-max`). Omitted (the default) keeps the strict no-debt rule.
- `PING_FEED_ACTION` (const): const PING_FEED_ACTION: "party.ping" — ⚠ undocumented
- `PairKeyCodec` (interface): interface PairKeyCodec — Canonicalizes a two-part relation identity into a single delimiter-safe record key.
- `PairKeyOptions` (interface): interface PairKeyOptions — Direction and delimiter policy for {@link createPairKeyCodec}.
- `ParamContribution` (interface): interface ParamContribution — One recorded fold step — which layer's op ran and the value before/after. Contribution provenance.
- `ParamDelta` (interface): interface ParamDelta — One parameter's change between two value maps, for preview/diff surfaces.
- `ParamLayer` (interface): interface ParamLayer — A named, serializable bundle of parameter transforms with a stable id and precedence. `label` is an optional display name that may intentionally differ from the applied ops (e.g. a tier shown as "Mayhem 4" whose real multipliers are data). Higher `priority` applies later — on top — and ties break by the layer's index in the active list, so ordering is deterministic.
- `ParamOp` (type): type ParamOp = | { readonly kind: "set"; readonly value: number } | { readonly kind: "add"; readonly value: number } | { readonly kind: "multiply"; readonly value: number } | { readonly kind: "clamp"; readonly min?: number; readonly max?: number } | { readonly kind: "curve"; readonly curve: Curve } — A single transform applied to one numeric parameter. `set` overrides, `add`/`multiply` accumulate, `clamp` bounds, and `curve` remaps the running value through a {@link Curve} (the same curve primitive progression tracks use), so a caller can reshape a value non-linearly mid-stack.
- `ParamSnapshot` (interface): interface ParamSnapshot — A resolved effective-parameter snapshot: final `values` plus the ordered op trace per parameter.
- `PartDef` (interface): interface PartDef { id: string; category: string; stats?: Record<string, number>; multipliers?: Record<string, number> } — ⚠ undocumented
- `Party` (interface): interface Party { register(config: PartyConfig): void; canInvite(fromUserId: string, toUserId: string): {reason: string} | null; invite(fromUserId: string, toUserId: string): {inviteId: string} | {reason: string}; accept(userId: string, inviteId: string): … — ⚠ undocumented
- `PartyInviteEntry` (interface): interface PartyInviteEntry { inviteId: string; fromUserId: string; createdAt: number } — ⚠ undocumented
- `PartyMemberEntry` (interface): interface PartyMemberEntry { userId: string; role: PartyRole } — ⚠ undocumented
- `PhysicsConfig` (interface): interface PhysicsConfig — World gravity and jump tuning, plus the optional rigid-body backend and character capsule.
- `PingCategory` (type): type PingCategory = string — ⚠ undocumented · used by `DEFAULT_PING_CATEGORIES`: Content-agnostic default ping wheel: enemy / loot / location / danger.
- `PingSystem` (interface): interface PingSystem { classify(hit: PointerHit): PingCategory; buildPayload(from: string, hit: PointerHit, category?: PingCategory): PingPayload; broadcast(payload: PingPayload): MapMarker; ping(from: string, hit: PointerHit, category?: PingCategory): PingPayl… — ⚠ undocumented · used by `createPingSystem`: Contextual ping/marker communication between teammates, classified by what was pinged.
- `PlayableGame` (interface): interface PlayableGame<TUi = unknown, TWorldOverlay = unknown, TRenderEntity = never, TRenderObject = never, TViewmodel = unknown, TOverlay = TWorldOverlay> { game: GameDefinition; content: GameContextContent; loop: Required<Omit<GameLoop<GameContext>, "onPlayerLeave">> & Pick<GameLoop<GameContext>, "onPlayerLeave">; GameUI: TUi; presentation?: "3d" | "hud"; WorldOverlay?: TOverlay; environment… — ⚠ undocumented · used by `defineGame` (@jgengine/shell/defineGame): The one public authoring entry point: compose engine fields (systems, world, physics, input) and presentation fields (camera, HUD, audio, au…
- `PointerAxisState` (interface): interface PointerAxisState { x: number; y: number; active: boolean } — ⚠ undocumented · used by `normalizePointerToAxis`: Normalize client coordinates against a surface rect into a `PointerAxisState`, clamped to `[-1, 1]` per axis.
- `PointerConfig` (interface): interface PointerConfig — Mouse/touch pointer bindings for `defineGame({ pointer })`.
- `PointerHit` (interface): interface PointerHit — Renderer-free result of a screen→world raycast. The shell's pointer service produces this from the cursor; core-side gameplay (item.use aim, click-to-move, ground-target abilities, pings) consumes it without touching three.js.
- `PointerVec3` (type): type PointerVec3 = readonly [number, number, number] — ⚠ undocumented · used by `aimToPoint`: Build an `origin → point` aim for `item.use` / projectiles, firing toward the cursor.
- `PolicyContext` (interface): interface PolicyContext — Read-only context handed to every {@link ResourcePolicy} for a transaction.
- `PolicyRead` (type): type PolicyRead = string | ((ctx: PolicyContext) => number) — Reader over policy context: a `vars` key or a function of the context.
- `Precision` (interface): interface Precision — Deterministic rounding applied to every transaction amount before it touches balances.
- `Predicate` (type): type Predicate = | { readonly all: readonly Predicate[] } | { readonly any: readonly Predicate[] } | { readonly not: Predicate } | { readonly eq: readonly [PredicatePath, PredicateValue] } | { readonly ne: readonly [PredicatePath, PredicateValue] } | { readonly gt: readonly [PredicatePath, number] }… — One node of the predicate tree. Combinators (`all`/`any`/`not`) nest; leaf comparators read a dot path from the facts and compare it. `has` passes when the path resolves to a non-nullish value.
- `PredicateFacts` (type): type PredicateFacts = Record<string, unknown> — Plain, serializable bag of facts a predicate reads by dot path.
- `PredicatePath` (type): type PredicatePath = string — Dot path into a fact bag, e.g. `"hit.crit"` or `"attacker.team"`.
- `PredicateValue` (type): type PredicateValue = string | number | boolean | null — A declarative, serializable predicate AST evaluated against a plain fact bag. Predicates carry no closures, so they survive save/load and stay deterministic — the reusable condition seam that event-conditioned rules, quests, perks, and reactive AI gate on instead of hand-rolled callbacks.
- `PresenceInfo` (interface): interface PresenceInfo { online: boolean; serverId?: string; zoneId?: string; instanceId?: string } — ⚠ undocumented
- `PriceStats` (interface): interface PriceStats — Aggregated market stats for one item over the retained samples.
- `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…
- `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…
- `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.
- `QueueEntry` (interface): interface QueueEntry — One guest waiting their turn, and when they joined the line.
- `QueueWait` (interface): interface QueueWait — A wait estimate read off the queue's own measured throughput.
- `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.
- `RankLeaderboardOptions` (interface): interface RankLeaderboardOptions — Options for {@link rankLeaderboard}. All optional.
- `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.
- `RankedEntry` (interface): interface RankedEntry — One render-ready row of the ranked table produced by {@link rankLeaderboard}.
- `RarityStyle` (interface): interface RarityStyle — Per-rarity look of a dropped item: beam, color and label. Set via `defineGame({ worldItem: { rarityStyle } })`.
- `RateLimit` (interface): interface RateLimit — Bounded firing budget over a sliding time window.
- `RebindActionConfig` (interface): interface RebindActionConfig — One rebindable action as declared to {@link createRebindSession}. The `id` and `label` are FREE strings the session never interprets — the game owns their meaning and display text. `defaultCodes` is the authored binding the session resets back to.
- `RebindConflict` (interface): interface RebindConflict — A group of actions bound to the same normalized code — the conflict this session detects.
- `RebindRow` (interface): interface RebindRow — One controls-list row: an action, its effective binding, and any conflicts.
- `RebindSession` (interface): interface RebindSession — A live, observable, conflict-aware key-remap editor over the action-binding model.
- `RebindSessionActionsConfig` (interface): interface RebindSessionActionsConfig extends RebindSessionCommon — Declare actions explicitly, in list order.
- `RebindSessionConfig` (type): type RebindSessionConfig = RebindSessionActionsConfig | RebindSessionMapConfig — Config for {@link createRebindSession}: an explicit action list, or an {@link ActionCodesMap} + labels.
- `RebindSessionMapConfig` (interface): interface RebindSessionMapConfig extends RebindSessionCommon — Declare actions from an authored {@link ActionCodesMap}, labelled by `labels` (falling back to the id).
- `RebindSessionSnapshot` (interface): interface RebindSessionSnapshot — Serializable session state for save/restore.
- `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.
- `RecipeItem` (interface): interface RecipeItem { itemId: string; count: number } — ⚠ undocumented
- `RecurringCharge` (interface): interface RecurringCharge — A recurring charge — upkeep, rent, a subscription — settled by {@link TransactionLedger.chargeDue}.
- `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.
- `ResourceCost` (type): type ResourceCost = Readonly<Record<string, number>> — Resource costs keyed by currency/resource id.
- `ResourceLedger` (interface): interface ResourceLedger — Fully serializable scheduled-transaction state: clock, balances, rule definitions, and cursors.
- `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.
- `ResourceTransaction` (interface): interface ResourceTransaction — One resource movement produced by a due cycle, before it is applied to balances.
- `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.
- `RideBreakdown` (interface): interface RideBreakdown — Breakdown curve and money for one ride. All data, so a park tunes its own economy.
- `RideChoicePolicy` (interface): interface RideChoicePolicy — Policy a park might vary when it turns taste and ride data into utility options.
- `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.
- `RideChooserConfig` (interface): interface RideChooserConfig — Everything a ride chooser needs: the park, the guest's taste, and the guest's needs.
- `RideChooserSnapshot` (interface): interface RideChooserSnapshot — Serializable chooser state: the guest's taste and the brain's held pick.
- `RideDefinition` (interface): interface RideDefinition — Everything a ride is: its ratings, its cycle and its wear. Content, not code.
- `RidePhase` (type): type RidePhase = "idle" | "loading" | "riding" | "unloading" | "broken" — Where a ride is in its cycle.
- `RideQueueView` (interface): interface RideQueueView — A ride's line as a game or the devtools overlay reads it.
- `RideRatingRange` (interface): interface RideRatingRange — The rating scale a park's taste curves are normalized against.
- `RideRatings` (interface): interface RideRatings — What a ride is worth to a guest. All three come from the ride's own data.
- `RideRetune` (interface): interface RideRetune — In-play dials a ride accepts from {@link RideSystem.retune}.
- `RideServiceResult` (interface): interface RideServiceResult — What a service cost the caller.
- `RideStats` (interface): interface RideStats — Counters a devtools probe or test reads.
- `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.
- `RideSystemConfig` (interface): interface RideSystemConfig — Everything a ride system needs.
- `RideSystemSnapshot` (interface): interface RideSystemSnapshot — Serializable park state: the clock, each ride's cycle position, wear and line.
- `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.
- `RideTickSink` (interface): interface RideTickSink — Where a ride's boardings, alightings and breakdowns are announced. Every hook is optional.
- `RideView` (interface): interface RideView — One ride's live state.
- `RideWaitSource` (interface): interface RideWaitSource — The live queue a ride-choice candidate is costed against. {@link RideSystem} satisfies this.
- `Ring` (interface): interface Ring — ⚠ undocumented
- `RingConfig` (interface): interface RingConfig { center: RingPoint; phases: readonly RingPhase[] } — ⚠ undocumented
- `RingPhase` (interface): interface RingPhase { startTime: number; shrinkDuration: number; fromRadius: number; toRadius: number; damagePerSecond: number; center?: RingPoint } — ⚠ undocumented
- `RoleSpec` (interface): interface RoleSpec { id: string; count?: number; ratio?: number } — ⚠ undocumented
- `Rotation` (type): type Rotation = 0 | 1 | 2 | 3 — ⚠ undocumented · used by `canPlace` (@jgengine/core/inventory/shapedGrid): Check bounds and overlap for a discrete footprint, optionally ignoring the item being moved.
- `RoundConfig` (interface): interface RoundConfig<TPhase extends string = RoundPhase> { phases: Record<TPhase, number>; teams: readonly string[] | readonly RoundTeam[]; phaseOrder?: readonly TPhase[]; winCondition?: (state: RoundSnapshot<TPhase>) => string | null; maxRounds?: number; winReward?: number; lossBonus?: LossBonus… — ⚠ undocumented
- `RoundSnapshot` (interface): interface RoundSnapshot<TPhase extends string = RoundPhase> { round: number; phase: TPhase; timeLeft: number; scores: Record<string, number>; lossStreaks: Record<string, number>; roles: Record<string, string | undefined>; matchOver: boolean; pendingWinner: string | null } — ⚠ undocumented
- `RoutineConfig` (interface): interface RoutineConfig — Everything needed to resolve a routine: its authored stops, its cycle, and how far apart places are.
- `RoutinePhase` (interface): interface RoutinePhase — Where a routine puts its agent at one instant.
- `RoutineStop` (interface): interface RoutineStop — One stop after travel is accounted for: the authored time and the time the agent really gets there.
- `RoutineStopSpec` (interface): interface RoutineStopSpec — One authored stop in a day: where the agent belongs, and when it wants to get there.
- `RoutineTimeline` (interface): interface RoutineTimeline — An authored day resolved against time: arrival times after walking, departures early enough to make the next stop, and a phase for any instant. Pure — there is no state to tick, so a far agent and a loaded save read the same day from the same clock.
- `RtsCameraConfig` (interface): interface RtsCameraConfig extends TopDownCameraConfig — Free-pan / edge-scroll RTS rig (#24) — pan/rotate/zoom independent of any avatar.
- `RuleCursor` (interface): interface RuleCursor — Mutable per-rule progress, kept separate from the immutable {@link ScheduledRule} definition.
- `RuleDef` (interface): interface RuleDef<TPayload = unknown> — A selectable rule over a tagged pool. `tags` classify it for include/exclude filtering and for `requires`/`conflicts` matching (which match either another rule's id or one of its tags). `layers` are the parameter layers this rule contributes when active; `payload` is opaque caller data.
- `RuleEffectDefinition` (interface): interface RuleEffectDefinition — A declared effect a triggered rule may reference. Behavior lives in the game; this is metadata.
- `RuleEvent` (interface): interface RuleEvent — A typed event handed to the engine; roles feed target resolution, facts feed the predicate.
- `RuleFiring` (interface): interface RuleFiring — The outcome of matching one rule against one event. `applied` is the effect the caller should now run through its own effect system; a blocked firing reports why. Provenance (rule, owner, event, timestamp) rides along for auditability.
- `RuleRegistry` (interface): interface RuleRegistry<TPayload = unknown> — Registered pool of {@link RuleDef}s — the install seam games register mutators/modes/events into.
- `RuleSelection` (interface): interface RuleSelection<TPayload = unknown> — The result of a selection — the chosen rules and their ids (a serializable {@link LayerSelection}-style list).
- `RuleSelectionConfig` (interface): interface RuleSelectionConfig — Deterministic selection inputs — plain serializable data a host can persist and replay.
- `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.
- `RunModifierOffer` (interface): interface RunModifierOffer<TStat extends string = string, TData = unknown> { id: string; weight: number; maxStacks?: number; label?: string; stats?: StatModifierSet<TStat>; data?: TData } — ⚠ undocumented
- `SaleRecord` (interface): interface SaleRecord — One completed sale recorded into a {@link PriceHistory}.
- `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 }`.
- `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.
- `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.
- `SaveSlotWrite` (interface): interface SaveSlotWrite — What a {@link SaveSlots.write} stamps onto a slot — a name and/or a fresh `meta` bag.
- `SaveSlots` (interface): interface SaveSlots — A serializable, observable index of save/profile slot *metadata* that a save-select menu renders. It complements `createSaveStore` (which owns the actual save payload and named slots) by carrying the per-slot display fields the store does not: name, empty flag, last-saved time, and a free-string `meta` bag the game fills. Nothing here is genre-specific.
- `SaveSlotsConfig` (interface): interface SaveSlotsConfig — How a {@link createSaveSlots} index is wired.
- `SaveSlotsSnapshot` (interface): interface SaveSlotsSnapshot — Serializable state of a {@link SaveSlots} index, for save/restore.
- `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.
- `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.
- `SaveTimers` (interface): interface SaveTimers — The timer seam autosave schedules through — defaults to the ambient `setTimeout`/`clearTimeout`; inject fakes in tests.
- `ScheduledDelivery` (interface): interface ScheduledDelivery { userId: string; inventoryId: string; items: readonly ItemStack[]; deliverAt: number } — ⚠ undocumented
- `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.
- `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.
- `SetBonus` (interface): interface SetBonus — A match/set bonus: extra stats granted when enough parts (or a tag) of a given kind are present — e.g. "3 Blackwood parts grant +recoil control". Counting is declarative (`countBy`/`value`) so the whole catalog is data.
- `ShapeTable` (type): type ShapeTable<TShape extends string = string> = Record< TShape, readonly (readonly (readonly [number, number])[])[] > — ⚠ undocumented
- `ShopBuyRejection` (type): type ShopBuyRejection = "unknown-item" | "out-of-stock" | "insufficient-funds" — Why a {@link ShopStock.buy} was refused.
- `ShopBuyResult` (type): type ShopBuyResult = | { ok: true; wallet: WalletState; entry: ShopStockEntry } | { ok: false; reason: ShopBuyRejection } — Result of {@link ShopStock.buy}: on success the caller receives the debited `wallet` to adopt and a snapshot of the purchased `entry` (post-decrement); on failure a `reason` and the wallet is untouched.
- `ShopPrice` (interface): interface ShopPrice — A price tag: how much of a free-string `currency` an entry costs (buy) or returns (sell). `amount` is a non-negative finite number; `0` means free (no wallet charge/grant happens).
- `ShopSellRejection` (type): type ShopSellRejection = "unknown-item" | "not-sellable" — Why a {@link ShopStock.sell} was refused.
- `ShopSellResult` (type): type ShopSellResult = | { ok: true; wallet: WalletState; entry: ShopStockEntry } | { ok: false; reason: ShopSellRejection } — Result of {@link ShopStock.sell}: on success the caller receives the credited `wallet` and a snapshot of the sold `entry` (post-restock); on failure a `reason` and the wallet is untouched.
- `ShopStock` (interface): interface ShopStock — A live, observable vendor/shop stock operating over a caller-owned wallet.
- `ShopStockConfig` (interface): interface ShopStockConfig — Config for {@link createShopStock}: the initial set of entries.
- `ShopStockEntry` (interface): interface ShopStockEntry — One item a vendor stocks. Fully serializable; `kind` and `currency` are free strings the model never branches on.
- `ShopStockSnapshot` (interface): interface ShopStockSnapshot — Serializable state of a shop's stock, for save/restore.
- `ShoulderCameraConfig` (interface): interface ShoulderCameraConfig — Over-the-shoulder combat rig (#25) — offset, ADS, shoulder swap, decoupled reticle.
- `SideScrollCameraConfig` (interface): interface SideScrollCameraConfig — Fixed lateral 2.5D follow (side-on platformer cam): the camera sits perpendicular to the travel axis, tracks the followed entity, and never reads player look input.
- `SkillActiveDef` (interface): interface SkillActiveDef — An action a node or synergy unlocks, shaped to bind straight into `createAbilityKit`'s slot config.
- `SkillNodeDef` (interface): interface SkillNodeDef<TStat extends string = string> — One authored tree node. Every field except `id` is optional data, so a game states its own tree: what a rank costs, what must come first, the passive it folds in and the actions it opens.
- `SkillRequirement` (interface): interface SkillRequirement — One node that must be at or above `rank` for a node or synergy to open; `rank` defaults to `1`.
- `SkillResolution` (interface): interface SkillResolution<TStat extends string = string> — The whole outcome of a build: merged passives, unlocked actions, live synergies and point accounting.
- `SkillSpendReason` (type): type SkillSpendReason = | "unknown-node" | "max-rank" | "no-points" | "requires" | "branch-points" | "excluded" — Why a spend was refused; each reason is reachable from authored data, so a UI can say which rule bit.
- `SkillSpendResult` (type): type SkillSpendResult = | { ok: true; spent: number; pointsAvailable: number } | { ok: false; reason: SkillSpendReason; detail: string } — The outcome of one spend or legality check: what it costs and the balance after it, or the rule that stopped it.
- `SkillSynergyDef` (interface): interface SkillSynergyDef<TStat extends string = string> — A payoff that exists only when two or more nodes are ranked together. This is what rewards breadth over dumping every point into one branch.
- `SkillTree` (interface): interface SkillTree<TStat extends string = string> — A live skill tree over one authored config, with respec, snapshot/restore and an optional devtools probe.
- `SkillTreeConfig` (interface): interface SkillTreeConfig<TStat extends string = string> — Everything {@link createSkillTree} reads: nodes, optional synergies, and starting points.
- `SkillTreeState` (interface): interface SkillTreeState — Saved tree state: unspent points and the rank of every ranked node.
- `SlotGrid` (type): type SlotGrid<T> = readonly Slot<T>[] — ⚠ undocumented
- `Social` (interface): interface Social { friends: Friends; party: Party; presence: {get(userId: string): PresenceInfo}; emotes: Emotes; worldInvites: WorldInvites; snapshot(): SocialSnapshot; hydrate(data: SocialSnapshot): void } — ⚠ undocumented · used by `createSocial`: Emotes and lightweight social interactions between nearby players.
- `SocialDeps` (interface): interface SocialDeps { events: GameEvents; presence?: (userId: string) => PresenceInfo; now?: () => number; emotes?: EmotesDeps; worldInviteTtlMs?: number } — ⚠ undocumented · used by `createSocial`: Emotes and lightweight social interactions between nearby players.
- `StackPolicy` (type): type StackPolicy = "refresh" | "stack" | "independent" | "ignore" — How a repeated application of the same rule's effect on the same target combines with a live one: `refresh` re-arms the timer at one stack, `stack` adds a stack up to `maxStacks` and re-arms, `independent` keeps each application as its own instance with its own expiry, `ignore` drops the new application while one is already active.
- `StaffedStation` (interface): interface StaffedStation — Serializable staffing snapshot. The caller owns assignment, unique worker ids, and stable order.
- `StatContribution` (interface): interface StatContribution — One folded contribution to a value, retained so a sheet can explain "why is this value 42?" — every step carries the source that produced it.
- `StatContributionStep` (interface): interface StatContributionStep extends StatContribution — One line of a provenance trace: a contribution plus the running total after it folds in.
- `StatDeriveContext` (interface): interface StatDeriveContext — The read-only view a derived formula gets: resolved values of its declared dependencies.
- `StatDerivedDef` (interface): interface StatDerivedDef — A derived value whose formula and dependencies are caller-owned. `compute` may return a scalar (shorthand for a single `add`) or an ordered list of contributions folded left-to-right, so additive/multiplicative/clamped and conditional modifiers are all expressed as plain data or branches inside the function.
- `StatExplanation` (interface): interface StatExplanation — A full provenance trace for one stat: the ordered steps that produced its value.
- `StatGraph` (interface): interface StatGraph — A compiled, immutable stat-graph schema that mints per-entity {@link StatSheet}s from base values or saved state.
- `StatGraphDef` (interface): interface StatGraphDef — The full schema of a stat graph: its named inputs and caller-authored derived formulas.
- `StatInputDef` (interface): interface StatInputDef — A game-owned named input value. The engine ships no attribute vocabulary — ids, bounds, defaults, and metadata are entirely caller data, so the same graph can model STR/AGI/INT, SPECIAL scores, skills, difficulty knobs, or anything else.
- `StatLevelUpEvent` (interface): interface StatLevelUpEvent { userId: string; stat: string; level: number } — ⚠ undocumented
- `StatModEntry` (type): type StatModEntry = StatContribution | readonly StatContribution[] — A modifier entry targeting one stat: a single contribution or an ordered list.
- `StatOp` (type): type StatOp = "add" | "mul" | "override" | "clampMin" | "clampMax" — How a single contribution folds into a running value.
- `StatSheet` (interface): interface StatSheet — A live per-entity instance of a {@link StatGraph}: mutable base values and modifier sources over a shared schema.
- `StatSheetState` (interface): interface StatSheetState — Plain-data, JSON-safe sheet state: input base values plus registered modifier sources.
- `StationRateTuning` (interface): interface StationRateTuning — Caller-owned output tuning in production cycles per game-second.
- `StationWorker` (interface): interface StationWorker — One assigned worker's caller-resolved contribution; stat names and modifiers stay caller-owned.
- `SystemDefinition` (interface): interface SystemDefinition — A reusable game capability — lifecycle, timing, events, and optional save / replication / reset / disposal. Pass instances via `defineGame({ systems })`. Prefer one system per meaningful capability (`combat`, `quests`), not per micro-tick.
- `SystemEventHandlers` (type): type SystemEventHandlers = { readonly [eventName: string]: (ctx: GameContext, event: unknown) => void; } — Event name → handler. Payload is the engine event shape for that name.
- `SystemTick` (type): type SystemTick = | { type: "fixed"; /** Steps per game-second. Default 60. */ rate?: number; stage?: string; after?: string | readonly string[]; before?: string | readonly string[]; } | { type: "frame"; stage?: string; after?: string | readonly string[]; before?: string | readonly string[]; } | { t… — How a system is scheduled. Omit `tick` (or use only `events`) for event-driven systems. Multiple systems may share the same channel; order within a channel is deterministic by stage then optional `before`/`after` constraints — never import order.
- `TOUCH_STYLES` (const): const TOUCH_STYLES: readonly TouchStyle[] — Every touch skin id, in menu order.
- `TOUCH_STYLE_OPTIONS` (const): const TOUCH_STYLE_OPTIONS: readonly { value: TouchStyle; label: string }[] — Touch skins as `{ value, label }` rows for the Settings → Controls selector.
- `TalentEdgeView` (interface): interface TalentEdgeView — One prerequisite edge into a node — the source node, the rank it demands, and whether that is met.
- `TalentNodeDef` (interface): interface TalentNodeDef<TStat extends string = string> { id: string; branch?: string; maxRank: number; requires?: readonly TalentRequirement[]; requiresPointsInBranch?: number; modifiersPerRank?: StatModifierSet<TStat>; grantsAbilities?: readonly string[] } — ⚠ undocumented · used by `talentTreeView`: Project the existing talent model (`createTalentTree`) into a flat, serializable render view: every node placed by branch + prerequisite-dep…
- `TalentNodeState` (type): type TalentNodeState = "locked" | "available" | "learned" | "maxed" — Render state of a talent node, derived from its rank and prerequisite satisfaction. - `locked` — rank 0 and at least one prerequisite unmet; cannot be trained yet. - `available` — rank 0, every prerequisite met; ready to take a first point. - `learned` — at least one rank invested, but below `maxRank`. - `maxed` — fully invested (`rank === maxRank`).
- `TalentNodeStatus` (interface): interface TalentNodeStatus — Per-node status a game supplies to build a view from *any* unlock rule — not just point-spend. A game computes these from whatever it wants (a currency threshold, a level, a quest flag, a skill-point pool, nothing at all) so the same widget renders a buy-with-points talent tree, a money-gated upgrade tree, or a condition-unlocked ability web without changing the renderer.
- `TalentNodeView` (interface): interface TalentNodeView — A per-node view for rendering: grid placement (tier/branch), rank, state, and inbound prerequisite edges.
- `TalentPointTotals` (interface): interface TalentPointTotals — Optional overall point totals for the view header; omit (or 0) for trees that spend no point currency.
- `TalentTree` (interface): interface TalentTree<TStat extends string = string> { rank(nodeId: string): number; pointsAvailable(): number; pointsSpent(): number; pointsInBranch(branch: string): number; grantPoints(amount: number): void; canAllocate(nodeId: string): TalentAllocateResult; allocate(nodeId: string): Talent… — ⚠ undocumented · used by `talentTreeView`: Project the existing talent model (`createTalentTree`) into a flat, serializable render view: every node placed by branch + prerequisite-dep…
- `TalentTreeView` (interface): interface TalentTreeView — A whole-tree render view: placed nodes plus branch/tier extents and point totals.
- `TargetRole` (type): type TargetRole = "subject" | "object" | "source" | "owner" — Role slots an event exposes; a target selector resolves one of these to a concrete id.
- `TargetSelector` (type): type TargetSelector = | { readonly role: TargetRole } | { readonly path: string } | { readonly literal: string } — How a rule picks the id its effect lands on: a fixed event role, a dot path into the event facts, or a literal id. Data-only so it saves with the rule.
- `TechNodeDef` (interface): interface TechNodeDef extends UnlockDef { requires?: readonly string[]; cost?: Readonly<Record<string, number>>; grants?: readonly string[]; recipe?: string } — ⚠ undocumented
- `ThresholdBand` (interface): interface ThresholdBand — A `{ min, factor }` band for {@link thresholdScale}; the highest band whose `min` is met wins.
- `ThresholdBoundary` (interface): interface ThresholdBoundary<Id = string> — A labelled cut point on the value axis. `Id` is caller-owned (string, enum, or a policy object).
- `ThresholdCrossing` (interface): interface ThresholdCrossing<Id = string> — A single boundary transition between a `before` and `after` value.
- `ThresholdDirection` (type): type ThresholdDirection = "up" | "down" — Generic threshold-crossing detection over ordered numeric boundaries.
- `TickResult` (interface): interface TickResult<TSpec, TReserve = undefined, TOutput = undefined> — Outcome of {@link tick}: advanced state plus the events produced.
- `TieMode` (type): type TieMode = "standard" | "dense" — How equal scores share ranks: - `"standard"` (competition ranking): ties share a rank and the next distinct score skips ahead — `1, 2, 2, 4`. - `"dense"`: ties share a rank and the next distinct score is the very next integer — `1, 2, 2, 3`.
- `TimeScaledRarityOptions` (interface): interface TimeScaledRarityOptions — Caller-authored weighting curve; item ids, quality tiers and balance never live in the modifier.
- `TimedFeedEntry` (interface): interface TimedFeedEntry — Any feed entry carrying a game-time (or wall-clock) `at` stamp for age-based pruning.
- `Toast` (interface): interface Toast<T = string> — A transient HUD message that expires on its own — banner, pickup note, alert.
- `TopDownCameraConfig` (interface): interface TopDownCameraConfig — Fixed top-down / isometric rig (#23) — height/pitch/yaw + decoupled follow.
- `TouchAnchor` (type): type TouchAnchor = | "bottom-left" | "bottom-center" | "bottom-right" | "left" | "right" | "top-left" | "top-center" | "top-right" — Screen zone a touch cluster or button docks to. The four corners plus the mid `left`/`right` rails (vertical stacks, MMO-style hotbars) and the `bottom-center` / `top-center` strips let controls use the whole viewport instead of piling into one bottom bar.
- `TouchButton` (interface): interface TouchButton { action: string; label: string; icon: string | false | null; kind: TouchButtonKind; shape: TouchButtonShape; anchor: TouchAnchor | null; image: string | null } — ⚠ undocumented
- `TouchButtonShape` (type): type TouchButtonShape = "circle" | "square" | "pedal" | "lever" | "trigger" | "wheel" | "tab" — Physical silhouette a touch button wears. The capture layer draws each as its own shape — a `pedal` reads as a foot pedal, a `lever` as a pull handle, a `trigger` as a firing paddle — so a control looks like the thing it does instead of a labelled circle. `circle`/`square` are the neutral fallbacks.
- `TouchControlsConfig` (interface): interface TouchControlsConfig — Game-authored refinement of the derived touch scheme on `defineGame({ touch })` — gestures, curated buttons, hidden actions, cluster layout, skin, and per-context `modes`.
- `TouchControlsModeConfig` (type): type TouchControlsModeConfig = Omit<TouchControlsConfig, "modes"> — One named control context's touch config — the same shape as the base config, minus nested modes.
- `TouchJoystick` (interface): interface TouchJoystick { up: string | null; down: string | null; left: string | null; right: string | null } — ⚠ undocumented
- `TouchScheme` (interface): interface TouchScheme { joystick: TouchJoystick | null; buttons: readonly TouchButton[]; gestures: TouchGestureBindings | null; look: boolean; lookSensitivity: number; layout: ResolvedTouchLayout; style: TouchStyle } — ⚠ undocumented · used by `deriveTouchScheme`: Null means "render no touch controls" — either the game opted out or there is nothing to synthesize.
- `TouchStyle` (type): type TouchStyle = "glass" | "arcade" | "mechanical" | "minimal" — Player-selectable skin for the whole touch layer. A style is a material + geometry preset (not just colours), chosen in Settings → Controls and persisted; `glass` is the translucent default, the rest are opt-in looks.
- `TrackedObjectiveView` (interface): interface TrackedObjectiveView — One objective as a tracker/HUD reads it — label + progress toward its count.
- `TrackedQuestView` (interface): interface TrackedQuestView — A quest as a tracker/HUD reads it — title, status, and per-objective progress.
- `TrainableUnitDef` (interface): interface TrainableUnitDef — A unit the producer can train.
- `TransactionLedger` (interface): interface TransactionLedger — The books: balances with a reason-tagged journal, and recurring charges on a cadence.
- `TransactionLedgerOptions` (interface): interface TransactionLedgerOptions — Options for {@link createTransactionLedger}.
- `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.
- `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.
- `TriggeredRuleEngine` (interface): interface TriggeredRuleEngine — A running set of triggered rules with gating, timed lifetimes, stacking, cleanup, and save/load.
- `TriggeredRuleState` (interface): interface TriggeredRuleState — Serializable runtime state — everything that changes future triggers. Rules travel with it.
- `TurnLoop` (interface): interface TurnLoop<TAction = unknown> { readonly commit: CommitController<TAction>; state(): TurnState; order(): readonly string[]; active(): string | null; phase(): string | null; round(): number; setOrder(order: readonly string[], keepActive?: boolean): TurnState; addParticip… — ⚠ undocumented
- `UnitReservation` (interface): interface UnitReservation — Reservation stored on a training job — the inputs to charge and refund.
- `UnitSpawnOrder` (interface): interface UnitSpawnOrder — Completion payload: everything a spawn/rally adapter needs, and nothing it doesn't.
- `UnitTrainingOptions` (interface): interface UnitTrainingOptions — Config knobs for {@link unitTrainingConfig}.
- `UnitTrainingSpec` (interface): interface UnitTrainingSpec — What the caller asks the queue to build.
- `UnlockDef` (interface): interface UnlockDef { id: string; category?: string } — ⚠ undocumented · used by `createUnlockCatalog`: A catalog of unlockable content gated behind conditions the player earns, tracking what is unlocked.
- `UseBehaviorContext` (interface): interface UseBehaviorContext<TWorld> — The context handed to each behavior hook: the shared folded `world`, this behavior's own `config` and `state` slice, and the triggering use input.
- `UseBehaviorDef` (interface): interface UseBehaviorDef<TWorld> — A registered behavior implementation. The combat/game side registers these (charge, thrown-reload, projectile-replacement, …); the item core only ever stores a {@link UseBehaviorRef} to one by id. Hooks are the lifecycle: `init` builds serializable state, `can` gates, `apply` folds the world.
- `UseBehaviorOutcome` (interface): interface UseBehaviorOutcome<TWorld> — The result of applying one behavior: the (possibly advanced) world, this behavior's updated state, an optional error that aborts the chain, and an optional `stop` that ends the chain after a successful apply.
- `UseBehaviorRef` (interface): interface UseBehaviorRef — The reference an item stores for one composed behavior: a stable behavior id, optional config, and an optional order override. Pure data — the item core never holds the implementation, only this reference.
- `UseBehaviorRegistry` (interface): interface UseBehaviorRegistry<TWorld> — A registry of use-behavior implementations plus a composer that turns an item's stored refs into an ordered, conflict-checked {@link ComposedUse}.
- `UseBehaviorRejection` (interface): interface UseBehaviorRejection — A reason a behavior refused a use, surfaced from `can`.
- `VfxInstancePatch` (interface): interface VfxInstancePatch — A partial update to a live retained VFX instance. Only the provided fields change; `params` is shallow-merged so a caller can nudge one knob without resending the whole bag. Setting a field to `undefined` clears it. Applying a patch refreshes the instance heartbeat.
- `VfxInstanceSpec` (interface): interface VfxInstanceSpec — The serializable specification for creating (or replacing) a retained VFX instance. Unlike a one-shot `combat.vfx` burst this describes a long-lived effect whose endpoints and parameters are updated over time. `id` is caller-stable so repeated `upsert` calls address the same effect; omit it to mint one. `from`/`to` are {@link VfxRef}s (an entity instance id or a world point) that a renderer resolves each frame, so an endpoint bound to a moving entity follows it without any per-frame command traffic.
- `VfxInstanceState` (interface): interface VfxInstanceState — The stored, fully-resolved form of a retained VFX instance. It is a plain serializable record so hosts can replicate it and debug tooling can inspect it; renderers receive it verbatim and never merge partial state themselves. `updatedAtMs` is the last create/update time and drives TTL heartbeat eviction.
- `VfxInstanceStopOptions` (interface): interface VfxInstanceStopOptions — Options for {@link VfxInstanceStore.stop}.
- `VfxInstanceStore` (interface): interface VfxInstanceStore — A headless registry of retained VFX instances: create/replace, partially update, and stop long-lived effects addressed by stable id, independent of any renderer. It owns the authoritative serializable state and exposes inspection counts; wire {@link VfxInstanceStoreOptions.onOp} to a renderer (via the `combat.vfxInstance` event) to drive visuals.
- `VfxInstanceStoreOptions` (interface): interface VfxInstanceStoreOptions — Options for {@link createVfxInstanceStore}.
- `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.
- `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.
- `Visitor` (interface): interface Visitor — One visitor on site: the id its body, its needs and its money are keyed by.
- `VisitorFlow` (interface): interface VisitorFlow — What a flow policy reads to decide how many arrive and when one has had enough.
- `VisitorPolicy` (interface): interface VisitorPolicy — The game's flow policy: what draws visitors in, how many fit, and when one has had enough.
- `VisitorPolicyPatch` (interface): interface VisitorPolicyPatch — Flow policy fields a scenario can change in play.
- `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.
- `VisitorPopulationOptions` (interface): interface VisitorPopulationOptions — Options for {@link createVisitorPopulation}.
- `VisitorPopulationSnapshot` (interface): interface VisitorPopulationSnapshot — Serializable state. No on-site count is stored: it is the restored visitor list.
- `VisitorPopulationStats` (interface): interface VisitorPopulationStats — Counters a HUD, a probe or a test reads. The on-site figure is the visitor list's length.
- `VisitorWorld` (interface): interface VisitorWorld — The game's world behind every counted visitor: it creates and removes the body.
- `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).
- `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.
- `WaitQueueOptions` (interface): interface WaitQueueOptions — Tunables for {@link createWaitQueue}, every one retunable through a restore.
- `WaitQueueSnapshot` (interface): interface WaitQueueSnapshot — Serializable line state: who is waiting, and the boardings the estimate is measured from.
- `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.
- `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}.
- `WorkQueueState` (interface): interface WorkQueueState<TSpec, TReserve = undefined> — Serializable queue state. Holds only non-terminal jobs, so it stays bounded.
- `WorldInvite` (interface): interface WorldInvite extends WorldInviteTarget { id: string; fromUserId: string; toUserId: string; createdAt: number } — ⚠ undocumented
- `WorldInviteTarget` (interface): interface WorldInviteTarget { serverId: string; joinCode?: string } — ⚠ undocumented
- `WorldItemRecord` (interface): interface WorldItemRecord { instanceId: string; itemId: string; rarity: string; baseType: string; count: number; affixTier?: number; source?: string; droppedAt: number } — ⚠ undocumented · used by `useNearestWorldItem` (@jgengine/react): Nearest ground item within `radius` of the local player — drives a pickup prompt/highlight.
- `WorldItemRenderConfig` (interface): interface WorldItemRenderConfig { rarityStyle?: Record<string, RarityStyle>; filter?: readonly LootFilterRule[]; pickupRadius?: number; beamHeight?: number; autoPickup?: boolean | {radius?: number} } — ⚠ undocumented · used by `WorldItems` (@jgengine/shell/world/WorldItems): Rarity→beam/color/label render binding + loot-filter overlay (#32/#33) for every dropped `worldItem`.
- `WorldOverlayProps` (interface): interface WorldOverlayProps — Props handed to a `WorldOverlay` component (#542): explicit `ctx` access so canvas-layer VFX read live engine state directly, without an extra hook or a module-global workaround.
- `XpCurve` (interface): interface XpCurve — A resolved, validated {@link XpCurveDef}: thresholds, lifetime totals, a stated rule, and a leveling track bound to the same numbers.
- `XpCurveDef` (interface): interface XpCurveDef — Authorable XP curve data. Thresholds are generated from one growth rule, so a game states its curve and its cap instead of hand-writing a table it cannot rebalance, and every consumer of the same data agrees on the numbers.
- `XpGrowthRule` (type): type XpGrowthRule = "flat" | "linear" | "power" | "geometric" | "table" — Named rule a level threshold grows by. `flat` repeats `step`; `linear` adds `growthRate` per level; `power` uses `level ^ growthRate`; `geometric` multiplies by `growthRate`; `table` reads `table`.
- `XpLevelStep` (interface): interface XpLevelStep — One row of a resolved curve: the threshold at `level`, and the lifetime XP it sits at.
- `activeJobs` (function): function activeJobs<TSpec, TReserve>(state: WorkQueueState<TSpec, TReserve>): Job<TSpec, TReserve>[] — Jobs currently progressing.
- `activeSetBonuses` (function): function activeSetBonuses(identity: ItemIdentity, bonuses: readonly SetBonus[]): SetBonus[] — Select the set bonuses whose membership count meets their threshold, in the order they were declared.
- `activeTouchControlsMode` (function): function activeTouchControlsMode(ctx: GameContext): string | null — The active touch control mode, `null` when the base config applies.
- `addScheduledRule` (function): function addScheduledRule(ledger: ResourceLedger, rule: ScheduledRule): ResourceLedger — Register a recurring rule and seed its cursor. Returns a new ledger; the rule's first cycle is due at `rule.startSeconds` (defaulting to the current clock).
- `addValue` (function): function addValue(record: Record<string, number>, key: string, delta: number, bounds?: NumericBounds): number — Add `delta` to `key` (clamped to `bounds`), writing the record in place. Returns the stored value.
- `advanceLedger` (function): function advanceLedger(ledger: ResourceLedger, toSeconds: number, options: AdvanceOptions = {}): AdvanceResult — Advance the ledger clock to `toSeconds`, settling every due cycle deterministically. Rules are processed in sorted-id order; cycle counts are integer math; large deltas are bounded by `catchUp`, `maxCatchUpCycles`, and `maxCyclesPerRule`. Every produced transaction flows through the policy pipeline (transform, cap, reject, split, redirect, annotate) before it is quantised and applied to balances.
- `advanceTransport` (function): function advanceTransport(path: TransportPath, items: readonly TransportItem[], dt: number): { items: TransportItem[]; delivered: TransportItem[] } — ⚠ undocumented
- `aimToPoint` (function): function aimToPoint(origin: PointerVec3, point: PointerVec3): Aim — Build an `origin → point` aim for `item.use` / projectiles, firing toward the cursor.
- `annotate` (function): function annotate(tag: string): ResourcePolicy — Append a provenance tag to a transaction without changing its value.
- `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.
- `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.
- `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.
- `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.
- `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).
- `applyWear` (function): function applyWear(state: DurabilityState, amount: number): DurabilityState — Apply wear to an item, tracking breakage and repair eligibility.
- `assertLootCatalog` (function): function assertLootCatalog(catalog: LootCatalog): void — Check a catalog before rolling; throws `RangeError` naming the offending entry.
- `assertSkillTreeConfig` (function): function assertSkillTreeConfig<TStat extends string>(config: SkillTreeConfig<TStat>): void — Check tree data before play; throws `RangeError` naming the offending node, requirement or synergy.
- `assertXpCurve` (function): function assertXpCurve(def: XpCurveDef): void — Check curve data before use; throws `RangeError` naming the offending field.
- `balance` (function): function balance(state: WalletState, currency: string | CurrencyDefinition): number — ⚠ undocumented
- `balanceOf` (function): function balanceOf(ledger: ResourceLedger, account: string, currency: string): number — Read a single balance; unknown account/currency pairs read as `0`.
- `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.
- `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).
- `canCraft` (function): function canCraft(state: InventoryState, layout: InventoryLayout, traits: ItemTraits, recipe: RecipeDef, context: CraftContext = {}): CraftCheck — ⚠ undocumented
- `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.
- `cancelRule` (function): function cancelRule(ledger: ResourceLedger, ruleId: string): ResourceLedger — Remove a rule and its cursor entirely (hard cancellation).
- `candidateViolatesForbid` (function): function candidateViolatesForbid(partial: ItemIdentity, candidate: CandidatePlacement, rules: readonly CompatibilityRule[]): ForbidRule | null — The generic backtracking contract for procedural generation (see #908): given a partial identity and a candidate part, return the first forbid rule the placement would violate, or null if it stays viable. Require rules are ignored here because they may still be satisfied by a later placement.
- `capAmount` (function): function capAmount(max: number | ((ctx: PolicyContext) => number)): ResourcePolicy — Clamp a transaction's amount to at most `max` (a fixed number or a function of context).
- `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.
- `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.
- `chargeAll` (function): function chargeAll(state: WalletState, costs: Readonly<Record<string, number>>, options?: ChargeOptions): ChargeResult — ⚠ undocumented
- `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.
- `clampValue` (function): function clampValue(value: number, bounds?: NumericBounds): number — Clamp a scalar to `bounds` (identity when `bounds` is omitted). Pure — touches no record.
- `clearBindingOverride` (function): function clearBindingOverride(gameId: string, action: string, storage: Pick<WebStorageLike, "getItem" | "setItem" | "removeItem"> | null | undefined = defaultStorage()): BindingOverrides — ⚠ undocumented
- `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.
- `compareLootItems` (function): function compareLootItems(a: LootItem, b: LootItem, options: LootComparisonOptions = {}): LootComparison — Compare two rolled items: every stat delta plus one weighted score for each, with caller-named weights and which stats read better when small.
- `compileSystemSchedule` (function): function compileSystemSchedule(systems: readonly SystemDefinition[], options?: CompileSystemScheduleOptions): CompiledSystemSchedule — Compile system definitions into a deterministic schedule. Validates unique ids, `dependsOn`, and before/after cycles.
- `composeGameLoop` (function): function composeGameLoop(systems: readonly SystemDefinition[] | undefined, loop: GameLoop<GameContext> | undefined, options?: ComposeGameLoopOptions): GameLoop<GameContext> — Merge a system list with an optional classic `GameLoop` into one loop the shell/runners drive. Systems install on first `onInit`; classic hooks still run for incremental migration.
- `computeEffectiveStats` (function): function computeEffectiveStats(def: ModularItemDef, installed: readonly InstalledPart[]): Record<string, number> — ⚠ undocumented
- `countSetMembers` (function): function countSetMembers(identity: ItemIdentity, bonus: SetBonus): number — Count how many parts (or tags) contribute to a set bonus on an identity.
- `craft` (function): function craft(state: InventoryState, layout: InventoryLayout, traits: ItemTraits, recipe: RecipeDef, context: CraftContext = {}): CraftResult — ⚠ undocumented
- `craftSeconds` (function): function craftSeconds(recipe: RecipeDef): number — ⚠ undocumented
- `createAchievementTracker` (function): function createAchievementTracker(options: AchievementTrackerOptions): AchievementTracker — Tracks achievement/trophy unlocks over caller-driven events — counter goals (`progress`/`setProgress`) and boolean flags (`unlock`) — with score, completion, an `onUnlock` seam, and serializable `snapshot`/`restore`. State is plain data; the view list keeps a stable identity between changes so React can read it through `useSyncExternalStore` without re-projecting every frame.
- `createAffixRoller` (function): function createAffixRoller(config: RollerConfig): AffixRoller — Rolls randomized gear from a base item: a weighted rarity tier scales base stats and picks prefix/suffix affixes that name and modify the item. Deterministic for a given `rng`.
- `createAuctionBook` (function): function createAuctionBook(config: AuctionBookConfig): AuctionBook — Timed-bid auctions in the WoW/BDO auction-house mold: post an item with a start price, minimum increment, and optional buyout; bids escrow currency, outbid players are refunded into their collection box, bids near the close extend it (anti-snipe), and settlement pays the seller minus the house cut while the item lands in the winner's collection box. Unsold auctions return the goods to the seller's box. Wallet and inventory movement is the caller's job (mirrors `economy/listingBook`) — this primitive owns the auction lifecycle and the escrowed collection-box bookkeeping behind it.
- `createBehaviourWorld` (function): function createBehaviourWorld(): BehaviourWorld — ⚠ undocumented
- `createCardPile` (function): function createCardPile(config: CardPileConfig, initial?: Partial<Record<ZoneName, readonly string[]>>): CardPile — ⚠ undocumented
- `createCardPileState` (function): function createCardPileState(config: CardPileConfig, initial?: Partial<Record<ZoneName, readonly string[]>>): CardPileState — ⚠ undocumented
- `createChatRateLimiter` (function): function createChatRateLimiter(limit: ChatRateLimit): ChatRateLimiter — ⚠ undocumented
- `createCodex` (function): function createCodex<TMeta = unknown>(options: CodexOptions<TMeta>): Codex<TMeta> — A codex / bestiary / lorebook: a fixed set of defined entries plus per-player discovery tracking, with categories, secret masking, completion, an `onDiscover` seam, and serializable `snapshot`/`restore`. The view `list()` keeps a stable identity between changes so React reads it through `useSyncExternalStore` without re-projecting each frame.
- `createCommitController` (function): function createCommitController<TAction>(config: CommitControllerConfig): CommitController<TAction> — ⚠ undocumented
- `createCosmetics` (function): function createCosmetics(deps: CosmeticsDeps = {}): Cosmetics — Equip cosmetic skins and customizations by slot, independent of gameplay stats.
- `createDecayMeterSet` (function): function createDecayMeterSet(configs: readonly DecayMeterConfig[]): DecayMeterSet — Named decay meters — hunger, thirst, oxygen, sanity, warmth, stamina. Each drains (or recovers) on game-time `dt` at a configurable rate, refills from consumables or actions, and raises moodle statuses at thresholds. Rate modifiers let the environment drive them (colder → faster warmth loss; toxic biome → oxygen drops), so a game reads an environment field then calls `setRateModifier`.
- `createDeliveryQueue` (function): function createDeliveryQueue(): DeliveryQueue — ⚠ undocumented
- `createDialogueRun` (function): function createDialogueRun(graph: DialogueGraph, options: DialogueRunOptions = {}): DialogueRun — Walk a branching {@link DialogueGraph}: hold the current node, expose its render-ready view, and advance by choosing one of the current node's responses (each choice names the node it leads to; a choice with no `to` ends the conversation). Purely a serializable model — a React host renders `current()` and calls `choose(index)` — so no game re-implements node lookup, choice-to-node traversal, or "am I at the end" bookkeeping. `snapshot`/`restore` round-trip the run through a save.
- `createDurability` (function): function createDurability(spec: DurabilitySpec): DurabilityState — ⚠ undocumented
- `createDurabilityTracker` (function): function createDurabilityTracker(): DurabilityTracker — ⚠ undocumented
- `createEmptyWallet` (function): function createEmptyWallet(): WalletState — Hold per-currency balances with affordability checks and charge/grant operations.
- `createEventTicker` (function): function createEventTicker(config: EventTickerOptions = {}): EventTicker — A thin, serializable, observable event/kill-feed ticker over the flat {@link appendFeed} / {@link pruneFeed} feed helpers: a single rolling, count-capped, time-fading list of free-string entries. A game calls `push({ kind, text, icon? })` and the ticker stamps and caps it; `recent()` prunes expired entries and returns the live list newest-first, each with a `fade` `0..1` (age / `ttlMs`) for the renderer to drop opacity as entries age out. Nothing here is genre-specific: `kind`, `text`, and `icon` are free strings the game owns and styles, and the model never interprets them. `snapshot`/`restore` round-trips the buffer through a save, re-anchoring ages so fades resume correctly.
- `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.
- `createGameEvents` (function): function createGameEvents<TMap extends GameEventMap = GameEventMap>(): GameEvents<TMap> — A typed publish/subscribe bus for gameplay events that systems and HUDs subscribe to.
- `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.
- `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.
- `createGestureSurfaceTracker` (function): function createGestureSurfaceTracker(bindings: TouchGestureBindings, tuning: GestureSurfaceTuning = DEFAULT_GESTURE_TUNING): GestureSurfaceTracker — ⚠ undocumented
- `createIntentBoard` (function): function createIntentBoard<TKind extends string = string>(): IntentBoard<TKind> — ⚠ undocumented
- `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.
- `createItemUse` (function): function createItemUse<TState>(resolveUse: (itemId: string) => string | null | undefined): ItemUse<TState> — Use or consume items, applying their effects and per-item cooldowns.
- `createKeyValueStore` (function): function createKeyValueStore<T>(config: KeyValueStoreConfig<T>): KeyValueStore<T> — A mutable local save cell through {@link KeyValueStorage}. Default fallback keeps session state on failure; `errorMode: "throw"` exposes failed reads/writes/removals through the original error. `storage: null` deliberately uses memory only.
- `createLapTimer` (function): function createLapTimer(): LapTimer — Create a {@link LapTimer} starting at lap 0 with no splits, best, or last time recorded.
- `createLayerRegistry` (function): function createLayerRegistry(initial?: readonly ParamLayer[]): LayerRegistry — Create a {@link LayerRegistry} — the registration seam difficulty tiers, mutators, and presets install into. Duplicate ids throw at registration; unknown ids at resolve time are reported, not fatal, which is what keeps saved sessions reproducible across content/version drift.
- `createLeaderboard` (function): function createLeaderboard(sink?: { onIncrement?(row: LeaderboardRow): void }): Leaderboard — Ranked score tracking across global, server, and per-profile scopes, with top-N queries and per-profile lookups.
- `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.
- `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.
- `createLoadouts` (function): function createLoadouts(deps: LoadoutDeps): Loadouts — Save, name, and swap equipment loadouts.
- `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.
- `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.
- `createLootRegistry` (function): function createLootRegistry(options: LootRegistryOptions = {}): LootRegistry — Register named loot tables and roll weighted randomized drops from them.
- `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.
- `createMarket` (function): function createMarket(config: MarketConfig = {}): Market — A market whose price comes from supply and demand over finite stock, as plain serializable state.
- `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.
- `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.
- `createModularItem` (function): function createModularItem(def: ModularItemDef, initial: readonly InstalledPart[] = []): ModularItem — ⚠ undocumented
- `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.
- `createMultiRegionHealth` (function): function createMultiRegionHealth(config: MultiRegionHealthConfig): MultiRegionHealth — Per-region/limb health tracked separately, so each body part takes and heals damage on its own.
- `createNameGenerator` (function): function createNameGenerator(options: NameGeneratorOptions): NameGenerator — Generate procedural names from templates and word banks with an injected random source.
- `createNearAgents` (function): function createNearAgents(options: NearAgentsOptions): NearCrowdAgents — Create the near-side simulation: agents on a nav mesh with decaying needs and a utility brain each. The off-screen world decides which agents exist here, so a resident beyond its radius costs this seam nothing at all — no path, no need tick, no decision.
- `createNeedSet` (function): function createNeedSet(definitions: readonly NeedDefinition[]): NeedSet — Create the needs an agent or a park guest carries. Decay reuses the survival meter formulas (`survival/decayMeter`), so moodle thresholds, clamping and rate modifiers behave exactly like every other meter; this set adds index-addressed reads and single-need retuning for hot AI loops. Score these needs into an action with `createUtilityBrain` (`@jgengine/core/world`).
- `createNotificationCenter` (function): function createNotificationCenter<TMeta = unknown>(options: NotificationCenterOptions = {}): NotificationStore<TMeta> — A persistent notification log with read/unread tracking — the "notification center" surface toasts don't cover. Newest-first, capped, serializable, and observable; a game pushes durable events (quest updates, trades, party news) here and a HUD renders the list + an unread badge. `snapshot`/`restore` round-trip through a save.
- `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.
- `createPairKeyCodec` (function): function createPairKeyCodec(options: PairKeyOptions = {}): PairKeyCodec — Build a pair-key codec for keyed relation values. Ids are escaped before joining, so any id (including ones containing the separator or a backslash) round-trips through {@link PairKeyCodec.key} → {@link PairKeyCodec.parse} without collision. Undirected codecs (the default) canonicalize so `key(a, b) === key(b, a)`.
- `createPingSystem` (function): function createPingSystem(deps: PingSystemDeps): PingSystem — Contextual ping/marker communication between teammates, classified by what was pinged.
- `createPriceHistory` (function): function createPriceHistory(config: PriceHistoryConfig): PriceHistory — The "market price" readout behind every auction house: a bounded rolling record of completed sales per item, aggregated into min/max/volume-weighted-average/latest unit-price stats so games can show current value and recent trends. Memory is bounded by `maxSamplesPerItem` (oldest samples drop first) and optionally by a sliding time window; timestamps are injected by the caller so the history stays deterministic.
- `createProductionState` (function): function createProductionState(): ProductionState — A production building that converts input items into outputs over time — factory/crafting station.
- `createQuestJournal` (function): function createQuestJournal(deps: QuestJournalDeps): QuestJournal — Track accepted quests and their per-objective progress, granting rewards on completion.
- `createRaceState` (function): function createRaceState(config: RaceStateConfig): RaceState — A checkpoint race state machine — laps, forks, live standings, splits, and pluggable win conditions.
- `createRebindSession` (function): function createRebindSession(config: RebindSessionConfig): RebindSession — A conflict-aware key-remap session over the action-binding model — the missing editor behind a controls-settings menu. It takes the game's authored actions ({@link RebindActionConfig}s, or an {@link ActionCodesMap} + labels) plus the player's saved {@link BindingOverrides}, and tracks the *effective* binding per action (default merged with the override via `applyBindingOverrides`). `rows()` exposes each action's label, current key glyph (via `bindingLabel`), whether it is still the default, and which other actions it collides with; `conflicts()` groups every action pair sharing a normalized code (the value-add a raw override map can't give you). `beginCapture`/`capture`/`cancelCapture` drive a "press a key" rebind (codes normalized via `normalizeKeyCode`), `reset`/ `resetAll` return to defaults, and `overrides()`/`apply()` hand the caller the `BindingOverrides` to persist. Nothing here is genre-specific: action ids and labels are free strings the session never interprets, and hold/toggle/repeat binding shapes survive a rebind. `snapshot`/`restore` round-trips the editor (including the in-flight capture) through a save.
- `createRecipeGraph` (function): function createRecipeGraph(defs: readonly RecipeDef[] = []): RecipeGraph — ⚠ undocumented
- `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.
- `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}.
- `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.
- `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.
- `createRing` (function): function createRing(config: RingConfig): Ring — ⚠ undocumented
- `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.
- `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.
- `createSaveSlots` (function): function createSaveSlots(config: SaveSlotsConfig = {}): SaveSlots — Create a {@link SaveSlots} index — the serializable, observable list of save/profile slot metadata a save-select menu renders. It is a thin companion to `createSaveStore`: the store owns the real save payload keyed by slot, this owns only the display fields (name, empty, last-saved, and a free-string `meta` bag) the menu shows. `write` stamps a slot saved on the injected clock, `clear` empties one, `rename` relabels one, `mostRecent()` returns the newest non-empty slot to power a "Continue" button, and `list()` feeds the New / Continue / Load / Delete grid. `meta` keys are free strings the game owns — the model never interprets them — and `snapshot`/`restore` round-trips the whole index through a save.
- `createSaveStore` (function): function createSaveStore<T>(config: SaveStoreConfig<T>): SaveStore<T> — Create a {@link SaveStore}. Same call for offline and cloud — only the `backend` differs (localStorage, memory, or an async DB/Convex endpoint). Turn on `autosave` and every `set`/`patch` persists on a debounce; leave it off and call `save()` at checkpoints. Bump `version` + pass `migrate` when the save shape changes so old players keep their progress.
- `createShopStock` (function): function createShopStock(config: ShopStockConfig = {}): ShopStock — A serializable, observable vendor/shop stock. Each entry carries a game-owned free-string `kind`, a `price` in a free-string `currency`, a finite or unlimited (`qty: null`) count, and an optional `sellPrice` buy-back. All currency math is delegated to the existing pure `wallet` model — `buy` charges and `sell` grants a **caller-owned** {@link WalletState} (the shop never holds the wallet, it returns the new wallet for the caller to adopt), so the same stock composes with any wallet the game owns. Nothing here is genre-specific: `kind` and `currency` are free labels the game styles and the model never branches on. `restock`/`setPrice`/`add`/`remove` mutate the catalog, `subscribe` observes every change, and `snapshot`/`restore` round-trips the whole stock through a save.
- `createSkillTree` (function): function createSkillTree<TStat extends string = string>(config: SkillTreeConfig<TStat>, options: { devtoolsName?: string } = {}): SkillTree<TStat> — A data-authored skill tree: nodes carry a point cost, prerequisites, passives and unlocked actions, synergies pay off two or more nodes together, and `respec` refunds exactly the points spent. Spend against `canSpend` for a reason a UI can show; read `resolved()` for the stat modifiers and action list to feed `createStats` / `createAbilityKit`.
- `createSocial` (function): function createSocial(deps: SocialDeps): Social — Emotes and lightweight social interactions between nearby players.
- `createSpawnPoints` (function): function createSpawnPoints(): SpawnPoints — Register spawn locations and choose where entities spawn or respawn.
- `createStatGraph` (function): function createStatGraph(def: StatGraphDef): StatGraph — A data-driven stat graph: game-owned named inputs feed caller-authored derived formulas, with contribution provenance, uncommitted previews, cycle detection, and selective recomputation. Formula semantics and numeric tables stay entirely game-defined.
- `createTalentTree` (function): function createTalentTree<TStat extends string = string>(config: TalentTreeConfig<TStat>): TalentTree<TStat> — ⚠ undocumented
- `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.
- `createTouchGestureTracker` (function): function createTouchGestureTracker(tuning: TouchGestureTuning): TouchGestureTracker — ⚠ undocumented
- `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.
- `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.
- `createTurnLoop` (function): function createTurnLoop<TAction = unknown>(config: TurnLoopConfig): TurnLoop<TAction> — ⚠ undocumented
- `createUnlockCatalog` (function): function createUnlockCatalog(defs: readonly UnlockDef[] = []): UnlockCatalog — A catalog of unlockable content gated behind conditions the player earns, tracking what is unlocked.
- `createUnlocks` (function): function createUnlocks(defs: UnlockDef[] = []): Unlocks — ⚠ undocumented
- `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.
- `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.
- `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.
- `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.
- `createWeaponStats` (function): function createWeaponStats(resolveEntry: (itemId: string) => WeaponEntry | null | undefined): WeaponStats — Resolve per-weapon stat values — damage, fire rate, spread — for combat math.
- `createWorkQueue` (function): function createWorkQueue<TSpec, TReserve = undefined>(): WorkQueueState<TSpec, TReserve> — Create an empty timed work queue.
- `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`.
- `curve` (function): function curve(spec: Curve): (x: number) => number — Bind a {@link Curve} into a reusable `(x) => value` evaluator — a partial application of {@link evalCurve}.
- `curveScale` (function): function curveScale(read: PolicyRead, shape: Curve): ResourcePolicy — Scale the amount by a {@link Curve} evaluated at the read value — a generic curve modifier (population upkeep, depletion falloff, difficulty income) over caller-provided context.
- `decayMeterMoodles` (function): function decayMeterMoodles(values: DecayMeterValues, defs: readonly DecayMeterConfig[]): Moodle[] — Moodles for every crossed threshold, worst-first per meter in declared order.
- `decayMeterSnapshot` (function): function decayMeterSnapshot(values: DecayMeterValues, defs: readonly DecayMeterConfig[]): Record<string, DecayMeterState> — Numeric state for every meter, keyed by id — the pure counterpart to {@link DecayMeterSet.snapshot}.
- `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.
- `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}.
- `defaultObjectiveLabel` (function): function defaultObjectiveLabel(objective: QuestObjective): string — Default objective label: a readable "verb count noun" from a {@link QuestObjective}.
- `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.
- `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}.
- `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.
- `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.
- `deriveTouchScheme` (function): function deriveTouchScheme(input: ActionCodesMap | undefined, { reserved, firstPerson, config: rawConfig, mode }: DeriveTouchSchemeOptions): TouchScheme | null — Null means "render no touch controls" — either the game opted out or there is nothing to synthesize.
- `describeTrackedQuest` (function): function describeTrackedQuest(def: QuestDef, instance: QuestInstance, label: (objective: QuestObjective) => string = defaultObjectiveLabel): TrackedQuestView — 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, status, labelled objective progress). Pass `label` to override the derived objective text.
- `dialogueSlot` (const): const dialogueSlot: StoreHandle<string | undefined> — Typed handle onto the open-dialogue slot — React reads it via `useOpenDialogueId`; game code uses `ctx.game.dialogue`.
- `diffParams` (function): function diffParams(before: Readonly<Record<string, number>>, after: Readonly<Record<string, number>>): readonly ParamDelta[] — Compute the per-parameter deltas between two value maps — the preview/diff of applying a change, for showing a player what a difficulty tier or mutator will do before they commit.
- `dispatchExpedition` (function): function dispatchExpedition(input: ExpeditionDispatch): ExpeditionState — Dispatch plain expedition state with a persisted seeded cursor; no clock, scheduler or storage is owned.
- `drainOutput` (function): function drainOutput(state: ProductionState, itemId: string, count?: number): { state: ProductionState; taken: number } — ⚠ undocumented
- `draw` (function): function draw(state: CardPileState, n: number, options: { from: ZoneName; to: ZoneName; handLimit?: number; reshuffleFrom?: ZoneName; seed?: string | number; }): DrawResult — ⚠ undocumented
- `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}.
- `durabilityFraction` (function): function durabilityFraction(state: DurabilityState): number — ⚠ undocumented
- `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`.
- `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.
- `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.
- `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.
- `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.
- `evaluatePredicate` (function): function evaluatePredicate(predicate: Predicate | undefined, facts: PredicateFacts): boolean — Evaluate a predicate against a fact bag. An omitted predicate matches unconditionally, so callers can treat "no condition" and "always" identically. Pure and deterministic — no allocation beyond path splits and no reliance on evaluation order between sibling clauses.
- `feedProduction` (function): function feedProduction(def: ProductionBuildingDef, state: ProductionState, itemId: string, count: number): { state: ProductionState; accepted: number } — ⚠ undocumented
- `fifoOrdering` (function): function fifoOrdering<TSpec, TReserve = undefined>(a: Job<TSpec, TReserve>, b: Job<TSpec, TReserve>): number — Pure FIFO ordering by enqueue sequence.
- `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.
- `firstPastPost` (function): function firstPastPost(count = 1): RaceWinCondition — Race ends when `count` racers have crossed the finish; ranking is the current standings order.
- `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.
- `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.
- `gearScore` (function): function gearScore(set: Readonly<Record<string, GearSlotItem | null | undefined>>, options: GearScoreOptions = {}): GearScore — Score a whole loadout with one documented formula:
- `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.
- `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.
- `getValue` (function): function getValue(record: Record<string, number>, key: string, fallback = 0): number — Current value for `key`, or `fallback` (default `0`) when the record has no entry.
- `grant` (function): function grant(state: WalletState, currency: string | CurrencyDefinition, amount: number): WalletState — ⚠ undocumented
- `identityOf` (function): function identityOf(family: string, tags: readonly string[], parts: readonly InstalledPart[]): ItemIdentity — Assemble an {@link ItemIdentity} from a family, tags, and installed parts.
- `idleRaceSession` (function): function idleRaceSession(): RaceSessionState — The pre-race session on the grid: `idle`, both clocks at zero. Call {@link startRaceCountdown} to light the lights, or hold here until the field is ready.
- `initDecayMeters` (function): function initDecayMeters(defs: readonly DecayMeterConfig[]): DecayMeterValues — Starting values for `defs` — each meter's `start ?? max`, clamped to its range. Seed a serialized state record with this instead of holding a {@link createDecayMeterSet} closure.
- `install` (function): function install(def: ModularItemDef, installed: readonly InstalledPart[], slotId: string, part: PartDef): InstallResult — ⚠ undocumented
- `insureLost` (function): function insureLost(lost: readonly ItemStack[], policy: InsurancePolicy, userId: string, now: number, rng?: () => number): ScheduledDelivery | null — ⚠ undocumented
- `isComplete` (function): function isComplete(def: ModularItemDef, installed: readonly InstalledPart[]): boolean — ⚠ undocumented
- `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.
- `isDisabled` (function): function isDisabled(spec: DurabilitySpec, state: DurabilityState): boolean — ⚠ undocumented
- `isIdentityValid` (function): function isIdentityValid(identity: ItemIdentity, rules: readonly CompatibilityRule[]): boolean — Convenience predicate: true when {@link validateIdentity} finds no violations.
- `isOverdrawn` (function): function isOverdrawn(state: WalletState, currency: string | CurrencyDefinition): boolean — True once `balance(state, currency)` has gone negative under an overdraft-enabled charge.
- `jobById` (function): function jobById<TSpec, TReserve>(state: WorkQueueState<TSpec, TReserve>, id: JobId): Job<TSpec, TReserve> | null — Look up a job by id, or `null` if absent/terminal.
- `jobProgress` (function): function jobProgress<TSpec, TReserve>(job: Job<TSpec, TReserve>): number — Fractional progress of a job (0…1); a zero-duration job reads as complete.
- `lapDurations` (function): function lapDurations(splits: readonly number[], gatesPerLap: number): number[] — Per-lap durations from a cumulative split book with `gatesPerLap` checkpoints per lap — each lap's time is its finish-gate split minus the previous lap's finish. Only complete laps are returned.
- `leveling` (function): function leveling(config: LevelingConfig): LevelingTrack — Build a leveling track from an xp-per-level {@link Curve} and a max level. The returned {@link LevelingTrack} resolves how many levels a given xp total earns (rolling over surplus xp, capping at `maxLevel`) and, via `grantXp`, writes the new level/xp back through a {@link LevelingStatAccess} and fires `onLevelUp` for each level gained in ascending order. Reach for this instead of hand-tracking xp thresholds; pair it with `resource-pool` (mana/stamina) and `ability-bar` (cooldowns) for a hero.
- `listRuleEffects` (function): function listRuleEffects(): RuleEffectDefinition[] — Every declared rule effect, for populating inspector dropdowns and validating a content set.
- `loadBindingOverrides` (function): function loadBindingOverrides(gameId: string, storage: Pick<WebStorageLike, "getItem"> | null | undefined = defaultStorage()): BindingOverrides — ⚠ undocumented
- `localSaveBackend` (function): function localSaveBackend(storage?: KeyValueStorage | null, policy: KeyValueStorageErrorPolicy = {}): SaveBackend — A {@link SaveBackend} over a synchronous {@link KeyValueStorage} — the browser's `localStorage` by default (offline, on-device saves), a test stub, or `null` for a no-op backend. Default fallback ignores failures; `errorMode: "throw"` rejects failed operations and unavailable storage, so SaveStore status/onError can report them. Use {@link memorySaveBackend} for deliberate ephemeral persistence.
- `lootFilter` (function): function lootFilter(rules: readonly LootFilterRule[]): readonly LootFilterRule[] — Validating factory — rule ids must be unique so authoring mistakes fail loudly.
- `lootLevelScale` (function): function lootLevelScale(catalog: LootCatalog, level: number): number — Stat multiplier at `level` from the catalog's level curve; `1` when the catalog declares none.
- `lootStatContributions` (function): function lootStatContributions(stats: Readonly<Record<string, number>>, options: Pick<LootComparisonOptions, "weights" | "lowerIsBetter"> = {}): Record<string, number> — Per-stat weighted contribution: `value × weight`, negated for stats listed in `lowerIsBetter`. This is the single weight policy behind {@link scoreLootStats}, {@link compareLootItems} and a gear score, so an item and a whole loadout are never ranked by different arithmetic.
- `lootTable` (function): function lootTable(def: LootTableDef): LootTableDef — Validates a loot table definition and returns it unchanged, for use with {@link createLootRegistry}.
- `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.
- `matchesQuery` (function): function matchesQuery(identity: ItemIdentity, query: IdentityQuery): boolean — Test whether an identity satisfies a declarative {@link IdentityQuery}.
- `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}.
- `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.
- `missingRequiredSlots` (function): function missingRequiredSlots(def: ModularItemDef, installed: readonly InstalledPart[]): string[] — ⚠ undocumented
- `missionMarkers` (function): function missionMarkers(document: SceneDocumentLike): Record<string, ScenePoint3> — Marker positions from an authored scene, keyed by marker id — what a positional objective reads.
- `moveCards` (function): function moveCards(state: CardPileState, ids: readonly string[], from: ZoneName, to: ZoneName, position: "top" | "bottom" = "top"): PileResult — ⚠ undocumented
- `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.
- `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.
- `parDelta` (function): function parDelta(splits: readonly number[], reference: readonly number[]): number[] — Elementwise delta of a cumulative split book against a `reference` book (a personal best or par lap): positive means behind the reference at that checkpoint. Compared up to the shorter length — the `+0.3s` / `−1.2s` gap every racing HUD shows against its ghost.
- `partInSlot` (function): function partInSlot(installed: readonly InstalledPart[], slotId: string): PartDef | null — ⚠ undocumented
- `partitionOnDeath` (function): function partitionOnDeath(containers: readonly ContainerSnapshot[]): DeathPartition — ⚠ undocumented
- `pauseJob` (function): function pauseJob<TSpec, TReserve>(state: WorkQueueState<TSpec, TReserve>, id: JobId): WorkQueueState<TSpec, TReserve> — Pause a queued or active job in place; a paused job keeps its progress and yields its slot.
- `pauseRule` (function): function pauseRule(ledger: ResourceLedger, ruleId: string): ResourceLedger — Pause a rule: its cursor is retained but it fires nothing until {@link resumeRule}.
- `peek` (function): function peek(state: CardPileState, zone: ZoneName, n = 1): readonly string[] — ⚠ undocumented
- `pickUniform` (function): function pickUniform<T>(rng: () => number, items: readonly T[]): T | undefined — Pick one item uniformly at random from `items` using `rng` (a `() => number` in `[0, 1)`); returns undefined when empty.
- `pickWeighted` (function): function pickWeighted<T>(rng: () => number, items: readonly T[], weightOf: (item: T) => number): T | undefined — Pick one item with probability proportional to `weightOf(item)`; skips non-positive weights, returns undefined when nothing is eligible.
- `pileRng` (function): function pileRng(seed: string | number): () => number — ⚠ undocumented
- `placementOf` (function): function placementOf(finishOrder: readonly string[], racerId: string, options?: PlacementOptions): RacePlacement | null — One racer's {@link RacePlacement} within a finish order, or `null` if they never crossed the line.
- `playControlsActive` (function): function playControlsActive(ctx: GameContext): boolean — ⚠ undocumented
- `priorityOrdering` (function): function priorityOrdering<TSpec, TReserve = undefined>(a: Job<TSpec, TReserve>, b: Job<TSpec, TReserve>): number — Priority-first ordering (higher priority sooner), FIFO within equal priority.
- `proceduralLootEntry` (function): function proceduralLootEntry<TDef>(registry: ItemInstanceRegistry<TDef>, roll: (rng: () => number) => { baseId: string; def: TDef }): (rng: () => number) => string — Bridges any procedural roller into a `LootEntry.generate` callback: rolls a `{ baseId, def }` pair and registers it, returning the runtime id the loot roll hands back as the drop's `item`.
- `productionBuilding` (function): function productionBuilding(config: ProductionBuildingConfig): ProductionBuildingDef — ⚠ undocumented
- `pruneFeed` (function): function pruneFeed<T extends TimedFeedEntry>(list: readonly T[], now: number, ttl: number): T[] — Drop feed entries older than `ttl` game-seconds before `now`. Returns the same array reference when nothing expired, so equality checks skip a redundant state write. The tick-time counterpart to {@link appendFeed}'s age bound.
- `pruneToasts` (function): function pruneToasts<T>(toasts: readonly Toast<T>[], now: number): readonly Toast<T>[] — Drop every toast whose `expiresAt` is at or before `now`. Returns the same array when nothing expired.
- `queueSize` (function): function queueSize<TSpec, TReserve>(state: WorkQueueState<TSpec, TReserve>): number — Non-terminal job count (queued + active + paused).
- `queuedJobs` (function): function queuedJobs<TSpec, TReserve>(state: WorkQueueState<TSpec, TReserve>, ordering: JobOrdering<TSpec, TReserve> = priorityOrdering): Job<TSpec, TReserve>[] — Jobs waiting for a slot, in selection order.
- `raceOutcomeOf` (function): function raceOutcomeOf(finishOrder: readonly string[], racerId: string, options?: PlacementOptions): RaceOutcome — The win/lose verdict for one racer in a finish order — `ranking[0] === player ? "win" : "lose"`, the check every racing game hand-rolls, generalized to a `winningPlaces` cutoff. A racer absent from the order counts as a `lose`.
- `racePlacements` (function): function racePlacements(finishOrder: readonly string[], options?: PlacementOptions): readonly RacePlacement[] — Turn a finish-order ranking (index 0 = winner, e.g. the `ranking` of a `race.finished` event) into per-racer {@link RacePlacement}s — the `1st/2nd/3rd` + win/lose every results screen shows.
- `raceTrack` (function): function raceTrack(config: RaceTrackConfig): RaceTrack — A race track is an ordered ring of checkpoint trigger volumes plus a lap count. The final checkpoint is the lap/finish line: a racer completes a lap by passing all checkpoints in order and hitting the last one. `forks` splice alternate route segments between mainline checkpoints.
- `rankLeaderboard` (function): function rankLeaderboard(rows: readonly RankableRow[], options: RankLeaderboardOptions = {}): RankedEntry[] — Turn raw leaderboard rows into a render-ready ranked table. Pure and allocation-bounded: it sorts a copy by `value` (descending by default), assigns 1-based ranks with correct tie handling (`"standard"` → `1, 2, 2, 4`; `"dense"` → `1, 2, 2, 3`), flags rows that share a score (`isTie`), marks the local player (`isLocal`, via `highlightUserId`), and finally applies `limit`. Sorting is stable, so rows with equal scores keep their input order. Nothing here styles or branches on game meaning — pair it with {@link medalFor} and a game-owned theme to render a reskinnable scoreboard. Accepts a {@link LeaderboardRow}`[]` straight from `leaderboard.snapshot()`/`getTop()` since those satisfy {@link RankableRow}.
- `readPath` (function): function readPath(facts: PredicateFacts, path: PredicatePath): unknown — Read a dot path out of a fact bag, descending only through plain objects. Returns `undefined` when any segment is missing or non-traversable. Bounded by the path's segment count.
- `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.
- `redirect` (function): function redirect(endpoints: { source?: string; recipient?: string }): ResourcePolicy — Override the source and/or recipient accounts of a transaction.
- `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}.
- `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.
- `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.
- `rejectWhen` (function): function rejectWhen(predicate: (txn: ResourceTransaction, ctx: PolicyContext) => boolean): ResourcePolicy — Drop a transaction when `predicate` holds — the reject arm of the pipeline.
- `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.
- `repairQuote` (function): function repairQuote(spec: DurabilitySpec, state: DurabilityState, options?: { to?: number; station?: string }): RepairQuote | null — ⚠ undocumented
- `rerollRules` (function): function rerollRules<TPayload = unknown>(pool: readonly RuleDef<TPayload>[], config: RuleSelectionConfig, keepIds: readonly string[], salt: string | number = 0): RuleSelection<TPayload> — Reroll a prior selection: keep `keepIds` (the locked slots) and re-draw the rest under a fresh, still-deterministic stream derived from `config.seed` and `salt`. The same seed + salt + keep set reproduce the same reroll, so reroll history stays replayable.
- `resolveConsolation` (function): function resolveConsolation(policy: ConsolationPolicy, partition: DeathPartition): { loadoutId: string } | null — ⚠ undocumented
- `resolveOneShotClip` (function): function resolveOneShotClip(oneShots: Record<string, string | readonly string[]> | undefined, event: string, roll: number): string | null — Resolves the clip name a one-shot `event` should play from a model's `animation.oneShots` map, or `null` if the event isn't bound. A `string[]` binding picks a variant by `roll` (a value in `[0, 1)`), so combat can vary attack swings. Pure and deterministic given `roll` — the shell supplies the randomness.
- `resolveParams` (function): function resolveParams(base: Readonly<Record<string, number>>, layers: readonly ParamLayer[]): ParamSnapshot — Fold an ordered stack of layers over `base` and return the effective {@link ParamSnapshot}. Layers apply in {@link orderLayers} sequence; within a layer each parameter's ops fold left-to-right. Every op is recorded in `contributions` for provenance/preview. Parameters a layer introduces but `base` omits start from `0`. Pure and deterministic — no ambient randomness or time.
- `resolvePowerGrid` (function): function resolvePowerGrid(supply: number, consumers: readonly PowerConsumer[]): PowerGridResult — ⚠ undocumented
- `resolveRoutine` (function): function resolveRoutine(config: RoutineConfig): RoutineTimeline — Resolve an authored routine into a timeline driven by the world clock.
- `resolveSelection` (function): function resolveSelection(base: Readonly<Record<string, number>>, registry: LayerRegistry, ids: LayerSelection): { readonly snapshot: ParamSnapshot; readonly unknown: readonly string[] } — Reproducible session setup in one call: resolve a saved {@link LayerSelection} through a registry, fold the found layers over `base`, and return the snapshot alongside any unknown ids. The same base + registry + selection always yields the same snapshot.
- `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.
- `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.
- `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.
- `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.
- `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.
- `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.
- `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`.
- `ringSampleAt` (function): function ringSampleAt(config: RingConfig, time: number): RingSample — ⚠ undocumented
- `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.
- `runPipeline` (function): function runPipeline<V>(base: V, modifiers: readonly Modifier<V>[], equals: (a: V, b: V) => boolean = Object.is): PipelineResult<V> — ⚠ undocumented
- `saveBindingOverride` (function): function saveBindingOverride(gameId: string, action: string, codes: ActionCodes, storage: Pick<WebStorageLike, "getItem" | "setItem" | "removeItem"> | null | undefined = defaultStorage()): BindingOverrides — ⚠ undocumented
- `scoreLootStats` (function): function scoreLootStats(stats: Readonly<Record<string, number>>, options: Pick<LootComparisonOptions, "weights" | "lowerIsBetter"> = {}): number — One stat block's weighted score: the sum of `value × weight`, negated for stats listed in `lowerIsBetter`. Pair it with {@link lootStatContributions} when a caller also needs the split.
- `seededRng` (function): function seededRng(seed: string | number): SeededRng — Deterministic pseudo-random generator seeded from a string or number — same seed, same sequence.
- `seededStreams` (function): function seededStreams(seed: string | number): (stream: string) => () => number — Derives independent, deterministic {@link seededRng} streams from one base seed, keyed by stream name.
- `selectDialogueView` (function): function selectDialogueView(graph: DialogueGraph, nodeId: string): DialogueGraphView | null — Project a {@link DialogueGraph} node id to its render-ready {@link DialogueGraphView} — the pure "current view" selector a stateless renderer reads (speaker, line, choices, done). Returns `null` when the id is not in the graph. No traversal or mutation.
- `selectRules` (function): function selectRules<TPayload = unknown>(pool: readonly RuleDef<TPayload>[], config: RuleSelectionConfig): RuleSelection<TPayload> — Select up to `count` rules from `pool` deterministically from `config.seed`. Locked ids are placed first (in order), then remaining slots are filled by weighted draw from tag-filtered, still-eligible candidates, honoring `requires`/`conflicts` after each pick. Each slot draws from an independent seed stream keyed by slot index, so a later slot's outcome never shifts an earlier one. Selection stops early when no compatible candidate remains. Pure given `pool` + `config`.
- `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.
- `setTouchControlsMode` (function): function setTouchControlsMode(ctx: GameContext, mode: string | null): void — Activate a named touch control mode, or `null` to return to the base config.
- `setValue` (function): function setValue(record: Record<string, number>, key: string, value: number, bounds?: NumericBounds): number — Set `key` to `value` (clamped to `bounds`), writing the record in place. Returns the stored value.
- `settleExpedition` (function): function settleExpedition<TCtx>(config: ExpeditionConfig<TCtx>, state: ExpeditionState, nowMs: number): ExpeditionState — Replay due event ticks using the existing stepped catch-up primitive. Order is loot → hazard → ordered supplies → death → capacity recall. Unprocessed ticks retain their frontier; returning never rolls or takes damage. Auto-recall uses the triggering tick's time, including offline arrival in the same call.
- `shuffleWithRng` (function): function shuffleWithRng<T>(values: readonly T[], rng: () => number): T[] — ⚠ undocumented
- `slotAccepts` (function): function slotAccepts(slot: MountSlotDef, category: string): boolean — Attach parts into an item's mount slots and resolve the combined stats.
- `splitSegments` (function): function splitSegments(splits: readonly number[], start = 0): number[] — Per-segment durations from a cumulative split book (`splits[i]` = elapsed time at checkpoint `i`): `segments[i] = splits[i] − splits[i−1]`, the first measured from `start` (default 0). Turns the cumulative splits {@link RacerProgress} records into the individual leg times a results screen shows.
- `stackMoodles` (function): function stackMoodles(...groups: readonly (readonly Moodle[])[]): Moodle[] — Merge any number of moodle groups into one stack — meters, ailments, and buffs share this display. Same-id moodles fold together (stacks add, worst severity wins); the result is ordered worst-first so the HUD reads critical statuses at a glance.
- `startRaceCountdown` (function): function startRaceCountdown(options?: RaceCountdownOptions): RaceSessionState — Drop the lights: return a fresh `countdown` session of `seconds` (default 3). A non-positive length skips straight to `racing` for a standing start with no countdown.
- `statModifierContributions` (function): function statModifierContributions<TStat extends string>(source: string, set: StatModifierSet<TStat>): Record<string, StatContribution[]> — Bridge the shared {@link StatModifierSet} shape (add/multiply, used by talents, items, and buffs) into stat-graph contributions, so a ranked talent tree or gear roll feeds the graph as one named source instead of a parallel store.
- `stationOutputRate` (function): function stationOutputRate(station: StaffedStation, tuning: StationRateTuning): number — Resolve `(base + perStat * sum(admitted worker stats)) * efficiency` without allocation. Empty staffing retains base production. Negative/nonfinite contributions are zero; a nonfinite efficiency or overflowing result stops production with rate zero. Invalid workers still occupy their ordered slots. Assign the result to a `ProductionBuildingDef.rate` for `tickProduction`.
- `stationSatisfied` (function): function stationSatisfied(recipe: RecipeDef, context: CraftContext): boolean — ⚠ undocumented
- `talentTreeView` (function): function talentTreeView<TStat extends string = string>(nodes: readonly TalentNodeDef<TStat>[], tree: TalentTree<TStat>): TalentTreeView — Project the existing talent model (`createTalentTree`) into a flat, serializable render view: every node placed by branch + prerequisite-depth tier, tagged learned/available/locked/maxed, with its inbound prerequisite edges (and whether each is met) and whether a point can be spent right now. It is a pure read over the node defs plus a live {@link TalentTree}, so a React/canvas widget can lay out nodes, draw edges, and gate clicks without re-deriving topology or re-interpreting eligibility. The model still owns allocation, requirements, and point rules — this only reshapes them for drawing, and never interprets what a node *means* (ids, branches, and ranks stay opaque game data). This is the point-spend adapter over {@link talentTreeViewFrom}; pass a custom status to that builder instead to drive the tree from a currency, level, or any other unlock rule.
- `talentTreeViewFrom` (function): function talentTreeViewFrom<TStat extends string = string>(nodes: readonly TalentNodeDef<TStat>[], status: (node: TalentNodeDef<TStat>) => TalentNodeStatus, totals?: TalentPointTotals): TalentTreeView — Build a flat, serializable render view of a node graph from a caller-supplied per-node status, decoupled from any particular progression model. For each node the game returns its `rank` and whether it is `allocatable` *right now* under whatever rule it likes — a skill-point pool, a cash threshold, a level gate, a quest flag, or nothing. The builder places every node by branch + prerequisite-depth tier, tags it learned/available/locked/maxed (`available` when rank 0 and every prerequisite is met — see below), and resolves inbound prerequisite edges (each `met` when the source node's supplied rank meets the demand). This is the general escape hatch behind {@link talentTreeView}: it lets the same widget render a buy-with-points talent tree, a money-gated upgrade tree, or a condition-unlocked ability web without the renderer changing. It never interprets what a node *means* — ids, branches, and ranks stay opaque game data.
- `taxFraction` (function): function taxFraction(fraction: number, to?: string): ResourcePolicy — Take a fraction of the amount. With `to`, the taxed portion is split off into a second transaction toward that recipient (a transfer/tax); without it, the fraction is simply removed.
- `thresholdScale` (function): function thresholdScale(read: PolicyRead, bands: readonly ThresholdBand[]): ResourcePolicy — Scale the amount by the highest {@link ThresholdBand} whose `min` the read value meets — a generic bracket modifier (progressive tax, tiered upkeep) over caller data, with no built-in currencies or brackets.
- `tick` (function): function tick<TSpec, TReserve, TOutput>(state: WorkQueueState<TSpec, TReserve>, config: WorkQueueConfig<TSpec, TReserve, TOutput>, dt: number): TickResult<TSpec, TReserve, TOutput> — Advance the queue by `dt` seconds. Promotes queued jobs into up to `concurrency` active slots, advances active jobs, and completes those that reach their duration — emitting `started`/`completed` events in deterministic order. A large `dt` catches up across many jobs in one call: when a job completes with leftover time, the freed slot promotes the next queued job and applies the remainder, so a reconnect or save/load gap resolves in a single bounded pass. Completed jobs are removed from the returned state.
- `tickProduction` (function): function tickProduction(def: ProductionBuildingDef, state: ProductionState, input: ProductionTickInput): ProductionState — ⚠ undocumented
- `tickRaceSession` (function): function tickRaceSession(session: RaceSessionState, dt: number): RaceSessionState — Advance the session by `dt` seconds: bleed the countdown down and flip to `racing` when it reaches zero, or accumulate `elapsed` while `racing`. `idle` and `finished` are inert. Overshoot past the countdown is dropped rather than banked into `elapsed`, so the race clock always starts from zero.
- `tierAt` (function): function tierAt<Id>(boundaries: readonly ThresholdBoundary<Id>[], value: number, options: { readonly inclusive?: boolean } = {}): ThresholdBoundary<Id> | null — The highest boundary at-or-below `value` — the band the value currently sits in. Returns `null` when `value` is below every boundary. Boundaries need not be sorted.
- `timeScaledRarity` (function): function timeScaledRarity<TCtx extends { elapsedMs: number }>(options: TimeScaledRarityOptions): LootModifier<TCtx> — Multiply weighted odds (or independent chances, clamped to one) by a caller-authored elapsed-time curve. Keeps source tables unchanged and uses the existing pipeline's modifier provenance. Elapsed time and multipliers must be finite and nonnegative; invalid curves reject the roll.
- `touchButtonShape` (function): function touchButtonShape(action: string): TouchButtonShape — Default silhouette for an action; `circle` when nothing more specific fits.
- `touchCode` (function): function touchCode(action: string): string — ⚠ undocumented
- `towardValue` (function): function towardValue(record: Record<string, number>, key: string, target: number, maxDelta: number, bounds?: NumericBounds): number — Step `key` toward `target` by at most `maxDelta` without overshooting, then clamp to `bounds`. Writes in place and returns the stored value.
- `uninstall` (function): function uninstall(installed: readonly InstalledPart[], slotId: string): readonly InstalledPart[] — ⚠ undocumented
- `unitTrainingConfig` (function): function unitTrainingConfig(options: UnitTrainingOptions): WorkQueueConfig<UnitTrainingSpec, UnitReservation, UnitSpawnOrder> — Build a {@link WorkQueueConfig} for training units from a catalog. Reservation is the unit's cost + population; duration is its train time; completion output is a {@link UnitSpawnOrder} for the caller to route to its spawn primitive.
- `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.
- `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.
- `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.
- `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.
- `wear` (function): function wear(spec: DurabilitySpec, state: DurabilityState, kind: WearKind, times = 1): DurabilityState — ⚠ undocumented
- `withTouchCodes` (function): function withTouchCodes(map: ActionCodesMap | undefined): ActionCodesMap — Every action gains a synthetic touch code alongside its physical codes.
- `worldHealthBarAllowsRole` (function): function worldHealthBarAllowsRole(roles: readonly CatalogEntityRole[] | undefined, role: CatalogEntityRole | undefined): boolean — ⚠ undocumented

## @jgengine/core/inventory/carryLoad

- `CharacterLoad` (interface): interface CharacterLoad extends EncumbranceState — A carrier's load: the encumbrance state, how it splits into carried and worn, and capacity left.
- `CharacterLoadInput` (interface): interface CharacterLoadInput — Everything a {@link characterLoad} reading takes: carried inventories, worn gear and the capacity they are measured against.
- `WeightLookup` (type): type WeightLookup = (itemId: string) => number — Per-item mass in the caller's weight unit; an unknown item weighs 0.
- `canCarry` (function): function canCarry(load: Pick<CharacterLoad, "mass" | "capacity">, addedMass: number): boolean — Whether `addedMass` more weight still fits under `capacity`. Pure: the caller decides what to do with a refusal, so an overload policy stays with the game.
- `carriedEntries` (function): function carriedEntries(states: readonly InventoryState[]): LoadEntry[] — Every filled stack in the given inventories as load entries, in slot order. Only the inventories the caller passes count, so a stash left out of the list adds no weight.
- `characterLoad` (function): function characterLoad(input: CharacterLoadInput): CharacterLoad — Weigh a character: carried stacks plus worn gear against a capacity, resolved into the shared encumbrance bands. Movement reads `moveMultiplier`, `canSprint`, `canJump` and `immobile`; pickup gates read `remaining` or {@link canCarry}. The stash is not part of `carried`, so it adds nothing.

## @jgengine/core/inventory/encumbrance

- `EncumbranceConfig` (interface): interface EncumbranceConfig — Tuning for where the encumbrance bands sit and how hard the carrier is slowed. Both fields are load *fractions* / multipliers in `0..1`, never absolute mass.
- `EncumbranceState` (interface): interface EncumbranceState — Serializable snapshot of a carrier's load versus capacity and the movement consequences.
- `EncumbranceTier` (type): type EncumbranceTier = "unencumbered" | "encumbered" | "immobile" — Coarse carry state: free-moving, slowed, or pinned in place.
- `LoadEntry` (interface): interface LoadEntry — One carried stack: an item id and how many of it the carrier holds.
- `MassResolver` (type): type MassResolver = (itemId: string) => number — Resolves the per-unit mass of an item id. Injected so mass tables stay decoupled from this module.
- `encumbranceMoveMultiplier` (function): function encumbranceMoveMultiplier(fraction: number, config?: EncumbranceConfig): number — Progressive move-speed multiplier for a raw load fraction: 1 while at/below `soft`, a linear decay from 1 down toward `floor` across the `soft..1` band, and 0 once at/over capacity. Pure and side-effect free — the curve `resolveEncumbrance` reads for `moveMultiplier`.
- `resolveEncumbrance` (function): function resolveEncumbrance(mass: number, capacity: number, config?: EncumbranceConfig): EncumbranceState — Resolve carried mass against carrying capacity into a serializable encumbrance state: load fraction, tier, and the movement consequences (`canSprint`/`canJump`/`immobile` gates plus a progressive `moveMultiplier`). Below `soft` the carrier is unencumbered and unhindered; from `soft` up to capacity it is encumbered — no sprint or jump, and speed decays from 1 toward `floor`; at or above capacity it is immobile (multiplier 0). Deterministic and allocation-light; pair with {@link totalLoad} to derive `mass` from an inventory and a mass table. A capacity of 0 or less pins any positive load as immobile (`fraction` 1) so the state stays finite/serializable.
- `totalLoad` (function): function totalLoad(entries: readonly LoadEntry[], massOf: MassResolver): number — Sum the mass of every carried stack using an injected per-unit mass resolver. Bounded by the number of entries; allocates nothing. Missing or negative unit masses are treated as 0.

## @jgengine/core/inventory/equipment

- `EquipItemDef` (interface): interface EquipItemDef — The gear facts the equip rules read from an item. A rolled item resolves its runtime id through the instance registry to its base and answers from that base's data — this is not a second item type.
- `EquipItemLookup` (type): type EquipItemLookup = (itemId: string) => EquipItemDef | null | undefined — Item lookup the rules read; returns nothing for an unknown id.
- `EquipRejection` (type): type EquipRejection = "unknown-slot" | "not-equippable" | "wrong-slot" | "already-equipped" | "blocked" — Why an equip attempt was refused; `detail` names the item and slots involved.
- `EquipResult` (type): type EquipResult = | { status: "ok"; state: EquipmentState; slotId: string; replaced: string | null } | { status: "rejected"; reason: EquipRejection; detail: string } — An equip attempt: the new worn set plus the replaced item, or the refusal with its reason and detail.
- `EquipSlotDef` (interface): interface EquipSlotDef — One body slot: the item kinds it accepts and the slots it occupies while filled.
- `Equipment` (interface): interface Equipment — A worn-gear set: one item per slot, rules from slot and item data, state out and back in.
- `EquipmentOptions` (interface): interface EquipmentOptions — Options for {@link createEquipment}.
- `EquipmentProbeReading` (interface): interface EquipmentProbeReading — What the debug overlay reads about a worn set.
- `EquipmentState` (interface): interface EquipmentState — Serializable equip state: the filled slots as `[slotId, itemId]` pairs.
- `UnequipResult` (type): type UnequipResult = | { status: "ok"; state: EquipmentState; itemId: string } | { status: "rejected"; reason: "unknown-slot" | "empty-slot"; detail: string } — An unequip attempt: the new worn set plus the item taken off, or the refusal with its detail.
- `WornEntry` (interface): interface WornEntry — One worn item and the slot holding it.
- `createEquipment` (function): function createEquipment(slotDefs: readonly EquipSlotDef[], lookup: EquipItemLookup, options: EquipmentOptions = {}): Equipment — A worn-gear set over caller slot and item data.

## @jgengine/core/inventory/inventoryModel

- `InventoryLayout` (interface): interface InventoryLayout { slots: number; accepts?: string | readonly string[] } — ⚠ undocumented · used by `createEmptyInventory`: A bag of stackable items supporting add, remove, count, and move — the base inventory model.
- `InventorySet` (interface): interface InventorySet<TId extends string> { put(id: TId, itemId: string, count: number, options?: {slot?: number}): PutResult; take(id: TId, itemId: string, count: number): TakeResult; move(fromId: TId, fromSlot: number, toId: TId, toSlot?: number): MoveResult; count(id: TId, itemI… — ⚠ undocumented · used by `createInventorySet`: Build a keyed set of named inventories from their `layouts`, sharing one `traits` table — the stateful façade over put/take/move/count.
- `InventorySetState` (type): type InventorySetState<TId extends string> = Record<TId, InventoryState> — Every inventory in a set, keyed by id, as plain slot data.
- `InventorySlot` (type): type InventorySlot = { itemId: string; count: number } | null — ⚠ undocumented
- `InventoryState` (interface): interface InventoryState { slots: InventorySlot[] } — ⚠ undocumented · used by `countItem`: Total quantity of `itemId` summed across every stack in the inventory.
- `ItemTraits` (interface): interface ItemTraits { stackLimit(itemId: string): number; kind?(itemId: string): string | null } — ⚠ undocumented · used by `createInventorySet`: Build a keyed set of named inventories from their `layouts`, sharing one `traits` table — the stateful façade over put/take/move/count.
- `MoveResult` (type): type MoveResult = | { status: "ok"; from: InventoryState; to: InventoryState } | { status: "rejected"; reason: "invalid-slot" | "empty-slot" | "wrong-kind" | "no-space" } — ⚠ undocumented · used by `moveItem`: Move the stack at `fromSlot` to `toSlot` (or auto-stack when omitted) — swapping, merging with remainder, or relocating across two inventori…
- `PutResult` (type): type PutResult = | { status: "ok"; state: InventoryState } | { status: "rejected"; reason: "no-space" | "wrong-kind" | "slot-occupied" | "invalid-slot" } — ⚠ undocumented · used by `putItem`: Add `count` of `itemId` — into a specific `options.slot`, or auto-stacked across free/partial slots.
- `SplitResult` (type): type SplitResult = | { status: "ok"; state: InventoryState } | { status: "rejected"; reason: "invalid-slot" | "empty-slot" | "invalid-amount" | "no-space" | "slot-occupied" | "over-stack" } — Outcome of {@link splitStack}: the new state, or a rejection reason.
- `TakeResult` (type): type TakeResult = { status: "ok"; state: InventoryState } | { status: "rejected"; reason: "insufficient" } — ⚠ undocumented · used by `takeItem`: Remove `count` of `itemId`, draining from the last matching stacks first.
- `countItem` (function): function countItem(state: InventoryState, itemId: string): number — Total quantity of `itemId` summed across every stack in the inventory.
- `createEmptyInventory` (function): function createEmptyInventory(layout: InventoryLayout): InventoryState — A bag of stackable items supporting add, remove, count, and move — the base inventory model.
- `createInventorySet` (function): function createInventorySet<TId extends string>(layouts: Record<TId, InventoryLayout>, traits: ItemTraits): InventorySet<TId> — Build a keyed set of named inventories from their `layouts`, sharing one `traits` table — the stateful façade over put/take/move/count.
- `hasItem` (function): function hasItem(state: InventoryState, itemId: string, count: number): boolean — True when the inventory holds at least `count` of `itemId`.
- `moveItem` (function): function moveItem(from: InventoryState, fromSlot: number, to: InventoryState, toLayout: InventoryLayout, traits: ItemTraits, toSlot?: number): MoveResult — Move the stack at `fromSlot` to `toSlot` (or auto-stack when omitted) — swapping, merging with remainder, or relocating across two inventories. Rejects on empty source, wrong kind, or no space.
- `putItem` (function): function putItem(state: InventoryState, layout: InventoryLayout, traits: ItemTraits, itemId: string, count: number, options?: { slot?: number }): PutResult — Add `count` of `itemId` — into a specific `options.slot`, or auto-stacked across free/partial slots. Rejects on no space or wrong kind.
- `splitStack` (function): function splitStack(state: InventoryState, slot: number, amount: number, toSlot?: number, limit?: number): SplitResult — Splits `amount` off the stack in `slot` into `toSlot` (or the first empty slot when `toSlot` is omitted). Without `limit` it is limit-agnostic: a same-item target merges by simple addition. Pass the item's stack limit to keep the merge legal, which rejects `over-stack`. Rejects an empty source, `amount <= 0`, `amount >= stack count` (a split must leave both sides non-empty), no free slot, or a target holding a different item.
- `takeItem` (function): function takeItem(state: InventoryState, itemId: string, count: number): TakeResult — Remove `count` of `itemId`, draining from the last matching stacks first. Rejects if fewer than `count` are held.

## @jgengine/core/inventory/shapedGrid

- `Cell` (type): type Cell = readonly [number, number] — ⚠ undocumented · used by `canPlace`: Check bounds and overlap for a discrete footprint, optionally ignoring the item being moved.
- `Footprint` (type): type Footprint = readonly Cell[] — ⚠ undocumented · used by `canPlace`: Check bounds and overlap for a discrete footprint, optionally ignoring the item being moved.
- `GridAdjacencyQuery` (interface): interface GridAdjacencyQuery { cellsOf(id: string): readonly Cell[]; neighborsOf(id: string): readonly string[]; touching(idA: string, idB: string): boolean; adjacentCells(cells: readonly Cell[]): readonly Cell[] } — ⚠ undocumented
- `Placement` (interface): interface Placement<T> { id: string; value: T; footprint: Footprint; origin: Cell; rotation: Rotation } — ⚠ undocumented
- `Rotation` (type): type Rotation = 0 | 1 | 2 | 3 — ⚠ undocumented · used by `canPlace`: Check bounds and overlap for a discrete footprint, optionally ignoring the item being moved.
- `ShapedFitRejection` (type): type ShapedFitRejection = "duplicate-id" | "invalid-footprint" | "too-large" | "no-space" | "budget-exceeded" — Why a first-fit placement failed: the footprint cannot fit an empty board at any offered rotation (`too-large`), the board is genuinely full (`no-space`), or the search hit its budget.
- `ShapedFitResult` (type): type ShapedFitResult<T> = | { status: "ok"; grid: ShapedGrid<T>; origin: Cell; rotation: Rotation; checks: number } | { status: "rejected"; reason: ShapedFitRejection; detail: string; checks: number } — A placed board, or a refusal that names why the item does not fit.
- `ShapedGrid` (interface): interface ShapedGrid<T> { readonly width: number; readonly height: number; readonly placements: readonly Placement<T>[] } — ⚠ undocumented · used by `canPlace`: Check bounds and overlap for a discrete footprint, optionally ignoring the item being moved.
- `ShapedItem` (interface): interface ShapedItem<T> { id: string; value: T; footprint: Footprint } — ⚠ undocumented · used by `fitShapedItem`: Place a shaped item at the first legal spot, or say why it does not fit.
- `ShapedPlaceResult` (interface): interface ShapedPlaceResult<T> { status: "ok"; grid: ShapedGrid<T> } — ⚠ undocumented
- `ShapedPlacementSearchOptions` (interface): interface ShapedPlacementSearchOptions — Search policy: rotation order first, then rows and columns; the work budget counts candidate origins.
- `ShapedPlacementSearchResult` (type): type ShapedPlacementSearchResult = | { status: "found"; origin: Cell; rotation: Rotation; checks: number } | { status: "no-space"; checks: number } | { status: "budget-exceeded"; checks: number } — A detached placement, a completed no-fit search, or an incomplete search that reached its budget.
- `ShapedRejected` (interface): interface ShapedRejected { status: "rejected"; reason: ShapedRejection; detail?: string } — ⚠ undocumented
- `ShapedRejection` (type): type ShapedRejection = "out-of-bounds" | "overlap" | "duplicate-id" | "unknown-id" | "invalid-footprint" | "invalid-origin" — ⚠ undocumented · used by `canPlace`: Check bounds and overlap for a discrete footprint, optionally ignoring the item being moved.
- `ShapedResult` (type): type ShapedResult<T> = ShapedPlaceResult<T> | ShapedRejected — ⚠ undocumented · used by `moveShaped`: Move or rotate one placement, ignoring its current cells during overlap checks.
- `canPlace` (function): function canPlace<T>(grid: ShapedGrid<T>, footprint: Footprint, origin: Cell, rotation: Rotation, ignoreId?: string): ShapedRejection | null — Check bounds and overlap for a discrete footprint, optionally ignoring the item being moved.
- `createShapedGrid` (function): function createShapedGrid<T>(width: number, height: number): ShapedGrid<T> — An immutable spatial inventory board holding caller-defined multi-cell items.
- `findShapedPlacement` (function): function findShapedPlacement<T>(grid: ShapedGrid<T>, footprint: Footprint, options: ShapedPlacementSearchOptions = {}): ShapedPlacementSearchResult — Find the first legal placement without mutating the board; occupancy is indexed once per search.
- `fitShapedItem` (function): function fitShapedItem<T>(grid: ShapedGrid<T>, item: ShapedItem<T>, options: ShapedPlacementSearchOptions = {}): ShapedFitResult<T> — Place a shaped item at the first legal spot, or say why it does not fit. Distinguishes an item that can never fit the board (`too-large`, with its footprint and the board size in `detail`) from a full board (`no-space`) and an exhausted search (`budget-exceeded`, not a full bag).
- `moveShaped` (function): function moveShaped<T>(grid: ShapedGrid<T>, id: string, origin: Cell, rotation?: Rotation): ShapedResult<T> — Move or rotate one placement, ignoring its current cells during overlap checks.
- `placeShaped` (function): function placeShaped<T>(grid: ShapedGrid<T>, item: ShapedItem<T>, origin: Cell, rotation: Rotation = 0): ShapedResult<T> — Place a caller-defined item without mutating the source board; duplicate ids reject.
- `removeShaped` (function): function removeShaped<T>(grid: ShapedGrid<T>, id: string): ShapedResult<T> — Remove one placement without mutating the source board.

## @jgengine/core/inventory/slotModel

- `Slot` (type): type Slot<T> = T | null — ⚠ undocumented
- `SlotGrid` (type): type SlotGrid<T> = readonly Slot<T>[] — ⚠ undocumented
- `SlotResult` (type): type SlotResult<T> = | { status: "ok"; grid: Slot<T>[] } | { status: "rejected"; reason: "invalid-slot" | "slot-occupied" | "empty-slot" } — ⚠ undocumented

## @jgengine/core/inventory/storageTier

- `ConsolationPolicy` (interface): interface ConsolationPolicy { loadoutId: string; when?: "always" | "if-carried-empty" } — ⚠ undocumented
- `ContainerSnapshot` (interface): interface ContainerSnapshot { inventoryId: string; tier: StorageTier; items: readonly ItemStack[] } — ⚠ undocumented
- `DeathPartition` (interface): interface DeathPartition { kept: readonly ItemStack[]; lost: readonly ItemStack[] } — ⚠ undocumented
- `DeliveryEntry` (interface): interface DeliveryEntry { id: string; userId: string; inventoryId: string; items: readonly ItemStack[]; deliverAt: number } — ⚠ undocumented
- `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
- `InsurancePolicy` (interface): interface InsurancePolicy { isInsured(itemId: string): boolean; returnInventoryId: string; delaySeconds: number | [number, number] } — ⚠ undocumented
- `ItemStack` (interface): interface ItemStack { itemId: string; count: number } — ⚠ undocumented
- `ScheduledDelivery` (interface): interface ScheduledDelivery { userId: string; inventoryId: string; items: readonly ItemStack[]; deliverAt: number } — ⚠ undocumented
- `StorageTier` (type): type StorageTier = "carried" | "banked" — ⚠ undocumented
- `createDeliveryQueue` (function): function createDeliveryQueue(): DeliveryQueue — ⚠ undocumented
- `insureLost` (function): function insureLost(lost: readonly ItemStack[], policy: InsurancePolicy, userId: string, now: number, rng?: () => number): ScheduledDelivery | null — ⚠ undocumented
- `partitionOnDeath` (function): function partitionOnDeath(containers: readonly ContainerSnapshot[]): DeathPartition — ⚠ undocumented
- `resolveConsolation` (function): function resolveConsolation(policy: ConsolationPolicy, partition: DeathPartition): { loadoutId: string } | null — ⚠ undocumented
- `tierOf` (function): function tierOf(tiers: Record<string, StorageTier>, inventoryId: string): StorageTier — ⚠ undocumented

## @jgengine/core/item/affix

- `AffixDef` (interface): interface AffixDef { id: string; stat: string; op?: AffixOp; roll: number | [number, number]; weight: number; minLevel?: number; namePart?: {position: "prefix" | "suffix"; text: string} } — ⚠ undocumented
- `AffixOp` (type): type AffixOp = "add" | "mul" — ⚠ undocumented
- `AffixPool` (interface): interface AffixPool { id: string; affixes: readonly AffixDef[] } — ⚠ undocumented
- `AffixRoller` (interface): interface AffixRoller { rollRarity(rng: () => number): RarityTier; roll(base: ItemBaseDef, rarityId: string, rng: () => number): RolledItem; rollRandom(base: ItemBaseDef, rng: () => number): RolledItem } — ⚠ undocumented · used by `createAffixRoller`: Rolls randomized gear from a base item: a weighted rarity tier scales base stats and picks prefix/suffix affixes that name and modify the it…
- `ItemBaseDef` (interface): interface ItemBaseDef { id: string; name: string; baseStats: Record<string, number>; pools: readonly string[] } — ⚠ undocumented
- `RarityTier` (interface): interface RarityTier { id: string; weight: number; affixCount: number | [number, number]; statScale?: number; namePart?: string; pools?: readonly string[] } — ⚠ undocumented
- `RolledAffix` (interface): interface RolledAffix { id: string; stat: string; op: AffixOp; value: number } — ⚠ undocumented
- `RolledItem` (interface): interface RolledItem { baseId: string; rarity: string; name: string; affixes: readonly RolledAffix[]; stats: Record<string, number> } — ⚠ undocumented
- `RollerConfig` (interface): interface RollerConfig { pools: readonly AffixPool[]; rarities: readonly RarityTier[] } — ⚠ undocumented · used by `createAffixRoller`: Rolls randomized gear from a base item: a weighted rarity tier scales base stats and picks prefix/suffix affixes that name and modify the it…
- `createAffixRoller` (function): function createAffixRoller(config: RollerConfig): AffixRoller — Rolls randomized gear from a base item: a weighted rarity tier scales base stats and picks prefix/suffix affixes that name and modify the item. Deterministic for a given `rng`.
- `seededRng` (function): function seededRng(seed: string | number): SeededRng — Deterministic pseudo-random generator seeded from a string or number — same seed, same sequence.

## @jgengine/core/item/durability

- `DurabilitySpec` (interface): interface DurabilitySpec { max: number; wearPerUse?: number; wearPerHit?: number; disableAtZero?: boolean; repair?: RepairSpec } — ⚠ undocumented
- `DurabilityState` (interface): interface DurabilityState { current: number; max: number } — ⚠ undocumented · used by `applyWear`: Apply wear to an item, tracking breakage and repair eligibility.
- `DurabilityTracker` (interface): interface DurabilityTracker { init(instanceId: string, spec: DurabilitySpec): DurabilityState; get(instanceId: string): DurabilityState | null; set(instanceId: string, state: DurabilityState): void; wear(instanceId: string, spec: DurabilitySpec, kind: WearKind, times?… — ⚠ undocumented
- `RepairCost` (interface): interface RepairCost { item: string; count: number } — ⚠ undocumented
- `RepairMaterial` (interface): interface RepairMaterial { item: string; perPoint: number } — ⚠ undocumented
- `RepairQuote` (interface): interface RepairQuote { materials: readonly RepairCost[]; restored: number; state: DurabilityState } — ⚠ undocumented
- `RepairSpec` (interface): interface RepairSpec { materials: readonly RepairMaterial[]; station?: string; qualityLossPerRepair?: number } — ⚠ undocumented
- `WearKind` (type): type WearKind = "use" | "hit" — ⚠ undocumented
- `applyWear` (function): function applyWear(state: DurabilityState, amount: number): DurabilityState — Apply wear to an item, tracking breakage and repair eligibility.
- `canRepairAt` (function): function canRepairAt(spec: DurabilitySpec, stationId?: string): boolean — ⚠ undocumented
- `createDurability` (function): function createDurability(spec: DurabilitySpec): DurabilityState — ⚠ undocumented
- `createDurabilityTracker` (function): function createDurabilityTracker(): DurabilityTracker — ⚠ undocumented
- `durabilityFraction` (function): function durabilityFraction(state: DurabilityState): number — ⚠ undocumented
- `isBroken` (function): function isBroken(state: DurabilityState): boolean — ⚠ undocumented
- `isDisabled` (function): function isDisabled(spec: DurabilitySpec, state: DurabilityState): boolean — ⚠ undocumented
- `repairQuote` (function): function repairQuote(spec: DurabilitySpec, state: DurabilityState, options?: { to?: number; station?: string }): RepairQuote | null — ⚠ undocumented
- `wear` (function): function wear(spec: DurabilitySpec, state: DurabilityState, kind: WearKind, times = 1): DurabilityState — ⚠ undocumented
- `wearAmount` (function): function wearAmount(spec: DurabilitySpec, kind: WearKind): number — ⚠ undocumented

## @jgengine/core/item/itemIdentity

- `CandidatePlacement` (interface): interface CandidatePlacement — A part proposed for a slot during generation, before it is committed to an identity. Used by the backtracking contract to test a placement in isolation.
- `CompatibilityRule` (type): type CompatibilityRule = RequireRule | ForbidRule — A cross-slot compatibility rule constraining which part/tag/family combinations a modular item may hold.
- `ConstraintViolation` (interface): interface ConstraintViolation — One failed {@link CompatibilityRule}, carrying the rule id, its kind, and a human-readable message for UI or generator diagnostics.
- `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.
- `IdentityQuery` (interface): interface IdentityQuery — A predicate over an {@link ItemIdentity}, expressed as data so a whole rule set round-trips through JSON. An empty query matches every identity; each present field narrows the match and all present fields must hold (AND).
- `ItemIdentity` (interface): interface ItemIdentity — The declarative identity of a built modular item: a caller-named family, its provenance tags, and the parts occupying its slots. This is the "what an item is" layer above the raw stat rollup in ./modularItem — a plain, serializable value with no game noun baked in ("gun", "manufacturer", "potion" are all caller data in `family`/`tags`).
- `ItemProvenance` (interface): interface ItemProvenance — The serializable record of how an item was generated: its family, tags, per-slot part selection, applied set-bonus ids, and the deterministic seed. Enough for UI provenance display and byte-exact regeneration.
- `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.
- `SetBonus` (interface): interface SetBonus — A match/set bonus: extra stats granted when enough parts (or a tag) of a given kind are present — e.g. "3 Blackwood parts grant +recoil control". Counting is declarative (`countBy`/`value`) so the whole catalog is data.
- `activeSetBonuses` (function): function activeSetBonuses(identity: ItemIdentity, bonuses: readonly SetBonus[]): SetBonus[] — Select the set bonuses whose membership count meets their threshold, in the order they were declared.
- `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).
- `candidateViolatesForbid` (function): function candidateViolatesForbid(partial: ItemIdentity, candidate: CandidatePlacement, rules: readonly CompatibilityRule[]): ForbidRule | null — The generic backtracking contract for procedural generation (see #908): given a partial identity and a candidate part, return the first forbid rule the placement would violate, or null if it stays viable. Require rules are ignored here because they may still be satisfied by a later placement.
- `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.
- `countSetMembers` (function): function countSetMembers(identity: ItemIdentity, bonus: SetBonus): number — Count how many parts (or tags) contribute to a set bonus on an identity.
- `identityOf` (function): function identityOf(family: string, tags: readonly string[], parts: readonly InstalledPart[]): ItemIdentity — Assemble an {@link ItemIdentity} from a family, tags, and installed parts.
- `isIdentityValid` (function): function isIdentityValid(identity: ItemIdentity, rules: readonly CompatibilityRule[]): boolean — Convenience predicate: true when {@link validateIdentity} finds no violations.
- `matchesQuery` (function): function matchesQuery(identity: ItemIdentity, query: IdentityQuery): boolean — Test whether an identity satisfies a declarative {@link IdentityQuery}.
- `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.

## @jgengine/core/item/itemInstanceRegistry

- `ItemInstanceRegistry` (interface): interface ItemInstanceRegistry<TDef> — A runtime store for procedurally generated item instances — a rolled unique gun, a rolled affixed relic — keyed by a generated id distinct from any static catalog id. The counterpart a game's `content.itemById` consults for ids `lootTable`'s `generate` entries hand back, so runtime rolls never need a hand-rolled parallel registry (#536.1).
- `ItemInstanceRegistryOptions` (interface): interface ItemInstanceRegistryOptions<TDef> — Inject storage and its saved allocator sequence when attaching an existing collection.
- `ItemInstanceRegistryState` (interface): interface ItemInstanceRegistryState<TDef> — Save data for a registry; definitions must be structured-cloneable and use the caller's serialization format.
- `ItemInstanceStorage` (interface): interface ItemInstanceStorage<TDef> — Caller-owned synchronous storage; `entries()` must stream without materializing the collection.
- `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.
- `proceduralLootEntry` (function): function proceduralLootEntry<TDef>(registry: ItemInstanceRegistry<TDef>, roll: (rng: () => number) => { baseId: string; def: TDef }): (rng: () => number) => string — Bridges any procedural roller into a `LootEntry.generate` callback: rolls a `{ baseId, def }` pair and registers it, returning the runtime id the loot roll hands back as the drop's `item`.

## @jgengine/core/item/itemgen

- `GenChoiceRecord` (interface): interface GenChoiceRecord — Provenance for one resolved step: which option stuck, its effective weight, how many options were eligible after constraints, and how many eligible options backtracking rejected before this one. A skipped optional step is recorded with an empty `optionId`.
- `GenChoices` (interface): interface GenChoices — Read-only view of the choices resolved so far, threaded into a later step's pool, constraint, weight function, or transform so a decision can depend on earlier picks (dependent choice).
- `GenDraft` (interface): interface GenDraft — The resolved-but-unvalidated draft passed to each {@link GenValidator}: the step choices, their values, and the transformed fields. Returning false from any validator rerolls the whole generation up to the attempt budget.
- `GenFieldRecord` (interface): interface GenFieldRecord — Provenance for one field mutation a transform made: which transform, field, op, and before/after.
- `GenOption` (interface): interface GenOption<V = unknown> — One selectable option in a generation step's pool: a stable `id` used in provenance and pinning, the payload `value` a chosen option contributes, and an optional relative `weight` (default 1).
- `GenOutcome` (type): type GenOutcome = | { ok: true; result: GenResult } | { ok: false; reason: "unsatisfiable" | "rejected"; attempts: number } — The outcome of {@link generate}: either a successful {@link GenResult}, or a failure carrying the reason (`"unsatisfiable"` — constraints left no valid assignment; `"rejected"` — validators kept rejecting drafts) and the attempts spent.
- `GenPool` (type): type GenPool<V = unknown> = readonly GenOption<V>[] | ((choices: GenChoices) => readonly GenOption<V>[]) — A step's candidate options: a fixed list, or a function of the choices resolved so far so pools can narrow to earlier picks (a slot pool that depends on a chosen category).
- `GenProvenance` (interface): interface GenProvenance — The full explanation of a generated result: how many whole-pipeline attempts it took, every step choice, and every field mutation. Plain, serializable data for UI, debugging, balancing, and regeneration.
- `GenResult` (interface): interface GenResult — A successful generation: the step-to-option map, step-to-value map, transformed numeric fields, and the {@link GenProvenance} that explains them. Entirely serializable; round-trips through save/load and multiplayer sync unchanged.
- `GenSchema` (interface): interface GenSchema — A caller-defined generation schema over plain data: ordered choice steps, optional field transforms, optional validators, and bounded reroll/backtracking budgets. Genre-agnostic — it carries no built-in notion of rarity, element, weapon, or name; those are caller step and option ids.
- `GenStep` (interface): interface GenStep<V = unknown> — One decision point in a {@link GenSchema}: pick a single option from a pool, honoring an optional constraint, dependent weighting, selection mode, and optionality. Steps resolve in array order.
- `GenTransform` (interface): interface GenTransform — A named derivation over the numeric field bag, applied in schema order after all choices resolve (affix rolls, level scaling, budget spend). Each field mutation it makes is recorded as provenance.
- `GenValidator` (type): type GenValidator = (draft: GenDraft) => boolean — A final-assembly check over a {@link GenDraft}; false triggers a whole-pipeline reroll.
- `GenerateOptions` (interface): interface GenerateOptions — Per-call options for {@link generate}.
- `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.
- `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.

## @jgengine/core/item/modularItem

- `InstallResult` (type): type InstallResult = | { status: "ok"; installed: readonly InstalledPart[] } | { status: "rejected"; reason: "unknown-slot" | "wrong-category" | "slot-occupied" } — ⚠ undocumented
- `InstalledPart` (interface): interface InstalledPart { slotId: string; part: PartDef } — ⚠ undocumented · used by `identityOf` (@jgengine/core/gameplay): Assemble an {@link ItemIdentity} from a family, tags, and installed parts.
- `ModularItem` (interface): interface ModularItem { readonly def: ModularItemDef; parts(): readonly InstalledPart[]; install(slotId: string, part: PartDef): InstallResult; uninstall(slotId: string): readonly InstalledPart[]; partInSlot(slotId: string): PartDef | null; effectiveStats(): Rec… — ⚠ undocumented
- `ModularItemDef` (interface): interface ModularItemDef { id: string; baseStats: Record<string, number>; slots: readonly MountSlotDef[] } — ⚠ undocumented
- `MountSlotDef` (interface): interface MountSlotDef { id: string; accepts: string | readonly string[]; required?: boolean } — ⚠ undocumented · used by `slotAccepts`: Attach parts into an item's mount slots and resolve the combined stats.
- `PartDef` (interface): interface PartDef { id: string; category: string; stats?: Record<string, number>; multipliers?: Record<string, number> } — ⚠ undocumented
- `computeEffectiveStats` (function): function computeEffectiveStats(def: ModularItemDef, installed: readonly InstalledPart[]): Record<string, number> — ⚠ undocumented
- `createModularItem` (function): function createModularItem(def: ModularItemDef, initial: readonly InstalledPart[] = []): ModularItem — ⚠ undocumented
- `install` (function): function install(def: ModularItemDef, installed: readonly InstalledPart[], slotId: string, part: PartDef): InstallResult — ⚠ undocumented
- `isComplete` (function): function isComplete(def: ModularItemDef, installed: readonly InstalledPart[]): boolean — ⚠ undocumented
- `missingRequiredSlots` (function): function missingRequiredSlots(def: ModularItemDef, installed: readonly InstalledPart[]): string[] — ⚠ undocumented
- `partInSlot` (function): function partInSlot(installed: readonly InstalledPart[], slotId: string): PartDef | null — ⚠ undocumented
- `slotAccepts` (function): function slotAccepts(slot: MountSlotDef, category: string): boolean — Attach parts into an item's mount slots and resolve the combined stats.
- `slotById` (function): function slotById(def: ModularItemDef, slotId: string): MountSlotDef | null — ⚠ undocumented
- `uninstall` (function): function uninstall(installed: readonly InstalledPart[], slotId: string): readonly InstalledPart[] — ⚠ undocumented

## @jgengine/core/item/use

- `ItemUse` (interface): interface ItemUse<TState> { register(handlers: Record<string, ItemUseHandler<TState>>): void; registered(): string[]; can(state: TState, input: ItemUseInput): ItemUseRejection | null; use(state: TState, input: ItemUseInput): ItemUseResult<TState> } — ⚠ undocumented · used by `createItemUse`: Use or consume items, applying their effects and per-item cooldowns.
- `ItemUseHandler` (interface): interface ItemUseHandler<TState> { can?(state: TState, input: ItemUseInput): ItemUseRejection | null; apply(state: TState, input: ItemUseInput): ItemUseResult<TState> } — ⚠ undocumented
- `ItemUseInput` (interface): interface ItemUseInput { from: string; itemId: string; inventoryId?: string; aim?: Aim } — ⚠ undocumented
- `ItemUseRejection` (interface): interface ItemUseRejection { reason: string } — ⚠ undocumented
- `ItemUseResult` (interface): interface ItemUseResult<TState> { state: TState; error?: string } — ⚠ undocumented
- `createItemUse` (function): function createItemUse<TState>(resolveUse: (itemId: string) => string | null | undefined): ItemUse<TState> — Use or consume items, applying their effects and per-item cooldowns.

## @jgengine/core/item/useBehavior

- `BehaviorConfig` (type): type BehaviorConfig = Record<string, unknown> — Per-behavior configuration stored on an item as plain data (e.g. charge time, projectile id). Kept opaque here so no game noun leaks into item core.
- `BehaviorState` (type): type BehaviorState = Record<string, unknown> — A single behavior's mutable, serializable runtime state (e.g. current charge, rounds queued). Composed state is a map of these keyed by behavior id.
- `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.
- `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.
- `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.
- `UseBehaviorContext` (interface): interface UseBehaviorContext<TWorld> — The context handed to each behavior hook: the shared folded `world`, this behavior's own `config` and `state` slice, and the triggering use input.
- `UseBehaviorDef` (interface): interface UseBehaviorDef<TWorld> — A registered behavior implementation. The combat/game side registers these (charge, thrown-reload, projectile-replacement, …); the item core only ever stores a {@link UseBehaviorRef} to one by id. Hooks are the lifecycle: `init` builds serializable state, `can` gates, `apply` folds the world.
- `UseBehaviorOutcome` (interface): interface UseBehaviorOutcome<TWorld> — The result of applying one behavior: the (possibly advanced) world, this behavior's updated state, an optional error that aborts the chain, and an optional `stop` that ends the chain after a successful apply.
- `UseBehaviorRef` (interface): interface UseBehaviorRef — The reference an item stores for one composed behavior: a stable behavior id, optional config, and an optional order override. Pure data — the item core never holds the implementation, only this reference.
- `UseBehaviorRegistry` (interface): interface UseBehaviorRegistry<TWorld> — A registry of use-behavior implementations plus a composer that turns an item's stored refs into an ordered, conflict-checked {@link ComposedUse}.
- `UseBehaviorRejection` (interface): interface UseBehaviorRejection — A reason a behavior refused a use, surfaced from `can`.
- `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.

## @jgengine/core/item/weapon

- `WeaponEntry` (interface): interface WeaponEntry { weapon?: Record<string, unknown> } — ⚠ undocumented · used by `createWeaponStats`: Resolve per-weapon stat values — damage, fire rate, spread — for combat math.
- `WeaponStats` (interface): interface WeaponStats { getStat(itemId: string, stat: string): number | null } — ⚠ undocumented · used by `createWeaponStats`: Resolve per-weapon stat values — damage, fire rate, spread — for combat math.
- `createWeaponStats` (function): function createWeaponStats(resolveEntry: (itemId: string) => WeaponEntry | null | undefined): WeaponStats — Resolve per-weapon stat values — damage, fire rate, spread — for combat math.
- `getWeaponStat` (function): function getWeaponStat(entry: WeaponEntry | null | undefined, stat: string): number | null — ⚠ undocumented

## @jgengine/core/loot/drop

- `EquippedComparison` (interface): interface EquippedComparison — What a HUD renders when a drop lands: per-stat deltas against the worn item and one verdict.
- `EquippedStatDelta` (interface): interface EquippedStatDelta extends LootStatDelta — A per-stat delta from the equipped item to the candidate; positive `delta` means the candidate is larger.
- `ItemDrop` (interface): interface ItemDrop extends LootItem — A rolled item with a stable instance id, so a stash, ledger and vendor stock can name it.
- `RollDropOptions` (interface): interface RollDropOptions extends LootRollOptions — {@link rollDrop} options: the loot roll plus the instance id (defaults to `drop:<seed>`).
- `compareToEquipped` (function): function compareToEquipped(candidate: ItemDrop, equipped: ItemDrop | null, options: LootComparisonOptions = {}): EquippedComparison — Compare a dropped item against what is equipped, with one delta per stat and a weighted verdict. The delta is `candidate - equipped`; `better` flips for stats the caller lists in `lowerIsBetter`, so reload time improving does not read as worse. A missing equipped item compares against zeros.
- `itemMass` (function): function itemMass(item: Pick<LootItem, "mass">): number — Carried mass of a rolled item. Older saves may predate `mass`; those default to `1`.
- `rollDrop` (function): function rollDrop(catalog: LootCatalog, seed: string | number, options: RollDropOptions = {}): ItemDrop — Roll one item from a seed. Same seed, catalog and options produce the same id, name, affixes, stats and mass on every run; level gates which bases and affixes are in the pool.

## @jgengine/core/loot/haul

- `CarryOutcome` (type): type CarryOutcome = | { ok: true; mass: number; remaining: number } | { ok: false; reason: "over-capacity" | "no-space" | "invalid-count"; mass: number; remaining: number } — What a carry attempt returns: the new load, or the rule that refused it.
- `HaulTransfer` (interface): interface HaulTransfer — Stacks moved between a run and its stash, or lost when the run fails.
- `RunHaul` (interface): interface RunHaul — A run's carried loot and the stash that outlives it.
- `RunHaulConfig` (interface): interface RunHaulConfig<TId extends string> — What a run haul needs: two inventories, a weight rule and an optional save cell.
- `RunHaulState` (interface): interface RunHaulState — Detached run and stash contents, for a save or a debug readout.
- `createRunHaul` (function): function createRunHaul<TId extends string>(config: RunHaulConfig<TId>): RunHaul — A run's haul beside a persistent stash. Carrying is gated by the shared encumbrance rules; `bank` moves what the stash fits and saves; `fail` throws the run's haul away and leaves the stash as it was. The game decides when a run succeeds or fails and calls one of them.

## @jgengine/core/loot/lootGen

- `LootBaseDef` (interface): interface LootBaseDef extends ItemBaseDef — A base family (frame, housing, chassis — caller nouns) with its slots, stats and affix pools.
- `LootCatalog` (interface): interface LootCatalog — Everything a roll reads: bases, parts, affixes, rarity odds, makers and the level curve.
- `LootComparison` (interface): interface LootComparison — How two items compare: every stat delta plus one weighted score for each.
- `LootComparisonOptions` (interface): interface LootComparisonOptions — Caller policy for the comparison score.
- `LootInstalledPart` (interface): interface LootInstalledPart — One part occupying one slot of a rolled item.
- `LootIssueCode` (type): type LootIssueCode = | "invalid-level" | "unknown-base" | "level-gated-base" | "unknown-manufacturer" | "manufacturer-base" | "unknown-rarity" | "duplicate-slot" | "unknown-slot" | "missing-slot-part" | "unknown-part" | "part-category" | "unknown-affix" | "duplicate-affix" | "invalid-affix" | "non-f… — A defect found by {@link validateLootItem}.
- `LootItem` (interface): interface LootItem — One rolled item: the base, maker, rarity, level, composed name, chosen parts, rolled affixes and resolved stats. Plain JSON, so a save stores it and the instance registry can key it.
- `LootManufacturerDef` (interface): interface LootManufacturerDef — A maker with a stat personality: its mark goes in the name, `bias` shifts stats additively, `scale` multiplies them, and favored affix pools weigh more when this maker rolls the item.
- `LootPartDef` (interface): interface LootPartDef extends PartDef — A part a base can mount: its stats, a pick weight, and an optional word for the item name.
- `LootRollOptions` (interface): interface LootRollOptions — Pin any part of a roll; omitted fields are drawn from the catalog.
- `LootRoller` (interface): interface LootRoller — A roll counter over one catalog: every roll goes through {@link rollLoot}, and the handle keeps counters (a distribution readout in the debug overlay) that snapshot and restore as plain data.
- `LootRollerOptions` (interface): interface LootRollerOptions — Options for {@link createLootRoller}.
- `LootRollerState` (interface): interface LootRollerState — Saved counters of a {@link LootRoller}.
- `LootStatDelta` (interface): interface LootStatDelta — A per-stat comparison entry; `delta` is `b - a`, so positive means the second item is larger.
- `LootValidationIssue` (interface): interface LootValidationIssue — One reason a rolled item is not legal against its catalog, with the offending value named.
- `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.
- `assertLootCatalog` (function): function assertLootCatalog(catalog: LootCatalog): void — Check a catalog before rolling; throws `RangeError` naming the offending entry.
- `compareLootItems` (function): function compareLootItems(a: LootItem, b: LootItem, options: LootComparisonOptions = {}): LootComparison — Compare two rolled items: every stat delta plus one weighted score for each, with caller-named weights and which stats read better when small.
- `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.
- `lootLevelScale` (function): function lootLevelScale(catalog: LootCatalog, level: number): number — Stat multiplier at `level` from the catalog's level curve; `1` when the catalog declares none.
- `lootStatContributions` (function): function lootStatContributions(stats: Readonly<Record<string, number>>, options: Pick<LootComparisonOptions, "weights" | "lowerIsBetter"> = {}): Record<string, number> — Per-stat weighted contribution: `value × weight`, negated for stats listed in `lowerIsBetter`. This is the single weight policy behind {@link scoreLootStats}, {@link compareLootItems} and a gear score, so an item and a whole loadout are never ranked by different arithmetic.
- `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.
- `scoreLootStats` (function): function scoreLootStats(stats: Readonly<Record<string, number>>, options: Pick<LootComparisonOptions, "weights" | "lowerIsBetter"> = {}): number — One stat block's weighted score: the sum of `value × weight`, negated for stats listed in `lowerIsBetter`. Pair it with {@link lootStatContributions} when a caller also needs the split.
- `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.

## @jgengine/core/loot/lootWeapon

- `LootWeaponProjection` (interface): interface LootWeaponProjection — A base weapon definition plus the stat map a rolled item overrides.
- `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.
- `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.

## @jgengine/core/loot/salvage

- `ItemDropLike` (interface): interface ItemDropLike — The fields salvage reads; an `ItemDrop` from `./drop` satisfies it.
- `ItemLedger` (interface): interface ItemLedger — One record of what happened to rolled item instances. Every path that removes an item - salvage, sale, granting a duplicate - claims it here first, so a second claim returns false and the item cannot be equipped, sold or broken down twice.
- `ItemLedgerState` (type): type ItemLedgerState = Readonly<Record<string, Exclude<ItemLifecycle, "owned">>> — Items that have left play, keyed by instance id; anything absent is still `owned`.
- `ItemLifecycle` (type): type ItemLifecycle = "owned" | "salvaged" | "sold" — Where an item instance stands: still usable, broken down, or sold.
- `SalvageResult` (type): type SalvageResult = | { ok: true; id: string; yield: SalvageYield } | { ok: false; reason: "already-spent" | "invalid-item" } — Salvage outcome: the yield, or the reason the instance could not be broken down.
- `SalvageTable` (interface): interface SalvageTable — What a broken-down item is worth: a game-authored currency, rate and per-rarity multiplier.
- `SalvageYield` (interface): interface SalvageYield — The currency and amount one salvage yields. `currency` is the game's key, never interpreted.
- `createItemLedger` (function): function createItemLedger(initial: ItemLedgerState = {}): ItemLedger — Build an item ledger. Ids are consumed once: the first successful {@link ItemLedger.spend} wins, every later call fails, which is what makes salvage and sale mutually exclusive.
- `salvageItem` (function): function salvageItem(item: ItemDropLike, table: SalvageTable, ledger: ItemLedger): SalvageResult — Break one item down through its ledger. The ledger is claimed before the yield is computed, so a salvaged item cannot be salvaged, equipped or sold again; pass the game's own wallet update from `yield`.
- `salvageValue` (function): function salvageValue(item: Pick<ItemDropLike, "level" | "rarity">, table: SalvageTable): SalvageYield — The yield an item of this level and rarity breaks down into. The formula is `round(perLevel x level x rarityMultiplier)`, floored by `minimum`, so the same item always yields the same amount and a higher level never yields less.

## @jgengine/core/loot/vendor

- `StockVendorOptions` (interface): interface StockVendorOptions — What stocking a vendor reads: the roll catalog, a seeded rng and the pricing policy.
- `VendorOffer` (interface): interface VendorOffer — One stocked item and the shop entry that prices it.
- `VendorPriceRule` (interface): interface VendorPriceRule — How a vendor price is derived from an item: a base, a per-level rate and a rarity multiplier.
- `VendorRotation` (interface): interface VendorRotation — A run-count refresh rule; the game owns how many runs between restocks.
- `VendorRotationState` (interface): interface VendorRotationState — Where a vendor shelf stands: the run number it was last stocked on.
- `createVendorRotation` (function): function createVendorRotation(everyRuns: number, start = 0): VendorRotation — A restock rule the game authors as "every N runs". It only answers when a refresh is due; the game calls {@link stockVendor} and then `mark`. No timer, so a paused or reloaded save keeps the same shelf until the run count moves.
- `itemPrice` (function): function itemPrice(item: Pick<LootItem, "level" | "rarity">, rule: VendorPriceRule): { buy: number; sell: number | null } — The price of one item under a `VendorPriceRule`: `round(base + perLevel x level)` times the rarity multiplier, never below 1. Sell-back is `floor(price x sellFactor)` when the rule sets one.
- `stockVendor` (function): function stockVendor(shop: ShopStock, options: StockVendorOptions): VendorOffer[] — Roll a vendor's shelf and add it to an existing {@link ShopStock}. Entries added by a previous call with the same `idPrefix` are removed first, so a refresh replaces the shelf instead of throwing on duplicate ids. Buying, selling and wallet charging stay in the economy owner.

## @jgengine/core/mission/compositions

- `ChaseMissionOptions` (interface): interface ChaseMissionOptions extends ComposedMissionOptions — Options for {@link chaseMission}: a target kept close until it is caught.
- `ComposedMissionOptions` (interface): interface ComposedMissionOptions — Options shared by every composed mission.
- `DefendMissionOptions` (interface): interface DefendMissionOptions extends ComposedMissionOptions — Options for {@link defendMission}: hold a position, scored by what is left standing.
- `EscortMissionOptions` (interface): interface EscortMissionOptions extends ComposedMissionOptions — Options for {@link escortMission}: a protected actor that must reach a destination alive.
- `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.
- `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.
- `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.

## @jgengine/core/mission/mission

- `DEFAULT_ESCAPE_MULTIPLE` (const): const DEFAULT_ESCAPE_MULTIPLE: 3 — A pursuit escapes at this multiple of its keep-close distance when none is declared.
- `DEFAULT_MARKER_TOLERANCE` (const): const DEFAULT_MARKER_TOLERANCE: 8 — Default vertical allowance (m) for a horizontal marker proximity test.
- `DEFAULT_PURSUE_DISTANCE` (const): const DEFAULT_PURSUE_DISTANCE: 3 — Default keep-close distance (m) for a `pursue` objective.
- `DEFAULT_REACH_RADIUS` (const): const DEFAULT_REACH_RADIUS: 2.5 — Default proximity radius (m) for a `reach` / `interact` objective.
- `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.
- `MissionActorFact` (interface): interface MissionActorFact — A live actor the machine tracks: whether it is alive and, when needed, where it is.
- `MissionBranch` (interface): interface MissionBranch — One outgoing edge of an objective: the first branch whose `when` matches wins over `next`.
- `MissionDef` (interface): interface MissionDef — A whole mission: the objective graph plus its fail states and rewards.
- `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.
- `MissionEventFilter` (interface): interface MissionEventFilter — Which world events an objective counts or a fail condition reacts to. Absent fields do not filter.
- `MissionFactCondition` (interface): interface MissionFactCondition — A readable fact test a branch or a `fact` fail condition reads. All comparators are optional.
- `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.
- `MissionFailDef` (interface): interface MissionFailDef — A named fail state an objective, timer or branch can land in.
- `MissionIssue` (interface): interface MissionIssue — A located mission-catalog problem; `path` is a JSON Pointer into the supplied catalog.
- `MissionMarkerPlane` (type): type MissionMarkerPlane = "horizontal" | "spatial" — Which plane a marker proximity test compares in.
- `MissionMarkerProximity` (interface): interface MissionMarkerProximity — How a positional objective compares an actor to its authored marker.
- `MissionObjectiveDef` (interface): interface MissionObjectiveDef — One objective. Every field is content; the machine reads only these.
- `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`).
- `MissionRewardAppliers` (interface): interface MissionRewardAppliers — Appliers a mission reward routes through — the same shape quests use, plus a loot-table hook.
- `MissionRewards` (interface): interface MissionRewards extends QuestRewards — What a mission pays. Economy/XP/items/unlocks flow through the quest appliers; loot names tables.
- `MissionRuntime` (interface): interface MissionRuntime — The mission state machine over one active mission.
- `MissionRuntimeConfig` (interface): interface MissionRuntimeConfig — Everything a mission runtime needs.
- `MissionRuntimeSnapshot` (interface): interface MissionRuntimeSnapshot — Serializable runtime state for a save.
- `MissionState` (interface): interface MissionState — Serializable mission state — one active mission's position in its graph.
- `MissionStats` (interface): interface MissionStats — Counters a devtools probe or a test reads.
- `MissionStatus` (type): type MissionStatus = "active" | "completed" | "failed" — Where a mission is in its life.
- `MissionTickInput` (interface): interface MissionTickInput — Everything the machine reads for one tick. All optional; a mission only touches what it declares.
- `MissionValidationOptions` (interface): interface MissionValidationOptions — Declarations a mission catalog is validated against.
- `MissionView` (interface): interface MissionView — Pooled per-frame readout a HUD tracker renders.
- `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.
- `MissionWorldEventKind` (type): type MissionWorldEventKind = "kill" | "collect" | "deliver" — What a reported world event is.
- `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.
- `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.
- `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.
- `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.

## @jgengine/core/mission/triggers

- `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.
- `MissionTriggerBridge` (interface): interface MissionTriggerBridge — Watches a document's authored mission triggers against moving actors.
- `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.
- `missionMarkers` (function): function missionMarkers(document: SceneDocumentLike): Record<string, ScenePoint3> — Marker positions from an authored scene, keyed by marker id — what a positional objective reads.
- `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.

## @jgengine/core/progression/careerBank

- `CareerBank` (interface): interface CareerBank — Persistent career money plus the run in progress, which a failed run loses.
- `CareerBankConfig` (interface): interface CareerBankConfig — Configuration for {@link createCareerBank}.
- `CareerBankState` (interface): interface CareerBankState — Everything a career bank stores, as plain JSON. `banked` is the persistent balance; `haul` is the run in progress and is the part a failed run loses. `deposited`, `lost`, `bestHaul` and `runs` are lifetime counters a results screen reads.
- `createCareerBank` (function): function createCareerBank(config: CareerBankConfig): CareerBank — Money that means something between runs: a persistent balance plus a run's haul that is banked on a cash-out and lost on a failure. Amounts are snapped to the currency's minor units, so a save round-trip and a display never drift. Pair it with `economy/upgrades` for a career upgrade tree.

## @jgengine/core/progression/gates

- `GateDef` (interface): interface GateDef — A milestone: content that opens exactly when its requirements hold and names the unlock it grants. `unlock` must resolve in the catalog the set is built with, or the set refuses to load.
- `GateFacts` (interface): interface GateFacts — What a gate is evaluated against: standing by track and money by currency.
- `GateMiss` (type): type GateMiss = "standing" | "balance" — Which named condition a closed gate still needs.
- `GateRequirement` (interface): interface GateRequirement — Every condition a gate can require; all named conditions must hold.
- `GateSet` (interface): interface GateSet — Evaluated gate content: the table, its status against facts, and the grants a caller applies.
- `GateSetConfig` (interface): interface GateSetConfig — Content and the resolvers a {@link GateSet} is built from.
- `GateStatus` (interface): interface GateStatus — One gate against live facts.
- `assertGates` (function): function assertGates(config: GateSetConfig): void — Check an authored gate table against the content it grants; throws `RangeError` naming the gate.
- `createGateSet` (function): function createGateSet(config: GateSetConfig): GateSet — Authored unlock gates: each one names the unlock it grants and the standing or balance it reads. Evaluated against caller-supplied facts, so one table serves a single-player save, a server actor or a probe. Load refuses a gate whose unlock id resolves to nothing (the D3.8 class), so a dead milestone fails at startup instead of in play. A gate with no requirements is open from the start.
- `gateFacts` (function): function gateFacts(standing: Pick<Standing, "standing">, actorId: string, balances: Readonly<Record<string, number>> = {}): GateFacts — Read a {@link Standing} and a balance record as {@link GateFacts}.

## @jgengine/core/progression/gearScore

- `GearScore` (interface): interface GearScore — A scored loadout: the total, each slot's share, each stat's signed contribution, and how complete it is.
- `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.
- `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.
- `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.
- `gearScore` (function): function gearScore(set: Readonly<Record<string, GearSlotItem | null | undefined>>, options: GearScoreOptions = {}): GearScore — Score a whole loadout with one documented formula:

## @jgengine/core/progression/skillTree

- `SkillActiveDef` (interface): interface SkillActiveDef — An action a node or synergy unlocks, shaped to bind straight into `createAbilityKit`'s slot config.
- `SkillNodeDef` (interface): interface SkillNodeDef<TStat extends string = string> — One authored tree node. Every field except `id` is optional data, so a game states its own tree: what a rank costs, what must come first, the passive it folds in and the actions it opens.
- `SkillRequirement` (interface): interface SkillRequirement — One node that must be at or above `rank` for a node or synergy to open; `rank` defaults to `1`.
- `SkillResolution` (interface): interface SkillResolution<TStat extends string = string> — The whole outcome of a build: merged passives, unlocked actions, live synergies and point accounting.
- `SkillSpendReason` (type): type SkillSpendReason = | "unknown-node" | "max-rank" | "no-points" | "requires" | "branch-points" | "excluded" — Why a spend was refused; each reason is reachable from authored data, so a UI can say which rule bit.
- `SkillSpendResult` (type): type SkillSpendResult = | { ok: true; spent: number; pointsAvailable: number } | { ok: false; reason: SkillSpendReason; detail: string } — The outcome of one spend or legality check: what it costs and the balance after it, or the rule that stopped it.
- `SkillSynergyDef` (interface): interface SkillSynergyDef<TStat extends string = string> — A payoff that exists only when two or more nodes are ranked together. This is what rewards breadth over dumping every point into one branch.
- `SkillTree` (interface): interface SkillTree<TStat extends string = string> — A live skill tree over one authored config, with respec, snapshot/restore and an optional devtools probe.
- `SkillTreeConfig` (interface): interface SkillTreeConfig<TStat extends string = string> — Everything {@link createSkillTree} reads: nodes, optional synergies, and starting points.
- `SkillTreeState` (interface): interface SkillTreeState — Saved tree state: unspent points and the rank of every ranked node.
- `assertSkillTreeConfig` (function): function assertSkillTreeConfig<TStat extends string>(config: SkillTreeConfig<TStat>): void — Check tree data before play; throws `RangeError` naming the offending node, requirement or synergy.
- `createSkillTree` (function): function createSkillTree<TStat extends string = string>(config: SkillTreeConfig<TStat>, options: { devtoolsName?: string } = {}): SkillTree<TStat> — A data-authored skill tree: nodes carry a point cost, prerequisites, passives and unlocked actions, synergies pay off two or more nodes together, and `respec` refunds exactly the points spent. Spend against `canSpend` for a reason a UI can show; read `resolved()` for the stat modifiers and action list to feed `createStats` / `createAbilityKit`.

## @jgengine/core/progression/standing

- `Standing` (interface): interface Standing — Live standing over authored tracks, moved by named outcomes or direct adjustments, with the tier on each track and a serializable snapshot.
- `StandingChange` (interface): interface StandingChange — One track's movement, with the tier on both sides so a caller can announce a crossing.
- `StandingConfig` (interface): interface StandingConfig — Authored standing content: the tracks an actor stands with, and the outcomes that move them.
- `StandingOutcomeDef` (interface): interface StandingOutcomeDef — One outcome a game can report, and the standing it moves on each track.
- `StandingRequirement` (interface): interface StandingRequirement — A threshold on one track, as an unlock or an upgrade reads it.
- `StandingState` (interface): interface StandingState — Plain JSON state of a {@link Standing}; tracks left at their authored `initial` are absent.
- `StandingTrackDef` (interface): interface StandingTrackDef — One standing track: a faction, a district, a licence board — whatever an authored outcome moves.
- `assertStandingConfig` (function): function assertStandingConfig(config: StandingConfig): void — Check authored standing content before use; throws `RangeError` naming the offending field.
- `createStanding` (function): function createStanding(config: StandingConfig): Standing — Per-faction or per-district standing that rises and falls from named outcomes, over authored tracks. Numbers live in the shared reputation ledger (`faction/reputation`); this adds the authored outcome table, tier-per-track and the one snapshot a save stores. An outcome id or track id that resolves to nothing throws at the call, so authored content fails loudly.

## @jgengine/core/progression/statGraph

- `StatContribution` (interface): interface StatContribution — One folded contribution to a value, retained so a sheet can explain "why is this value 42?" — every step carries the source that produced it.
- `StatContributionStep` (interface): interface StatContributionStep extends StatContribution — One line of a provenance trace: a contribution plus the running total after it folds in.
- `StatDeriveContext` (interface): interface StatDeriveContext — The read-only view a derived formula gets: resolved values of its declared dependencies.
- `StatDerivedDef` (interface): interface StatDerivedDef — A derived value whose formula and dependencies are caller-owned. `compute` may return a scalar (shorthand for a single `add`) or an ordered list of contributions folded left-to-right, so additive/multiplicative/clamped and conditional modifiers are all expressed as plain data or branches inside the function.
- `StatExplanation` (interface): interface StatExplanation — A full provenance trace for one stat: the ordered steps that produced its value.
- `StatGraph` (interface): interface StatGraph — A compiled, immutable stat-graph schema that mints per-entity {@link StatSheet}s from base values or saved state.
- `StatGraphDef` (interface): interface StatGraphDef — The full schema of a stat graph: its named inputs and caller-authored derived formulas.
- `StatInputDef` (interface): interface StatInputDef — A game-owned named input value. The engine ships no attribute vocabulary — ids, bounds, defaults, and metadata are entirely caller data, so the same graph can model STR/AGI/INT, SPECIAL scores, skills, difficulty knobs, or anything else.
- `StatModEntry` (type): type StatModEntry = StatContribution | readonly StatContribution[] — A modifier entry targeting one stat: a single contribution or an ordered list.
- `StatOp` (type): type StatOp = "add" | "mul" | "override" | "clampMin" | "clampMax" — How a single contribution folds into a running value.
- `StatSheet` (interface): interface StatSheet — A live per-entity instance of a {@link StatGraph}: mutable base values and modifier sources over a shared schema.
- `StatSheetState` (interface): interface StatSheetState — Plain-data, JSON-safe sheet state: input base values plus registered modifier sources.
- `createStatGraph` (function): function createStatGraph(def: StatGraphDef): StatGraph — A data-driven stat graph: game-owned named inputs feed caller-authored derived formulas, with contribution provenance, uncommitted previews, cycle detection, and selective recomputation. Formula semantics and numeric tables stay entirely game-defined.
- `statModifierContributions` (function): function statModifierContributions<TStat extends string>(source: string, set: StatModifierSet<TStat>): Record<string, StatContribution[]> — Bridge the shared {@link StatModifierSet} shape (add/multiply, used by talents, items, and buffs) into stat-graph contributions, so a ranked talent tree or gear roll feeds the graph as one named source instead of a parallel store.

## @jgengine/core/progression/upgrades

- `UpgradeBuy` (type): type UpgradeBuy = { ok: true; nodeId: string; rank: number; cost: number } | { ok: false; reason: UpgradeRejection } — Result of {@link UpgradeTree.buy}: the rank reached and what it cost, or why it was refused.
- `UpgradeNodeDef` (interface): interface UpgradeNodeDef — One upgrade node. Its price is the shared progression {@link Curve} evaluated at the rank being bought, so a game authors one curve and every rank of every node follows it.
- `UpgradeRejection` (type): type UpgradeRejection = "unknown-node" | "max-rank" | "missing-prerequisites" | "standing" | "insufficient-funds" — Why a purchase was refused; the tree is left untouched on any rejection.
- `UpgradeState` (interface): interface UpgradeState — Plain JSON state: node id → ranks owned. Nodes at rank `0` are absent.
- `UpgradeTree` (interface): interface UpgradeTree — Authored upgrade nodes with a per-node cost curve, prerequisites, a standing gate and one snapshot.
- `UpgradeTreeConfig` (interface): interface UpgradeTreeConfig — Authored nodes plus the standing a node's requirement reads.
- `assertUpgrades` (function): function assertUpgrades(config: UpgradeTreeConfig): void — Check authored upgrade nodes; throws `RangeError` naming the offending node or field.
- `createUpgradeTree` (function): function createUpgradeTree(config: UpgradeTreeConfig): UpgradeTree — An upgrade tree whose prices come from the shared curve primitive: each node authors one cost curve, each rank is that curve at the rank, and a purchase passes prerequisites, a standing gate and the caller's own payment step. State is one rank map that JSON round-trips, so a career save stores what a player paid for rather than the arithmetic behind it.

## @jgengine/core/progression/xpCurve

- `XpCurve` (interface): interface XpCurve — A resolved, validated {@link XpCurveDef}: thresholds, lifetime totals, a stated rule, and a leveling track bound to the same numbers.
- `XpCurveDef` (interface): interface XpCurveDef — Authorable XP curve data. Thresholds are generated from one growth rule, so a game states its curve and its cap instead of hand-writing a table it cannot rebalance, and every consumer of the same data agrees on the numbers.
- `XpGrowthRule` (type): type XpGrowthRule = "flat" | "linear" | "power" | "geometric" | "table" — Named rule a level threshold grows by. `flat` repeats `step`; `linear` adds `growthRate` per level; `power` uses `level ^ growthRate`; `geometric` multiplies by `growthRate`; `table` reads `table`.
- `XpLevelStep` (interface): interface XpLevelStep — One row of a resolved curve: the threshold at `level`, and the lifetime XP it sits at.
- `assertXpCurve` (function): function assertXpCurve(def: XpCurveDef): void — Check curve data before use; throws `RangeError` naming the offending field.
- `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.

## @jgengine/core/puzzle/cellGrid

- `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.
- `CellRun` (interface): interface CellRun<T> — A straight line of matching cells found by {@link findRuns}.
- `cellAt` (function): function cellAt<T>(grid: CellGrid<T>, x: number, y: number): T | null — The value at `(x, y)`, or `null` when empty or off the board.
- `clearRows` (function): function clearRows<T>(grid: CellGrid<T>, rows: readonly number[]): CellGrid<T> — A copy with `rows` removed and the rows above shifted down, refilling empty rows at the top.
- `collapseColumns` (function): function collapseColumns<T>(grid: CellGrid<T>): CellGrid<T> — A copy where every column's cells fall to the bottom, keeping their order.
- `createCellGrid` (function): function createCellGrid<T>(width: number, height: number): CellGrid<T> — An empty `width` × `height` board. Every helper here returns a new grid, so a store slot can hold it and undo, replay, and save/restore work without copying.
- `findRuns` (function): function findRuns<T>(grid: CellGrid<T>, minLength: number, matches: (a: T, b: T) => boolean = (a, b) => a === b): CellRun<T>[] — Horizontal and vertical runs of at least `minLength` cells whose values `matches` (default `===`).
- `fullRows` (function): function fullRows<T>(grid: CellGrid<T>): number[] — Indices of rows with no empty cell, top to bottom.
- `inGridBounds` (function): function inGridBounds<T>(grid: CellGrid<T>, x: number, y: number): boolean — Whether `(x, y)` lies on the board.
- `withCell` (function): function withCell<T>(grid: CellGrid<T>, x: number, y: number, value: T | null): CellGrid<T> — A copy with `(x, y)` set to `value`; off-board writes return the grid unchanged.
- `withCells` (function): function withCells<T>(grid: CellGrid<T>, entries: readonly { readonly x: number; readonly y: number; readonly value: T | null }[]): CellGrid<T> — A copy with every in-bounds entry written; one allocation for a whole piece or stamp.

## @jgengine/core/puzzle/fallingPiece

- `FallingPiece` (interface): interface FallingPiece<TShape extends string = string> { readonly shape: TShape; readonly rotation: number; readonly x: number; readonly y: number } — ⚠ undocumented
- `LockDelayState` (interface): interface LockDelayState { readonly delaySeconds: number; readonly elapsed: number } — ⚠ undocumented
- `ShapeTable` (type): type ShapeTable<TShape extends string = string> = Record< TShape, readonly (readonly (readonly [number, number])[])[] > — ⚠ undocumented

## @jgengine/core/puzzle/nonogram

- `NonogramCell` (type): type NonogramCell = "unknown" | "filled" | "empty" — A cell in a nonogram line: not yet determined, painted, or ruled out.
- `NonogramClue` (type): type NonogramClue = readonly number[] — A line clue — the lengths of its consecutive filled runs, in order.
- `NonogramSolution` (type): type NonogramSolution = readonly (readonly boolean[])[] — A solved grid, row-major; `true` is a filled cell.
- `NonogramSolveResult` (interface): interface NonogramSolveResult — Outcome of {@link solveNonogram}: the deduced board and whether propagation fully determined it.

## @jgengine/core/random/nameGen

- `NameGenerator` (interface): interface NameGenerator { name(): string } — ⚠ undocumented · used by `createNameGenerator`: Generate procedural names from templates and word banks with an injected random source.
- `NameGeneratorOptions` (interface): interface NameGeneratorOptions { rng: () => number; syllables: SyllableBank; minSyllables?: number; maxSyllables?: number; capitalize?: boolean } — ⚠ undocumented · used by `createNameGenerator`: Generate procedural names from templates and word banks with an injected random source.
- `SyllableBank` (interface): interface SyllableBank { onset?: readonly string[]; nucleus: readonly string[]; coda?: readonly string[] } — ⚠ undocumented
- `createNameGenerator` (function): function createNameGenerator(options: NameGeneratorOptions): NameGenerator — Generate procedural names from templates and word banks with an injected random source.
- `fillTemplate` (function): function fillTemplate(template: string, vars: Record<string, () => string> | Record<string, string>): string — ⚠ undocumented
- `pickFrom` (function): function pickFrom(rng: () => number, bank: readonly string[]): string — ⚠ undocumented

## @jgengine/core/random/pick

- `pickUniform` (function): function pickUniform<T>(rng: () => number, items: readonly T[]): T | undefined — Pick one item uniformly at random from `items` using `rng` (a `() => number` in `[0, 1)`); returns undefined when empty.
- `pickWeighted` (function): function pickWeighted<T>(rng: () => number, items: readonly T[], weightOf: (item: T) => number): T | undefined — Pick one item with probability proportional to `weightOf(item)`; skips non-positive weights, returns undefined when nothing is eligible.

## @jgengine/core/random/resolveRng

- `resetRngFallbackWarnings` (function): function resetRngFallbackWarnings(): void — Clears the warned-site memo. Tests only — the warning is once-per-site for the life of the process.
- `resolveRng` (function): function resolveRng(provided: (() => number) | undefined, site: string): () => number — Resolves an optional injected `[0,1)` generator, falling back to `Math.random` — and says so, once per call site.

## @jgengine/core/random/rng

- `RandomSeed` (type): type RandomSeed = number & { readonly __randomSeed: unique symbol } — Opaque, serializable PRNG cursor for state machines that must persist their own random stream (a spawn director, a heat/pursuit meter) instead of holding a closure — the state round-trips through save/load and multiplayer sync, so it can't carry a function. Never read or do arithmetic on the raw value directly; thread it through {@link stepRandomSeed} only.
- `SeededRng` (interface): interface SeededRng — A {@link seededRng} stream: callable like any `() => number`, with its cursor readable and restorable for snapshots and replay.
- `hashString` (function): function hashString(text: string): number — Deterministic 32-bit FNV-1a hash of a string → unsigned int. Same text, same number, on every platform — the stable seed behind per-id jitter, spread offsets, and content-addressed variation.
- `randomSeedFrom` (function): function randomSeedFrom(seed: number): RandomSeed — Wraps an already-integer seed (e.g. a `config.seed`) as a {@link RandomSeed} — no hashing.
- `restoreRng` (function): function restoreRng(rng: () => number, cursor: number): void — Restore a seeded stream's cursor; a no-op for generators that carry no state.
- `rngStateOf` (function): function rngStateOf(rng: () => number): number | null — The cursor of a seeded stream, or `null` for a generator that carries no state (an injected closure, `Math.random`).
- `seededRng` (function): function seededRng(seed: string | number): SeededRng — Deterministic pseudo-random generator seeded from a string or number — same seed, same sequence.
- `seededStreams` (function): function seededStreams(seed: string | number): (stream: string) => () => number — Derives independent, deterministic {@link seededRng} streams from one base seed, keyed by stream name.
- `stepRandomSeed` (function): function stepRandomSeed(seed: RandomSeed): readonly [value: number, next: RandomSeed] — One step of the {@link seededRng} recurrence in pure (seed in, seed out) form — the same mulberry32-style generator, shared by every state machine that persists its own PRNG cursor instead of closing over a generator.

## @jgengine/core/random/seedLink

- `DEFAULT_SEED_PARAM` (const): const DEFAULT_SEED_PARAM: "seed" — ⚠ undocumented

## @jgengine/core/relation/keyedValues

- `NumericBounds` (interface): interface NumericBounds — Optional inclusive `[min, max]` clamp applied after a write. Omit an edge for unbounded.
- `PairKeyCodec` (interface): interface PairKeyCodec — Canonicalizes a two-part relation identity into a single delimiter-safe record key.
- `PairKeyOptions` (interface): interface PairKeyOptions — Direction and delimiter policy for {@link createPairKeyCodec}.
- `addValue` (function): function addValue(record: Record<string, number>, key: string, delta: number, bounds?: NumericBounds): number — Add `delta` to `key` (clamped to `bounds`), writing the record in place. Returns the stored value.
- `clampValue` (function): function clampValue(value: number, bounds?: NumericBounds): number — Clamp a scalar to `bounds` (identity when `bounds` is omitted). Pure — touches no record.
- `createPairKeyCodec` (function): function createPairKeyCodec(options: PairKeyOptions = {}): PairKeyCodec — Build a pair-key codec for keyed relation values. Ids are escaped before joining, so any id (including ones containing the separator or a backslash) round-trips through {@link PairKeyCodec.key} → {@link PairKeyCodec.parse} without collision. Undirected codecs (the default) canonicalize so `key(a, b) === key(b, a)`.
- `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}.
- `getValue` (function): function getValue(record: Record<string, number>, key: string, fallback = 0): number — Current value for `key`, or `fallback` (default `0`) when the record has no entry.
- `setValue` (function): function setValue(record: Record<string, number>, key: string, value: number, bounds?: NumericBounds): number — Set `key` to `value` (clamped to `bounds`), writing the record in place. Returns the stored value.
- `towardValue` (function): function towardValue(record: Record<string, number>, key: string, target: number, maxDelta: number, bounds?: NumericBounds): number — Step `key` toward `target` by at most `maxDelta` without overshooting, then clamp to `bounds`. Writes in place and returns the stored value.

## @jgengine/core/relation/thresholds

- `CrossThresholdsOptions` (interface): interface CrossThresholdsOptions — Exact-boundary and dead-band policy for {@link crossThresholds}.
- `ThresholdBoundary` (interface): interface ThresholdBoundary<Id = string> — A labelled cut point on the value axis. `Id` is caller-owned (string, enum, or a policy object).
- `ThresholdCrossing` (interface): interface ThresholdCrossing<Id = string> — A single boundary transition between a `before` and `after` value.
- `ThresholdDirection` (type): type ThresholdDirection = "up" | "down" — Generic threshold-crossing detection over ordered numeric boundaries.
- `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`.
- `tierAt` (function): function tierAt<Id>(boundaries: readonly ThresholdBoundary<Id>[], value: number, options: { readonly inclusive?: boolean } = {}): ThresholdBoundary<Id> | null — The highest boundary at-or-below `value` — the band the value currently sits in. Returns `null` when `value` is below every boundary. Boundaries need not be sorted.

## @jgengine/core/rules/predicate

- `Predicate` (type): type Predicate = | { readonly all: readonly Predicate[] } | { readonly any: readonly Predicate[] } | { readonly not: Predicate } | { readonly eq: readonly [PredicatePath, PredicateValue] } | { readonly ne: readonly [PredicatePath, PredicateValue] } | { readonly gt: readonly [PredicatePath, number] }… — One node of the predicate tree. Combinators (`all`/`any`/`not`) nest; leaf comparators read a dot path from the facts and compare it. `has` passes when the path resolves to a non-nullish value.
- `PredicateFacts` (type): type PredicateFacts = Record<string, unknown> — Plain, serializable bag of facts a predicate reads by dot path.
- `PredicatePath` (type): type PredicatePath = string — Dot path into a fact bag, e.g. `"hit.crit"` or `"attacker.team"`.
- `PredicateValue` (type): type PredicateValue = string | number | boolean | null — A declarative, serializable predicate AST evaluated against a plain fact bag. Predicates carry no closures, so they survive save/load and stay deterministic — the reusable condition seam that event-conditioned rules, quests, perks, and reactive AI gate on instead of hand-rolled callbacks.
- `evaluatePredicate` (function): function evaluatePredicate(predicate: Predicate | undefined, facts: PredicateFacts): boolean — Evaluate a predicate against a fact bag. An omitted predicate matches unconditionally, so callers can treat "no condition" and "always" identically. Pure and deterministic — no allocation beyond path splits and no reliance on evaluation order between sibling clauses.
- `readPath` (function): function readPath(facts: PredicateFacts, path: PredicatePath): unknown — Read a dot path out of a fact bag, descending only through plain objects. Returns `undefined` when any segment is missing or non-traversable. Bounded by the path's segment count.

## @jgengine/core/rules/ruleEffects

- `RuleEffectDefinition` (interface): interface RuleEffectDefinition — A declared effect a triggered rule may reference. Behavior lives in the game; this is metadata.
- `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.
- `listRuleEffects` (function): function listRuleEffects(): RuleEffectDefinition[] — Every declared rule effect, for populating inspector dropdowns and validating a content set.
- `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.

## @jgengine/core/rules/triggeredRules

- `ActiveEffect` (interface): interface ActiveEffect — A live timed effect an engine is tracking until it expires or is cleaned up.
- `EffectRef` (interface): interface EffectRef — A reference to an effect the game knows how to apply — id plus JSON-safe params, no closures.
- `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.
- `RateLimit` (interface): interface RateLimit — Bounded firing budget over a sliding time window.
- `RuleEvent` (interface): interface RuleEvent — A typed event handed to the engine; roles feed target resolution, facts feed the predicate.
- `RuleFiring` (interface): interface RuleFiring — The outcome of matching one rule against one event. `applied` is the effect the caller should now run through its own effect system; a blocked firing reports why. Provenance (rule, owner, event, timestamp) rides along for auditability.
- `StackPolicy` (type): type StackPolicy = "refresh" | "stack" | "independent" | "ignore" — How a repeated application of the same rule's effect on the same target combines with a live one: `refresh` re-arms the timer at one stack, `stack` adds a stack up to `maxStacks` and re-arms, `independent` keeps each application as its own instance with its own expiry, `ignore` drops the new application while one is already active.
- `TargetRole` (type): type TargetRole = "subject" | "object" | "source" | "owner" — Role slots an event exposes; a target selector resolves one of these to a concrete id.
- `TargetSelector` (type): type TargetSelector = | { readonly role: TargetRole } | { readonly path: string } | { readonly literal: string } — How a rule picks the id its effect lands on: a fixed event role, a dot path into the event facts, or a literal id. Data-only so it saves with the rule.
- `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.
- `TriggeredRuleEngine` (interface): interface TriggeredRuleEngine — A running set of triggered rules with gating, timed lifetimes, stacking, cleanup, and save/load.
- `TriggeredRuleState` (interface): interface TriggeredRuleState — Serializable runtime state — everything that changes future triggers. Rules travel with it.
- `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.

## @jgengine/core/session/contestedChannel

- `ContestReaction` (type): type ContestReaction = "pause" | "decay" — ⚠ undocumented
- `ContestedChannel` (interface): interface ContestedChannel { start(team: string): ContestedEvent | null; tick(dt: number, occupants?: Record<string, number>): ContestedEvent[]; damage(reason?: string): ContestedEvent | null; reset(): void; progress(): number; phase(): ContestedPhase; owner(): strin… — ⚠ undocumented
- `ContestedChannelConfig` (interface): interface ContestedChannelConfig { duration: number; interruptOnDamage?: boolean; resetOnInterrupt?: boolean; favorability?: Record<string, number>; ratePerOccupant?: boolean; contested?: ContestReaction; decayRate?: number } — ⚠ undocumented
- `ContestedEvent` (interface): interface ContestedEvent { kind: ContestedEventKind; owner: string | null; progress: number; reason?: string } — ⚠ undocumented
- `ContestedEventKind` (type): type ContestedEventKind = "start" | "tick" | "contested" | "paused" | "complete" | "interrupted" — ⚠ undocumented
- `ContestedPhase` (type): type ContestedPhase = "idle" | "active" | "paused" | "contested" | "complete" | "interrupted" — ⚠ undocumented
- `ContestedSnapshot` (interface): interface ContestedSnapshot { phase: ContestedPhase; progress: number; owner: string | null; remaining: number } — ⚠ undocumented

## @jgengine/core/session/extraction

- `DeathResult` (interface): interface DeathResult { userId: string; kept: readonly ItemStack[]; lost: readonly ItemStack[]; scheduled: DeliveryEntry | null; consolationLoadoutId: string | null } — ⚠ undocumented
- `ExtractPoint` (interface): interface ExtractPoint { id: string; center: RingPoint; radius: number; holdSeconds: number; favorability?: Record<string, number>; interruptOnDamage?: boolean } — ⚠ undocumented
- `ExtractionAttempt` (interface): interface ExtractionAttempt { extractId: string; channel: ContestedChannel } — ⚠ undocumented
- `ExtractionResult` (interface): interface ExtractionResult { userId: string; extractId: string; banked: readonly ItemStack[] } — ⚠ undocumented
- `RaidPlayerSnapshot` (interface): interface RaidPlayerSnapshot { status: RaidStatus; extractId: string | null; progress: number; remaining: number } — ⚠ undocumented
- `RaidSession` (interface): interface RaidSession { beginExtract(userId: string, extractId: string, position: RingPoint, team?: string): ContestedEvent | null; tickExtract(userId: string, dt: number, occupants?: Record<string, number>): ContestedEvent[]; damage(userId: string, reason?: str… — ⚠ undocumented
- `RaidSessionConfig` (interface): interface RaidSessionConfig { extracts: readonly ExtractPoint[]; insurance?: InsurancePolicy; consolation?: ConsolationPolicy } — ⚠ undocumented
- `RaidStatus` (type): type RaidStatus = "in-raid" | "extracting" | "extracted" | "dead" — ⚠ undocumented

## @jgengine/core/session/ring

- `Ring` (interface): interface Ring { at(time: number): RingSample; isOutside(time: number, position: RingPoint): boolean; distanceOutside(time: number, position: RingPoint): number; damageOutside(time: number, dt: number, positions: Iterable<{id: string; position: RingPoint}… — ⚠ undocumented
- `RingConfig` (interface): interface RingConfig { center: RingPoint; phases: readonly RingPhase[] } — ⚠ undocumented
- `RingHit` (interface): interface RingHit { id: string; damage: number; distanceOutside: number } — ⚠ undocumented
- `RingPhase` (interface): interface RingPhase { startTime: number; shrinkDuration: number; fromRadius: number; toRadius: number; damagePerSecond: number; center?: RingPoint } — ⚠ undocumented
- `RingPoint` (type): type RingPoint = [number, number] — ⚠ undocumented
- `RingSample` (interface): interface RingSample { center: RingPoint; radius: number; damagePerSecond: number; phase: number; shrinking: boolean } — ⚠ undocumented
- `createRing` (function): function createRing(config: RingConfig): Ring — ⚠ undocumented
- `ringSampleAt` (function): function ringSampleAt(config: RingConfig, time: number): RingSample — ⚠ undocumented

## @jgengine/core/session/roles

- `RoleSpec` (interface): interface RoleSpec { id: string; count?: number; ratio?: number } — ⚠ undocumented

## @jgengine/core/session/roundState

- `LossBonusRule` (interface): interface LossBonusRule { base: number; step: number; max: number } — ⚠ undocumented
- `PhaseEndHook` (type): type PhaseEndHook<TPhase extends string = RoundPhase> = ( endingPhase: TPhase, nextPhase: TPhase, round: number, ) => void — ⚠ undocumented
- `RoundConfig` (interface): interface RoundConfig<TPhase extends string = RoundPhase> { phases: Record<TPhase, number>; teams: readonly string[] | readonly RoundTeam[]; phaseOrder?: readonly TPhase[]; winCondition?: (state: RoundSnapshot<TPhase>) => string | null; maxRounds?: number; winReward?: number; lossBonus?: LossBonus… — ⚠ undocumented
- `RoundEconomy` (interface): interface RoundEconomy { team: string; reward: number; won: boolean; lossStreak: number } — ⚠ undocumented
- `RoundEvent` (interface): interface RoundEvent<TPhase extends string = RoundPhase> { kind: RoundEventKind; round: number; phase?: TPhase; nextPhase?: TPhase; winner?: string; economy?: RoundEconomy[] } — ⚠ undocumented
- `RoundEventKind` (type): type RoundEventKind = | "phase.start" | "phase.end" | "round.win" | "round.economy" | "match.end" — ⚠ undocumented
- `RoundPhase` (type): type RoundPhase = string — ⚠ undocumented
- `RoundPhaseDurations` (interface): interface RoundPhaseDurations — Default phase-duration shape for the built-in buy/live/end cycle; pass a wider `Record<string, number>` when using a custom `phaseOrder`.
- `RoundSnapshot` (interface): interface RoundSnapshot<TPhase extends string = RoundPhase> { round: number; phase: TPhase; timeLeft: number; scores: Record<string, number>; lossStreaks: Record<string, number>; roles: Record<string, string | undefined>; matchOver: boolean; pendingWinner: string | null } — ⚠ undocumented
- `RoundState` (interface): interface RoundState<TPhase extends string = RoundPhase> { tick(dt: number): RoundEvent<TPhase>[]; concludeRound(winner: string): RoundEvent<TPhase>[]; evaluate(): RoundEvent<TPhase>[]; onPhaseEnd(hook: PhaseEndHook<TPhase>): () => void; phase(): TPhase; round(): number; timeLeft(): number; score… — ⚠ undocumented
- `RoundTeam` (interface): interface RoundTeam — A team entry with an optional role tag (e.g. "attacker", "defender") retrievable via `RoundState.roleOf`.

## @jgengine/core/sim/nearAgents

- `NearAgentSnapshot` (interface): interface NearAgentSnapshot — Serializable state of one near agent: where it walks, what it needs, what it last chose.
- `NearAgentView` (interface): interface NearAgentView — Everything a near agent is doing, for a HUD, a probe or a test. Allocates.
- `NearAgentsOptions` (interface): interface NearAgentsOptions — What the near side needs from the game: a nav mesh, the shared need definitions, and what agents can do.
- `NearCrowdAgents` (interface): interface NearCrowdAgents extends NearAgents — The near half of the off-screen world: one nav crowd for movement, one need set and utility brain per agent for what it wants. Resident identity survives the handoff because the off-screen world spawns and despawns through this seam and keeps the saved state.
- `createNearAgents` (function): function createNearAgents(options: NearAgentsOptions): NearCrowdAgents — Create the near-side simulation: agents on a nav mesh with decaying needs and a utility brain each. The off-screen world decides which agents exist here, so a resident beyond its radius costs this seam nothing at all — no path, no need tick, no decision.

## @jgengine/core/sim/needs

- `NeedDefinition` (type): type NeedDefinition = DecayMeterConfig — A decaying need is a survival decay meter (`max`/`min`/`start`/`rate`, optional moodle thresholds) whose satisfaction an agent brain reads to score actions. The meter owns the numbers; per-need appeal lives in the game's utility options.
- `NeedReading` (interface): interface NeedReading — One need's current satisfaction, worst-first ready: `fraction` is 0 (empty) … 1 (full).
- `NeedSet` (interface): interface NeedSet — Named needs that drain or recover on game time — hunger, energy, hygiene, bladder, fun. Reads are index-addressed (`indexOf` once, `fractionAt` per tick) so a thousand-agent loop never re-resolves ids; the whole set round-trips through {@link NeedSnapshot}.
- `NeedSnapshot` (interface): interface NeedSnapshot — Serializable need state: values plus any in-play retuning, so a save keeps the dials.
- `createNeedSet` (function): function createNeedSet(definitions: readonly NeedDefinition[]): NeedSet — Create the needs an agent or a park guest carries. Decay reuses the survival meter formulas (`survival/decayMeter`), so moodle thresholds, clamping and rate modifiers behave exactly like every other meter; this set adds index-addressed reads and single-need retuning for hot AI loops. Score these needs into an action with `createUtilityBrain` (`@jgengine/core/world`).

## @jgengine/core/sim/offScreen

- `NearAgents` (interface): interface NearAgents — The near half of the world: the game's real simulation. Only residents inside the radius are ever spawned here, which is what keeps far agents free of navigation and utility scoring.
- `NearHandoff` (interface): interface NearHandoff — What a near-side simulator hands back when a resident leaves range.
- `NearSpawn` (interface): interface NearSpawn — Everything a near-side simulator is told when a resident crosses into range.
- `OffScreenAgentView` (interface): interface OffScreenAgentView — A resident as a game or the devtools overlay reads it. Allocates a need copy — debug and tests.
- `OffScreenMode` (type): type OffScreenMode = "near" | "far" — Which side of the distance policy a resident is on: simulated near the viewer, or cheap state.
- `OffScreenOptions` (interface): interface OffScreenOptions — Options for {@link createOffScreenWorld}.
- `OffScreenPolicy` (interface): interface OffScreenPolicy — Where the near/far boundary is and what it costs. The radius, the cost model and the budget are the game's call — a city block and a haunted-house hallway do not share a number.
- `OffScreenPolicyPatch` (interface): interface OffScreenPolicyPatch — A policy change that stays reachable in play.
- `OffScreenResidentSpec` (interface): interface OffScreenResidentSpec — One resident of the world: an identity, where it belongs, and the day it follows.
- `OffScreenSnapshot` (interface): interface OffScreenSnapshot — Serializable world state: the policy and every resident, near ones included.
- `OffScreenStats` (interface): interface OffScreenStats — Counters a devtools probe or a test reads to prove far agents cost nothing.
- `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.
- `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.

## @jgengine/core/sim/population

- `Visitor` (interface): interface Visitor — One visitor on site: the id its body, its needs and its money are keyed by.
- `VisitorAdoption` (interface): interface VisitorAdoption — How a body the game made itself joins the population.
- `VisitorFlow` (interface): interface VisitorFlow — What a flow policy reads to decide how many arrive and when one has had enough.
- `VisitorPolicy` (interface): interface VisitorPolicy — The game's flow policy: what draws visitors in, how many fit, and when one has had enough.
- `VisitorPolicyPatch` (interface): interface VisitorPolicyPatch — Flow policy fields a scenario can change in play.
- `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.
- `VisitorPopulationOptions` (interface): interface VisitorPopulationOptions — Options for {@link createVisitorPopulation}.
- `VisitorPopulationSnapshot` (interface): interface VisitorPopulationSnapshot — Serializable state. No on-site count is stored: it is the restored visitor list.
- `VisitorPopulationStats` (interface): interface VisitorPopulationStats — Counters a HUD, a probe or a test reads. The on-site figure is the visitor list's length.
- `VisitorWorld` (interface): interface VisitorWorld — The game's world behind every counted visitor: it creates and removes the body.
- `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.

## @jgengine/core/sim/queue

- `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.
- `DEFAULT_QUEUE_WINDOW` (const): const DEFAULT_QUEUE_WINDOW: 8 — Boarding events the throughput window keeps.
- `QueueEntry` (interface): interface QueueEntry — One guest waiting their turn, and when they joined the line.
- `QueueWait` (interface): interface QueueWait — A wait estimate read off the queue's own measured throughput.
- `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.
- `WaitQueueOptions` (interface): interface WaitQueueOptions — Tunables for {@link createWaitQueue}, every one retunable through a restore.
- `WaitQueueSnapshot` (interface): interface WaitQueueSnapshot — Serializable line state: who is waiting, and the boardings the estimate is measured from.
- `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.

## @jgengine/core/sim/rides

- `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.
- `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.
- `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.
- `RideBreakdown` (interface): interface RideBreakdown — Breakdown curve and money for one ride. All data, so a park tunes its own economy.
- `RideChoicePolicy` (interface): interface RideChoicePolicy — Policy a park might vary when it turns taste and ride data into utility options.
- `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.
- `RideChooserConfig` (interface): interface RideChooserConfig — Everything a ride chooser needs: the park, the guest's taste, and the guest's needs.
- `RideChooserSnapshot` (interface): interface RideChooserSnapshot — Serializable chooser state: the guest's taste and the brain's held pick.
- `RideDefinition` (interface): interface RideDefinition — Everything a ride is: its ratings, its cycle and its wear. Content, not code.
- `RidePhase` (type): type RidePhase = "idle" | "loading" | "riding" | "unloading" | "broken" — Where a ride is in its cycle.
- `RideQueueView` (interface): interface RideQueueView — A ride's line as a game or the devtools overlay reads it.
- `RideRatingRange` (interface): interface RideRatingRange — The rating scale a park's taste curves are normalized against.
- `RideRatings` (interface): interface RideRatings — What a ride is worth to a guest. All three come from the ride's own data.
- `RideRetune` (interface): interface RideRetune — In-play dials a ride accepts from {@link RideSystem.retune}.
- `RideServiceResult` (interface): interface RideServiceResult — What a service cost the caller.
- `RideStats` (interface): interface RideStats — Counters a devtools probe or test reads.
- `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.
- `RideSystemConfig` (interface): interface RideSystemConfig — Everything a ride system needs.
- `RideSystemSnapshot` (interface): interface RideSystemSnapshot — Serializable park state: the clock, each ride's cycle position, wear and line.
- `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.
- `RideTickSink` (interface): interface RideTickSink — Where a ride's boardings, alightings and breakdowns are announced. Every hook is optional.
- `RideView` (interface): interface RideView — One ride's live state.
- `RideWaitSource` (interface): interface RideWaitSource — The live queue a ride-choice candidate is costed against. {@link RideSystem} satisfies this.
- `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.
- `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.
- `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.
- `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.
- `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.
- `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`.

## @jgengine/core/sim/routine

- `RoutineConfig` (interface): interface RoutineConfig — Everything needed to resolve a routine: its authored stops, its cycle, and how far apart places are.
- `RoutinePhase` (interface): interface RoutinePhase — Where a routine puts its agent at one instant.
- `RoutineStop` (interface): interface RoutineStop — One stop after travel is accounted for: the authored time and the time the agent really gets there.
- `RoutineStopSpec` (interface): interface RoutineStopSpec — One authored stop in a day: where the agent belongs, and when it wants to get there.
- `RoutineTimeline` (interface): interface RoutineTimeline — An authored day resolved against time: arrival times after walking, departures early enough to make the next stop, and a phase for any instant. Pure — there is no state to tick, so a far agent and a loaded save read the same day from the same clock.
- `resolveRoutine` (function): function resolveRoutine(config: RoutineConfig): RoutineTimeline — Resolve an authored routine into a timeline driven by the world clock.

## @jgengine/core/store/defineKeyedStore

- `KeyedStoreHandle` (interface): interface KeyedStoreHandle<T> — A typed, cast-free handle onto a per-owner keyed family of slots on the reactive game store (`ctx.game.store`) — the {@link StoreHandle} shape widened with an `id` (userId, instanceId, …) so one definition covers every owner instead of one `defineStore` call per key. `keyFor` composes the underlying store key from the id; call sites never see it. Writes flow through the engine store, so they bump `ctx.version()`, serialize into a {@link WorldSnapshot}, and replay under host authority — the same guarantees a hand-rolled `` `prefix:${id}` `` string plus `store.get(key) as T` gives up.
- `defineKeyedStore` (function): function defineKeyedStore<T>(keyFor: (id: string) => string, initial: T | (() => T)): KeyedStoreHandle<T> — Define a typed per-owner keyed family on the game store: game code expresses `read(ctx, userId)`/`write(ctx, userId, v)`/`update(...)` with the value type it means, and both the `` `prefix:${id}` `` key composition and the `unknown → T` cast live once, here, behind the boundary. Reach for this over N separate `defineStore` calls whenever the owning id varies at runtime (per-user class, per-instance auras) — `defineStore` stays the right call for a single fixed slot.

## @jgengine/core/store/defineStore

- `StoreHandle` (interface): interface StoreHandle<T> — A typed, cast-free handle onto one slot of the reactive game store (`ctx.game.store`). The single type parameter is fixed at definition; `read`/`write`/`update` never widen to `unknown`, so no call site repeats `store.get(key) as T`. Writes flow through the engine store, so they bump `ctx.version()`, serialize into a {@link WorldSnapshot}, and replay under host authority — the same guarantees a hand-rolled `store.get`/`store.set` pair gives up the moment it forks run state into a module-level singleton.
- `defineStore` (function): function defineStore<T>(key: string, initial: T | (() => T)): StoreHandle<T> — Define a typed slot on the game store: game code expresses `read(ctx)`/`write(ctx, v)`/`update(...)` with the value type it means, and the `unknown → T` cast lives once, here, behind the boundary. Pass a factory for `initial` when the fallback is a fresh mutable object; the factory runs at most once and its result is reused, so an unwritten slot keeps a stable identity across reads (no per-read churn for a React selector, no allocation on a hot path). A value that carries functions (a closure-based run store, an input handle) is runtime-only: snapshots, saves and replication skip it and hydration keeps it in place. Hold such objects with `perContext` when they need no store notifications.

## @jgengine/core/survival/decayMeter

- `DecayMeterConfig` (interface): interface DecayMeterConfig { id: string; max: number; min?: number; start?: number; rate: number; thresholds?: readonly MeterThreshold[] } — ⚠ undocumented · used by `createDecayMeterSet`: Named decay meters — hunger, thirst, oxygen, sanity, warmth, stamina.
- `DecayMeterSet` (interface): interface DecayMeterSet — Set of named survival meters (hunger/thirst/…) that drain and refill over game time.
- `DecayMeterState` (interface): interface DecayMeterState { id: string; value: number; max: number; min: number; fraction: number } — ⚠ undocumented · used by `decayMeterSnapshot`: Numeric state for every meter, keyed by id — the pure counterpart to {@link DecayMeterSet.snapshot}.
- `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.
- `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.
- `MeterThreshold` (interface): interface MeterThreshold { id: string; label: string; at: number; when: "below" | "above"; severity?: MoodleSeverity; icon?: string } — ⚠ undocumented
- `createDecayMeterSet` (function): function createDecayMeterSet(configs: readonly DecayMeterConfig[]): DecayMeterSet — Named decay meters — hunger, thirst, oxygen, sanity, warmth, stamina. Each drains (or recovers) on game-time `dt` at a configurable rate, refills from consumables or actions, and raises moodle statuses at thresholds. Rate modifiers let the environment drive them (colder → faster warmth loss; toxic biome → oxygen drops), so a game reads an environment field then calls `setRateModifier`.
- `decayMeterMoodles` (function): function decayMeterMoodles(values: DecayMeterValues, defs: readonly DecayMeterConfig[]): Moodle[] — Moodles for every crossed threshold, worst-first per meter in declared order.
- `decayMeterSnapshot` (function): function decayMeterSnapshot(values: DecayMeterValues, defs: readonly DecayMeterConfig[]): Record<string, DecayMeterState> — Numeric state for every meter, keyed by id — the pure counterpart to {@link DecayMeterSet.snapshot}.
- `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.
- `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}.
- `initDecayMeters` (function): function initDecayMeters(defs: readonly DecayMeterConfig[]): DecayMeterValues — Starting values for `defs` — each meter's `start ?? max`, clamped to its range. Seed a serialized state record with this instead of holding a {@link createDecayMeterSet} closure.
- `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}.

## @jgengine/core/survival/moodle

- `MOODLE_SEVERITY_ORDER` (const): const MOODLE_SEVERITY_ORDER: Record<MoodleSeverity, number> — ⚠ undocumented
- `Moodle` (interface): interface Moodle — One survival moodle (status icon) — severity, source, and label for HUD chips.
- `MoodleSeverity` (type): type MoodleSeverity = "good" | "neutral" | "warning" | "critical" — ⚠ undocumented
- `MoodleSource` (type): type MoodleSource = "meter" | "ailment" | "buff" — ⚠ undocumented
- `MoodleStack` (interface): interface MoodleStack — Ordered stack of active moodles derived from meters/ailments/buffs.
- `TimedMoodleInput` (interface): interface TimedMoodleInput { id: string; label: string; severity?: MoodleSeverity; icon?: string; note?: string; stacks?: number; duration?: number } — ⚠ undocumented
- `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.
- `stackMoodles` (function): function stackMoodles(...groups: readonly (readonly Moodle[])[]): Moodle[] — Merge any number of moodle groups into one stack — meters, ailments, and buffs share this display. Same-id moodles fold together (stacks add, worst severity wins); the result is ordered worst-first so the HUD reads critical statuses at a glance.

## @jgengine/core/survival/regionHealth

- `AilmentConfig` (interface): interface AilmentConfig { id: string; label: string; region?: string; severity?: MoodleSeverity; icon?: string; drainPerSecond?: number; stacking?: boolean; treatedBy?: readonly string[] } — ⚠ undocumented
- `AilmentInstance` (interface): interface AilmentInstance { id: string; stacks: number } — ⚠ undocumented
- `DamageResult` (interface): interface DamageResult { region: RegionHealthState; applied: number; dead: boolean } — ⚠ undocumented
- `HealthRegionConfig` (interface): interface HealthRegionConfig { id: string; label: string; max: number; vital?: boolean; vulnerability?: number } — ⚠ undocumented
- `MultiRegionHealth` (interface): interface MultiRegionHealth — Per-limb / per-region health track with treat/damage/heal APIs.
- `MultiRegionHealthConfig` (interface): interface MultiRegionHealthConfig { regions: readonly HealthRegionConfig[]; ailments?: Record<string, AilmentConfig> } — ⚠ undocumented · used by `createMultiRegionHealth`: Per-region/limb health tracked separately, so each body part takes and heals damage on its own.
- `RegionHealthState` (interface): interface RegionHealthState { id: string; label: string; current: number; max: number; fraction: number; vital: boolean } — ⚠ undocumented
- `TreatResult` (interface): interface TreatResult { treated: readonly string[] } — ⚠ undocumented
- `createMultiRegionHealth` (function): function createMultiRegionHealth(config: MultiRegionHealthConfig): MultiRegionHealth — Per-region/limb health tracked separately, so each body part takes and heals damage on its own.

## @jgengine/core/tactics/fallingGrid

- `FallingGrid` (interface): interface FallingGrid<TCell> { readonly cols: number; readonly rows: number; occupied(col: number, row: number): boolean; cellAt(col: number, row: number): TCell | null; setCell(col: number, row: number, value: TCell): void; clearCell(col: number, row: number): void; c… — ⚠ undocumented
- `FallingGridCell` (type): type FallingGridCell = readonly [number, number] — ⚠ undocumented
- `FallingGridConfig` (interface): interface FallingGridConfig { cols: number; rows: number; lockDelayMs?: number } — ⚠ undocumented
- `FallingGridSnapshot` (interface): interface FallingGridSnapshot<TCell> { cols: number; rows: number; cells: readonly (TCell | null)[] } — ⚠ undocumented
- `GravityIntervalConfig` (interface): interface GravityIntervalConfig { baseMs?: number; perLevel?: number; minMs?: number } — ⚠ undocumented
- `LockState` (interface): interface LockState — Elapsed grounded time for the lock-delay state machine. `null` means airborne / not timing.

## @jgengine/core/tactics/predictiveQuery

- `ArcPredictInput` (interface): interface ArcPredictInput { from: string; aim: Aim; radius: number; halfAngleDeg?: number; effect?: string; requireReceive?: boolean } — ⚠ undocumented
- `AreaPredictInput` (interface): interface AreaPredictInput extends AreaTargetInput { effect?: string; requireReceive?: boolean } — ⚠ undocumented
- `PredictedTarget` (interface): interface PredictedTarget { instanceId: string; scale: number } — ⚠ undocumented
- `PredictiveDeps` (interface): interface PredictiveDeps { spatial: CombatSpatialDeps; queryArc(options: QueryArcOptions): string[]; canReceive?(instanceId: string, effect: string): string | null } — ⚠ undocumented
- `TilePredictInput` (interface): interface TilePredictInput { at: EntityPosition; radius: number; originTile: Tile; tileSize: number } — ⚠ undocumented

## @jgengine/core/tactics/snapshot

- `Snapshot` (type): type Snapshot = Record<string, unknown> — ⚠ undocumented
- `SnapshotSlice` (interface): interface SnapshotSlice<T = unknown> { capture(): T; restore(state: T): void } — ⚠ undocumented
- `SnapshotStore` (interface): interface SnapshotStore { register<T>(id: string, slice: SnapshotSlice<T>): void; unregister(id: string): void; capture(): Snapshot; restore(snapshot: Snapshot): void; push(): Snapshot; pop(): boolean; peek(): Snapshot | null; depth(): number; clear(): void } — ⚠ undocumented

## @jgengine/core/tactics/surface

- `SurfaceCell` (interface): interface SurfaceCell { tile: Tile; kinds: SurfaceCellKind[] } — ⚠ undocumented
- `SurfaceCellKind` (interface): interface SurfaceCellKind { surface: string; remaining: number | null } — ⚠ undocumented
- `SurfaceEvent` (type): type SurfaceEvent = | { kind: "apply"; tile: Tile; surface: string } | { kind: "react"; tile: Tile; consumed: readonly [string, string]; produced: string | null } | { kind: "expire"; tile: Tile; surface: string } — ⚠ undocumented
- `SurfaceKindDef` (interface): interface SurfaceKindDef { id: string; duration?: number } — ⚠ undocumented
- `SurfaceLayer` (interface): interface SurfaceLayer { apply(tile: Tile, surface: string, patch?: SurfacePatch): SurfaceEvent[]; has(tile: Tile, surface: string): boolean; kindsAt(tile: Tile): string[]; remove(tile: Tile, surface: string): void; clearTile(tile: Tile): void; clear(): void; tic… — ⚠ undocumented
- `SurfaceLayerConfig` (interface): interface SurfaceLayerConfig { kinds: readonly SurfaceKindDef[]; reactions?: readonly SurfaceReaction[] } — ⚠ undocumented
- `SurfaceLayerSnapshot` (type): type SurfaceLayerSnapshot = Record<string, Record<string, number | null>> — ⚠ undocumented
- `SurfacePatch` (interface): interface SurfacePatch { duration?: number } — ⚠ undocumented
- `SurfaceReaction` (interface): interface SurfaceReaction { when: readonly [string, string]; result: string | null } — ⚠ undocumented

## @jgengine/core/tactics/tacticalGrid

- `PushCollision` (interface): interface PushCollision { mover: string; into: string | PushObstacle; at: Tile } — ⚠ undocumented
- `PushMove` (interface): interface PushMove { id: string; from: Tile; to: Tile } — ⚠ undocumented
- `PushObstacle` (type): type PushObstacle = "wall" | "edge" — ⚠ undocumented
- `PushOptions` (interface): interface PushOptions { distance?: number; chain?: boolean } — ⚠ undocumented
- `PushResult` (interface): interface PushResult { moves: PushMove[]; collisions: PushCollision[] } — ⚠ undocumented
- `ReachableOptions` (interface): interface ReachableOptions { passThrough?: readonly string[]; diagonal?: boolean } — ⚠ undocumented
- `ReachableTile` (interface): interface ReachableTile { tile: Tile; cost: number } — ⚠ undocumented
- `TacticalGrid` (interface): interface TacticalGrid { readonly width: number; readonly height: number; inBounds(tile: Tile): boolean; isBlocked(tile: Tile): boolean; setBlocked(tile: Tile, blocked: boolean): void; occupantAt(tile: Tile): string | null; tileOf(id: string): Tile | null; place(… — ⚠ undocumented
- `TacticalGridConfig` (interface): interface TacticalGridConfig { width: number; height: number; blocked?: readonly Tile[]; diagonal?: boolean; world?: TacticalGridWorldConfig } — ⚠ undocumented
- `TacticalGridSnapshot` (interface): interface TacticalGridSnapshot { blocked: string[]; occupants: Record<string, string> } — ⚠ undocumented
- `TacticalGridWorldConfig` (interface): interface TacticalGridWorldConfig — Maps abstract `[col, row]` tiles onto world-space `[x, z]`, mirroring `navGrid`'s bounds+cellSize convention.
- `Tile` (type): type Tile = readonly [number, number] — ⚠ undocumented

## @jgengine/core/turn/commit

- `CommitController` (interface): interface CommitController<TAction> { readonly mode: CommitMode; submit(participant: string, action: TAction): CommitOutcome<TAction>; expected(participants: readonly string[]): void; hasSubmitted(participant: string): boolean; allReady(): boolean; pending(): SubmittedAction<… — ⚠ undocumented
- `CommitControllerConfig` (interface): interface CommitControllerConfig { mode: CommitMode; participants?: readonly string[] } — ⚠ undocumented
- `CommitMode` (type): type CommitMode = "immediate" | "simultaneous" | "resealable" — ⚠ undocumented
- `CommitOutcome` (interface): interface CommitOutcome<TAction> { status: "committed" | "sealed" | "pending" | "rejected"; committed: SubmittedAction<TAction>[]; reason?: string } — ⚠ undocumented
- `SubmittedAction` (interface): interface SubmittedAction<TAction> { participant: string; action: TAction } — ⚠ undocumented
- `createCommitController` (function): function createCommitController<TAction>(config: CommitControllerConfig): CommitController<TAction> — ⚠ undocumented

## @jgengine/core/turn/intent

- `DeclaredIntent` (interface): interface DeclaredIntent<TKind extends string = string> { kind: TKind; magnitude?: number; targetId?: string; note?: string } — ⚠ undocumented
- `IntentBoard` (interface): interface IntentBoard<TKind extends string = string> { declare(participantId: string, intent: DeclaredIntent<TKind>): void; peek(participantId: string): DeclaredIntent<TKind> | null; all(): readonly [string, DeclaredIntent<TKind>][]; consume(participantId: string): DeclaredIntent<TKind> | nul… — ⚠ undocumented
- `createIntentBoard` (function): function createIntentBoard<TKind extends string = string>(): IntentBoard<TKind> — ⚠ undocumented

## @jgengine/core/turn/turnLoop

- `CommitController` (interface): interface CommitController<TAction> { readonly mode: CommitMode; submit(participant: string, action: TAction): CommitOutcome<TAction>; expected(participants: readonly string[]): void; hasSubmitted(participant: string): boolean; allReady(): boolean; pending(): SubmittedAction<… — ⚠ undocumented
- `CommitMode` (type): type CommitMode = "immediate" | "simultaneous" | "resealable" — ⚠ undocumented
- `PoolConfig` (interface): interface PoolConfig { id: string; max: number; start?: number } — ⚠ undocumented
- `PoolState` (interface): interface PoolState { id: string; current: number; max: number } — ⚠ undocumented
- `TurnLoop` (interface): interface TurnLoop<TAction = unknown> { readonly commit: CommitController<TAction>; state(): TurnState; order(): readonly string[]; active(): string | null; phase(): string | null; round(): number; setOrder(order: readonly string[], keepActive?: boolean): TurnState; addParticip… — ⚠ undocumented
- `TurnLoopConfig` (interface): interface TurnLoopConfig { order: readonly string[]; phases?: readonly string[]; pools?: readonly PoolConfig[]; commit?: {mode: CommitMode}; onTurnStart?(participantId: string): void; onTurnEnd?(participantId: string): void } — ⚠ undocumented
- `TurnLoopSnapshot` (interface): interface TurnLoopSnapshot { round: number; order: string[]; activeIndex: number; phaseIndex: number; pools: Record<string, Record<string, number>> } — ⚠ undocumented
- `TurnState` (interface): interface TurnState { round: number; order: readonly string[]; activeIndex: number; active: string | null; phaseIndex: number; phase: string | null } — ⚠ undocumented
- `createTurnLoop` (function): function createTurnLoop<TAction = unknown>(config: TurnLoopConfig): TurnLoop<TAction> — ⚠ undocumented

## @jgengine/core/work/expedition

- `ExpeditionConfig` (interface): interface ExpeditionConfig<TCtx> — Runtime policy, supplied on each transition and never saved. Callbacks must be pure.
- `ExpeditionDispatch` (interface): interface ExpeditionDispatch — Dispatch data, detached from the caller's supply record. All timestamps are epoch milliseconds.
- `ExpeditionEvent` (interface): interface ExpeditionEvent — Timestamped serializable event. `at` is epoch milliseconds, compatible with `appendFeed`.
- `ExpeditionHazard` (interface): interface ExpeditionHazard — One encounter's mechanical effects and optional caller-authored notices.
- `ExpeditionState` (interface): interface ExpeditionState — Plain saveable expedition data. Persist this whole value, including the RNG cursor and tick frontier.
- `ExpeditionSupplyRule` (interface): interface ExpeditionSupplyRule — Ordered auto-consumption rule: spends one finite supply only when its declared effect changes a vital.
- `dispatchExpedition` (function): function dispatchExpedition(input: ExpeditionDispatch): ExpeditionState — Dispatch plain expedition state with a persisted seeded cursor; no clock, scheduler or storage is owned.
- `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.
- `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.
- `settleExpedition` (function): function settleExpedition<TCtx>(config: ExpeditionConfig<TCtx>, state: ExpeditionState, nowMs: number): ExpeditionState — Replay due event ticks using the existing stepped catch-up primitive. Order is loot → hazard → ordered supplies → death → capacity recall. Unprocessed ticks retain their frontier; returning never rolls or takes damage. Auto-recall uses the triggering tick's time, including offline arrival in the same call.

## @jgengine/core/work/jobQueue

- `CancelResult` (type): type CancelResult<TSpec, TReserve = undefined> = | { readonly ok: true; readonly state: WorkQueueState<TSpec, TReserve>; readonly job: Job<TSpec, TReserve>; readonly refund: TReserve | null; } | { readonly ok: false; readonly state: WorkQueueState<TSpec, TReserve>; readonly reason: string } — Outcome of {@link cancelJob}, carrying the removed job and its computed refund.
- `EnqueueOptions` (interface): interface EnqueueOptions — Optional per-enqueue overrides.
- `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.
- `Job` (interface): interface Job<TSpec, TReserve = undefined> — One unit of timed work. Plain serializable data (given serializable `TSpec`/`TReserve`).
- `JobId` (type): type JobId = string — Generic timed work queue — a pure-data model for discrete jobs that reserve inputs, advance over game time, can be paused/cancelled, and emit an output on completion. It backs unit training, crafting jobs, construction, research, respawns, downloads, and fabrication without any of them re-implementing the reservation → progress → completion → output-routing loop.
- `JobOrdering` (type): type JobOrdering<TSpec, TReserve = undefined> = ( a: Job<TSpec, TReserve>, b: Job<TSpec, TReserve>, ) => number — Comparator over jobs; negative means the first job runs sooner.
- `JobStatus` (type): type JobStatus = "queued" | "active" | "paused" — Lifecycle phase of a single queued job. Terminal jobs are removed from state.
- `JobValidation` (interface): interface JobValidation — Result of pre-enqueue validation (population caps, prerequisites, affordability).
- `TickResult` (interface): interface TickResult<TSpec, TReserve = undefined, TOutput = undefined> — Outcome of {@link tick}: advanced state plus the events produced.
- `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.
- `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}.
- `WorkQueueState` (interface): interface WorkQueueState<TSpec, TReserve = undefined> — Serializable queue state. Holds only non-terminal jobs, so it stays bounded.
- `activeJobs` (function): function activeJobs<TSpec, TReserve>(state: WorkQueueState<TSpec, TReserve>): Job<TSpec, TReserve>[] — Jobs currently progressing.
- `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.
- `createWorkQueue` (function): function createWorkQueue<TSpec, TReserve = undefined>(): WorkQueueState<TSpec, TReserve> — Create an empty timed work queue.
- `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`.
- `fifoOrdering` (function): function fifoOrdering<TSpec, TReserve = undefined>(a: Job<TSpec, TReserve>, b: Job<TSpec, TReserve>): number — Pure FIFO ordering by enqueue sequence.
- `jobById` (function): function jobById<TSpec, TReserve>(state: WorkQueueState<TSpec, TReserve>, id: JobId): Job<TSpec, TReserve> | null — Look up a job by id, or `null` if absent/terminal.
- `jobProgress` (function): function jobProgress<TSpec, TReserve>(job: Job<TSpec, TReserve>): number — Fractional progress of a job (0…1); a zero-duration job reads as complete.
- `pauseJob` (function): function pauseJob<TSpec, TReserve>(state: WorkQueueState<TSpec, TReserve>, id: JobId): WorkQueueState<TSpec, TReserve> — Pause a queued or active job in place; a paused job keeps its progress and yields its slot.
- `priorityOrdering` (function): function priorityOrdering<TSpec, TReserve = undefined>(a: Job<TSpec, TReserve>, b: Job<TSpec, TReserve>): number — Priority-first ordering (higher priority sooner), FIFO within equal priority.
- `queueSize` (function): function queueSize<TSpec, TReserve>(state: WorkQueueState<TSpec, TReserve>): number — Non-terminal job count (queued + active + paused).
- `queuedJobs` (function): function queuedJobs<TSpec, TReserve>(state: WorkQueueState<TSpec, TReserve>, ordering: JobOrdering<TSpec, TReserve> = priorityOrdering): Job<TSpec, TReserve>[] — Jobs waiting for a slot, in selection order.
- `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.
- `tick` (function): function tick<TSpec, TReserve, TOutput>(state: WorkQueueState<TSpec, TReserve>, config: WorkQueueConfig<TSpec, TReserve, TOutput>, dt: number): TickResult<TSpec, TReserve, TOutput> — Advance the queue by `dt` seconds. Promotes queued jobs into up to `concurrency` active slots, advances active jobs, and completes those that reach their duration — emitting `started`/`completed` events in deterministic order. A large `dt` catches up across many jobs in one call: when a job completes with leftover time, the freed slot promotes the next queued job and applies the remainder, so a reconnect or save/load gap resolves in a single bounded pass. Completed jobs are removed from the returned state.

## @jgengine/core/work/staffedStation

- `StaffedStation` (interface): interface StaffedStation — Serializable staffing snapshot. The caller owns assignment, unique worker ids, and stable order.
- `StationRateTuning` (interface): interface StationRateTuning — Caller-owned output tuning in production cycles per game-second.
- `StationWorker` (interface): interface StationWorker — One assigned worker's caller-resolved contribution; stat names and modifiers stay caller-owned.
- `stationOutputRate` (function): function stationOutputRate(station: StaffedStation, tuning: StationRateTuning): number — Resolve `(base + perStat * sum(admitted worker stats)) * efficiency` without allocation. Empty staffing retains base production. Negative/nonfinite contributions are zero; a nonfinite efficiency or overflowing result stops production with rate zero. Invalid workers still occupy their ordered slots. Assign the result to a `ProductionBuildingDef.rate` for `tickProduction`.

## @jgengine/core/work/unitTraining

- `ResourceCost` (type): type ResourceCost = Readonly<Record<string, number>> — Resource costs keyed by currency/resource id.
- `TrainableUnitDef` (interface): interface TrainableUnitDef — A unit the producer can train.
- `UnitReservation` (interface): interface UnitReservation — Reservation stored on a training job — the inputs to charge and refund.
- `UnitSpawnOrder` (interface): interface UnitSpawnOrder — Completion payload: everything a spawn/rally adapter needs, and nothing it doesn't.
- `UnitTrainingOptions` (interface): interface UnitTrainingOptions — Config knobs for {@link unitTrainingConfig}.
- `UnitTrainingSpec` (interface): interface UnitTrainingSpec — What the caller asks the queue to build.
- `unitTrainingConfig` (function): function unitTrainingConfig(options: UnitTrainingOptions): WorkQueueConfig<UnitTrainingSpec, UnitReservation, UnitSpawnOrder> — Build a {@link WorkQueueConfig} for training units from a catalog. Reservation is the unit's cost + population; duration is its train time; completion output is a {@link UnitSpawnOrder} for the caller to route to its spawn primitive.
