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

# jgengine-combat — exported API surface

## @jgengine/core/combat

- `AbilityKit` (interface): interface AbilityKit { slots(): readonly string[]; config(slotId: string): AbilitySlotConfig | null; state(): AbilityKitState; state(slotId: string, resourceAvailable?: number): AbilitySlotSnapshot | null; snapshot(resourceAvailable?: number): AbilitySlotSnapsh… — ⚠ undocumented · used by `createAbilityKit`: A bar of cooldown-gated abilities the player fires by slot, tracking readiness and cooldown per ability.
- `AbilitySlotSnapshot` (interface): interface AbilitySlotSnapshot { id: string; state: AbilitySlotState; castType: AbilityCastType; resourceCost: number; charges: number; chargesMax: number; cooldownRemainingMs: number; cooldownFraction: number; groupRemainingMs: number; justCast: boolean; ready: boolean … — ⚠ undocumented · used by `actionFromAbilitySlot` (@jgengine/react): Composable React renderers over the headless action view model (`@jgengine/core/ui/actionModel`) — the data/renderer/chrome split for an RTS…
- `AbilitySlotState` (type): type AbilitySlotState = "ready" | "cooldown" | "no-resource" | "just-cast" — ⚠ undocumented
- `AllocationOutcome` (interface): interface AllocationOutcome — The serializable result of an allocation pass — immediate `grants` plus any deferred `pools`.
- `AllocationRequest` (interface): interface AllocationRequest — The inputs one allocation pass consumes. `allocationSeed` governs distribution decisions (ordering, round-robin rotation, remainder splits, reservation) while the separate optional `generationSeed` seeds per-recipient `instanced` generation — keeping join order from perturbing other players' rolls. Provide `results` for pre-rolled policies, `generate` for `instanced`, `assignment` for `assigned`, and `claim` for `claimed`.
- `AnimationClip` (interface): interface AnimationClip { id: string; frames: number; fps: number; ranges: readonly FrameRange[]; loop?: boolean } — ⚠ undocumented · used by `createGraphPose` (@jgengine/shell/render/useModelAnimation): Binds a graph's clips to a rig exactly as `useModelAnimation` does (masked layers get filtered clips, additive layers additive ones) so a ho…
- `AntiOneShotConfig` (interface): interface AntiOneShotConfig — Caller data for the anti-one-shot composition: "cannot cross lethal while above X, leave Y, then recover for Z".
- `AntiOneShotPolicy` (interface): interface AntiOneShotPolicy — The anti-one-shot policy: an interceptor plus its serializable recovery-immunity state.
- `ArmorConfig` (interface): interface ArmorConfig — The armor curve: `mitigation = armor / (armor + halfValue)`. Naming the half value instead of a percentage per point is what makes a generated gun's armor number readable — armor equal to `halfValue` halves the hit, and mitigation approaches the cap without ever reaching it.
- `BUILTIN_COMPLETION_PREDICATES` (const): const BUILTIN_COMPLETION_PREDICATES: Readonly<Record<string, CompletionPredicate>> — Built-in completion predicates covering the common encounter gates: `immediate` (leaf marker), `manual`/`flag` (external event via a caller flag), `timer` (phase seconds), `cleared` (tagged entity count drained), `metric` (threshold on a live value), `event` (cumulative event count), and `quorum` (at least N of nested predicates met). Merge your own over these through {@link EncounterConfig.predicates}.
- `BUILTIN_SPAWN_PROVIDERS` (const): const BUILTIN_SPAWN_PROVIDERS: Readonly<Record<string, SpawnProvider>> — Built-in spawn providers. `points` reads a named authored scene point list from context and cycles it to emit `count` requests, keeping coordinates in the scene rather than the sequence. `list` echoes literal requests authored in `params.requests`. Merge your own catalog- or director-backed providers through {@link EncounterConfig.spawnProviders}.
- `BuildupProc` (interface): interface BuildupProc { status: string; durationMs: number } — ⚠ undocumented
- `CheckAdvantage` (type): type CheckAdvantage = "advantage" | "disadvantage" | "normal" — ⚠ undocumented
- `CheckResult` (interface): interface CheckResult { rolls: readonly number[]; roll: number; total: number; success: boolean; critical: "success" | "failure" | null } — ⚠ undocumented · used by `rollCheck`: Resolve a tabletop-style pass/fail roll against a target number with modifiers and crit/fumble bands.
- `ClaimOutcome` (interface): interface ClaimOutcome — The outcome of a claim attempt — the updated pool and the grants owed (empty when the claim is refused).
- `ClaimablePool` (interface): interface ClaimablePool — A serializable pool of results left open for later claiming — first-come contested drops or a `reservedFor` personal reward. Tracks `eligible` claimants, optional `expiresAtMs`, and the authoritative `claimedBy` winner so reconnect and duplicate-claim attempts resolve idempotently.
- `ComboMeter` (interface): interface ComboMeter — A live, observable combo/multiplier meter — an integer hit chain with a decay window, free-string tier thresholds, a derived multiplier, and peak tracking.
- `ComboMeterConfig` (interface): interface ComboMeterConfig — Options for {@link createComboMeter}.
- `ComboMeterSnapshot` (interface): interface ComboMeterSnapshot — Serializable state for save/restore — clock-agnostic (stores time left, not an absolute deadline).
- `ComboMeterView` (interface): interface ComboMeterView — A pooled, read-only snapshot of the live meter for a renderer to draw each frame. Reused across {@link ComboMeter.view} calls and overwritten on the next one — read it, do not retain it. For a save, use {@link ComboMeter.snapshot}.
- `ComboStep` (interface): interface ComboStep { id: string; clip: string; cancelInto?: readonly string[]; cancelPhases?: readonly FramePhase[]; stance?: string } — ⚠ undocumented
- `ComboTier` (interface): interface ComboTier — One tier threshold in a {@link ComboMeter}. Tiers gate on the integer combo `count` (not a filled fraction), and `id` is a free string the game owns and styles ("good", "great", "savage", …) — the model never interprets it.
- `CompletionPredicate` (type): type CompletionPredicate = ( params: Readonly<Record<string, unknown>>, ctx: PredicateContext, ) => boolean — A completion predicate: pure and deterministic, returns true when the node it gates is finished. Registered under a `kind` and reused across phases with different `params`.
- `CoverChoice` (interface): interface CoverChoice — A scored cover point, with every term visible so a probe or test can see why it won.
- `CoverField` (interface): interface CoverField extends CoverSource — Cover derived from authored geometry, rebuilt when the world is edited.
- `CoverFieldOptions` (interface): interface CoverFieldOptions extends CoverPointOptions — Options for {@link createCoverField}: the authored boxes, the dials, and a probe name.
- `CoverFieldSnapshot` (interface): interface CoverFieldSnapshot — Serializable cover field state: the boxes and the dials, not the derived points.
- `CoverPoint` (interface): interface CoverPoint — One stand position beside authored geometry, with the face direction it hides against.
- `CoverPointOptions` (interface): interface CoverPointOptions — How cover points sit relative to the geometry that generates them.
- `CoverQuery` (interface): interface CoverQuery — Everything one cover decision reads: where the member is, what it believes, and its role's policy.
- `CoverSolid` (interface): interface CoverSolid — A box of authored world geometry a body can hide behind. Structurally a `WorldSolid`, so `ctx.world.solids.all()` drops in directly; a game with its own collision can pass any boxes.
- `CoverSource` (interface): interface CoverSource — Bounded source of cover near a position: generated from authored geometry, or the game's own spatial query. Called for one member at a time, never for the whole squad.
- `CoverThreat` (interface): interface CoverThreat — A remembered threat: where the member last saw it and how strongly it still believes it.
- `CoverWeights` (interface): interface CoverWeights — What each term is worth when choosing cover. A role owns these numbers.
- `CrossingDirection` (type): type CrossingDirection = "falling" | "rising" — The direction a crossing moved: `falling` = value decreased past the mark, `rising` = increased past it.
- `CrossingPolicy` (type): type CrossingPolicy = "once" | "repeat" — Whether a threshold may fire repeatedly (`repeat`) or at most once per direction (`once`).
- `CrossingTrigger` (type): type CrossingTrigger = "falling" | "rising" | "both" — Which directions should emit crossings.
- `DEFAULT_ARMOR_HALF_VALUE` (const): const DEFAULT_ARMOR_HALF_VALUE: 100 — Default armor points at which a hit is halved.
- `DEFAULT_CRIT_MULTIPLIER` (const): const DEFAULT_CRIT_MULTIPLIER: 2 — Default crit multiplier for a zone that does not name one.
- `DEFAULT_EYE_HEIGHT` (const): const DEFAULT_EYE_HEIGHT: number — Shot-origin and first-person camera eye height above an entity's position: 90% of the default 1.8m hitbox top.
- `DEFAULT_FIRE_PULSE_SECONDS` (const): const DEFAULT_FIRE_PULSE_SECONDS: 0.12 — Default `RenderCueTuning.firePulseSeconds`.
- `DEFAULT_HIT_PULSE_SECONDS` (const): const DEFAULT_HIT_PULSE_SECONDS: 0.2 — Default `RenderCueTuning.hitPulseSeconds`.
- `DEFAULT_MAX_MITIGATION` (const): const DEFAULT_MAX_MITIGATION: 0.9 — Default ceiling on armor mitigation, so armor never fully negates a hit.
- `DEFAULT_RENDER_CUES` (const): const DEFAULT_RENDER_CUES: Readonly<EntityRenderCues> — Neutral starting cue set: idle, unarmed, undamaged.
- `DEFAULT_VFX_PRESET` (const): const DEFAULT_VFX_PRESET: VfxPresetName — The fallback flavor used when a `vfx()` call names an unknown preset — so a typo still shows a spark instead of nothing.
- `DEFAULT_WEAPON_PELLETS_IN_FLIGHT` (const): const DEFAULT_WEAPON_PELLETS_IN_FLIGHT: 32 — Default live-pellet cap for a weapon that does not name one.
- `DamageChannelId` (type): type DamageChannelId = string — Caller-owned id for a damage channel — `"fire"`, `"ballistic"`, `"physical"`, `"corrosive"`. The engine never branches on the value; a channel is whatever a game's data declares.
- `DamageClampConfig` (interface): interface DamageClampConfig — Caller data for a flat per-hit damage cap.
- `DamageContext` (interface): interface DamageContext — The facts a received-damage modifier predicates over: the incoming `channel`, who dealt it, the statuses the target currently carries, and any caller tags. All caller-owned strings; the engine never assigns meaning to a channel, source, status, or tag.
- `DamageHitInput` (interface): interface DamageHitInput — One data-defined damage hit: a channel, a base impact, the target's traits and carried statuses, and the caller-owned matchup/received/status data that shapes the outcome. Everything is serializable; the only non-data input is the injected `rng`, so authority can resolve a hit and replicate the returned instances.
- `DamageHitResolution` (interface): interface DamageHitResolution — The full, provenance-rich result of resolving a hit — every stage kept for UI and debugging. `impact` is the final number to drain; `matchup`, `received`, and `status` expose exactly how it got there. Authority applies `impact` (plus `received.redirects`/`conversions`) and the returned status `instance`; nothing here mutates game state.
- `DamageInterceptor` (interface): interface DamageInterceptor — A named stage in the interception pipeline. The `id` is stable so it can be installed, removed, and cited in provenance.
- `DamageMatchup` (interface): interface DamageMatchup<TChannel extends string = DamageChannelId, TTrait extends string = TargetTraitId> — A serializable, data-defined matchup table: `channel → trait → outputs`. When a hit's channel meets a target carrying several traits, every matching entry's outputs multiply together, so axes compose independently (a trait can halve impact yet double status duration). `default` applies for a channel/trait pair the table does not mention.
- `DamagePipeline` (interface): interface DamagePipeline — A mutable ordered interceptor chain that transitions can install into and remove from at runtime.
- `DamagePredicate` (interface): interface DamagePredicate — A typed predicate over a {@link DamageContext}. Every listed facet must match (AND); a facet matches when the context value is in the list (channels/sources) or shares any member (targetStatuses/tags). An empty predicate matches every hit.
- `DamageResolution` (interface): interface DamageResolution — The outcome of running a pending application through the pipeline: what to apply, what was deferred, and why each value changed.
- `DamageRuntimeConfig` (interface): interface DamageRuntimeConfig — Everything the model reads: the table, the zones, the status definitions, and the RNG.
- `DamageRuntimeHitInput` (interface): interface DamageRuntimeHitInput — One incoming hit: what struck, how hard, where it landed, and what statuses it carries.
- `DamageRuntimeResolution` (interface): interface DamageRuntimeResolution — Every stage of one resolved hit, so a UI or a test can read why the final number is what it is.
- `DamageRuntimeRetune` (interface): interface DamageRuntimeRetune — In-play dials, all retunable without discarding registered targets or carried statuses.
- `DamageRuntimeState` (interface): interface DamageRuntimeState — Serialized model state: registered targets, carried statuses, and the probe counters.
- `DamageStatusRequest` (interface): interface DamageStatusRequest — One status a hit tries to apply, scaled against that status's own base chance and values.
- `DamageTableDef` (interface): interface DamageTableDef — A serializable damage table: damage types scored against resistance classes, plus the armor curve those rows are read with. It is data a generated gun (B3.1) and a weapon runtime (B2.3) pass in; the engine holds no built-in elemental chart.
- `DamageTableRow` (interface): interface DamageTableRow — One readable row: a type against a resistance class at a given armor value.
- `DamageTypeDef` (interface): interface DamageTypeDef — One damage type's row in a damage table: a caller-owned id (`"kinetic"`, `"fire"`) and how it fares against each resistance class a target can present (`"flesh"`, `"shield"`, `"armor"`). Values below `1` are resisted, `1` is neutral, above `1` is a weakness, and `0` is immune.
- `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.
- `DefenseResolution` (interface): interface DefenseResolution — Result of resolving an incoming hit against a defensive window: `outcome` is the graded defense (`"parry"`/`"block"`/`"iframe"`/`"hit"`) and `perfect` is true when the input landed inside the tight just-frame at the window's start rather than its wider active span.
- `DuplicateDamageTypeError` (class): class DuplicateDamageTypeError extends Error — Raised when a table lists the same damage type twice, which would make the winner depend on order.
- `EncounterConfig` (interface): interface EncounterConfig<TData = unknown> — Non-serializable configuration for an encounter: the authored phase tree plus predicate and spawn-provider registries. Re-supplied alongside a loaded {@link EncounterState}, the way `advanceSpawnDirector` pairs config with state, so the state itself stays pure data.
- `EncounterContext` (interface): interface EncounterContext — Context passed to {@link startEncounter} / {@link updateEncounter}: the caller signals predicates evaluate against, plus named `spawnPoints` catalogs (authored in the scene, referenced by key) that spawn providers place against. Never holds coordinates the sequence itself owns.
- `EncounterEvent` (type): type EncounterEvent = | { type: "enter"; phaseId: string; iteration: number } | { type: "spawn"; phaseId: string; provider: string; requests: readonly EncounterSpawnRequest[] } | { type: "complete"; phaseId: string; iteration: number; reason: string } | { type: "done" } — A lifecycle event emitted while stepping an encounter, carrying provenance.
- `EncounterPhase` (interface): interface EncounterPhase<TData = unknown> — One node in an encounter sequence tree. `data` is caller-owned and opaque to the core. A node with `children` is a group whose children run in order; a node without is a leaf. `completion` gates when the node finishes, `spawn` names an on-enter provider, and `repeat` re-runs the node's subtree that many extra times before advancing.
- `EncounterSignals` (interface): interface EncounterSignals — Caller-supplied signals a completion predicate reads. Every field is optional and opaque to the core: `counts` of tagged live entities, continuous `metrics`, cumulative `events`, and boolean `flags`. Deterministic given the same values.
- `EncounterSpawnRequest` (interface): interface EncounterSpawnRequest — A single spawn request a provider emits; `ref` is caller-defined, `point` optional.
- `EncounterState` (interface): interface EncounterState<TData = unknown> — Full serializable encounter state: the working phase tree (including any injected phases), a per-node runtime map, the active path from root to the deepest open node, accumulated time, and whether the sequence has finished. Round-trips through JSON with no behavioral change; the registries live in {@link EncounterConfig}, not here.
- `EncounterStep` (interface): interface EncounterStep<TData = unknown> — Result of a step: the (mutated, returned) state and the events emitted this step.
- `EntityRenderCues` (interface): interface EntityRenderCues — Per-entity render cues: the motion/animation signal a custom `renderEntity` or first-person viewmodel component needs to drive gait, muzzle flash, reload poses, and hit reactions — without diffing the parent group's position itself or reading a game-side module map for attack timing.
- `EventMeter` (interface): interface EventMeter { state(): EventMeterState; restore(next: EventMeterState): void; value(): number; fraction(): number; tier(): string | null; ready(): boolean; feed(tag: string, scale?: number): EventMeterFeedResult; consume(): boolean; drain(amount: numbe… — ⚠ undocumented · used by `createEventMeter`: A heat/hype gauge that rises as tagged events land and cools between them, firing when it fills or breaks — the streak/overdrive meter shoot…
- `EventMeterFeedResult` (interface): interface EventMeterFeedResult { tag: string; reset: boolean; amount: number; value: number; fraction: number; fired: boolean; ready: boolean; overflow: number; tier: string | null; tierChanged: boolean } — ⚠ undocumented
- `FireCadence` (interface): interface FireCadence — A minimal minimum-interval rate gate for a repeated action — weapon fire, ability spam, any "no faster than N per second" rule. Deterministic and serializable: its whole state is the elapsed time since the last action, exposed via {@link FireCadence.elapsedMs}.
- `FireCadenceConfig` (interface): interface FireCadenceConfig — Tuning for {@link createFireCadence}: the minimum interval between actions and whether it starts ready.
- `FireDiscipline` (interface): interface FireDiscipline — Fire discipline: how long a member stays down between shots, how long it leans out, and how fast it fires while it has a target. A role that peeks for longer holds an angle better and spends more time in the open — the trade is the caller's to tune.
- `FrameRange` (interface): interface FrameRange { phase: FramePhase; from: number; to: number } — ⚠ undocumented
- `HitReactionConfig` (interface): interface HitReactionConfig { hitstopMs: number; knockback: number; vertical?: number; shake?: CameraShake; trauma?: number; timescale?: number } — ⚠ undocumented · used by `resolveHitReaction`: Resolves hit feel (hitstop, knockback impulse, camera shake) from either a named `impactPresets` event (`resolveHitReaction("explosion", inp…
- `HitZoneDef` (interface): interface HitZoneDef — One hit zone: what a hit there multiplies, and how much likelier it is to crit.
- `HitZoneResolution` (interface): interface HitZoneResolution — One resolved zone: where the hit landed, whether it crit, and the single multiplier to apply.
- `HitZoneTable` (interface): interface HitZoneTable — A serializable hit-zone table: where a hit landed, what that multiplies, and the table's base crit chance and multiplier. A generated gun or a weapon runtime passes its own zones in; the engine has no built-in headshot.
- `ImmunityWindow` (interface): interface ImmunityWindow — A per-target timed immunity policy: an interceptor plus grant/query/serialize controls, toggled by transitions.
- `InterceptContext` (interface): interface InterceptContext — Read-only context an interceptor may consult — deterministic clock and optional health lookup for HP-relative policies.
- `InterceptDecision` (type): type InterceptDecision = | { kind: "pass" } | { kind: "transform"; amount: number; note?: string } | { kind: "clamp"; max: number; note?: string } | { kind: "redirect"; target: string; note?: string } | { kind: "split"; parts: readonly PendingDamage[]; note?: string } | { kind: "defer"; note?: strin… — What an interceptor decides to do with the pending application it was handed. `split` parts continue at the NEXT interceptor (never re-entering the splitter), which is what keeps the pipeline bounded and recursion-free.
- `InterceptRecord` (interface): interface InterceptRecord — One row of provenance: which interceptor acted, what it decided, and the amount before/after it acted.
- `MAX_INTERCEPT_STEPS` (const): const MAX_INTERCEPT_STEPS: 256 — Upper bound on interceptor evaluations for a single resolution; guards against runaway `split`/`redirect` loops.
- `MAX_WEAPON_BURST_COUNT` (const): const MAX_WEAPON_BURST_COUNT: 64 — Cap on `WeaponBurstDef.count`.
- `MAX_WEAPON_PELLETS_IN_FLIGHT` (const): const MAX_WEAPON_PELLETS_IN_FLIGHT: 256 — Cap on `WeaponDefinition.maxInFlight`; bounds per-tick projectile work.
- `MAX_WEAPON_PELLETS_PER_SHOT` (const): const MAX_WEAPON_PELLETS_PER_SHOT: 64 — Cap on `WeaponDefinition.pellets`; bounds rays and damage resolutions per shot.
- `Magazine` (interface): interface Magazine — A per-weapon magazine: discrete loaded rounds, a timed reload that refills from a reserve pool, and the reserve-pool interaction itself — the primitive that replaces hand-rolling mag size, reload delay, and reserve bookkeeping per game (#536.2).
- `MagazineConfig` (interface): interface MagazineConfig — Tuning for `createMagazine`: mag capacity, reload delay, and where reserve ammo is drawn from.
- `MagazineReserve` (interface): interface MagazineReserve — Draws ammo for a `Magazine`'s reload from wherever the reserve pool actually lives.
- `MagazineSnapshot` (interface): interface MagazineSnapshot — Complete serializable state for a {@link Magazine}; `reserve: null` means infinite reserve.
- `MatchupOutputs` (interface): interface MatchupOutputs — The independent, typed outputs a channel-vs-trait matchup can scale. Every field is an optional multiplier that defaults to `1` (identity), so a matchup entry names only the axes it bends. `impact` scales the direct hit, `applyChance` the odds a status lands, `magnitude` and `duration` the applied status itself, and `extra` carries any further caller-defined scalar (knockback, stagger, heat) the engine forwards without interpreting.
- `MeterAddResult` (interface): interface MeterAddResult { value: number; fired: boolean; overflow: number; tier: string | null; tierChanged: boolean } — ⚠ undocumented
- `ObjectRaycastHit` (interface): interface ObjectRaycastHit — ⚠ undocumented
- `OnDeathSpec` (interface): interface OnDeathSpec — Catalog `onDeath` for an entity: loot tables to roll, `dropMode: "world"` to scatter drops on the ground (rendered with loot beams) instead of granting them into the killer's bag, and commands to run. Fires only when the entity dies through `ctx.scene.entity.effect`, not a raw `stats.delta`.
- `PendingDamage` (interface): interface PendingDamage — Ordered, inspectable damage-resolution interception (#931).
- `PhaseCompletionRef` (interface): interface PhaseCompletionRef — Reference to a registered completion predicate: a `kind` naming the evaluator plus opaque `params` the evaluator reads. The sequence core never interprets `params`; the predicate registered under `kind` does.
- `PhaseInjectAt` (type): type PhaseInjectAt = | { before: string } | { after: string } | { childOf: string; index?: number } — Where to insert an injected phase, relative to an existing node by id.
- `PhaseRuntime` (interface): interface PhaseRuntime — Per-node runtime record. Serializable — holds no functions or tree references.
- `PhaseSpawnRef` (interface): interface PhaseSpawnRef — Reference to a registered spawn provider invoked when a phase is entered: a `kind` naming the provider plus opaque `params`. Spawning is one optional node adapter — a phase without `spawn` simply emits no spawn requests.
- `PhaseStatus` (type): type PhaseStatus = "pending" | "active" | "complete" — Lifecycle status of one phase in an encounter sequence: waiting to run, currently running, or finished. Groups and leaves share the same three states.
- `PredicateContext` (interface): interface PredicateContext — Evaluation context a completion predicate receives for the node under test.
- `ProjectileSystemDeps` (interface): interface ProjectileSystemDeps { effects: EffectSystem; spatial: CombatSpatialDeps; getStat(itemId: string, stat: string): number | null; raycast?: Raycast; sceneRaycast?: SceneRaycastApi; objects?: ProjectileObjectsDeps; entityCollidersOf?(instanceId: string): EntityCol… — ⚠ undocumented · used by `createProjectileSystem`: Spawn and advance projectiles each frame, resolving travel, lifetime, and hits.
- `RaycastHit` (type): type RaycastHit = EntityRaycastHit | ObjectRaycastHit — ⚠ undocumented
- `ReceiveMap` (type): type ReceiveMap = Record<string, ReceiveRule> — ⚠ undocumented
- `ReceivedDamageResult` (interface): interface ReceivedDamageResult — The full, provenance-rich outcome of running received modifiers over one hit.
- `ReceivedModifier` (interface): interface ReceivedModifier — One serializable receiver-side rule: an optional predicate, a policy, and an ordering key.
- `ReceivedPolicy` (type): type ReceivedPolicy = | { kind: "scale"; factor: number } | { kind: "flat"; delta: number } | { kind: "cap"; max: number } | { kind: "floor"; min: number } | { kind: "convert"; toChannel: DamageChannelId; portion?: number } | { kind: "redirect"; toTarget: string; portion?: number } | { kind: "immune… — What a matched modifier does to the incoming amount. Amplification is one policy beside reduction — both are `scale` (factor `> 1` amplifies, `< 1` reduces). `cap`/`floor` clamp, `flat` adds/subtracts, `convert` moves a portion to another channel on the same target, `redirect` moves a portion to another target, and `immune` zeroes the hit outright.
- `RenderCueTuning` (interface): interface RenderCueTuning — Tuning knobs for `advanceMotionCues` / `useEntityRenderCues`; every field has a default, override only what a weapon/rig's feel needs to differ.
- `ResolvedMatchup` (interface): interface ResolvedMatchup — Fully-resolved matchup outputs (every axis populated) plus the contributions that produced them.
- `ResolvedShot` (interface): interface ResolvedShot — A shot's resolved firing geometry in world space: `origin` is the point the projectile/ray starts from and `direction` is its normalized aim vector, both computed by {@link resolveShot} from the shooter's position, facing, and the chosen origin policy.
- `ResourcePool` (interface): interface ResourcePool { current(): number; max(): number; setMax(value: number): void; fraction(): number; canSpend(amount: number): boolean; spend(amount: number): boolean; gain(amount: number): number; set(value: number): void; tick(dtSeconds: number): void; i… — ⚠ undocumented · used by `createResourcePool`: A regenerating resource pool — mana, stamina, energy — that actions spend from and that refills over time.
- `RewardClaimSpec` (interface): interface RewardClaimSpec — How a `claimed` allocation exposes its pool: open first-come (`first`) or `reserved` to one recipient.
- `RewardGrant` (interface): interface RewardGrant — An authoritative, serializable award of one result stack to one recipient — carries `via` (the policy that produced it) and `private` (replication scope) so provenance and visibility survive save/load and viewer projection. Applying a grant twice with the same identity is the caller's idempotency contract; this seam only decides who is owed what.
- `RewardPolicyKind` (type): type RewardPolicyKind = "instanced" | "shared" | "copy" | "roundRobin" | "assigned" | "claimed" — The distribution policies allocation ships — each a distinct answer to "who gets this result".
- `RewardRecipient` (interface): interface RewardRecipient — A participant that may receive rewards — an opaque recipient id (player, team, party slot) with an optional split `weight` (shared policy), eligibility `tags`, and an `eligible` gate. Ineligible recipients are excluded before any allocation decision so they never perturb others' streams.
- `RewardResult` (interface): interface RewardResult — One indivisible reward to distribute among participants — an opaque result id (a rolled drop, a currency bundle, a quest token) with an optional stack `count` and free-form `tags` for eligibility and provenance. Allocation never interprets the id; generation (loot tables, roll formulas) owns what it means, keeping the seam genre-agnostic.
- `RewardShare` (interface): interface RewardShare — A `{ result, count }` slice of a reward — the unit shared pools and grants are expressed in.
- `ShotOriginPolicy` (type): type ShotOriginPolicy = | { kind: "converge"; muzzle?: EntityPosition; height?: number } | { kind: "eye"; height?: number } | { kind: "legacy" } | { kind: "entity" } | { kind: "entityOffset"; offset: EntityPosition } | { kind: "muzzle"; offset?: EntityPosition } | { kind: "camera"; origin: EntityPos… — How a shot's world-space origin (and optional direction) is resolved before prediction/settlement. - `converge` — the shot leaves the gun `muzzle` yet still passes through whatever the shooter's sightline (crosshair) covers: origin is the muzzle offset, direction is bent from the muzzle to the eye ray's aim point. The projectile system's default for a free `{ yaw, pitch }` aim, so a bullet visibly comes from the barrel without missing the reticle. Needs a scene raycast to find the aim point (`convergeShot`); a bare `resolveShot` degrades to a straight muzzle ray. Passes an explicit `{ origin, direction }` aim through untouched. - `eye` — `aim.origin` when present, else the shooter's entity position raised to eye height; the shot traces the shooter's sightline, so what the crosshair covers is what gets hit. - `legacy` — `aim.origin` when present, else the shooter's raw entity position (feet). - `entity` — always the shooter's entity position. - `entityOffset` / `muzzle` — entity-local offset rotated by the shooter's yaw (muzzle on a weapon model). - `camera` — explicit camera/reticle world origin (and optional direction override). - `world` — absolute world origin.
- `SpawnProvider` (type): type SpawnProvider = ( params: Readonly<Record<string, unknown>>, ctx: SpawnProviderContext, ) => readonly EncounterSpawnRequest[] — A spawn provider: given the phase's `params` and context, returns the spawn requests to emit on enter. Deterministic; reads authored scene points from `ctx.spawnPoints` rather than embedding coordinates.
- `SpawnProviderContext` (interface): interface SpawnProviderContext — Evaluation context a spawn provider receives when its phase is entered.
- `SquadCombat` (interface): interface SquadCombat — Drive a squad: cover by threat, flanking, fire discipline, suppression and retreat.
- `SquadCombatOptions` (interface): interface SquadCombatOptions extends SquadCombatTunables — Everything the squad AI reads from the game, plus its tunables.
- `SquadCombatSnapshot` (interface): interface SquadCombatSnapshot — Serializable squad state: member decisions, the crowd, and the tuning they ran under.
- `SquadCombatStats` (interface): interface SquadCombatStats — Counters a probe or a test reads.
- `SquadCombatTunables` (interface): interface SquadCombatTunables — In-play dials, every one retunable.
- `SquadComposition` (interface): interface SquadComposition — A squad's roles in assignment order.
- `SquadMemberSpec` (interface): interface SquadMemberSpec — One combatant the runtime drives: whose side it is on, where it stands, and how hurt it is.
- `SquadMemberView` (interface): interface SquadMemberView — One member as a HUD, a probe or a test reads it. Allocates.
- `SquadMode` (type): type SquadMode = "advance" | "cover" | "peek" | "retreat" | "down" — What a member is doing this tick: moving to cover, holding it, leaning out, falling back, or down.
- `SquadRole` (interface): interface SquadRole — One caller-defined squad role. The engine ships the machinery and no role list: a game names its own roles and dials them, so `"assault"`, `"breacher"` and `"sniper"` are content, not engine concepts.
- `StatPool` (interface): interface StatPool — Serializable state for any bounded named resource. The caller defines what the resource means.
- `StatPoolAccess` (interface): interface StatPoolAccess<TOwnerId extends string = string, TStatId extends string = string> — Structural bridge to caller-owned resource state. Implement it over an ECS, Redux/Zustand store, plain object, database-backed model, or JGengine's native entity stats without moving ownership into the SDK.
- `StatPoolAccessResult` (type): type StatPoolAccessResult = | ({ status: "ok" } & StatPoolChange) | { status: "rejected"; reason: string } — Outcome of changing a pool through {@link StatPoolAccess}.
- `StatPoolChange` (interface): interface StatPoolChange — Inspectable result of a bounded pool change.
- `StatPoolInput` (interface): interface StatPoolInput — Input used to create a normalized pool. `current` defaults to `max`; `min` defaults to zero.
- `StatPoolPatch` (interface): interface StatPoolPatch — Partial update applied without mutating the previous pool.
- `Stats` (interface): interface Stats<TStat extends string> { setBase(stat: TStat, value: number): void; getBase(stat: TStat): number; addSource(sourceId: string, modifiers: StatModifierSet<TStat>, options?: {expiresAtMs?: number}): void; removeSource(sourceId: string): void; hasSource(sourceId: str… — ⚠ undocumented · used by `createStats`: A stat block whose base values take stacking, timed buffs and debuffs, resolving the modified value on read.
- `StatsSnapshot` (interface): interface StatsSnapshot<TStat extends string> — Complete plain-data state for a {@link Stats} runtime.
- `StatusApplicationOutcome` (interface): interface StatusApplicationOutcome — The result of one status application: the outcome, the resulting instance (if any), and the roll.
- `StatusApplicationSpec` (interface): interface StatusApplicationSpec — A serializable, effect-agnostic description of a status a hit tries to apply: an opaque `status` id the game routes to its own effect/DoT pipeline, a base landing `chance`, and the duration/ticks/magnitude/attribution/stacking data the resolver needs. The engine never interprets `status` — it is a reference, not a built-in condition.
- `StatusApplyOptions` (interface): interface StatusApplyOptions — Options for one application; scales compose with the definition's own base values.
- `StatusDamageTick` (interface): interface StatusDamageTick — A damage tick, already routed through the caller's `applyDamage` when one was supplied.
- `StatusDef` (interface): interface StatusDef — One status the runtime can apply: how a fresh application folds into a live one ({@link StatusStackPolicy}), how long it lives, how often and how hard it ticks, and what a tick does. The stack rule is the *only* thing that changes stacks — per-tick magnitude is `magnitude × stacks`, never `magnitude ^ applications`.
- `StatusEffect` (type): type StatusEffect = | { kind: "damage"; channel: string } | { kind: "stat"; stat: string } — What a status does on each tick. Damage ticks are reported with the channel the caller's damage pipeline resolves, so a burn still meets resistances and armor; stat ticks are a per-stack delta summed by {@link StatusRuntime.statDelta} (`slow` → move speed, `corrode` → armor).
- `StatusEffectView` (interface): interface StatusEffectView — A serializable, presentation-ready snapshot of one active status for a timeline HUD row: a stable list `id`, the free-string `kind` the game styles (color / label / icon), the countdown-ring inputs `remainingMs` / `durationMs`, the `stacks` badge count, and the optional `magnitude` in force. Derived from a live {@link StatusInstance} via {@link toStatusEffectView}. The engine never interprets `kind` — it is a reference the game skins, not a built-in condition.
- `StatusEffectViewOptions` (interface): interface StatusEffectViewOptions — Options for {@link toStatusEffectView} / {@link toStatusEffectViews}.
- `StatusExpiredTick` (interface): interface StatusExpiredTick — A status ended: remove its HUD row and any stat delta it was contributing.
- `StatusImmunity` (interface): interface StatusImmunity — Statuses a target cannot receive at all — the immunity half of application policy.
- `StatusInstance` (interface): interface StatusInstance — A live status carried by a target — the serializable, replicable state a status application mutates.
- `StatusRuntime` (interface): interface StatusRuntime — A pool of per-target statuses that applies stack rules, ticks effects, and hands its state out.
- `StatusRuntimeEntry` (interface): interface StatusRuntimeEntry — One live status plus its tick timer, as saved and restored.
- `StatusRuntimeOptions` (interface): interface StatusRuntimeOptions — Tunables a game can adjust at runtime without discarding carried statuses.
- `StatusRuntimeState` (interface): interface StatusRuntimeState — Serializable runtime state: carried statuses, tick timers, and the counters a probe reports.
- `StatusStackPolicy` (type): type StatusStackPolicy = | { kind: "refresh" } | { kind: "stack"; max?: number; add?: number } | { kind: "replace" } | { kind: "ignore" } — How a fresh application behaves when the target already carries the status. - `refresh` — reset duration, hold the existing stack count. - `stack` — add `add` stacks (default 1) up to `max`, and refresh duration. - `replace` — overwrite duration and magnitude, stacks reset to 1. - `ignore` — leave the existing instance untouched (first application wins).
- `StatusStatTick` (interface): interface StatusStatTick — A stat tick: a per-stack delta the caller reads while the status lives.
- `StatusTickEvent` (type): type StatusTickEvent = StatusDamageTick | StatusStatTick | StatusExpiredTick — Everything one `tick` call produced, in target-then-status order.
- `TargetProfile` (interface): interface TargetProfile — What a target presents to the table: one resistance class and its armor points.
- `TargetTraitId` (type): type TargetTraitId = string — Caller-owned id for a target trait — `"armored"`, `"fleshy"`, `"wet"`, `"boss"`. Traits are the receiver-side facets a matchup scores a channel against.
- `TelegraphConfig` (interface): interface TelegraphConfig { shape: TelegraphShape; at: EntityPosition; dir?: number; windupMs?: number; turns?: number; kind?: string } — ⚠ undocumented
- `TelegraphShape` (type): type TelegraphShape = | { kind: "circle"; radius: number } | { kind: "ring"; radius: number; innerRadius: number } | { kind: "cone"; radius: number; angle: number } | { kind: "line"; length: number; width: number } — ⚠ undocumented
- `ThreatReadOptions` (interface): interface ThreatReadOptions — Bounds for {@link threatsFromMemory}.
- `ThreatReading` (interface): interface ThreatReading extends CoverThreat — One remembered enemy with its age, so a role can treat a stale sighting differently.
- `ThresholdCrossing` (interface): interface ThresholdCrossing — One emitted crossing: which threshold, which way, and the value span that produced it.
- `ThresholdCrossingConfig` (interface): interface ThresholdCrossingConfig — Caller configuration for a threshold tracker.
- `ThresholdMark` (interface): interface ThresholdMark — Generic numeric threshold-crossing tracker (#931).
- `ThresholdTracker` (interface): interface ThresholdTracker — A stateful crossing tracker over one numeric source.
- `ThresholdTrackerSnapshot` (interface): interface ThresholdTrackerSnapshot — Serializable tracker state for save/load.
- `TimeToKill` (interface): interface TimeToKill — A quoted time to kill for one fixed hit against one health pool.
- `UnknownDamageTypeError` (class): class UnknownDamageTypeError extends Error — Raised when a hit names a damage type the table does not define, rather than silently dealing 1×.
- `UnknownHitZoneError` (class): class UnknownHitZoneError extends Error — Raised when neither the named zone nor the table's `defaultZone` exists — a data error, not a 1× hit.
- `UnknownStatusError` (class): class UnknownStatusError extends Error — Raised when a caller names a status id the runtime has no definition for.
- `UnknownTargetProfileError` (class): class UnknownTargetProfileError extends Error — Raised when a hit names a target that was never registered — a wiring error, not a 0-damage hit.
- `VfxPreset` (interface): interface VfxPreset — A named visual flavor for a one-shot `combat.vfx` burst: the archetype (`kind`), a `0xRRGGBB` tint, and optional default `durationMs`/`radius`. Purely presentation — a preset never touches damage, range, or any authoritative value; it just answers "what does this attack look like" so a game does not hand-roll colors and archetypes.
- `VfxPresetName` (type): type VfxPresetName = keyof typeof vfxPresets — A named key into {@link vfxPresets} (`"arrow" | "fireball" | "lightning" | "web" | "slash" | "shield" | "heal" | ...`).
- `WeaponAim` (interface): interface WeaponAim — Current aim with recoil applied.
- `WeaponAmmo` (interface): interface WeaponAmmo — Ammo and cadence as a HUD or a test reads them.
- `WeaponBurstDef` (interface): interface WeaponBurstDef — Shots one trigger pull commits to. A burst finishes even if the trigger is released.
- `WeaponContact` (interface): interface WeaponContact — Where one pellet met the caller's world.
- `WeaponDamageDef` (interface): interface WeaponDamageDef — What one pellet does when it reaches a registered damage target.
- `WeaponDefinition` (interface): interface WeaponDefinition — One weapon as plain data: cadence, fire mode, delivery, magazine, feel and damage. Nothing here is a function, so a generator can roll it, a save can store it, and two weapons differ by their fields.
- `WeaponFalloffDef` (interface): interface WeaponFalloffDef — Linear damage falloff between two distances.
- `WeaponFireMode` (type): type WeaponFireMode = "single" | "auto" | "burst" — How a held or tapped trigger turns into shots.
- `WeaponFireResult` (interface): interface WeaponFireResult<THit> — The result of a {@link WeaponRuntime.fire} attempt. On `"fired"`, `hits` is whatever the caller's raycast returned and `resolutions` holds the portable damage provenance for each hit that produced a {@link DamageHitInput}; on any blocked status both are empty and no round was spent.
- `WeaponFireStatus` (type): type WeaponFireStatus = "fired" | "cooling" | "empty" | "reloading" — Why a {@link WeaponRuntime.fire} attempt resolved the way it did.
- `WeaponHitscanDef` (interface): interface WeaponHitscanDef — A ray resolved in the caller's world on the same tick it is fired.
- `WeaponImpact` (interface): interface WeaponImpact — One resolved hit, with the damage runtime's full provenance.
- `WeaponImpactContext` (interface): interface WeaponImpactContext — Read-only facts about the hit handed to `damageFor`.
- `WeaponMagazineDef` (interface): interface WeaponMagazineDef — Loaded rounds, reload time, and where reloads draw from.
- `WeaponProjectileDef` (interface): interface WeaponProjectileDef — A travelling pellet simulated by the runtime, resolved when it meets the caller's world.
- `WeaponProjectileView` (interface): interface WeaponProjectileView — A pellet alive in flight, for presentation or prediction.
- `WeaponReloadState` (type): type WeaponReloadState = "idle" | "reloading" | "interrupted" — `idle`, `reloading`, or `interrupted` after `interruptReload()` kept the progress.
- `WeaponRuntime` (interface): interface WeaponRuntime<TAim, THit> — A composed weapon fire controller: a {@link FireCadence} gate, an optional {@link Magazine}, the caller's raycast, and portable {@link resolveDamageHit} damage resolution wired together. The caller retains ownership of models, animations, muzzle flash, audio, input, camera, aiming, and the raycaster itself.
- `WeaponRuntimeConfig` (interface): interface WeaponRuntimeConfig<TAim, THit> — Configuration for {@link createWeaponRuntime}. Everything time/ammo-related is plain data; the two callbacks are where the caller keeps ownership of aiming, its own raycaster/projectile query, and how a hit maps to damage. There is deliberately no default weapon, projectile, or damage table here — those are game content.
- `WeaponShotRecord` (interface): interface WeaponShotRecord — One fired shot: the cone it fired into, the kick it took, and where each pellet went.
- `WeaponStats` (interface): interface WeaponStats — Lifetime ammo economy and resolution counters.
- `WeaponSystem` (interface): interface WeaponSystem — A weapon as the game drives it: base aim in, shots and resolved impacts out. Fire mode, cadence, handling, delivery, magazine and damage all come from one {@link WeaponDefinition}; the game owns input, the muzzle, and the world query.
- `WeaponSystemDeps` (interface): interface WeaponSystemDeps — Everything the runtime is allowed to reach: RNG, the damage model, the muzzle, and the world query.
- `WeaponSystemState` (interface): interface WeaponSystemState — Serializable runtime state: aim, handling, ammo, trigger, pellets and counters.
- `WeaponTickResult` (interface): interface WeaponTickResult — What one {@link WeaponSystem.tick} produced. Empty arrays on a quiet tick.
- `WeaponVec3` (type): type WeaponVec3 = readonly [number, number, number] — A world-space point or direction in metres.
- `activePhaseId` (function): function activePhaseId<TData>(state: EncounterState<TData>): string | null — The deepest active phase id — the completion cursor a HUD reads to label the current wave/phase — or null before start and once done.
- `advanceCombo` (function): function advanceCombo(input: AdvanceComboInput): AdvanceComboResult — ⚠ undocumented
- `advanceMotionCues` (function): function advanceMotionCues(cues: EntityRenderCues, speed: number, dt: number, tuning?: RenderCueTuning): EntityRenderCues — Advances `bobPhase` and decays `recoil` from a live `speed` sample (e.g. `groundSpeed(entity)`); leaves event-driven fields untouched.
- `allocateRewards` (function): function allocateRewards(kind: RewardPolicyKind, request: AllocationRequest): AllocationOutcome — Allocate reward results among participants under a named policy, returning immediate grants and/or claimable pools. Distribution is deterministic and serializable: the same seeds, recipients, and results yield an identical outcome on host and every peer regardless of join order, so allocation replicates as data without re-rolling. Reward *generation* stays upstream (loot tables, roll formulas); this seam only decides who is owed what.
- `applyRenderAnimationEvent` (function): function applyRenderAnimationEvent(cues: EntityRenderCues, event: string): EntityRenderCues — Applies a `entity.animation` event (`"fire"` / `"reload"` / `"reloadEnd"`, or any game-defined name) to the cue set. Unknown event names are a no-op.
- `applyRenderDeathEvent` (function): function applyRenderDeathEvent(cues: EntityRenderCues): EntityRenderCues — Marks the cue set dead after `entity.died`; sticky for the lifetime of the render component.
- `applyRenderHitEvent` (function): function applyRenderHitEvent(cues: EntityRenderCues): EntityRenderCues — Marks a `combat.hitReaction` pulse; the caller clears `hit` again after its own pulse window.
- `applyStatPoolDelta` (function): function applyStatPoolDelta<TOwnerId extends string, TStatId extends string>(access: StatPoolAccess<TOwnerId, TStatId>, ownerId: TOwnerId, statId: TStatId, amount: number): StatPoolAccessResult — Read, transition, and write a caller-owned pool through the structural adapter. Positive amounts increase the resource; negative amounts decrease it. The adapter receives a complete replacement value, never a hidden mutation.
- `armorMitigation` (function): function armorMitigation(armor: number, config?: ArmorConfig): number — Fraction of a hit that armor removes at `armor` points; `0` at zero armor, capped by config.
- `assertDamageTable` (function): function assertDamageTable(table: DamageTableDef): void — Validate a table once at construction: duplicate ids and non-finite multipliers fail loudly.
- `assertHitZoneTable` (function): function assertHitZoneTable(table: HitZoneTable): void — Validate a zone table once at construction: duplicate ids and a missing default fail loudly.
- `assertWeaponDefinition` (function): function assertWeaponDefinition(definition: WeaponDefinition): void — Check a definition before it reaches the runtime, so a rolled weapon fails loudly at construction instead of firing nothing. Throws `RangeError` naming the field.
- `assignSquadRoles` (function): function assignSquadRoles(members: readonly string[], composition: SquadComposition): Map<string, SquadRole> — Deterministic role per member: declared order, `count` copies of each role, and the list repeats when the squad is larger than the composition. Same members and composition give the same answer on every host and after a reload.
- `attackMeta` (function): function attackMeta(tags: readonly AttackTag[], extra?: Omit<AttackMeta, "tags">): AttackMeta — ⚠ undocumented
- `changeStatPool` (function): function changeStatPool(pool: StatPool, amount: number): StatPoolChange — Pure bounded delta transition with the exact applied amount and boundary flags.
- `convergeShot` (function): function convergeShot(deps: ShotOriginDeps, from: string, aim: Aim, range: number, sightHit: (origin: EntityPosition, direction: EntityPosition) => EntityPosition | null, muzzleOffset?: EntityPosition): ResolvedShot | null — Resolves a `converge` shot with scene knowledge: fires from the gun muzzle but bends the direction so the shot passes through the aim point the shooter's eye ray covers. `sightHit` casts the eye ray and returns where it lands (first impact), or `null` to fall back to a point `range` metres down the sightline. A `{ origin, direction }` aim is passed through unchanged (nothing to converge).
- `counters` (function): function counters(meta: AttackMeta, move: CounterMove): boolean — ⚠ undocumented
- `coverPointsFromSolids` (function): function coverPointsFromSolids(solids: readonly CoverSolid[], options: CoverPointOptions = {}): CoverPoint[] — Stand points on every vertical face of the supplied boxes: one row per face, spaced along it, `standOff` out from the surface. Geometry in, cover out — no authored coordinate list, so moving a wall in the editor moves its cover.
- `coverPointsNear` (function): function coverPointsNear(points: readonly CoverPoint[], position: Vec3, radius: number, limit = Number.POSITIVE_INFINITY): CoverPoint[] — The `limit` nearest cover points within `radius`, nearest first, ties broken by id. A linear scan of the points the field holds; the field caps how many points exist.
- `createAbilityKit` (function): function createAbilityKit(configs: readonly AbilitySlotConfig[], options: AbilityKitOptions = {}): AbilityKit — A bar of cooldown-gated abilities the player fires by slot, tracking readiness and cooldown per ability.
- `createAccumulatorMeter` (function): function createAccumulatorMeter(config: AccumulatorMeterConfig): AccumulatorMeter — A raw accumulating gauge that crosses named tier thresholds as a value builds, with optional decay — the primitive under charge, rage, and combo meters.
- `createAntiOneShotPolicy` (function): function createAntiOneShotPolicy(config: AntiOneShotConfig): AntiOneShotPolicy — Compose a reusable anti-one-shot / chip-guard clamp from caller data: while above `guardAboveFraction` a hit cannot drop the target below `leaveFraction`, and after such a save the target gets `recoverMs` of immunity. Below the guard fraction, lethal hits pass unchanged.
- `createBuildupMeter` (function): function createBuildupMeter(config: BuildupMeterConfig): BuildupMeter — Accumulate an ailment buildup — bleed, freeze, poison — that procs a status once it fills, then decays.
- `createCastRunner` (function): function createCastRunner(): CastRunner — Run a channeled cast/charge timer that movement or damage can interrupt — the spell cast bar.
- `createComboMeter` (function): function createComboMeter(config: ComboMeterConfig): ComboMeter — A count-based combo / multiplier meter: an integer hit chain that climbs with every `hit()` and drops when a decay window elapses, crossing free-string tier thresholds ("good" → "great" → "savage") that derive a score multiplier, while tracking the peak reached. Time is injected (`now`, default `Date.now`) and/or driven by `update(dt)`; `view()` returns a pooled draw-state and `snapshot`/`restore` round-trips the chain through a save.
- `createComboPoints` (function): function createComboPoints(config: ComboPointsConfig): ComboPoints — Build and spend finisher points — the combo-point economy behind rogue-style builders and spenders.
- `createComboRunner` (function): function createComboRunner(combo: ComboString, anim: AnimationState): ComboRunner — Advance a chained melee string from timed inputs, tracking the current step and its cancel/continue windows.
- `createCoverField` (function): function createCoverField(options: CoverFieldOptions): CoverField — Cover over authored boxes: derive the stand points once, re-derive them after an edit, and answer bounded nearest-cover queries. `walkable` is injected, so the seam checks the game's own ground test (`nav.findPolygon(point) !== null`) instead of assuming a flat floor.
- `createDamageClamp` (function): function createDamageClamp(config: DamageClampConfig): DamageInterceptor — A stateless interceptor that caps any single application at `maxPerHit`.
- `createDamagePipeline` (function): function createDamagePipeline(initial?: readonly DamageInterceptor[]): DamagePipeline — Create a mutable damage interception chain that state transitions install into and remove from — e.g. add an invulnerability interceptor on phase enter and drop it on phase exit. Evaluation order is install order.
- `createDamageRuntime` (function): function createDamageRuntime(config: DamageRuntimeConfig): DamageRuntime — Build a damage model from data. The number a hit lands is `base × zone multiplier × type multiplier × (1 − armor mitigation)`; statuses tick through the same table and armor, so a burn on an armored target is mitigated like a bullet. Every application — a hit or a status tick — is announced as `combat.damage` carrying the target, source, type, amount, absorbed, remaining health and a lethal flag, so a HUD names the blow instead of guessing.
- `createDeathSystem` (function): function createDeathSystem(deps: DeathSystemDeps): DeathSystem — Resolve entity death and the on-death consequences — drops, respawn eligibility, kill credit.
- `createDefensiveWindow` (function): function createDefensiveWindow(config: DefensiveWindowConfig): DefensiveWindow — Open a timed defensive window — block, parry, or i-frames — and test incoming hits against it.
- `createDotField` (function): function createDotField(): DotField — Builds an empty {@link DotField}; `apply` DoTs onto it and drain damage each frame with `tick`.
- `createDownedState` (function): function createDownedState(config: DownedConfig): DownedState — A downed/bleed-out state that ticks toward death and that teammates can revive before the timer runs out.
- `createEffectSystem` (function): function createEffectSystem(deps: EffectSystemDeps): EffectSystem — Resolve direct or area resource effects through caller-owned stat pools, including ordered absorption, restoration, modifiers, and lethal context.
- `createEncounterState` (function): function createEncounterState<TData>(config: EncounterConfig<TData>): EncounterState<TData> — Build the initial, serializable state for an encounter from its config. Deep-copies the authored phase tree (so later injection never mutates the config), verifies phase ids are unique, and leaves every node pending. Does not enter the first phase — call {@link startEncounter} for that.
- `createEventMeter` (function): function createEventMeter(config: EventMeterConfig): EventMeter — A heat/hype gauge that rises as tagged events land and cools between them, firing when it fills or breaks — the streak/overdrive meter shooters and fighters hand-roll.
- `createFireCadence` (function): function createFireCadence(config: FireCadenceConfig): FireCadence — Build a {@link FireCadence} rate gate. Reach for this instead of hand-tracking a `lastFiredAt` timestamp and comparing against a fire interval per game.
- `createImmunityWindow` (function): function createImmunityWindow(id = "immunity"): ImmunityWindow — A per-target immunity/invulnerability window as an ordinary damage policy — granted and cleared by state transitions (i-frames, phase invuln), rejecting damage while active. Deterministic (time is passed in) and serializable.
- `createMagazine` (function): function createMagazine(config: MagazineConfig): Magazine — Builds a {@link Magazine}: discrete loaded ammo, a timed reload, and reserve-pool interaction.
- `createProjectileSystem` (function): function createProjectileSystem(deps: ProjectileSystemDeps): ProjectileSystem — Spawn and advance projectiles each frame, resolving travel, lifetime, and hits.
- `createRegenShield` (function): function createRegenShield(config: RegenShieldConfig): RegenShield — Builds a {@link RegenShield} that suppresses regen for `regenDelayMs` after each hit.
- `createResourcePool` (function): function createResourcePool(config: ResourcePoolConfig): ResourcePool — A regenerating resource pool — mana, stamina, energy — that actions spend from and that refills over time.
- `createSquadCombat` (function): function createSquadCombat(options: SquadCombatOptions): SquadCombat — One squad's combat behavior per tick, over the perception memory a game already keeps and the nav crowd it already moves. Each member picks a stand point that hides it from the threats it remembers, at the distance and angle its role wants; a flanker goes around the side, a support holds and fires, an assault closes. Incoming fire raises suppression, which pins the member to its cover and stops its shooting until the meter decays; low health turns it toward the point furthest from the threat.
- `createStaggerMeter` (function): function createStaggerMeter(config: StaggerMeterConfig): StaggerMeter — Build a stagger/poise gauge from landed hits toward a break threshold that staggers the target.
- `createStatPool` (function): function createStatPool(input: StatPoolInput): StatPool — Normalize caller data into a complete plain-data pool.
- `createStats` (function): function createStats<TStat extends string>(base: Record<TStat, number>, options?: CreateStatsOptions): Stats<TStat> — A stat block whose base values take stacking, timed buffs and debuffs, resolving the modified value on read.
- `createStatusRuntime` (function): function createStatusRuntime(options: StatusRuntimeOptions): StatusRuntime — Build a status runtime over serializable definitions. Applications reuse {@link resolveStatusApplication} for chance and stacking, so a refresh/stack-to-N/ignore rule has exactly one implementation; `tick` then applies each status's declared effect per stack.
- `createThresholdTracker` (function): function createThresholdTracker(config: ThresholdCrossingConfig): ThresholdTracker — Track a numeric source against named thresholds and emit ordered crossing events with direction, hysteresis, once/repeat policy, and skipped-threshold handling. Deterministic and serializable; drives phase transitions, armor breaks, resource warnings, and any other threshold consumer.
- `createWeaponRuntime` (function): function createWeaponRuntime<TAim, THit>(config: WeaponRuntimeConfig<TAim, THit>): WeaponRuntime<TAim, THit> — Compose a portable weapon fire controller from the existing generic primitives — a {@link FireCadence} gate, an optional {@link Magazine}, a caller-provided raycast, and portable {@link resolveDamageHit} damage resolution. No `GameContext`, entity store, renderer, or default weapon is involved; the caller owns aiming, its raycaster, and all presentation, and the result carries full damage provenance for authority to apply and replicate.
- `createWeaponSystem` (function): function createWeaponSystem(initial: WeaponDefinition, deps: WeaponSystemDeps): WeaponSystem — Build a weapon from one {@link WeaponDefinition}. The game supplies aim, a muzzle, one world query, the damage model and an RNG; the runtime owns fire modes, cadence, recoil, bloom, reload states, ammo accounting, projectile ballistics and the damage call. State snapshots as plain data.
- `encounterProgress` (function): function encounterProgress<TData>(state: EncounterState<TData>): { completed: number; total: number; done: boolean; } — Progress across the whole tree: how many phases have completed out of the total node count, plus whether the encounter has finished. Counts injected phases.
- `eyeHeightFromColliders` (function): function eyeHeightFromColliders(set: EntityColliderSet | null | undefined): number — Eye height derived from a collider set: 90% of the tallest hitbox top, or the humanoid default when unknown.
- `filterOutcomeFor` (function): function filterOutcomeFor(outcome: AllocationOutcome, viewerId: string): AllocationOutcome — Project an allocation outcome for one viewer, enforcing replication authoritatively: private grants belonging to other recipients are dropped, and pools the viewer cannot claim (not eligible, or reserved for someone else) are hidden — so private rewards never leak across the wire while provenance on the viewer's own grants is preserved.
- `forceCompletePhase` (function): function forceCompletePhase<TData>(config: EncounterConfig<TData>, state: EncounterState<TData>, ctx: EncounterContext = {}, phaseId?: string): EncounterStep<TData> — Force the deepest active phase (or a named active phase) to complete now, regardless of its predicate — the escape hatch for external/scripted completion and failure/retry flows. Advances into the next phase and emits the same lifecycle events as a natural completion. Returns no events if the phase is not currently active. Mutates and returns `state`.
- `formatDamageTable` (function): function formatDamageTable(rows: readonly DamageTableRow[]): string[] — Render rows as fixed-width lines for a devtools probe, a CLI dump, or a test's diff.
- `hitZoneMultiplier` (function): function hitZoneMultiplier(table: HitZoneTable, zone: string | undefined, crit: boolean): { zone: string; multiplier: number; fallback: boolean } — The multiplier a zone earns for a known crit outcome, without rolling. `resolveHitZone` and a time-to-kill quote both read through this, so a quoted crit uses the same number combat does.
- `impactPresets` (const): const impactPresets: { readonly pickup: { readonly hitstopMs: 0; readonly trauma: 0.15; }; readonly jumpLand: { readonly hitstopMs: 0; readonly trauma: 0.2; }; readonly enemyKilled: { readonly hitstopMs: 40; readonly trauma: 0.3; }; readonly playerHit: { readonly hitstopMs: 70; readonly trauma: 0.4;… — Calibrated per-event impact feel — hitstop and trauma numbers harvested from a shipped game-feel reference, not hand-invented per game. `explosion` and `playerHit` are "heavy hit" events (60–90ms hitstop @ 0.05 timescale); `pickup`/`jumpLand` are light events with no hitstop. Trauma is later clamped to 1.0 by `resolveHitReaction`.
- `injectPhase` (function): function injectPhase<TData>(state: EncounterState<TData>, phase: EncounterPhase<TData>, at: PhaseInjectAt): EncounterState<TData> — Insert a phase into the working tree at runtime — before/after a sibling, or as a child of a group — without disturbing already-completed or active nodes. The injected subtree becomes part of the serializable state (so a mid-encounter save preserves it) and is reached in normal order if it sits ahead of the cursor. Ids must stay tree-unique. Mutates and returns `state`.
- `isBlockable` (function): function isBlockable(meta: AttackMeta): boolean — ⚠ undocumented
- `isDodgeable` (function): function isDodgeable(meta: AttackMeta): boolean — ⚠ undocumented
- `isParryable` (function): function isParryable(meta: AttackMeta): boolean — ⚠ undocumented
- `patchStatPool` (function): function patchStatPool(pool: StatPool, patch: StatPoolPatch): StatPool — Apply new bounds/current to a pool, clamping the result and leaving the input untouched.
- `phaseStatus` (function): function phaseStatus<TData>(state: EncounterState<TData>, id: string): PhaseStatus | null — The runtime status of a phase by id (pending/active/complete), or null if the id is unknown — for driving per-phase HUD ticks and objective checklists.
- `readDamageTable` (function): function readDamageTable(table: DamageTableDef, read?: { base?: number; armor?: number | Readonly<Record<string, number>>; types?: readonly string[]; resistances?: readonly string[]; }): DamageTableRow[] — Read the whole table as rows — every listed type against every listed resistance class, each with the armor it was read at and the damage a base would land. This is the table a designer reads and a test asserts, so a resistance change is visible without running combat.
- `resistanceScale` (function): function resistanceScale<TCategory extends string = string, TProperty extends string = string>(matrix: ResistanceMatrix<TCategory, TProperty>, category: TCategory | string, targetProperties: readonly (TProperty | string)[]): number — ⚠ undocumented
- `resolveClaim` (function): function resolveClaim(pool: ClaimablePool, claimantId: string, options?: { nowMs?: number; private?: boolean }): ClaimOutcome — Resolve an authoritative claim against a pool. Idempotent: re-claiming an already-owned pool returns the same grants without re-awarding, a losing claimant gets no grants, and eligibility, reservation, and expiry are all enforced here — the authority, not UI hiding, decides ownership. Returns the updated (serializable) pool plus the grants owed.
- `resolveDamage` (function): function resolveDamage(interceptors: readonly DamageInterceptor[], pending: PendingDamage, ctx: InterceptContext): DamageResolution — Run one pending damage application through an ordered interceptor list before lethality resolves, returning the final applications, any deferred ones, and full provenance. Pure and deterministic; bounded by `MAX_INTERCEPT_STEPS`.
- `resolveDamageHit` (function): function resolveDamageHit(input: DamageHitInput): DamageHitResolution — Resolve a full damage hit through the data-defined pipeline: score the channel against the target's traits ({@link resolveMatchup}), scale base impact by the matchup's `impact` axis, run receiver-side modifiers ({@link resolveReceivedDamage}), then roll status application scaled by the matchup's `applyChance`/`magnitude`/`duration` axes ({@link resolveStatusApplication}). Pure and deterministic given a seeded `rng`; returns full provenance and never mutates state, so it is safe to run on the authority and replicate the results.
- `resolveDefense` (function): function resolveDefense(input: ResolveDefenseInput): DefenseResolution — ⚠ undocumented
- `resolveHitReaction` (function): function resolveHitReaction(config: HitReactionConfig | ImpactPresetName, input: HitReactionInput): HitReaction — Resolves hit feel (hitstop, knockback impulse, camera shake) from either a named `impactPresets` event (`resolveHitReaction("explosion", input)`) or a raw `HitReactionConfig` override.
- `resolveHitZone` (function): function resolveHitZone(table: HitZoneTable, zone: string | undefined, rng?: () => number): HitZoneResolution — Resolve where a hit landed into one multiplier: roll the crit chance for that zone, and apply the crit multiplier when it lands, otherwise the zone's own multiplier. The injected `rng` keeps the roll reproducible; a zero chance draws nothing, so a deterministic test can force either outcome.
- `resolveMatchup` (function): function resolveMatchup<TChannel extends string = DamageChannelId, TTrait extends string = TargetTraitId>(matchup: DamageMatchup<TChannel, TTrait>, channel: TChannel | string, targetTraits: readonly (TTrait | string)[]): ResolvedMatchup — Resolve a channel against a target's traits into independent, multiplied outputs. Pure and order-independent: every trait the channel has an entry for contributes, its axes multiplying into the running product; unmatched traits are skipped, and when nothing matches the table's `default` (or identity) is used. Bounded by the trait count — no world scan.
- `resolveReceivedDamage` (function): function resolveReceivedDamage(input: ReceivedDamageInput): ReceivedDamageResult — Run receiver-side modifiers over an incoming hit, in ascending `order`, recording every step. Amplification, reduction, caps, conversion, redirection, and immunity are all data — the engine applies whichever policies the target's modifiers declare and never branches on channel names. Pure over serializable data with bounded work (one pass over the modifier list); an `immune` policy short-circuits the remaining modifiers.
- `resolveResistance` (function): function resolveResistance<TCategory extends string = string, TProperty extends string = string>(matrix: ResistanceMatrix<TCategory, TProperty>, category: TCategory | string, targetProperties: readonly (TProperty | string)[]): ResistanceResult — ⚠ undocumented
- `resolveShot` (function): function resolveShot(deps: ShotOriginDeps, from: string, aim: Aim, policy: ShotOriginPolicy = { kind: "eye" }): ResolvedShot | null — Resolves a shot's world origin and direction from the shooter's eye or muzzle and an {@link Aim}, ready for `ctx.scene.raycast` — the aim half of a hitscan weapon.
- `resolveStatusApplication` (function): function resolveStatusApplication(input: StatusApplicationInput): StatusApplicationOutcome — Resolve one status application: reject on immunity, roll landing chance against injected RNG, scale magnitude/duration by the matchup, then fold into any existing instance per the stacking policy. Deterministic given a seeded `rng`; pure over serializable data, so authority can run it and replicate only the returned `instance`.
- `resolveTableDamage` (function): function resolveTableDamage(table: DamageTableDef, input: { type: string; resistance: string; armor?: number; base?: number }): DamageTableRow — Resolve one hit through the table: type multiplier, then armor mitigation, and the base scaled by both. Formula order matters only for the numbers a UI shows — the product is the same.
- `resolveVfxPreset` (function): function resolveVfxPreset(name: string | undefined, overrides?: Partial<VfxPreset>): VfxPreset — Resolve a named visual flavor into a concrete `{ kind, color, durationMs?, radius? }`, with any provided `overrides` winning field by field. An unknown name resolves to {@link DEFAULT_VFX_PRESET} rather than throwing, so a flavor typo degrades to a visible spark. Used by `ctx.scene.entity.vfx({ preset })`; call it directly when you need the raw numbers (e.g. to seed a retained `vfxInstance` from the same vocabulary).
- `rollCheck` (function): function rollCheck(input: CheckInput, rng?: () => number): CheckResult — Resolve a tabletop-style pass/fail roll against a target number with modifiers and crit/fumble bands.
- `scoreCoverPoint` (function): function scoreCoverPoint(point: CoverPoint, query: CoverQuery): CoverChoice | null — Score one stand point against the threats the member remembers. `hidden` is the confidence-weighted share of remembered threats that cannot see the point, so a point that hides from the shooter that matters scores over one that hides from a fading one. Returns `null` when nothing it can hide from is worth considering.
- `selectCover` (function): function selectCover(points: readonly CoverPoint[], query: CoverQuery): CoverChoice | null — The best of `points` under one {@link CoverQuery}, ties broken by point id. Pass the candidate set the injected query already bounded; this scores what it is given.
- `startEncounter` (function): function startEncounter<TData>(config: EncounterConfig<TData>, state: EncounterState<TData>, ctx: EncounterContext = {}): EncounterStep<TData> — Start a created encounter: enter the first root phase, descending to its first leaf, and return the initial enter/spawn events. A no-op (with no events) on an already-started or empty encounter. Mutates and returns `state`.
- `statusEffectRemainingFraction` (function): function statusEffectRemainingFraction(view: StatusEffectView): number — Fraction of the countdown still remaining, clamped to `[0,1]` — the value a countdown ring fills to. Returns `0` when the duration is non-positive. Pure; safe to call every frame.
- `threatsFromMemory` (function): function threatsFromMemory(perception: PerceptionService, observerId: string, nowMs: number, options: ThreatReadOptions = {}): ThreatReading[] — Read one member's threat list out of its perception memory — the only source of threat. Sorted by confidence, then recency, then id, and bounded by `max`, so a crowded memory cannot grow the tick.
- `tierAt` (function): function tierAt(value: number, tiers: readonly MeterTier[]): string | null — The highest tier id whose `at` threshold `value` has reached, or `null` below every tier — the pure lookup `createAccumulatorMeter`/`createEventMeter` call on every `add`/`tick`.
- `toStatusEffectView` (function): function toStatusEffectView(instance: StatusInstance, options?: StatusEffectViewOptions): StatusEffectView — Map one live {@link StatusInstance} to a serializable {@link StatusEffectView} for a HUD row. Pure: no clock, no allocation beyond the returned view. The `durationMs` option supplies the ring denominator the instance does not carry; without it the ring reads full.
- `toStatusEffectViews` (function): function toStatusEffectViews(instances: readonly StatusInstance[], options?: StatusEffectViewOptions): StatusEffectView[] — Map a list of live statuses (a target's carried {@link StatusInstance}s) to ordered HUD views. Pure and allocation-bounded — one pass, one view per input — so a status bar can render straight off the existing status model's snapshot without re-deriving ring math or timers.
- `typeBypassesArmor` (function): function typeBypassesArmor(table: DamageTableDef, type: string): boolean — Whether armor points reduce this damage type.
- `typeMultiplier` (function): function typeMultiplier(table: DamageTableDef, type: string, resistance: string): number — The type × resistance multiplier for one class, before armor. An unknown type throws; an unknown resistance class uses the table's `defaultMultiplier`, since target classes may be narrower than the table's coverage.
- `updateEncounter` (function): function updateEncounter<TData>(config: EncounterConfig<TData>, state: EncounterState<TData>, dt: number, ctx: EncounterContext = {}): EncounterStep<TData> — Advance an encounter by `dt` seconds against the caller `ctx`. Accumulates time, then repeatedly: evaluates the cursor node's completion predicate; on completion, either re-runs its subtree (`repeat`) or marks it complete and advances to the next sibling — bubbling up to parent groups whose children are exhausted — entering the next chain and emitting enter/spawn/complete events. Emits a final `done` event when the last phase completes. Bounded per call by node count; mutates and returns `state`.
- `vfxPresets` (const): const vfxPresets: { readonly arrow: { readonly kind: "projectile"; readonly color: 14207392; }; readonly bolt: { readonly kind: "projectile"; readonly color: 16777215; }; readonly fireball: { readonly kind: "projectile"; readonly color: 16738842; readonly durationMs: 460; }; readonly firebolt: { rea… — Ready-made visual flavors for the things players actually shoot, swing, and cast — so `ctx.scene.entity.vfx({ preset: "arrow", from, to })` renders a visible bolt with zero tuning, and `"lightning"`, `"web"`, `"slash"`, `"shield"`, `"heal"`, `"explosion"` likewise just work. Each entry only picks a `kind` (`projectile | beam | nova | glow | spark`), a color, and a lifetime; it is visual vocabulary (like named CSS colors), not a gameplay archetype — combat numbers stay in the caller's own effect/ability data. Any field passed to `vfx()` overrides the preset, and unknown names fall back to `spark` so a flavor typo still shows *something* rather than nothing.
- `weaponDamageAt` (function): function weaponDamageAt(definition: WeaponDefinition, distance: number): number — Damage multiplier at a distance: `1` before `falloff.start`, linearly down to `endScale` at `end`.
- `weaponIntervalMs` (function): function weaponIntervalMs(definition: WeaponDefinition): number — Milliseconds between shots at full cadence: `60_000 / roundsPerMinute`.
- `weaponMaxInFlight` (function): function weaponMaxInFlight(definition: WeaponDefinition): number — Live pellets one definition may keep, clamped to a bounded range.

## @jgengine/core/combat/abilityKit

- `AbilityCastReason` (type): type AbilityCastReason = "unknown-slot" | "cooldown" | "group-cooldown" | "no-resource" — ⚠ undocumented
- `AbilityCastResult` (type): type AbilityCastResult = | { ok: true; slot: AbilitySlotSnapshot } | { ok: false; reason: AbilityCastReason; slot: AbilitySlotSnapshot | null } — ⚠ undocumented
- `AbilityCastType` (type): type AbilityCastType = "instant" | "projectile" | "channel" | "targeted" — ⚠ undocumented
- `AbilityCooldownGroup` (interface): interface AbilityCooldownGroup — A cooldown shared across every member slot: casting any member starts it, and no member can cast while it runs. One group that every slot joins is an MMO global cooldown.
- `AbilityKit` (interface): interface AbilityKit { slots(): readonly string[]; config(slotId: string): AbilitySlotConfig | null; state(): AbilityKitState; state(slotId: string, resourceAvailable?: number): AbilitySlotSnapshot | null; snapshot(resourceAvailable?: number): AbilitySlotSnapsh… — ⚠ undocumented · used by `createAbilityKit`: A bar of cooldown-gated abilities the player fires by slot, tracking readiness and cooldown per ability.
- `AbilityKitOptions` (interface): interface AbilityKitOptions { groups?: readonly AbilityCooldownGroup[]; resource?: AbilityResource } — ⚠ undocumented · used by `createAbilityKit`: A bar of cooldown-gated abilities the player fires by slot, tracking readiness and cooldown per ability.
- `AbilityKitState` (interface): interface AbilityKitState — Mutable kit state; slot/group definitions and any bound resource are saved by the caller.
- `AbilityResource` (interface): interface AbilityResource — A spendable resource pool (mana, energy, rage) bound to an ability kit. When bound, `cast` deducts a slot's `resourceCost` on success and `state`/`snapshot`/`canCast` reflect affordability without a per-call `resourceAvailable` argument — the cast path actually spends instead of only gating (#357).
- `AbilitySlotConfig` (interface): interface AbilitySlotConfig { id: string; cooldownMs: number; chargesMax?: number; resourceCost?: number; castType?: AbilityCastType; flashMs?: number; groups?: readonly string[] } — ⚠ undocumented · used by `createAbilityKit`: A bar of cooldown-gated abilities the player fires by slot, tracking readiness and cooldown per ability.
- `AbilitySlotRetune` (interface): interface AbilitySlotRetune { cooldownMs?: number; resourceCost?: number } — ⚠ undocumented
- `AbilitySlotSnapshot` (interface): interface AbilitySlotSnapshot { id: string; state: AbilitySlotState; castType: AbilityCastType; resourceCost: number; charges: number; chargesMax: number; cooldownRemainingMs: number; cooldownFraction: number; groupRemainingMs: number; justCast: boolean; ready: boolean … — ⚠ undocumented · used by `actionFromAbilitySlot` (@jgengine/react): Composable React renderers over the headless action view model (`@jgengine/core/ui/actionModel`) — the data/renderer/chrome split for an RTS…
- `AbilitySlotState` (type): type AbilitySlotState = "ready" | "cooldown" | "no-resource" | "just-cast" — ⚠ undocumented
- `createAbilityKit` (function): function createAbilityKit(configs: readonly AbilitySlotConfig[], options: AbilityKitOptions = {}): AbilityKit — A bar of cooldown-gated abilities the player fires by slot, tracking readiness and cooldown per ability.

## @jgengine/core/combat/animationState

- `AnimationClip` (interface): interface AnimationClip { id: string; frames: number; fps: number; ranges: readonly FrameRange[]; loop?: boolean } — ⚠ undocumented · used by `createGraphPose` (@jgengine/shell/render/useModelAnimation): Binds a graph's clips to a rig exactly as `useModelAnimation` does (masked layers get filtered clips, additive layers additive ones) so a ho…
- `AnimationSnapshot` (interface): interface AnimationSnapshot { clipId: string; frame: number; elapsedMs: number } — ⚠ undocumented
- `AnimationState` (interface): interface AnimationState { play(clipId: string): void; stop(): void; tick(dtSeconds: number): AnimationTickResult; current(): AnimationSnapshot | null; phases(): readonly FramePhase[]; inPhase(phase: FramePhase): boolean; isActive(): boolean; canCancel(): boolean; … — ⚠ undocumented · used by `createComboRunner` (@jgengine/core/combat): Advance a chained melee string from timed inputs, tracking the current step and its cancel/continue windows.
- `AnimationStateConfig` (interface): interface AnimationStateConfig { clips: readonly AnimationClip[] } — ⚠ undocumented
- `AnimationTickResult` (interface): interface AnimationTickResult { clipId: string | null; frame: number; entered: readonly FramePhase[]; exited: readonly FramePhase[]; completed: boolean } — ⚠ undocumented
- `FramePhase` (type): type FramePhase = "windup" | "active" | "recovery" | "cancel" — ⚠ undocumented
- `FrameRange` (interface): interface FrameRange { phase: FramePhase; from: number; to: number } — ⚠ undocumented

## @jgengine/core/combat/attackTags

- `AttackMeta` (interface): interface AttackMeta { tags: readonly AttackTag[]; effect?: string; power?: number } — ⚠ undocumented
- `AttackTag` (type): type AttackTag = | "unblockable" | "thrust" | "sweep" | "grab" | "overhead" | "ranged" | "aerial" — ⚠ undocumented
- `CounterMove` (type): type CounterMove = "mikiri" | "deflect" | "sidestep" — ⚠ undocumented
- `attackMeta` (function): function attackMeta(tags: readonly AttackTag[], extra?: Omit<AttackMeta, "tags">): AttackMeta — ⚠ undocumented
- `counters` (function): function counters(meta: AttackMeta, move: CounterMove): boolean — ⚠ undocumented
- `hasAnyTag` (function): function hasAnyTag(meta: AttackMeta, tags: readonly AttackTag[]): boolean — ⚠ undocumented
- `hasTag` (function): function hasTag(meta: AttackMeta, tag: AttackTag): boolean — ⚠ undocumented
- `isBlockable` (function): function isBlockable(meta: AttackMeta): boolean — ⚠ undocumented
- `isDodgeable` (function): function isDodgeable(meta: AttackMeta): boolean — ⚠ undocumented
- `isParryable` (function): function isParryable(meta: AttackMeta): boolean — ⚠ undocumented

## @jgengine/core/combat/breakMeters

- `BuildupMeter` (interface): interface BuildupMeter { add(amount: number): BuildupProc | null; value(): number; fraction(): number; tick(dtSeconds: number): void } — ⚠ undocumented · used by `createBuildupMeter`: Accumulate an ailment buildup — bleed, freeze, poison — that procs a status once it fills, then decays.
- `BuildupMeterConfig` (interface): interface BuildupMeterConfig { status: string; max: number; durationMs: number; decayPerSecond?: number; decayDelayMs?: number } — ⚠ undocumented · used by `createBuildupMeter`: Accumulate an ailment buildup — bleed, freeze, poison — that procs a status once it fills, then decays.
- `BuildupProc` (interface): interface BuildupProc { status: string; durationMs: number } — ⚠ undocumented
- `StaggerMeter` (interface): interface StaggerMeter { add(amount: number): boolean; broke(): boolean; value(): number; fraction(): number; recover(): void; tick(dtSeconds: number): void } — ⚠ undocumented · used by `createStaggerMeter`: Build a stagger/poise gauge from landed hits toward a break threshold that staggers the target.
- `StaggerMeterConfig` (interface): interface StaggerMeterConfig { max: number; decayPerSecond?: number; decayDelayMs?: number } — ⚠ undocumented · used by `createStaggerMeter`: Build a stagger/poise gauge from landed hits toward a break threshold that staggers the target.
- `createBuildupMeter` (function): function createBuildupMeter(config: BuildupMeterConfig): BuildupMeter — Accumulate an ailment buildup — bleed, freeze, poison — that procs a status once it fills, then decays.
- `createStaggerMeter` (function): function createStaggerMeter(config: StaggerMeterConfig): StaggerMeter — Build a stagger/poise gauge from landed hits toward a break threshold that staggers the target.

## @jgengine/core/combat/castRunner

- `CastBarSnapshot` (interface): interface CastBarSnapshot { abilityId: string; castTimeMs: number; elapsedMs: number; remainingMs: number; fraction: number } — ⚠ undocumented
- `CastConfig` (interface): interface CastConfig { abilityId: string; castTimeMs: number; moveTolerance?: number; moveDeadzone?: number } — ⚠ undocumented
- `CastEvent` (type): type CastEvent = | { kind: "completed"; abilityId: string } | { kind: "interrupted"; abilityId: string; reason: CastInterruptReason } — ⚠ undocumented
- `CastInterruptReason` (type): type CastInterruptReason = "moved" | "cancelled" | "replaced" — ⚠ undocumented
- `CastRunner` (interface): interface CastRunner — Per-entity cast-time state machine — begin, tick with game-time `dt` plus how far the caster moved, and act on the returned event. The runner owns timing and move-interruption only; the caller spends resources, starts cooldowns, and executes the ability when `completed` fires (compose with `abilityKit` — check readiness before `begin`, `cast` on completion).
- `createCastRunner` (function): function createCastRunner(): CastRunner — Run a channeled cast/charge timer that movement or damage can interrupt — the spell cast bar.

## @jgengine/core/combat/comboMeter

- `ComboMeter` (interface): interface ComboMeter — A live, observable combo/multiplier meter — an integer hit chain with a decay window, free-string tier thresholds, a derived multiplier, and peak tracking.
- `ComboMeterConfig` (interface): interface ComboMeterConfig — Options for {@link createComboMeter}.
- `ComboMeterSnapshot` (interface): interface ComboMeterSnapshot — Serializable state for save/restore — clock-agnostic (stores time left, not an absolute deadline).
- `ComboMeterView` (interface): interface ComboMeterView — A pooled, read-only snapshot of the live meter for a renderer to draw each frame. Reused across {@link ComboMeter.view} calls and overwritten on the next one — read it, do not retain it. For a save, use {@link ComboMeter.snapshot}.
- `ComboTier` (interface): interface ComboTier — One tier threshold in a {@link ComboMeter}. Tiers gate on the integer combo `count` (not a filled fraction), and `id` is a free string the game owns and styles ("good", "great", "savage", …) — the model never interprets it.
- `createComboMeter` (function): function createComboMeter(config: ComboMeterConfig): ComboMeter — A count-based combo / multiplier meter: an integer hit chain that climbs with every `hit()` and drops when a decay window elapses, crossing free-string tier thresholds ("good" → "great" → "savage") that derive a score multiplier, while tracking the peak reached. Time is injected (`now`, default `Date.now`) and/or driven by `update(dt)`; `view()` returns a pooled draw-state and `snapshot`/`restore` round-trips the chain through a save.

## @jgengine/core/combat/comboPoints

- `ComboPoints` (interface): interface ComboPoints { points(): number; gain(amount?: number): number; spend(amount: number): boolean; spendAll(): number; tick(dtSeconds: number): void; expiresIn(): number | null; clear(): void; snapshot(): ComboPointsSnapshot; restore(state: ComboPointsSnap… — ⚠ undocumented · used by `createComboPoints`: Build and spend finisher points — the combo-point economy behind rogue-style builders and spenders.
- `ComboPointsConfig` (interface): interface ComboPointsConfig { max: number; expireAfterSeconds?: number } — ⚠ undocumented · used by `createComboPoints`: Build and spend finisher points — the combo-point economy behind rogue-style builders and spenders.
- `ComboPointsSnapshot` (interface): interface ComboPointsSnapshot — Complete serializable state for {@link ComboPoints}; `remaining: null` means no expiry is running.
- `createComboPoints` (function): function createComboPoints(config: ComboPointsConfig): ComboPoints — Build and spend finisher points — the combo-point economy behind rogue-style builders and spenders.

## @jgengine/core/combat/comboString

- `AdvanceComboInput` (interface): interface AdvanceComboInput { combo: ComboString; currentStepId: string | null; requestedStepId: string; phases: readonly FramePhase[]; stance?: string } — ⚠ undocumented
- `AdvanceComboResult` (type): type AdvanceComboResult = | { accepted: true; step: ComboStep } | { accepted: false; reason: "unknown-step" | "not-chainable" | "wrong-stance" | "window-closed" } — ⚠ undocumented
- `ComboRunner` (interface): interface ComboRunner { currentStep(): string | null; request(stepId: string, stance?: string): AdvanceComboResult; reset(): void } — ⚠ undocumented · used by `createComboRunner`: Advance a chained melee string from timed inputs, tracking the current step and its cancel/continue windows.
- `ComboStep` (interface): interface ComboStep { id: string; clip: string; cancelInto?: readonly string[]; cancelPhases?: readonly FramePhase[]; stance?: string } — ⚠ undocumented
- `ComboString` (interface): interface ComboString { id: string; entry: string; steps: readonly ComboStep[] } — ⚠ undocumented · used by `createComboRunner`: Advance a chained melee string from timed inputs, tracking the current step and its cancel/continue windows.
- `advanceCombo` (function): function advanceCombo(input: AdvanceComboInput): AdvanceComboResult — ⚠ undocumented
- `createComboRunner` (function): function createComboRunner(combo: ComboString, anim: AnimationState): ComboRunner — Advance a chained melee string from timed inputs, tracking the current step and its cancel/continue windows.
- `stepById` (function): function stepById(combo: ComboString, stepId: string): ComboStep | null — ⚠ undocumented

## @jgengine/core/combat/cover

- `CoverChoice` (interface): interface CoverChoice — A scored cover point, with every term visible so a probe or test can see why it won.
- `CoverField` (interface): interface CoverField extends CoverSource — Cover derived from authored geometry, rebuilt when the world is edited.
- `CoverFieldOptions` (interface): interface CoverFieldOptions extends CoverPointOptions — Options for {@link createCoverField}: the authored boxes, the dials, and a probe name.
- `CoverFieldSnapshot` (interface): interface CoverFieldSnapshot — Serializable cover field state: the boxes and the dials, not the derived points.
- `CoverPoint` (interface): interface CoverPoint — One stand position beside authored geometry, with the face direction it hides against.
- `CoverPointOptions` (interface): interface CoverPointOptions — How cover points sit relative to the geometry that generates them.
- `CoverQuery` (interface): interface CoverQuery — Everything one cover decision reads: where the member is, what it believes, and its role's policy.
- `CoverSolid` (interface): interface CoverSolid — A box of authored world geometry a body can hide behind. Structurally a `WorldSolid`, so `ctx.world.solids.all()` drops in directly; a game with its own collision can pass any boxes.
- `CoverSource` (interface): interface CoverSource — Bounded source of cover near a position: generated from authored geometry, or the game's own spatial query. Called for one member at a time, never for the whole squad.
- `CoverThreat` (interface): interface CoverThreat — A remembered threat: where the member last saw it and how strongly it still believes it.
- `CoverWeights` (interface): interface CoverWeights — What each term is worth when choosing cover. A role owns these numbers.
- `coverPointsFromSolids` (function): function coverPointsFromSolids(solids: readonly CoverSolid[], options: CoverPointOptions = {}): CoverPoint[] — Stand points on every vertical face of the supplied boxes: one row per face, spaced along it, `standOff` out from the surface. Geometry in, cover out — no authored coordinate list, so moving a wall in the editor moves its cover.
- `coverPointsNear` (function): function coverPointsNear(points: readonly CoverPoint[], position: Vec3, radius: number, limit = Number.POSITIVE_INFINITY): CoverPoint[] — The `limit` nearest cover points within `radius`, nearest first, ties broken by id. A linear scan of the points the field holds; the field caps how many points exist.
- `createCoverField` (function): function createCoverField(options: CoverFieldOptions): CoverField — Cover over authored boxes: derive the stand points once, re-derive them after an edit, and answer bounded nearest-cover queries. `walkable` is injected, so the seam checks the game's own ground test (`nav.findPolygon(point) !== null`) instead of assuming a flat floor.
- `scoreCoverPoint` (function): function scoreCoverPoint(point: CoverPoint, query: CoverQuery): CoverChoice | null — Score one stand point against the threats the member remembers. `hidden` is the confidence-weighted share of remembered threats that cannot see the point, so a point that hides from the shooter that matters scores over one that hides from a fading one. Returns `null` when nothing it can hide from is worth considering.
- `selectCover` (function): function selectCover(points: readonly CoverPoint[], query: CoverQuery): CoverChoice | null — The best of `points` under one {@link CoverQuery}, ties broken by point id. Pass the candidate set the injected query already bounded; this scores what it is given.

## @jgengine/core/combat/damageInterceptors

- `AntiOneShotConfig` (interface): interface AntiOneShotConfig — Caller data for the anti-one-shot composition: "cannot cross lethal while above X, leave Y, then recover for Z".
- `AntiOneShotPolicy` (interface): interface AntiOneShotPolicy — The anti-one-shot policy: an interceptor plus its serializable recovery-immunity state.
- `DamageClampConfig` (interface): interface DamageClampConfig — Caller data for a flat per-hit damage cap.
- `DamageInterceptor` (interface): interface DamageInterceptor — A named stage in the interception pipeline. The `id` is stable so it can be installed, removed, and cited in provenance.
- `DamagePipeline` (interface): interface DamagePipeline — A mutable ordered interceptor chain that transitions can install into and remove from at runtime.
- `DamageResolution` (interface): interface DamageResolution — The outcome of running a pending application through the pipeline: what to apply, what was deferred, and why each value changed.
- `ImmunityWindow` (interface): interface ImmunityWindow — A per-target timed immunity policy: an interceptor plus grant/query/serialize controls, toggled by transitions.
- `InterceptContext` (interface): interface InterceptContext — Read-only context an interceptor may consult — deterministic clock and optional health lookup for HP-relative policies.
- `InterceptDecision` (type): type InterceptDecision = | { kind: "pass" } | { kind: "transform"; amount: number; note?: string } | { kind: "clamp"; max: number; note?: string } | { kind: "redirect"; target: string; note?: string } | { kind: "split"; parts: readonly PendingDamage[]; note?: string } | { kind: "defer"; note?: strin… — What an interceptor decides to do with the pending application it was handed. `split` parts continue at the NEXT interceptor (never re-entering the splitter), which is what keeps the pipeline bounded and recursion-free.
- `InterceptRecord` (interface): interface InterceptRecord — One row of provenance: which interceptor acted, what it decided, and the amount before/after it acted.
- `MAX_INTERCEPT_STEPS` (const): const MAX_INTERCEPT_STEPS: 256 — Upper bound on interceptor evaluations for a single resolution; guards against runaway `split`/`redirect` loops.
- `PendingDamage` (interface): interface PendingDamage — Ordered, inspectable damage-resolution interception (#931).
- `createAntiOneShotPolicy` (function): function createAntiOneShotPolicy(config: AntiOneShotConfig): AntiOneShotPolicy — Compose a reusable anti-one-shot / chip-guard clamp from caller data: while above `guardAboveFraction` a hit cannot drop the target below `leaveFraction`, and after such a save the target gets `recoverMs` of immunity. Below the guard fraction, lethal hits pass unchanged.
- `createDamageClamp` (function): function createDamageClamp(config: DamageClampConfig): DamageInterceptor — A stateless interceptor that caps any single application at `maxPerHit`.
- `createDamagePipeline` (function): function createDamagePipeline(initial?: readonly DamageInterceptor[]): DamagePipeline — Create a mutable damage interception chain that state transitions install into and remove from — e.g. add an invulnerability interceptor on phase enter and drop it on phase exit. Evaluation order is install order.
- `createImmunityWindow` (function): function createImmunityWindow(id = "immunity"): ImmunityWindow — A per-target immunity/invulnerability window as an ordinary damage policy — granted and cleared by state transitions (i-frames, phase invuln), rejecting damage while active. Deterministic (time is passed in) and serializable.
- `resolveDamage` (function): function resolveDamage(interceptors: readonly DamageInterceptor[], pending: PendingDamage, ctx: InterceptContext): DamageResolution — Run one pending damage application through an ordered interceptor list before lethality resolves, returning the final applications, any deferred ones, and full provenance. Pure and deterministic; bounded by `MAX_INTERCEPT_STEPS`.

## @jgengine/core/combat/damageMatchup

- `DamageChannelId` (type): type DamageChannelId = string — Caller-owned id for a damage channel — `"fire"`, `"ballistic"`, `"physical"`, `"corrosive"`. The engine never branches on the value; a channel is whatever a game's data declares.
- `DamageMatchup` (interface): interface DamageMatchup<TChannel extends string = DamageChannelId, TTrait extends string = TargetTraitId> — A serializable, data-defined matchup table: `channel → trait → outputs`. When a hit's channel meets a target carrying several traits, every matching entry's outputs multiply together, so axes compose independently (a trait can halve impact yet double status duration). `default` applies for a channel/trait pair the table does not mention.
- `MatchupContribution` (interface): interface MatchupContribution — One `(trait → outputs)` pair that contributed to a resolved matchup — provenance for UI/debug.
- `MatchupOutputs` (interface): interface MatchupOutputs — The independent, typed outputs a channel-vs-trait matchup can scale. Every field is an optional multiplier that defaults to `1` (identity), so a matchup entry names only the axes it bends. `impact` scales the direct hit, `applyChance` the odds a status lands, `magnitude` and `duration` the applied status itself, and `extra` carries any further caller-defined scalar (knockback, stagger, heat) the engine forwards without interpreting.
- `ResolvedMatchup` (interface): interface ResolvedMatchup — Fully-resolved matchup outputs (every axis populated) plus the contributions that produced them.
- `TargetTraitId` (type): type TargetTraitId = string — Caller-owned id for a target trait — `"armored"`, `"fleshy"`, `"wet"`, `"boss"`. Traits are the receiver-side facets a matchup scores a channel against.
- `resolveMatchup` (function): function resolveMatchup<TChannel extends string = DamageChannelId, TTrait extends string = TargetTraitId>(matchup: DamageMatchup<TChannel, TTrait>, channel: TChannel | string, targetTraits: readonly (TTrait | string)[]): ResolvedMatchup — Resolve a channel against a target's traits into independent, multiplied outputs. Pure and order-independent: every trait the channel has an entry for contributes, its axes multiplying into the running product; unmatched traits are skipped, and when nothing matches the table's `default` (or identity) is used. Bounded by the trait count — no world scan.

## @jgengine/core/combat/damageResolution

- `DamageHitInput` (interface): interface DamageHitInput — One data-defined damage hit: a channel, a base impact, the target's traits and carried statuses, and the caller-owned matchup/received/status data that shapes the outcome. Everything is serializable; the only non-data input is the injected `rng`, so authority can resolve a hit and replicate the returned instances.
- `DamageHitResolution` (interface): interface DamageHitResolution — The full, provenance-rich result of resolving a hit — every stage kept for UI and debugging. `impact` is the final number to drain; `matchup`, `received`, and `status` expose exactly how it got there. Authority applies `impact` (plus `received.redirects`/`conversions`) and the returned status `instance`; nothing here mutates game state.
- `resolveDamageHit` (function): function resolveDamageHit(input: DamageHitInput): DamageHitResolution — Resolve a full damage hit through the data-defined pipeline: score the channel against the target's traits ({@link resolveMatchup}), scale base impact by the matchup's `impact` axis, run receiver-side modifiers ({@link resolveReceivedDamage}), then roll status application scaled by the matchup's `applyChance`/`magnitude`/`duration` axes ({@link resolveStatusApplication}). Pure and deterministic given a seeded `rng`; returns full provenance and never mutates state, so it is safe to run on the authority and replicate the results.

## @jgengine/core/combat/damageRuntime

- `DamageRuntime` (interface): interface DamageRuntime — A damage model: registered targets, the table/zones/statuses they are hit with, and carried status state. `hit` resolves a blow, `tick` runs status effects, `timeToKill` quotes a fight, and `table` reads the whole chart. State is plain data, so a save, a replay, or a worker can move it.
- `DamageRuntimeConfig` (interface): interface DamageRuntimeConfig — Everything the model reads: the table, the zones, the status definitions, and the RNG.
- `DamageRuntimeHitInput` (interface): interface DamageRuntimeHitInput — One incoming hit: what struck, how hard, where it landed, and what statuses it carries.
- `DamageRuntimeResolution` (interface): interface DamageRuntimeResolution — Every stage of one resolved hit, so a UI or a test can read why the final number is what it is.
- `DamageRuntimeRetune` (interface): interface DamageRuntimeRetune — In-play dials, all retunable without discarding registered targets or carried statuses.
- `DamageRuntimeState` (interface): interface DamageRuntimeState — Serialized model state: registered targets, carried statuses, and the probe counters.
- `DamageStatusRequest` (interface): interface DamageStatusRequest — One status a hit tries to apply, scaled against that status's own base chance and values.
- `TargetProfile` (interface): interface TargetProfile — What a target presents to the table: one resistance class and its armor points.
- `TimeToKill` (interface): interface TimeToKill — A quoted time to kill for one fixed hit against one health pool.
- `UnknownTargetProfileError` (class): class UnknownTargetProfileError extends Error — Raised when a hit names a target that was never registered — a wiring error, not a 0-damage hit.
- `createDamageRuntime` (function): function createDamageRuntime(config: DamageRuntimeConfig): DamageRuntime — Build a damage model from data. The number a hit lands is `base × zone multiplier × type multiplier × (1 − armor mitigation)`; statuses tick through the same table and armor, so a burn on an armored target is mitigated like a bullet. Every application — a hit or a status tick — is announced as `combat.damage` carrying the target, source, type, amount, absorbed, remaining health and a lethal flag, so a HUD names the blow instead of guessing.

## @jgengine/core/combat/damageTable

- `ArmorConfig` (interface): interface ArmorConfig — The armor curve: `mitigation = armor / (armor + halfValue)`. Naming the half value instead of a percentage per point is what makes a generated gun's armor number readable — armor equal to `halfValue` halves the hit, and mitigation approaches the cap without ever reaching it.
- `DEFAULT_ARMOR_HALF_VALUE` (const): const DEFAULT_ARMOR_HALF_VALUE: 100 — Default armor points at which a hit is halved.
- `DEFAULT_MAX_MITIGATION` (const): const DEFAULT_MAX_MITIGATION: 0.9 — Default ceiling on armor mitigation, so armor never fully negates a hit.
- `DamageTableDef` (interface): interface DamageTableDef — A serializable damage table: damage types scored against resistance classes, plus the armor curve those rows are read with. It is data a generated gun (B3.1) and a weapon runtime (B2.3) pass in; the engine holds no built-in elemental chart.
- `DamageTableRow` (interface): interface DamageTableRow — One readable row: a type against a resistance class at a given armor value.
- `DamageTypeDef` (interface): interface DamageTypeDef — One damage type's row in a damage table: a caller-owned id (`"kinetic"`, `"fire"`) and how it fares against each resistance class a target can present (`"flesh"`, `"shield"`, `"armor"`). Values below `1` are resisted, `1` is neutral, above `1` is a weakness, and `0` is immune.
- `DuplicateDamageTypeError` (class): class DuplicateDamageTypeError extends Error — Raised when a table lists the same damage type twice, which would make the winner depend on order.
- `UnknownDamageTypeError` (class): class UnknownDamageTypeError extends Error — Raised when a hit names a damage type the table does not define, rather than silently dealing 1×.
- `armorMitigation` (function): function armorMitigation(armor: number, config?: ArmorConfig): number — Fraction of a hit that armor removes at `armor` points; `0` at zero armor, capped by config.
- `assertDamageTable` (function): function assertDamageTable(table: DamageTableDef): void — Validate a table once at construction: duplicate ids and non-finite multipliers fail loudly.
- `formatDamageTable` (function): function formatDamageTable(rows: readonly DamageTableRow[]): string[] — Render rows as fixed-width lines for a devtools probe, a CLI dump, or a test's diff.
- `readDamageTable` (function): function readDamageTable(table: DamageTableDef, read?: { base?: number; armor?: number | Readonly<Record<string, number>>; types?: readonly string[]; resistances?: readonly string[]; }): DamageTableRow[] — Read the whole table as rows — every listed type against every listed resistance class, each with the armor it was read at and the damage a base would land. This is the table a designer reads and a test asserts, so a resistance change is visible without running combat.
- `resolveTableDamage` (function): function resolveTableDamage(table: DamageTableDef, input: { type: string; resistance: string; armor?: number; base?: number }): DamageTableRow — Resolve one hit through the table: type multiplier, then armor mitigation, and the base scaled by both. Formula order matters only for the numbers a UI shows — the product is the same.
- `typeBypassesArmor` (function): function typeBypassesArmor(table: DamageTableDef, type: string): boolean — Whether armor points reduce this damage type.
- `typeMultiplier` (function): function typeMultiplier(table: DamageTableDef, type: string, resistance: string): number — The type × resistance multiplier for one class, before armor. An unknown type throws; an unknown resistance class uses the table's `defaultMultiplier`, since target classes may be narrower than the table's coverage.

## @jgengine/core/combat/death

- `DeathIdentity` (interface): interface DeathIdentity { catalogId: string; userId?: string; displayName?: string; position: [number, number, number] } — ⚠ undocumented
- `DeathReasonKind` (type): type DeathReasonKind = DeathReason["kind"] — ⚠ undocumented
- `DeathResolution` (type): type DeathResolution = | { status: "resolved"; drops: Drop[]; ranCommand: string | null } | { status: "rejected"; reason: string } — ⚠ undocumented
- `DeathSystem` (interface): interface DeathSystem { resolveDeath(instanceId: string, reason: DeathReason): DeathResolution; revive(instanceId: string): boolean } — ⚠ undocumented · used by `createDeathSystem`: Resolve entity death and the on-death consequences — drops, respawn eligibility, kill credit.
- `DeathSystemDeps` (interface): interface DeathSystemDeps { resolveOnDeath(instanceId: string, reason?: DeathReason): OnDeathSpec | null | undefined; resolveIdentity(instanceId: string): DeathIdentity | null; loot: {roll(tableId: string): Drop[]}; events: GameEvents; runCommand?(name: string, args… — ⚠ undocumented · used by `createDeathSystem`: Resolve entity death and the on-death consequences — drops, respawn eligibility, kill credit.
- `DropMode` (type): type DropMode = "grant" | "world" — ⚠ undocumented
- `EffectDeathContext` (interface): interface EffectDeathContext { from: string; via?: EffectVia; userIdOf?(instanceId: string): string | undefined } — ⚠ undocumented
- `NormalizedOnDeath` (interface): interface NormalizedOnDeath { drops: OnDeathDropRule[]; command: OnDeathCommandRule | null; dropMode: DropMode; scatter?: ScatterOptions } — ⚠ undocumented
- `OnDeathCommandRule` (interface): interface OnDeathCommandRule { name: string; args?: unknown; when?: {reason: DeathReasonKind} } — ⚠ undocumented
- `OnDeathDropRule` (interface): interface OnDeathDropRule { table: string; when?: {reason: DeathReasonKind | "any"} } — ⚠ undocumented
- `OnDeathSpec` (interface): interface OnDeathSpec — Catalog `onDeath` for an entity: loot tables to roll, `dropMode: "world"` to scatter drops on the ground (rendered with loot beams) instead of granting them into the killer's bag, and commands to run. Fires only when the entity dies through `ctx.scene.entity.effect`, not a raw `stats.delta`.
- `createDeathSystem` (function): function createDeathSystem(deps: DeathSystemDeps): DeathSystem — Resolve entity death and the on-death consequences — drops, respawn eligibility, kill credit.
- `deathReasonFromEffect` (function): function deathReasonFromEffect(ctx: EffectDeathContext): DeathReason — ⚠ undocumented
- `normalizeOnDeath` (function): function normalizeOnDeath(spec: OnDeathSpec | null | undefined): NormalizedOnDeath — ⚠ undocumented

## @jgengine/core/combat/deathReason

- `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.

## @jgengine/core/combat/defensiveWindow

- `DefenseKind` (type): type DefenseKind = "parry" | "block" | "dodge" — ⚠ undocumented
- `DefenseOutcome` (type): type DefenseOutcome = "parry" | "block" | "iframe" | "hit" — ⚠ undocumented
- `DefenseResolution` (interface): interface DefenseResolution — Result of resolving an incoming hit against a defensive window: `outcome` is the graded defense (`"parry"`/`"block"`/`"iframe"`/`"hit"`) and `perfect` is true when the input landed inside the tight just-frame at the window's start rather than its wider active span.
- `DefensiveWindow` (interface): interface DefensiveWindow { open(nowMs: number): void; close(): void; isOpen(nowMs: number): boolean; evaluate(nowMs: number, attack: AttackMeta): DefenseResolution; isInvulnerable(nowMs: number): boolean } — ⚠ undocumented · used by `createDefensiveWindow`: Open a timed defensive window — block, parry, or i-frames — and test incoming hits against it.
- `DefensiveWindowConfig` (interface): interface DefensiveWindowConfig { kind: DefenseKind; startupMs?: number; activeMs: number; recoveryMs?: number; iframes?: {fromMs: number; toMs: number} } — ⚠ undocumented · used by `createDefensiveWindow`: Open a timed defensive window — block, parry, or i-frames — and test incoming hits against it.
- `ResolveDefenseInput` (interface): interface ResolveDefenseInput { config: DefensiveWindowConfig; elapsedMs: number; attack: AttackMeta } — ⚠ undocumented
- `createDefensiveWindow` (function): function createDefensiveWindow(config: DefensiveWindowConfig): DefensiveWindow — Open a timed defensive window — block, parry, or i-frames — and test incoming hits against it.
- `iframeActiveAt` (function): function iframeActiveAt(config: DefensiveWindowConfig, elapsedMs: number): boolean — ⚠ undocumented
- `resolveDefense` (function): function resolveDefense(input: ResolveDefenseInput): DefenseResolution — ⚠ undocumented
- `totalWindowMs` (function): function totalWindowMs(config: DefensiveWindowConfig): number — ⚠ undocumented
- `windowActiveAt` (function): function windowActiveAt(config: DefensiveWindowConfig, elapsedMs: number): boolean — ⚠ undocumented

## @jgengine/core/combat/dotField

- `DotField` (interface): interface DotField — A pool of timed damage-over-time instances keyed by string (`bleed`, `poison`, `burn`) — the recurring-damage counterpart to `breakMeters`' one-shot buildup procs (#536.4). `tick` advances every active DoT and returns the damage due this frame, one entry per interval crossed, so the game routes each through its own effect pipeline; a pure scheduler that never applies damage itself.
- `DotSpec` (interface): interface DotSpec — A single damage-over-time instance: how hard, how often, and for how long.
- `DotTick` (interface): interface DotTick — One damage event (or expiry marker) emitted by `DotField.tick` for the game to route through its effects.
- `createDotField` (function): function createDotField(): DotField — Builds an empty {@link DotField}; `apply` DoTs onto it and drain damage each frame with `tick`.

## @jgengine/core/combat/downed

- `DownedConfig` (interface): interface DownedConfig { bleedoutSeconds: number; reviveSeconds?: number; reviveHealthFraction?: number; banner?: {expireSeconds: number} } — ⚠ undocumented · used by `createDownedState`: A downed/bleed-out state that ticks toward death and that teammates can revive before the timer runs out.
- `DownedEntry` (interface): interface DownedEntry { phase: DownedPhase; bleedoutRemaining: number; reviveProgress: number; bannerRemaining: number | null } — ⚠ undocumented
- `DownedEvent` (interface): interface DownedEvent { kind: DownedEventKind; instanceId: string; reason?: string; reviveHealthFraction?: number } — ⚠ undocumented
- `DownedEventKind` (type): type DownedEventKind = | "downed" | "revived" | "reviving" | "died" | "banner.created" | "banner.expired" | "respawned" — ⚠ undocumented
- `DownedPhase` (type): type DownedPhase = "alive" | "downed" | "dead" — ⚠ undocumented
- `DownedState` (interface): interface DownedState { down(instanceId: string): DownedEvent | null; revive(instanceId: string, dt: number): DownedEvent | null; interruptRevive(instanceId: string): void; finish(instanceId: string, reason?: string): DownedEvent | null; tick(dt: number): Downed… — ⚠ undocumented · used by `createDownedState`: A downed/bleed-out state that ticks toward death and that teammates can revive before the timer runs out.
- `createDownedState` (function): function createDownedState(config: DownedConfig): DownedState — A downed/bleed-out state that ticks toward death and that teammates can revive before the timer runs out.

## @jgengine/core/combat/effects

- `AppliedPoolDelta` (interface): interface AppliedPoolDelta { statId: string; delta: number } — ⚠ undocumented
- `AreaEffectInput` (interface): interface AreaEffectInput { from: string; effect: string; via?: EffectVia; at: EntityPosition; radius: number; falloff?: "linear" | "none"; los?: boolean } — ⚠ undocumented
- `AreaTarget` (interface): interface AreaTarget { instanceId: string; scale: number } — ⚠ undocumented
- `AreaTargetInput` (interface): interface AreaTargetInput { at: EntityPosition; radius: number; falloff?: "linear" | "none"; los?: boolean } — ⚠ undocumented
- `CombatSpatialDeps` (interface): interface CombatSpatialDeps { inRadius(center: EntityPosition, radius: number): string[]; hasLineOfSight(from: EntityPosition | string, to: string): boolean; positionOf(instanceId: string): EntityPosition | undefined } — ⚠ undocumented
- `EffectDamageApplication` (interface): interface EffectDamageApplication — One effect application that drained a target's pools, as an announcer needs it. The effect path has no damage table, so the caller names the channel (`effect`) and reads health its own way.
- `EffectInput` (type): type EffectInput = SingleTargetEffectInput | AreaEffectInput — ⚠ undocumented
- `EffectResult` (interface): interface EffectResult { instanceId: string; effect: string; applied: AppliedPoolDelta[]; lethal: boolean; slain?: SlainIdentity } — ⚠ undocumented
- `EffectSystem` (interface): interface EffectSystem { canReceive(instanceId: string, effect: string, magnitude?: number): string | null; preview(input: SingleTargetEffectInput): number; applyEffect(input: EffectInput): EffectResult[] } — ⚠ undocumented · used by `createEffectSystem`: Resolve direct or area resource effects through caller-owned stat pools, including ordered absorption, restoration, modifiers, and lethal co…
- `EffectSystemDeps` (interface): interface EffectSystemDeps { resolveReceive(instanceId: string): ReceiveMap | null | undefined; statPools?: StatPoolAccess; resolveStats?(instanceId: string): Record<string, StatPool> | undefined; getStat(itemId: string, stat: string): number | null; spatial: CombatS… — ⚠ undocumented · used by `createEffectSystem`: Resolve direct or area resource effects through caller-owned stat pools, including ordered absorption, restoration, modifiers, and lethal co…
- `EffectVia` (interface): interface EffectVia { item?: string; amount?: number } — ⚠ undocumented
- `LethalContext` (interface): interface LethalContext { from: string; via?: EffectVia; effect: string } — ⚠ undocumented
- `ReceiveMap` (type): type ReceiveMap = Record<string, ReceiveRule> — ⚠ undocumented
- `ReceiveRule` (interface): interface ReceiveRule { order: string[]; modifiers?: Record<string, number> } — ⚠ undocumented
- `SingleTargetEffectInput` (interface): interface SingleTargetEffectInput { from: string; to: string; effect: string; via?: EffectVia } — ⚠ undocumented
- `SlainIdentity` (interface): interface SlainIdentity — Identity of an entity slain by a lethal effect, captured before the death system despawns it. Serializable and genre-agnostic: `catalogId` is the slain entity's spawn kind/name (the same value the `entity.died` event carries), `name` an optional human-readable label for kill feeds, and `userId` the owning player when the slain unit was player-controlled. The slain entity's instance id is already {@link EffectResult.instanceId}.
- `createEffectSystem` (function): function createEffectSystem(deps: EffectSystemDeps): EffectSystem — Resolve direct or area resource effects through caller-owned stat pools, including ordered absorption, restoration, modifiers, and lethal context.
- `resolveAreaTargets` (function): function resolveAreaTargets(spatial: CombatSpatialDeps, input: AreaTargetInput, accept?: (instanceId: string) => boolean): AreaTarget[] — ⚠ undocumented

## @jgengine/core/combat/encounterSequence

- `BUILTIN_COMPLETION_PREDICATES` (const): const BUILTIN_COMPLETION_PREDICATES: Readonly<Record<string, CompletionPredicate>> — Built-in completion predicates covering the common encounter gates: `immediate` (leaf marker), `manual`/`flag` (external event via a caller flag), `timer` (phase seconds), `cleared` (tagged entity count drained), `metric` (threshold on a live value), `event` (cumulative event count), and `quorum` (at least N of nested predicates met). Merge your own over these through {@link EncounterConfig.predicates}.
- `BUILTIN_SPAWN_PROVIDERS` (const): const BUILTIN_SPAWN_PROVIDERS: Readonly<Record<string, SpawnProvider>> — Built-in spawn providers. `points` reads a named authored scene point list from context and cycles it to emit `count` requests, keeping coordinates in the scene rather than the sequence. `list` echoes literal requests authored in `params.requests`. Merge your own catalog- or director-backed providers through {@link EncounterConfig.spawnProviders}.
- `CompletionPredicate` (type): type CompletionPredicate = ( params: Readonly<Record<string, unknown>>, ctx: PredicateContext, ) => boolean — A completion predicate: pure and deterministic, returns true when the node it gates is finished. Registered under a `kind` and reused across phases with different `params`.
- `EncounterConfig` (interface): interface EncounterConfig<TData = unknown> — Non-serializable configuration for an encounter: the authored phase tree plus predicate and spawn-provider registries. Re-supplied alongside a loaded {@link EncounterState}, the way `advanceSpawnDirector` pairs config with state, so the state itself stays pure data.
- `EncounterContext` (interface): interface EncounterContext — Context passed to {@link startEncounter} / {@link updateEncounter}: the caller signals predicates evaluate against, plus named `spawnPoints` catalogs (authored in the scene, referenced by key) that spawn providers place against. Never holds coordinates the sequence itself owns.
- `EncounterEvent` (type): type EncounterEvent = | { type: "enter"; phaseId: string; iteration: number } | { type: "spawn"; phaseId: string; provider: string; requests: readonly EncounterSpawnRequest[] } | { type: "complete"; phaseId: string; iteration: number; reason: string } | { type: "done" } — A lifecycle event emitted while stepping an encounter, carrying provenance.
- `EncounterPhase` (interface): interface EncounterPhase<TData = unknown> — One node in an encounter sequence tree. `data` is caller-owned and opaque to the core. A node with `children` is a group whose children run in order; a node without is a leaf. `completion` gates when the node finishes, `spawn` names an on-enter provider, and `repeat` re-runs the node's subtree that many extra times before advancing.
- `EncounterSignals` (interface): interface EncounterSignals — Caller-supplied signals a completion predicate reads. Every field is optional and opaque to the core: `counts` of tagged live entities, continuous `metrics`, cumulative `events`, and boolean `flags`. Deterministic given the same values.
- `EncounterSpawnRequest` (interface): interface EncounterSpawnRequest — A single spawn request a provider emits; `ref` is caller-defined, `point` optional.
- `EncounterState` (interface): interface EncounterState<TData = unknown> — Full serializable encounter state: the working phase tree (including any injected phases), a per-node runtime map, the active path from root to the deepest open node, accumulated time, and whether the sequence has finished. Round-trips through JSON with no behavioral change; the registries live in {@link EncounterConfig}, not here.
- `EncounterStep` (interface): interface EncounterStep<TData = unknown> — Result of a step: the (mutated, returned) state and the events emitted this step.
- `PhaseCompletionRef` (interface): interface PhaseCompletionRef — Reference to a registered completion predicate: a `kind` naming the evaluator plus opaque `params` the evaluator reads. The sequence core never interprets `params`; the predicate registered under `kind` does.
- `PhaseInjectAt` (type): type PhaseInjectAt = | { before: string } | { after: string } | { childOf: string; index?: number } — Where to insert an injected phase, relative to an existing node by id.
- `PhaseRuntime` (interface): interface PhaseRuntime — Per-node runtime record. Serializable — holds no functions or tree references.
- `PhaseSpawnRef` (interface): interface PhaseSpawnRef — Reference to a registered spawn provider invoked when a phase is entered: a `kind` naming the provider plus opaque `params`. Spawning is one optional node adapter — a phase without `spawn` simply emits no spawn requests.
- `PhaseStatus` (type): type PhaseStatus = "pending" | "active" | "complete" — Lifecycle status of one phase in an encounter sequence: waiting to run, currently running, or finished. Groups and leaves share the same three states.
- `PredicateContext` (interface): interface PredicateContext — Evaluation context a completion predicate receives for the node under test.
- `SpawnProvider` (type): type SpawnProvider = ( params: Readonly<Record<string, unknown>>, ctx: SpawnProviderContext, ) => readonly EncounterSpawnRequest[] — A spawn provider: given the phase's `params` and context, returns the spawn requests to emit on enter. Deterministic; reads authored scene points from `ctx.spawnPoints` rather than embedding coordinates.
- `SpawnProviderContext` (interface): interface SpawnProviderContext — Evaluation context a spawn provider receives when its phase is entered.
- `activePhaseId` (function): function activePhaseId<TData>(state: EncounterState<TData>): string | null — The deepest active phase id — the completion cursor a HUD reads to label the current wave/phase — or null before start and once done.
- `createEncounterState` (function): function createEncounterState<TData>(config: EncounterConfig<TData>): EncounterState<TData> — Build the initial, serializable state for an encounter from its config. Deep-copies the authored phase tree (so later injection never mutates the config), verifies phase ids are unique, and leaves every node pending. Does not enter the first phase — call {@link startEncounter} for that.
- `encounterProgress` (function): function encounterProgress<TData>(state: EncounterState<TData>): { completed: number; total: number; done: boolean; } — Progress across the whole tree: how many phases have completed out of the total node count, plus whether the encounter has finished. Counts injected phases.
- `forceCompletePhase` (function): function forceCompletePhase<TData>(config: EncounterConfig<TData>, state: EncounterState<TData>, ctx: EncounterContext = {}, phaseId?: string): EncounterStep<TData> — Force the deepest active phase (or a named active phase) to complete now, regardless of its predicate — the escape hatch for external/scripted completion and failure/retry flows. Advances into the next phase and emits the same lifecycle events as a natural completion. Returns no events if the phase is not currently active. Mutates and returns `state`.
- `injectPhase` (function): function injectPhase<TData>(state: EncounterState<TData>, phase: EncounterPhase<TData>, at: PhaseInjectAt): EncounterState<TData> — Insert a phase into the working tree at runtime — before/after a sibling, or as a child of a group — without disturbing already-completed or active nodes. The injected subtree becomes part of the serializable state (so a mid-encounter save preserves it) and is reached in normal order if it sits ahead of the cursor. Ids must stay tree-unique. Mutates and returns `state`.
- `phaseStatus` (function): function phaseStatus<TData>(state: EncounterState<TData>, id: string): PhaseStatus | null — The runtime status of a phase by id (pending/active/complete), or null if the id is unknown — for driving per-phase HUD ticks and objective checklists.
- `startEncounter` (function): function startEncounter<TData>(config: EncounterConfig<TData>, state: EncounterState<TData>, ctx: EncounterContext = {}): EncounterStep<TData> — Start a created encounter: enter the first root phase, descending to its first leaf, and return the initial enter/spawn events. A no-op (with no events) on an already-started or empty encounter. Mutates and returns `state`.
- `updateEncounter` (function): function updateEncounter<TData>(config: EncounterConfig<TData>, state: EncounterState<TData>, dt: number, ctx: EncounterContext = {}): EncounterStep<TData> — Advance an encounter by `dt` seconds against the caller `ctx`. Accumulates time, then repeatedly: evaluates the cursor node's completion predicate; on completion, either re-runs its subtree (`repeat`) or marks it complete and advances to the next sibling — bubbling up to parent groups whose children are exhausted — entering the next chain and emitting enter/spawn/complete events. Emits a final `done` event when the last phase completes. Bounded per call by node count; mutates and returns `state`.

## @jgengine/core/combat/hitReaction

- `CameraShake` (interface): interface CameraShake { amplitude: number; decay: number } — ⚠ undocumented
- `HitReaction` (interface): interface HitReaction { hitstopMs: number; impulse: [number, number, number]; shake: CameraShake | null; trauma: number | null; timescale: number | null } — ⚠ undocumented · used by `resolveHitReaction`: Resolves hit feel (hitstop, knockback impulse, camera shake) from either a named `impactPresets` event (`resolveHitReaction("explosion", inp…
- `HitReactionConfig` (interface): interface HitReactionConfig { hitstopMs: number; knockback: number; vertical?: number; shake?: CameraShake; trauma?: number; timescale?: number } — ⚠ undocumented · used by `resolveHitReaction`: Resolves hit feel (hitstop, knockback impulse, camera shake) from either a named `impactPresets` event (`resolveHitReaction("explosion", inp…
- `HitReactionInput` (interface): interface HitReactionInput { attackerPos: EntityPosition; targetPos: EntityPosition; power?: number } — ⚠ undocumented · used by `resolveHitReaction`: Resolves hit feel (hitstop, knockback impulse, camera shake) from either a named `impactPresets` event (`resolveHitReaction("explosion", inp…
- `ImpactPreset` (interface): interface ImpactPreset — A calibrated `resolveHitReaction` config for a named impact event — hitstop + trauma so feel works with zero tuning.
- `ImpactPresetName` (type): type ImpactPresetName = keyof typeof impactPresets — A named key into {@link impactPresets} (`"pickup" | "jumpLand" | "enemyKilled" | "playerHit" | "explosion"`).
- `applyImpulse` (function): function applyImpulse(position: EntityPosition, impulse: [number, number, number]): EntityPosition — ⚠ undocumented
- `impactPresets` (const): const impactPresets: { readonly pickup: { readonly hitstopMs: 0; readonly trauma: 0.15; }; readonly jumpLand: { readonly hitstopMs: 0; readonly trauma: 0.2; }; readonly enemyKilled: { readonly hitstopMs: 40; readonly trauma: 0.3; }; readonly playerHit: { readonly hitstopMs: 70; readonly trauma: 0.4;… — Calibrated per-event impact feel — hitstop and trauma numbers harvested from a shipped game-feel reference, not hand-invented per game. `explosion` and `playerHit` are "heavy hit" events (60–90ms hitstop @ 0.05 timescale); `pickup`/`jumpLand` are light events with no hitstop. Trauma is later clamped to 1.0 by `resolveHitReaction`.
- `resolveHitReaction` (function): function resolveHitReaction(config: HitReactionConfig | ImpactPresetName, input: HitReactionInput): HitReaction — Resolves hit feel (hitstop, knockback impulse, camera shake) from either a named `impactPresets` event (`resolveHitReaction("explosion", input)`) or a raw `HitReactionConfig` override.

## @jgengine/core/combat/hitZones

- `DEFAULT_CRIT_MULTIPLIER` (const): const DEFAULT_CRIT_MULTIPLIER: 2 — Default crit multiplier for a zone that does not name one.
- `HitZoneDef` (interface): interface HitZoneDef — One hit zone: what a hit there multiplies, and how much likelier it is to crit.
- `HitZoneResolution` (interface): interface HitZoneResolution — One resolved zone: where the hit landed, whether it crit, and the single multiplier to apply.
- `HitZoneTable` (interface): interface HitZoneTable — A serializable hit-zone table: where a hit landed, what that multiplies, and the table's base crit chance and multiplier. A generated gun or a weapon runtime passes its own zones in; the engine has no built-in headshot.
- `UnknownHitZoneError` (class): class UnknownHitZoneError extends Error — Raised when neither the named zone nor the table's `defaultZone` exists — a data error, not a 1× hit.
- `assertHitZoneTable` (function): function assertHitZoneTable(table: HitZoneTable): void — Validate a zone table once at construction: duplicate ids and a missing default fail loudly.
- `hitZoneMultiplier` (function): function hitZoneMultiplier(table: HitZoneTable, zone: string | undefined, crit: boolean): { zone: string; multiplier: number; fallback: boolean } — The multiplier a zone earns for a known crit outcome, without rolling. `resolveHitZone` and a time-to-kill quote both read through this, so a quoted crit uses the same number combat does.
- `resolveHitZone` (function): function resolveHitZone(table: HitZoneTable, zone: string | undefined, rng?: () => number): HitZoneResolution — Resolve where a hit landed into one multiplier: roll the crit chance for that zone, and apply the crit multiplier when it lands, otherwise the zone's own multiplier. The injected `rng` keeps the roll reproducible; a zero chance draws nothing, so a deterministic test can force either outcome.

## @jgengine/core/combat/magazine

- `Magazine` (interface): interface Magazine — A per-weapon magazine: discrete loaded rounds, a timed reload that refills from a reserve pool, and the reserve-pool interaction itself — the primitive that replaces hand-rolling mag size, reload delay, and reserve bookkeeping per game (#536.2).
- `MagazineConfig` (interface): interface MagazineConfig — Tuning for `createMagazine`: mag capacity, reload delay, and where reserve ammo is drawn from.
- `MagazineReserve` (interface): interface MagazineReserve — Draws ammo for a `Magazine`'s reload from wherever the reserve pool actually lives.
- `MagazineSnapshot` (interface): interface MagazineSnapshot — Complete serializable state for a {@link Magazine}; `reserve: null` means infinite reserve.
- `MagazineTuning` (interface): interface MagazineTuning — Live magazine tuning; shrinking below loaded rounds rejects unless overflow is explicit.
- `createMagazine` (function): function createMagazine(config: MagazineConfig): Magazine — Builds a {@link Magazine}: discrete loaded ammo, a timed reload, and reserve-pool interaction.

## @jgengine/core/combat/projectiles

- `EntityRaycastHit` (interface): interface EntityRaycastHit { kind: "entity"; instanceId: string; distance: number; at: EntityPosition; colliderName?: string; damageEligible?: boolean; blocks?: boolean } — ⚠ undocumented
- `LiveProjectile` (interface): interface LiveProjectile — Detached pose of one active projectile pellet for presentation.
- `ObjectRaycastHit` (interface): interface ObjectRaycastHit { kind: "object"; instanceId: string; catalogId: string; distance: number; at: EntityPosition; colliderName?: string; damageEligible?: boolean; blocks?: boolean } — ⚠ undocumented
- `ProjectileFlightState` (interface): interface ProjectileFlightState — Serializable motion state of one projectile pellet.
- `ProjectileHit` (type): type ProjectileHit = | { kind: "entity"; instanceId: string; distance: number; colliderName?: string; damageEligible?: boolean; } | { kind: "object"; instanceId: string; catalogId: string; distance: number; colliderName?: string; damageEligible?: boolean; } — ⚠ undocumented
- `ProjectileObjectsDeps` (interface): interface ProjectileObjectsDeps { list(): readonly {instanceId: string; catalogId: string; position: readonly [number, number, number]; rotationY?: number;}[]; inBox?(min: EntityPosition, max: EntityPosition): readonly {instanceId: string; catalogId: string; position: rea… — ⚠ undocumented
- `ProjectilePrediction` (interface): interface ProjectilePrediction { hits: ProjectileHit[]; blocked?: boolean; origin?: EntityPosition; direction?: EntityPosition; firstImpact?: ProjectileHit | null } — ⚠ undocumented
- `ProjectileSettleReport` (interface): interface ProjectileSettleReport — Exactly-once settlement with launch identity and actual applied effects.
- `ProjectileShotInput` (interface): interface ProjectileShotInput { from: string; via: EffectVia; aim: Aim; effect: string; originPolicy?: ShotOriginPolicy; travel?: ProjectileTravelConfig } — ⚠ undocumented
- `ProjectileShotState` (interface): interface ProjectileShotState — Serializable captured launch and settlement state.
- `ProjectileSystem` (interface): interface ProjectileSystem { willHitProjectile(input: ProjectileShotInput): ProjectilePrediction; fireProjectile(input: ProjectileShotInput): string; settleProjectile(shotId: string): SettleResult; advanceProjectiles(dt: number, time: number): SettleResult[]; activeP… — ⚠ undocumented · used by `createProjectileSystem`: Spawn and advance projectiles each frame, resolving travel, lifetime, and hits.
- `ProjectileSystemDeps` (interface): interface ProjectileSystemDeps { effects: EffectSystem; spatial: CombatSpatialDeps; getStat(itemId: string, stat: string): number | null; raycast?: Raycast; sceneRaycast?: SceneRaycastApi; objects?: ProjectileObjectsDeps; entityCollidersOf?(instanceId: string): EntityCol… — ⚠ undocumented · used by `createProjectileSystem`: Spawn and advance projectiles each frame, resolving travel, lifetime, and hits.
- `ProjectileSystemState` (interface): interface ProjectileSystemState — Detached projectile owner state for replay and restore.
- `ProjectileTravelConfig` (interface): interface ProjectileTravelConfig — Captured launch settings for authoritative live travel.
- `ProjectileTravelDeps` (interface): interface ProjectileTravelDeps — Authoritative clock, collision and environmental acceleration providers.
- `ProjectileTravelImpact` (interface): interface ProjectileTravelImpact — Nearest contact returned by a live segment sweep.
- `Raycast` (type): type Raycast = (from: string, aim: Aim, range: number, originPolicy?: ShotOriginPolicy) => RaycastHit[] — ⚠ undocumented
- `RaycastHit` (type): type RaycastHit = EntityRaycastHit | ObjectRaycastHit — ⚠ undocumented
- `SettleResult` (type): type SettleResult = | { status: "settled"; shotId: string; at: [number, number, number]; hits: EffectResult[]; origin?: [number, number, number]; } | { status: "rejected"; shotId: string; reason: string } — ⚠ undocumented
- `createProjectileSystem` (function): function createProjectileSystem(deps: ProjectileSystemDeps): ProjectileSystem — Spawn and advance projectiles each frame, resolving travel, lifetime, and hits.

## @jgengine/core/combat/receivedDamage

- `DamageContext` (interface): interface DamageContext — The facts a received-damage modifier predicates over: the incoming `channel`, who dealt it, the statuses the target currently carries, and any caller tags. All caller-owned strings; the engine never assigns meaning to a channel, source, status, or tag.
- `DamageDivert` (interface): interface DamageDivert — A portion of the hit sent elsewhere by a `redirect`/`convert` policy.
- `DamagePredicate` (interface): interface DamagePredicate — A typed predicate over a {@link DamageContext}. Every listed facet must match (AND); a facet matches when the context value is in the list (channels/sources) or shares any member (targetStatuses/tags). An empty predicate matches every hit.
- `ReceivedDamageInput` (interface): interface ReceivedDamageInput — The incoming amount, its {@link DamageContext}, and the receiver's modifier list to run over it.
- `ReceivedDamageResult` (interface): interface ReceivedDamageResult — The full, provenance-rich outcome of running received modifiers over one hit.
- `ReceivedModifier` (interface): interface ReceivedModifier — One serializable receiver-side rule: an optional predicate, a policy, and an ordering key.
- `ReceivedPolicy` (type): type ReceivedPolicy = | { kind: "scale"; factor: number } | { kind: "flat"; delta: number } | { kind: "cap"; max: number } | { kind: "floor"; min: number } | { kind: "convert"; toChannel: DamageChannelId; portion?: number } | { kind: "redirect"; toTarget: string; portion?: number } | { kind: "immune… — What a matched modifier does to the incoming amount. Amplification is one policy beside reduction — both are `scale` (factor `> 1` amplifies, `< 1` reduces). `cap`/`floor` clamp, `flat` adds/subtracts, `convert` moves a portion to another channel on the same target, `redirect` moves a portion to another target, and `immune` zeroes the hit outright.
- `ReceivedStep` (interface): interface ReceivedStep — One recorded transformation — the provenance a UI or debugger reads to explain a final number.
- `resolveReceivedDamage` (function): function resolveReceivedDamage(input: ReceivedDamageInput): ReceivedDamageResult — Run receiver-side modifiers over an incoming hit, in ascending `order`, recording every step. Amplification, reduction, caps, conversion, redirection, and immunity are all data — the engine applies whichever policies the target's modifiers declare and never branches on channel names. Pure over serializable data with bounded work (one pass over the modifier list); an `immune` policy short-circuits the remaining modifiers.

## @jgengine/core/combat/regenShield

- `RegenShield` (interface): interface RegenShield — A shield pool that stops regenerating for `regenDelayMs` after every hit, then refills at `regenPerSecond` — the delayed-regen primitive that replaces snapshot-comparing stat values per tick to detect "damage taken" (#536.3). `damage` resets the grace timer; `tick` counts it down and regenerates once it elapses.
- `RegenShieldConfig` (interface): interface RegenShieldConfig — Tuning for `createRegenShield`: pool size, refill rate, and the post-damage grace period.
- `RegenShieldPool` (interface): interface RegenShieldPool — External storage a {@link RegenShield} reads and writes instead of keeping the value itself — an entity stat, a replicated store, a save record. This is the same port `Magazine` exposes as `MagazineReserve`, and it exists for the same reason: in most games the shield value is already owned by the stat system that damage, the HUD, and replication all read, so a primitive that insists on owning the number privately cannot be adopted without creating a second source of truth.
- `RegenShieldRates` (interface): interface RegenShieldRates — Per-tick rate overrides, for games that derive regen from live state — a talent tree, a buff, an equipped mod — rather than a constant fixed when the shield was built. Omit to use the configured values; the grace period in effect is whichever `regenDelayMs` was last passed to `tick`.
- `RegenShieldState` (interface): interface RegenShieldState — Complete mutable shield state, including pending external damage detection.
- `createRegenShield` (function): function createRegenShield(config: RegenShieldConfig): RegenShield — Builds a {@link RegenShield} that suppresses regen for `regenDelayMs` after each hit.

## @jgengine/core/combat/renderCues

- `DEFAULT_CYCLES_PER_UNIT` (const): const DEFAULT_CYCLES_PER_UNIT: 0.6 — Default `RenderCueTuning.cyclesPerUnit`.
- `DEFAULT_FIRE_PULSE_SECONDS` (const): const DEFAULT_FIRE_PULSE_SECONDS: 0.12 — Default `RenderCueTuning.firePulseSeconds`.
- `DEFAULT_HIT_PULSE_SECONDS` (const): const DEFAULT_HIT_PULSE_SECONDS: 0.2 — Default `RenderCueTuning.hitPulseSeconds`.
- `DEFAULT_RECOIL_DECAY_PER_SECOND` (const): const DEFAULT_RECOIL_DECAY_PER_SECOND: 6 — Default `RenderCueTuning.recoilDecayPerSecond`.
- `DEFAULT_RENDER_CUES` (const): const DEFAULT_RENDER_CUES: Readonly<EntityRenderCues> — Neutral starting cue set: idle, unarmed, undamaged.
- `EntityRenderCues` (interface): interface EntityRenderCues — Per-entity render cues: the motion/animation signal a custom `renderEntity` or first-person viewmodel component needs to drive gait, muzzle flash, reload poses, and hit reactions — without diffing the parent group's position itself or reading a game-side module map for attack timing.
- `RenderCueTuning` (interface): interface RenderCueTuning — Tuning knobs for `advanceMotionCues` / `useEntityRenderCues`; every field has a default, override only what a weapon/rig's feel needs to differ.
- `advanceMotionCues` (function): function advanceMotionCues(cues: EntityRenderCues, speed: number, dt: number, tuning?: RenderCueTuning): EntityRenderCues — Advances `bobPhase` and decays `recoil` from a live `speed` sample (e.g. `groundSpeed(entity)`); leaves event-driven fields untouched.
- `applyRenderAnimationEvent` (function): function applyRenderAnimationEvent(cues: EntityRenderCues, event: string): EntityRenderCues — Applies a `entity.animation` event (`"fire"` / `"reload"` / `"reloadEnd"`, or any game-defined name) to the cue set. Unknown event names are a no-op.
- `applyRenderDeathEvent` (function): function applyRenderDeathEvent(cues: EntityRenderCues): EntityRenderCues — Marks the cue set dead after `entity.died`; sticky for the lifetime of the render component.
- `applyRenderHitEvent` (function): function applyRenderHitEvent(cues: EntityRenderCues): EntityRenderCues — Marks a `combat.hitReaction` pulse; the caller clears `hit` again after its own pulse window.

## @jgengine/core/combat/resistance

- `ResistVerdict` (type): type ResistVerdict = "immune" | "resist" | "normal" | "vulnerable" — ⚠ undocumented
- `ResistanceMatrix` (interface): interface ResistanceMatrix<TCategory extends string = string, TProperty extends string = string> { categories: Partial<Record<TCategory, Partial<Record<TProperty, ResistVerdict>>>>; categoryIds?: readonly TCategory[]; propertyIds?: readonly TProperty[]; multipliers?: Partial<Record<ResistVerdict, number>>; default?: ResistVerdict; unkn… — ⚠ undocumented
- `ResistanceResult` (interface): interface ResistanceResult { verdict: ResistVerdict; multiplier: number; immune: boolean } — ⚠ undocumented
- `UnknownResistanceCategoryError` (class): class UnknownResistanceCategoryError extends Error — ⚠ undocumented
- `UnknownResistancePropertyError` (class): class UnknownResistancePropertyError extends Error — ⚠ undocumented
- `resistanceScale` (function): function resistanceScale<TCategory extends string = string, TProperty extends string = string>(matrix: ResistanceMatrix<TCategory, TProperty>, category: TCategory | string, targetProperties: readonly (TProperty | string)[]): number — ⚠ undocumented
- `resolveResistance` (function): function resolveResistance<TCategory extends string = string, TProperty extends string = string>(matrix: ResistanceMatrix<TCategory, TProperty>, category: TCategory | string, targetProperties: readonly (TProperty | string)[]): ResistanceResult — ⚠ undocumented

## @jgengine/core/combat/resourcePool

- `ResourcePool` (interface): interface ResourcePool { current(): number; max(): number; setMax(value: number): void; fraction(): number; canSpend(amount: number): boolean; spend(amount: number): boolean; gain(amount: number): number; set(value: number): void; tick(dtSeconds: number): void; i… — ⚠ undocumented · used by `createResourcePool`: A regenerating resource pool — mana, stamina, energy — that actions spend from and that refills over time.
- `ResourcePoolConfig` (interface): interface ResourcePoolConfig { max: number; initial?: number; regenPerSecond?: number; decayPerSecond?: number } — ⚠ undocumented · used by `createResourcePool`: A regenerating resource pool — mana, stamina, energy — that actions spend from and that refills over time.
- `ResourcePoolRetune` (interface): interface ResourcePoolRetune — Runtime tuning patch for {@link ResourcePool.retune} — omitted fields keep their current value.
- `ResourcePoolSnapshot` (interface): interface ResourcePoolSnapshot — Complete serializable state for a {@link ResourcePool}.
- `createResourcePool` (function): function createResourcePool(config: ResourcePoolConfig): ResourcePool — A regenerating resource pool — mana, stamina, energy — that actions spend from and that refills over time.

## @jgengine/core/combat/rewardAllocation

- `AllocationOutcome` (interface): interface AllocationOutcome — The serializable result of an allocation pass — immediate `grants` plus any deferred `pools`.
- `AllocationRequest` (interface): interface AllocationRequest — The inputs one allocation pass consumes. `allocationSeed` governs distribution decisions (ordering, round-robin rotation, remainder splits, reservation) while the separate optional `generationSeed` seeds per-recipient `instanced` generation — keeping join order from perturbing other players' rolls. Provide `results` for pre-rolled policies, `generate` for `instanced`, `assignment` for `assigned`, and `claim` for `claimed`.
- `ClaimOutcome` (interface): interface ClaimOutcome — The outcome of a claim attempt — the updated pool and the grants owed (empty when the claim is refused).
- `ClaimablePool` (interface): interface ClaimablePool — A serializable pool of results left open for later claiming — first-come contested drops or a `reservedFor` personal reward. Tracks `eligible` claimants, optional `expiresAtMs`, and the authoritative `claimedBy` winner so reconnect and duplicate-claim attempts resolve idempotently.
- `RewardClaimSpec` (interface): interface RewardClaimSpec — How a `claimed` allocation exposes its pool: open first-come (`first`) or `reserved` to one recipient.
- `RewardGrant` (interface): interface RewardGrant — An authoritative, serializable award of one result stack to one recipient — carries `via` (the policy that produced it) and `private` (replication scope) so provenance and visibility survive save/load and viewer projection. Applying a grant twice with the same identity is the caller's idempotency contract; this seam only decides who is owed what.
- `RewardPolicyKind` (type): type RewardPolicyKind = "instanced" | "shared" | "copy" | "roundRobin" | "assigned" | "claimed" — The distribution policies allocation ships — each a distinct answer to "who gets this result".
- `RewardRecipient` (interface): interface RewardRecipient — A participant that may receive rewards — an opaque recipient id (player, team, party slot) with an optional split `weight` (shared policy), eligibility `tags`, and an `eligible` gate. Ineligible recipients are excluded before any allocation decision so they never perturb others' streams.
- `RewardResult` (interface): interface RewardResult — One indivisible reward to distribute among participants — an opaque result id (a rolled drop, a currency bundle, a quest token) with an optional stack `count` and free-form `tags` for eligibility and provenance. Allocation never interprets the id; generation (loot tables, roll formulas) owns what it means, keeping the seam genre-agnostic.
- `RewardShare` (interface): interface RewardShare — A `{ result, count }` slice of a reward — the unit shared pools and grants are expressed in.
- `allocateRewards` (function): function allocateRewards(kind: RewardPolicyKind, request: AllocationRequest): AllocationOutcome — Allocate reward results among participants under a named policy, returning immediate grants and/or claimable pools. Distribution is deterministic and serializable: the same seeds, recipients, and results yield an identical outcome on host and every peer regardless of join order, so allocation replicates as data without re-rolling. Reward *generation* stays upstream (loot tables, roll formulas); this seam only decides who is owed what.
- `filterOutcomeFor` (function): function filterOutcomeFor(outcome: AllocationOutcome, viewerId: string): AllocationOutcome — Project an allocation outcome for one viewer, enforcing replication authoritatively: private grants belonging to other recipients are dropped, and pools the viewer cannot claim (not eligible, or reserved for someone else) are hidden — so private rewards never leak across the wire while provenance on the viewer's own grants is preserved.
- `resolveClaim` (function): function resolveClaim(pool: ClaimablePool, claimantId: string, options?: { nowMs?: number; private?: boolean }): ClaimOutcome — Resolve an authoritative claim against a pool. Idempotent: re-claiming an already-owned pool returns the same grants without re-awarding, a losing claimant gets no grants, and eligibility, reservation, and expiry are all enforced here — the authority, not UI hiding, decides ownership. Returns the updated (serializable) pool plus the grants owed.

## @jgengine/core/combat/shotOrigin

- `DEFAULT_EYE_HEIGHT` (const): const DEFAULT_EYE_HEIGHT: number — Shot-origin and first-person camera eye height above an entity's position: 90% of the default 1.8m hitbox top.
- `ResolvedShot` (interface): interface ResolvedShot — A shot's resolved firing geometry in world space: `origin` is the point the projectile/ray starts from and `direction` is its normalized aim vector, both computed by {@link resolveShot} from the shooter's position, facing, and the chosen origin policy.
- `ShotOriginDeps` (interface): interface ShotOriginDeps { positionOf(instanceId: string): EntityPosition | undefined; rotationYOf?(instanceId: string): number | undefined; collidersOf?(instanceId: string): EntityColliderSet | null | undefined } — ⚠ undocumented · used by `convergeShot`: Resolves a `converge` shot with scene knowledge: fires from the gun muzzle but bends the direction so the shot passes through the aim point …
- `ShotOriginPolicy` (type): type ShotOriginPolicy = | { kind: "converge"; muzzle?: EntityPosition; height?: number } | { kind: "eye"; height?: number } | { kind: "legacy" } | { kind: "entity" } | { kind: "entityOffset"; offset: EntityPosition } | { kind: "muzzle"; offset?: EntityPosition } | { kind: "camera"; origin: EntityPos… — How a shot's world-space origin (and optional direction) is resolved before prediction/settlement. - `converge` — the shot leaves the gun `muzzle` yet still passes through whatever the shooter's sightline (crosshair) covers: origin is the muzzle offset, direction is bent from the muzzle to the eye ray's aim point. The projectile system's default for a free `{ yaw, pitch }` aim, so a bullet visibly comes from the barrel without missing the reticle. Needs a scene raycast to find the aim point (`convergeShot`); a bare `resolveShot` degrades to a straight muzzle ray. Passes an explicit `{ origin, direction }` aim through untouched. - `eye` — `aim.origin` when present, else the shooter's entity position raised to eye height; the shot traces the shooter's sightline, so what the crosshair covers is what gets hit. - `legacy` — `aim.origin` when present, else the shooter's raw entity position (feet). - `entity` — always the shooter's entity position. - `entityOffset` / `muzzle` — entity-local offset rotated by the shooter's yaw (muzzle on a weapon model). - `camera` — explicit camera/reticle world origin (and optional direction override). - `world` — absolute world origin.
- `aimDirection` (function): function aimDirection(aim: Aim): EntityPosition | null — ⚠ undocumented
- `aimSpreadDeg` (function): function aimSpreadDeg(aim: Aim): number — ⚠ undocumented
- `convergeShot` (function): function convergeShot(deps: ShotOriginDeps, from: string, aim: Aim, range: number, sightHit: (origin: EntityPosition, direction: EntityPosition) => EntityPosition | null, muzzleOffset?: EntityPosition): ResolvedShot | null — Resolves a `converge` shot with scene knowledge: fires from the gun muzzle but bends the direction so the shot passes through the aim point the shooter's eye ray covers. `sightHit` casts the eye ray and returns where it lands (first impact), or `null` to fall back to a point `range` metres down the sightline. A `{ origin, direction }` aim is passed through unchanged (nothing to converge).
- `eyeHeightFromColliders` (function): function eyeHeightFromColliders(set: EntityColliderSet | null | undefined): number — Eye height derived from a collider set: 90% of the tallest hitbox top, or the humanoid default when unknown.
- `resolveShot` (function): function resolveShot(deps: ShotOriginDeps, from: string, aim: Aim, policy: ShotOriginPolicy = { kind: "eye" }): ResolvedShot | null — Resolves a shot's world origin and direction from the shooter's eye or muzzle and an {@link Aim}, ready for `ctx.scene.raycast` — the aim half of a hitscan weapon.

## @jgengine/core/combat/squadCombat

- `SquadCombat` (interface): interface SquadCombat — Drive a squad: cover by threat, flanking, fire discipline, suppression and retreat.
- `SquadCombatOptions` (interface): interface SquadCombatOptions extends SquadCombatTunables — Everything the squad AI reads from the game, plus its tunables.
- `SquadCombatSnapshot` (interface): interface SquadCombatSnapshot — Serializable squad state: member decisions, the crowd, and the tuning they ran under.
- `SquadCombatStats` (interface): interface SquadCombatStats — Counters a probe or a test reads.
- `SquadCombatTunables` (interface): interface SquadCombatTunables — In-play dials, every one retunable.
- `SquadMemberSpec` (interface): interface SquadMemberSpec — One combatant the runtime drives: whose side it is on, where it stands, and how hurt it is.
- `SquadMemberView` (interface): interface SquadMemberView — One member as a HUD, a probe or a test reads it. Allocates.
- `SquadMode` (type): type SquadMode = "advance" | "cover" | "peek" | "retreat" | "down" — What a member is doing this tick: moving to cover, holding it, leaning out, falling back, or down.
- `createSquadCombat` (function): function createSquadCombat(options: SquadCombatOptions): SquadCombat — One squad's combat behavior per tick, over the perception memory a game already keeps and the nav crowd it already moves. Each member picks a stand point that hides it from the threats it remembers, at the distance and angle its role wants; a flanker goes around the side, a support holds and fires, an assault closes. Incoming fire raises suppression, which pins the member to its cover and stops its shooting until the meter decays; low health turns it toward the point furthest from the threat.

## @jgengine/core/combat/squadTactics

- `FireDiscipline` (interface): interface FireDiscipline — Fire discipline: how long a member stays down between shots, how long it leans out, and how fast it fires while it has a target. A role that peeks for longer holds an angle better and spends more time in the open — the trade is the caller's to tune.
- `SquadComposition` (interface): interface SquadComposition — A squad's roles in assignment order.
- `SquadRole` (interface): interface SquadRole — One caller-defined squad role. The engine ships the machinery and no role list: a game names its own roles and dials them, so `"assault"`, `"breacher"` and `"sniper"` are content, not engine concepts.
- `ThreatReadOptions` (interface): interface ThreatReadOptions — Bounds for {@link threatsFromMemory}.
- `ThreatReading` (interface): interface ThreatReading extends CoverThreat — One remembered enemy with its age, so a role can treat a stale sighting differently.
- `assignSquadRoles` (function): function assignSquadRoles(members: readonly string[], composition: SquadComposition): Map<string, SquadRole> — Deterministic role per member: declared order, `count` copies of each role, and the list repeats when the squad is larger than the composition. Same members and composition give the same answer on every host and after a reload.
- `threatsFromMemory` (function): function threatsFromMemory(perception: PerceptionService, observerId: string, nowMs: number, options: ThreatReadOptions = {}): ThreatReading[] — Read one member's threat list out of its perception memory — the only source of threat. Sorted by confidence, then recency, then id, and bounded by `max`, so a crowded memory cannot grow the tick.

## @jgengine/core/combat/statusApplication

- `StatusApplicationInput` (interface): interface StatusApplicationInput — Everything `resolveStatusApplication` needs; all data plus an injected RNG for reproducibility.
- `StatusApplicationOutcome` (interface): interface StatusApplicationOutcome — The result of one status application: the outcome, the resulting instance (if any), and the roll.
- `StatusApplicationOutcomeKind` (type): type StatusApplicationOutcomeKind = | "applied" | "refreshed" | "stacked" | "replaced" | "immune" | "missed" | "ignored" — Why an application did or did not take, plus the roll for provenance.
- `StatusApplicationScale` (interface): interface StatusApplicationScale — Matchup-derived multipliers on the independent application axes. Each defaults to 1.
- `StatusApplicationSpec` (interface): interface StatusApplicationSpec — A serializable, effect-agnostic description of a status a hit tries to apply: an opaque `status` id the game routes to its own effect/DoT pipeline, a base landing `chance`, and the duration/ticks/magnitude/attribution/stacking data the resolver needs. The engine never interprets `status` — it is a reference, not a built-in condition.
- `StatusImmunity` (interface): interface StatusImmunity — Statuses a target cannot receive at all — the immunity half of application policy.
- `StatusInstance` (interface): interface StatusInstance — A live status carried by a target — the serializable, replicable state a status application mutates.
- `StatusStackPolicy` (type): type StatusStackPolicy = | { kind: "refresh" } | { kind: "stack"; max?: number; add?: number } | { kind: "replace" } | { kind: "ignore" } — How a fresh application behaves when the target already carries the status. - `refresh` — reset duration, hold the existing stack count. - `stack` — add `add` stacks (default 1) up to `max`, and refresh duration. - `replace` — overwrite duration and magnitude, stacks reset to 1. - `ignore` — leave the existing instance untouched (first application wins).
- `resolveStatusApplication` (function): function resolveStatusApplication(input: StatusApplicationInput): StatusApplicationOutcome — Resolve one status application: reject on immunity, roll landing chance against injected RNG, scale magnitude/duration by the matchup, then fold into any existing instance per the stacking policy. Deterministic given a seeded `rng`; pure over serializable data, so authority can run it and replicate only the returned `instance`.

## @jgengine/core/combat/statusEffectView

- `StatusEffectView` (interface): interface StatusEffectView — A serializable, presentation-ready snapshot of one active status for a timeline HUD row: a stable list `id`, the free-string `kind` the game styles (color / label / icon), the countdown-ring inputs `remainingMs` / `durationMs`, the `stacks` badge count, and the optional `magnitude` in force. Derived from a live {@link StatusInstance} via {@link toStatusEffectView}. The engine never interprets `kind` — it is a reference the game skins, not a built-in condition.
- `StatusEffectViewOptions` (interface): interface StatusEffectViewOptions — Options for {@link toStatusEffectView} / {@link toStatusEffectViews}.
- `statusEffectRemainingFraction` (function): function statusEffectRemainingFraction(view: StatusEffectView): number — Fraction of the countdown still remaining, clamped to `[0,1]` — the value a countdown ring fills to. Returns `0` when the duration is non-positive. Pure; safe to call every frame.
- `toStatusEffectView` (function): function toStatusEffectView(instance: StatusInstance, options?: StatusEffectViewOptions): StatusEffectView — Map one live {@link StatusInstance} to a serializable {@link StatusEffectView} for a HUD row. Pure: no clock, no allocation beyond the returned view. The `durationMs` option supplies the ring denominator the instance does not carry; without it the ring reads full.
- `toStatusEffectViews` (function): function toStatusEffectViews(instances: readonly StatusInstance[], options?: StatusEffectViewOptions): StatusEffectView[] — Map a list of live statuses (a target's carried {@link StatusInstance}s) to ordered HUD views. Pure and allocation-bounded — one pass, one view per input — so a status bar can render straight off the existing status model's snapshot without re-deriving ring math or timers.

## @jgengine/core/combat/statusRuntime

- `StatusApplyOptions` (interface): interface StatusApplyOptions — Options for one application; scales compose with the definition's own base values.
- `StatusDamageTick` (interface): interface StatusDamageTick — A damage tick, already routed through the caller's `applyDamage` when one was supplied.
- `StatusDef` (interface): interface StatusDef — One status the runtime can apply: how a fresh application folds into a live one ({@link StatusStackPolicy}), how long it lives, how often and how hard it ticks, and what a tick does. The stack rule is the *only* thing that changes stacks — per-tick magnitude is `magnitude × stacks`, never `magnitude ^ applications`.
- `StatusEffect` (type): type StatusEffect = | { kind: "damage"; channel: string } | { kind: "stat"; stat: string } — What a status does on each tick. Damage ticks are reported with the channel the caller's damage pipeline resolves, so a burn still meets resistances and armor; stat ticks are a per-stack delta summed by {@link StatusRuntime.statDelta} (`slow` → move speed, `corrode` → armor).
- `StatusExpiredTick` (interface): interface StatusExpiredTick — A status ended: remove its HUD row and any stat delta it was contributing.
- `StatusRuntime` (interface): interface StatusRuntime — A pool of per-target statuses that applies stack rules, ticks effects, and hands its state out.
- `StatusRuntimeEntry` (interface): interface StatusRuntimeEntry — One live status plus its tick timer, as saved and restored.
- `StatusRuntimeOptions` (interface): interface StatusRuntimeOptions — Tunables a game can adjust at runtime without discarding carried statuses.
- `StatusRuntimeState` (interface): interface StatusRuntimeState — Serializable runtime state: carried statuses, tick timers, and the counters a probe reports.
- `StatusStatTick` (interface): interface StatusStatTick — A stat tick: a per-stack delta the caller reads while the status lives.
- `StatusTickEvent` (type): type StatusTickEvent = StatusDamageTick | StatusStatTick | StatusExpiredTick — Everything one `tick` call produced, in target-then-status order.
- `UnknownStatusError` (class): class UnknownStatusError extends Error — Raised when a caller names a status id the runtime has no definition for.
- `createStatusRuntime` (function): function createStatusRuntime(options: StatusRuntimeOptions): StatusRuntime — Build a status runtime over serializable definitions. Applications reuse {@link resolveStatusApplication} for chance and stacking, so a refresh/stack-to-N/ignore rule has exactly one implementation; `tick` then applies each status's declared effect per stack.

## @jgengine/core/combat/telegraph

- `HazardCycleConfig` (interface): interface HazardCycleConfig { windupMs: number; activeMs: number; cooldownMs?: number; offsetMs?: number } — ⚠ undocumented
- `HazardCycleSample` (interface): interface HazardCycleSample { phase: HazardPhase; fraction: number; remainingMs: number; cycleIndex: number } — ⚠ undocumented
- `HazardPhase` (type): type HazardPhase = "windup" | "active" | "cooldown" — ⚠ undocumented
- `TelegraphConfig` (interface): interface TelegraphConfig { shape: TelegraphShape; at: EntityPosition; dir?: number; windupMs?: number; turns?: number; kind?: string } — ⚠ undocumented
- `TelegraphShape` (type): type TelegraphShape = | { kind: "circle"; radius: number } | { kind: "ring"; radius: number; innerRadius: number } | { kind: "cone"; radius: number; angle: number } | { kind: "line"; length: number; width: number } — ⚠ undocumented

## @jgengine/core/combat/thresholdCrossings

- `CrossingDirection` (type): type CrossingDirection = "falling" | "rising" — The direction a crossing moved: `falling` = value decreased past the mark, `rising` = increased past it.
- `CrossingPolicy` (type): type CrossingPolicy = "once" | "repeat" — Whether a threshold may fire repeatedly (`repeat`) or at most once per direction (`once`).
- `CrossingTrigger` (type): type CrossingTrigger = "falling" | "rising" | "both" — Which directions should emit crossings.
- `ThresholdCrossing` (interface): interface ThresholdCrossing — One emitted crossing: which threshold, which way, and the value span that produced it.
- `ThresholdCrossingConfig` (interface): interface ThresholdCrossingConfig — Caller configuration for a threshold tracker.
- `ThresholdMark` (interface): interface ThresholdMark — Generic numeric threshold-crossing tracker (#931).
- `ThresholdTracker` (interface): interface ThresholdTracker — A stateful crossing tracker over one numeric source.
- `ThresholdTrackerSnapshot` (interface): interface ThresholdTrackerSnapshot — Serializable tracker state for save/load.
- `createThresholdTracker` (function): function createThresholdTracker(config: ThresholdCrossingConfig): ThresholdTracker — Track a numeric source against named thresholds and emit ordered crossing events with direction, hysteresis, once/repeat policy, and skipped-threshold handling. Deterministic and serializable; drives phase transitions, armor breaks, resource warnings, and any other threshold consumer.

## @jgengine/core/combat/vfxPresets

- `DEFAULT_VFX_PRESET` (const): const DEFAULT_VFX_PRESET: VfxPresetName — The fallback flavor used when a `vfx()` call names an unknown preset — so a typo still shows a spark instead of nothing.
- `VfxPreset` (interface): interface VfxPreset — A named visual flavor for a one-shot `combat.vfx` burst: the archetype (`kind`), a `0xRRGGBB` tint, and optional default `durationMs`/`radius`. Purely presentation — a preset never touches damage, range, or any authoritative value; it just answers "what does this attack look like" so a game does not hand-roll colors and archetypes.
- `VfxPresetName` (type): type VfxPresetName = keyof typeof vfxPresets — A named key into {@link vfxPresets} (`"arrow" | "fireball" | "lightning" | "web" | "slash" | "shield" | "heal" | ...`).
- `resolveVfxPreset` (function): function resolveVfxPreset(name: string | undefined, overrides?: Partial<VfxPreset>): VfxPreset — Resolve a named visual flavor into a concrete `{ kind, color, durationMs?, radius? }`, with any provided `overrides` winning field by field. An unknown name resolves to {@link DEFAULT_VFX_PRESET} rather than throwing, so a flavor typo degrades to a visible spark. Used by `ctx.scene.entity.vfx({ preset })`; call it directly when you need the raw numbers (e.g. to seed a retained `vfxInstance` from the same vocabulary).
- `vfxPresets` (const): const vfxPresets: { readonly arrow: { readonly kind: "projectile"; readonly color: 14207392; }; readonly bolt: { readonly kind: "projectile"; readonly color: 16777215; }; readonly fireball: { readonly kind: "projectile"; readonly color: 16738842; readonly durationMs: 460; }; readonly firebolt: { rea… — Ready-made visual flavors for the things players actually shoot, swing, and cast — so `ctx.scene.entity.vfx({ preset: "arrow", from, to })` renders a visible bolt with zero tuning, and `"lightning"`, `"web"`, `"slash"`, `"shield"`, `"heal"`, `"explosion"` likewise just work. Each entry only picks a `kind` (`projectile | beam | nova | glow | spark`), a color, and a lifetime; it is visual vocabulary (like named CSS colors), not a gameplay archetype — combat numbers stay in the caller's own effect/ability data. Any field passed to `vfx()` overrides the preset, and unknown names fall back to `spark` so a flavor typo still shows *something* rather than nothing.

## @jgengine/core/combat/weaponDefinition

- `DEFAULT_WEAPON_PELLETS_IN_FLIGHT` (const): const DEFAULT_WEAPON_PELLETS_IN_FLIGHT: 32 — Default live-pellet cap for a weapon that does not name one.
- `MAX_WEAPON_BURST_COUNT` (const): const MAX_WEAPON_BURST_COUNT: 64 — Cap on `WeaponBurstDef.count`.
- `MAX_WEAPON_PELLETS_IN_FLIGHT` (const): const MAX_WEAPON_PELLETS_IN_FLIGHT: 256 — Cap on `WeaponDefinition.maxInFlight`; bounds per-tick projectile work.
- `MAX_WEAPON_PELLETS_PER_SHOT` (const): const MAX_WEAPON_PELLETS_PER_SHOT: 64 — Cap on `WeaponDefinition.pellets`; bounds rays and damage resolutions per shot.
- `WeaponBurstDef` (interface): interface WeaponBurstDef — Shots one trigger pull commits to. A burst finishes even if the trigger is released.
- `WeaponDamageDef` (interface): interface WeaponDamageDef — What one pellet does when it reaches a registered damage target.
- `WeaponDefinition` (interface): interface WeaponDefinition — One weapon as plain data: cadence, fire mode, delivery, magazine, feel and damage. Nothing here is a function, so a generator can roll it, a save can store it, and two weapons differ by their fields.
- `WeaponFalloffDef` (interface): interface WeaponFalloffDef — Linear damage falloff between two distances.
- `WeaponFireMode` (type): type WeaponFireMode = "single" | "auto" | "burst" — How a held or tapped trigger turns into shots.
- `WeaponHitscanDef` (interface): interface WeaponHitscanDef — A ray resolved in the caller's world on the same tick it is fired.
- `WeaponMagazineDef` (interface): interface WeaponMagazineDef — Loaded rounds, reload time, and where reloads draw from.
- `WeaponProjectileDef` (interface): interface WeaponProjectileDef — A travelling pellet simulated by the runtime, resolved when it meets the caller's world.
- `WeaponVec3` (type): type WeaponVec3 = readonly [number, number, number] — A world-space point or direction in metres.
- `assertWeaponDefinition` (function): function assertWeaponDefinition(definition: WeaponDefinition): void — Check a definition before it reaches the runtime, so a rolled weapon fails loudly at construction instead of firing nothing. Throws `RangeError` naming the field.
- `weaponDamageAt` (function): function weaponDamageAt(definition: WeaponDefinition, distance: number): number — Damage multiplier at a distance: `1` before `falloff.start`, linearly down to `endScale` at `end`.
- `weaponIntervalMs` (function): function weaponIntervalMs(definition: WeaponDefinition): number — Milliseconds between shots at full cadence: `60_000 / roundsPerMinute`.
- `weaponMaxInFlight` (function): function weaponMaxInFlight(definition: WeaponDefinition): number — Live pellets one definition may keep, clamped to a bounded range.

## @jgengine/core/combat/weaponFeedback

- `WeaponFeedbackSignal` (type): type WeaponFeedbackSignal = "shot" | "kick" | "impact" | "recoil" | "cameraKick" | "spread" | "ads" — Signals {@link createWeaponFeedbackSignals} reports each tick, named for `createFeedbackMixer` routes. `shot`, `kick` and `impact` are pulses that read non-zero only on the tick they happened; the rest follow the handling frame.
- `WeaponFeedbackSignals` (interface): interface WeaponFeedbackSignals — Collects weapon events between presentation ticks and hands them to a feedback mixer as one signal record.
- `WeaponFeedbackState` (interface): interface WeaponFeedbackState — Serializable pending pulses, so a snapshot taken between a shot and the next read loses nothing.
- `createWeaponFeedbackSignals` (function): function createWeaponFeedbackSignals(): WeaponFeedbackSignals — Creates {@link WeaponFeedbackSignals}: the bridge from shots, recoil kick and impacts to `createFeedbackMixer` routes (camera shake, audio, rumble). Route `kick` with no smoothing into camera-shake trauma, `impact` with a `release` into rumble, and `ads`/`spread` into continuous audio or FOV targets. Deterministic and allocation-free per read.

## @jgengine/core/combat/weaponFire

- `FireCadence` (interface): interface FireCadence — A minimal minimum-interval rate gate for a repeated action — weapon fire, ability spam, any "no faster than N per second" rule. Deterministic and serializable: its whole state is the elapsed time since the last action, exposed via {@link FireCadence.elapsedMs}.
- `FireCadenceConfig` (interface): interface FireCadenceConfig — Tuning for {@link createFireCadence}: the minimum interval between actions and whether it starts ready.
- `WeaponFireResult` (interface): interface WeaponFireResult<THit> — The result of a {@link WeaponRuntime.fire} attempt. On `"fired"`, `hits` is whatever the caller's raycast returned and `resolutions` holds the portable damage provenance for each hit that produced a {@link DamageHitInput}; on any blocked status both are empty and no round was spent.
- `WeaponFireStatus` (type): type WeaponFireStatus = "fired" | "cooling" | "empty" | "reloading" — Why a {@link WeaponRuntime.fire} attempt resolved the way it did.
- `WeaponRuntime` (interface): interface WeaponRuntime<TAim, THit> — A composed weapon fire controller: a {@link FireCadence} gate, an optional {@link Magazine}, the caller's raycast, and portable {@link resolveDamageHit} damage resolution wired together. The caller retains ownership of models, animations, muzzle flash, audio, input, camera, aiming, and the raycaster itself.
- `WeaponRuntimeConfig` (interface): interface WeaponRuntimeConfig<TAim, THit> — Configuration for {@link createWeaponRuntime}. Everything time/ammo-related is plain data; the two callbacks are where the caller keeps ownership of aiming, its own raycaster/projectile query, and how a hit maps to damage. There is deliberately no default weapon, projectile, or damage table here — those are game content.
- `createFireCadence` (function): function createFireCadence(config: FireCadenceConfig): FireCadence — Build a {@link FireCadence} rate gate. Reach for this instead of hand-tracking a `lastFiredAt` timestamp and comparing against a fire interval per game.
- `createWeaponRuntime` (function): function createWeaponRuntime<TAim, THit>(config: WeaponRuntimeConfig<TAim, THit>): WeaponRuntime<TAim, THit> — Compose a portable weapon fire controller from the existing generic primitives — a {@link FireCadence} gate, an optional {@link Magazine}, a caller-provided raycast, and portable {@link resolveDamageHit} damage resolution. No `GameContext`, entity store, renderer, or default weapon is involved; the caller owns aiming, its raycaster, and all presentation, and the result carries full damage provenance for authority to apply and replicate.

## @jgengine/core/combat/weaponHandling

- `WeaponHandling` (interface): interface WeaponHandling — The player-to-weapon relationship as state: recoil that climbs and recovers, spread that blooms and settles, and an aim-down-sights blend. Cadence, ammo and hits stay in `weaponFire`/`magazine`; this owns how the weapon feels between them. First-person, third-person and over-the-shoulder presentations read the same frame.
- `WeaponHandlingFrame` (interface): interface WeaponHandlingFrame — Live handling readout: the offsets to add to aim and camera, current spread and ADS blend.
- `WeaponHandlingState` (interface): interface WeaponHandlingState — Serializable handling state.
- `WeaponHandlingTuning` (interface): interface WeaponHandlingTuning — Tuning for {@link createWeaponHandling}. Every number is an angle in radians or a time in seconds, so two weapons differ by numbers a person can reason about: a controllable rifle climbs a little and recovers fast; a shotgun kicks hard and blooms wide.
- `WeaponProbeOptions` (interface): interface WeaponProbeOptions — Options for {@link measureWeapon}.
- `WeaponRecoilTuning` (interface): interface WeaponRecoilTuning — Recoil per shot, in radians of aim. `pitch > 0` climbs the muzzle, `yaw > 0` pulls right.
- `WeaponReport` (interface): interface WeaponReport — Deterministic weapon-feel metrics from {@link measureWeapon}.
- `WeaponShot` (interface): interface WeaponShot — What one shot did: the cone to sample and the kick it applied.
- `WeaponSpreadTuning` (interface): interface WeaponSpreadTuning — Cone of fire, as a half-angle in radians.
- `WeaponStance` (interface): interface WeaponStance — Stance and aim for one tick.
- `createWeaponHandling` (function): function createWeaponHandling(initial: WeaponHandlingTuning, options: { random?: () => number } = {}): WeaponHandling — Creates a {@link WeaponHandling}. Pass `random` (e.g. `ctx.rng` or `seededRng(seed)`) for the random recoil cone; without it the cone is skipped, so the result stays deterministic either way.
- `measureWeapon` (function): function measureWeapon(create: () => WeaponHandling, options: WeaponProbeOptions): WeaponReport — Fires a held burst through a fresh handling instance at a fixed interval and reports spread growth, climb, reset time, ADS time and time-to-kill. Time-to-kill counts expected damage: each projectile hits with the share of its spread cone the target covers at `range`, scaled by `damageAt(range)`, so a blooming rifle and a wide shotgun compare at the distance the game cares about.

## @jgengine/core/combat/weaponPresentation

- `DEFAULT_VIEWMODEL_ADS` (const): const DEFAULT_VIEWMODEL_ADS: ViewmodelOffset — Default ADS anchor: the built-in viewmodel's top rail on the camera axis.
- `DEFAULT_VIEWMODEL_HIP` (const): const DEFAULT_VIEWMODEL_HIP: ViewmodelOffset — Default hip anchor, matching the shell's built-in viewmodel.
- `ViewmodelOffset` (type): type ViewmodelOffset = readonly [number, number, number] — Camera-space position `[x, y, z]` in metres: `+x` right, `+y` up, `-z` forward.
- `WeaponPose` (interface): interface WeaponPose — Where the viewmodel and camera go this frame. First person applies all of it; third person and over-the-shoulder read `lookPitch`/`lookYaw`, `aimPitch`/`aimYaw` and `adsProgress` from the same frame.
- `WeaponPresentation` (interface): interface WeaponPresentation — Turns a {@link WeaponHandlingFrame} plus look and movement into a viewmodel and camera pose.
- `WeaponPresentationInput` (interface): interface WeaponPresentationInput — One frame of inputs: look motion, the movement probe, and the weapon's handling readout.
- `WeaponPresentationState` (interface): interface WeaponPresentationState — Serializable presentation state: the current sway lag.
- `WeaponPresentationTuning` (interface): interface WeaponPresentationTuning — How one weapon sits in first person. Offsets are camera-space metres, angles are radians, FOVs are degrees. Every field is optional; two weapons differ by the ones they set.
- `createWeaponPresentation` (function): function createWeaponPresentation(initial: WeaponPresentationTuning = {}): WeaponPresentation — Creates a {@link WeaponPresentation}: per-weapon viewmodel offset, ADS pose and viewmodel FOV, sway and inertia from look speed, bob from the movement probe, and a recoil kick, all driven by the same handling frame third-person and over-the-shoulder rigs read. Deterministic and allocation-free per update.
- `viewmodelFovScale` (function): function viewmodelFovScale(worldFov: number, viewmodelFov: number): number — Scale for a viewmodel drawn at `viewmodelFov` through a camera at `worldFov` (both degrees): multiply the viewmodel's camera-space x and y by this and it projects as if rendered with its own FOV, without a second camera or render pass.

## @jgengine/core/combat/weaponSystem

- `WeaponAim` (interface): interface WeaponAim — Current aim with recoil applied.
- `WeaponAmmo` (interface): interface WeaponAmmo — Ammo and cadence as a HUD or a test reads them.
- `WeaponContact` (interface): interface WeaponContact — Where one pellet met the caller's world.
- `WeaponImpact` (interface): interface WeaponImpact — One resolved hit, with the damage runtime's full provenance.
- `WeaponImpactContext` (interface): interface WeaponImpactContext — Read-only facts about the hit handed to `damageFor`.
- `WeaponProjectileView` (interface): interface WeaponProjectileView — A pellet alive in flight, for presentation or prediction.
- `WeaponReloadState` (type): type WeaponReloadState = "idle" | "reloading" | "interrupted" — `idle`, `reloading`, or `interrupted` after `interruptReload()` kept the progress.
- `WeaponShotRecord` (interface): interface WeaponShotRecord — One fired shot: the cone it fired into, the kick it took, and where each pellet went.
- `WeaponStats` (interface): interface WeaponStats — Lifetime ammo economy and resolution counters.
- `WeaponSystem` (interface): interface WeaponSystem — A weapon as the game drives it: base aim in, shots and resolved impacts out. Fire mode, cadence, handling, delivery, magazine and damage all come from one {@link WeaponDefinition}; the game owns input, the muzzle, and the world query.
- `WeaponSystemDeps` (interface): interface WeaponSystemDeps — Everything the runtime is allowed to reach: RNG, the damage model, the muzzle, and the world query.
- `WeaponSystemState` (interface): interface WeaponSystemState — Serializable runtime state: aim, handling, ammo, trigger, pellets and counters.
- `WeaponTickResult` (interface): interface WeaponTickResult — What one {@link WeaponSystem.tick} produced. Empty arrays on a quiet tick.
- `createWeaponSystem` (function): function createWeaponSystem(initial: WeaponDefinition, deps: WeaponSystemDeps): WeaponSystem — Build a weapon from one {@link WeaponDefinition}. The game supplies aim, a muzzle, one world query, the damage model and an RNG; the runtime owns fire modes, cadence, recoil, bloom, reload states, ammo accounting, projectile ballistics and the damage call. State snapshots as plain data.

## @jgengine/core/stats/accumulatorMeter

- `AccumulatorMeter` (interface): interface AccumulatorMeter { state(): AccumulatorMeterState; restore(next: AccumulatorMeterState): void; value(): number; fraction(): number; tier(): string | null; broke(): boolean; add(amount: number): MeterAddResult; drain(amount: number): void; reset(): void; tic… — ⚠ undocumented · used by `createAccumulatorMeter`: A raw accumulating gauge that crosses named tier thresholds as a value builds, with optional decay — the primitive under charge, rage, and c…
- `AccumulatorMeterConfig` (interface): interface AccumulatorMeterConfig { max: number; mode?: MeterMode; decayPerSecond?: number; decayDelayMs?: number; tiers?: readonly MeterTier[] } — ⚠ undocumented · used by `createAccumulatorMeter`: A raw accumulating gauge that crosses named tier thresholds as a value builds, with optional decay — the primitive under charge, rage, and c…
- `AccumulatorMeterState` (interface): interface AccumulatorMeterState — Mutable meter value, hold latch, and time since the last gain.
- `MeterAddResult` (interface): interface MeterAddResult { value: number; fired: boolean; overflow: number; tier: string | null; tierChanged: boolean } — ⚠ undocumented
- `MeterMode` (type): type MeterMode = "hold" | "reset" — ⚠ undocumented
- `MeterTier` (interface): interface MeterTier { id: string; at: number } — ⚠ undocumented · used by `tierAt`: The highest tier id whose `at` threshold `value` has reached, or `null` below every tier — the pure lookup `createAccumulatorMeter`/`createE…
- `createAccumulatorMeter` (function): function createAccumulatorMeter(config: AccumulatorMeterConfig): AccumulatorMeter — A raw accumulating gauge that crosses named tier thresholds as a value builds, with optional decay — the primitive under charge, rage, and combo meters.
- `tierAt` (function): function tierAt(value: number, tiers: readonly MeterTier[]): string | null — The highest tier id whose `at` threshold `value` has reached, or `null` below every tier — the pure lookup `createAccumulatorMeter`/`createEventMeter` call on every `add`/`tick`.

## @jgengine/core/stats/eventMeter

- `EventMeter` (interface): interface EventMeter { state(): EventMeterState; restore(next: EventMeterState): void; value(): number; fraction(): number; tier(): string | null; ready(): boolean; feed(tag: string, scale?: number): EventMeterFeedResult; consume(): boolean; drain(amount: numbe… — ⚠ undocumented · used by `createEventMeter`: A heat/hype gauge that rises as tagged events land and cools between them, firing when it fills or breaks — the streak/overdrive meter shoot…
- `EventMeterConfig` (interface): interface EventMeterConfig { max: number; mode?: MeterMode; decayPerSecond?: number; decayDelayMs?: number; tiers?: readonly MeterTier[]; gains: Record<string, number>; resets?: readonly string[] } — ⚠ undocumented · used by `createEventMeter`: A heat/hype gauge that rises as tagged events land and cools between them, firing when it fills or breaks — the streak/overdrive meter shoot…
- `EventMeterFeedResult` (interface): interface EventMeterFeedResult { tag: string; reset: boolean; amount: number; value: number; fraction: number; fired: boolean; ready: boolean; overflow: number; tier: string | null; tierChanged: boolean } — ⚠ undocumented
- `EventMeterState` (type): type EventMeterState = AccumulatorMeterState — Event meter persistence uses the underlying accumulator's complete state.
- `createEventMeter` (function): function createEventMeter(config: EventMeterConfig): EventMeter — A heat/hype gauge that rises as tagged events land and cools between them, firing when it fills or breaks — the streak/overdrive meter shooters and fighters hand-roll.

## @jgengine/core/stats/rollCheck

- `CheckAdvantage` (type): type CheckAdvantage = "advantage" | "disadvantage" | "normal" — ⚠ undocumented
- `CheckInput` (interface): interface CheckInput { modifier: number; dc: number; advantage?: CheckAdvantage; diceSides?: number } — ⚠ undocumented · used by `rollCheck`: Resolve a tabletop-style pass/fail roll against a target number with modifiers and crit/fumble bands.
- `CheckResult` (interface): interface CheckResult { rolls: readonly number[]; roll: number; total: number; success: boolean; critical: "success" | "failure" | null } — ⚠ undocumented · used by `rollCheck`: Resolve a tabletop-style pass/fail roll against a target number with modifiers and crit/fumble bands.
- `rollCheck` (function): function rollCheck(input: CheckInput, rng?: () => number): CheckResult — Resolve a tabletop-style pass/fail roll against a target number with modifiers and crit/fumble bands.

## @jgengine/core/stats/spawnLevelStats

- `CreatureStatInstance` (interface): interface CreatureStatInstance<TStat extends string> — A single creature's serializable stat record — a reference to its species (`speciesId`), the current `level`, the per-stat count of distributed points, and how many post-capture domestic levels have been spent. Plain data: round-trips through JSON, save/load, and multiplayer sync. Resolve display values with {@link resolveSpawnStats}.
- `SpawnSpeciesDef` (type): type SpawnSpeciesDef<TStat extends string> = Record<TStat, SpawnStatDef> — A species' stat table: every stat the creature owns keyed to its {@link SpawnStatDef}. The key order is the deterministic order random points are distributed over, so a serialized species definition reproduces the same rolls under the same rng sequence.
- `SpawnStatDef` (interface): interface SpawnStatDef — Per-stat growth definition for one species. `base` is the level-1 value of the stat; `growth` is how much a single distributed point adds, expressed as a fraction of `base` — so a point on a `growth: 0.1` stat is worth +10% of base. The resolved value is `base * (1 + points * growth)`.
- `applyCaptureEffectiveness` (function): function applyCaptureEffectiveness<TStat extends string>(species: SpawnSpeciesDef<TStat>, instance: CreatureStatInstance<TStat>, effectiveness: number, rng: () => number): CaptureResult<TStat> — Apply a capture at the given effectiveness: compute bonus levels via {@link captureBonusLevels}, distribute those extra points randomly with the injected rng, and return the post-capture instance (level raised to the tamed total) alongside the granted bonus levels and tamed level. The input instance is not mutated.
- `captureBonusLevels` (function): function captureBonusLevels(level: number, effectiveness: number): number — Bonus levels granted by a capture at the given effectiveness: `floor(level * clamp01(effectiveness) / 2)`. A perfect (1.0) capture grants half the wild level; a botched (0) capture grants none. Effectiveness outside `[0,1]` clamps.
- `resolveSpawnStats` (function): function resolveSpawnStats<TStat extends string>(species: SpawnSpeciesDef<TStat>, instance: CreatureStatInstance<TStat>): Record<TStat, number> — Resolve an instance's live stat values from its distributed points: `value = base * (1 + points * growth)` per stat. Stats with zero points return their base.
- `restoreSpawnInstance` (function): function restoreSpawnInstance<TStat extends string>(data: CreatureStatInstance<TStat>): CreatureStatInstance<TStat> — Rehydrate a creature stat instance from decoded data (e.g. `JSON.parse` output), returning a fresh deep copy the caller owns. Inverse of {@link snapshotSpawnInstance}.
- `rollSpawnInstance` (function): function rollSpawnInstance<TStat extends string>(speciesId: string, species: SpawnSpeciesDef<TStat>, level: number, rng: () => number): CreatureStatInstance<TStat> — Roll a fresh wild creature at `level`: distribute `(level - 1)` points randomly across the species' stats using the injected rng and return a serializable {@link CreatureStatInstance}. Deterministic — the same rng sequence yields the same point spread. Levels below 1 clamp to 1 (no points). Use `seededRng` from `../random/rng` for a persisted, reproducible stream.
- `snapshotSpawnInstance` (function): function snapshotSpawnInstance<TStat extends string>(instance: CreatureStatInstance<TStat>): CreatureStatInstance<TStat> — Deep-copy an instance into a detached, serializable record — the transport/save counterpart of {@link restoreSpawnInstance}. Copies the points map so later edits don't leak into the snapshot.
- `spendDomesticLevel` (function): function spendDomesticLevel<TStat extends string>(instance: CreatureStatInstance<TStat>, stat: TStat, options?: SpendLevelOptions): SpendLevelResult<TStat> — Spend one earned post-capture level into `stat`, adding a single growth increment (one point) and raising both `level` and `domesticLevels`. When `maxDomesticLevels` is set and already reached, the spend is refused (`spent: false`) and the instance is returned untouched. Pure: returns a new instance rather than mutating the input.

## @jgengine/core/stats/statModifiers

- `CreateStatsOptions` (interface): interface CreateStatsOptions { now?: () => number } — ⚠ undocumented · used by `createStats`: A stat block whose base values take stacking, timed buffs and debuffs, resolving the modified value on read.
- `StatModifier` (interface): interface StatModifier { add?: number; multiply?: number } — ⚠ undocumented
- `StatModifierSet` (type): type StatModifierSet<TStat extends string> = Partial<Record<TStat, StatModifier>> — ⚠ undocumented · used by `statModifierContributions` (@jgengine/core/gameplay): Bridge the shared {@link StatModifierSet} shape (add/multiply, used by talents, items, and buffs) into stat-graph contributions, so a ranked…
- `Stats` (interface): interface Stats<TStat extends string> { setBase(stat: TStat, value: number): void; getBase(stat: TStat): number; addSource(sourceId: string, modifiers: StatModifierSet<TStat>, options?: {expiresAtMs?: number}): void; removeSource(sourceId: string): void; hasSource(sourceId: str… — ⚠ undocumented · used by `createStats`: A stat block whose base values take stacking, timed buffs and debuffs, resolving the modified value on read.
- `StatsSnapshot` (interface): interface StatsSnapshot<TStat extends string> — Complete plain-data state for a {@link Stats} runtime.
- `createStats` (function): function createStats<TStat extends string>(base: Record<TStat, number>, options?: CreateStatsOptions): Stats<TStat> — A stat block whose base values take stacking, timed buffs and debuffs, resolving the modified value on read.

## @jgengine/core/stats/statPool

- `StatPool` (interface): interface StatPool — Serializable state for any bounded named resource. The caller defines what the resource means.
- `StatPoolAccess` (interface): interface StatPoolAccess<TOwnerId extends string = string, TStatId extends string = string> — Structural bridge to caller-owned resource state. Implement it over an ECS, Redux/Zustand store, plain object, database-backed model, or JGengine's native entity stats without moving ownership into the SDK.
- `StatPoolAccessResult` (type): type StatPoolAccessResult = | ({ status: "ok" } & StatPoolChange) | { status: "rejected"; reason: string } — Outcome of changing a pool through {@link StatPoolAccess}.
- `StatPoolChange` (interface): interface StatPoolChange — Inspectable result of a bounded pool change.
- `StatPoolInput` (interface): interface StatPoolInput — Input used to create a normalized pool. `current` defaults to `max`; `min` defaults to zero.
- `StatPoolPatch` (interface): interface StatPoolPatch — Partial update applied without mutating the previous pool.
- `applyStatPoolDelta` (function): function applyStatPoolDelta<TOwnerId extends string, TStatId extends string>(access: StatPoolAccess<TOwnerId, TStatId>, ownerId: TOwnerId, statId: TStatId, amount: number): StatPoolAccessResult — Read, transition, and write a caller-owned pool through the structural adapter. Positive amounts increase the resource; negative amounts decrease it. The adapter receives a complete replacement value, never a hidden mutation.
- `changeStatPool` (function): function changeStatPool(pool: StatPool, amount: number): StatPoolChange — Pure bounded delta transition with the exact applied amount and boundary flags.
- `createStatPool` (function): function createStatPool(input: StatPoolInput): StatPool — Normalize caller data into a complete plain-data pool.
- `patchStatPool` (function): function patchStatPool(pool: StatPool, patch: StatPoolPatch): StatPool — Apply new bounds/current to a pool, clamping the result and leaving the input untouched.
