@jgengine/shell 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/CHANGELOG.md +265 -2
  2. package/dist/GamePlayerShell.js +27 -4
  3. package/dist/JoinGate.d.ts +17 -0
  4. package/dist/JoinGate.js +14 -0
  5. package/dist/Shell3dPresentation.d.ts +9 -8
  6. package/dist/Shell3dPresentation.js +57 -8
  7. package/dist/ShellChrome.d.ts +2 -0
  8. package/dist/ShellChrome.js +6 -0
  9. package/dist/ShellHudPresentation.d.ts +9 -1
  10. package/dist/ShellHudPresentation.js +21 -0
  11. package/dist/TerritoryOverlay.d.ts +21 -0
  12. package/dist/TerritoryOverlay.js +9 -0
  13. package/dist/audio/AudioComponents.js +13 -2
  14. package/dist/audio/audioEngine.d.ts +15 -1
  15. package/dist/audio/audioEngine.js +132 -11
  16. package/dist/audio/audioWire.d.ts +3 -0
  17. package/dist/audio/audioWire.js +7 -1
  18. package/dist/audio/loopParams.d.ts +39 -0
  19. package/dist/audio/loopParams.js +43 -0
  20. package/dist/camera/GameCameraRig.js +1 -1
  21. package/dist/camera/GameFirstPersonCamera.d.ts +4 -2
  22. package/dist/camera/GameFirstPersonCamera.js +52 -15
  23. package/dist/camera/Viewports.d.ts +34 -0
  24. package/dist/camera/Viewports.js +123 -0
  25. package/dist/camera/cameraRigs.js +77 -62
  26. package/dist/camera/orbitCameraMath.js +2 -2
  27. package/dist/camera/rigMath.d.ts +82 -4
  28. package/dist/camera/rigMath.js +133 -15
  29. package/dist/defineGame.d.ts +9 -0
  30. package/dist/defineGame.js +38 -6
  31. package/dist/devtools/DevtoolsOverlay.js +2 -0
  32. package/dist/devtools/KeysPanel.js +3 -3
  33. package/dist/devtools/agentBridge.d.ts +6 -0
  34. package/dist/devtools/agentBridge.js +15 -1
  35. package/dist/diagnostics/FpsCounter.d.ts +17 -0
  36. package/dist/diagnostics/FpsCounter.js +32 -0
  37. package/dist/drivers/FrameDriver.d.ts +5 -1
  38. package/dist/drivers/FrameDriver.js +74 -26
  39. package/dist/drivers/FrameRateLimiter.d.ts +9 -0
  40. package/dist/drivers/FrameRateLimiter.js +39 -0
  41. package/dist/drivers/HudOnlyDriver.js +10 -5
  42. package/dist/environment/DayNightSky.js +5 -5
  43. package/dist/environment/Daylight.d.ts +35 -1
  44. package/dist/environment/Daylight.js +98 -28
  45. package/dist/environment/EnvironmentScene.js +1 -1
  46. package/dist/environment/VolumetricClouds.js +20 -2
  47. package/dist/environment/daylightCycle.d.ts +20 -0
  48. package/dist/environment/daylightCycle.js +59 -7
  49. package/dist/environment/sunShadowMath.d.ts +45 -0
  50. package/dist/environment/sunShadowMath.js +50 -0
  51. package/dist/input/gamepadMerge.d.ts +10 -0
  52. package/dist/input/gamepadMerge.js +12 -0
  53. package/dist/input/gamepadPoll.d.ts +47 -0
  54. package/dist/input/gamepadPoll.js +142 -0
  55. package/dist/input/gamepadSource.d.ts +22 -0
  56. package/dist/input/gamepadSource.js +153 -0
  57. package/dist/input/mouseLook.js +2 -1
  58. package/dist/input/padHaptics.d.ts +17 -0
  59. package/dist/input/padHaptics.js +32 -0
  60. package/dist/input/pointerLock.d.ts +11 -0
  61. package/dist/input/pointerLock.js +19 -0
  62. package/dist/materialOverride.d.ts +4 -1
  63. package/dist/materialOverride.js +10 -1
  64. package/dist/postfx/PostProcessing.d.ts +11 -8
  65. package/dist/postfx/PostProcessing.js +38 -16
  66. package/dist/postfx/gradeShader.js +13 -0
  67. package/dist/postfx/stylizePass.d.ts +23 -0
  68. package/dist/postfx/stylizePass.js +216 -0
  69. package/dist/render/CascadedShadows.d.ts +11 -0
  70. package/dist/render/CascadedShadows.js +19 -8
  71. package/dist/render/EnvironmentLighting.d.ts +4 -1
  72. package/dist/render/EnvironmentLighting.js +45 -9
  73. package/dist/render/SceneLighting.d.ts +16 -2
  74. package/dist/render/SceneLighting.js +56 -6
  75. package/dist/render/SceneModels.js +45 -9
  76. package/dist/render/SkinnedInstances.d.ts +91 -0
  77. package/dist/render/SkinnedInstances.js +249 -0
  78. package/dist/render/TextureFiltering.d.ts +16 -0
  79. package/dist/render/TextureFiltering.js +64 -0
  80. package/dist/render/displayColor.d.ts +33 -0
  81. package/dist/render/displayColor.js +138 -0
  82. package/dist/render/modelLoad.d.ts +39 -0
  83. package/dist/render/modelLoad.js +89 -1
  84. package/dist/render/modelRender.d.ts +3 -0
  85. package/dist/render/modelRender.js +6 -2
  86. package/dist/render/resolveModel.js +4 -0
  87. package/dist/render/useFootIk.d.ts +58 -0
  88. package/dist/render/useFootIk.js +216 -0
  89. package/dist/render/useModelAnimation.d.ts +26 -0
  90. package/dist/render/useModelAnimation.js +184 -107
  91. package/dist/scene/AuthoredScene.d.ts +9 -0
  92. package/dist/scene/AuthoredScene.js +17 -1
  93. package/dist/scene/CityRenderer.js +666 -241
  94. package/dist/scene/cityWindowMaterial.d.ts +8 -6
  95. package/dist/scene/cityWindowMaterial.js +80 -21
  96. package/dist/settings/QuickControls.js +1 -1
  97. package/dist/settings/SettingsMenu.js +1 -1
  98. package/dist/settings/appliedSettings.d.ts +10 -2
  99. package/dist/settings/appliedSettings.js +9 -5
  100. package/dist/settings/settingsController.d.ts +3 -0
  101. package/dist/settings/settingsController.js +47 -3
  102. package/dist/structures/BuildingKitBatch.js +26 -22
  103. package/dist/structures/GeneratedBuilding.d.ts +3 -15
  104. package/dist/structures/GeneratedBuilding.js +21 -15
  105. package/dist/structures/buildingSurface.d.ts +21 -0
  106. package/dist/structures/buildingSurface.js +134 -0
  107. package/dist/terrain/terrainDetailMaterial.js +7 -3
  108. package/dist/useShellMultiplayerSync.d.ts +9 -2
  109. package/dist/useShellMultiplayerSync.js +30 -8
  110. package/dist/visibility/CullingProvider.d.ts +2 -1
  111. package/dist/visibility/CullingProvider.js +7 -2
  112. package/dist/world/GridWorldScene.js +4 -0
  113. package/dist/world/TileLayerRenderer.d.ts +9 -0
  114. package/dist/world/TileLayerRenderer.js +64 -0
  115. package/dist/world/WorldParticles.d.ts +31 -0
  116. package/dist/world/WorldParticles.js +128 -0
  117. package/dist/world/WorldScene.d.ts +2 -1
  118. package/dist/world/WorldScene.js +46 -4
  119. package/dist/world/entityPose.d.ts +4 -0
  120. package/dist/world/entityPose.js +9 -0
  121. package/dist/world/tileLayerInstances.d.ts +11 -0
  122. package/dist/world/tileLayerInstances.js +28 -0
  123. package/dist/worldSync.d.ts +5 -1
  124. package/dist/worldSync.js +25 -4
  125. package/package.json +4 -4
  126. package/skills/ce-handoff/SKILL.md +2 -2
  127. package/skills/game-design/SKILL.md +11 -1
  128. package/skills/jgengine/SKILL.md +9 -5
  129. package/skills/jgengine/api.md +205 -101
  130. package/skills/jgengine/capabilities.md +56 -0
  131. package/skills/jgengine/recipes/minimal-game.md +3 -0
  132. package/skills/jgengine-ui/SKILL.md +20 -15
  133. package/skills/jgengine-ui/api.md +538 -326
  134. package/skills/jgengine-ui/capabilities.md +37 -0
  135. package/skills/jgengine-ui/reference-primitives.md +89 -0
  136. package/skills/jgengine-ui/reference.md +2 -78
  137. package/skills/jgengine-world/SKILL.md +21 -3
  138. package/skills/jgengine-world/api.md +1172 -625
  139. package/skills/jgengine-world/capabilities.md +229 -3
  140. package/skills/jgengine-world/recipes/character-animation.md +39 -0
  141. package/skills/jgengine-world/recipes/controls.md +44 -0
  142. package/skills/jgengine-world/recipes/flight-feel.md +76 -0
  143. package/skills/jgengine-world/recipes/npc-senses.md +43 -0
  144. package/skills/jgengine-world/recipes/vehicle-feel.md +85 -0
  145. package/skills/jgengine-world/reference.md +31 -2
  146. package/skills/jgengine-world/visibility.md +112 -0
  147. package/skills/level-design/SKILL.md +1 -1
  148. package/skills/jgengine-ui/references/visual-scorecard.md +0 -73
@@ -4,16 +4,32 @@
4
4
 
5
5
  ## @jgengine/core/ai/crowd
6
6
 
7
- - `CrowdField` (interface): interface CrowdField — ⚠ undocumented
8
- - `FlowField` (interface): interface FlowField — ⚠ undocumented
9
- - `FlowFieldOptions` (interface): interface FlowFieldOptions — ⚠ undocumented
10
- - `Poi` (interface): interface Poi — ⚠ undocumented
11
- - `SelectPoiOptions` (interface): interface SelectPoiOptions — ⚠ undocumented
7
+ - `CrowdField` (interface): interface CrowdField { enter(point: NavPoint): void; leave(point: NavPoint): void; count(point: NavPoint): number; cellCount(col: number, row: number): number; penalty(weight?: number): (col: number, row: number) => number; reset(): void } — ⚠ undocumented
8
+ - `FlowField` (interface): interface FlowField { readonly cols: number; readonly rows: number; cost(col: number, row: number): number; reachable(point: NavPoint): boolean; direction(point: NavPoint): NavPoint; next(point: NavPoint): NavPoint | null } — ⚠ undocumented
9
+ - `FlowFieldOptions` (interface): interface FlowFieldOptions { clearance?: number; congestion?: (col: number, row: number) => number } — ⚠ undocumented
10
+ - `Poi` (interface): interface Poi { id: string; point: NavPoint; appeal?: number; capacity?: number } — ⚠ undocumented
11
+ - `SelectPoiOptions` (interface): interface SelectPoiOptions { roll: number; occupancy?: (id: string) => number; distanceBias?: number; distance?: (from: NavPoint, poi: Poi) => number } — ⚠ undocumented
12
12
  - `VisitorLoop` (interface): interface VisitorLoop — Handle returned by {@link createVisitorLoop}: per-agent seek/travel/dwell/depart state machine.
13
13
  - `VisitorLoopOptions` (interface): interface VisitorLoopOptions — Config for {@link createVisitorLoop}: the POI catalog, dwell duration, and exit point every agent shares.
14
14
  - `VisitorPhase` (type): type VisitorPhase = "seeking" | "traveling" | "dwelling" | "departing" | "done" — A many-agent visitor's current step of the seek→travel→arrive→dwell→depart loop.
15
15
  - `VisitorStep` (interface): interface VisitorStep — One tick's result from a {@link VisitorLoop}: current phase, where to steer, and which POI it concerns.
16
16
 
17
+ ## @jgengine/core/ai/decisionGraph
18
+
19
+ - `Blackboard` (type): type Blackboard = Record<string, BlackboardValue> — Named facts available to conditions, utilities, and actions.
20
+ - `BlackboardValue` (type): type BlackboardValue = number | boolean | string — Scalar values stored in a decision graph blackboard.
21
+ - `DecisionAbort` (type): type DecisionAbort<Context = unknown> = ( action: string, ctx: Context, params: Record<string, BlackboardValue> | undefined, blackboard: Blackboard, ) => void — Called when an action that was running last tick is not reached this tick, so it can release what it holds.
22
+ - `DecisionAction` (type): type DecisionAction<Context = unknown> = ( ctx: Context, params: Record<string, BlackboardValue> | undefined, blackboard: Blackboard, ) => DecisionStatus — Callback implementation for an action node.
23
+ - `DecisionGraph` (type): type DecisionGraph = DecisionNode — Root node for a serializable AI decision graph.
24
+ - `DecisionGraphOptions` (interface): interface DecisionGraphOptions<Context = unknown> — Optional hooks and injected randomness for {@link createDecisionGraphRuntime}.
25
+ - `DecisionGraphRuntime` (interface): interface DecisionGraphRuntime<Context = unknown> — Stateful evaluator for a serializable decision graph.
26
+ - `DecisionGraphSnapshot` (interface): interface DecisionGraphSnapshot — Serializable state retained by an active decision graph. Fields besides `runningPath` are absent in older saves.
27
+ - `DecisionNode` (type): type DecisionNode = | { kind: "selector"; children: DecisionNode[]; memory?: boolean } | { kind: "sequence"; children: DecisionNode[]; memory?: boolean } | { kind: "condition"; key: string; op: DecisionOperator; value: BlackboardValue } | { kind: "action"; action: string; params?: Record<string, Bla… — Serializable decision node. - `selector` runs children in order until one does not fail; `sequence` until one does not finish. With `memory`, a composite whose child was running last tick resumes at that child instead of re-checking earlier ones. - `condition` compares a blackboard key; `action` calls a registered action. - `utility` runs the option with the highest weighted blackboard score. - `invert` swaps `done` and `failed`; `cooldown` fails for `seconds` after its child finishes; `wait` stays running for `seconds`; `random` picks a child by `weights` from the runtime's `rng` and keeps it while it runs.
28
+ - `DecisionNodeMemory` (interface): interface DecisionNodeMemory — Progress of a memory composite, `random` choice, or `wait` timer, keyed by node id (depth-first order).
29
+ - `DecisionOperator` (type): type DecisionOperator = "=" | "==" | "!=" | "<" | "<=" | ">" | ">=" | "eq" | "ne" | "lt" | "lte" | "gt" | "gte" — Comparison operators supported by decision conditions.
30
+ - `DecisionStatus` (type): type DecisionStatus = "running" | "done" | "failed" — Outcome reported when a decision graph evaluates.
31
+ - `createDecisionGraphRuntime` (function): function createDecisionGraphRuntime<Context = unknown>(graph: DecisionGraph, actions: Record<string, DecisionAction<Context>>, options: DecisionGraphOptions<Context> = {}): DecisionGraphRuntime<Context> — Creates a deterministic runtime for a serializable decision graph.
32
+
17
33
  ## @jgengine/core/ai/difficulty
18
34
 
19
35
  - `DIFFICULTY_TIERS` (const): const DIFFICULTY_TIERS: Readonly<Record<DifficultyTier, DifficultyProfile>> — The canonical easy/standard/expert profiles. Frozen — use {@link difficultyProfile} to derive a tweaked copy instead of mutating.
@@ -44,16 +60,17 @@
44
60
 
45
61
  ## @jgengine/core/ai/flock
46
62
 
47
- - `FlockAgent` (interface): interface FlockAgent — ⚠ undocumented
48
- - `FlockConfig` (interface): interface FlockConfig — ⚠ undocumented
49
- - `FlockStepAgent` (interface): interface FlockStepAgent — ⚠ undocumented
63
+ - `FlockAgent` (interface): interface FlockAgent { position: FlockVec3; velocity: FlockVec3 } — ⚠ undocumented
64
+ - `FlockConfig` (interface): interface FlockConfig { maxSpeed: number; accel?: number; separationRadius: number; separationWeight?: number; neighborRadius: number; cohesionWeight?: number; alignmentWeight?: number; seekWeight?: number; stragglerRadius?: number; stragglerBoost?: number } — ⚠ undocumented
65
+ - `FlockStepAgent` (interface): interface FlockStepAgent { position: FlockVec3; velocity: FlockVec3 } — ⚠ undocumented
50
66
  - `FlockVec3` (type): type FlockVec3 = readonly [number, number, number] — ⚠ undocumented
51
67
 
52
68
  ## @jgengine/core/ai/groupAssist
53
69
 
54
- - `AssistMember` (interface): interface AssistMember — ⚠ undocumented
55
- - `AssistNetwork` (interface): interface AssistNetwork — ⚠ undocumented
56
- - `AssistNetworkConfig` (interface): interface AssistNetworkConfig — ⚠ undocumented
70
+ - `AssistMember` (interface): interface AssistMember { id: string; groupId: string; table: ThreatTable } — ⚠ undocumented
71
+ - `AssistNetwork` (interface): interface AssistNetwork { register(member: AssistMember): void; remove(memberId: string): void; memberIds(groupId?: string): string[]; assistersOf(memberId: string): string[]; addThreat(memberId: string, sourceId: string, amount: number): string[]; snapshot(): Ass… — ⚠ undocumented
72
+ - `AssistNetworkConfig` (interface): interface AssistNetworkConfig { radius?: number; shareFraction?: number; distanceBetween?: (a: string, b: string) => number } — ⚠ undocumented
73
+ - `AssistNetworkState` (interface): interface AssistNetworkState — Plain JSON membership of an {@link AssistNetwork}, in registration order; threat lives in each member's own table.
57
74
 
58
75
  ## @jgengine/core/ai/heatSystem
59
76
 
@@ -82,28 +99,32 @@
82
99
 
83
100
  ## @jgengine/core/ai/jobBoard
84
101
 
85
- - `Job` (interface): interface Job — ⚠ undocumented
86
- - `JobBoard` (interface): interface JobBoard — ⚠ undocumented
87
- - `JobDef` (interface): interface JobDef — ⚠ undocumented
102
+ - `Job` (interface): interface Job { id: string; station: NavPoint; work: number; priority: number; arriveRadius: number; repeat: boolean; worker: string | null } — ⚠ undocumented · used by `activeJobs` (@jgengine/core/gameplay): Jobs currently progressing.
103
+ - `JobBoard` (interface): interface JobBoard { post(job: JobDef): string; cancel(jobId: string): boolean; assign(workerId: string, jobId: string): boolean; claim(workerId: string): string | null; release(workerId: string): void; advance(workerId: string, dt: number, ctx: JobTickContex… — ⚠ undocumented
104
+ - `JobDef` (interface): interface JobDef { id?: string; station: NavPoint; work: number; priority?: number; arriveRadius?: number; repeat?: boolean } — ⚠ undocumented
88
105
  - `JobPhase` (type): type JobPhase = "idle" | "travelling" | "working" | "done" — ⚠ undocumented
89
- - `JobReport` (interface): interface JobReport — ⚠ undocumented
90
- - `JobTickContext` (interface): interface JobTickContext — ⚠ undocumented
91
- - `WorkerState` (interface): interface WorkerState — ⚠ undocumented
106
+ - `JobReport` (interface): interface JobReport { jobId: string; workerId: string; cycle: number } — ⚠ undocumented
107
+ - `JobTickContext` (interface): interface JobTickContext { distanceToStation: number } — ⚠ undocumented
108
+ - `WorkerState` (interface): interface WorkerState { jobId: string | null; phase: JobPhase; worked: number; cycles: number } — ⚠ undocumented
92
109
 
93
110
  ## @jgengine/core/ai/laneSelect
94
111
 
95
- - `LaneCandidate` (interface): interface LaneCandidate<TId extends string = string> — ⚠ undocumented
96
- - `PickLaneOptions` (interface): interface PickLaneOptions<TId extends string = string> — ⚠ undocumented
112
+ - `LaneCandidate` (interface): interface LaneCandidate<TId extends string = string> { id: TId; cost: number } — ⚠ undocumented
113
+ - `PickLaneOptions` (interface): interface PickLaneOptions<TId extends string = string> { current?: TId | null; stickiness?: number; tieEpsilon?: number; rng?: () => number } — ⚠ undocumented
97
114
 
98
115
  ## @jgengine/core/ai/mobBrain
99
116
 
100
117
  - `MobBrain` (interface): interface MobBrain — The wander → aggro → chase → engage → leash-evade loop every MMO-shaped game hand-rolls, composed over `ai/threat`. The brain decides intent; the game executes it (`moveToward`, ground-snap, facing, swings) and routes damage into `addThreat`. Pack aggro is game-side: call `addThreat` on nearby packmates' brains when one aggros.
101
- - `MobBrainConfig` (interface): interface MobBrainConfig — ⚠ undocumented
102
- - `MobBrainDeps` (interface): interface MobBrainDeps — ⚠ undocumented
118
+ - `MobBrainConfig` (interface): interface MobBrainConfig { aggroRadius: number; attackRange: number; leashDistance: number; wander?: MobWanderConfig | false; evadeSpeedScale?: number; stickiness?: number; homeArriveRadius?: number; threat?: ThreatTableConfig } — ⚠ undocumented
119
+ - `MobBrainDeps` (interface): interface MobBrainDeps { home: MobVec3; position(): MobVec3 | null; targetPosition(targetId: string): MobVec3 | null; candidates(): readonly string[]; rng?: () => number } — ⚠ undocumented
103
120
  - `MobBrainMode` (type): type MobBrainMode = "idle" | "wander" | "chase" | "engage" | "evade" — ⚠ undocumented
104
- - `MobBrainStep` (interface): interface MobBrainStep — ⚠ undocumented
121
+ - `MobBrainStep` (interface): interface MobBrainStep { mode: MobBrainMode; targetId: string | null; moveTo: MobVec3 | null; speedScale: number; inAttackRange: boolean; arrivedHome: boolean } — ⚠ undocumented
105
122
  - `MobVec3` (type): type MobVec3 = readonly [number, number, number] — ⚠ undocumented
106
- - `MobWanderConfig` (interface): interface MobWanderConfig — ⚠ undocumented
123
+ - `MobWanderConfig` (interface): interface MobWanderConfig { radius: number; intervalSeconds?: number; speedScale?: number; arriveRadius?: number } — ⚠ undocumented
124
+
125
+ ## @jgengine/core/ai/mobBrainGraph
126
+
127
+ - `mobBrainGraph` (const): const mobBrainGraph: DecisionGraph — Graph-shaped description of the mob brain's idle, wander, chase, engage, and evade decisions.
107
128
 
108
129
  ## @jgengine/core/ai/populationDirector
109
130
 
@@ -128,16 +149,16 @@
128
149
 
129
150
  ## @jgengine/core/ai/spawnDirector
130
151
 
131
- - `DirectorContext` (interface): interface DirectorContext — ⚠ undocumented
132
- - `DirectorStep` (interface): interface DirectorStep — ⚠ undocumented
133
- - `SpawnDirectorConfig` (interface): interface SpawnDirectorConfig — ⚠ undocumented
134
- - `SpawnDirectorState` (interface): interface SpawnDirectorState — ⚠ undocumented
135
- - `SpawnEntry` (interface): interface SpawnEntry — ⚠ undocumented
152
+ - `DirectorContext` (interface): interface DirectorContext { alive: number; players?: number; playerPositions?: readonly NavPoint[] } — ⚠ undocumented
153
+ - `DirectorStep` (interface): interface DirectorStep { state: SpawnDirectorState; spawns: SpawnRequest[] } — ⚠ undocumented
154
+ - `SpawnDirectorConfig` (interface): interface SpawnDirectorConfig { waves: readonly WaveManifest[]; maxAlive?: number; escalationPerSecond?: number; alertBudgetPerSecond?: number; alertDecayPerSecond?: number; playerBudgetPerSecond?: number; maxSpawnsPerTick?: number; loop?: boolean; seed?: number; spawnP… — ⚠ undocumented
155
+ - `SpawnDirectorState` (interface): interface SpawnDirectorState { wave: number; elapsed: number; waveElapsed: number; budget: number; alert: number; spawnedThisWave: number; spawnedTotal: number; rng: RandomSeed; done: boolean } — ⚠ undocumented
156
+ - `SpawnEntry` (interface): interface SpawnEntry { id: string; cost: number; weight?: number; minWave?: number } — ⚠ undocumented
136
157
  - `SpawnPointBiasStrength` (type): type SpawnPointBiasStrength = "subtle" | "moderate" | "strong" — How strongly `distanceBias` weights candidates by distance from `avoid` — a named intent, not a weighting exponent.
137
158
  - `SpawnPointDistanceBias` (type): type SpawnPointDistanceBias = "near" | "far" | "none" — Preference for picking a spawn point relative to `avoid` positions: closer, farther, or unweighted.
138
159
  - `SpawnPointSelectionOptions` (interface): interface SpawnPointSelectionOptions — Semantic options for selecting a spawn point without exposing weighting internals.
139
- - `SpawnRequest` (interface): interface SpawnRequest — ⚠ undocumented
140
- - `WaveManifest` (interface): interface WaveManifest — ⚠ undocumented
160
+ - `SpawnRequest` (interface): interface SpawnRequest { entryId: string; cost: number; wave: number; point?: NavPoint; laneId?: number } — ⚠ undocumented
161
+ - `WaveManifest` (interface): interface WaveManifest { budget: number; entries: readonly SpawnEntry[]; duration?: number; budgetPerSecond?: number } — ⚠ undocumented
141
162
  - `advanceSpawnDirector` (function): function advanceSpawnDirector(config: SpawnDirectorConfig, state: SpawnDirectorState, dt: number, ctx: DirectorContext): DirectorStep — ⚠ undocumented
142
163
  - `advanceWave` (function): function advanceWave(config: SpawnDirectorConfig, state: SpawnDirectorState): SpawnDirectorState — ⚠ undocumented
143
164
  - `createSpawnDirectorState` (function): function createSpawnDirectorState(config: SpawnDirectorConfig): SpawnDirectorState — ⚠ undocumented
@@ -149,6 +170,14 @@
149
170
  - `SpawnPointDistanceBias` (type): type SpawnPointDistanceBias = "near" | "far" | "none" — Preference for picking a spawn point relative to `avoid` positions: closer, farther, or unweighted.
150
171
  - `SpawnPointSelectionOptions` (interface): interface SpawnPointSelectionOptions — Semantic options for selecting a spawn point without exposing weighting internals.
151
172
 
173
+ ## @jgengine/core/ai/tacticalQueries
174
+
175
+ - `ScoredPosition` (interface): interface ScoredPosition — A candidate position with its deterministic weighted tactical score.
176
+ - `TacticalPositionEvaluators` (interface): interface TacticalPositionEvaluators — Functions that score one candidate position; higher values are preferred.
177
+ - `TacticalPositionWeights` (interface): interface TacticalPositionWeights — Weights and a hard bound for tactical candidate scoring.
178
+ - `coverPoints` (function): function coverPoints(mesh: NavMeshData, threatPos: Vec3, losBlocked: (a: Vec3, b: Vec3) => boolean): Vec3[] — Returns boundary locations that are hidden from a threat.
179
+ - `scorePositions` (function): function scorePositions(points: readonly Vec3[], evaluators: TacticalPositionEvaluators, weights: TacticalPositionWeights = {}): ScoredPosition[] — Score positions and retain at most `maxCandidates`, ordered highest score first.
180
+
152
181
  ## @jgengine/core/ai/targetAcquisition
153
182
 
154
183
  - `AcquisitionEnvelope` (type): type AcquisitionEnvelope = number | ((selfId: string, candidateId: string) => number) — Composable target acquisition: the "which enemy do I lock onto?" decision split into the independent concerns every aggro system tangles together — a bounded candidate provider, an eligibility filter, a per-pair acquisition envelope (dynamic range), a perception/LOS gate, scoring, deterministic tie-break, and retention hysteresis. This owns *policy*; threat, brains, and movement stay separate. Feed `candidates` a spatial-index query, never a full-world scan.
@@ -161,10 +190,11 @@
161
190
 
162
191
  ## @jgengine/core/ai/threat
163
192
 
164
- - `HighestThreatOptions` (interface): interface HighestThreatOptions — ⚠ undocumented
165
- - `ThreatEntry` (interface): interface ThreatEntry — ⚠ undocumented
166
- - `ThreatTable` (interface): interface ThreatTable — ⚠ undocumented
167
- - `ThreatTableConfig` (interface): interface ThreatTableConfig — ⚠ undocumented
193
+ - `HighestThreatOptions` (interface): interface HighestThreatOptions { current?: string | null; stickiness?: number } — ⚠ undocumented
194
+ - `ThreatEntry` (interface): interface ThreatEntry { sourceId: string; threat: number } — ⚠ undocumented
195
+ - `ThreatTable` (interface): interface ThreatTable { add(sourceId: string, amount: number): number; set(sourceId: string, amount: number): void; threatOf(sourceId: string): number; decay(dt: number): void; highest(options?: HighestThreatOptions): string | null; ranked(): ThreatEntry[]; taun… — ⚠ undocumented
196
+ - `ThreatTableConfig` (interface): interface ThreatTableConfig { decayPerSecond?: number; max?: number; forgetBelow?: number } — ⚠ undocumented
197
+ - `ThreatTableState` (interface): interface ThreatTableState — Plain JSON state of a {@link ThreatTable}; `entries` keeps insertion order, which breaks ties in `highest`.
168
198
  - `createThreatTable` (function): function createThreatTable(config: ThreatTableConfig = {}): ThreatTable — ⚠ undocumented
169
199
 
170
200
  ## @jgengine/core/ai/waveRunner
@@ -175,10 +205,72 @@
175
205
  - `WaveView` (interface): interface WaveView — A pooled, per-frame readout of the current wave — the "brain behind WAVE 3". Reused across {@link WaveRunner.view} calls (never per-frame allocated), so read it and render it, don't retain it.
176
206
  - `createWaveRunner` (function): function createWaveRunner(config: WaveRunnerConfig): WaveRunner — A thin, stateful, observable wrapper around the seeded {@link createSpawnDirectorState} / {@link advanceSpawnDirector} model. It OWNS a {@link SpawnDirectorState}, ticks it from `update(dt, ctx?)`, keeps the new state, and forwards each emitted {@link SpawnRequest} to an optional `onSpawn` sink so the model never instantiates entities. `view()` returns a pooled per-frame readout — the "brain behind WAVE 3": the 1-based wave number, wave progress `0..1`, banked budget, per-wave and total spawn counts, alert, and done flag. `forceNextWave` / `raiseAlert` drive it, `subscribe` observes it, and `snapshot`/`restore` round-trip the plain serializable state object through a save. Nothing here is genre-specific: spawn-entry `kind`s (the director's `entryId`s) stay free strings the runner never interprets.
177
207
 
208
+ ## @jgengine/core/anim/animGraph
209
+
210
+ - `ANIM_PARAMS_KEY` (const): const ANIM_PARAMS_KEY: "anim.params" — Entity blackboard key the shell reads extra graph parameters from: `ctx.scene.entity.blackboard.set(id, ANIM_PARAMS_KEY, { aiming: true })`.
211
+ - `AnimClipOutput` (interface): interface AnimClipOutput — One clip's contribution: weight 0..1 and the time to seek it to.
212
+ - `AnimCompare` (type): type AnimCompare = ">" | "<" | ">=" | "<=" | "==" | "!=" — Comparison operators an {@link AnimCondition} supports.
213
+ - `AnimCondition` (interface): interface AnimCondition — A parameter comparison; every condition on a transition must hold.
214
+ - `AnimEvent` (interface): interface AnimEvent — A named moment inside a clip (foot plant, hit frame, reload point).
215
+ - `AnimGraph` (interface): interface AnimGraph — Serializable animation graph. Clip durations come from the rig at runtime (see {@link AnimGraphClipInfo}).
216
+ - `AnimGraphClipInfo` (type): type AnimGraphClipInfo = Readonly<Record<string, number | { duration: number; rootTrack?: { times: Float32Array; values: Float32Array } }>> — Per-clip duration in seconds, read from the loaded rig.
217
+ - `AnimGraphOutput` (interface): interface AnimGraphOutput — What one advance asks the rig to show.
218
+ - `AnimGraphRuntime` (interface): interface AnimGraphRuntime — The evaluator handle: arm triggers, advance, inspect, snapshot and restore.
219
+ - `AnimGraphState` (interface): interface AnimGraphState — Serializable evaluator state.
220
+ - `AnimLayer` (interface): interface AnimLayer — A blend layer with its own state machine. Masked layers apply only to bones whose track names start with a prefix.
221
+ - `AnimParamValue` (type): type AnimParamValue = number | boolean — Parameter value a graph reads: floats for blends and comparisons, booleans for gates.
222
+ - `AnimParams` (type): type AnimParams = Readonly<Record<string, AnimParamValue>> — The parameter set a graph evaluates against each advance.
223
+ - `AnimState` (type): type AnimState = | { kind: "clip"; clip: string; speed?: number; loop?: boolean; rootMotion?: boolean } | { kind: "blend1D"; param: string; points: readonly { at: number; clip: string }[]; speed?: number; loop?: boolean; rootMotion?: boolean } | { kind: "blend2D"; params: readonly [string, string]; … — A state plays one clip, or blends clips by one or two parameters.
224
+ - `AnimTransition` (interface): interface AnimTransition — Edge between states. `from: "*"` matches any state except `to`.
225
+ - `createAnimGraphRuntime` (function): function createAnimGraphRuntime(initial: AnimGraph): AnimGraphRuntime — Headless animation state machine and blend evaluator. It owns every clip's playback time and weight, so the renderer only seeks and weights actions on a mixer, and headless hosts, replays, and tests advance the same graph without three.js. Transitions are data (parameter comparisons and consumed triggers), layers can be masked or additive, and events fire by clip time, including across loop wraps.
226
+ - `parseAnimGraph` (function): function parseAnimGraph(value: unknown): AnimGraph | undefined — Validates untrusted JSON (a saved scene document, a network payload) as an {@link AnimGraph}. Malformed states, transitions to unknown states, and bad conditions are dropped; a layer whose entry state is missing is dropped; the result is `undefined` when no layer survives.
227
+ - `stateClipWeights` (function): function stateClipWeights(state: AnimState, params: AnimParams): Record<string, number> — Static clip weights of a state at `params`, before any crossfade.
228
+
229
+ ## @jgengine/core/anim/boneTexture
230
+
231
+ - `BoneTextureClip` (interface): interface BoneTextureClip — One baked clip's rows in a {@link BoneTextureLayout}.
232
+ - `BoneTextureClipInput` (interface): interface BoneTextureClipInput — A clip to bake: its name and length in seconds.
233
+ - `BoneTextureInput` (interface): interface BoneTextureInput — Inputs for {@link planBoneTexture}.
234
+ - `BoneTextureLayout` (interface): interface BoneTextureLayout — Where every bone matrix of every baked frame lives in a vertex-animation texture: one row per frame, four RGBA texels (matrix columns) per bone. Plain data, so a baked crowd can be cached, shipped or checked in a test without a renderer.
235
+ - `BoneTextureSample` (interface): interface BoneTextureSample — Two texture rows around a playback time and the blend between them.
236
+ - `planBoneTexture` (function): function planBoneTexture(input: BoneTextureInput): BoneTextureLayout — Plans a bone-matrix texture for a rig's clips. Throws when the rig or the clip set does not fit `maxTextureSize`; lower `fps` or bake fewer clips.
237
+ - `sampleBoneTexture` (function): function sampleBoneTexture(clip: BoneTextureClip, fps: number, time: number, loop: boolean, out?: BoneTextureSample): BoneTextureSample — Finds the baked rows around `time` in a clip, wrapping when `loop` and holding the last pose otherwise. This is the CPU mirror of the crowd shader's lookup.
238
+
178
239
  ## @jgengine/core/anim/easing
179
240
 
180
241
  - `Easing` (type): type Easing = (t: number) => number — ⚠ undocumented
181
242
 
243
+ ## @jgengine/core/anim/footPlacement
244
+
245
+ - `FootGroundSample` (interface): interface FootGroundSample — One foot's animated ankle height and the ground found under it, both in world units.
246
+ - `FootPlacement` (interface): interface FootPlacement — Result of {@link placeFeet}: where each ankle should go and how far the pelvis drops.
247
+ - `FootPlacementInput` (interface): interface FootPlacementInput — Inputs for {@link placeFeet}. All heights are world units.
248
+ - `LegChain` (interface): interface LegChain — Thigh → shin → foot bone names for one leg.
249
+ - `RigBone` (interface): interface RigBone — A bone as {@link inferLegChains} sees it: its name and its parent's name.
250
+ - `inferLegChains` (function): function inferLegChains(bones: readonly RigBone[]): LegChain[] — Finds leg chains on a humanoid rig by bone name: a thigh-like bone (`UpLeg`, `UpperLeg`, `Thigh`) with its first child and grandchild as shin and foot. Control, IK-target and twist bones are skipped. Returns chains in rig order; an empty array means the rig has no recognizable legs.
251
+ - `placeFeet` (function): function placeFeet(input: FootPlacementInput, out?: FootPlacement): FootPlacement — Resolves foot placement for a rig whose clips were authored on flat ground at its origin. Each foot keeps its animated lift and moves by its ground's height above or below the origin, the sole is never left under the ground, and the pelvis drops by the deepest reach so both legs stay within length. Pure and allocation-light; the renderer applies the targets with {@link solveTwoBone}.
252
+
253
+ ## @jgengine/core/anim/ikSolver
254
+
255
+ - `FabrikOptions` (interface): interface FabrikOptions — Iteration budget and convergence threshold for {@link solveFabrik}.
256
+ - `LookAtInput` (interface): interface LookAtInput — Inputs for {@link lookAt}. Angles are in radians.
257
+ - `MutableVec3` (type): type MutableVec3 = [number, number, number] — A mutable three-dimensional tuple used by allocation-aware solver outputs.
258
+ - `Quat` (type): type Quat = readonly [number, number, number, number] — A quaternion in `(x, y, z, w)` order.
259
+ - `TwoBoneInput` (interface): interface TwoBoneInput — Inputs for {@link solveTwoBone}.
260
+ - `TwoBoneOutput` (interface): interface TwoBoneOutput — Reused output buffers filled by {@link solveTwoBone}.
261
+ - `Vec3` (type): type Vec3 = readonly [number, number, number] — A three-dimensional point or direction represented without a renderer dependency.
262
+ - `lookAt` (function): function lookAt(input: LookAtInput): Quat — Returns a quaternion that points a +Z bone from `from` toward `target`, with optional yaw and pitch limits.
263
+ - `solveFabrik` (function): function solveFabrik(chain: readonly Vec3[], target: Vec3, options: FabrikOptions = {}): MutableVec3[] — Solves a chain with the FABRIK forward-and-backward reaching algorithm. Returned tuples are new values; the input chain is not modified.
264
+ - `solveTwoBone` (function): function solveTwoBone(input: TwoBoneInput, out: TwoBoneOutput): TwoBoneOutput — Solves a two-segment chain analytically, placing the middle and tip joints toward `target` and `pole`. The root remains fixed, and unreachable targets are clamped to the chain's maximum reach.
265
+
266
+ ## @jgengine/core/anim/locomotionGraph
267
+
268
+ - `LOCOMOTION_LAYER` (const): const LOCOMOTION_LAYER: "base" — Layer id the locomotion graph uses; query `runtime.stateOf(LOCOMOTION_LAYER)`.
269
+ - `LOCOMOTION_SPEED_PARAM` (const): const LOCOMOTION_SPEED_PARAM: "speed" — The parameter name the shell feeds with the entity's smoothed ground speed.
270
+ - `LocomotionGraphInput` (interface): interface LocomotionGraphInput — Inputs for {@link locomotionGraph}: the idle/walk/run clip names and the one-shot table a rig config already carries.
271
+ - `animGraphFromConfig` (function): function animGraphFromConfig(config: ModelAnimationConfig): AnimGraph | undefined — The graph a model animation config plays: its `graph`, or the {@link locomotionGraph} its `states` and `oneShots` describe (a `string[]` one-shot uses its first variant). `undefined` for a single-clip config. The shell plays this and the editor inspects it, so both see the same graph.
272
+ - `locomotionGraph` (function): function locomotionGraph(input: LocomotionGraphInput): AnimGraph — The engine's default locomotion as an authored graph: a speed-driven blend between idle, walk, and run, plus a state per one-shot that plays once and returns (or clamps for `death`). What `useModelAnimation` used to hardcode.
273
+
182
274
  ## @jgengine/core/area/areaEffectField
183
275
 
184
276
  - `AreaEffectEvent` (interface): interface AreaEffectEvent<P> — One membership edge emitted by `step`, `removeSource`, or `clear`.
@@ -204,15 +296,32 @@
204
296
 
205
297
  ## @jgengine/core/audio/audioFalloff
206
298
 
207
- - `AudioBusDef` (interface): interface AudioBusDef — ⚠ undocumented
299
+ - `AudioBusDef` (interface): interface AudioBusDef { id: AudioBusId; gain?: number } — ⚠ undocumented
208
300
  - `AudioBusId` (type): type AudioBusId = string — ⚠ undocumented
209
- - `AudioFalloffConfig` (interface): interface AudioFalloffConfig — ⚠ undocumented
301
+ - `AudioFalloffConfig` (interface): interface AudioFalloffConfig { minDistance?: number; maxDistance?: number; curve?: FalloffCurve } — ⚠ undocumented
210
302
  - `FalloffCurve` (type): type FalloffCurve = "linear" | "inverse" | "none" — ⚠ undocumented
211
- - `SoundDef` (interface): interface SoundDef — ⚠ undocumented
303
+ - `SoundDef` (interface): interface SoundDef { id: string; url?: string; synth?: SynthPatch; bus: AudioBusId; gain?: number; loop?: boolean; positional?: boolean; falloff?: AudioFalloffConfig; doppler?: number; spatial?: {panning: "hrtf" | "equalpower"; refDistance?: number; maxDistan… — ⚠ undocumented
212
304
  - `computeFalloffGain` (function): function computeFalloffGain(distance: number, config: AudioFalloffConfig = {}): number — ⚠ undocumented
213
305
  - `distance3` (function): function distance3(a: { x: number; y: number; z: number }, b: { x: number; y: number; z: number }): number — ⚠ undocumented
214
306
  - `resolveEmitterGain` (function): function resolveEmitterGain(distance: number, sound: Pick<SoundDef, "gain" | "positional" | "falloff">, busGain: number): number — ⚠ undocumented
215
307
 
308
+ ## @jgengine/core/audio/doppler
309
+
310
+ - `DopplerOptions` (interface): interface DopplerOptions — Options for {@link dopplerRate}.
311
+ - `SPEED_OF_SOUND` (const): const SPEED_OF_SOUND: 343 — Speed of sound in air at 20 °C, metres per second — the default for {@link dopplerRate}.
312
+ - `dopplerRate` (function): function dopplerRate(listenerPosition: Vec3Tuple, listenerVelocity: Vec3Tuple, emitterPosition: Vec3Tuple, emitterVelocity: Vec3Tuple, options: DopplerOptions = {}): number — Doppler pitch multiplier for an emitter heard by a listener: `(c + vListener) / (c - vEmitter)`, where each speed is the component along the line between them, positive when closing. Multiply a loop's playback rate by it. Pure and allocation-free.
313
+
314
+ ## @jgengine/core/audio/engineLayers
315
+
316
+ - `EngineLayer` (interface): interface EngineLayer — One recorded engine sample, keyed by the rpm it was recorded at.
317
+ - `EngineLayerMix` (interface): interface EngineLayerMix — One layer's live mix.
318
+ - `EngineLayers` (interface): interface EngineLayers — A layered engine loop: N rpm-keyed samples crossfaded by rpm, with on- and off-load sets picked by engine load.
319
+ - `EngineLayersAudio` (interface): interface EngineLayersAudio — The part of `ctx.game.audio` {@link EngineLayers} drives.
320
+ - `EngineLayersConfig` (interface): interface EngineLayersConfig — Config for {@link createEngineLayers}.
321
+ - `EngineLayersPlayOptions` (interface): interface EngineLayersPlayOptions — Per-tick parameters {@link EngineLayers.play} forwards to every layer's loop.
322
+ - `EngineLayersState` (interface): interface EngineLayersState — Serializable {@link EngineLayers} state.
323
+ - `createEngineLayers` (function): function createEngineLayers(initial: EngineLayersConfig): EngineLayers — Layered engine sound: each set of rpm-keyed samples is equal-power crossfaded between the two samples bracketing the current rpm and pitched by `rpm / layer.rpm`; the on- and off-load sets are equal-power crossfaded by smoothed `engineLoad`. A config with only one load set plays it at every load. `play` drives `ctx.game.audio` directly, so a game needs no per-layer glue.
324
+
216
325
  ## @jgengine/core/audio/music
217
326
 
218
327
  - `MusicInstrument` (type): type MusicInstrument = | "strings" | "flute" | "harp" | "horn" | "choir" | "bell" | "timpani" | "bass" | "stacc" | "pad" | "lute" | "dulcimer" | "frameDrum" | "warDrum" | "reed" | "pipe" | "squareLead" | "woodBlock" | "tinyBell" | "piano" | "shaker" | "brassStab" | "cymSwell" | "oboe" — Named synthesised instrument. Each maps to a voice in the shell's instrument library (`@jgengine/shell/audio/musicVoices`); an unknown name falls back to a plain sine voice so a theme is never silent.
@@ -254,21 +363,22 @@
254
363
 
255
364
  ## @jgengine/core/faction/factions
256
365
 
257
- - `FactionDef` (interface): interface FactionDef — ⚠ undocumented
258
- - `FactionGraph` (interface): interface FactionGraph — ⚠ undocumented
259
- - `FactionGraphConfig` (interface): interface FactionGraphConfig — ⚠ undocumented
366
+ - `FactionDef` (interface): interface FactionDef { id: string; relations?: Readonly<Record<string, FactionRelation>>; towardSelf?: FactionRelation; towardOthers?: FactionRelation } — ⚠ undocumented
367
+ - `FactionGraph` (interface): interface FactionGraph { relationBetween(observer: string | null | undefined, other: string | null | undefined): FactionRelation; isHostile(observer: string | null | undefined, other: string | null | undefined): boolean; isFriendly(observer: string | null | undef… — ⚠ undocumented
368
+ - `FactionGraphConfig` (interface): interface FactionGraphConfig { factions: readonly FactionDef[]; symmetric?: boolean; unaligned?: FactionRelation } — ⚠ undocumented
260
369
  - `FactionRelation` (type): type FactionRelation = "hostile" | "neutral" | "friendly" — ⚠ undocumented
261
- - `FactionRoster` (interface): interface FactionRoster — ⚠ undocumented
370
+ - `FactionRoster` (interface): interface FactionRoster { assign(entityId: string, factionId: string | null): void; factionOf(entityId: string): string | null; relationBetweenEntities(observer: string, other: string): FactionRelation; isHostile(observer: string, other: string): boolean; isFriend… — ⚠ undocumented
262
371
  - `createFactionGraph` (function): function createFactionGraph(config: FactionGraphConfig): FactionGraph — ⚠ undocumented
263
372
  - `createFactionRoster` (function): function createFactionRoster(graph: FactionGraph): FactionRoster — ⚠ undocumented
264
373
 
265
374
  ## @jgengine/core/faction/reputation
266
375
 
267
376
  - `DEFAULT_REPUTATION_TIERS` (const): const DEFAULT_REPUTATION_TIERS: readonly ReputationTier[] — ⚠ undocumented
268
- - `EffectiveRelationInput` (interface): interface EffectiveRelationInput — ⚠ undocumented
269
- - `ReputationLedger` (interface): interface ReputationLedger — ⚠ undocumented
270
- - `ReputationLedgerConfig` (interface): interface ReputationLedgerConfig — ⚠ undocumented
271
- - `ReputationTier` (interface): interface ReputationTier — ⚠ undocumented
377
+ - `EffectiveRelationInput` (interface): interface EffectiveRelationInput { base: FactionRelation; ledger: ReputationLedger; actorId: string; factionId: string } — ⚠ undocumented
378
+ - `ReputationLedger` (interface): interface ReputationLedger { standing(actorId: string, factionId: string): number; hasStanding(actorId: string, factionId: string): boolean; gain(actorId: string, factionId: string, amount: number): number; set(actorId: string, factionId: string, standing: number): n… — ⚠ undocumented
379
+ - `ReputationLedgerConfig` (interface): interface ReputationLedgerConfig { tiers?: readonly ReputationTier[]; initial?: Readonly<Record<string, number>>; min?: number; max?: number } — ⚠ undocumented
380
+ - `ReputationLedgerState` (interface): interface ReputationLedgerState — Plain JSON standings of a {@link ReputationLedger}: stored values only, `initial` stays config.
381
+ - `ReputationTier` (interface): interface ReputationTier { id: string; min: number; relation: FactionRelation } — ⚠ undocumented · used by `tierForStanding`: Map a faction standing value to its named reputation tier.
272
382
  - `createReputationLedger` (function): function createReputationLedger(config: ReputationLedgerConfig = {}): ReputationLedger — ⚠ undocumented
273
383
  - `effectiveRelation` (function): function effectiveRelation(input: EffectiveRelationInput): FactionRelation — ⚠ undocumented
274
384
  - `tierForStanding` (function): function tierForStanding(tiers: readonly ReputationTier[], standing: number): ReputationTier — Map a faction standing value to its named reputation tier.
@@ -278,27 +388,48 @@
278
388
  - `ActionBinding` (interface): interface ActionBinding<TCode extends string = string> — Action-binding model: games bind semantic actions ("jump", "interact") to physical control codes; capture layers resolve raw events through this map so gameplay code never sees keycodes. Control codes are plain strings, so the same model serves keyboard codes, mouse buttons, touch controls, or gamepad inputs.
279
389
  - `ActionBindingConfig` (type): type ActionBindingConfig<TCode extends string = string> = ActionBinding<TCode>[] | ActionBindingModes<TCode> — ⚠ undocumented
280
390
  - `ActionBindingMap` (type): type ActionBindingMap<TAction extends string, TCode extends string = string> = Record< TAction, ActionBinding<TCode> > — ⚠ undocumented
281
- - `ActionBindingModes` (interface): interface ActionBindingModes<TCode extends string = string> — ⚠ undocumented
391
+ - `ActionBindingModes` (interface): interface ActionBindingModes<TCode extends string = string> { hold?: ActionBinding<TCode>[]; toggle?: ActionBinding<TCode>[] } — ⚠ undocumented
282
392
  - `ActionCodes` (type): type ActionCodes<TCode extends string = string> = | readonly TCode[] | { hold?: readonly TCode[]; toggle?: readonly TCode[]; repeatMs?: number } — ⚠ undocumented
283
- - `ActionCodesMap` (type): type ActionCodesMap<TAction extends string = string, TCode extends string = string> = Record< TAction, ActionCodes<TCode> > — Maps each game action name to the input codes (hold/toggle keys, repeat rate) that trigger it.
393
+ - `ActionCodesMap` (type): type ActionCodesMap<TAction extends string = string, TCode extends string = string> = Record< TAction, ActionCodes<TCode> > — Maps each game action name to the input codes (hold/toggle keys, repeat rate) that trigger it. In a `defineGame({ input })`, pressing an action runs the same-named command with `{ yaw, pitch, aim }`; `repeatMs` re-fires it while held (automatic weapons).
284
394
  - `ActionStateBindingMap` (type): type ActionStateBindingMap<TAction extends string, TCode extends string = string> = Record< TAction, ActionBindingConfig<TCode> > — ⚠ undocumented
285
- - `ActionStateTracker` (interface): interface ActionStateTracker<TAction extends string> — ⚠ undocumented
286
- - `ShouldDispatchActionInput` (interface): interface ShouldDispatchActionInput — ⚠ undocumented
395
+ - `ActionStateTracker` (interface): interface ActionStateTracker<TAction extends string> { handleDown(code: string): TAction | null; handleUp(code: string): TAction | null; isDown(action: TAction): boolean; wasPressed(action: TAction): boolean; endFrame(): void; reset(): void; rebind(map: ActionStateBindingMap<TAction, string>)… — ⚠ undocumented · used by `rebindGamepadPoll` (@jgengine/shell/input/gamepadPoll): Swap the pad bindings mid-game (a context push) without touching keyboard state: release the codes of pad-held actions whose pad codes chang…
396
+ - `ShouldDispatchActionInput` (interface): interface ShouldDispatchActionInput { pressed: boolean; down: boolean; repeatMs: number | undefined; lastFiredAt: number | null; now: number } — ⚠ undocumented
397
+
398
+ ## @jgengine/core/input/actionContexts
399
+
400
+ - `ActionContext` (interface): interface ActionContext — Named action-binding layer that may optionally expose lower layers.
401
+ - `ActionContextAxisShape` (type): type ActionContextAxisShape = Omit<AxisShapeConfig, "scale"> — Serializable axis shaping a context may carry: {@link AxisShapeConfig} without the `scale` callback.
402
+ - `ActionContextStack` (interface): interface ActionContextStack — Mutable layered action-map stack with snapshot and restore support.
403
+ - `ActionContextStackSnapshot` (interface): interface ActionContextStackSnapshot — Serializable state for an action-context stack.
404
+ - `ActiveContextAxes` (interface): interface ActiveContextAxes — Axis bindings and shaping merged across the active contexts.
405
+ - `createActionContextStack` (function): function createActionContextStack(): ActionContextStack — Creates a serializable stack of layered action maps for menus and gameplay modes.
287
406
 
288
407
  ## @jgengine/core/input/axisInput
289
408
 
290
409
  - `AXIS_RANGE` (const): const AXIS_RANGE: Record<AxisName, AxisRange> — ⚠ undocumented
291
- - `AxisBinding` (interface): interface AxisBinding — ⚠ undocumented
292
- - `AxisBindingMap` (type): type AxisBindingMap = Record<AxisName, AxisBinding> — ⚠ undocumented
293
- - `AxisChannelConfig` (interface): interface AxisChannelConfig — ⚠ undocumented
294
- - `AxisInput` (interface): interface AxisInput — ⚠ undocumented
410
+ - `AxisBinding` (interface): interface AxisBinding { positive: readonly string[]; negative?: readonly string[]; pointer?: PointerAxisBinding } — ⚠ undocumented · used by `analogAxes` (@jgengine/core/input/axisShaper): Which axes an analog source is driving this frame: an axis counts as analog when any action bound to it has a published analog magnitude (`c…
411
+ - `AxisBindingMap` (type): type AxisBindingMap = Record<AxisName, AxisBinding> — ⚠ undocumented · used by `DRIVE_AXIS_BINDINGS`: Car axes bound to raw key codes, for an {@link AxisChannel} sampled with a key-code `isDown`.
412
+ - `AxisChannelConfig` (interface): interface AxisChannelConfig { bindings: AxisBindingMap; smoothing?: number } — ⚠ undocumented · used by `useAxisChannel` (@jgengine/react): Wires useHeldKeys into a fresh AxisChannel, ready for a per-frame `channel.sample(dt, isDown)`.
413
+ - `AxisInput` (interface): interface AxisInput { throttle: number; brake: number; steer: number; handbrake: number } — ⚠ undocumented · used by `tickDrivableVehicle` (@jgengine/core/physics/drivableVehicle): Connects an `AxisInput` sample straight through a ground-vehicle sim (`KinematicVehicle` or `VehicleDynamics`) to a scene entity's pose for …
295
414
  - `AxisName` (type): type AxisName = keyof AxisInput — ⚠ undocumented
296
- - `AxisRange` (interface): interface AxisRange — ⚠ undocumented
297
- - `DRIVE_AXIS_BINDINGS` (const): const DRIVE_AXIS_BINDINGS: AxisBindingMap — ⚠ undocumented
415
+ - `AxisRange` (interface): interface AxisRange { min: number; max: number } — ⚠ undocumented
416
+ - `DRIVE_AXIS_BINDINGS` (const): const DRIVE_AXIS_BINDINGS: AxisBindingMap — Car axes bound to raw key codes, for an {@link AxisChannel} sampled with a key-code `isDown`. `ctx.input.axis` samples action names instead, so bind it to the game's input actions (e.g. `moveForward`), not this map.
298
417
  - `GenericAxisChannel` (interface): interface GenericAxisChannel<TAxes extends string> — The held-key-ramping analog channel for any axis schema (#282.7) — drones (pitch/roll/strafe), boats, mechs — not just the four car axes `AxisChannel` hardcodes. Same semantics: keys ramp, `setAnalog` overrides, a binding's `pointer` source takes over while a pointer is active.
299
- - `GenericAxisConfig` (interface): interface GenericAxisConfig<TAxes extends string> — ⚠ undocumented
418
+ - `GenericAxisConfig` (interface): interface GenericAxisConfig<TAxes extends string> { bindings: Record<TAxes, AxisBinding>; ranges?: Partial<Record<TAxes, AxisRange>>; smoothing?: number } — ⚠ undocumented
300
419
  - `NEUTRAL_AXIS` (const): const NEUTRAL_AXIS: AxisInput — ⚠ undocumented
301
420
 
421
+ ## @jgengine/core/input/axisShaper
422
+
423
+ - `AxisShapeConfig` (interface): interface AxisShapeConfig — Shaping for one named axis.
424
+ - `AxisShapeProfile` (interface): interface AxisShapeProfile — How one axis responds to one kind of source. Keys want ramps (a held key should feel like a pedal being pressed, not a switch); sticks want deadzone and curve but no lag.
425
+ - `AxisShapeSample` (interface): interface AxisShapeSample<TAxes extends string> — Per-sample options for {@link AxisShaper.shape}.
426
+ - `AxisShaper` (interface): interface AxisShaper<TAxes extends string> — Stateful per-axis response shaping between raw input and a sim.
427
+ - `AxisShaperConfig` (interface): interface AxisShaperConfig<TAxes extends string> — Config for {@link createAxisShaper}: one entry per axis.
428
+ - `AxisValues` (type): type AxisValues<TAxes extends string> = Record<TAxes, number> — Shaped axis output, one number per axis.
429
+ - `analogAxes` (function): function analogAxes<TAxes extends string>(bindings: Readonly<Record<TAxes, AxisBinding>>, analog: Readonly<Record<string, number>> | null): Set<TAxes> — Which axes an analog source is driving this frame: an axis counts as analog when any action bound to it has a published analog magnitude (`ctx.input.analog()`). Feed the result to {@link AxisShaper.shape}.
430
+ - `createAxisShaper` (function): function createAxisShaper<TAxes extends string>(initial: AxisShaperConfig<TAxes>): AxisShaper<TAxes> — Creates an {@link AxisShaper}: deadzone, curve and ramp rates per axis, chosen per frame by whether the source was a key or a stick. It sits between `ctx.input.axis(...)` and any sim (a vehicle, an aircraft, aim), so a held key eases in and self-centres while a stick stays direct. Deterministic and serializable.
431
+ - `shapeAxisValue` (function): function shapeAxisValue(raw: number, profile: AxisShapeProfile | undefined): number — Deadzone, saturation and curve applied to one raw value; sign is preserved.
432
+
302
433
  ## @jgengine/core/input/bindingOverrides
303
434
 
304
435
  - `BINDING_OVERRIDES_STORAGE_PREFIX` (const): const BINDING_OVERRIDES_STORAGE_PREFIX: "jgengine:keybinds:" — ⚠ undocumented
@@ -318,29 +449,64 @@
318
449
  - `controlGroupKey` (function): function controlGroupKey(digit: number, options: ControlGroupOptions = {}): string — The stable bookmark key for a control-group `digit` under `options.keyPrefix` — the key a caller passes to `SelectionBookmarks.bind`/`recall` to store a group without going through {@link resolveControlGroupIntent}.
319
450
  - `resolveControlGroupIntent` (function): function resolveControlGroupIntent(input: ControlGroupInput, options: ControlGroupOptions = {}): ControlGroupIntent — Resolve a control-group key press into a {@link ControlGroupIntent}: Ctrl+digit binds, a bare digit recalls, and a second recall of the same group within `doubleTapMs` focuses. Pure — the caller applies the intent against the store and its own focus hook, and records the returned recall for the next call.
320
451
 
452
+ ## @jgengine/core/input/gamepadModel
453
+
454
+ - `DEFAULT_GAMEPAD_DEADZONE` (const): const DEFAULT_GAMEPAD_DEADZONE: GamepadDeadzone — Shell default stick deadzone.
455
+ - `GAMEPAD_GLYPH_SETS` (const): const GAMEPAD_GLYPH_SETS: Record<GamepadGlyphName, GamepadGlyphSet> — Built-in short labels for the common controller families.
456
+ - `GamepadBindings` (type): type GamepadBindings<TAction extends string = string> = ActionCodesMap<TAction, GamepadCode> — Action bindings whose codes identify gamepad buttons or axes.
457
+ - `GamepadCode` (type): type GamepadCode = `pad:${number}` | `padaxis:${number}${"+" | "-"}` — A gamepad button or signed axis binding code.
458
+ - `GamepadDeadzone` (interface): interface GamepadDeadzone — Deadzone policy applied to gamepad axes.
459
+ - `GamepadFeelConfig` (interface): interface GamepadFeelConfig — Game-level pad feel read by the shell's gamepad poll. A number `deadzone` is the axial inner deadzone with a `0.95` outer edge.
460
+ - `GamepadFrame` (interface): interface GamepadFrame — The digital and analog action state produced by a gamepad frame.
461
+ - `GamepadGlyphName` (type): type GamepadGlyphName = "xbox" | "playstation" | "nintendo" | "generic" — Names of the built-in controller glyph sets.
462
+ - `GamepadGlyphSet` (interface): interface GamepadGlyphSet — Button labels used by one controller family.
463
+ - `GamepadSample` (interface): interface GamepadSample — Read-only view of one sampled gamepad. The browser `Gamepad` satisfies it structurally, so a poll loop can resolve `navigator.getGamepads()` entries without copying them.
464
+ - `GamepadSnapshot` (interface): interface GamepadSnapshot — A serializable gamepad state sampled from the platform input API.
465
+ - `ResolveGamepadFrameOptions` (interface): interface ResolveGamepadFrameOptions — Options for resolving one gamepad snapshot into action state.
466
+ - `gamepadFeelOptions` (function): function gamepadFeelOptions(config: GamepadFeelConfig | undefined): ResolveGamepadFrameOptions — Resolve a {@link GamepadFeelConfig} into the options {@link resolveGamepadFrame} takes.
467
+ - `gamepadGlyphSets` (const): const gamepadGlyphSets: Record<GamepadGlyphName, GamepadGlyphSet> — Lowercase alias for consumers that prefer data-oriented naming.
468
+ - `resolveGamepadFrame` (function): function resolveGamepadFrame(snapshot: GamepadSample, bindings: GamepadBindings, options: ResolveGamepadFrameOptions, out: GamepadFrame = { held: [], analog: {} }): GamepadFrame — Resolve one sampled gamepad into held actions and shaped analog action values. Sticks go through the deadzone and curve; analog buttons (triggers) through `triggerDeadzone` and the same curve. Pass `out` to reuse a frame across polls; it is cleared and returned.
469
+
321
470
  ## @jgengine/core/input/gestureSurface
322
471
 
323
472
  - `DEFAULT_GESTURE_TUNING` (const): const DEFAULT_GESTURE_TUNING: GestureSurfaceTuning — ⚠ undocumented
324
- - `GestureSurfaceTracker` (interface): interface GestureSurfaceTracker — ⚠ undocumented
325
- - `GestureSurfaceTuning` (interface): interface GestureSurfaceTuning — ⚠ undocumented
473
+ - `GestureSurfaceTracker` (interface): interface GestureSurfaceTracker { begin(x: number, y: number, nowMs: number): void; move(x: number, y: number): readonly string[]; end(x: number, y: number, nowMs: number): readonly string[]; cancel(): void; isActive(): boolean } — ⚠ undocumented
474
+ - `GestureSurfaceTuning` (interface): interface GestureSurfaceTuning { tapMoveThresholdPx: number; tapMaxMs: number; swipeMinPx: number; swipeMinVelocity: number; dragStepPx: number } — ⚠ undocumented
326
475
  - `createGestureSurfaceTracker` (function): function createGestureSurfaceTracker(bindings: TouchGestureBindings, tuning: GestureSurfaceTuning = DEFAULT_GESTURE_TUNING): GestureSurfaceTracker — ⚠ undocumented
327
476
 
477
+ ## @jgengine/core/input/haptics
478
+
479
+ - `HapticChannels` (interface): interface HapticChannels — Named continuous rumble channels for one player, mixed by priority each frame. Game code sets levels from its own telemetry (engine rpm, road surface, impacts); the shell mixes and drives the pad.
480
+ - `HapticChannelsOptions` (interface): interface HapticChannelsOptions — Options for {@link createHapticChannels}.
481
+ - `HapticChannelsSnapshot` (interface): interface HapticChannelsSnapshot — Serializable channel state.
482
+ - `HapticLevel` (interface): interface HapticLevel — Motor intensities, each `0..1`: `strong` is the low-frequency motor, `weak` the high-frequency one.
483
+ - `HapticPulse` (interface): interface HapticPulse extends HapticLevel — A decaying one-shot on a channel: starts at `strong`/`weak` and fades to zero over `ms`.
484
+ - `createHapticChannels` (function): function createHapticChannels(options: HapticChannelsOptions = {}): HapticChannels — Per-player haptic channels mixed by priority.
485
+
486
+ ## @jgengine/core/input/inputBuffer
487
+
488
+ - `BufferedAction` (interface): interface BufferedAction — One action's press history inside an {@link InputBuffer}.
489
+ - `InputBuffer` (interface): interface InputBuffer — Remembers recent action presses so a press slightly early (a jump before landing) still counts. Times are caller-supplied ms, so it runs the same on a client, a host or in a replay.
490
+ - `InputBufferSnapshot` (interface): interface InputBufferSnapshot — Serializable state for an {@link InputBuffer}.
491
+ - `createInputBuffer` (function): function createInputBuffer(options: { windowMs: number }): InputBuffer — Creates an input buffer for jump buffering, coyote time, hold duration and double taps.
492
+
328
493
  ## @jgengine/core/input/lookChannel
329
494
 
330
- - `LookChannel` (interface): interface LookChannel — ⚠ undocumented
331
- - `LookChannelOptions` (interface): interface LookChannelOptions — ⚠ undocumented
495
+ - `LookChannel` (interface): interface LookChannel { accumulate(dx: number, dy: number): void; consume(): LookDeltas; setYaw(yaw: number): void; readYaw(): number; setPitch(pitch: number): void; readPitch(): number; setVerticalOffset(offset: number): void; readVerticalOffset(): number; snap… — ⚠ undocumented
496
+ - `LookChannelOptions` (interface): interface LookChannelOptions { sensitivity: number; maxVerticalOffset?: number } — ⚠ undocumented
497
+ - `LookChannelState` (interface): interface LookChannelState — Plain JSON state of a {@link LookChannel}: the pending pixel deltas and the committed pose.
332
498
  - `LookDeltas` (interface): interface LookDeltas — Per-frame look channel shared between an event-driven capture layer (writer of raw pointer deltas) and a frame-driven controller (consumer), plus the latest committed pose for same-frame readers such as presence sync. Kept as plain mutable state on purpose: routing per-frame deltas through a reactive store would notify subscribers every frame for state no UI reads.
333
499
  - `createLookChannel` (function): function createLookChannel({ sensitivity, maxVerticalOffset = Infinity }: LookChannelOptions): LookChannel — ⚠ undocumented
334
500
 
335
501
  ## @jgengine/core/input/pointer
336
502
 
337
503
  - `DragCapture` (interface): interface DragCapture — Renderer-agnostic drag-capture / pull-vector state machine for slingshot-style aiming, drawback abilities, and similar gestures.
338
- - `DragCaptureConfig` (interface): interface DragCaptureConfig — ⚠ undocumented
504
+ - `DragCaptureConfig` (interface): interface DragCaptureConfig { maxPull?: number; grabRadius?: number } — ⚠ undocumented
339
505
  - `DragResult` (type): type DragResult = DragState — ⚠ undocumented
340
506
  - `DragState` (interface): interface DragState — Snapshot of an in-progress or just-released drag: origin/current cursor points plus the clamped pull vector.
341
507
  - `PointerButton` (type): type PointerButton = "primary" | "secondary" | "middle" — ⚠ undocumented
342
508
  - `PointerHit` (interface): interface PointerHit — Renderer-free result of a screen→world raycast. The shell's pointer service produces this from the cursor; core-side gameplay (item.use aim, click-to-move, ground-target abilities, pings) consumes it without touching three.js.
343
- - `PointerVec3` (type): type PointerVec3 = readonly [number, number, number] — ⚠ undocumented
509
+ - `PointerVec3` (type): type PointerVec3 = readonly [number, number, number] — ⚠ undocumented · used by `aimToPoint`: Build an `origin → point` aim for `item.use` / projectiles, firing toward the cursor.
344
510
  - `aimToPoint` (function): function aimToPoint(origin: PointerVec3, point: PointerVec3): Aim — Build an `origin → point` aim for `item.use` / projectiles, firing toward the cursor.
345
511
  - `createDragCapture` (function): function createDragCapture(config: DragCaptureConfig = {}): DragCapture — ⚠ undocumented
346
512
  - `groundOf` (function): function groundOf(hit: PointerHit): readonly [number, number] — Project a pointer hit onto the XZ plane for navmesh routing (`findPath` takes `[x, z]`).
@@ -349,8 +515,8 @@
349
515
  ## @jgengine/core/input/pointerAxis
350
516
 
351
517
  - `PointerAxisBinding` (interface): interface PointerAxisBinding — Maps one pointer axis onto an analog axis target — the pointer-backed counterpart of an `AxisBinding`'s key lists.
352
- - `PointerAxisState` (interface): interface PointerAxisState — ⚠ undocumented
353
- - `PointerSurfaceRect` (interface): interface PointerSurfaceRect — ⚠ undocumented
518
+ - `PointerAxisState` (interface): interface PointerAxisState { x: number; y: number; active: boolean } — ⚠ undocumented · used by `normalizePointerToAxis`: Normalize client coordinates against a surface rect into a `PointerAxisState`, clamped to `[-1, 1]` per axis.
519
+ - `PointerSurfaceRect` (interface): interface PointerSurfaceRect { left: number; top: number; width: number; height: number } — ⚠ undocumented · used by `normalizePointerToAxis`: Normalize client coordinates against a surface rect into a `PointerAxisState`, clamped to `[-1, 1]` per axis.
354
520
  - `normalizePointerToAxis` (function): function normalizePointerToAxis(clientX: number, clientY: number, rect: PointerSurfaceRect): PointerAxisState — Normalize client coordinates against a surface rect into a `PointerAxisState`, clamped to `[-1, 1]` per axis.
355
521
  - `pointerAxisValue` (function): function pointerAxisValue(binding: PointerAxisBinding, state: PointerAxisState | null | undefined): number | null — Resolve a pointer binding against the current pointer state: `null` when no pointer is active (callers fall back to their digital target), otherwise the deadzone/curve-shaped value in `[-1, 1]`.
356
522
 
@@ -374,7 +540,7 @@
374
540
  ## @jgengine/core/input/touchGestures
375
541
 
376
542
  - `TouchGestureEnd` (type): type TouchGestureEnd = "tap" | "hold-end" | null — ⚠ undocumented
377
- - `TouchGestureTracker` (interface): interface TouchGestureTracker — ⚠ undocumented
543
+ - `TouchGestureTracker` (interface): interface TouchGestureTracker { begin(x: number, y: number, nowMs: number): void; move(x: number, y: number): {dx: number; dy: number} | null; beginHold(): boolean; end(nowMs: number): TouchGestureEnd; cancel(): TouchGestureEnd; isActive(): boolean; isHolding(): boolean… — ⚠ undocumented
378
544
  - `TouchGestureTuning` (interface): interface TouchGestureTuning — Single-finger gesture disambiguation for touch look controls: one touch stream drives look-drag, tap, and long-press-hold without fighting. Movement past the tap threshold commits the gesture to "look" and cancels tap/hold; a still finger that lifts quickly is a tap; a still finger held past the long-press delay is a hold. Timestamps are injected so the state machine stays pure; the capture layer owns timers and touch identifiers.
379
545
  - `createTouchGestureTracker` (function): function createTouchGestureTracker(tuning: TouchGestureTuning): TouchGestureTracker — ⚠ undocumented
380
546
 
@@ -382,7 +548,7 @@
382
548
 
383
549
  - `DEFAULT_TOUCH_JOYSTICK_VARIANT` (const): const DEFAULT_TOUCH_JOYSTICK_VARIANT: TouchJoystickVariant — Variant used when the player has not picked one.
384
550
  - `DEFAULT_TOUCH_STYLE` (const): const DEFAULT_TOUCH_STYLE: TouchStyle — Skin used when neither the game nor the player picks one.
385
- - `DeriveTouchSchemeOptions` (interface): interface DeriveTouchSchemeOptions — ⚠ undocumented
551
+ - `DeriveTouchSchemeOptions` (interface): interface DeriveTouchSchemeOptions { reserved: ReadonlySet<string>; firstPerson: boolean; config?: TouchControlsConfig | false; mode?: string | null } — ⚠ undocumented · used by `deriveTouchScheme`: Null means "render no touch controls" — either the game opted out or there is nothing to synthesize.
386
552
  - `ResolvedTouchLayout` (interface): interface ResolvedTouchLayout — The dock zone each cluster resolved to, after applying game config over the bottom-layout defaults.
387
553
  - `TOUCH_CODE_PREFIX` (const): const TOUCH_CODE_PREFIX: "touch:" — ⚠ undocumented
388
554
  - `TOUCH_JOYSTICK_VARIANTS` (const): const TOUCH_JOYSTICK_VARIANTS: readonly TouchJoystickVariant[] — Every joystick variant id, in menu order.
@@ -390,19 +556,19 @@
390
556
  - `TOUCH_STYLES` (const): const TOUCH_STYLES: readonly TouchStyle[] — Every touch skin id, in menu order.
391
557
  - `TOUCH_STYLE_OPTIONS` (const): const TOUCH_STYLE_OPTIONS: readonly { value: TouchStyle; label: string }[] — Touch skins as `{ value, label }` rows for the Settings → Controls selector.
392
558
  - `TouchAnchor` (type): type TouchAnchor = | "bottom-left" | "bottom-center" | "bottom-right" | "left" | "right" | "top-left" | "top-center" | "top-right" — Screen zone a touch cluster or button docks to. The four corners plus the mid `left`/`right` rails (vertical stacks, MMO-style hotbars) and the `bottom-center` / `top-center` strips let controls use the whole viewport instead of piling into one bottom bar.
393
- - `TouchButton` (interface): interface TouchButton — ⚠ undocumented
559
+ - `TouchButton` (interface): interface TouchButton { action: string; label: string; icon: string | false | null; kind: TouchButtonKind; shape: TouchButtonShape; anchor: TouchAnchor | null; image: string | null } — ⚠ undocumented
394
560
  - `TouchButtonKind` (type): type TouchButtonKind = "primary" | "utility" — ⚠ undocumented
395
561
  - `TouchButtonShape` (type): type TouchButtonShape = "circle" | "square" | "pedal" | "lever" | "trigger" | "wheel" | "tab" — Physical silhouette a touch button wears. The capture layer draws each as its own shape — a `pedal` reads as a foot pedal, a `lever` as a pull handle, a `trigger` as a firing paddle — so a control looks like the thing it does instead of a labelled circle. `circle`/`square` are the neutral fallbacks.
396
- - `TouchButtonSpec` (interface): interface TouchButtonSpec — ⚠ undocumented
562
+ - `TouchButtonSpec` (interface): interface TouchButtonSpec { action: string; label?: string; icon?: string | false; kind?: TouchButtonKind; shape?: TouchButtonShape; anchor?: TouchAnchor; image?: string } — ⚠ undocumented
397
563
  - `TouchControlsConfig` (interface): interface TouchControlsConfig — Game-authored refinement of the derived touch scheme on `defineGame({ touch })` — gestures, curated buttons, hidden actions, cluster layout, skin, and per-context `modes`.
398
564
  - `TouchControlsModeConfig` (type): type TouchControlsModeConfig = Omit<TouchControlsConfig, "modes"> — One named control context's touch config — the same shape as the base config, minus nested modes.
399
- - `TouchDragBinding` (interface): interface TouchDragBinding — ⚠ undocumented
400
- - `TouchGestureBindings` (interface): interface TouchGestureBindings — ⚠ undocumented
401
- - `TouchJoystick` (interface): interface TouchJoystick — ⚠ undocumented
565
+ - `TouchDragBinding` (interface): interface TouchDragBinding { left?: string; right?: string; up?: string; down?: string; stepPx?: number } — ⚠ undocumented
566
+ - `TouchGestureBindings` (interface): interface TouchGestureBindings { tap?: string; swipeUp?: string; swipeDown?: string; swipeLeft?: string; swipeRight?: string; drag?: TouchDragBinding } — ⚠ undocumented
567
+ - `TouchJoystick` (interface): interface TouchJoystick { up: string | null; down: string | null; left: string | null; right: string | null } — ⚠ undocumented
402
568
  - `TouchJoystickVariant` (type): type TouchJoystickVariant = "fixed" | "floating" — How the movement joystick behaves — the two shipped variants, player-selectable in Settings → Controls. `fixed` is the classic always-visible stick in its dock corner; `floating` keeps the corner as an empty capture zone and spawns the stick centered under wherever the thumb lands, so the hand never has to find a fixed target mid-play.
403
569
  - `TouchLayoutConfig` (interface): interface TouchLayoutConfig — Where each touch cluster docks; unset falls back to the classic bottom layout.
404
570
  - `TouchMovementConfig` (interface): interface TouchMovementConfig — Restricts the virtual joystick to one axis — a `horizontal` zone reads as a steering control, freeing throttle/brake to become pedal buttons.
405
- - `TouchScheme` (interface): interface TouchScheme — ⚠ undocumented
571
+ - `TouchScheme` (interface): interface TouchScheme { joystick: TouchJoystick | null; buttons: readonly TouchButton[]; gestures: TouchGestureBindings | null; look: boolean; lookSensitivity: number; layout: ResolvedTouchLayout; style: TouchStyle } — ⚠ undocumented · used by `deriveTouchScheme`: Null means "render no touch controls" — either the game opted out or there is nothing to synthesize.
406
572
  - `TouchStyle` (type): type TouchStyle = "glass" | "arcade" | "mechanical" | "minimal" — Player-selectable skin for the whole touch layer. A style is a material + geometry preset (not just colours), chosen in Settings → Controls and persisted; `glass` is the translucent default, the rest are opt-in looks.
407
573
  - `deriveTouchScheme` (function): function deriveTouchScheme(input: ActionCodesMap | undefined, { reserved, firstPerson, config: rawConfig, mode }: DeriveTouchSchemeOptions): TouchScheme | null — Null means "render no touch controls" — either the game opted out or there is nothing to synthesize.
408
574
  - `touchActionLabel` (function): function touchActionLabel(action: string): string — ⚠ undocumented
@@ -413,8 +579,8 @@
413
579
 
414
580
  ## @jgengine/core/interaction/contextMenu
415
581
 
416
- - `BuildContextMenuInput` (interface): interface BuildContextMenuInput — ⚠ undocumented
417
- - `ContextMenu` (interface): interface ContextMenu — ⚠ undocumented
582
+ - `BuildContextMenuInput` (interface): interface BuildContextMenuInput { kind: ContextTargetKind; targetId: string; verbs: readonly ContextVerb[] | undefined; point?: readonly [number, number, number] } — ⚠ undocumented · used by `buildContextMenu`: Assemble a menu from a target's catalog verbs; null when the target lists none.
583
+ - `ContextMenu` (interface): interface ContextMenu { kind: ContextTargetKind; targetId: string; point?: readonly [number, number, number]; verbs: readonly ContextVerb[] } — ⚠ undocumented · used by `buildContextMenu`: Assemble a menu from a target's catalog verbs; null when the target lists none.
418
584
  - `ContextTargetKind` (type): type ContextTargetKind = "entity" | "object" — ⚠ undocumented
419
585
  - `ContextVerb` (interface): interface ContextVerb — One right-click verb: a label plus the command it dispatches (walk-then-act supported by args).
420
586
  - `buildContextMenu` (function): function buildContextMenu(input: BuildContextMenuInput): ContextMenu | null — Assemble a menu from a target's catalog verbs; null when the target lists none.
@@ -446,14 +612,14 @@
446
612
 
447
613
  ## @jgengine/core/interaction/proximityPrompt
448
614
 
449
- - `GaugePromptDisplay` (interface): interface GaugePromptDisplay — ⚠ undocumented
450
- - `KeybindPromptDisplay` (interface): interface KeybindPromptDisplay — ⚠ undocumented
451
- - `LabelPromptDisplay` (interface): interface LabelPromptDisplay — ⚠ undocumented
452
- - `PositionedPrompt` (interface): interface PositionedPrompt — ⚠ undocumented
453
- - `PromptCommand` (interface): interface PromptCommand — ⚠ undocumented
454
- - `PromptPoint` (interface): interface PromptPoint — ⚠ undocumented
455
- - `ProximityPrompt` (interface): interface ProximityPrompt — ⚠ undocumented
456
- - `ProximityPromptConfig` (interface): interface ProximityPromptConfig — ⚠ undocumented
615
+ - `GaugePromptDisplay` (interface): interface GaugePromptDisplay { kind: "gauge"; gaugeId: string } — ⚠ undocumented
616
+ - `KeybindPromptDisplay` (interface): interface KeybindPromptDisplay { kind: "keybind"; actionId: string; label?: string } — ⚠ undocumented
617
+ - `LabelPromptDisplay` (interface): interface LabelPromptDisplay { kind: "label"; text: string } — ⚠ undocumented
618
+ - `PositionedPrompt` (interface): interface PositionedPrompt { id: string; position: PromptPoint; priority?: number; prompt: ProximityPrompt } — ⚠ undocumented · used by `resolveActivePrompt`: Nearest prompt strictly within its radius wins; a higher-priority prompt in range beats any lower-priority one regardless of distance; equal…
619
+ - `PromptCommand` (interface): interface PromptCommand { name: string; input: unknown } — ⚠ undocumented
620
+ - `PromptPoint` (interface): interface PromptPoint { x: number; z: number } — ⚠ undocumented · used by `resolveActivePrompt`: Nearest prompt strictly within its radius wins; a higher-priority prompt in range beats any lower-priority one regardless of distance; equal…
621
+ - `ProximityPrompt` (interface): interface ProximityPrompt { radius: number; display: ProximityPromptDisplay; invoke: PromptCommand | null } — ⚠ undocumented
622
+ - `ProximityPromptConfig` (interface): interface ProximityPromptConfig { radius: number; display: ProximityPromptDisplay; invoke?: PromptCommand | null } — ⚠ undocumented
457
623
  - `ProximityPromptDisplay` (type): type ProximityPromptDisplay = KeybindPromptDisplay | GaugePromptDisplay | LabelPromptDisplay — ⚠ undocumented
458
624
  - `command` (function): function command(name: string, input?: unknown): PromptCommand — ⚠ undocumented
459
625
  - `gauge` (function): function gauge(gaugeId: string): GaugePromptDisplay — ⚠ undocumented
@@ -467,18 +633,18 @@
467
633
 
468
634
  ## @jgengine/core/interaction/qte
469
635
 
470
- - `QteInputEvent` (interface): interface QteInputEvent — ⚠ undocumented
471
- - `QteOutcome` (type): type QteOutcome = | { status: "success" } | { status: "fail"; atStep: string; reason: "missed-window" | "wrong-action" | "too-early" } — ⚠ undocumented
472
- - `QteStep` (interface): interface QteStep — ⚠ undocumented
636
+ - `QteInputEvent` (interface): interface QteInputEvent { action: string; at: number } — ⚠ undocumented · used by `evaluateQteSequence`: Evaluate a quick-time-event input sequence against timed hit windows.
637
+ - `QteOutcome` (type): type QteOutcome = | { status: "success" } | { status: "fail"; atStep: string; reason: "missed-window" | "wrong-action" | "too-early" } — ⚠ undocumented · used by `evaluateQteSequence`: Evaluate a quick-time-event input sequence against timed hit windows.
638
+ - `QteStep` (interface): interface QteStep { id: string; action: string; windowStart: number; windowEnd: number } — ⚠ undocumented · used by `evaluateQteSequence`: Evaluate a quick-time-event input sequence against timed hit windows.
473
639
  - `evaluateQteSequence` (function): function evaluateQteSequence(steps: readonly QteStep[], inputs: readonly QteInputEvent[]): QteOutcome — Evaluate a quick-time-event input sequence against timed hit windows.
474
640
  - `pendingQteStep` (function): function pendingQteStep(steps: readonly QteStep[], elapsedSeconds: number): QteStep | null — ⚠ undocumented
475
641
  - `qteProgress` (function): function qteProgress(steps: readonly QteStep[], elapsedSeconds: number): number — ⚠ undocumented
476
642
 
477
643
  ## @jgengine/core/interaction/skillCheck
478
644
 
479
- - `SkillCheckConfig` (interface): interface SkillCheckConfig — ⚠ undocumented
480
- - `SkillCheckResult` (interface): interface SkillCheckResult — ⚠ undocumented
481
- - `SkillCheckZone` (interface): interface SkillCheckZone — ⚠ undocumented
645
+ - `SkillCheckConfig` (interface): interface SkillCheckConfig { trackWidth: number; zone: SkillCheckZone; markerPeriod: number; window: number; zoneDriftPerSecond?: number } — ⚠ undocumented · used by `skillCheckZoneAt`: A timing-bar skill check that succeeds when the moving marker is released inside the target zone.
646
+ - `SkillCheckResult` (interface): interface SkillCheckResult { success: boolean; timedOut: boolean; markerPosition: number; zone: SkillCheckZone } — ⚠ undocumented
647
+ - `SkillCheckZone` (interface): interface SkillCheckZone { start: number; end: number } — ⚠ undocumented · used by `skillCheckZoneAt`: A timing-bar skill check that succeeds when the moving marker is released inside the target zone.
482
648
  - `evaluateSkillCheck` (function): function evaluateSkillCheck(config: SkillCheckConfig, elapsedSeconds: number): SkillCheckResult — ⚠ undocumented
483
649
  - `skillCheckMarkerPosition` (function): function skillCheckMarkerPosition(config: SkillCheckConfig, elapsedSeconds: number): number — ⚠ undocumented
484
650
  - `skillCheckZoneAt` (function): function skillCheckZoneAt(config: SkillCheckConfig, elapsedSeconds: number): SkillCheckZone — A timing-bar skill check that succeeds when the moving marker is released inside the target zone.
@@ -486,7 +652,7 @@
486
652
  ## @jgengine/core/movement/avatarGait
487
653
 
488
654
  - `DEFAULT_GAIT_TUNING` (const): const DEFAULT_GAIT_TUNING: GaitTuning — ⚠ undocumented
489
- - `GaitTuning` (interface): interface GaitTuning — ⚠ undocumented
655
+ - `GaitTuning` (interface): interface GaitTuning { stridesPerUnit: number; bobAmplitude: number; swayAmplitude: number; fullIntensitySpeed: number } — ⚠ undocumented · used by `gaitBobOffset`: Vertical hop per footfall — two peaks per stride cycle.
490
656
  - `advanceGaitPhase` (function): function advanceGaitPhase(phase: number, speedUnitsPerSec: number, dtSec: number, tuning: GaitTuning = DEFAULT_GAIT_TUNING): number — ⚠ undocumented
491
657
  - `gaitBobOffset` (function): function gaitBobOffset(phase: number, speedUnitsPerSec: number, tuning: GaitTuning = DEFAULT_GAIT_TUNING): number — Vertical hop per footfall — two peaks per stride cycle.
492
658
  - `gaitSwayAngle` (function): function gaitSwayAngle(phase: number, speedUnitsPerSec: number, tuning: GaitTuning = DEFAULT_GAIT_TUNING): number — Signed side-to-side lean alternating with each footfall.
@@ -501,13 +667,22 @@
501
667
 
502
668
  - `CAMERA_PITCH_LIMIT` (const): const CAMERA_PITCH_LIMIT: 1.45 — ⚠ undocumented
503
669
 
670
+ ## @jgengine/core/movement/characterController
671
+
672
+ - `CharacterController` (interface): interface CharacterController — The controller handle: config, state, and the per-step move.
673
+ - `CharacterControllerConfig` (interface): interface CharacterControllerConfig — Capsule dimensions and the walk rules a controller applies; every field is retunable during play.
674
+ - `CharacterControllerState` (interface): interface CharacterControllerState — The controller's serializable state. `position` is the feet point; the capsule stands above it.
675
+ - `CharacterMoveInput` (interface): interface CharacterMoveInput — One step of intent for {@link CharacterController.move}.
676
+ - `CharacterMoveResult` (interface): interface CharacterMoveResult — What one move did.
677
+ - `createCharacterController` (function): function createCharacterController(initial: CharacterControllerConfig): CharacterController — Collide-and-slide capsule controller over any {@link PhysicsBackend}: horizontal slide along walls, step-up over ledges, slope limit, ceiling test, crouch with headroom check, ground snapping, and moving-platform carry read from the ground body's velocity. Pure over the backend's `shapecast`/`overlap`; the caller owns input and gravity policy.
678
+
504
679
  ## @jgengine/core/movement/dash
505
680
 
506
- - `DashBurst` (interface): interface DashBurst — ⚠ undocumented
507
- - `DashConfig` (interface): interface DashConfig — ⚠ undocumented
508
- - `DashDirection` (interface): interface DashDirection — ⚠ undocumented
681
+ - `DashBurst` (interface): interface DashBurst { direction: DashDirection; durationMs: number; distance: number } — ⚠ undocumented
682
+ - `DashConfig` (interface): interface DashConfig { distance: number; durationMs: number; iframes: {fromMs: number; toMs: number}; staminaCost: number; staminaMax: number; staminaRegenPerSecond: number; cooldownMs: number } — ⚠ undocumented
683
+ - `DashDirection` (interface): interface DashDirection { x: number; z: number } — ⚠ undocumented
509
684
  - `DashRejection` (type): type DashRejection = { reason: "no-stamina" | "cooldown" | "dashing" } — ⚠ undocumented
510
- - `DashState` (interface): interface DashState — ⚠ undocumented
685
+ - `DashState` (interface): interface DashState { tryDash(direction: DashDirection, nowMs: number): DashRejection | DashBurst; tick(dtSeconds: number, nowMs: number): void; stamina(): number; staminaFraction(): number; isDashing(nowMs: number): boolean; isInvulnerable(nowMs: number): boo… — ⚠ undocumented
511
686
 
512
687
  ## @jgengine/core/movement/formation
513
688
 
@@ -526,30 +701,50 @@
526
701
  - `placeFormation` (function): function placeFormation(destination: Vec2, facing: number, count: number, generator: FormationSlotGenerator): Vec2[] — Transform a generator's local slot offsets into world XZ positions around a `destination`, rotated by `facing` (engine yaw). Slot `i` in the returned array is `generator(count)[i]` mapped through the group frame, so it stays aligned with {@link assignFormationSlots}' slot indices. Pure and allocation- light: one array of `count` points, no per-call closures retained.
527
702
  - `wedgeFormation` (function): function wedgeFormation(options: WedgeFormationOptions): FormationSlotGenerator — A "V"/arrowhead with the apex at the destination and arms trailing back — a flying-wedge charge or a goose skein. Slot 0 is the tip; later slots alternate right then left, each rank stepping one `spacing` outward and backward.
528
703
 
704
+ ## @jgengine/core/movement/freeFlight
705
+
706
+ - `CREATIVE_FLIGHT_TUNING` (const): const CREATIVE_FLIGHT_TUNING: FreeFlightTuning — Preset for Minecraft-like creative flight — weightless, collides, yaw-relative strafe.
707
+ - `FreeFlightBindings` (interface): interface FreeFlightBindings — Per-axis bindings for free-flight — which actions drive each flight axis. Positive is forward/right/up.
708
+ - `FreeFlightController` (interface): interface FreeFlightController — Stateful handle for any free-flight actor with snapshot/restore/retune.
709
+ - `FreeFlightIntent` (interface): interface FreeFlightIntent — Intent for one free-flight tick — forward/right from WASD/analog, vertical from jump/crouch.
710
+ - `FreeFlightMode` (type): type FreeFlightMode = "creative" | "spectator" | "noclip" | "hover" — Free-flight families — character-scale 6DOF movement, distinct from vehicle aerodynamics.
711
+ - `FreeFlightState` (interface): interface FreeFlightState — Velocity state for a free-flight actor — serializable and ownable by the caller.
712
+ - `FreeFlightStep` (interface): interface FreeFlightStep — World displacement produced by one free-flight tick.
713
+ - `FreeFlightTuning` (interface): interface FreeFlightTuning — Data-first tuning for one free-flight profile.
714
+ - `HOVER_FLIGHT_TUNING` (const): const HOVER_FLIGHT_TUNING: FreeFlightTuning — Preset for hover/jetpack — gravity + thrust, useful for short bursts.
715
+ - `NOCLIP_FLIGHT_TUNING` (const): const NOCLIP_FLIGHT_TUNING: FreeFlightTuning — Preset for noclip — weightless, noclips, yaw-relative with independent vertical.
716
+ - `SPECTATOR_FLIGHT_TUNING` (const): const SPECTATOR_FLIGHT_TUNING: FreeFlightTuning — Preset for spectator — weightless, noclips, flies where the camera looks.
717
+ - `advanceFreeFlight` (function): function advanceFreeFlight(state: FreeFlightState, intent: FreeFlightIntent, yaw: number, pitch: number | undefined, dt: number, tuning: FreeFlightTuning): FreeFlightStep — Advance one frame of free-flight kinematics. Horizontal uses yaw-relative strafe (A = left, D = right) — never roll/bank. Vertical is independent of pitch unless `alignWithLook` is true (spectator).
718
+ - `createFreeFlightController` (function): function createFreeFlightController(initialTuning: FreeFlightTuning, options: { yaw?: number; pitch?: number; state?: FreeFlightState } = {}): FreeFlightController — Totally free flight for any actor — character, camera, drone, or debug rig. Horizontal is always yaw-relative strafe; vertical is jump/crouch. Use `alignWithLook` for a 6DOF spectator that flies where the camera looks.
719
+ - `createFreeFlightState` (function): function createFreeFlightState(): FreeFlightState — Create an empty flight velocity state.
720
+ - `resolveFlightStep` (function): function resolveFlightStep(position: readonly [number, number, number], stepX: number, stepY: number, stepZ: number, obstacles: readonly CollisionObstacle[], radius: number = DEFAULT_OBSTACLE_PLAYER_RADIUS): { stepX: number; stepY: number; stepZ: number } — Resolve a flight step against world solids (XZ slide + Y clamp).
721
+ - `resolveFreeFlightIntent` (function): function resolveFreeFlightIntent(keys: MovementKeysState, analog: AnalogMoveIntent | null | undefined): FreeFlightIntent — Translate held keys + analog into a free-flight intent. Vertical is `space - (control|c)` so jump ascends and crouch descends — the same keys that walk/jump/crouch use, re-mapped for flight without re-binding.
722
+ - `resolveFreeFlightIntentFromInput` (function): function resolveFreeFlightIntentFromInput(isDown: (action: string) => boolean, value: (action: string) => number, pointer: PointerAxisState | null, bindings?: FreeFlightBindings): FreeFlightIntent — Translate live input (held actions + analog + pointer) into a flight intent using per-profile axis bindings. Unlisted bindings fall back to the defaults above so existing games keep WASD/Space/Ctrl/Shift without declaring anything.
723
+
529
724
  ## @jgengine/core/movement/glideModel
530
725
 
531
- - `GlideInput` (interface): interface GlideInput — ⚠ undocumented
726
+ - `GlideInput` (interface): interface GlideInput { yaw?: number; throttle?: number; control?: number } — ⚠ undocumented
532
727
  - `GlideModel` (interface): interface GlideModel — A kinematic glider (#282.6) — the walk-controller-compatible sibling of `physics/traversal`'s rigid-body `Glide`, with the yaw and powered-climb authority that one lacks. External flows — `physics/flowTube` corridors, `world/windZones` schedules — compose per tick through `externalVelocity`, and turbulence degrades control through the `control` scalar.
533
- - `GlideModelConfig` (interface): interface GlideModelConfig — ⚠ undocumented
534
- - `GlideStep` (interface): interface GlideStep — ⚠ undocumented
728
+ - `GlideModelConfig` (interface): interface GlideModelConfig { gravityScale?: number; gravity?: number; thrustAccel?: number; forwardSpeed?: number; yawRate?: number; climbAccel?: number; maxFallSpeed?: number; control?: number } — ⚠ undocumented · used by `createGlideModel`: Gliding/wingsuit descent control — lift, drag, and steering from a launch.
729
+ - `GlideStep` (interface): interface GlideStep { position: GlideVec3; velocity: GlideVec3; heading: number } — ⚠ undocumented
535
730
  - `GlideVec3` (type): type GlideVec3 = readonly [number, number, number] — ⚠ undocumented
536
731
  - `createGlideModel` (function): function createGlideModel(config: GlideModelConfig = {}): GlideModel — Gliding/wingsuit descent control — lift, drag, and steering from a launch.
537
732
 
538
733
  ## @jgengine/core/movement/grappleSwing
539
734
 
540
735
  - `GrappleSwing` (interface): interface GrappleSwing — A rope-swing constraint for kinematic controllers (#282.5) — the walk-controller-compatible sibling of `physics/traversal`'s rigid-body `Grapple`. Fire at an anchor, feed each frame's integrated position/velocity through `step`, and commit what comes back (via `beforeCommit` or `setPose`): positions beyond the rope clamp to its sphere and velocity loses its outward radial component, which is exactly a pendulum swing.
541
- - `GrappleSwingConfig` (interface): interface GrappleSwingConfig — ⚠ undocumented
542
- - `GrappleSwingState` (interface): interface GrappleSwingState — ⚠ undocumented
543
- - `GrappleSwingStep` (interface): interface GrappleSwingStep — ⚠ undocumented
736
+ - `GrappleSwingConfig` (interface): interface GrappleSwingConfig { reelSpeed?: number; minLength?: number; stiffness?: number; damping?: number } — ⚠ undocumented · used by `createGrappleSwing`: Grappling-hook rope swing physics with anchor, pendulum motion, and reel-in.
737
+ - `GrappleSwingState` (interface): interface GrappleSwingState { attached: boolean; anchor: SwingVec3 | null; ropeLength: number } — ⚠ undocumented
738
+ - `GrappleSwingStep` (interface): interface GrappleSwingStep { position: SwingVec3; velocity: SwingVec3 } — ⚠ undocumented
544
739
  - `SwingVec3` (type): type SwingVec3 = readonly [number, number, number] — ⚠ undocumented
545
740
  - `createGrappleSwing` (function): function createGrappleSwing(config: GrappleSwingConfig = {}): GrappleSwing — Grappling-hook rope swing physics with anchor, pendulum motion, and reel-in.
546
741
 
547
742
  ## @jgengine/core/movement/leaderTrail
548
743
 
549
744
  - `LeaderTrail` (interface): interface LeaderTrail — A live breadcrumb trail recorded from a moving leader, with followers placed by arc-length behind the head — conga lines, convoys, duckling chains, snake bodies. Call `record` with the leader's position every tick; read `followerAt(i)` for the pose `spacing * (i + 1)` behind.
550
- - `LeaderTrailConfig` (interface): interface LeaderTrailConfig — ⚠ undocumented
745
+ - `LeaderTrailConfig` (interface): interface LeaderTrailConfig { spacing: number; maxFollowers?: number; sampleDistance?: number } — ⚠ undocumented · used by `createLeaderTrail`: A trailing follower formation that chases a leader along its past path — snake/convoy trails.
551
746
  - `TrailPoint` (type): type TrailPoint = readonly [number, number, number] — ⚠ undocumented
552
- - `TrailPose` (interface): interface TrailPose — ⚠ undocumented
747
+ - `TrailPose` (interface): interface TrailPose { position: TrailPoint; heading: number } — ⚠ undocumented
553
748
  - `createLeaderTrail` (function): function createLeaderTrail(config: LeaderTrailConfig): LeaderTrail — A trailing follower formation that chases a leader along its past path — snake/convoy trails.
554
749
 
555
750
  ## @jgengine/core/movement/movementModel
@@ -562,36 +757,58 @@
562
757
  - `MovementFrameStep` (interface): interface MovementFrameStep — Horizontal step (world units) the avatar should commit this frame.
563
758
  - `MovementIntent` (interface): interface MovementIntent — Frame-independent description of what the player is asking the avatar to do. `forward`/`right` are in the range -1..1 in the avatar's local frame; the controller rotates them into world space against the camera each frame.
564
759
  - `MovementKey` (type): type MovementKey = "w" | "a" | "s" | "d" | "shift" | "control" | "c" | "space" — Movement core (pure model).
565
- - `MovementKeysState` (type): type MovementKeysState = Record<MovementKey, boolean> — ⚠ undocumented
760
+ - `MovementKeysState` (type): type MovementKeysState = Record<MovementKey, boolean> — ⚠ undocumented · used by `resolveFreeFlightIntent` (@jgengine/core/movement/freeFlight): Translate held keys + analog into a free-flight intent.
566
761
  - `MovementTuningOverrides` (interface): interface MovementTuningOverrides — Per-game overrides for the gravity/jump feel, sourced from `GameDefinition.physics`. Omitted fields fall back to {@link MOVEMENT_TUNING}.
567
762
  - `PlayerMotionState` (interface): interface PlayerMotionState — Mutable kinematic state carried between frames by the controller. Kept here so the velocity / jump / gravity integration is a pure function testable without a renderer — the controller just owns the ref.
568
763
 
764
+ ## @jgengine/core/movement/movementProbe
765
+
766
+ - `MovementProbeOptions` (interface): interface MovementProbeOptions — Scenario settings for {@link measureMovement}; every field has a default.
767
+ - `MovementProbeSubject` (interface): interface MovementProbeSubject — The walk character {@link measureMovement} drives: the same fields a game passes to `defineGame`.
768
+ - `MovementReport` (interface): interface MovementReport — Deterministic walk-feel metrics. `Infinity` means the target was never reached.
769
+ - `measureMovement` (function): function measureMovement(subject: MovementProbeSubject = {}, options: MovementProbeOptions = {}): MovementReport — Drives a walk character through fixed scenarios (standing start, release to stop, reversal, a standing jump, a tapped jump, a strafed jump) on the same integrator `stepPlayerMovement` uses, and reports the feel metrics a test can assert. Deterministic: the same subject and options always produce the same report, so a feel change shows up as a number moving. Collision, terrain and swimming are out of scope; it measures flat ground.
770
+
569
771
  ## @jgengine/core/movement/playerMovement
570
772
 
773
+ - `PlayerMovementSnapshot` (interface): interface PlayerMovementSnapshot — One player's serializable movement state: heading, facing, velocities, jump latch and controller capsule. The entity pose lives in the entity store.
571
774
  - `PlayerMovementTuning` (interface): interface PlayerMovementTuning — The resolved, per-world movement configuration {@link stepPlayerMovement} integrates against — the same inputs the shell FrameDriver used to read piecemeal, gathered into one struct so single-player and host movement run identical math.
572
775
  - `forgetPlayerMovement` (function): function forgetPlayerMovement(ctx: GameContext, userId: string): void — Drop a player's retained movement state (heading + kinematic body) — call on leave so a rejoin starts fresh instead of resuming stale velocity.
573
776
  - `playerMovementHeading` (function): function playerMovementHeading(ctx: GameContext, userId: string): number — One player's current heading (radians), integrated by {@link stepPlayerMovement} — the shell reads it back into its camera/aim yaw.
574
777
  - `resolvePhysicsTuning` (function): function resolvePhysicsTuning(physics: PhysicsConfig | undefined): MovementTuningOverrides | undefined — Maps a game's declared `physics` onto the movement controllers' tuning. `PhysicsConfig.gravity` is a signed world acceleration (negative points down), but the controllers integrate `velocityY -= gravityAcceleration * dt` and expect a positive downward magnitude — so gravity is negated here to keep down-pointing gravity pulling down.
575
778
  - `resolvePlayerMovementTuning` (function): function resolvePlayerMovementTuning(opts: { collision?: VoxelCollisionConfig; movement?: PlayerMovementConfig; physics?: PhysicsConfig; world?: WorldFeature; }): PlayerMovementTuning — Gather a game's collision/movement/physics/world config into a {@link PlayerMovementTuning} — call once per world; both the shell and a host pass the result to {@link stepPlayerMovement}.
576
- - `stepPlayerMovement` (function): function stepPlayerMovement(ctx: GameContext, userId: string, input: InputFrame, dt: number, tuning: PlayerMovementTuning, heading?: number): void — Integrate one player's movement for a tick from their held-input frame and commit the pose — the single genre-agnostic controller both the shell (its local player) and a host (each connected player in `onTick`) call, so single-player and server-authoritative movement are identical. Reads the player's controlled entity, terrain, scene solids, and pending motion impulses; writes the entity pose via `setPose`. Retains heading + kinematic body per `userId` on the `ctx`. Pass `heading` to override the internally-integrated yaw (the shell owns yaw for its camera); omit it and the controller turns from the frame's `turnLeft`/`turnRight` actions.
779
+ - `restorePlayerMovement` (function): function restorePlayerMovement(ctx: GameContext, userId: string, snapshot: PlayerMovementSnapshot): void — Put a player's movement state back to a {@link snapshotPlayerMovement} copy, so the next {@link stepPlayerMovement} replays from there.
780
+ - `snapshotPlayerMovement` (function): function snapshotPlayerMovement(ctx: GameContext, userId: string): PlayerMovementSnapshot | null — Copy one player's movement state for prediction, rollback or a save; `null` when the player has not moved yet.
781
+ - `stepPlayerMovement` (function): function stepPlayerMovement(ctx: GameContext, userId: string, input: InputFrame, dt: number, tuning: PlayerMovementTuning, heading?: number, pitch?: number): void — Integrate one player's movement for a tick from their held-input frame and commit the pose — the single genre-agnostic controller both the shell (its local player) and a host (each connected player in `onTick`) call, so single-player and server-authoritative movement are identical. Reads the player's controlled entity, terrain, scene solids, and pending motion impulses; writes the entity pose via `setPose`. Retains heading + kinematic body per `userId` on the `ctx`. Pass `heading` to override the internally-integrated yaw (the shell owns yaw for its camera); omit it and the controller turns from the frame's `turnLeft`/`turnRight` actions. Pass `pitch` for 6DOF spectator flight when `alignWithLook` is set.
577
782
 
578
783
  ## @jgengine/core/movement/poseState
579
784
 
580
785
  - `AimMode` (type): type AimMode = "hip" | "ads" — ⚠ undocumented
581
786
  - `MovementPose` (type): type MovementPose = "standing" | "crouch" | "prone" | "running" — ⚠ undocumented
582
787
  - `POSE_HITBOX` (const): const POSE_HITBOX: Record<MovementPose, PoseHitbox> — ⚠ undocumented
583
- - `PoseAllowedStates` (interface): interface PoseAllowedStates — ⚠ undocumented
584
- - `PoseHitbox` (interface): interface PoseHitbox — ⚠ undocumented
585
- - `PoseRejection` (interface): interface PoseRejection — ⚠ undocumented
586
- - `PoseSnapshot` (interface): interface PoseSnapshot — ⚠ undocumented
587
- - `PoseState` (interface): interface PoseState — ⚠ undocumented
788
+ - `PoseAllowedStates` (interface): interface PoseAllowedStates { poses?: readonly MovementPose[]; aim?: readonly AimMode[] } — ⚠ undocumented · used by `createPoseState`: Stance/pose transitions — stand, crouch, prone — that change the hitbox and movement.
789
+ - `PoseHitbox` (interface): interface PoseHitbox { height: number; eyeHeight: number; speedMultiplier: number } — ⚠ undocumented
790
+ - `PoseRejection` (interface): interface PoseRejection { reason: string } — ⚠ undocumented
791
+ - `PoseSnapshot` (interface): interface PoseSnapshot { poses: Record<string, MovementPose>; aims: Record<string, AimMode> } — ⚠ undocumented
792
+ - `PoseState` (interface): interface PoseState { getPose(instanceId: string): MovementPose; setPose(instanceId: string, pose: MovementPose): PoseRejection | null; getAim(instanceId: string): AimMode; setAim(instanceId: string, mode: AimMode): PoseRejection | null; clear(instanceId: stri… — ⚠ undocumented · used by `createPoseState`: Stance/pose transitions — stand, crouch, prone — that change the hitbox and movement.
588
793
  - `createPoseState` (function): function createPoseState(resolveAllowed: (instanceId: string) => PoseAllowedStates | null | undefined): PoseState — Stance/pose transitions — stand, crouch, prone — that change the hitbox and movement.
589
794
 
795
+ ## @jgengine/core/movement/serverStep
796
+
797
+ - `serverStep` (function): function serverStep(ctx: GameContext, userId: string, frame: InputFrame, dt: number, tuning?: PlayerMovementTuning): void — Advance one authoritative player's movement using the same controller as the shell.
798
+
590
799
  ## @jgengine/core/movement/solidObstacles
591
800
 
592
801
  - `ObstacleReach` (interface): interface ObstacleReach — Largest blocking-collider extent in the scene, split so tower height cannot inflate the XZ query.
802
+ - `ObstacleReachCache` (interface): interface ObstacleReachCache — Mutable reach cache; one per source, invalidated by object count.
803
+ - `SolidObstacleSource` (interface): interface SolidObstacleSource — The slice of the scene's object store this query needs. Narrow on purpose: the scene context wires its own store here while it is still being constructed, `ctx.scene.object` satisfies it as-is, and a pure rules package with no `GameContext` to import can satisfy it from its own object list.
804
+ - `createObstacleReachCache` (function): function createObstacleReachCache(): ObstacleReachCache — A fresh {@link ObstacleReachCache} for a caller that owns its own source.
805
+ - `obstacleFromSolid` (function): function obstacleFromSolid(solid: WorldSolid): CollisionObstacle — A {@link WorldSolid} as a {@link CollisionObstacle}. Axis-aligned solids are one box; a yawed solid is cut into strips along its long axis, each fitted with an AABB, so a turned building does not block the street beside it the way a single enclosing box would.
806
+ - `resolveSourceWalkerStep` (function): function resolveSourceWalkerStep(source: SolidObstacleSource, cache: ObstacleReachCache, position: EntityPosition, stepX: number, stepZ: number, options: { radius?: number; stepUpHeight?: number } = {}): { stepX: number; stepZ: number } — {@link resolveWalkerStep} with no `GameContext`: gather plus slide against a bare {@link SolidObstacleSource} and a caller-owned {@link ObstacleReachCache}.
593
807
  - `resolveWalkerStep` (function): function resolveWalkerStep(ctx: GameContext, position: EntityPosition, stepX: number, stepZ: number, options: { radius?: number; stepUpHeight?: number } = {}): { stepX: number; stepZ: number } — Slide a walker's horizontal step against the same solid geometry that stops the player, returning the X/Z it may actually take this tick. A step into a wall is cut on the blocked axis and preserved on the other, exactly as {@link stepPlayerMovement} resolves the player's.
594
- - `solidObstaclesNear` (function): function solidObstaclesNear(ctx: GameContext, position: EntityPosition, reachX: number, reachZ: number, height = WALKER_HEIGHT): CollisionObstacle[] — Every blocking physical obstacle overlapping the box `position` ± `reachX`/`reachZ`, read from the scene's resolved colliders.
808
+ - `slideStep` (function): function slideStep(position: EntityPosition, stepX: number, stepZ: number, obstacles: readonly CollisionObstacle[], radius = DEFAULT_OBSTACLE_PLAYER_RADIUS, stepUpHeight = 0): { stepX: number; stepZ: number } — {@link resolveWalkerStep} against an already-gathered obstacle set.
809
+ - `solidObstaclesNear` (function): function solidObstaclesNear(ctx: GameContext, position: EntityPosition, reachX: number, reachZ: number, height = WALKER_HEIGHT): CollisionObstacle[] — Every blocking physical obstacle overlapping the box `position` ± `reachX`/`reachZ`, read from the scene's resolved colliders and `ctx.world.solids`.
810
+ - `sourceObstacleReach` (function): function sourceObstacleReach(source: SolidObstacleSource, cache: ObstacleReachCache): ObstacleReach — {@link solidObstacleReach} against a bare source and caller-owned cache.
811
+ - `sourceObstaclesNear` (function): function sourceObstaclesNear(source: SolidObstacleSource, reach: ObstacleReach, position: EntityPosition, reachX: number, reachZ: number, height = WALKER_HEIGHT): CollisionObstacle[] — {@link solidObstaclesNear} against a bare source and an already-resolved reach.
595
812
 
596
813
  ## @jgengine/core/movement/steering
597
814
 
@@ -605,7 +822,7 @@
605
822
 
606
823
  - `DEFAULT_VOXEL_DIMS` (const): const DEFAULT_VOXEL_DIMS: VoxelPlayerDims — ⚠ undocumented
607
824
  - `GroundHeightQuery` (type): type GroundHeightQuery = (x: number, z: number) => number — Samples the terrain floor height at a point; unset means flat ground plays no part in support.
608
- - `SolidQuery` (type): type SolidQuery = (x: number, y: number, z: number) => boolean — ⚠ undocumented
825
+ - `SolidQuery` (type): type SolidQuery = (x: number, y: number, z: number) => boolean — ⚠ undocumented · used by `advanceVoxelPlayer`: Advance one frame of voxel-collided player kinematics.
609
826
  - `VoxelPlayerBody` (interface): interface VoxelPlayerBody — Mutable kinematic state carried between frames by the voxel controller.
610
827
  - `VoxelPlayerDims` (interface): interface VoxelPlayerDims — Footprint + height of the player box, in world units.
611
828
  - `advanceVoxelPlayer` (function): function advanceVoxelPlayer(body: VoxelPlayerBody, intent: MovementIntent, forwardX: number, forwardZ: number, baseSpeed: number, rawDeltaSeconds: number, isSolid: SolidQuery, dims: VoxelPlayerDims = DEFAULT_VOXEL_DIMS, tuning?: MovementTuningOverrides, groundHeight?: GroundHeightQuery): void — Advance one frame of voxel-collided player kinematics. Mutates `body` (position, velocity, grounded) in place.
@@ -613,44 +830,60 @@
613
830
 
614
831
  ## @jgengine/core/nav/corridors
615
832
 
616
- - `CorridorEdge` (interface): interface CorridorEdge — ⚠ undocumented
833
+ - `CorridorEdge` (interface): interface CorridorEdge { points: readonly CorridorPoint[]; width: number } — ⚠ undocumented
617
834
  - `CorridorField` (interface): interface CorridorField — Organic corridor/path collision (#284.9): a distance-to-polyline width clamp over an edge graph — cave tunnels, river channels, winding roads. Grid/navmesh/voxel collision can't express a smooth ribbon; this can. Pure math over authored centerlines.
618
835
  - `CorridorPoint` (type): type CorridorPoint = readonly [number, number] — ⚠ undocumented
619
- - `CorridorSample` (interface): interface CorridorSample — ⚠ undocumented
836
+ - `CorridorSample` (interface): interface CorridorSample { distance: number; closest: CorridorPoint; edgeIndex: number } — ⚠ undocumented
620
837
  - `createCorridorField` (function): function createCorridorField(edges: readonly CorridorEdge[]): CorridorField — ⚠ undocumented
621
838
 
622
839
  ## @jgengine/core/nav/navConstrain
623
840
 
624
- - `NavConstrainEntity` (interface): interface NavConstrainEntity — ⚠ undocumented
625
- - `NavConstrainOptions` (interface): interface NavConstrainOptions — ⚠ undocumented
626
- - `NavConstrainProposed` (interface): interface NavConstrainProposed — ⚠ undocumented
841
+ - `NavConstrainEntity` (interface): interface NavConstrainEntity { position: EntityPosition } — ⚠ undocumented
842
+ - `NavConstrainOptions` (interface): interface NavConstrainOptions { y?: (point: NavPoint) => number } — ⚠ undocumented
843
+ - `NavConstrainProposed` (interface): interface NavConstrainProposed { position: EntityPosition; rotationY: number; grounded: boolean } — ⚠ undocumented
627
844
  - `constrainToNavGrid` (function): function constrainToNavGrid(grid: NavGrid, options?: NavConstrainOptions): (proposed: NavConstrainProposed, entity: NavConstrainEntity) => NavConstrainProposed | null — ⚠ undocumented
628
845
 
629
846
  ## @jgengine/core/nav/navFromEnvironment
630
847
 
631
- - `NavObstacleGrid` (interface): interface NavObstacleGrid — ⚠ undocumented
632
- - `populateNavGridFromEnvironment` (function): function populateNavGridFromEnvironment(grid: NavObstacleGrid, world: EnvironmentWorldFeature): number — Expands every structure descriptor on an environment world feature into its generated buildings and blocks their footprints on `grid`. Returns the number of buildings blocked.
848
+ - `NavObstacleGrid` (interface): interface NavObstacleGrid { blockAabb(aabb: Aabb): void } — ⚠ undocumented · used by `populateNavGridFromEnvironment`: Blocks the footprint of every solid building an environment feature's `structures` generate — the same set `ctx.world.solids` holds for it.
849
+ - `populateNavGridFromEnvironment` (function): function populateNavGridFromEnvironment(grid: NavObstacleGrid, world: EnvironmentWorldFeature): number — Blocks the footprint of every solid building an environment feature's `structures` generate — the same set `ctx.world.solids` holds for it. Returns the number of buildings blocked.
850
+ - `populateNavGridFromSolids` (function): function populateNavGridFromSolids(grid: NavObstacleGrid, solids: Pick<WorldSolids, "all">): number — Blocks the XZ footprint of every solid in `solids` (usually `ctx.world.solids`) on `grid`, so NPC paths avoid exactly what movement and physics collide with. Returns the number of solids blocked.
633
851
 
634
852
  ## @jgengine/core/nav/navGrid
635
853
 
636
- - `FindPathOptions` (interface): interface FindPathOptions — ⚠ undocumented
637
- - `NavCell` (interface): interface NavCell — ⚠ undocumented
638
- - `NavGrid` (interface): interface NavGrid — ⚠ undocumented
639
- - `NavGridConfig` (interface): interface NavGridConfig — ⚠ undocumented
640
- - `NavPoint` (type): type NavPoint = readonly [number, number] — ⚠ undocumented
854
+ - `FindPathOptions` (interface): interface FindPathOptions { smooth?: boolean; clearance?: number; stepCost?: (from: NavPoint, to: NavPoint) => number } — ⚠ undocumented · used by `findPath`: A* over the walkable grid.
855
+ - `NavCell` (interface): interface NavCell { col: number; row: number } — ⚠ undocumented
856
+ - `NavGrid` (interface): interface NavGrid { readonly cols: number; readonly rows: number; readonly cellSize: number; readonly bounds: Aabb; readonly diagonal: boolean; isWalkable(col: number, row: number): boolean; setWalkable(col: number, row: number, walkable: boolean): void; blo… — ⚠ undocumented · used by `findPath`: A* over the walkable grid.
857
+ - `NavGridConfig` (interface): interface NavGridConfig { bounds: Aabb; cellSize: number; diagonal?: boolean } — ⚠ undocumented
858
+ - `NavPoint` (type): type NavPoint = readonly [number, number] — ⚠ undocumented · used by `findPath`: A* over the walkable grid.
641
859
  - `createNavGrid` (function): function createNavGrid(config: NavGridConfig): NavGrid — ⚠ undocumented
642
860
  - `findPath` (function): function findPath(grid: NavGrid, from: NavPoint, to: NavPoint, options: FindPathOptions = {}): NavPoint[] | null — A* over the walkable grid. Returns a polyline of world-space `[x, z]` waypoints from `from` to `to`, or `null` when no route exists. Blocked start/goal snap to the nearest walkable cell so a click on an obstacle still routes to its edge.
643
861
  - `slopeStepCost` (function): function slopeStepCost(field: { sampleHeight(x: number, z: number): number }, weight = DEFAULT_SLOPE_STEP_WEIGHT): (from: NavPoint, to: NavPoint) => number — `FindPathOptions.stepCost` factory that penalizes steep terrain: cost is `1 + weight * |Δheight| / horizontalDistance`, so with the default weight a 45° slope roughly doubles the step cost.
644
862
  - `smoothPath` (function): function smoothPath(grid: NavGrid, points: readonly NavPoint[]): NavPoint[] — Remove waypoints the mover can skip because it has clear line-of-sight past them.
645
863
 
864
+ ## @jgengine/core/nav/navMesh
865
+
866
+ - `NavMeshAdjacency` (interface): interface NavMeshAdjacency — Neighbor relationship for one navigation polygon.
867
+ - `NavMeshData` (interface): interface NavMeshData — Serializable polygon navigation mesh data. Treat it as immutable once queried; queries cache derived geometry per object.
868
+ - `NavMeshLink` (interface): interface NavMeshLink — Explicit traversable connection between two navigation polygons.
869
+ - `NavMeshPath` (interface): interface NavMeshPath — Route points and polygons selected through a navigation mesh.
870
+ - `NavMeshQuery` (interface): interface NavMeshQuery — Cached, allocation-light queries over one {@link NavMeshData}.
871
+ - `NavMeshQueryOptions` (interface): interface NavMeshQueryOptions — Tunable pricing and bounds for a {@link NavMeshQuery}.
872
+ - `NavMeshQuerySnapshot` (interface): interface NavMeshQuerySnapshot — Serializable tuning of a {@link NavMeshQuery}.
873
+ - `buildNavAdjacency` (function): function buildNavAdjacency(mesh: NavMeshData): NavMeshAdjacency[] — Build polygon adjacency from shared edges and explicit off-mesh links.
874
+ - `closestPoint` (function): function closestPoint(mesh: NavMeshData, point: Vec3): Vec3 | null — Return the closest point on the mesh surface, or null for an empty mesh.
875
+ - `createNavMeshQuery` (function): function createNavMeshQuery(mesh: NavMeshData, options: NavMeshQueryOptions = {}): NavMeshQuery — Create a cached query over a nav mesh: height-aware polygon lookup through a uniform grid, binary-heap A* priced by area costs and bounded by `maxNodes`, portal-funnel path straightening, and edge-walking raycasts.
876
+ - `findPath` (function): function findPath(mesh: NavMeshData, from: Vec3, to: Vec3): NavMeshPath | null — A* over polygon portals with default area costs, straightened by a portal funnel. Use {@link createNavMeshQuery} to price areas.
877
+ - `raycastNav` (function): function raycastNav(mesh: NavMeshData, from: Vec3, to: Vec3): boolean — True when the segment remains over walkable polygons.
878
+
646
879
  ## @jgengine/core/nav/pathFollow
647
880
 
648
- - `HeightSampler` (interface): interface HeightSampler — ⚠ undocumented
649
- - `PathFollowConfig` (interface): interface PathFollowConfig — ⚠ undocumented
881
+ - `HeightSampler` (interface): interface HeightSampler { sampleHeight(x: number, z: number): number } — ⚠ undocumented · used by `drapePolyline` (@jgengine/core/world): Drapes an XZ polyline onto the surface: subdivides each span to at most `spacing` and lifts every vertex to `sampleHeight + offset`, returni…
882
+ - `PathFollowConfig` (interface): interface PathFollowConfig { waypoints: readonly Waypoint[]; speed: number; loop?: boolean } — ⚠ undocumented · used by `advancePathFollow`: Advance a path-follower by `speed * dt` along its authored polyline.
650
883
  - `PathFollowProgress` (interface): interface PathFollowProgress — Read-only progress readout for inspection/debug tooling, produced by {@link pathFollowProgress}.
651
- - `PathFollowState` (interface): interface PathFollowState — ⚠ undocumented
884
+ - `PathFollowState` (interface): interface PathFollowState { position: Waypoint; target: number; heading: number; done: boolean; distanceTravelled: number } — ⚠ undocumented · used by `advancePathFollow`: Advance a path-follower by `speed * dt` along its authored polyline.
652
885
  - `PathProgress` (type): type PathProgress = | { readonly kind: "normalized"; readonly value: number } /** World-distance travelled from the first waypoint (looping paths wrap; clamped otherwise). */ | { readonly kind: "distance"; readonly value: number } /** Segment `index` (0-based) plus `fraction` `0..1` along that segme… — Semantic seek target for {@link pathFollowSeek} — the caller-facing progress vocabulary a stateful path behavior restores from, so a follower can start at a distributed phase or resume a serialized route without knowing waypoint internals. `direction` (forward heading) falls out of the resulting {@link PathFollowState.heading}, so it is an output rather than a seek input.
653
- - `Waypoint` (type): type Waypoint = readonly [number, number, number] — ⚠ undocumented
886
+ - `Waypoint` (type): type Waypoint = readonly [number, number, number] — ⚠ undocumented · used by `useWaypoints` (@jgengine/react): Subscribe to a {@link WaypointTracker} and re-render on every change, returning its current waypoints.
654
887
  - `advancePathFollow` (function): function advancePathFollow(config: PathFollowConfig, state: PathFollowState, dt: number): PathFollowState — Advance a path-follower by `speed * dt` along its authored polyline. Pure — returns the next state. Crosses multiple waypoints in one step, loops when configured, and reports `done` at the end of a non-looping path. No navmesh required (#52); feed it a navmesh route via `pathFromNav` for click-to-move (#51).
655
888
  - `createPathFollow` (function): function createPathFollow(config: PathFollowConfig): PathFollowState — ⚠ undocumented
656
889
  - `pathFollowProgress` (function): function pathFollowProgress(config: PathFollowConfig, state: PathFollowState): PathFollowProgress — Read a follower's current progress in every semantic form — the inverse of {@link pathFollowSeek}, for editor/debug inspection and progress HUDs. Pure and allocation-light.
@@ -660,23 +893,23 @@
660
893
 
661
894
  ## @jgengine/core/nav/railGraph
662
895
 
663
- - `RailEdge` (interface): interface RailEdge — ⚠ undocumented
896
+ - `RailEdge` (interface): interface RailEdge { id: string; from: string; to: string; via?: readonly Waypoint[] } — ⚠ undocumented
664
897
  - `RailGraph` (interface): interface RailGraph — A directed graph of track segments with junction switch-throw semantics — the topological seam `nav/navGrid`'s walkable cells can't express. Each node with several out-edges is a switch whose thrown edge decides where traffic exits; riders (`createRailRider`) run along edge polylines and take the thrown edge at every junction.
665
- - `RailGraphConfig` (interface): interface RailGraphConfig — ⚠ undocumented
666
- - `RailNode` (interface): interface RailNode — ⚠ undocumented
667
- - `RailRider` (interface): interface RailRider — ⚠ undocumented
668
- - `RailRiderConfig` (interface): interface RailRiderConfig — ⚠ undocumented
669
- - `RailRiderPose` (interface): interface RailRiderPose — ⚠ undocumented
670
- - `ResolvedRailEdge` (interface): interface ResolvedRailEdge — ⚠ undocumented
898
+ - `RailGraphConfig` (interface): interface RailGraphConfig { nodes: readonly RailNode[]; edges: readonly RailEdge[] } — ⚠ undocumented
899
+ - `RailNode` (interface): interface RailNode { id: string; at: Waypoint } — ⚠ undocumented
900
+ - `RailRider` (interface): interface RailRider { advance(dt: number): RailRiderPose; pose(): RailRiderPose; setSpeed(speed: number): void; place(edgeId: string, s?: number): void } — ⚠ undocumented
901
+ - `RailRiderConfig` (interface): interface RailRiderConfig { edgeId: string; s?: number; speed: number } — ⚠ undocumented
902
+ - `RailRiderPose` (interface): interface RailRiderPose { position: Waypoint; heading: number; edgeId: string; s: number; atDeadEnd: boolean } — ⚠ undocumented
903
+ - `ResolvedRailEdge` (interface): interface ResolvedRailEdge { id: string; from: string; to: string; points: readonly Waypoint[]; length: number } — ⚠ undocumented
671
904
  - `createRailGraph` (function): function createRailGraph(config: RailGraphConfig): RailGraph — ⚠ undocumented
672
905
  - `createRailRider` (function): function createRailRider(graph: RailGraph, config: RailRiderConfig): RailRider — ⚠ undocumented
673
906
 
674
907
  ## @jgengine/core/nav/timetable
675
908
 
676
909
  - `RouteTimetable` (interface): interface RouteTimetable — A deterministic mover over an authored route: position is a pure function of absolute time, so a forecast preview (`poseAt(t + 30)`) and the live mover can never disagree — the seam `nav/pathFollow`'s dt-incremental state can't offer. Trains, ferries, patrol shuttles, crushers: anything on a timetable.
677
- - `RouteTimetableConfig` (interface): interface RouteTimetableConfig — ⚠ undocumented
678
- - `TimetablePose` (interface): interface TimetablePose — ⚠ undocumented
679
- - `TimetableStop` (interface): interface TimetableStop — ⚠ undocumented
910
+ - `RouteTimetableConfig` (interface): interface RouteTimetableConfig { waypoints: readonly (Waypoint | TimetableStop)[]; speed: number; loop?: boolean; dwellSeconds?: number; offsetSeconds?: number } — ⚠ undocumented
911
+ - `TimetablePose` (interface): interface TimetablePose { position: Waypoint; heading: number; segment: number; dwelling: boolean } — ⚠ undocumented
912
+ - `TimetableStop` (interface): interface TimetableStop { at: Waypoint; dwellSeconds?: number } — ⚠ undocumented
680
913
  - `createRouteTimetable` (function): function createRouteTimetable(config: RouteTimetableConfig): RouteTimetable — ⚠ undocumented
681
914
 
682
915
  ## @jgengine/core/orders/orderKinds
@@ -723,45 +956,83 @@
723
956
  - `createOrderQueue` (function): function createOrderQueue<TCtx, TPayload = unknown>(registry: OrderRegistry<TCtx>, options: OrderQueueOptions<TPayload> = {}): OrderQueue<TCtx, TPayload> — Create a per-entity order queue over a shared kind registry. The queue owns the deterministic lifecycle and preemption policy; the kinds own behavior. Nothing here is random or unbounded: id generation is injected, activation is bounded by the pending count, and a single `tick` advances at most the active order plus one activation.
724
957
  - `createOrderRegistry` (function): function createOrderRegistry<TCtx>(): OrderRegistry<TCtx> — Build an empty order-kind registry. Register the built-in compositions from `orders/orderKinds` or your own verbs, then hand it to `createOrderQueue`. One registry is shared by many per-entity queues.
725
958
 
959
+ ## @jgengine/core/physics/aircraftDynamics
960
+
961
+ - `AircraftAssistCommand` (interface): interface AircraftAssistCommand — Control commands, `-1..1`, that drive the actuators after the assists.
962
+ - `AircraftAssistContext` (interface): interface AircraftAssistContext — What an assist sees each substep, derived from the integrator state so it replays deterministically.
963
+ - `AircraftAssistTuning` (interface): interface AircraftAssistTuning — Flight assists. Each one moves the same actuators the pilot does, so a stronger assist still flies within the airframe's authority. Strengths are `0..1`; an axis the pilot is deflecting gets less help the further the stick is pushed, so full stick is always the pilot's.
964
+ - `AircraftControlChannel` (interface): interface AircraftControlChannel — One control channel's actuator: how far the surfaces move and how fast.
965
+ - `AircraftEngineTuning` (interface): interface AircraftEngineTuning — A thrust source fixed to the body.
966
+ - `AircraftGearTuning` (interface): interface AircraftGearTuning — Wheels or skids: what the body rests on when it touches the ground.
967
+ - `AircraftMotorTuning` (interface): interface AircraftMotorTuning — A rocket motor: thrust follows a curve over burn time, propellant leaves at a mass flow so the body gets lighter and easier to turn, and the nozzle gimbals on the pitch and yaw channels. Stage by `retune`-ing to the next stage's mass and motor.
968
+ - `AircraftQuaternion` (type): type AircraftQuaternion = readonly [number, number, number, number] — Unit quaternion `[x, y, z, w]` taking body-frame vectors to world space.
969
+ - `AircraftRotorTuning` (interface): interface AircraftRotorTuning — A main rotor. Collective sets blade pitch, throttle sets rotor speed, and cyclic (the pitch and roll channels) tilts the disc. Its drag torque yaws the body the other way unless a tail rotor, a second rotor or a pedal input cancels it.
970
+ - `AircraftSurface` (interface): interface AircraftSurface — One lifting surface: a wing panel, a tailplane, a fin, a canard. Its lift acts at `at`, so the moments that pitch, roll and yaw the body come from where the surfaces sit, not from commanded rates.
971
+ - `AircraftVector` (type): type AircraftVector = readonly [number, number, number] — Body-frame or world-frame vector, m or N. The body frame is `[left, up, forward]` about the centre of mass.
972
+ - `RigidAircraft` (interface): interface RigidAircraft — A force-and-torque aircraft on the same tick/snapshot/retune contract as `VehicleDynamics`.
973
+ - `RigidAircraftInput` (interface): interface RigidAircraftInput — Pilot input for one tick.
974
+ - `RigidAircraftModifiers` (interface): interface RigidAircraftModifiers — Per-tick overrides layered over tuning: damage, icing, boost, gusts. Each scale defaults to `1`.
975
+ - `RigidAircraftOptions` (interface): interface RigidAircraftOptions — World hooks for one aircraft instance.
976
+ - `RigidAircraftState` (interface): interface RigidAircraftState — Serializable integrator state: everything `restore` needs to resume bit-for-bit.
977
+ - `RigidAircraftStep` (interface): interface RigidAircraftStep — One aircraft tick: pose plus the telemetry HUDs, camera, sound and probes read.
978
+ - `RigidAircraftTuning` (interface): interface RigidAircraftTuning — A rigid aircraft in physical units. There is no aircraft type: a jet, a glider and a paper plane differ only in these numbers. Rotation comes from surface forces acting on the inertia tensor, so loops, rolls, stalls and weathervaning are outcomes, not special cases.
979
+ - `aircraftAttitudeQuaternion` (function): function aircraftAttitudeQuaternion(heading: number, pitch: number, bank: number): AircraftQuaternion — Quaternion from heading, nose-up pitch and right bank, rad — the inverse of a step's `heading`/`pitch`/`bank`. Matches three.js `Euler(-pitch, heading, bank, "YXZ")`.
980
+ - `aircraftHeadingQuaternion` (function): function aircraftHeadingQuaternion(heading: number): AircraftQuaternion — Quaternion for a heading about world up, forward `[sin h, 0, cos h]`.
981
+ - `createRigidAircraft` (function): function createRigidAircraft(initial: RigidAircraftTuning, options: RigidAircraftOptions = {}): RigidAircraft — Creates a {@link RigidAircraft}: a quaternion rigid body with a diagonal inertia tensor, pushed by lifting surfaces, fuselage drag, an engine and gravity. Controls deflect surfaces through rate-limited actuators; nothing commands a rotation rate, so a jet loops when its tail can push the nose around and a glider stalls when it runs out of speed. Fixed internal substeps make it deterministic for a given `dt` sequence.
982
+
726
983
  ## @jgengine/core/physics/ballisticSweep
727
984
 
728
- - `BallisticSweep` (type): type BallisticSweep = ( origin: readonly [number, number, number], velocity: readonly [number, number, number], gravity: number, maxTime: number, ) => BallisticSweepHit | null — ⚠ undocumented
729
- - `BallisticSweepHit` (interface): interface BallisticSweepHit — ⚠ undocumented
730
- - `BallisticSweepOptions` (interface): interface BallisticSweepOptions — ⚠ undocumented
985
+ - `BallisticSweep` (type): type BallisticSweep = ( origin: readonly [number, number, number], velocity: readonly [number, number, number], gravity: number, maxTime: number, ) => BallisticSweepHit | null — ⚠ undocumented · used by `createBallisticSweep`: Marches the closed-form arc (constant gravity, straight lateral) through `world` and reports the first sample inside any live body's AABB — …
986
+ - `BallisticSweepHit` (interface): interface BallisticSweepHit { point: [number, number, number]; time: number } — ⚠ undocumented
987
+ - `BallisticSweepOptions` (interface): interface BallisticSweepOptions { step?: number; radius?: number } — ⚠ undocumented · used by `createBallisticSweep`: Marches the closed-form arc (constant gravity, straight lateral) through `world` and reports the first sample inside any live body's AABB — …
731
988
  - `createBallisticSweep` (function): function createBallisticSweep(world: PhysicsWorld, options: BallisticSweepOptions = {}): BallisticSweep — Marches the closed-form arc (constant gravity, straight lateral) through `world` and reports the first sample inside any live body's AABB — sleeping bodies included — refined by one bisection between the last clear sample and the hit sample. Returns `null` when the whole arc is clear.
732
989
 
990
+ ## @jgengine/core/physics/boatDynamics
991
+
992
+ - `BoatDynamics` (interface): interface BoatDynamics — A force-based powered hull on the same tick/snapshot/retune contract as `VehicleDynamics`.
993
+ - `BoatOptions` (interface): interface BoatOptions — World hooks for a boat instance.
994
+ - `BoatState` (interface): interface BoatState — Serializable boat state.
995
+ - `BoatSteering` (type): type BoatSteering = | { kind: "rudder"; /** Rudder area, m². */ area: number; /** Largest rudder angle, rad (default `0.6`). */ maxAngle?: number; /** Share of prop thrust that washes over the rudder as flow, `0..1` (default `0.5`) — steering at low speed. */ propWash?: number; } | { kind: "outboard… — How the boat turns: a rudder needs water flowing past it; an outboard swings its own thrust.
996
+ - `BoatStep` (interface): interface BoatStep — One boat tick: pose plus the telemetry wake, spray and engine sound read.
997
+ - `BoatTuning` (interface): interface BoatTuning — A powered hull in physical units. Drag rises toward hull speed (`√(g·L)·1.34`) and then falls away once the hull planes, the keel resists sliding sideways, and the prop's thrust fades as the boat approaches the prop's speed.
998
+ - `createBoatDynamics` (function): function createBoatDynamics(initial: BoatTuning, options: BoatOptions = {}): BoatDynamics — Creates a {@link BoatDynamics}: throttle drives the prop, brake reverses it, steer swings the rudder or outboard. A rudder boat barely turns at rest unless the prop is washing over it; an outboard turns at rest because it swings the thrust itself. Deterministic for a given `dt` sequence.
999
+
733
1000
  ## @jgengine/core/physics/buoyancy
734
1001
 
735
1002
  - `BuoyantBody` (class): class BuoyantBody — Floats a {@link PhysicsWorld} body on a CPU {@link WaterSurface}: each hull sample point pushes the body up by its submerged depth (Archimedes, coarse), with vertical and horizontal water drag so the hull settles at the waterline and rides the Gerstner waves. Passing an {@link AxisInput} drives it as a boat — throttle thrusts along the heading, steer yaws, a keel bleeds sideways slip. Call `update(dt, time, input?)` before the shared `world.step(dt)`.
736
- - `BuoyantBodyConfig` (interface): interface BuoyantBodyConfig — ⚠ undocumented
1003
+ - `BuoyantBodyConfig` (interface): interface BuoyantBodyConfig { body: number; water: WaterSurface; heading?: number; hullPoints?: readonly (readonly [number, number])[]; hullDepth?: number; buoyancy?: number; verticalDrag?: number; linearDrag?: number; engineAccel?: number; reverseAccel?: number; topS… — ⚠ undocumented
737
1004
  - `createBuoyantBody` (function): function createBuoyantBody(world: PhysicsWorld, config: BuoyantBodyConfig): BuoyantBody — ⚠ undocumented
738
1005
 
739
1006
  ## @jgengine/core/physics/carryable
740
1007
 
741
1008
  - `Carryable` (class): class Carryable — A grabbed physics object following a moving hold point through a spring constraint (the pick — a raycast — is the caller's/shell's job; core owns the constraint). Supports shared multi-owner carry (the follow point is the average of owners' hold points), an encumbrance read, and drop/throw. Reuses `PhysicsWorld.springJoint` to a world anchor moved each frame.
742
- - `CarryableConfig` (interface): interface CarryableConfig — ⚠ undocumented
1009
+ - `CarryableConfig` (interface): interface CarryableConfig { followStiffness?: number; followDamping?: number; maxForce?: number; carryCapacity?: number } — ⚠ undocumented
743
1010
  - `carrySpeedMultiplier` (function): function carrySpeedMultiplier(mass: number, carryCapacity: number, owners: number): number — Movement multiplier (1 = unhindered, →0 = crushed) for a body of `mass` carried by `owners`. Pure — the HUD/movement kit reads it to slow a laden hauler (Lethal Company) and to gate items that need 2+ people (R.E.P.O.).
744
1011
 
745
1012
  ## @jgengine/core/physics/damageZones
746
1013
 
747
1014
  - `DamageModel` (class): class DamageModel — Coarse crash-damage model (issue #86 — stages, not soft-body). Each zone accumulates contact impulse fed from G3's `onCollision` `CollisionEvent`; crossing a threshold bumps the zone to the next discrete stage (the caller swaps the visual/collider), an optional `detachStage` ejects a part as debris once, and a total-impulse `disableAt` flips the whole body to a disabled state. `absorb` returns a transition only when something actually changed, so it doubles as the event source for HUD/feed.
748
- - `DamageModelConfig` (interface): interface DamageModelConfig — ⚠ undocumented
749
- - `DamageTransition` (interface): interface DamageTransition — ⚠ undocumented
750
- - `DamageZoneDef` (interface): interface DamageZoneDef — ⚠ undocumented
751
- - `DamageZoneState` (interface): interface DamageZoneState — ⚠ undocumented
1015
+ - `DamageModelConfig` (interface): interface DamageModelConfig { zones: readonly DamageZoneDef[]; disableAt?: number; onStage?: (transition: DamageTransition) => void; onDetach?: (zoneId: string, accumulated: number) => void } — ⚠ undocumented
1016
+ - `DamageTransition` (interface): interface DamageTransition { zone: string; stage: number; previousStage: number; detached: boolean; disabled: boolean; accumulated: number; total: number } — ⚠ undocumented
1017
+ - `DamageZoneDef` (interface): interface DamageZoneDef { id: string; thresholds: readonly number[]; detachStage?: number } — ⚠ undocumented
1018
+ - `DamageZoneState` (interface): interface DamageZoneState { id: string; accumulated: number; stage: number; detached: boolean } — ⚠ undocumented
752
1019
  - `createDamageModel` (function): function createDamageModel(config: DamageModelConfig): DamageModel — ⚠ undocumented
753
1020
 
754
1021
  ## @jgengine/core/physics/drivableVehicle
755
1022
 
756
- - `DrivableVehicleOptions` (interface): interface DrivableVehicleOptions — Options for {@link tickDrivableVehicle} — ground snapping and per-tick tuning modifiers.
1023
+ - `DrivableSim` (interface): interface DrivableSim<TModifiers, TStep extends DrivableSimStep> — Any ground-vehicle sim {@link tickDrivableVehicle} can drive: `KinematicVehicle` or `VehicleDynamics`.
1024
+ - `DrivableSimStep` (interface): interface DrivableSimStep — The pose fields {@link tickDrivableVehicle} reads from a sim step; `KinematicVehicleStep` and `VehicleDynamicsStep` both carry them.
1025
+ - `DrivableVehicleOptions` (interface): interface DrivableVehicleOptions<TModifiers = KinematicVehicleModifiers> — Options for {@link tickDrivableVehicle} — ground snapping and per-tick tuning modifiers.
757
1026
  - `DrivableVehiclePose` (interface): interface DrivableVehiclePose — A `setPose`-ready patch — spread straight into `entities.setPose(vehicleId, drive.pose)`.
758
1027
  - `DrivableVehiclePosition` (type): type DrivableVehiclePosition = readonly [number, number, number] — World-space `[x, y, z]` for a drivable vehicle's resolved pose.
759
- - `DrivableVehicleStep` (interface): interface DrivableVehicleStep — {@link tickDrivableVehicle}'s result — the ready-to-apply pose patch plus the raw sim step for HUD/telemetry reads.
760
- - `tickDrivableVehicle` (function): function tickDrivableVehicle(vehicle: KinematicVehicle, dt: number, axis: AxisInput, options: DrivableVehicleOptions = {}): DrivableVehicleStep — Connects an `AxisInput` sample straight through a {@link KinematicVehicle} to a scene entity's pose for one tick (#533.1) — the throttle/steer/handbrake → sim → `setPose` loop every drivable-vehicle game hand-rolled. Ground-snaps the result when `groundHeight` is given (terrain-following cars, not just flat racetracks). Pair with `scene/vehicleSeat` for who is allowed to drive and where the camera points; this function only steps the sim and shapes the pose patch, nothing else.
1028
+ - `DrivableVehicleStep` (interface): interface DrivableVehicleStep<TStep extends DrivableSimStep = KinematicVehicleStep> — {@link tickDrivableVehicle}'s result — the ready-to-apply pose patch plus the raw sim step for HUD/telemetry reads.
1029
+ - `tickDrivableVehicle` (function): function tickDrivableVehicle<TStep extends DrivableSimStep = KinematicVehicleStep, TModifiers = KinematicVehicleModifiers>(vehicle: DrivableSim<TModifiers, TStep>, dt: number, axis: AxisInput, options: DrivableVehicleOptions<TModifiers> = {}): DrivableVehicleStep<TStep> — Connects an `AxisInput` sample straight through a ground-vehicle sim (`KinematicVehicle` or `VehicleDynamics`) to a scene entity's pose for one tick (#533.1) — the throttle/steer/handbrake → sim → `setPose` loop every drivable-vehicle game hand-rolled. Ground-snaps the result when `groundHeight` is given (terrain-following cars, not just flat racetracks). Pair with `scene/vehicleSeat` for who is allowed to drive and where the camera points; this function only steps the sim and shapes the pose patch, nothing else.
761
1030
 
762
1031
  ## @jgengine/core/physics/flightDynamics
763
1032
 
1033
+ - `AircraftAxis` (type): type AircraftAxis = "pitch" | "roll" | "yaw" | "throttle" | "collective" | "airbrake" | "afterburner" | "vectoring" — Axes an aircraft can bind — which actions drive each flight control.
764
1034
  - `AircraftDynamics` (interface): interface AircraftDynamics — Stateful six-degree-of-freedom aircraft simulation.
1035
+ - `AircraftDynamicsState` (interface): interface AircraftDynamicsState — Serializable integrator state of an {@link AircraftDynamics}: what `restore` needs to resume bit-for-bit.
765
1036
  - `AircraftKind` (type): type AircraftKind = "fixedWing" | "rotorcraft" | "vtol" — Supported aerodynamic/propulsion families.
766
1037
  - `AircraftOptions` (interface): interface AircraftOptions — Spawn state and injectable world-field samplers for an aircraft instance.
767
1038
  - `AircraftStep` (interface): interface AircraftStep — Pose and aerodynamic telemetry returned after one flight tick.
@@ -769,26 +1040,26 @@
769
1040
  - `FlightControlInput` (interface): interface FlightControlInput — Normalized pilot inputs for one flight-simulation tick.
770
1041
  - `FlightControlRates` (interface): interface FlightControlRates — Angular authority, response, damping, and self-leveling configuration.
771
1042
  - `FlightVector` (type): type FlightVector = readonly [number, number, number] — Three-dimensional world-space vector used by the flight model.
772
- - `createAircraftDynamics` (function): function createAircraftDynamics(tuning: AircraftTuning, options: AircraftOptions = {}): AircraftDynamics — Six-degree-of-freedom arcade flight model for fixed-wing, helicopter, and VTOL aircraft.
1043
+ - `createAircraftDynamics` (function): function createAircraftDynamics(initialTuning: AircraftTuning, options: AircraftOptions = {}): AircraftDynamics — Six-degree-of-freedom arcade flight model for fixed-wing, helicopter, and VTOL aircraft.
773
1044
 
774
1045
  ## @jgengine/core/physics/flowTube
775
1046
 
776
1047
  - `FlowTube` (interface): interface FlowTube — An axial corridor of directional flow with radial core falloff and a spool scalar — fan tunnels, updraft shafts, river narrows, thruster wash. Pure math: sample `velocityAt(point, spool)` and add it to whatever integrator moves the body (walk controller drift, `BuoyantBody`, a custom sim).
777
- - `FlowTubeConfig` (interface): interface FlowTubeConfig — ⚠ undocumented
778
- - `FlowVec3` (type): type FlowVec3 = readonly [number, number, number] — ⚠ undocumented
1048
+ - `FlowTubeConfig` (interface): interface FlowTubeConfig { from: FlowVec3; to: FlowVec3; radius: number; strength: number; falloff?: number; capFalloff?: number } — ⚠ undocumented
1049
+ - `FlowVec3` (type): type FlowVec3 = readonly [number, number, number] — ⚠ undocumented · used by `combineFlowVelocity`: Sum several tubes' flow at one point — each entry carries its own spool.
779
1050
  - `combineFlowVelocity` (function): function combineFlowVelocity(tubes: readonly (FlowTube | { tube: FlowTube; spool: number })[], point: FlowVec3): FlowVec3 — Sum several tubes' flow at one point — each entry carries its own spool.
780
1051
  - `createFlowTube` (function): function createFlowTube(config: FlowTubeConfig): FlowTube — ⚠ undocumented
781
1052
 
782
1053
  ## @jgengine/core/physics/forceVolume
783
1054
 
784
- - `ForceMode` (type): type ForceMode = "impulse" | "velocity" | "accelerate" — ⚠ undocumented
1055
+ - `ForceMode` (type): type ForceMode = "impulse" | "velocity" | "accelerate" — ⚠ undocumented · used by `applyVolumeForce`: One tick's force math for a body outside `PhysicsWorld` — apply the returned velocity in any custom integrator.
785
1056
  - `ForceVolume` (class): class ForceVolume — A trigger region that pushes bodies passing through it — boost pads (`impulse` + `once`), conveyors (`velocity`), fans/wind (`accelerate`). Call `apply` each tick; `once` mode fires only on entry by tracking membership between ticks.
786
- - `ForceVolumeConfig` (interface): interface ForceVolumeConfig — ⚠ undocumented
1057
+ - `ForceVolumeConfig` (interface): interface ForceVolumeConfig { bounds: PhysicsBounds; force: readonly [number, number, number]; mode?: ForceMode; once?: boolean } — ⚠ undocumented
787
1058
  - `PlatformCarry` (class): class PlatformCarry — Carries bodies standing on a moving platform by composing their transform with the platform's per-`step` delta — moving/rotating lifts and conveyor floors (Fall Guys, Gang Beasts). The platform is a body the game repositions each frame; riders are detected by overlap on its top face.
788
- - `PlatformCarryConfig` (interface): interface PlatformCarryConfig — ⚠ undocumented
1059
+ - `PlatformCarryConfig` (interface): interface PlatformCarryConfig { contactTolerance?: number } — ⚠ undocumented
789
1060
  - `VolumeTrigger` (interface): interface VolumeTrigger<TId> — The enter-once membership tracking from `ForceVolume`, freed from `PhysicsWorld`'s body indices (#286.8): feed any integrator's `{ id, position }` list each tick and act on the edges — apply `applyVolumeForce` on `entered` for a boost pad, on `inside` for a fan.
790
- - `VolumeTriggerConfig` (interface): interface VolumeTriggerConfig — ⚠ undocumented
791
- - `VolumeTriggerStep` (interface): interface VolumeTriggerStep<TId> — ⚠ undocumented
1061
+ - `VolumeTriggerConfig` (interface): interface VolumeTriggerConfig { bounds: PhysicsBounds } — ⚠ undocumented
1062
+ - `VolumeTriggerStep` (interface): interface VolumeTriggerStep<TId> { entered: readonly TId[]; inside: readonly TId[]; exited: readonly TId[] } — ⚠ undocumented
792
1063
  - `applyVolumeForce` (function): function applyVolumeForce(velocity: readonly [number, number, number], force: readonly [number, number, number], mode: ForceMode, dt: number): readonly [number, number, number] — One tick's force math for a body outside `PhysicsWorld` — apply the returned velocity in any custom integrator.
793
1064
  - `createVolumeTrigger` (function): function createVolumeTrigger<TId = string>(config: VolumeTriggerConfig): VolumeTrigger<TId> — ⚠ undocumented
794
1065
 
@@ -801,6 +1072,30 @@
801
1072
  - `pointGravity` (function): function pointGravity(options: PointGravityOptions): GravityField — Radial gravity toward one center, with optional inverse-square falloff for planetary worlds.
802
1073
  - `uniformGravity` (function): function uniformGravity(vector: GravityVector = [0, -9.81, 0]): GravityField — Constant vector gravity for ordinary worlds, space stations, and sideways-gravity levels.
803
1074
 
1075
+ ## @jgengine/core/physics/handlingProbe
1076
+
1077
+ - `AirReport` (interface): interface AirReport — Deterministic jump and air-control metrics.
1078
+ - `AirSubject` (interface): interface AirSubject — The slice of a jumping vehicle sim {@link measureAir} drives; a `VehicleDynamics` with `suspension`, `jump` and `air` fits.
1079
+ - `CourseProbeOptions` (interface): interface CourseProbeOptions — Settings for {@link measureCourse}; every field but `wheelbase` has a default.
1080
+ - `CourseReport` (interface): interface CourseReport — Deterministic driven-course metrics.
1081
+ - `CourseSubject` (interface): interface CourseSubject — A vehicle sim {@link measureCourse} can drive along a line: a {@link HandlingSubject} that also reports its pose and front-wheel angle.
1082
+ - `FlightProbeOptions` (interface): interface FlightProbeOptions — Scenario settings for {@link measureFlight}.
1083
+ - `FlightReport` (interface): interface FlightReport — Deterministic flight metrics. Fields that don't apply to the aircraft are `NaN`: turn and stall need wings, hover drift needs a rotor.
1084
+ - `FlightSpawn` (interface): interface FlightSpawn — Where {@link measureFlight} spawns each fresh aircraft: level, heading `0` (forward `+z`).
1085
+ - `HandlingProbeOptions` (interface): interface HandlingProbeOptions — Scenario settings for {@link measureHandling}; every field has a default.
1086
+ - `HandlingReport` (interface): interface HandlingReport — Deterministic feel metrics, in the units drivers and reviewers use. `Infinity` means the target was never reached.
1087
+ - `HandlingSubject` (interface): interface HandlingSubject — The slice of a vehicle sim {@link measureHandling} drives: `VehicleDynamics` and `KinematicVehicle` both fit.
1088
+ - `LeanReport` (interface): interface LeanReport — Deterministic lean metrics for a motorcycle or bicycle.
1089
+ - `LeanSubject` (interface): interface LeanSubject — The slice of a single-track sim {@link measureLean} drives; a `VehicleDynamics` with a `lean` block fits.
1090
+ - `RideReport` (interface): interface RideReport — Deterministic ride metrics for a sprung vehicle.
1091
+ - `RideSubject` (interface): interface RideSubject — The slice of a sprung vehicle sim {@link measureRide} drives; a `VehicleDynamics` with `suspension` fits.
1092
+ - `measureAir` (function): function measureAir(create: () => AirSubject, options: { dt?: number } = {}): AirReport — Jumps a fresh vehicle from rest and holds full air input on each axis, reporting jump height and timing, double-jump height, and how fast the body rotates in the air.
1093
+ - `measureCourse` (function): function measureCourse(create: () => CourseSubject, options: CourseProbeOptions): CourseReport — Drives a fresh vehicle from `create` through a steer ramp, a skidpad and a slalom with simple deterministic drivers, and reports understeer gradient, skidpad g and the fastest clean slalom.
1094
+ - `measureFlight` (function): function measureFlight(create: (spawn: FlightSpawn) => RigidAircraft, options: FlightProbeOptions = {}): FlightReport — Flies fresh aircraft from `create` through fixed scenarios with simple deterministic autopilots: a full-aileron roll, banked turns at full throttle, an idle deceleration holding altitude, a full-throttle climb at cruise speed, a throttle step from idle, and a hands-off hover. `create` gets a spawn to pass straight into `createRigidAircraft`. Deterministic, so a tuning change shows up as a number moving.
1095
+ - `measureHandling` (function): function measureHandling(create: () => HandlingSubject, options: HandlingProbeOptions = {}): HandlingReport — Drives fresh instances from `create` through fixed scenarios (launch, top speed, braking, a slow steer ramp, a step steer, a mid-corner lift-off, a handbrake pull, full throttle with full steer) and reports the feel metrics a test can assert. Deterministic: the same subject and options always produce the same report, so a tuning change shows up as a number moving, not an opinion.
1096
+ - `measureLean` (function): function measureLean(create: () => LeanSubject, options: { dt?: number; speed?: number } = {}): LeanReport — Brings a fresh bike to `speed` and holds full steer, reporting how far and how fast it leans and how much it tips the other way first.
1097
+ - `measureRide` (function): function measureRide(create: () => RideSubject, options: { dt?: number } = {}): RideReport — Drives fresh sprung vehicles from `create` through a vertical kick, a hard stop, a steady corner and a launch-and-land, and reports how the body moves: how fast it settles, how much it dives and rolls, and whether a landing bounces.
1098
+
804
1099
  ## @jgengine/core/physics/kinematicVehicle
805
1100
 
806
1101
  - `DEFAULT_REVERSE_FORCE_SCALE` (const): const DEFAULT_REVERSE_FORCE_SCALE: 0.48 — Default reverse drive force as a fraction of forward `engineForce` / `engineAccel`.
@@ -810,35 +1105,72 @@
810
1105
  - `KinematicSteeringTuning` (interface): interface KinematicSteeringTuning — Bicycle-model steering settings; all angles are radians.
811
1106
  - `KinematicVehicle` (interface): interface KinematicVehicle — The pure-kinematic arcade car every racing game hand-rolled (#282.1): steer-yaw scaled by speed, throttle/brake acceleration, and a grip-curve lateral-slip bleed — no `PhysicsWorld`, no wheels, just the drift-friendly integration the three shipped racers proved out. Games keep their flavor (drift meters, boost, off-track rules) via `surfaceFriction`/`dragAt` hooks and the returned slip.
812
1107
  - `KinematicVehicleModifiers` (interface): interface KinematicVehicleModifiers — Per-tick multipliers layered over the base tuning — the transient overrides games apply for one frame without rebuilding the vehicle: nitro/boost, a braced-plow bonus, or entering a speed zone or slow field. Each defaults to `1` (no change), so passing nothing leaves the base tuning untouched.
813
- - `KinematicVehicleOptions` (interface): interface KinematicVehicleOptions — ⚠ undocumented
814
- - `KinematicVehicleStep` (interface): interface KinematicVehicleStep — ⚠ undocumented
815
- - `KinematicVehicleTuning` (interface): interface KinematicVehicleTuning — ⚠ undocumented
816
- - `createKinematicVehicle` (function): function createKinematicVehicle(initialTuning: KinematicVehicleTuning, options: KinematicVehicleOptions = {}): KinematicVehicle — ⚠ undocumented
1108
+ - `KinematicVehicleOptions` (interface): interface KinematicVehicleOptions { position?: readonly [number, number, number]; heading?: number; surfaceFriction?: (x: number, z: number) => number; dragAt?: (x: number, z: number) => number; clampMove?: (from: readonly [number, number], to: readonly [number, number]) =>… — ⚠ undocumented · used by `createKinematicVehicle`: Arcade ground-vehicle sim (car, kart, bike) with throttle, brake, steer, drift and retunable handling.
1109
+ - `KinematicVehicleState` (interface): interface KinematicVehicleState — Serializable integrator state of a {@link KinematicVehicle}: what `restore` needs to resume bit-for-bit.
1110
+ - `KinematicVehicleStep` (interface): interface KinematicVehicleStep { position: readonly [number, number, number]; heading: number; forwardSpeed: number; lateralSpeed: number; slip: number; surface: number; gear: number; rpm: number; steerAngle: number; yawRate: number; longitudinalAcceleration: number; tra… — ⚠ undocumented · used by `tickDrivableVehicle` (@jgengine/core/physics/drivableVehicle): Connects an `AxisInput` sample straight through a ground-vehicle sim (`KinematicVehicle` or `VehicleDynamics`) to a scene entity's pose for …
1111
+ - `KinematicVehicleTuning` (interface): interface KinematicVehicleTuning { engineAccel: number; brakeAccel: number; topSpeed: number; reverseSpeed: number; turnRate: number; turnSpeedRef: number; grip?: GripCurve; gripStrength: number; handbrakeGrip: number; rollingResistance?: number; coastDeceleration?: number… — ⚠ undocumented · used by `createKinematicVehicle`: Arcade ground-vehicle sim (car, kart, bike) with throttle, brake, steer, drift and retunable handling.
1112
+ - `createKinematicVehicle` (function): function createKinematicVehicle(initialTuning: KinematicVehicleTuning, options: KinematicVehicleOptions = {}): KinematicVehicle — Arcade ground-vehicle sim (car, kart, bike) with throttle, brake, steer, drift and retunable handling.
1113
+
1114
+ ## @jgengine/core/physics/physicsBackend
1115
+
1116
+ - `BodyDesc` (interface): interface BodyDesc — Everything a backend needs to create a body. Rotation-free backends ignore `rotation` and `angularVelocity` and say so in {@link PhysicsCapabilities}.
1117
+ - `BodyHandle` (type): type BodyHandle = number — Backend-issued body id; stable for the body's lifetime and across snapshot/restore.
1118
+ - `BodyKind` (type): type BodyKind = "dynamic" | "kinematic" | "static" — `dynamic` integrates under forces, `kinematic` moves only through {@link PhysicsBackend.setKinematicTarget}, `static` never moves.
1119
+ - `BodyShape` (type): type BodyShape = | { kind: "box"; halfExtents: PhysicsVec3 } | { kind: "sphere"; radius: number } | { kind: "capsule"; radius: number; halfHeight: number } | { kind: "convex"; points: readonly PhysicsVec3[] } | { kind: "trimesh"; vertices: ArrayLike<number>; indices: ArrayLike<number> } | { kind: "h… — Collision shape of a body or a cast. Capsules stand along +Y; a trimesh or heightfield is static-only on every backend.
1120
+ - `BodyShapeKind` (type): type BodyShapeKind = BodyShape["kind"] — Shape discriminator, as listed in {@link PhysicsCapabilities.shapes}.
1121
+ - `BodyState` (interface): interface BodyState — A body's live pose and motion. Rotation-free backends report identity rotation and zero angular velocity.
1122
+ - `ContactEvent` (interface): interface ContactEvent — A contact reported during {@link PhysicsBackend.step}; the object is reused between calls, so copy what you keep.
1123
+ - `IDENTITY_QUAT` (const): const IDENTITY_QUAT: PhysicsQuat — The identity rotation.
1124
+ - `JointDesc` (interface): interface JointDesc — Joint between two bodies, or between `bodyA` and a world anchor when `bodyB` is omitted.
1125
+ - `JointHandle` (type): type JointHandle = number — Backend-issued joint id.
1126
+ - `OverlapDesc` (interface): interface OverlapDesc — Which bodies a shape placed at `position` intersects.
1127
+ - `PhysicsBackend` (interface): interface PhysicsBackend — The seam every physics consumer talks to: the in-tree `PhysicsWorld` behind `createPhysicsWorldBackend`, or a native solver such as Rapier behind its own adapter. Handles are backend-issued and survive snapshot/restore, so gameplay state can store them.
1128
+ - `PhysicsBackendConfig` (interface): interface PhysicsBackendConfig — Solver-wide knobs a backend accepts at creation and through `retune`.
1129
+ - `PhysicsCapabilities` (interface): interface PhysicsCapabilities — What a backend can actually simulate, so a game or the conformance suite can adapt instead of guessing.
1130
+ - `PhysicsQuat` (type): type PhysicsQuat = readonly [number, number, number, number] — Unit quaternion `[x, y, z, w]`; `[0, 0, 0, 1]` is identity.
1131
+ - `PhysicsVec3` (type): type PhysicsVec3 = readonly [number, number, number] — `[x, y, z]`.
1132
+ - `RayDesc` (interface): interface RayDesc — A ray query.
1133
+ - `RayHit` (interface): interface RayHit — Nearest surface a ray reached.
1134
+ - `ShapeCastDesc` (interface): interface ShapeCastDesc — Sweep `shape` from `position` along `motion` and report the first body it touches.
1135
+ - `ShapeCastHit` (interface): interface ShapeCastHit — First contact of a shape sweep.
1136
+ - `isIdentityQuat` (function): function isIdentityQuat(q: PhysicsQuat | undefined): boolean — True for an absent or identity rotation.
1137
+ - `shapeHalfExtents` (function): function shapeHalfExtents(shape: BodyShape): [number, number, number] — Axis-aligned bounds of a shape at identity rotation, as half extents.
1138
+
1139
+ ## @jgengine/core/physics/physicsBackendConformance
1140
+
1141
+ - `ConformanceHarness` (interface): interface ConformanceHarness — The slice of a test runner the conformance suite needs; `bun:test` satisfies it directly.
1142
+ - `runPhysicsBackendConformance` (function): function runPhysicsBackendConformance(create: () => PhysicsBackend, harness: ConformanceHarness): void — Behavioral contract every {@link PhysicsBackend} must pass: bodies rest on floors, casts and rays report the first surface with an outward normal, kinematic targets produce velocity, masks filter, and snapshot/restore round-trips with stable handles. Backends declare what they cannot do through `capabilities`; the suite reads it. Expects `create()` to return a fresh backend whose world spans at least ±50 on every axis with a floor at y=0.
817
1143
 
818
1144
  ## @jgengine/core/physics/physicsWorld
819
1145
 
820
1146
  - `AddBodyOptions` (type): type AddBodyOptions = BoxBodyOptions | SphereBodyOptions — ⚠ undocumented
821
- - `BodyCommonOptions` (interface): interface BodyCommonOptions — ⚠ undocumented
822
- - `BoxBodyOptions` (interface): interface BoxBodyOptions extends BodyCommonOptions — ⚠ undocumented
1147
+ - `BodyCommonOptions` (interface): interface BodyCommonOptions { position: readonly [number, number, number]; velocity?: readonly [number, number, number]; mass?: number; static?: boolean; asleep?: boolean } — ⚠ undocumented
1148
+ - `BoxBodyOptions` (interface): interface BoxBodyOptions extends BodyCommonOptions { shape?: "box"; halfExtents: readonly [number, number, number] } — ⚠ undocumented
823
1149
  - `CollisionEvent` (interface): interface CollisionEvent — A contact reported to `onCollision`. The object is reused each call — read/copy, never retain.
824
1150
  - `JOINT_DISTANCE` (const): const JOINT_DISTANCE: 2 — ⚠ undocumented
825
1151
  - `JOINT_FIXED` (const): const JOINT_FIXED: 0 — ⚠ undocumented
826
1152
  - `JOINT_HINGE` (const): const JOINT_HINGE: 1 — ⚠ undocumented
827
1153
  - `JOINT_SPRING` (const): const JOINT_SPRING: 3 — ⚠ undocumented
828
1154
  - `JointKind` (type): type JointKind = "hinge" | "distance" | "spring" | "fixed" — Hard bilateral: `fixed` pins the shared anchor (3-DOF), `hinge` pins only the plane perpendicular to `axis` (free along the axis — translational cylindrical), `distance` holds a fixed separation. `spring` is a soft PD drive toward `restLength`.
829
- - `JointOptions` (interface): interface JointOptions — ⚠ undocumented
1155
+ - `JointOptions` (interface): interface JointOptions { bodyA: number; bodyB?: number; anchorA?: readonly [number, number, number]; anchorB?: readonly [number, number, number]; restLength?: number; stiffness?: number; damping?: number; maxImpulse?: number; axis?: readonly [number, number, numb… — ⚠ undocumented
830
1156
  - `MAX_BROADPHASE_CELLS` (const): const MAX_BROADPHASE_CELLS: 1000000 — Cap on `nx*ny*nz` broadphase cells — guards a huge-bounds/tiny-cellSize config from hanging `step()`.
831
- - `PhysicsBounds` (interface): interface PhysicsBounds — ⚠ undocumented
1157
+ - `PhysicsBounds` (interface): interface PhysicsBounds { min: readonly [number, number, number]; max: readonly [number, number, number] } — ⚠ undocumented
832
1158
  - `PhysicsPrecision` (type): type PhysicsPrecision = "low" | "standard" | "high" — Simulation fidelity intent: `low` (cheap — many bodies, loose stacks, forgiving sleep), `standard` (default), `high` (tight stacks, accurate joints, worth the extra solver work). Sets the solver knobs below to a matched preset; an individual knob left explicit always wins over the preset.
833
- - `PhysicsStats` (interface): interface PhysicsStats — ⚠ undocumented
1159
+ - `PhysicsStats` (interface): interface PhysicsStats { count: number; awake: number; sleeping: number; contacts: number; pairs: number; substeps: number; stepMs: number } — ⚠ undocumented
834
1160
  - `PhysicsWorld` (class): class PhysicsWorld — ⚠ undocumented
835
- - `PhysicsWorldConfig` (interface): interface PhysicsWorldConfig — ⚠ undocumented
1161
+ - `PhysicsWorldConfig` (interface): interface PhysicsWorldConfig { capacity: number; bounds: PhysicsBounds; gravity?: number; precision?: PhysicsPrecision; fixedDt?: number; maxSubsteps?: number; restitution?: number; restitutionThreshold?: number; friction?: number; linearDamping?: number; sleepLinearVe… — ⚠ undocumented
836
1162
  - `SHAPE_BOX` (const): const SHAPE_BOX: 0 — ⚠ undocumented
837
1163
  - `SHAPE_SPHERE` (const): const SHAPE_SPHERE: 1 — ⚠ undocumented
838
1164
  - `SphereBodyOptions` (interface): interface SphereBodyOptions extends BodyCommonOptions — The radius fills all three half-extent columns, so broadphase and bounds see the sphere's enclosing AABB.
839
1165
  - `cellCoord` (function): function cellCoord(value: number, min: number, cellSize: number, cells: number): number — Grid cell containing a point, clamped into the grid. Pure — exported for tests.
840
1166
  - `cellIndex` (function): function cellIndex(cx: number, cy: number, cz: number, nx: number, ny: number): number — Linear cell index from clamped 3D coords. Pure — exported for tests.
841
1167
 
1168
+ ## @jgengine/core/physics/physicsWorldBackend
1169
+
1170
+ - `PhysicsWorldBackendOptions` (interface): interface PhysicsWorldBackendOptions extends PhysicsBackendConfig — Construction options: the `PhysicsWorld` capacity and bounds plus the shared backend config.
1171
+ - `PhysicsWorldBackendState` (interface): interface PhysicsWorldBackendState — Serializable backend state: every live body and joint, with handles preserved.
1172
+ - `createPhysicsWorldBackend` (function): function createPhysicsWorldBackend(options: PhysicsWorldBackendOptions): PhysicsBackend — `PhysicsWorld` behind the {@link PhysicsBackend} interface: zero dependencies, translation-only. Capsules, convex hulls, meshes, and heightfields collide as their bounding boxes; rotation, angular velocity, CCD, and hinge limits are accepted and ignored (see {@link PhysicsBackend.capabilities}). Reach for `@jgengine/rapier` when a game needs those for real; the seam is the same.
1173
+
842
1174
  ## @jgengine/core/physics/radialImpulse
843
1175
 
844
1176
  - `RadialFalloff` (type): type RadialFalloff = "linear" | "quadratic" | "none" — How a radial impulse fades from the blast center to its edge.
@@ -849,51 +1181,85 @@
849
1181
  ## @jgengine/core/physics/ragdoll
850
1182
 
851
1183
  - `Ragdoll` (class): class Ragdoll — A jointed multi-body character — floppy by default, or active-ragdoll when a balance motor is configured. Bones are `PhysicsWorld` bodies; links are joints on the joint API. `balance(dt, mx, mz)` drives the root toward its target height (staying upright) and pushes it by the move vector.
852
- - `RagdollBalanceConfig` (interface): interface RagdollBalanceConfig — ⚠ undocumented
853
- - `RagdollBoneSpec` (interface): interface RagdollBoneSpec — ⚠ undocumented
854
- - `RagdollConfig` (interface): interface RagdollConfig — ⚠ undocumented
855
- - `RagdollLinkSpec` (interface): interface RagdollLinkSpec — ⚠ undocumented
1184
+ - `RagdollBalanceConfig` (interface): interface RagdollBalanceConfig { root: string; targetHeight: number; strength?: number; moveForce?: number } — ⚠ undocumented
1185
+ - `RagdollBoneSpec` (interface): interface RagdollBoneSpec { name: string; position: readonly [number, number, number]; halfExtents: readonly [number, number, number]; mass?: number } — ⚠ undocumented
1186
+ - `RagdollConfig` (interface): interface RagdollConfig { bones: RagdollBoneSpec[]; links: RagdollLinkSpec[]; balance?: RagdollBalanceConfig } — ⚠ undocumented
1187
+ - `RagdollLinkSpec` (interface): interface RagdollLinkSpec { a: string; b: string; kind?: "hinge" | "distance"; anchor?: readonly [number, number, number] } — ⚠ undocumented
856
1188
  - `createRagdoll` (function): function createRagdoll(world: PhysicsWorld, config: RagdollConfig): Ragdoll — ⚠ undocumented
857
1189
 
858
1190
  ## @jgengine/core/physics/spatialGrid
859
1191
 
860
1192
  - `SpatialGrid` (class): class SpatialGrid — A uniform-grid broad-phase over the x/z plane, separate from the rigid-body sim, for cheap same-tick proximity across hundreds–thousands of simple movers (swarm enemies). Rebuild each tick from the caller's own position arrays, then `queryCircle` (enemies hitting the player / an AoE) or `forEachPair` (mutual separation). Both are precise: no false negatives, no false positives beyond the exact distance test.
861
- - `SpatialGridConfig` (interface): interface SpatialGridConfig — ⚠ undocumented
1193
+ - `SpatialGridConfig` (interface): interface SpatialGridConfig { bounds: PhysicsBounds; cellSize: number; capacity: number } — ⚠ undocumented
862
1194
 
863
1195
  ## @jgengine/core/physics/structure
864
1196
 
865
- - `CollapseEvent` (interface): interface CollapseEvent — ⚠ undocumented
866
- - `DebrisConfig` (interface): interface DebrisConfig — ⚠ undocumented
867
- - `StructureEdgeSpec` (interface): interface StructureEdgeSpec — ⚠ undocumented
1197
+ - `CollapseEvent` (interface): interface CollapseEvent { fell: readonly string[]; collapsed: boolean } — ⚠ undocumented
1198
+ - `DebrisConfig` (interface): interface DebrisConfig { impulse?: number; origin?: readonly [number, number, number] } — ⚠ undocumented
1199
+ - `StructureEdgeSpec` (interface): interface StructureEdgeSpec { a: string; b: string; strength?: number } — ⚠ undocumented
868
1200
  - `StructureGraph` (class): class StructureGraph — A structural-integrity graph over a building — nodes are pieces (walls, beams, floors), edges are load-bearing connections, some nodes are anchored foundations. `damage`/`damageEdge` wear pieces and connections down; when a piece shatters or an edge severs, the graph recomputes which pieces still reach an anchor and hands back every newly-disconnected piece as one `CollapseEvent`. Feed that to `toDebris` to sink the fallen pieces into a `PhysicsWorld` as rigid bodies ("The Finals" smooth destruction, Rainbow Six walls). Coarse by design: it replicates the collapse event, not per fragment.
869
- - `StructureMaterial` (interface): interface StructureMaterial — ⚠ undocumented
1201
+ - `StructureMaterial` (interface): interface StructureMaterial { id: string; strength: number; mass?: number } — ⚠ undocumented
870
1202
  - `StructureMaterialTable` (type): type StructureMaterialTable = Readonly<Record<string, StructureMaterial>> — ⚠ undocumented
871
- - `StructureNodeSpec` (interface): interface StructureNodeSpec — ⚠ undocumented
1203
+ - `StructureNodeSpec` (interface): interface StructureNodeSpec { id: string; position: readonly [number, number, number]; halfExtents: readonly [number, number, number]; mass?: number; integrity?: number; material?: string; anchor?: boolean } — ⚠ undocumented
872
1204
 
873
1205
  ## @jgengine/core/physics/traversal
874
1206
 
875
1207
  - `Glide` (class): class Glide — A reduced-gravity, forward-thrust glide over a physics body — wingsuit / glider / paraglider (Enshrouded, Grounded). Call `apply(dt, steerX, steerZ)` each frame *before* `world.step`: it feeds back most of the gravity the sim is about to apply (leaving `gravityScale` of it), pushes the body along the steer vector by `thrust`, and clamps descent to `maxFallSpeed`. Stop calling it to fall normally again — no attach/detach state to leak.
876
- - `GlideConfig` (interface): interface GlideConfig — ⚠ undocumented
1208
+ - `GlideConfig` (interface): interface GlideConfig { gravityScale?: number; thrust?: number; maxFallSpeed?: number } — ⚠ undocumented
877
1209
  - `Grapple` (class): class Grapple — A fired-anchor rope on the joint API — grapple (reel toward a hit point), zipline (rigid cable to a far anchor you then slide/reel along), swing (rigid rope + gravity = a pendulum). `fire` attaches a `distance`/`spring` joint from the traveller body to a fixed world point; `reel` shrinks its rest length so the constraint drags the body in; `moveAnchor` re-points it (zipline glide, grapple-to- moving-target). The pick — a raycast to find the anchor — is the caller's; core owns the constraint.
878
- - `GrappleConfig` (interface): interface GrappleConfig — ⚠ undocumented
1210
+ - `GrappleConfig` (interface): interface GrappleConfig { reelSpeed?: number; minLength?: number; maxLength?: number; elastic?: boolean; stiffness?: number; damping?: number } — ⚠ undocumented
1211
+
1212
+ ## @jgengine/core/physics/vehicleBackendLink
1213
+
1214
+ - `VehicleBackendLink` (interface): interface VehicleBackendLink — A vehicle sim's presence in a physics backend: a kinematic chassis that shoves props, and a wall-aware move clamp.
1215
+ - `VehicleBackendLinkOptions` (interface): interface VehicleBackendLinkOptions — Options for {@link createVehicleBackendLink}.
1216
+ - `VehicleLinkHit` (interface): interface VehicleLinkHit — A wall the last clamped move ran into.
1217
+ - `VehicleLinkPose` (interface): interface VehicleLinkPose — The pose fields {@link VehicleBackendLink.sync} reads; any vehicle step (`VehicleDynamicsStep`, `KinematicVehicleStep`) fits.
1218
+ - `createVehicleBackendLink` (function): function createVehicleBackendLink(backend: PhysicsBackend, options: VehicleBackendLinkOptions): VehicleBackendLink — Puts a vehicle sim (`createVehicleDynamics`, `createKinematicVehicle`) into a {@link PhysicsBackend} world without handing its handling to the rigid-body solver: the sim still owns grip and balance, while a kinematic chassis box follows it so Rapier or `PhysicsWorld` props get shoved, and `clampMove` sweeps that box so walls and parked cars stop it and it slides along them.
879
1219
 
880
1220
  ## @jgengine/core/physics/vehicleBody
881
1221
 
882
1222
  - `DEFAULT_GRIP_CURVE` (const): const DEFAULT_GRIP_CURVE: GripCurve — ⚠ undocumented
883
- - `GripCurve` (interface): interface GripCurve — ⚠ undocumented
1223
+ - `GripCurve` (interface): interface GripCurve { points: readonly (readonly [number, number])[] } — ⚠ undocumented · used by `sampleGripCurve`: Piecewise-linear tire-grip curve: normalized lateral slip → available grip (0..1).
884
1224
  - `VehicleBody` (class): class VehicleBody — Arcade vehicle over the {@link PhysicsWorld} rigid-body sim. The chassis is a single box body driven by an {@link AxisInput}: per-wheel suspension is a spring-damper held with G3's `springJoint` against the sampled ground, drive/brake push along the heading, and a tire-grip curve bleeds lateral velocity (cornering, and drift under handbrake). Because the chassis is a physics body it still collides — that contact feeds crash damage. Call `update(dt, input)` before the shared `world.step(dt)`.
885
- - `VehicleBodyConfig` (interface): interface VehicleBodyConfig — ⚠ undocumented
886
- - `WheelSpec` (interface): interface WheelSpec — ⚠ undocumented
887
- - `WheelState` (interface): interface WheelState — ⚠ undocumented
1225
+ - `VehicleBodyConfig` (interface): interface VehicleBodyConfig { position: readonly [number, number, number]; heading?: number; chassisHalfExtents?: readonly [number, number, number]; mass?: number; wheels?: readonly WheelSpec[]; engineAccel?: number; brakeAccel?: number; topSpeed?: number; reverseSpee… — ⚠ undocumented
1226
+ - `WheelSpec` (interface): interface WheelSpec { offset: readonly [number, number, number]; radius?: number; restLength?: number; steered?: boolean; powered?: boolean; handbrakeLocks?: boolean } — ⚠ undocumented
1227
+ - `WheelState` (interface): interface WheelState { worldX: number; worldY: number; worldZ: number; grounded: boolean; compression: number; steerAngle: number } — ⚠ undocumented
888
1228
  - `createVehicleBody` (function): function createVehicleBody(world: PhysicsWorld, config: VehicleBodyConfig): VehicleBody — ⚠ undocumented
889
1229
  - `sampleGripCurve` (function): function sampleGripCurve(curve: GripCurve, slip: number): number — Piecewise-linear tire-grip curve: normalized lateral slip → available grip (0..1). Grip peaks near the breakaway slip then falls off as the tire slides — the shape that separates a planted corner from a drift. Points are read in ascending slip order; ends clamp.
890
1230
 
1231
+ ## @jgengine/core/physics/vehicleDynamics
1232
+
1233
+ - `VehicleAeroTuning` (interface): interface VehicleAeroTuning — Aero and resistance. Uses air density 1.225 kg/m³.
1234
+ - `VehicleAirInput` (interface): interface VehicleAirInput — Air-control input, each `-1..1`: `pitch > 0` noses down, `yaw > 0` turns like `steer > 0`, `roll > 0` drops the left side.
1235
+ - `VehicleAirTuning` (interface): interface VehicleAirTuning — Control of the body while airborne (needs `suspension`, the only way to leave the ground).
1236
+ - `VehicleAssistTuning` (interface): interface VehicleAssistTuning — Electronic and arcade assists; each is a strength `0..1`, `0`/omitted = off.
1237
+ - `VehicleDirectDriveTuning` (interface): interface VehicleDirectDriveTuning — Single-speed drive (electric, kart, arcade ball-car): force capped by power, so top speed comes out of drag.
1238
+ - `VehicleDynamics` (interface): interface VehicleDynamics — Force-based planar car: a two-axle ("bicycle") model where yaw comes from tire forces rather than being commanded, so understeer, oversteer, lift-off rotation, trail-braking, power slides and handbrake turns emerge from the numbers instead of from special cases. Deterministic for a given `dt` sequence; ticks are split into fixed substeps. Pairs with `tickDrivableVehicle` for the entity pose and `measureHandling` for asserting feel.
1239
+ - `VehicleDynamicsModifiers` (interface): interface VehicleDynamicsModifiers — Per-tick overrides layered over tuning: boost, grip zones, damage. Each scale defaults to `1`.
1240
+ - `VehicleDynamicsOptions` (interface): interface VehicleDynamicsOptions — World hooks for one vehicle instance.
1241
+ - `VehicleDynamicsState` (interface): interface VehicleDynamicsState — Serializable integrator state: everything {@link VehicleDynamics.restore} needs to resume bit-for-bit.
1242
+ - `VehicleDynamicsStep` (interface): interface VehicleDynamicsStep — Result of one {@link VehicleDynamics.tick}: pose plus the telemetry camera, audio, haptics and HUD read.
1243
+ - `VehicleDynamicsTuning` (interface): interface VehicleDynamicsTuning — Tuning for {@link createVehicleDynamics}. Every number is a physical quantity in SI units (kg, m, N, N·m, rad, s), so a feel target maps to a knob a person can reason about: more rear grip or a lower centre of mass for stability, softer tires for forgiveness, more drive to the rear for power oversteer.
1244
+ - `VehicleGearboxTuning` (interface): interface VehicleGearboxTuning — Engine and gearbox. Drive force at the wheels = torque · curve(rpm) · gear · finalDrive · efficiency / wheelRadius.
1245
+ - `VehicleJumpTuning` (interface): interface VehicleJumpTuning — Jumps from the ground and in the air.
1246
+ - `VehicleLeanTuning` (interface): interface VehicleLeanTuning — Single-track lean for motorcycles, bicycles and scooters. Steer input asks for a lean angle; the front wheel then takes whatever angle a balanced turn at that lean needs (curvature = g·tan(lean) / v²), with a brief countersteer as the lean starts. Tire grip still limits the turn, so over-leaning on a low-grip surface slides.
1247
+ - `VehicleSteeringTuning` (interface): interface VehicleSteeringTuning — Steering rack: lock, speed-sensitive lock, rack speed, and caster self-alignment.
1248
+ - `VehicleSuspensionTuning` (interface): interface VehicleSuspensionTuning — Four sprung corners. With this block the chassis heaves, pitches and rolls on real springs, axle loads come from spring forces instead of a filtered estimate, slopes pull the car downhill, and the car can leave the ground and land. Omit it for the flat-ground model.
1249
+ - `VehicleTireTuning` (interface): interface VehicleTireTuning — One axle's tire, in physical terms. Lateral force follows a simplified Pacejka curve `μ·Fz·sin(C·atan(B·α))` whose `B`/`C` are solved from `peakSlipAngle` and `slideGrip`, so the three numbers read the way a driver feels them: how much grip, how early it peaks, how much is left sliding.
1250
+ - `createVehicleDynamics` (function): function createVehicleDynamics(initialTuning: VehicleDynamicsTuning, options: VehicleDynamicsOptions = {}): VehicleDynamics — Creates a {@link VehicleDynamics}.
1251
+
891
1252
  ## @jgengine/core/physics/vehicleObstacles
892
1253
 
893
1254
  - `VehicleImpact` (interface): interface VehicleImpact — A single blocked-move event a car can react to (#1051): crash damage, screen shake, a metal-crunch cue. Reported once, when a move is first vetoed, then consumed by {@link VehicleObstacleClamp.takeImpact}.
894
1255
  - `VehicleObstacleClamp` (interface): interface VehicleObstacleClamp — A planar move clamp for a kinematic car: feed {@link clampMove} to a vehicle's `clampMove` hook so an attempted XZ displacement slides along world solids instead of driving through them, and read {@link takeImpact} once per tick for the crash it produced.
895
1256
  - `createVehicleObstacleClamp` (function): function createVehicleObstacleClamp(options: { /** Solids near the car this tick (already filtered to the relevant, solid set). */ obstacles: () => readonly CollisionObstacle[]; /** Vehicle body radius (units). Default {@link DEFAULT_VEHICLE_RADIUS}. */ radius?: number; /** Current tick dt (seconds)… — Build a slide-along move clamp for a kinematic car (#1051). `obstacles` is sampled fresh each tick — the caller hands back the already-filtered set of solids near the car — and `dt` supplies the current tick length so a blocked move's lost displacement converts to a closing speed. `radius` inflates each obstacle footprint by the car's body radius (default {@link DEFAULT_VEHICLE_RADIUS}).
896
1257
 
1258
+ ## @jgengine/core/physics/worldColliders
1259
+
1260
+ - `WorldColliderSync` (interface): interface WorldColliderSync — Handle for synchronizing authored static world collision with a physics backend.
1261
+ - `syncWorldColliders` (function): function syncWorldColliders(backend: PhysicsBackend, ctx: GameContext): WorldColliderSync — Mirrors static scene-object physical colliders, `ctx.world.solids` and the context's ground field into a physics backend.
1262
+
897
1263
  ## @jgengine/core/procedural
898
1264
 
899
1265
  - `DecayMeterSet` (interface): interface DecayMeterSet — Set of named survival meters (hunger/thirst/…) that drain and refill over game time.
@@ -907,10 +1273,10 @@
907
1273
 
908
1274
  ## @jgengine/core/scene/assetCatalog
909
1275
 
910
- - `AssetCatalog` (interface): interface AssetCatalog<TMeta extends ModelAssetRef = ModelAssetRef> — ⚠ undocumented
1276
+ - `AssetCatalog` (interface): interface AssetCatalog<TMeta extends ModelAssetRef = ModelAssetRef> { register(id: string, asset: TMeta): void; resolve(id: string): TMeta | null; has(id: string): boolean; ids(): readonly string[] } — ⚠ undocumented · used by `buildCatalog` (@jgengine/assets): Builds a game's asset catalog from the generated CC0 pack index plus singles, extras, and aliases.
911
1277
  - `AssetRef` (type): type AssetRef = ModelAssetRef | GeneratorAssetRef — A catalog entry: a static GLB model, or a parametric generator.
912
1278
  - `GeneratorAssetRef` (interface): interface GeneratorAssetRef — A catalog entry backed by a registered {@link registerAssetGenerator} instead of a GLB URL — a slider-driven parametric prop (bookcase, building). `defaults` seeds a fresh placement's params. Placed instances persist `{ assetId, params, seed }` in the scene and re-resolve at runtime.
913
- - `ModelAssetRef` (interface): interface ModelAssetRef — ⚠ undocumented
1279
+ - `ModelAssetRef` (interface): interface ModelAssetRef { url: string; dims?: ModelDims; collisionMesh?: CollisionMeshData; space?: AssetSpace; clips?: readonly string[] } — ⚠ undocumented · used by `createHostedWorldSessionAsync` (@jgengine/core/runtime/hostedWorldSession): Build a hosted session from an asynchronous persistence backend.
914
1280
  - `ModelDims` (interface): interface ModelDims — Measured horizontal footprint, footprint center, and lowest Y of a model in model space.
915
1281
  - `createAssetCatalog` (function): function createAssetCatalog<TMeta extends ModelAssetRef = ModelAssetRef>(): AssetCatalog<TMeta> — ⚠ undocumented
916
1282
 
@@ -977,29 +1343,34 @@
977
1343
 
978
1344
  ## @jgengine/core/scene/autoTarget
979
1345
 
980
- - `AutoTargetDeps` (interface): interface AutoTargetDeps — ⚠ undocumented
1346
+ - `AutoTargetDeps` (interface): interface AutoTargetDeps { candidates: (fromId: string) => readonly string[]; distance: (fromId: string, toId: string) => number | null; strength?: (toId: string) => number; progress?: (toId: string) => number; rng?: () => number } — ⚠ undocumented
981
1347
  - `AutoTargetPolicy` (type): type AutoTargetPolicy = | "nearest" | "farthest" | "random" | "strongest" | "weakest" | "first" | "last" — ⚠ undocumented
982
- - `AutoTargeter` (interface): interface AutoTargeter — ⚠ undocumented
1348
+ - `AutoTargeter` (interface): interface AutoTargeter { policy(): AutoTargetPolicy; setPolicy(policy: AutoTargetPolicy): void; pick(fromId: string): string | null } — ⚠ undocumented
983
1349
  - `createAutoTargeter` (function): function createAutoTargeter(policy: AutoTargetPolicy, deps: AutoTargetDeps): AutoTargeter — ⚠ undocumented
984
1350
  - `selectAutoTarget` (function): function selectAutoTarget(policy: AutoTargetPolicy, fromId: string, deps: AutoTargetDeps): string | null — ⚠ undocumented
985
1351
 
986
1352
  ## @jgengine/core/scene/behaviorRuntime
987
1353
 
1354
+ - `BehaviorAction` (type): type BehaviorAction = DecisionAction<BehaviorActionContext> — Callback used by a registered decision graph behavior action.
1355
+ - `BehaviorActionContext` (interface): interface BehaviorActionContext — Context supplied to a registered decision graph action.
1356
+ - `BehaviorActionOptions` (interface): interface BehaviorActionOptions — Optional hooks for a registered behavior action set.
988
1357
  - `BehaviorControl` (interface): interface BehaviorControl — Per-entity control surface for the behavior runtime — pause/resume/disable/enable an instance, seek it to semantic progress, serialize/restore its state, and inspect it, all keyed by stable entity id without a full-world scan. Obtain it with {@link behaviorControl}.
989
1358
  - `BehaviorInspection` (interface): interface BehaviorInspection — Inspection readout for editor/debug tooling, from {@link BehaviorControl.inspect}/{@link BehaviorControl.list}.
990
1359
  - `BehaviorResumePolicy` (type): type BehaviorResumePolicy = "freeze" | "advance" — Catch-up policy applied when a paused instance resumes. `freeze` (default, deterministic) discards the time spent paused; `advance` silently fast-forwards the instance by the paused duration without emitting intermediate pose writes. Only patrol honors `advance`; wander treats it as `freeze`.
991
- - `BehaviorSnapshot` (type): type BehaviorSnapshot = | { readonly kind: "patrol"; readonly state: PathFollowState } | { readonly kind: "wander"; readonly origin: Waypoint; readonly target: Waypoint | null } — Serializable snapshot of one behavior instance — round-trips exactly through {@link BehaviorControl.serialize}/{@link BehaviorControl.restore}.
1360
+ - `BehaviorSnapshot` (type): type BehaviorSnapshot = | { readonly kind: "patrol"; readonly state: PathFollowState } | { readonly kind: "wander"; readonly origin: Waypoint; readonly target: Waypoint | null } | { readonly kind: "decisionGraph"; readonly graph: ReturnType<DecisionGraphRuntime["snapshot"]>; readonly gate: InterestG… — Serializable snapshot of one behavior instance — round-trips exactly through {@link BehaviorControl.serialize}/{@link BehaviorControl.restore}.
992
1361
  - `BehaviorStatus` (type): type BehaviorStatus = "active" | "paused" | "disabled" — Whether a behavior instance advances and writes pose (`active`), is temporarily suspended retaining state (`paused`), or is held off until re-enabled (`disabled`).
993
1362
  - `advanceBehaviors` (function): function advanceBehaviors(ctx: GameContext, dt: number): void — Advance every spawned entity carrying a `patrol` or `wander` {@link BehaviorDescriptor} one tick — the engine reads the descriptor, keeps the per-entity nav state itself, and poses the entity, so ambient traffic and idle NPC routes are register-once (attach the behavior at spawn) instead of a per-game per-frame `advancePathFollow` + `setPose` loop. Instances that are paused or disabled through {@link behaviorControl} retain their state and are skipped. The shell/host call this each frame; a game never does.
994
1363
  - `behaviorControl` (function): function behaviorControl(ctx: GameContext): BehaviorControl — Obtain the per-context {@link BehaviorControl} surface for suspending, resuming, seeking, serializing, and inspecting behavior instances by entity id — the lifecycle contract games use to hand pose ownership to possession/streaming/staggering code instead of bypassing the behavior runtime.
1364
+ - `registerBehaviorActions` (function): function registerBehaviorActions(id: string, actions: Record<string, BehaviorAction>, options: BehaviorActionOptions = {}): () => void — Register the named actions used by decision graph behavior descriptors.
995
1365
 
996
1366
  ## @jgengine/core/scene/behaviors
997
1367
 
998
- - `BehaviorDescriptor` (type): type BehaviorDescriptor = | WanderBehavior | PatrolBehavior | PromptableBehavior | PlayerBehavior — ⚠ undocumented
999
- - `PatrolBehavior` (interface): interface PatrolBehavior — ⚠ undocumented
1000
- - `PlayerBehavior` (interface): interface PlayerBehavior — ⚠ undocumented
1001
- - `PromptableBehavior` (interface): interface PromptableBehavior — ⚠ undocumented
1002
- - `WanderBehavior` (interface): interface WanderBehavior — ⚠ undocumented
1368
+ - `BehaviorDescriptor` (type): type BehaviorDescriptor = | WanderBehavior | PatrolBehavior | PromptableBehavior | PlayerBehavior | DecisionGraphBehavior — ⚠ undocumented
1369
+ - `DecisionGraphBehavior` (interface): interface DecisionGraphBehavior — Decision graph behavior descriptor using a named registered action set.
1370
+ - `PatrolBehavior` (interface): interface PatrolBehavior { kind: "patrol"; waypoints: readonly Waypoint[]; speed: number; loop: boolean; startProgress?: PathProgress; groundClamp?: boolean } — ⚠ undocumented
1371
+ - `PlayerBehavior` (interface): interface PlayerBehavior { kind: "player" } — ⚠ undocumented
1372
+ - `PromptableBehavior` (interface): interface PromptableBehavior { kind: "promptable"; prompt: ProximityPrompt } — ⚠ undocumented
1373
+ - `WanderBehavior` (interface): interface WanderBehavior { kind: "wander"; radius: number } — ⚠ undocumented
1003
1374
  - `patrol` (function): function patrol({ waypoints, speed, loop = true, startProgress, groundClamp, }: { waypoints: readonly Waypoint[]; speed: number; loop?: boolean; startProgress?: PathProgress; groundClamp?: boolean; }): PatrolBehavior — ⚠ undocumented
1004
1375
  - `player` (function): function player(): PlayerBehavior — ⚠ undocumented
1005
1376
  - `promptable` (function): function promptable(prompt: ProximityPrompt): PromptableBehavior — ⚠ undocumented
@@ -1021,23 +1392,23 @@
1021
1392
 
1022
1393
  ## @jgengine/core/scene/captureCheck
1023
1394
 
1024
- - `CaptureCheckInput` (interface): interface CaptureCheckInput — ⚠ undocumented
1395
+ - `CaptureCheckInput` (interface): interface CaptureCheckInput { hpFraction: number; catchPower: number; difficulty?: number } — ⚠ undocumented
1025
1396
  - `captureChance` (function): function captureChance(input: CaptureCheckInput): number — ⚠ undocumented
1026
1397
  - `rollCapture` (function): function rollCapture(input: CaptureCheckInput, rng?: () => number): boolean — ⚠ undocumented
1027
1398
 
1028
1399
  ## @jgengine/core/scene/colliders
1029
1400
 
1030
- - `ColliderDef` (interface): interface ColliderDef — ⚠ undocumented
1401
+ - `ColliderDef` (interface): interface ColliderDef { name: string; purpose: ColliderPurpose; shape: ColliderShape; damageEligible?: boolean; blocks?: boolean } — ⚠ undocumented
1031
1402
  - `ColliderPurpose` (type): type ColliderPurpose = "physical" | "damage" — ⚠ undocumented
1032
1403
  - `ColliderShape` (type): type ColliderShape = | { kind: "sphere"; radius: number; offset?: EntityPosition } | { kind: "aabb"; halfExtents: EntityPosition; offset?: EntityPosition } | { kind: "mesh"; /** Prepared triangle mesh in model space — engine-derived from an opted-in catalog asset, never hand-authored. */ mesh: Prepa… — Collision geometry in entity-local space. `sphere` and `aabb` are analytic; `mesh` carries a prepared triangle mesh so opted-in concave models raycast their real surface while bounds and broadphase keep reading the conservative `halfExtents`.
1033
1404
  - `DEFAULT_ENTITY_BODY_HALF_EXTENTS` (const): const DEFAULT_ENTITY_BODY_HALF_EXTENTS: EntityPosition — Matches the shell's fallback actor capsule (~0.7m wide, feet at y=0 to head at ~1.8m).
1034
1405
  - `DEFAULT_ENTITY_BODY_OFFSET` (const): const DEFAULT_ENTITY_BODY_OFFSET: EntityPosition — Entity-local center of the default body hitbox (half its height above the feet).
1035
1406
  - `DEFAULT_ENTITY_HIT_RADIUS` (const): const DEFAULT_ENTITY_HIT_RADIUS: 0.5 — ⚠ undocumented
1036
1407
  - `DEFAULT_OBJECT_HALF_EXTENTS` (const): const DEFAULT_OBJECT_HALF_EXTENTS: EntityPosition — ⚠ undocumented
1037
- - `EntityColliderSet` (interface): interface EntityColliderSet — ⚠ undocumented
1408
+ - `EntityColliderSet` (interface): interface EntityColliderSet { body?: ColliderDef; hitboxes?: readonly ColliderDef[] } — ⚠ undocumented · used by `eyeHeightFromColliders` (@jgengine/core/combat): Eye height derived from a collider set: 90% of the tallest hitbox top, or the humanoid default when unknown.
1038
1409
  - `MeasuredBounds` (interface): interface MeasuredBounds — Entity-local AABB of what the renderer actually mounted for a kind — the runtime counterpart to index-measured `dims`. Reported through `ctx.scene.entity.reportBounds` / `ctx.scene.object.reportBounds` (the shell does this automatically for custom `renderEntity`/`renderObject` content and models without index dims) so collider resolution can wrap the real rendered shape instead of a fixed-size guess.
1039
1410
  - `ModelBodySource` (interface): interface ModelBodySource — The render-config subset collider fitting reads — structurally satisfied by a resolved `ModelConfig`, so the shell can hand its render config straight to the fitting math without a conversion step.
1040
- - `ResolvedCollider` (interface): interface ResolvedCollider — ⚠ undocumented
1411
+ - `ResolvedCollider` (interface): interface ResolvedCollider { name: string; purpose: ColliderPurpose; shape: ColliderShape; damageEligible: boolean; blocks: boolean } — ⚠ undocumented
1041
1412
 
1042
1413
  ## @jgengine/core/scene/collisionMesh
1043
1414
 
@@ -1076,17 +1447,17 @@
1076
1447
  ## @jgengine/core/scene/entityStore
1077
1448
 
1078
1449
  - `EntityBlackboard` (interface): interface EntityBlackboard — Per-entity scratch and cooldown timers, auto-cleared on despawn (#533.8) — the home for AI state (next-shot-at, alert level) that would otherwise be smuggled through the serializable `meta` or a hand-pruned module-level map. Keys share one namespace per entity: `arm`/`ready`/`remaining` store a deadline under a key, `get`/`set` store arbitrary scratch.
1079
- - `EntityMovement` (interface): interface EntityMovement — ⚠ undocumented
1080
- - `EntityPose` (interface): interface EntityPose — ⚠ undocumented
1081
- - `EntityPosition` (type): type EntityPosition = readonly [number, number, number] — ⚠ undocumented
1450
+ - `EntityMovement` (interface): interface EntityMovement { walkSpeed?: number; frozen?: boolean } — ⚠ undocumented
1451
+ - `EntityPose` (interface): interface EntityPose { position: SpawnPositionInput; rotationY?: number; rotationX?: number; rotationZ?: number; dt?: number } — ⚠ undocumented
1452
+ - `EntityPosition` (type): type EntityPosition = readonly [number, number, number] — ⚠ undocumented · used by `resolveSourceWalkerStep` (@jgengine/core/movement/solidObstacles): {@link resolveWalkerStep} with no `GameContext`: gather plus slide against a bare {@link SolidObstacleSource} and a caller-owned {@link Obst…
1082
1453
  - `EntityRole` (type): type EntityRole = "player" | "npc" | "prop" — ⚠ undocumented
1083
- - `EntityStore` (interface): interface EntityStore<TMeta = unknown> — ⚠ undocumented
1454
+ - `EntityStore` (interface): interface EntityStore<TMeta = unknown> { spawn(name: string, options?: SpawnOptions<TMeta>): string; despawn(id: string): boolean; update(id: string, patch: EntityUpdatePatch<TMeta>): boolean; setPose(id: string, pose: EntityPose): boolean; setPoseConstraint(id: string, constrai… — ⚠ undocumented · used by `createSimContext` (@jgengine/core/runtime/simContext): Build `ctx.sim` for a context; `createGameContext` calls this from `definition.simulation`.
1084
1455
  - `EntityUpdatePatch` (type): type EntityUpdatePatch<TMeta = unknown> = Partial< Pick<SceneEntity<TMeta>, "name" | "rotationY" | "rotationX" | "rotationZ" | "role" | "movement" | "behaviors" | "hidden" | "meta"> > & { /** Accepts the same friendly shapes as `spawn`/`setPose` (#286.13). Raw patch semantics — velocity is not deriv… — ⚠ undocumented
1085
1456
  - `PoseConstraint` (type): type PoseConstraint = (frame: PoseConstraintFrame) => readonly [number, number, number] | undefined | void — Return a replacement position to constrain the step, or nothing to accept it.
1086
- - `PoseConstraintFrame` (interface): interface PoseConstraintFrame — ⚠ undocumented
1087
- - `SceneEntity` (interface): interface SceneEntity<TMeta = unknown> — ⚠ undocumented
1088
- - `SpawnOptions` (interface): interface SpawnOptions<TMeta = unknown> — ⚠ undocumented
1089
- - `SpawnPose` (interface): interface SpawnPose — ⚠ undocumented
1457
+ - `PoseConstraintFrame` (interface): interface PoseConstraintFrame { entityId: string; current: EntityPosition; next: EntityPosition; dt?: number } — ⚠ undocumented
1458
+ - `SceneEntity` (interface): interface SceneEntity<TMeta = unknown> { id: string; name: string; position: EntityPosition; rotationY: number; rotationX: number; rotationZ: number; velocity: EntityPosition; role: EntityRole; movement: EntityMovement; behaviors: readonly BehaviorDescriptor[]; hidden?: boolean;… — ⚠ undocumented · used by `entityMetaOf`: Narrow `entity.meta` with a type guard — prefer this over `entity.meta as T` so failed shapes return `null` instead of lying to the type che…
1459
+ - `SpawnOptions` (interface): interface SpawnOptions<TMeta = unknown> { id?: string; position?: SpawnPositionInput; rotationY?: number; rotationX?: number; rotationZ?: number; role?: EntityRole; movement?: EntityMovement; behaviors?: readonly BehaviorDescriptor[]; hidden?: boolean; meta?: TMeta; onExisting?: … — ⚠ undocumented
1460
+ - `SpawnPose` (interface): interface SpawnPose { position: EntityPosition; rotationY: number } — ⚠ undocumented
1090
1461
  - `SpawnPositionInput` (type): type SpawnPositionInput = EntityPosition | { x: number; y: number; z: number } — ⚠ undocumented
1091
1462
  - `createEntityStore` (function): function createEntityStore<TMeta = unknown>(): EntityStore<TMeta> — ⚠ undocumented
1092
1463
  - `entityMetaOf` (function): function entityMetaOf<T>(entity: SceneEntity<unknown>, isMeta: (value: unknown) => value is T): T | null — Narrow `entity.meta` with a type guard — prefer this over `entity.meta as T` so failed shapes return `null` instead of lying to the type checker.
@@ -1099,13 +1470,13 @@
1099
1470
 
1100
1471
  ## @jgengine/core/scene/form
1101
1472
 
1102
- - `FormChangedEvent` (interface): interface FormChangedEvent — ⚠ undocumented
1103
- - `FormDef` (interface): interface FormDef — ⚠ undocumented
1104
- - `FormEntities` (interface): interface FormEntities — ⚠ undocumented
1105
- - `FormEvents` (interface): interface FormEvents — ⚠ undocumented
1106
- - `FormTime` (interface): interface FormTime — ⚠ undocumented
1107
- - `Forms` (interface): interface Forms — ⚠ undocumented
1108
- - `FormsDeps` (interface): interface FormsDeps — ⚠ undocumented
1473
+ - `FormChangedEvent` (interface): interface FormChangedEvent { instanceId: string; formId: string | null } — ⚠ undocumented
1474
+ - `FormDef` (interface): interface FormDef { id: string; movement?: EntityMovement; abilities?: readonly string[]; model?: string } — ⚠ undocumented
1475
+ - `FormEntities` (interface): interface FormEntities { get(id: string): SceneEntity | null; update(id: string, patch: {movement?: EntityMovement; name?: string}): boolean } — ⚠ undocumented
1476
+ - `FormEvents` (interface): interface FormEvents { emit(name: "form.changed", payload: FormChangedEvent): void } — ⚠ undocumented
1477
+ - `FormTime` (interface): interface FormTime { after(seconds: number, callback: () => void): () => void } — ⚠ undocumented
1478
+ - `Forms` (interface): interface Forms { register(defs: readonly FormDef[]): void; get(formId: string): FormDef | null; abilities(instanceId: string): readonly string[] | null; active(instanceId: string): string | null; shapeshift(instanceId: string, formId: string, durationSeco… — ⚠ undocumented
1479
+ - `FormsDeps` (interface): interface FormsDeps { entities: FormEntities; time: FormTime; events?: FormEvents } — ⚠ undocumented
1109
1480
  - `createForms` (function): function createForms(deps: FormsDeps): Forms — ⚠ undocumented
1110
1481
 
1111
1482
  ## @jgengine/core/scene/modelSockets
@@ -1119,63 +1490,63 @@
1119
1490
 
1120
1491
  - `MountController` (class): class MountController — Mount / rideable control-transfer (issue #83). Registers rideables (each with one or more seats — a control seat drives, the rest ride) and tracks who is on what. It owns no camera or physics: game code reads `cameraTarget(riderId)` to point the follow camera at the mount, and `driveTarget(riderId)` to route that rider's {@link import("../physics/vehicleBody").AxisInput}-driven input at the mount's movement kit — the same seam a horse, a truck, or a shared multi-seat ship all plug into.
1121
1492
  - `MountKind` (type): type MountKind = "ground" | "boat" | "flying" | "swimming" — ⚠ undocumented
1122
- - `MountKit` (interface): interface MountKit — ⚠ undocumented
1493
+ - `MountKit` (interface): interface MountKit { kind: MountKind; moveSpeed?: number; turnSpeed?: number } — ⚠ undocumented
1123
1494
  - `MountResult` (type): type MountResult = { ok: true; seat: MountSeat } | { ok: false; reason: string } — ⚠ undocumented
1124
- - `MountSeat` (interface): interface MountSeat — ⚠ undocumented
1125
- - `Occupant` (interface): interface Occupant — ⚠ undocumented
1126
- - `RideableConfig` (interface): interface RideableConfig — ⚠ undocumented
1127
- - `SeatRef` (interface): interface SeatRef — ⚠ undocumented
1495
+ - `MountSeat` (interface): interface MountSeat { id: string; offset: readonly [number, number, number]; control?: boolean } — ⚠ undocumented
1496
+ - `Occupant` (interface): interface Occupant { riderId: string; seatId: string } — ⚠ undocumented
1497
+ - `RideableConfig` (interface): interface RideableConfig { id: string; kit: MountKit; seats?: readonly MountSeat[] } — ⚠ undocumented
1498
+ - `SeatRef` (interface): interface SeatRef { mountId: string; seatId: string } — ⚠ undocumented
1128
1499
  - `createMountController` (function): function createMountController(): MountController — ⚠ undocumented
1129
1500
 
1130
1501
  ## @jgengine/core/scene/movementSpeed
1131
1502
 
1132
- - `MovementSpeedConfig` (interface): interface MovementSpeedConfig — ⚠ undocumented
1133
- - `MovementSpeedDeps` (interface): interface MovementSpeedDeps — ⚠ undocumented
1134
- - `MovementSpeedModifiers` (interface): interface MovementSpeedModifiers — ⚠ undocumented
1503
+ - `MovementSpeedConfig` (interface): interface MovementSpeedConfig { baseSpeed: number; multiplierStat?: string; flatBonusStat?: string } — ⚠ undocumented · used by `applyStatDrivenSpeed`: Recomputes `movement.walkSpeed` for an entity from its stats and writes it back via `deps.entities.update`.
1504
+ - `MovementSpeedDeps` (interface): interface MovementSpeedDeps { stats: {get(instanceId: string, statId: string): StatValue | null}; entities: {get(id: string): {movement?: {walkSpeed?: number}} | null; update(id: string, patch: {movement: {walkSpeed: number}}): boolean;} } — ⚠ undocumented · used by `applyStatDrivenSpeed`: Recomputes `movement.walkSpeed` for an entity from its stats and writes it back via `deps.entities.update`.
1505
+ - `MovementSpeedModifiers` (interface): interface MovementSpeedModifiers { multiplier?: number; flatBonus?: number } — ⚠ undocumented · used by `deriveWalkSpeed`: `base * (multiplier ?? 1) + (flatBonus ?? 0)`, clamped to never go negative.
1135
1506
  - `applyStatDrivenSpeed` (function): function applyStatDrivenSpeed(deps: MovementSpeedDeps, instanceId: string, config: MovementSpeedConfig): boolean — Recomputes `movement.walkSpeed` for an entity from its stats and writes it back via `deps.entities.update`. Either stat id is optional; an omitted or unresolved stat contributes its neutral value (multiplier 1, flat bonus 0) rather than failing. Returns false only when the entity itself doesn't exist.
1136
1507
  - `deriveWalkSpeed` (function): function deriveWalkSpeed(base: number, modifiers: MovementSpeedModifiers): number — `base * (multiplier ?? 1) + (flatBonus ?? 0)`, clamped to never go negative.
1137
1508
 
1138
1509
  ## @jgengine/core/scene/objectQuery
1139
1510
 
1140
1511
  - `ObjectQueryBroadphase` (interface): interface ObjectQueryBroadphase — Optional broadphase for large object sets — typically `ObjectStore.inBox`.
1141
- - `ObjectRaycastHit` (interface): interface ObjectRaycastHit — ⚠ undocumented
1142
- - `ObjectRaycastInput` (interface): interface ObjectRaycastInput — ⚠ undocumented
1512
+ - `ObjectRaycastHit` (interface): interface ObjectRaycastHit { instanceId: string; catalogId: string; distance: number; point: EntityPosition; normal: EntityPosition } — ⚠ undocumented
1513
+ - `ObjectRaycastInput` (interface): interface ObjectRaycastInput { origin: EntityPosition; direction: EntityPosition; maxDistance: number; halfExtents?: EntityPosition; filter?: (object: SceneObject) => boolean } — ⚠ undocumented
1143
1514
  - `ObjectRaycastSource` (type): type ObjectRaycastSource = readonly SceneObject[] | ObjectQueryBroadphase — ⚠ undocumented
1144
1515
  - `intersectAabb` (function): function intersectAabb(origin: EntityPosition, direction: EntityPosition, min: EntityPosition, max: EntityPosition, maxDistance: number): { distance: number; normal: EntityPosition } | null — ⚠ undocumented
1145
1516
  - `normalizeDirection` (function): function normalizeDirection(direction: EntityPosition): EntityPosition — ⚠ undocumented
1146
1517
 
1147
1518
  ## @jgengine/core/scene/objectStore
1148
1519
 
1149
- - `ObjectListFilter` (interface): interface ObjectListFilter — ⚠ undocumented
1150
- - `ObjectStore` (interface): interface ObjectStore — ⚠ undocumented
1151
- - `ObjectVisual` (interface): interface ObjectVisual — ⚠ undocumented
1152
- - `PlaceOptions` (interface): interface PlaceOptions — ⚠ undocumented
1153
- - `SceneObject` (interface): interface SceneObject — ⚠ undocumented
1520
+ - `ObjectListFilter` (interface): interface ObjectListFilter { parentSpace?: string } — ⚠ undocumented
1521
+ - `ObjectStore` (interface): interface ObjectStore { place(catalogId: string, x: number, y: number, z: number, options?: PlaceOptions): string; remove(instanceId: string): boolean; move(instanceId: string, x: number, y: number, z: number): boolean; rotate(instanceId: string, rotationY: numb… — ⚠ undocumented
1522
+ - `ObjectVisual` (interface): interface ObjectVisual { scale?: number | readonly [number, number, number]; color?: string; opacity?: number } — ⚠ undocumented
1523
+ - `PlaceOptions` (interface): interface PlaceOptions { instanceId?: string; parentSpace?: string; rotation?: number; visual?: ObjectVisual; state?: Record<string, unknown>; slots?: InventoryState; animation?: ModelAnimationConfig | "auto" | "none"; onExisting?: "throw" | "replace" | "keep" } — ⚠ undocumented
1524
+ - `SceneObject` (interface): interface SceneObject { instanceId: string; catalogId: string; position: EntityPosition; rotationY: number; parentSpace?: string; visual?: ObjectVisual; animation?: ModelAnimationConfig | "auto" | "none"; state?: Record<string, unknown>; slots?: InventoryState } — ⚠ undocumented · used by `fromRuntimeObjectRow` (@jgengine/core/runtime/objectRows): Inverse of {@link toRuntimeObjectRow}: rebuild the live placed object a host persisted.
1154
1525
  - `createObjectStore` (function): function createObjectStore(): ObjectStore — ⚠ undocumented
1155
1526
  - `objectVisualScale` (function): function objectVisualScale(visual: ObjectVisual | undefined): readonly [number, number, number] — ⚠ undocumented
1156
1527
 
1157
1528
  ## @jgengine/core/scene/paintLayer
1158
1529
 
1159
- - `PaintLayer` (interface): interface PaintLayer — ⚠ undocumented
1160
- - `PaintStroke` (interface): interface PaintStroke — ⚠ undocumented
1530
+ - `PaintLayer` (interface): interface PaintLayer { paint(instanceId: string, stroke: PaintStroke): void; strokes(instanceId: string): readonly PaintStroke[]; paintedIds(): readonly string[]; clear(instanceId?: string): void; version(instanceId: string): number; subscribe(listener: () => v… — ⚠ undocumented
1531
+ - `PaintStroke` (interface): interface PaintStroke { u: number; v: number; radius: number; color: string } — ⚠ undocumented
1161
1532
  - `createPaintLayer` (function): function createPaintLayer(): PaintLayer — ⚠ undocumented
1162
1533
 
1163
1534
  ## @jgengine/core/scene/possession
1164
1535
 
1165
- - `Possession` (interface): interface Possession — ⚠ undocumented
1166
- - `PossessionDeps` (interface): interface PossessionDeps — ⚠ undocumented
1167
- - `PossessionEntities` (interface): interface PossessionEntities — ⚠ undocumented
1168
- - `PossessionEvents` (interface): interface PossessionEvents — ⚠ undocumented
1169
- - `PossessionSnapshot` (interface): interface PossessionSnapshot — ⚠ undocumented
1170
- - `PossessionSwappedEvent` (interface): interface PossessionSwappedEvent — ⚠ undocumented
1536
+ - `Possession` (interface): interface Possession { own(userId: string, entityId: string): void; disown(userId: string, entityId: string): void; owns(userId: string, entityId: string): boolean; listOwned(userId: string): readonly string[]; active(userId: string): string; possess(userId: st… — ⚠ undocumented
1537
+ - `PossessionDeps` (interface): interface PossessionDeps { entities: PossessionEntities; events?: PossessionEvents } — ⚠ undocumented
1538
+ - `PossessionEntities` (interface): interface PossessionEntities { get(id: string): SceneEntity | null; update(id: string, patch: {role?: SceneEntity["role"]}): boolean } — ⚠ undocumented
1539
+ - `PossessionEvents` (interface): interface PossessionEvents { emit(name: "possession.swapped", payload: PossessionSwappedEvent): void } — ⚠ undocumented
1540
+ - `PossessionSnapshot` (interface): interface PossessionSnapshot { owned: Record<string, readonly string[]>; active: Record<string, string> } — ⚠ undocumented
1541
+ - `PossessionSwappedEvent` (interface): interface PossessionSwappedEvent { userId: string; entityId: string; previousEntityId: string } — ⚠ undocumented
1171
1542
  - `createPossession` (function): function createPossession(deps: PossessionDeps): Possession — ⚠ undocumented
1172
1543
 
1173
1544
  ## @jgengine/core/scene/roster
1174
1545
 
1175
- - `Roster` (interface): interface Roster — ⚠ undocumented
1176
- - `RosterCaptureOptions` (interface): interface RosterCaptureOptions — ⚠ undocumented
1177
- - `RosterDeps` (interface): interface RosterDeps — ⚠ undocumented
1178
- - `RosterEntry` (interface): interface RosterEntry — ⚠ undocumented
1546
+ - `Roster` (interface): interface Roster { capture(userId: string, catalogId: string, options?: RosterCaptureOptions): RosterEntry; release(userId: string, entryId: string): boolean; has(userId: string, entryId: string): boolean; get(userId: string, entryId: string): RosterEntry |… — ⚠ undocumented
1547
+ - `RosterCaptureOptions` (interface): interface RosterCaptureOptions { id?: string; capturedAt?: number } — ⚠ undocumented
1548
+ - `RosterDeps` (interface): interface RosterDeps { now?: () => number } — ⚠ undocumented
1549
+ - `RosterEntry` (interface): interface RosterEntry { id: string; catalogId: string; capturedAt: number; equipped: boolean } — ⚠ undocumented
1179
1550
  - `createRoster` (function): function createRoster(deps: RosterDeps = {}): Roster — ⚠ undocumented
1180
1551
 
1181
1552
  ## @jgengine/core/scene/sceneKinds
@@ -1195,7 +1566,7 @@
1195
1566
  - `SceneKindDefinition` (interface): interface SceneKindDefinition<TResolved = unknown> — A registered scene kind — everything the editor/engine need to author and render a studio without bespoke code. `schema` drives the inspector + parse; `resolve` (optional) turns one document object into pure renderable data a matching `shell` renderer consumes; `add*` fields build the `+ Add` menu.
1196
1567
  - `SceneKindObject` (interface): interface SceneKindObject — The raw document object a resolver receives — shape shared by markers, volumes, and paths.
1197
1568
  - `SceneKindResolveContext` (interface): interface SceneKindResolveContext — Ground sampler + options a resolver may read (terrain height/normal snap).
1198
- - `SceneKindTarget` (type): type SceneKindTarget = "path" | "marker" | "volume" — The parametric-studio seam: a registry that maps an editor object `kind` to a typed parameter schema (drives the inspector + `meta` parse/validation), an optional pure-data `resolve` (turns a document object into renderable data), and `+ Add` menu metadata. Registering a kind lets a third party ship a new authorable "studio" (pole line, water, bookcase) — schema + resolver here, a matching renderer in `shell` — without editing editor or engine files. Scatter is the proof adopter.
1569
+ - `SceneKindTarget` (type): type SceneKindTarget = "path" | "marker" | "volume" — Which document collection a scene kind lives in. Drives placement + which `meta` bag holds params.
1199
1570
  - `ScenePathShape` (type): type ScenePathShape = "area" | "line" — A closed-polygon area vs an open polyline, for path-target kinds. Ignored for marker/volume kinds.
1200
1571
  - `SeedParamField` (interface): interface SeedParamField — A seed string with a reroll button — same seed reproduces the same generated result.
1201
1572
  - `SelectParamField` (interface): interface SelectParamField — A dropdown of fixed string options.
@@ -1209,25 +1580,25 @@
1209
1580
 
1210
1581
  ## @jgengine/core/scene/sceneRaycast
1211
1582
 
1212
- - `SceneEntityQuerySource` (interface): interface SceneEntityQuerySource — ⚠ undocumented
1213
- - `SceneObjectQuerySource` (interface): interface SceneObjectQuerySource — ⚠ undocumented
1214
- - `SceneRaycastApi` (interface): interface SceneRaycastApi — ⚠ undocumented
1215
- - `SceneRaycastDeps` (interface): interface SceneRaycastDeps — ⚠ undocumented
1216
- - `SceneRaycastFilter` (interface): interface SceneRaycastFilter — ⚠ undocumented
1217
- - `SceneRaycastHit` (interface): interface SceneRaycastHit — ⚠ undocumented
1218
- - `SceneRaycastInput` (interface): interface SceneRaycastInput — ⚠ undocumented
1583
+ - `SceneEntityQuerySource` (interface): interface SceneEntityQuerySource { list(): readonly {id: string; position: EntityPosition; rotationY: number; name?: string}[]; collidersOf?(instanceId: string): EntityColliderSet | null | undefined; inRadius?(center: EntityPosition, radius: number): readonly string[]; get… — ⚠ undocumented
1584
+ - `SceneObjectQuerySource` (interface): interface SceneObjectQuerySource { list(): readonly SceneObject[]; inBox?(min: EntityPosition, max: EntityPosition): readonly SceneObject[]; collidersOf?(instanceId: string): EntityColliderSet | null | undefined; halfExtentsOf?(catalogId: string): EntityPosition | null | u… — ⚠ undocumented
1585
+ - `SceneRaycastApi` (interface): interface SceneRaycastApi { raycast(input: SceneRaycastInput): SceneRaycastHit | null; raycastAll(input: SceneRaycastInput): SceneRaycastHit[] } — ⚠ undocumented
1586
+ - `SceneRaycastDeps` (interface): interface SceneRaycastDeps { entities?: SceneEntityQuerySource; objects?: SceneObjectQuerySource; terrain?: TerrainRaycastSource; walls?: readonly WallSegment[] } — ⚠ undocumented
1587
+ - `SceneRaycastFilter` (interface): interface SceneRaycastFilter { entities?: boolean; objects?: boolean; terrain?: boolean; walls?: boolean } — ⚠ undocumented
1588
+ - `SceneRaycastHit` (interface): interface SceneRaycastHit { targetKind: SceneRaycastTargetKind; instanceId: string; catalogId?: string; colliderName: string; purpose: ColliderPurpose; damageEligible: boolean; blocks: boolean; distance: number; point: EntityPosition; normal: EntityPosition } — ⚠ undocumented · used by `firstImpact`: First impact: nearest hit that blocks, or nearest hit if none block.
1589
+ - `SceneRaycastInput` (interface): interface SceneRaycastInput { origin: EntityPosition; direction: EntityPosition; maxDistance: number; excludeInstanceIds?: ReadonlySet<string> | readonly string[]; filter?: SceneRaycastFilter; accept?: (hit: SceneRaycastHit) => boolean } — ⚠ undocumented
1219
1590
  - `SceneRaycastTargetKind` (type): type SceneRaycastTargetKind = "entity" | "object" | "terrain" | "wall" — ⚠ undocumented
1220
- - `TerrainRaycastSource` (interface): interface TerrainRaycastSource — ⚠ undocumented
1221
- - `WallSegment` (interface): interface WallSegment — ⚠ undocumented
1591
+ - `TerrainRaycastSource` (interface): interface TerrainRaycastSource { sampleHeight(x: number, z: number): number } — ⚠ undocumented
1592
+ - `WallSegment` (interface): interface WallSegment { id: string; a: readonly [number, number]; b: readonly [number, number]; yCenter?: number; halfHeight?: number; thickness?: number } — ⚠ undocumented · used by `wallSolids` (@jgengine/core/world/worldSolids): One oriented solid per wall segment (see `wallSegments` in `world/walls`).
1222
1593
  - `createSceneRaycast` (function): function createSceneRaycast(deps: SceneRaycastDeps): SceneRaycastApi — ⚠ undocumented
1223
1594
  - `firstImpact` (function): function firstImpact(hits: readonly SceneRaycastHit[]): SceneRaycastHit | null — First impact: nearest hit that blocks, or nearest hit if none block.
1224
1595
  - `hitsUntilBlocked` (function): function hitsUntilBlocked(hits: readonly SceneRaycastHit[]): SceneRaycastHit[] — Hits up to and including the first blocking collider (damage hitboxes before a wall stay).
1225
1596
 
1226
1597
  ## @jgengine/core/scene/selection
1227
1598
 
1228
- - `ScreenPoint` (interface): interface ScreenPoint — ⚠ undocumented
1229
- - `ScreenRect` (interface): interface ScreenRect — ⚠ undocumented
1230
- - `SelectionSet` (interface): interface SelectionSet — ⚠ undocumented
1599
+ - `ScreenPoint` (interface): interface ScreenPoint { id: string; x: number; y: number } — ⚠ undocumented · used by `selectWithinRect`: Ids of the projected candidates whose screen point falls inside the marquee.
1600
+ - `ScreenRect` (interface): interface ScreenRect { minX: number; minY: number; maxX: number; maxY: number } — ⚠ undocumented · used by `isMarquee`: True when the drag is large enough to be a marquee rather than a click.
1601
+ - `SelectionSet` (interface): interface SelectionSet { add(id: string): void; remove(id: string): void; toggle(id: string): void; has(id: string): boolean; replace(ids: Iterable<string>): void; clear(): void; list(): string[]; size(): number } — ⚠ undocumented · used by `createSelectionSet`: An ordered, deduplicated set of selected instance ids for RTS unit-command routing.
1231
1602
  - `createSelectionSet` (function): function createSelectionSet(initial?: Iterable<string>): SelectionSet — An ordered, deduplicated set of selected instance ids for RTS unit-command routing.
1232
1603
  - `isMarquee` (function): function isMarquee(rect: ScreenRect, thresholdPx = 4): boolean — True when the drag is large enough to be a marquee rather than a click.
1233
1604
  - `rectContainsPoint` (function): function rectContainsPoint(rect: ScreenRect, x: number, y: number): boolean — ⚠ undocumented
@@ -1257,30 +1628,30 @@
1257
1628
 
1258
1629
  ## @jgengine/core/scene/spatial
1259
1630
 
1260
- - `Aim` (type): type Aim = | { origin: EntityPosition; direction: EntityPosition } | { yaw: number; pitch: number; spread?: number } — ⚠ undocumented
1261
- - `MoveTowardOptions` (interface): interface MoveTowardOptions — ⚠ undocumented
1262
- - `QueryArcOptions` (interface): interface QueryArcOptions — ⚠ undocumented
1263
- - `SpatialApi` (interface): interface SpatialApi — ⚠ undocumented
1264
- - `SpatialApiOptions` (interface): interface SpatialApiOptions — ⚠ undocumented
1265
- - `SpatialGridOptions` (interface): interface SpatialGridOptions — ⚠ undocumented
1631
+ - `Aim` (type): type Aim = | { origin: EntityPosition; direction: EntityPosition } | { yaw: number; pitch: number; spread?: number } — ⚠ undocumented · used by `aimToPoint` (@jgengine/core/input/pointer): Build an `origin → point` aim for `item.use` / projectiles, firing toward the cursor.
1632
+ - `MoveTowardOptions` (interface): interface MoveTowardOptions { speed: number; stopDistance?: number; dt: number; avoidSolids?: boolean } — ⚠ undocumented
1633
+ - `QueryArcOptions` (interface): interface QueryArcOptions { from: string; aim: Aim; radius: number; halfAngleDeg?: number } — ⚠ undocumented
1634
+ - `SpatialApi` (interface): interface SpatialApi { distance(aInstanceId: string, bInstanceId: string): number | null; inRadius(center: EntityPosition | string, radius: number, filter?: (instanceId: string) => boolean): string[]; hasLineOfSight(fromInstanceId: string, toInstanceId: string)… — ⚠ undocumented
1635
+ - `SpatialApiOptions` (interface): interface SpatialApiOptions { resolvePosition: (instanceId: string) => EntityPosition | undefined; candidates: () => readonly string[]; occluder?: (from: EntityPosition, to: EntityPosition) => boolean; grid?: SpatialGridOptions | false; getVersion?: () => number; reso… — ⚠ undocumented
1636
+ - `SpatialGridOptions` (interface): interface SpatialGridOptions { cellSize: number } — ⚠ undocumented
1266
1637
  - `createSpatialApi` (function): function createSpatialApi(options: SpatialApiOptions): SpatialApi — ⚠ undocumented
1267
1638
  - `distanceBetween` (function): function distanceBetween(a: EntityPosition, b: EntityPosition): number — ⚠ undocumented
1268
1639
 
1269
1640
  ## @jgengine/core/scene/stationClaim
1270
1641
 
1271
1642
  - `ClaimResult` (type): type ClaimResult = | { ok: true; station: Station } | { ok: false; reason: "unknown_vehicle" | "unknown_facet" | "station_taken" | "vehicle_full" } — ⚠ undocumented
1272
- - `SharedVehicleConfig` (interface): interface SharedVehicleConfig — ⚠ undocumented
1273
- - `Station` (interface): interface Station — ⚠ undocumented
1643
+ - `SharedVehicleConfig` (interface): interface SharedVehicleConfig { id: string; kit: MountKit; stations: readonly Station[] } — ⚠ undocumented
1644
+ - `Station` (interface): interface Station { id: string; facet: string; offset: readonly [number, number, number]; control?: boolean } — ⚠ undocumented
1274
1645
  - `StationClaim` (class): class StationClaim — ⚠ undocumented
1275
1646
  - `createStationClaim` (function): function createStationClaim(controller?: MountController): StationClaim — ⚠ undocumented
1276
1647
 
1277
1648
  ## @jgengine/core/scene/targeting
1278
1649
 
1279
- - `CycleTargetOptions` (interface): interface CycleTargetOptions — ⚠ undocumented
1650
+ - `CycleTargetOptions` (interface): interface CycleTargetOptions { filter?: TargetFilter; direction?: "next" | "prev"; maxDistance?: number } — ⚠ undocumented
1280
1651
  - `TargetFilter` (type): type TargetFilter = TargetRelation | "any" — ⚠ undocumented
1281
1652
  - `TargetRelation` (type): type TargetRelation = "hostile" | "friendly" — ⚠ undocumented
1282
- - `Targeting` (interface): interface Targeting — ⚠ undocumented
1283
- - `TargetingOptions` (interface): interface TargetingOptions — ⚠ undocumented
1653
+ - `Targeting` (interface): interface Targeting { setTarget(fromId: string, toId: string | null): void; getTarget(fromId: string): string | null; cycleTarget(fromId: string, options?: CycleTargetOptions): string | null; clearAll(instanceId: string): void } — ⚠ undocumented
1654
+ - `TargetingOptions` (interface): interface TargetingOptions { candidates: () => string[]; classify?: (fromId: string, toId: string) => TargetRelation; orderBy?: (a: string, b: string) => number; distance?: (fromId: string, toId: string) => number | null } — ⚠ undocumented
1284
1655
  - `createTargeting` (function): function createTargeting(options: TargetingOptions): Targeting — ⚠ undocumented
1285
1656
 
1286
1657
  ## @jgengine/core/scene/vehicleSeat
@@ -1298,74 +1669,94 @@
1298
1669
  ## @jgengine/core/sensor/concealment
1299
1670
 
1300
1671
  - `ColorHex` (type): type ColorHex = string — ⚠ undocumented
1301
- - `ConcealmentSample` (interface): interface ConcealmentSample — ⚠ undocumented
1302
- - `ConcealmentSensor` (interface): interface ConcealmentSensor — ⚠ undocumented
1303
- - `ConcealmentTarget` (interface): interface ConcealmentTarget — ⚠ undocumented
1672
+ - `ConcealmentSample` (interface): interface ConcealmentSample { id: string; score: number; concealed: boolean; dwellSeconds: number } — ⚠ undocumented
1673
+ - `ConcealmentSensor` (interface): interface ConcealmentSensor { tick(targets: readonly ConcealmentTarget[], dt: number): ConcealmentSample[]; reset(id?: string): void; snapshot(): ConcealmentSensorState; restore(next: ConcealmentSensorState): void } — ⚠ undocumented
1674
+ - `ConcealmentSensorState` (interface): interface ConcealmentSensorState — Plain JSON state of a {@link ConcealmentSensor}: seconds each target has stayed concealed.
1675
+ - `ConcealmentTarget` (interface): interface ConcealmentTarget { id: string; entityColors: readonly ColorHex[]; backgroundColors: readonly ColorHex[] } — ⚠ undocumented
1304
1676
 
1305
1677
  ## @jgengine/core/sensor/freezeMonitor
1306
1678
 
1307
- - `FreezeMonitor` (interface): interface FreezeMonitor — ⚠ undocumented
1308
- - `FreezeSubject` (interface): interface FreezeSubject — ⚠ undocumented
1309
- - `FreezeViolation` (interface): interface FreezeViolation — ⚠ undocumented
1679
+ - `FreezeMonitor` (interface): interface FreezeMonitor { tick(subjects: readonly FreezeSubject[], frozenIds: ReadonlySet<string>, dt: number): FreezeViolation[]; reset(id?: string): void; snapshot(): FreezeMonitorState; restore(next: FreezeMonitorState): void } — ⚠ undocumented
1680
+ - `FreezeMonitorState` (interface): interface FreezeMonitorState — Plain JSON state of a {@link FreezeMonitor}: seconds each frozen subject has kept moving.
1681
+ - `FreezeSubject` (interface): interface FreezeSubject { id: string; groundSpeed: number } — ⚠ undocumented
1682
+ - `FreezeViolation` (interface): interface FreezeViolation { id: string; speed: number; movedSeconds: number } — ⚠ undocumented
1310
1683
 
1311
1684
  ## @jgengine/core/sensor/frustumSensor
1312
1685
 
1313
- - `FramingConfig` (interface): interface FramingConfig — ⚠ undocumented
1314
- - `FrustumCamera` (interface): interface FrustumCamera — ⚠ undocumented
1315
- - `FrustumProjection` (interface): interface FrustumProjection — ⚠ undocumented
1316
- - `FrustumSample` (interface): interface FrustumSample — ⚠ undocumented
1317
- - `FrustumSensor` (interface): interface FrustumSensor — ⚠ undocumented
1318
- - `FrustumTarget` (interface): interface FrustumTarget — ⚠ undocumented
1686
+ - `FramingConfig` (interface): interface FramingConfig { idealDistance?: number; centerWeight?: number; sizeWeight?: number } — ⚠ undocumented
1687
+ - `FrustumCamera` (interface): interface FrustumCamera { position: EntityPosition; lookAt: EntityPosition; fovDeg?: number; aspect?: number; near?: number; far?: number } — ⚠ undocumented
1688
+ - `FrustumProjection` (interface): interface FrustumProjection { inView: boolean; distance: number; screenX: number; screenY: number } — ⚠ undocumented
1689
+ - `FrustumSample` (interface): interface FrustumSample { id: string; inView: boolean; distance: number; screenX: number; screenY: number; framing: number; dwellSeconds: number } — ⚠ undocumented
1690
+ - `FrustumSensor` (interface): interface FrustumSensor { tick(camera: FrustumCamera, targets: readonly FrustumTarget[], dt: number): FrustumSample[]; reset(id?: string): void } — ⚠ undocumented
1691
+ - `FrustumTarget` (interface): interface FrustumTarget { id: string; position: EntityPosition; radius?: number } — ⚠ undocumented
1319
1692
 
1320
1693
  ## @jgengine/core/sensor/hiddenStateProbe
1321
1694
 
1322
- - `HiddenStateSource` (interface): interface HiddenStateSource — ⚠ undocumented
1695
+ - `HiddenStateSource` (interface): interface HiddenStateSource { id: string; position: EntityPosition; variables: Readonly<Record<string, HiddenStateValue>> } — ⚠ undocumented · used by `useHiddenStateProbe` (@jgengine/shell/vision/HiddenStateProbeHud): Reads a hidden zone/entity state variable in range (EMF / thermometer / geiger style sensor verb, #116).
1323
1696
  - `HiddenStateValue` (type): type HiddenStateValue = number | string | boolean — ⚠ undocumented
1324
- - `SensorProbeOptions` (interface): interface SensorProbeOptions — ⚠ undocumented
1325
- - `SensorReading` (interface): interface SensorReading — ⚠ undocumented
1697
+ - `SensorProbeOptions` (interface): interface SensorProbeOptions { range: number; variableId: string; falloff?: "linear" | "none" } — ⚠ undocumented · used by `useHiddenStateProbe` (@jgengine/shell/vision/HiddenStateProbeHud): Reads a hidden zone/entity state variable in range (EMF / thermometer / geiger style sensor verb, #116).
1698
+ - `SensorReading` (interface): interface SensorReading { sourceId: string; variableId: string; value: HiddenStateValue; strength: number; distance: number } — ⚠ undocumented · used by `useHiddenStateProbe` (@jgengine/shell/vision/HiddenStateProbeHud): Reads a hidden zone/entity state variable in range (EMF / thermometer / geiger style sensor verb, #116).
1699
+
1700
+ ## @jgengine/core/sensor/perception
1701
+
1702
+ - `PerceptionCandidate` (interface): interface PerceptionCandidate — A candidate target considered by a sight check.
1703
+ - `PerceptionConfig` (interface): interface PerceptionConfig — Configuration for sight, hearing, memory decay, and optional occlusion.
1704
+ - `PerceptionMemory` (interface): interface PerceptionMemory — A remembered target and its linearly decaying confidence.
1705
+ - `PerceptionObserver` (interface): interface PerceptionObserver — The observer pose used for a sight check.
1706
+ - `PerceptionPosition` (type): type PerceptionPosition = readonly [number, number, number] — A world position used by perception, in `[x, y, z]` order.
1707
+ - `PerceptionService` (interface): interface PerceptionService — Stateful perception API with retuning and save/restore support.
1708
+ - `PerceptionSnapshot` (interface): interface PerceptionSnapshot — Serializable state for a perception service.
1709
+ - `PerceptionStimulus` (interface): interface PerceptionStimulus — An event that can seed an observer's memory.
1710
+ - `PerceptionStimulusKind` (type): type PerceptionStimulusKind = "sight" | "sound" | "damage" — The kinds of stimulus the perception service can retain.
1711
+ - `createPerception` (function): function createPerception(initial: PerceptionConfig): PerceptionService — Creates a deterministic sight, sound, and damage perception service with expiring target memory.
1326
1712
 
1327
1713
  ## @jgengine/core/sensor/recordingBuffer
1328
1714
 
1329
- - `RecordingBuffer` (interface): interface RecordingBuffer<T> — ⚠ undocumented
1330
- - `RecordingBufferOptions` (interface): interface RecordingBufferOptions — ⚠ undocumented
1331
- - `RecordingFrame` (interface): interface RecordingFrame<T> — ⚠ undocumented
1332
- - `RecordingPair` (interface): interface RecordingPair<T> — ⚠ undocumented
1715
+ - `RecordingBuffer` (interface): interface RecordingBuffer<T> { append(t: number, data: T): void; seek(t: number): RecordingFrame<T> | null; seekPair(t: number): RecordingPair<T>; range(fromT: number, toT: number): RecordingFrame<T>[]; clear(): void; duration(): number; frames(): readonly RecordingFra… — ⚠ undocumented · used by `useSessionRecorder` (@jgengine/shell/replay/useSessionRecorder): Session-recording buffer (#120) for replay / photo mode / kill-cam: records an entity's pose on game-time every frame into a `RecordingBuffe…
1716
+ - `RecordingBufferOptions` (interface): interface RecordingBufferOptions { maxDurationSeconds?: number; maxFrames?: number } — ⚠ undocumented · used by `useSessionRecorder` (@jgengine/shell/replay/useSessionRecorder): Session-recording buffer (#120) for replay / photo mode / kill-cam: records an entity's pose on game-time every frame into a `RecordingBuffe…
1717
+ - `RecordingFrame` (interface): interface RecordingFrame<T> { t: number; data: T } — ⚠ undocumented
1718
+ - `RecordingPair` (interface): interface RecordingPair<T> { before: RecordingFrame<T> | null; after: RecordingFrame<T> | null } — ⚠ undocumented
1333
1719
 
1334
1720
  ## @jgengine/core/sensor/replayLoop
1335
1721
 
1336
- - `RecordedPoseLike` (interface): interface RecordedPoseLike — ⚠ undocumented
1337
- - `ReplayEntityDeps` (interface): interface ReplayEntityDeps — ⚠ undocumented
1722
+ - `RecordedPoseLike` (interface): interface RecordedPoseLike { position: readonly [number, number, number]; rotationY?: number } — ⚠ undocumented
1723
+ - `ReplayEntityDeps` (interface): interface ReplayEntityDeps { has(id: string): boolean; spawn(id: string): void; setPose(id: string, pose: {position: readonly [number, number, number]; rotationY?: number; dt?: number}): unknown; despawn(id: string): unknown } — ⚠ undocumented
1338
1724
  - `ReplayLoop` (interface): interface ReplayLoop<T> — Replays a finished `RecordingBuffer` on a loop — modulo-time seek, frame interpolation, and spawn grace, the pieces every ghost-lap/echo feature hand-rolled (#286.4). `sample(t)` is a pure function of absolute time; `null` means "the ghost isn't on track right now".
1339
- - `ReplayLoopOptions` (interface): interface ReplayLoopOptions<T> — ⚠ undocumented
1725
+ - `ReplayLoopOptions` (interface): interface ReplayLoopOptions<T> { interpolate?: (before: T, after: T, alpha: number) => T; spawnGraceSeconds?: number } — ⚠ undocumented
1340
1726
 
1341
1727
  ## @jgengine/core/sensor/revealQuery
1342
1728
 
1343
- - `RevealHit` (interface): interface RevealHit — ⚠ undocumented
1344
- - `RevealQuery` (interface): interface RevealQuery — ⚠ undocumented
1345
- - `RevealQueryOptions` (interface): interface RevealQueryOptions — ⚠ undocumented
1729
+ - `RevealHit` (interface): interface RevealHit { instanceId: string; distance: number; tags: readonly string[] } — ⚠ undocumented · used by `useRevealHits` (@jgengine/shell/vision/RevealVision): Occlusion-ignoring tagged-entity radius query (#115), bound to the live scene.
1730
+ - `RevealQuery` (interface): interface RevealQuery { inRadius(center: EntityPosition | string, radius: number, tags: readonly string[]): RevealHit[] } — ⚠ undocumented
1731
+ - `RevealQueryOptions` (interface): interface RevealQueryOptions { resolvePosition: (instanceId: string) => EntityPosition | undefined; resolveTags: (instanceId: string) => readonly string[]; candidates: () => string[] } — ⚠ undocumented
1346
1732
 
1347
1733
  ## @jgengine/core/sensor/visionCone
1348
1734
 
1349
1735
  - `VisionCone` (interface): interface VisionCone — The guard-sight primitive every stealth game hand-rolled: an angle+range cone on the XZ plane whose sight lines are blocked by 2D wall segments (`world/walls` segments fit structurally). Pure math — feed entity positions and heading each tick.
1350
- - `VisionConeConfig` (interface): interface VisionConeConfig — ⚠ undocumented
1736
+ - `VisionConeConfig` (interface): interface VisionConeConfig { range: number; angle: number } — ⚠ undocumented
1351
1737
  - `VisionPoint` (type): type VisionPoint = readonly [number, number] — ⚠ undocumented
1352
- - `VisionTarget` (interface): interface VisionTarget<TId extends string = string> — ⚠ undocumented
1738
+ - `VisionTarget` (interface): interface VisionTarget<TId extends string = string> { id: TId; at: VisionPoint } — ⚠ undocumented
1353
1739
  - `VisionWall` (interface): interface VisionWall — Structurally matches `world/walls` `WallSegment` — pass those straight in as occluders.
1354
1740
 
1741
+ ## @jgengine/core/time/accrueSince
1742
+
1743
+ - `Accrual` (interface): interface Accrual — Elapsed duration and the next anchor to persist with accrued effects.
1744
+ - `accrueSince` (function): function accrueSince(anchorMs: number, nowMs: number, options: { capMs?: number } = {}): Accrual — Elapsed time since a persisted anchor, capped once; persist anchorMs with the accrued result.
1745
+
1355
1746
  ## @jgengine/core/time/beatClock
1356
1747
 
1357
- - `BeatAccuracyTier` (interface): interface BeatAccuracyTier — ⚠ undocumented
1358
- - `BeatClock` (interface): interface BeatClock — ⚠ undocumented
1359
- - `BeatClockConfig` (interface): interface BeatClockConfig — ⚠ undocumented
1360
- - `BeatInputBuffer` (interface): interface BeatInputBuffer<T> — ⚠ undocumented
1361
- - `BeatJudgement` (interface): interface BeatJudgement — ⚠ undocumented
1362
- - `BeatSnapshot` (interface): interface BeatSnapshot — ⚠ undocumented
1363
- - `BufferedAction` (interface): interface BufferedAction<T> — ⚠ undocumented
1748
+ - `BeatAccuracyTier` (interface): interface BeatAccuracyTier { id: string; windowSec: number } — ⚠ undocumented
1749
+ - `BeatClock` (interface): interface BeatClock { advance(gameDt: number): BeatSnapshot; snapshot(): BeatSnapshot; now(): number; beatDurationSec(): number; bpm(): number } — ⚠ undocumented
1750
+ - `BeatClockConfig` (interface): interface BeatClockConfig { bpm: number; beatsPerBar?: number } — ⚠ undocumented
1751
+ - `BeatInputBuffer` (interface): interface BeatInputBuffer<T> { buffer(action: T, nowSec: number): number; advance(nowSec: number): T[]; pendingCount(): number; clear(): void } — ⚠ undocumented
1752
+ - `BeatJudgement` (interface): interface BeatJudgement { tier: string; deltaSec: number } — ⚠ undocumented
1753
+ - `BeatSnapshot` (interface): interface BeatSnapshot { beat: number; beatIndex: number; bar: number; beatInBar: number; phase: number } — ⚠ undocumented
1754
+ - `BufferedAction` (interface): interface BufferedAction<T> { action: T; bufferedAtSec: number; fireAtSec: number } — ⚠ undocumented
1364
1755
  - `DEFAULT_BEAT_TIERS` (const): const DEFAULT_BEAT_TIERS: readonly BeatAccuracyTier[] — ⚠ undocumented
1365
1756
 
1366
1757
  ## @jgengine/core/time/calendarClock
1367
1758
 
1368
- - `GameTime` (interface): interface GameTime — ⚠ undocumented
1759
+ - `GameTime` (interface): interface GameTime { year: number; month: number; monthName: string; monthNameFull: string; dayOfMonth: number; hour: number; minute: number; second: number; formattedDate: string; formattedDateFull: string; formattedTime: string; formatted: string } — ⚠ undocumented
1369
1760
 
1370
1761
  ## @jgengine/core/time/dayNightCycle
1371
1762
 
@@ -1387,37 +1778,45 @@
1387
1778
 
1388
1779
  ## @jgengine/core/time/idleProgress
1389
1780
 
1390
- - `ExponentialCatchUpInput` (interface): interface ExponentialCatchUpInput — ⚠ undocumented
1391
- - `IdleWindow` (interface): interface IdleWindow — ⚠ undocumented
1392
- - `IdleWindowConfig` (interface): interface IdleWindowConfig — ⚠ undocumented
1393
- - `LinearCatchUpInput` (interface): interface LinearCatchUpInput — ⚠ undocumented
1394
- - `SteppedCatchUpResult` (interface): interface SteppedCatchUpResult — ⚠ undocumented
1781
+ - `ExponentialCatchUpInput` (interface): interface ExponentialCatchUpInput { current: number; factorPerSecond: number; min?: number; max?: number } — ⚠ undocumented
1782
+ - `IdleWindow` (interface): interface IdleWindow { elapsedSeconds: number; effectiveSeconds: number; capped: boolean } — ⚠ undocumented
1783
+ - `IdleWindowConfig` (interface): interface IdleWindowConfig { maxSeconds?: number; efficiency?: number } — ⚠ undocumented
1784
+ - `LinearCatchUpInput` (interface): interface LinearCatchUpInput { current: number; ratePerSecond: number; min?: number; max?: number } — ⚠ undocumented
1785
+ - `SteppedCatchUpResult` (interface): interface SteppedCatchUpResult { steps: number; remainderSeconds: number } — ⚠ undocumented
1786
+
1787
+ ## @jgengine/core/time/rateWindow
1788
+
1789
+ - `RateWindowDecision` (interface): interface RateWindowDecision — Admission result, next stored timestamps, and wait before retrying.
1790
+ - `RateWindowPolicy` (interface): interface RateWindowPolicy — Maximum accepted operations in a sliding duration.
1791
+ - `decideRateWindow` (function): function decideRateWindow(timestamps: readonly number[], nowMs: number, policy: RateWindowPolicy): RateWindowDecision — A sliding rate window; persist timestamps only alongside the accepted operation.
1395
1792
 
1396
1793
  ## @jgengine/core/time/serverTick
1397
1794
 
1398
- - `PlanServerTickOptions` (type): type PlanServerTickOptions = { /** Cap catch-up runs per system per heartbeat to avoid spiral-of-death. Default 3. */ maxCatchUp?: number; } — ⚠ undocumented
1399
- - `ServerTickPlan` (interface): interface ServerTickPlan<TSystemId extends string = string> — ⚠ undocumented
1795
+ - `PlanServerTickOptions` (type): type PlanServerTickOptions = { /** Cap catch-up runs per system per heartbeat to avoid spiral-of-death. Default 3. */ maxCatchUp?: number; } — ⚠ undocumented · used by `planServerTick`: Decides which systems a heartbeat should run.
1796
+ - `ServerTickPlan` (interface): interface ServerTickPlan<TSystemId extends string = string> { due: TickSystemRun<TSystemId>[]; anchors: TickAnchors } — ⚠ undocumented · used by `planServerTick`: Decides which systems a heartbeat should run.
1400
1797
  - `TickAnchors` (type): type TickAnchors = Record<string, number> — Last-run timestamp per system id.
1401
- - `TickSystemDefinition` (interface): interface TickSystemDefinition<TSystemId extends string = string> — ⚠ undocumented
1402
- - `planServerTick` (function): function planServerTick<TSystemId extends string>(systems: readonly TickSystemDefinition<TSystemId>[], anchors: TickAnchors, now: number, options?: PlanServerTickOptions): ServerTickPlan<TSystemId> — Decides which systems a heartbeat should run. A system with no anchor runs immediately. When wall time stalls past multiple intervals, the system id is repeated (bounded by maxCatchUp). Excess lag past the bound resyncs the anchor to `now`. Returned anchors carry only systems present in the pipeline, so removed systems clean up.
1798
+ - `TickSystemDefinition` (interface): interface TickSystemDefinition<TSystemId extends string = string> { id: TSystemId; intervalMs: number; scope?: "onlinePlayers" | "allServers"; batchSize?: number } — ⚠ undocumented · used by `planServerTick`: Decides which systems a heartbeat should run.
1799
+ - `TickSystemRun` (interface): interface TickSystemRun<TSystemId extends string = string> — One due system and how many times this heartbeat owes it.
1800
+ - `planServerTick` (function): function planServerTick<TSystemId extends string>(systems: readonly TickSystemDefinition<TSystemId>[], anchors: TickAnchors, now: number, options?: PlanServerTickOptions): ServerTickPlan<TSystemId> — Decides which systems a heartbeat should run. A system with no anchor runs immediately. When wall time stalls past multiple intervals the system's `runs` climbs (bounded by maxCatchUp), and the returned anchor moves by that many intervals — so a host that ignores `runs` loses the catch-up work. Excess lag past the bound resyncs the anchor to `now`. Returned anchors carry only systems present in the pipeline, so removed systems clean up.
1801
+ - `tickRunCount` (function): function tickRunCount<TSystemId extends string>(plan: ServerTickPlan<TSystemId>, id: TSystemId): number — Times this plan owes `id`, or 0 when it is not due. Saves a host a lookup over {@link ServerTickPlan.due}.
1403
1802
 
1404
1803
  ## @jgengine/core/time/simClock
1405
1804
 
1406
- - `CalendarTime` (interface): interface CalendarTime — ⚠ undocumented
1407
- - `ClockSnapshot` (interface): interface ClockSnapshot — ⚠ undocumented
1408
- - `SimClock` (interface): interface SimClock — ⚠ undocumented
1409
- - `SimClockOptions` (interface): interface SimClockOptions — ⚠ undocumented
1410
- - `TimeConfig` (interface): interface TimeConfig — ⚠ undocumented
1805
+ - `CalendarTime` (interface): interface CalendarTime { totalSeconds: number; day: number; hour: number; minute: number; second: number; dayFraction: number; year: number; dayOfYear: number; yearFraction: number; season?: string } — ⚠ undocumented
1806
+ - `ClockSnapshot` (interface): interface ClockSnapshot { now: number; paused: boolean; speed: number; playSpeed: number; timescale: number; scale: number; speeds: readonly number[]; calendar: CalendarTime } — ⚠ undocumented
1807
+ - `SimClock` (interface): interface SimClock { advance(realDt: number): number; now(): number; snapshot(): ClockSnapshot; hydrate(snapshot: ClockSnapshot): void; calendar(): CalendarTime; isPaused(): boolean; speed(): number; pause(): void; play(): void; toggle(): void; setSpeed(multi… — ⚠ undocumented
1808
+ - `SimClockOptions` (interface): interface SimClockOptions { config?: TimeConfig; onChange?: () => void } — ⚠ undocumented
1809
+ - `TimeConfig` (interface): interface TimeConfig { scale?: number; speeds?: readonly number[]; dayLength?: number; start?: number; startPaused?: boolean; daysPerYear?: number; seasons?: readonly string[] } — ⚠ undocumented
1411
1810
  - `createSimClock` (function): function createSimClock(options: SimClockOptions = {}): SimClock — ⚠ undocumented
1412
1811
 
1413
1812
  ## @jgengine/core/time/stateSchedule
1414
1813
 
1415
- - `ClearWindowScan` (interface): interface ClearWindowScan — ⚠ undocumented
1416
- - `SchedulePhase` (interface): interface SchedulePhase<T> — ⚠ undocumented
1417
- - `ScheduleSample` (interface): interface ScheduleSample<T> — ⚠ undocumented
1418
- - `ScheduleWindow` (interface): interface ScheduleWindow — ⚠ undocumented
1814
+ - `ClearWindowScan` (interface): interface ClearWindowScan { fromSeconds: number; horizonSeconds: number; stepSeconds: number; minDurationSeconds?: number } — ⚠ undocumented · used by `nextClearWindow`: Forward-scan any predicate-of-time — a timetable mover's "is the crossing clear at `t`" — for the next open window.
1815
+ - `SchedulePhase` (interface): interface SchedulePhase<T> { state: T; durationSeconds: number } — ⚠ undocumented
1816
+ - `ScheduleSample` (interface): interface ScheduleSample<T> { state: T; index: number; elapsedSeconds: number; remainingSeconds: number; fraction: number } — ⚠ undocumented
1817
+ - `ScheduleWindow` (interface): interface ScheduleWindow { start: number; end: number } — ⚠ undocumented · used by `nextClearWindow`: Forward-scan any predicate-of-time — a timetable mover's "is the crossing clear at `t`" — for the next open window.
1419
1818
  - `StateSchedule` (interface): interface StateSchedule<T> — A deterministic timeline of states — position-in-schedule is a pure function of absolute time, so a forecast preview and the live state can never disagree. One primitive behind zoned weather shifts, hazard cycles, and timetabled machinery: `stateAt`/`sampleAt` for the live state, `nextTransitionAt` for countdowns, `windowsOf`/`nextWindow` for "when is it safe" forecasts.
1420
- - `StateScheduleConfig` (interface): interface StateScheduleConfig<T> — ⚠ undocumented
1819
+ - `StateScheduleConfig` (interface): interface StateScheduleConfig<T> { phases: readonly SchedulePhase<T>[]; loop?: boolean; offsetSeconds?: number } — ⚠ undocumented
1421
1820
  - `createStateSchedule` (function): function createStateSchedule<T>(config: StateScheduleConfig<T>): StateSchedule<T> — ⚠ undocumented
1422
1821
  - `nextClearWindow` (function): function nextClearWindow(isClear: (t: number) => boolean, scan: ClearWindowScan): ScheduleWindow | null — Forward-scan any predicate-of-time — a timetable mover's "is the crossing clear at `t`" — for the next open window. Sampling-based: pick `stepSeconds` at or below half the shortest gap that matters.
1423
1822
 
@@ -1450,6 +1849,27 @@
1450
1849
  - `HitInput` (interface): interface HitInput — A single incoming hit to register on a {@link DamageDirectionTracker}. The angle is relative to the player's facing (renderer-agnostic): `0` points at the front/top of the reticle and increases clockwise, so a game passes the bearing from the player toward the attacker without knowing anything about the screen.
1451
1850
  - `createDamageDirectionTracker` (function): function createDamageDirectionTracker(options: DamageDirectionOptions = {}): DamageDirectionTracker — Create a damage-direction tracker: the classic "hit-from" feedback brain. A game calls `registerHit({ angle, intensity, kind })` with the bearing from the player toward the attacker (radians, `0` = front) and the tracker owns the fade timers and eased strength so the renderer just draws an arc per `active()` entry. It is renderer-free and genre-agnostic (the `kind` tag is never interpreted here), allocation-aware (a fixed pool, no per-frame garbage), and fully serializable via `snapshot`/`restore`. Optional angle merging collapses a burst from one direction into a single strong arc.
1452
1851
 
1852
+ ## @jgengine/core/vfx/feedbackMixer
1853
+
1854
+ - `FeedbackCurve` (type): type FeedbackCurve = readonly (readonly [number, number])[] — Piecewise-linear map from a signal value to an output value; points in ascending input order, ends clamp.
1855
+ - `FeedbackEvent` (interface): interface FeedbackEvent<TSignal extends string> — A one-shot fired when a signal crosses a threshold (landing thud, gear-change clunk, impact rumble).
1856
+ - `FeedbackMixer` (interface): interface FeedbackMixer<TSignal extends string, TTarget extends string> — Maps sim telemetry to presentation parameters through declared routes, curves and smoothing.
1857
+ - `FeedbackMixerConfig` (interface): interface FeedbackMixerConfig<TSignal extends string, TTarget extends string> — Config for {@link createFeedbackMixer}.
1858
+ - `FeedbackMixerState` (interface): interface FeedbackMixerState — Serializable mixer state: smoothed route values, last signal per event, and event cooldowns.
1859
+ - `FeedbackRoute` (interface): interface FeedbackRoute<TSignal extends string, TTarget extends string> — One wire from a sim signal to a named output.
1860
+ - `createFeedbackMixer` (function): function createFeedbackMixer<TSignal extends string, TTarget extends string>(initial: FeedbackMixerConfig<TSignal, TTarget>): FeedbackMixer<TSignal, TTarget> — Creates a {@link FeedbackMixer}: the one place a game declares how sim telemetry drives presentation — rpm to engine pitch, tire saturation to squeal and rumble, speed to FOV, landing speed to a thud — instead of hand-writing that glue per vehicle, aircraft or weapon. Deterministic, allocation-free per update.
1861
+ - `sampleFeedbackCurve` (function): function sampleFeedbackCurve(curve: FeedbackCurve | undefined, x: number): number — Sample a {@link FeedbackCurve}; an empty curve is the identity.
1862
+
1863
+ ## @jgengine/core/vfx/particleDirector
1864
+
1865
+ - `ParticleAttachOptions` (interface): interface ParticleAttachOptions — Options for {@link ParticleDirector.attach}.
1866
+ - `ParticleBlendHint` (type): type ParticleBlendHint = "additive" | "normal" — How a particle effect composites on screen: `additive` for sparks/fire/glow, `normal` for smoke/dust.
1867
+ - `ParticleBurst` (interface): interface ParticleBurst — A one-shot burst request — consumed once by the renderer, never serialized.
1868
+ - `ParticleDirector` (interface): interface ParticleDirector — The game-side seam for particle effects. Game logic requests one-shot bursts and standing emitters as plain data; the shell renders them through `createParticleSystem`/`ParticleField`, applies the graphics-quality particle cap, and tracks `follow` entities. Nothing here touches a renderer, so commands and `onTick` systems can drive VFX headlessly and tests can assert the requested effects.
1869
+ - `ParticleDirectorState` (interface): interface ParticleDirectorState — Serializable director state: the standing emitters (bursts are transient by nature).
1870
+ - `ParticleEmitterSpec` (interface): interface ParticleEmitterSpec — A keyed continuous emitter owned by the director until detached.
1871
+ - `createParticleDirector` (function): function createParticleDirector(): ParticleDirector — Create the particle intent registry a `GameContext` exposes as `ctx.particles`. State is data-only and serializable: standing emitters survive `snapshot`/`restore`, queued bursts are transient. The renderer subscribes, drains bursts, and mirrors the emitter list — the director never allocates particle pools itself.
1872
+
1453
1873
  ## @jgengine/core/vfx/particles
1454
1874
 
1455
1875
  - `Curve` (interface): interface Curve — A per-life start→end curve (linear interpolation from birth to death).
@@ -1475,13 +1895,13 @@
1475
1895
 
1476
1896
  ## @jgengine/core/visibility/assetStreaming
1477
1897
 
1478
- - `AssetLoadResult` (interface): interface AssetLoadResult — ⚠ undocumented
1898
+ - `AssetLoadResult` (interface): interface AssetLoadResult { readonly bytes?: number; readonly value?: unknown } — ⚠ undocumented
1479
1899
  - `AssetLoadState` (type): type AssetLoadState = "queued" | "loading" | "loaded" | "unloaded" | "error" — ⚠ undocumented
1480
- - `AssetRecord` (interface): interface AssetRecord — ⚠ undocumented
1481
- - `AssetStreamingOptions` (interface): interface AssetStreamingOptions — ⚠ undocumented
1482
- - `AssetStreamingSystem` (interface): interface AssetStreamingSystem — ⚠ undocumented
1483
- - `CancelSignal` (interface): interface CancelSignal — ⚠ undocumented
1484
- - `StreamingStats` (interface): interface StreamingStats — ⚠ undocumented
1900
+ - `AssetRecord` (interface): interface AssetRecord { readonly id: string; state: AssetLoadState; bytes: number; priority: number; refCount: number; pinned: boolean; lastActiveMs: number; value: unknown } — ⚠ undocumented
1901
+ - `AssetStreamingOptions` (interface): interface AssetStreamingOptions { readonly load: (assetId: string, signal: CancelSignal) => Promise<AssetLoadResult>; readonly unload?: (assetId: string) => void; readonly settings?: Partial<StreamingSettings>; readonly now?: () => number } — ⚠ undocumented
1902
+ - `AssetStreamingSystem` (interface): interface AssetStreamingSystem { request(assetId: string, priority?: number): void; retain(assetId: string): void; release(assetId: string): void; pin(assetId: string): void; unpin(assetId: string): void; markActive(assetId: string): void; tick(dt: number): void; cancel(… — ⚠ undocumented
1903
+ - `CancelSignal` (interface): interface CancelSignal { readonly cancelled: boolean } — ⚠ undocumented
1904
+ - `StreamingStats` (interface): interface StreamingStats { queued: number; loading: number; loaded: number; unloaded: number; errored: number; inFlight: number; cancelled: number; bytes: number } — ⚠ undocumented
1485
1905
  - `createAssetStreamingSystem` (function): function createAssetStreamingSystem(options: AssetStreamingOptions): AssetStreamingSystem — ⚠ undocumented
1486
1906
 
1487
1907
  ## @jgengine/core/visibility/bounds
@@ -1490,7 +1910,7 @@
1490
1910
  - `BoundsSpec` (type): type BoundsSpec = | { readonly kind: "sphere"; readonly radius: number; readonly offset?: Vec3 } | { readonly kind: "aabb"; readonly half: Vec3; readonly offset?: Vec3 } | { readonly kind: "rect"; readonly halfWidth: number; readonly halfDepth: number; readonly halfHeight?: number; readonly offset?:… — How a renderable declares its extent. AABB, bounding sphere, and 2D rectangle cover the common cases; `point` is the degenerate zero-size default for objects that never override. `offset` shifts the volume from the object origin (e.g. a tall model whose pivot is at its feet).
1491
1911
  - `DEFAULT_BOUNDS` (const): const DEFAULT_BOUNDS: BoundsSpec — Conservative default: a unit sphere. Objects without explicit bounds cull as a small volume, never a point.
1492
1912
  - `RenderBounds` (interface): interface RenderBounds — World-space bounds a culler tests against. Kept as flat scalars (not tuples) so the hot culling path reads them without allocating. Carries both a bounding sphere (cheap broad reject) and a tight AABB (precise reject) — the standard "engine bounds" the frustum, distance, and spatial-index tests all consume.
1493
- - `Vec3` (type): type Vec3 = EntityPosition — ⚠ undocumented
1913
+ - `Vec3` (type): type Vec3 = EntityPosition — ⚠ undocumented · used by `coverPoints` (@jgengine/core/ai/tacticalQueries): Returns boundary locations that are hidden from a threat.
1494
1914
 
1495
1915
  ## @jgengine/core/visibility/camera
1496
1916
 
@@ -1518,14 +1938,14 @@
1518
1938
  ## @jgengine/core/visibility/frustum
1519
1939
 
1520
1940
  - `CameraView` (type): type CameraView = PerspectiveView | OrthographicView — ⚠ undocumented
1521
- - `Frustum` (interface): interface Frustum — ⚠ undocumented
1941
+ - `Frustum` (interface): interface Frustum { readonly planes: Float64Array; readonly corners: Float64Array; minX: number; minY: number; minZ: number; maxX: number; maxY: number; maxZ: number } — ⚠ undocumented
1522
1942
  - `OrthographicView` (interface): interface OrthographicView — 2D / orthographic camera (top-down, side-scroller, minimap).
1523
1943
  - `PerspectiveView` (interface): interface PerspectiveView — 3D perspective camera (the default game camera).
1524
1944
 
1525
1945
  ## @jgengine/core/visibility/occlusion
1526
1946
 
1527
- - `AxisOccluderOptions` (interface): interface AxisOccluderOptions — ⚠ undocumented
1528
- - `OcclusionInput` (interface): interface OcclusionInput — ⚠ undocumented
1947
+ - `AxisOccluderOptions` (interface): interface AxisOccluderOptions { enabled?: boolean; minOccluderRadius?: number } — ⚠ undocumented · used by `createAxisAlignedOcclusionTester`: A deliberately conservative bounding-volume occlusion tester.
1948
+ - `OcclusionInput` (interface): interface OcclusionInput { readonly camera: CameraView; readonly bounds: RenderBounds; readonly occluders: Iterable<RenderBounds> } — ⚠ undocumented
1529
1949
  - `OcclusionTester` (interface): interface OcclusionTester — Optional occlusion stage. Kept behind a feature flag and disabled by default: a fragile occlusion test that wrongly hides a visible object is worse than no occlusion at all. Any tester here MUST be conservative — it may return false (visible) for a truly hidden object, but must never return true (hidden) for an object the player can actually see.
1530
1950
  - `createAxisAlignedOcclusionTester` (function): function createAxisAlignedOcclusionTester(options: AxisOccluderOptions = {}): OcclusionTester — A deliberately conservative bounding-volume occlusion tester. It hides an object only when a single large occluder's AABB fully contains the object's AABB on every axis AND sits strictly nearer the camera on the dominant view axis — the object is then provably in the occluder's shadow. Full containment (not just the two perpendicular axes) makes it stricter than it needs to be, which is the safe direction: it never hides a partially-visible object.
1531
1951
  - `noOcclusion` (const): const noOcclusion: OcclusionTester — The safe default: never occludes anything.
@@ -1536,44 +1956,48 @@
1536
1956
  - `DEFAULT_CULLING_SETTINGS` (const): const DEFAULT_CULLING_SETTINGS: CullingSettings — ⚠ undocumented
1537
1957
  - `DEFAULT_STREAMING_SETTINGS` (const): const DEFAULT_STREAMING_SETTINGS: StreamingSettings — ⚠ undocumented
1538
1958
  - `ObjectVisibilityOverrides` (interface): interface ObjectVisibilityOverrides — Per-object visibility/streaming overrides. Also the shape used at the layer, scene, and global-override levels — resolution merges object → layer → scene → global-override, so a game can, say, mark a whole "hud" layer alwaysVisible without touching each object.
1539
- - `ResolvedOverrides` (interface): interface ResolvedOverrides — ⚠ undocumented
1540
- - `StreamingSettings` (interface): interface StreamingSettings — ⚠ undocumented
1959
+ - `ResolvedOverrides` (interface): interface ResolvedOverrides { alwaysVisible: boolean; neverUnload: boolean; minRenderDistance: number | undefined; maxRenderDistance: number | undefined; preloadMargin: number | undefined; cullingDisabled: boolean; streamingDisabled: boolean; classification: "static" … — ⚠ undocumented · used by `resolveOverrides`: Merge override layers by precedence: earlier arguments win.
1960
+ - `StreamingSettings` (interface): interface StreamingSettings { readonly enabled: boolean; readonly preloadMargin: number; readonly unloadGraceSeconds: number; readonly maxLoadsPerFrame: number; readonly maxUnloadsPerFrame: number; readonly keepResidentBytes: number } — ⚠ undocumented
1541
1961
  - `mergeCullingSettings` (function): function mergeCullingSettings(base: CullingSettings, patch: Partial<CullingSettings>): CullingSettings — ⚠ undocumented
1542
1962
  - `mergeStreamingSettings` (function): function mergeStreamingSettings(base: StreamingSettings, patch: Partial<StreamingSettings>): StreamingSettings — ⚠ undocumented
1543
1963
  - `resolveOverrides` (function): function resolveOverrides(...layers: readonly (ObjectVisibilityOverrides | undefined)[]): ResolvedOverrides — Merge override layers by precedence: earlier arguments win. Pass object, then layer, then scene, then global.
1544
1964
 
1545
1965
  ## @jgengine/core/visibility/simulationCulling
1546
1966
 
1547
- - `SimulationCuller` (interface): interface SimulationCuller — ⚠ undocumented
1967
+ - `SimulationCuller` (interface): interface SimulationCuller { enabled(): boolean; setEnabled(value: boolean): void; step(id: string, distance: number, dt: number): SimulationDecision; forget(id: string): void; clear(): void; snapshot(): SimulationCullerState; restore(next: SimulationCullerState): vo… — ⚠ undocumented
1968
+ - `SimulationCullerState` (interface): interface SimulationCullerState — Plain JSON state of a {@link SimulationCuller}: the enabled flag and each id's throttle accumulator.
1548
1969
  - `SimulationCullingOptions` (interface): interface SimulationCullingOptions — Simulation culling is a SEPARATE, opt-in system from render culling. Render culling only decides what is drawn; this decides whether a low-priority off-screen entity updates this tick. It is disabled by default and never throttles a protected entity — physics-critical, networking-critical, audio-critical, scripted, or explicitly-active entities always update. Gameplay correctness must never depend on an entity being on-screen, so opt in only where skipping updates is provably safe.
1549
- - `SimulationDecision` (interface): interface SimulationDecision — ⚠ undocumented
1970
+ - `SimulationDecision` (interface): interface SimulationDecision { update: boolean; elapsed: number } — ⚠ undocumented
1550
1971
  - `createSimulationCuller` (function): function createSimulationCuller(options: SimulationCullingOptions = {}): SimulationCuller — ⚠ undocumented
1551
1972
 
1552
1973
  ## @jgengine/core/visibility/spatialIndex
1553
1974
 
1975
+ - `SpatialCellRange` (interface): interface SpatialCellRange — Integer cell bounds an object covers, inclusive on both ends.
1554
1976
  - `SpatialIndex` (interface): interface SpatialIndex — A uniform 3D spatial hash the renderer and streaming system query for potentially-visible objects instead of scanning the whole scene. Objects are keyed by their world AABB into every overlapping cell; a moving object only rewrites the cells that actually changed. Static objects are inserted once and never touched again. Oversized objects (huge terrain chunks, world bounds) are held separately so they are always considered.
1555
- - `SpatialIndexOptions` (interface): interface SpatialIndexOptions — ⚠ undocumented
1977
+ - `SpatialIndexOptions` (interface): interface SpatialIndexOptions { readonly cellSize?: number; readonly maxCellSpan?: number } — ⚠ undocumented
1978
+ - `SpatialIndexState` (interface): interface SpatialIndexState — Plain JSON state of a {@link SpatialIndex}. Cells and their ids keep insertion order, so a restored index returns query results in the same order.
1556
1979
  - `createSpatialIndex` (function): function createSpatialIndex(options: SpatialIndexOptions = {}): SpatialIndex — ⚠ undocumented
1557
1980
 
1558
1981
  ## @jgengine/core/visibility/visibilitySystem
1559
1982
 
1560
1983
  - `Renderable` (interface): interface Renderable — A scene object the visibility system considers. A normal game object already carries a position and a version counter, so it becomes cullable automatically — no separate "cullable" component. Everything else is optional override.
1561
- - `VisibilityDebugSnapshot` (interface): interface VisibilityDebugSnapshot — ⚠ undocumented
1562
- - `VisibilityResult` (interface): interface VisibilityResult — ⚠ undocumented
1563
- - `VisibilitySystem` (interface): interface VisibilitySystem — ⚠ undocumented
1564
- - `VisibilitySystemOptions` (interface): interface VisibilitySystemOptions — ⚠ undocumented
1984
+ - `VisibilityDebugSnapshot` (interface): interface VisibilityDebugSnapshot { cameras: {id: string; kind: CameraKind; corners: number[]; preloadMargin: number}[]; bounds: {id: string; minX: number; minY: number; minZ: number; maxX: number; maxY: number; maxZ: number; visible: boolean}[]; partitions: {key: string; c… — ⚠ undocumented
1985
+ - `VisibilityResult` (interface): interface VisibilityResult { readonly visible: ReadonlySet<string>; readonly preload: ReadonlySet<string>; readonly stats: VisibilityStats } — ⚠ undocumented
1986
+ - `VisibilitySystem` (interface): interface VisibilitySystem { update(): VisibilityResult; isVisible(id: string): boolean; isPreloaded(id: string): boolean; boundsOf(id: string): RenderBounds | undefined; settings(): CullingSettings; setSettings(patch: Partial<CullingSettings>): void; stats(): Visibi… — ⚠ undocumented
1987
+ - `VisibilitySystemOptions` (interface): interface VisibilitySystemOptions { readonly renderables: () => Iterable<Renderable>; readonly cameras: () => readonly CameraVisibilityContext[]; readonly settings?: Partial<CullingSettings>; readonly sceneOverrides?: ObjectVisibilityOverrides; readonly globalOverrides?: Ob… — ⚠ undocumented
1565
1988
  - `createVisibilitySystem` (function): function createVisibilitySystem(options: VisibilitySystemOptions): VisibilitySystem — ⚠ undocumented
1566
1989
 
1567
1990
  ## @jgengine/core/world
1568
1991
 
1569
1992
  - `ANNOTATION_FEED_ACTION` (const): const ANNOTATION_FEED_ACTION: "map.annotation" — Feed action shared drawings ride by default (pair with the party feed, like pings).
1570
- - `Aabb` (interface): interface Aabb — ⚠ undocumented
1993
+ - `Aabb` (interface): interface Aabb { minX: number; minZ: number; maxX: number; maxZ: number } — ⚠ undocumented · used by `polygonBounds`: Axis-aligned bounds of a polygon, or null if it has no points.
1571
1994
  - `AcquisitionEnvelope` (type): type AcquisitionEnvelope = number | ((selfId: string, candidateId: string) => number) — Composable target acquisition: the "which enemy do I lock onto?" decision split into the independent concerns every aggro system tangles together — a bounded candidate provider, an eligibility filter, a per-pair acquisition envelope (dynamic range), a perception/LOS gate, scoring, deterministic tie-break, and retention hysteresis. This owns *policy*; threat, brains, and movement stay separate. Feed `candidates` a spatial-index query, never a full-world scan.
1572
1995
  - `AcquisitionPolicy` (interface): interface AcquisitionPolicy — A fully composed acquisition policy. Every concern is an independent, injectable seam; the only required pieces are the bounded `candidates` provider and the `distance` metric. Omit the rest to fall back to the thin default — a static/unbounded range, everything eligible and perceptible, nearest-wins scoring, id tie-break, no hysteresis — which matches a plain proximity aggro radius.
1573
1996
  - `AcquisitionResult` (interface): interface AcquisitionResult — Outcome of one acquisition pass.
1574
1997
  - `AcquisitionRetention` (interface): interface AcquisitionRetention — Retention hysteresis that keeps an already-held target from flickering under churn.
1575
1998
  - `AddBodyOptions` (type): type AddBodyOptions = BoxBodyOptions | SphereBodyOptions — ⚠ undocumented
1576
- - `Aim` (type): type Aim = | { origin: EntityPosition; direction: EntityPosition } | { yaw: number; pitch: number; spread?: number } — ⚠ undocumented
1999
+ - `Aim` (type): type Aim = | { origin: EntityPosition; direction: EntityPosition } | { yaw: number; pitch: number; spread?: number } — ⚠ undocumented · used by `aimToPoint` (@jgengine/core/input/pointer): Build an `origin → point` aim for `item.use` / projectiles, firing toward the cursor.
2000
+ - `AircraftAxis` (type): type AircraftAxis = "pitch" | "roll" | "yaw" | "throttle" | "collective" | "airbrake" | "afterburner" | "vectoring" — Axes an aircraft can bind — which actions drive each flight control.
1577
2001
  - `AircraftDynamics` (interface): interface AircraftDynamics — Stateful six-degree-of-freedom aircraft simulation.
1578
2002
  - `AircraftKind` (type): type AircraftKind = "fixedWing" | "rotorcraft" | "vtol" — Supported aerodynamic/propulsion families.
1579
2003
  - `AircraftOptions` (interface): interface AircraftOptions — Spawn state and injectable world-field samplers for an aircraft instance.
@@ -1596,25 +2020,28 @@
1596
2020
  - `AreaStackPolicy` (type): type AreaStackPolicy<P> = (memberships: readonly AreaMembership<P>[]) => AreaMembership<P>[] — Reduce one receiver's overlapping memberships to the subset that applies under a stacking rule.
1597
2021
  - `AreaStepInput` (interface): interface AreaStepInput — Per-tick inputs the field needs to reconcile membership without scanning the world.
1598
2022
  - `AssetAnchor` (type): type AssetAnchor = "center" | "corner" | { readonly x: number; readonly z: number } — Where a model's pivot sits within its footprint: `center` (origin at the footprint center), `corner` (origin at the min-X/min-Z corner), or a normalized `{ x, z }` fraction in `[-0.5, 0.5]`.
1599
- - `AssetCatalog` (interface): interface AssetCatalog<TMeta extends ModelAssetRef = ModelAssetRef> — ⚠ undocumented
2023
+ - `AssetCatalog` (interface): interface AssetCatalog<TMeta extends ModelAssetRef = ModelAssetRef> { register(id: string, asset: TMeta): void; resolve(id: string): TMeta | null; has(id: string): boolean; ids(): readonly string[] } — ⚠ undocumented · used by `buildCatalog` (@jgengine/assets): Builds a game's asset catalog from the generated CC0 pack index plus singles, extras, and aliases.
1600
2024
  - `AssetSpace` (interface): interface AssetSpace — Catalog-level asset-space metadata: how a model is authored relative to the engine, owned by the catalog entry rather than re-derived per game. Every field is optional so an unmeasured asset stays valid; {@link resolveFacingRotationY}/{@link assetUnitScale}/{@link resolveAnchorOffset} supply the documented defaults.
1601
2025
  - `AssetSpaceIssue` (interface): interface AssetSpaceIssue — One problem found by {@link validateAssetSpace}: which metadata field and why it is invalid.
1602
2026
  - `AttackMoveOrderPayload` (interface): interface AttackMoveOrderPayload — Payload for an attack-move: advance toward `point`, engaging hostiles encountered en route.
1603
- - `AudioBusDef` (interface): interface AudioBusDef — ⚠ undocumented
1604
- - `AudioFalloffConfig` (interface): interface AudioFalloffConfig — ⚠ undocumented
2027
+ - `AudioBusDef` (interface): interface AudioBusDef { id: AudioBusId; gain?: number } — ⚠ undocumented
2028
+ - `AudioFalloffConfig` (interface): interface AudioFalloffConfig { minDistance?: number; maxDistance?: number; curve?: FalloffCurve } — ⚠ undocumented
1605
2029
  - `AuthoredTrigger` (interface): interface AuthoredTrigger — One resolved trigger binding from a document object.
1606
2030
  - `AuthoredTriggerRuntime` (interface): interface AuthoredTriggerRuntime — Runtime handle that watches authored triggers against moving actors each tick.
1607
2031
  - `AutoTargetPolicy` (type): type AutoTargetPolicy = | "nearest" | "farthest" | "random" | "strongest" | "weakest" | "first" | "last" — ⚠ undocumented
1608
2032
  - `AvoidZone` (interface): interface AvoidZone — A circular clearance around a gameplay spot (spawn, plot, path point, POI): scatter is repelled from it and terrain is flattened toward its center. `feather` (meters) is the soft outer band — full effect within `radius - feather`, ramping to zero at `radius`.
1609
2033
  - `AvoidanceAgent` (interface): interface AvoidanceAgent — A circular agent that avoidance may push on the XZ plane.
1610
- - `BallisticSweep` (type): type BallisticSweep = ( origin: readonly [number, number, number], velocity: readonly [number, number, number], gravity: number, maxTime: number, ) => BallisticSweepHit | null — ⚠ undocumented
1611
- - `BallisticSweepHit` (interface): interface BallisticSweepHit — ⚠ undocumented
2034
+ - `BallisticSweep` (type): type BallisticSweep = ( origin: readonly [number, number, number], velocity: readonly [number, number, number], gravity: number, maxTime: number, ) => BallisticSweepHit | null — ⚠ undocumented · used by `createBallisticSweep`: Marches the closed-form arc (constant gravity, straight lateral) through `world` and reports the first sample inside any live body's AABB — …
2035
+ - `BallisticSweepHit` (interface): interface BallisticSweepHit { point: [number, number, number]; time: number } — ⚠ undocumented
1612
2036
  - `BandTrimOptions` (interface): interface BandTrimOptions extends JunctionGeometryOptions — Options for {@link trimBandAtJunctions} — junction geometry tunables plus a band-specific clearance.
2037
+ - `BehaviorAction` (type): type BehaviorAction = DecisionAction<BehaviorActionContext> — Callback used by a registered decision graph behavior action.
2038
+ - `BehaviorActionContext` (interface): interface BehaviorActionContext — Context supplied to a registered decision graph action.
2039
+ - `BehaviorActionOptions` (interface): interface BehaviorActionOptions — Optional hooks for a registered behavior action set.
1613
2040
  - `BehaviorControl` (interface): interface BehaviorControl — Per-entity control surface for the behavior runtime — pause/resume/disable/enable an instance, seek it to semantic progress, serialize/restore its state, and inspect it, all keyed by stable entity id without a full-world scan. Obtain it with {@link behaviorControl}.
1614
- - `BehaviorDescriptor` (type): type BehaviorDescriptor = | WanderBehavior | PatrolBehavior | PromptableBehavior | PlayerBehavior — ⚠ undocumented
2041
+ - `BehaviorDescriptor` (type): type BehaviorDescriptor = | WanderBehavior | PatrolBehavior | PromptableBehavior | PlayerBehavior | DecisionGraphBehavior — ⚠ undocumented
1615
2042
  - `BehaviorInspection` (interface): interface BehaviorInspection — Inspection readout for editor/debug tooling, from {@link BehaviorControl.inspect}/{@link BehaviorControl.list}.
1616
2043
  - `BehaviorResumePolicy` (type): type BehaviorResumePolicy = "freeze" | "advance" — Catch-up policy applied when a paused instance resumes. `freeze` (default, deterministic) discards the time spent paused; `advance` silently fast-forwards the instance by the paused duration without emitting intermediate pose writes. Only patrol honors `advance`; wander treats it as `freeze`.
1617
- - `BehaviorSnapshot` (type): type BehaviorSnapshot = | { readonly kind: "patrol"; readonly state: PathFollowState } | { readonly kind: "wander"; readonly origin: Waypoint; readonly target: Waypoint | null } — Serializable snapshot of one behavior instance — round-trips exactly through {@link BehaviorControl.serialize}/{@link BehaviorControl.restore}.
2044
+ - `BehaviorSnapshot` (type): type BehaviorSnapshot = | { readonly kind: "patrol"; readonly state: PathFollowState } | { readonly kind: "wander"; readonly origin: Waypoint; readonly target: Waypoint | null } | { readonly kind: "decisionGraph"; readonly graph: ReturnType<DecisionGraphRuntime["snapshot"]>; readonly gate: InterestG… — Serializable snapshot of one behavior instance — round-trips exactly through {@link BehaviorControl.serialize}/{@link BehaviorControl.restore}.
1618
2045
  - `BehaviorStatus` (type): type BehaviorStatus = "active" | "paused" | "disabled" — Whether a behavior instance advances and writes pose (`active`), is temporarily suspended retaining state (`paused`), or is held off until re-enabled (`disabled`).
1619
2046
  - `BiomeBand` (interface): interface BiomeBand — A z-ordered ground palette zone — the linear-boundary counterpart to the radial `materialRegions`. Adjacent bands cross-fade into each other across a `fade`-wide window centered on the midpoint z between their centers, so a multi-biome world (vale → marsh → peaks along z) blends its ground color instead of hard-switching. Bands may also carry per-zone `fog`, `sky`, and `weather`. Order the list by ascending `z`.
1620
2047
  - `BoardGround` (interface): interface BoardGround — A 2D surface you look at — grid games, solitaire, tabletop. Physics is often zero-gravity or omitted; the game owns the face it draws on the board.
@@ -1623,10 +2050,10 @@
1623
2050
  - `BoundsSpec` (type): type BoundsSpec = | { readonly kind: "sphere"; readonly radius: number; readonly offset?: Vec3 } | { readonly kind: "aabb"; readonly half: Vec3; readonly offset?: Vec3 } | { readonly kind: "rect"; readonly halfWidth: number; readonly halfDepth: number; readonly halfHeight?: number; readonly offset?:… — How a renderable declares its extent. AABB, bounding sphere, and 2D rectangle cover the common cases; `point` is the degenerate zero-size default for objects that never override. `offset` shifts the volume from the object origin (e.g. a tall model whose pivot is at its feet).
1624
2051
  - `BoxFormationOptions` (interface): interface BoxFormationOptions — Options for {@link boxFormation}.
1625
2052
  - `BuildRole` (type): type BuildRole = "owner" | "editor" | "viewer" — ⚠ undocumented
1626
- - `BuildingEnvironmentDescriptor` (type): type BuildingEnvironmentDescriptor = { kind: "building" } & Required< Pick<BuildingEnvironmentConfig, "count" | "footprint" | "stories" | "storyHeight" | "spacing" | "style"> > & Pick<BuildingEnvironmentConfig, "seed" | "position" | "palette" | "along" | "kit"> — ⚠ undocumented
1627
- - `BuildingIndex` (interface): interface BuildingIndex — ⚠ undocumented
2053
+ - `BuildingEnvironmentDescriptor` (type): type BuildingEnvironmentDescriptor = { kind: "building" } & Required< Pick<BuildingEnvironmentConfig, "count" | "footprint" | "stories" | "storyHeight" | "spacing" | "style"> > & Pick<BuildingEnvironmentConfig, "seed" | "position" | "palette" | "along" | "kit" | "solid"> — ⚠ undocumented · used by `building`: Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style.
2054
+ - `BuildingIndex` (interface): interface BuildingIndex { readonly buildings: readonly GeneratedBuilding[]; at(point: Vec2): GeneratedBuilding | undefined; within(area: Aabb): GeneratedBuilding[]; nearest(point: Vec2): BuildingHit | undefined; isInside(point: Vec2): boolean; blockers(margin?: nu… — ⚠ undocumented
1628
2055
  - `BuildingPaletteOverrides` (type): type BuildingPaletteOverrides = Partial<BuildingPalette> — ⚠ undocumented
1629
- - `BuildingStyle` (type): type BuildingStyle = | "generic" | "capital" | "village" | "desert" | "industrial" | "coastal" | "neon" | "ruin" | "frontier" | "aerial" — ⚠ undocumented
2056
+ - `BuildingStyle` (type): type BuildingStyle = | "generic" | "capital" | "village" | "desert" | "industrial" | "coastal" | "neon" | "ruin" | "frontier" | "aerial" — ⚠ undocumented · used by `BUILDING_STYLE_WALL_TONES` (@jgengine/core/world/buildings): Per-style facade-tone family: the wall colours a district spreads across its buildings so neighbours differ in hue and value while the block…
1630
2057
  - `CITY_BUILDING_BUDGET` (const): const CITY_BUILDING_BUDGET: 2600 — Max buildings a single `city` district generates — the block/parcel pipeline's bounded lot cap.
1631
2058
  - `CITY_DEFAULTS` (const): const CITY_DEFAULTS: CityRules — City defaults: a zoned mixed metropolis — towers downtown, slabs mid-ring, houses at the edge.
1632
2059
  - `CITY_FILLER_CLASSES` (const): const CITY_FILLER_CLASSES: readonly CityFillerClass[] — All filler classes, for validation and interior-pass allow-lists.
@@ -1638,6 +2065,7 @@
1638
2065
  - `CITY_TREE_SPECIES` (const): const CITY_TREE_SPECIES: readonly CityTreeSpecies[] — All species, for schema hints and validation.
1639
2066
  - `CITY_ZONE_KIND` (const): const CITY_ZONE_KIND: "cityzone" — The editor volume kind that locally overrides a city's zone band/mix — a district in a district.
1640
2067
  - `CITY_ZONE_SCHEMA` (const): const CITY_ZONE_SCHEMA: ParamSchema — Zone-override schema for `cityzone` volumes: pin a band and optionally a bespoke class mix.
2068
+ - `CREATIVE_FLIGHT_TUNING` (const): const CREATIVE_FLIGHT_TUNING: FreeFlightTuning — Preset for Minecraft-like creative flight — weightless, collides, yaw-relative strafe.
1641
2069
  - `CameraShakeConfig` (interface): interface CameraShakeConfig — Configuration for {@link createCameraShake}. Every field has a game-feel default.
1642
2070
  - `CameraShakeController` (interface): interface CameraShakeController — A live, dt-driven, trauma-based camera shake controller.
1643
2071
  - `CameraShakeOffset` (interface): interface CameraShakeOffset — A per-frame camera shake offset: three positional axes plus three rotational axes (radians).
@@ -1683,13 +2111,13 @@
1683
2111
  - `CityZoneBand` (type): type CityZoneBand = "core" | "mid" | "edge" — Zone band a lot falls in: dense core, middle ring, or the district edge.
1684
2112
  - `CityZoneMixes` (interface): interface CityZoneMixes — Weighted building-class mix per zone band; the radial profile decides which band a lot falls in.
1685
2113
  - `CityZoneProfile` (type): type CityZoneProfile = "core-out" | "inverted" | "uniform" — How the radial zone metric maps to bands.
1686
- - `ClockSnapshot` (interface): interface ClockSnapshot — ⚠ undocumented
1687
- - `CollapseEvent` (interface): interface CollapseEvent — ⚠ undocumented
2114
+ - `ClockSnapshot` (interface): interface ClockSnapshot { now: number; paused: boolean; speed: number; playSpeed: number; timescale: number; scale: number; speeds: readonly number[]; calendar: CalendarTime } — ⚠ undocumented
2115
+ - `CollapseEvent` (interface): interface CollapseEvent { fell: readonly string[]; collapsed: boolean } — ⚠ undocumented
1688
2116
  - `ColliderPurpose` (type): type ColliderPurpose = "physical" | "damage" — ⚠ undocumented
1689
2117
  - `CollisionEvent` (interface): interface CollisionEvent — A contact reported to `onCollision`. The object is reused each call — read/copy, never retain.
1690
2118
  - `CollisionObstacle` (interface): interface CollisionObstacle — A placed scene object the walking player collides against as a circle-vs-AABB obstacle.
1691
- - `ConcealmentSensor` (interface): interface ConcealmentSensor — ⚠ undocumented
1692
- - `ContextMenu` (interface): interface ContextMenu — ⚠ undocumented
2119
+ - `ConcealmentSensor` (interface): interface ConcealmentSensor { tick(targets: readonly ConcealmentTarget[], dt: number): ConcealmentSample[]; reset(id?: string): void; snapshot(): ConcealmentSensorState; restore(next: ConcealmentSensorState): void } — ⚠ undocumented
2120
+ - `ContextMenu` (interface): interface ContextMenu { kind: ContextTargetKind; targetId: string; point?: readonly [number, number, number]; verbs: readonly ContextVerb[] } — ⚠ undocumented · used by `buildContextMenu`: Assemble a menu from a target's catalog verbs; null when the target lists none.
1693
2121
  - `ContextVerb` (interface): interface ContextVerb — One right-click verb: a label plus the command it dispatches (walk-then-act supported by args).
1694
2122
  - `ContourLine` (interface): interface ContourLine — A single iso-elevation contour traced across a region as a flat list of XZ line segments.
1695
2123
  - `ContourOptions` (interface): interface ContourOptions — Shaping for {@link extractContours}: region, vertical spacing, emphasis cadence, and sample budget.
@@ -1716,43 +2144,51 @@
1716
2144
  - `DayNightKeyframe` (interface): interface DayNightKeyframe — Turnkey day-night cycle: one serializable brain that advances a normalized day fraction on an injected clock and blends per-keyframe phase labels and tint/light colors. A game wires this one model and drives an existing sky/daylight seam from `sample()` instead of hand-rolling a clock plus a color lerp.
1717
2145
  - `DayNightSample` (interface): interface DayNightSample — The interpolated day-night look at a moment: day fraction, active phase, and blended colors.
1718
2146
  - `DayNightSnapshot` (interface): interface DayNightSnapshot — Serializable day-night position — accumulated clock offset, pause state, and speed — for save/load.
2147
+ - `DecisionGraphBehavior` (interface): interface DecisionGraphBehavior — Decision graph behavior descriptor using a named registered action set.
1719
2148
  - `DrapeOptions` (interface): interface DrapeOptions — Shaping for surface draping: subdivision spacing and a lift to keep the line off the ground.
1720
- - `EditableTerrain` (interface): interface EditableTerrain extends TerrainField — ⚠ undocumented
2149
+ - `EditableTerrain` (interface): interface EditableTerrain extends TerrainField { readonly cols: number; readonly rows: number; readonly cellSize: number; apply(edit: TerraformEdit): number; applyRecording(edit: TerraformEdit, record: TerraformDeltaRecorder): number; editDelta(edit: TerraformEdit): TerraformDelta; appl… — ⚠ undocumented · used by `beginSurfaceStroke`: Opens a paint-stroke recorder over `terrain`; stamp paint edits into it, then read one net delta.
1721
2150
  - `ElevationReadout` (interface): interface ElevationReadout — Measurable elevation readout at a single world point — the cursor/hover feedback value.
1722
2151
  - `ElevationSummary` (interface): interface ElevationSummary — Aggregate elevation statistics over a region — the selection min/max/mean and legend range.
1723
2152
  - `EmittedCue` (interface): interface EmittedCue<Payload = unknown> — A cue plus the resolved firing context passed to {@link SequenceDirector.onCue} listeners.
1724
2153
  - `EmitterConfig` (interface): interface EmitterConfig — A particle emitter: how particles spawn and how each one evolves over its life. Every field is data — no functions — so an emitter is fully serializable and an editor/tunable can drive it. Genre-agnostic: smoke, sparks, rain, magic, dust.
1725
2154
  - `EmptyOrderPayload` (type): type EmptyOrderPayload = Record<string, never> — Payload for stop/hold orders — no data; the verb is the intent.
1726
- - `EnclosedFootprint` (interface): interface EnclosedFootprint — ⚠ undocumented
2155
+ - `EnclosedFootprint` (interface): interface EnclosedFootprint { polygon: readonly Vec2[]; aabb: Aabb; area: number; perimeter: number; closed: boolean } — ⚠ undocumented
1727
2156
  - `EngagementKindConfig` (interface): interface EngagementKindConfig extends OrderKindConfig — Move + engagement config carrying the default radii the payload may override.
1728
2157
  - `EngagementOrderState` (interface): interface EngagementOrderState — Live intent an attack-move/targeted order writes into `Order.state`; the game reads it to run the actual attack. Serializable.
1729
- - `EntityColliderSet` (interface): interface EntityColliderSet — ⚠ undocumented
1730
- - `EntityPosition` (type): type EntityPosition = readonly [number, number, number] — ⚠ undocumented
1731
- - `EnvironmentField` (interface): interface EnvironmentField — ⚠ undocumented
1732
- - `EnvironmentWorldFeature` (interface): interface EnvironmentWorldFeature — ⚠ undocumented
1733
- - `FactionDef` (interface): interface FactionDef — ⚠ undocumented
2158
+ - `EntityColliderSet` (interface): interface EntityColliderSet { body?: ColliderDef; hitboxes?: readonly ColliderDef[] } — ⚠ undocumented · used by `eyeHeightFromColliders` (@jgengine/core/combat): Eye height derived from a collider set: 90% of the tallest hitbox top, or the humanoid default when unknown.
2159
+ - `EntityPosition` (type): type EntityPosition = readonly [number, number, number] — ⚠ undocumented · used by `resolveSourceWalkerStep` (@jgengine/core/movement/solidObstacles): {@link resolveWalkerStep} with no `GameContext`: gather plus slide against a bare {@link SolidObstacleSource} and a caller-owned {@link Obst…
2160
+ - `EnvironmentField` (interface): interface EnvironmentField { sample(x: number, z: number, time: number, y?: number): EnvironmentSample; temperature(x: number, z: number, time: number, y?: number): number; wetness(x: number, z: number, time: number): number; lightExposure(x: number, z: number, time:… — ⚠ undocumented · used by `createEnvironmentField`: A sampleable environment field: read temperature, wetness, sun/sky exposure, and ambient light at any world position and time.
2161
+ - `EnvironmentWorldFeature` (interface): interface EnvironmentWorldFeature { kind: "environment"; terrain?: TerrainEnvironmentDescriptor; islands?: readonly TerrainIslandDescriptor[]; sky?: SkyEnvironmentDescriptor; weather?: readonly WeatherEnvironmentDescriptor[]; vegetation?: readonly VegetationEnvironmentDescr… — ⚠ undocumented · used by `environment`: Composes an `environment()` feature from terrain, sky, weather, vegetation, water, structures, roads, and pads.
2162
+ - `FactionDef` (interface): interface FactionDef { id: string; relations?: Readonly<Record<string, FactionRelation>>; towardSelf?: FactionRelation; towardOthers?: FactionRelation } — ⚠ undocumented
1734
2163
  - `FallbackPolicy` (type): type FallbackPolicy<P extends SamplePoint = SamplePoint> = | "none" | "last-candidate" | { readonly point: P } — What to return when the attempt budget is exhausted. `"none"` yields no point (honest failure); `"last-candidate"` returns the final rejected draw (post-projection); `{ point }` returns a caller fixed fallback (a hand-placed safe spot). Explicit, so a caller never mistakes a fallback for a hit.
1735
2164
  - `FastTravelNetwork` (interface): interface FastTravelNetwork<TMeta = unknown> — A network of fast-travel points with per-player discovery + distance queries.
1736
2165
  - `FastTravelOptions` (interface): interface FastTravelOptions<TMeta = unknown> — Options for {@link createFastTravelNetwork}.
1737
2166
  - `FastTravelSnapshot` (interface): interface FastTravelSnapshot — Serializable discovery state.
1738
- - `FireGrid` (interface): interface FireGrid — ⚠ undocumented
2167
+ - `FireGrid` (interface): interface FireGrid { readonly cols: number; readonly rows: number; step(dt: number, options?: FireStepOptions): void; igniteCell(col: number, row: number): void; ignite(x: number, z: number): boolean; cell(col: number, row: number): FireCell; cellAt(x: number… — ⚠ undocumented
1739
2168
  - `FlatGround` (interface): interface FlatGround — A 3D walkable plane/slab. `Infinity` axes are unbounded; no separate "infinite" mode exists.
1740
2169
  - `FlatGroundSize` (interface): interface FlatGroundSize — Size of a `flat` ground: extents in world units. `Infinity` on an axis means unbounded — an endless plain needs no bounds number invented for it. `y` optionally bounds vertical play space.
1741
2170
  - `FlightControlInput` (interface): interface FlightControlInput — Normalized pilot inputs for one flight-simulation tick.
1742
2171
  - `FlightControlRates` (interface): interface FlightControlRates — Angular authority, response, damping, and self-leveling configuration.
1743
2172
  - `FlightVector` (type): type FlightVector = readonly [number, number, number] — Three-dimensional world-space vector used by the flight model.
1744
- - `FogCells` (interface): interface FogCells — ⚠ undocumented
2173
+ - `FogCells` (interface): interface FogCells { cols: number; rows: number; minX: number; minZ: number; cellSize: number; revealed: readonly boolean[]; revealedCount: number } — ⚠ undocumented
1745
2174
  - `FogField` (interface): interface FogField — Reveal-on-event fog of war over a fixed grid. Walking (`revealAlong`) and digging/acting (`reveal`) clear cells; once revealed a cell stays revealed. Pure and renderer-free — the shell/react map draws `cells()`.
1746
2175
  - `ForceVolume` (class): class ForceVolume — A trigger region that pushes bodies passing through it — boost pads (`impulse` + `once`), conveyors (`velocity`), fans/wind (`accelerate`). Call `apply` each tick; `once` mode fires only on entry by tracking membership between ticks.
1747
2176
  - `FormationSlotGenerator` (type): type FormationSlotGenerator = (count: number) => Vec2[] — Produces `count` slot offsets in the group's local frame — `[right, forward]` where `+forward` points where the group faces. Index order is the slot order; a generator must be pure (same `count` → same offsets) so placement stays deterministic. Sample generators below cover common shapes; games pass their own for anything else (crowds, convoys, sports positions) with no engine edit.
1748
- - `FramingConfig` (interface): interface FramingConfig — ⚠ undocumented
1749
- - `FreezeMonitor` (interface): interface FreezeMonitor — ⚠ undocumented
1750
- - `FreezeViolation` (interface): interface FreezeViolation — ⚠ undocumented
1751
- - `Frustum` (interface): interface Frustum — ⚠ undocumented
1752
- - `FrustumProjection` (interface): interface FrustumProjection — ⚠ undocumented
1753
- - `FrustumSample` (interface): interface FrustumSample — ⚠ undocumented
1754
- - `FrustumSensor` (interface): interface FrustumSensor — ⚠ undocumented
1755
- - `FrustumTarget` (interface): interface FrustumTarget — ⚠ undocumented
2177
+ - `FramingConfig` (interface): interface FramingConfig { idealDistance?: number; centerWeight?: number; sizeWeight?: number } — ⚠ undocumented
2178
+ - `FreeFlightBindings` (interface): interface FreeFlightBindings — Per-axis bindings for free-flight — which actions drive each flight axis. Positive is forward/right/up.
2179
+ - `FreeFlightController` (interface): interface FreeFlightController — Stateful handle for any free-flight actor with snapshot/restore/retune.
2180
+ - `FreeFlightIntent` (interface): interface FreeFlightIntent — Intent for one free-flight tick — forward/right from WASD/analog, vertical from jump/crouch.
2181
+ - `FreeFlightMode` (type): type FreeFlightMode = "creative" | "spectator" | "noclip" | "hover" — Free-flight families — character-scale 6DOF movement, distinct from vehicle aerodynamics.
2182
+ - `FreeFlightState` (interface): interface FreeFlightState — Velocity state for a free-flight actor — serializable and ownable by the caller.
2183
+ - `FreeFlightStep` (interface): interface FreeFlightStep — World displacement produced by one free-flight tick.
2184
+ - `FreeFlightTuning` (interface): interface FreeFlightTuning — Data-first tuning for one free-flight profile.
2185
+ - `FreezeMonitor` (interface): interface FreezeMonitor { tick(subjects: readonly FreezeSubject[], frozenIds: ReadonlySet<string>, dt: number): FreezeViolation[]; reset(id?: string): void; snapshot(): FreezeMonitorState; restore(next: FreezeMonitorState): void } — ⚠ undocumented
2186
+ - `FreezeViolation` (interface): interface FreezeViolation { id: string; speed: number; movedSeconds: number } — ⚠ undocumented
2187
+ - `Frustum` (interface): interface Frustum { readonly planes: Float64Array; readonly corners: Float64Array; minX: number; minY: number; minZ: number; maxX: number; maxY: number; maxZ: number } — ⚠ undocumented
2188
+ - `FrustumProjection` (interface): interface FrustumProjection { inView: boolean; distance: number; screenX: number; screenY: number } — ⚠ undocumented
2189
+ - `FrustumSample` (interface): interface FrustumSample { id: string; inView: boolean; distance: number; screenX: number; screenY: number; framing: number; dwellSeconds: number } — ⚠ undocumented
2190
+ - `FrustumSensor` (interface): interface FrustumSensor { tick(camera: FrustumCamera, targets: readonly FrustumTarget[], dt: number): FrustumSample[]; reset(id?: string): void } — ⚠ undocumented
2191
+ - `FrustumTarget` (interface): interface FrustumTarget { id: string; position: EntityPosition; radius?: number } — ⚠ undocumented
1756
2192
  - `GRASS_SCHEMA` (const): const GRASS_SCHEMA: ParamSchema — The grass parameter schema — drives the inspector and `meta` parse via the studio seam.
1757
2193
  - `GROUND_DECAL_LAYERS` (const): const GROUND_DECAL_LAYERS: { readonly road: 0.06; readonly junction: 0.06; readonly marking: 0.11; readonly glow: 0.14; } — The single owning table of ground-decal Y offsets, in world units above the sampled terrain.
1758
2194
  - `GeneratedAsset` (interface): interface GeneratedAsset — A resolved generator asset: its parts plus the overall local-space bounds (min/max corners).
@@ -1760,22 +2196,23 @@
1760
2196
  - `GeneratedPart` (interface): interface GeneratedPart — One generated primitive part — a box/panel placed in the asset's local space.
1761
2197
  - `Glide` (class): class Glide — A reduced-gravity, forward-thrust glide over a physics body — wingsuit / glider / paraglider (Enshrouded, Grounded). Call `apply(dt, steerX, steerZ)` each frame *before* `world.step`: it feeds back most of the gravity the sim is about to apply (leaving `gravityScale` of it), pushes the body along the steer vector by `thrust`, and clamps descent to `maxFallSpeed`. Stop calling it to fall normally again — no attach/detach state to leak.
1762
2198
  - `Grapple` (class): class Grapple — A fired-anchor rope on the joint API — grapple (reel toward a hit point), zipline (rigid cable to a far anchor you then slide/reel along), swing (rigid rope + gravity = a pendulum). `fire` attaches a `distance`/`spring` joint from the traveller body to a fixed world point; `reel` shrinks its rest length so the constraint drags the body in; `moveAnchor` re-points it (zipline glide, grapple-to- moving-target). The pick — a raycast to find the anchor — is the caller's; core owns the constraint.
1763
- - `GrassEnvironmentDescriptor` (type): type GrassEnvironmentDescriptor = { kind: "grass" } & Required< Pick<GrassEnvironmentConfig, "area" | "density" | "bladeHeight" | "bladeWidth" | "windStrength" | "colors"> > & Pick<GrassEnvironmentConfig, "seed"> — ⚠ undocumented
2199
+ - `GrassEnvironmentDescriptor` (type): type GrassEnvironmentDescriptor = { kind: "grass" } & Required< Pick<GrassEnvironmentConfig, "area" | "density" | "bladeHeight" | "bladeWidth" | "windStrength" | "colors"> > & Pick<GrassEnvironmentConfig, "seed" | "bladeBend" | "tuftRadius" | "colorVariation" | "normalLift"> — ⚠ undocumented · used by `grass`: Declares a grass vegetation patch for `environment()` — area, blade sizing, density, and colors.
1764
2200
  - `GravityField` (interface): interface GravityField — Position-dependent gravity source used by movement and vehicle simulations.
1765
2201
  - `GravityVector` (type): type GravityVector = readonly [number, number, number] — Three-dimensional acceleration vector sampled from a gravity field.
1766
- - `GripCurve` (interface): interface GripCurve — ⚠ undocumented
2202
+ - `GripCurve` (interface): interface GripCurve { points: readonly (readonly [number, number])[] } — ⚠ undocumented · used by `sampleGripCurve`: Piecewise-linear tire-grip curve: normalized lateral slip → available grip (0..1).
1767
2203
  - `GroundConfig` (type): type GroundConfig = FlatGround | RoundGround | VoxelGround | BoardGround — The substrate of a place, discriminated by `mode` — TS rejects a `radius` on `flat` and `x`/`z` on `round`.
1768
2204
  - `GroundGenerator` (interface): interface GroundGenerator — Serializable algorithm parameters for a procedural ground generator. Never a genre kit.
1769
2205
  - `GroundMode` (type): type GroundMode = "flat" | "round" | "voxel" | "board" — Canonical ground modes after normalization (`stage` → `board`).
1770
2206
  - `GroundPoint` (type): type GroundPoint = readonly [number, number] — A world-space point on the ground plane as an `[x, z]` pair.
1771
2207
  - `GuideRegion` (interface): interface GuideRegion — An axis-aligned XZ rectangle to generate terrain-readability guides within.
2208
+ - `HOVER_FLIGHT_TUNING` (const): const HOVER_FLIGHT_TUNING: FreeFlightTuning — Preset for hover/jetpack — gravity + thrust, useful for short bursts.
1772
2209
  - `HeatConfig` (interface): interface HeatConfig — Tuning for {@link createHeatState}/{@link advanceHeat} — levels, decay, and pursuit-spawn ring.
1773
2210
  - `HeatGain` (interface): interface HeatGain — One crime tick's contribution — only `witnessed` gains raise heat (unseen crimes are free, GTA-style).
1774
2211
  - `HeatLevelDef` (interface): interface HeatLevelDef — One escalation tier — the heat threshold it begins at and the pursuer count it wants active.
1775
2212
  - `HeatSource` (interface): interface HeatSource — A localized warmth source — campfire, forge, geothermal vent.
1776
2213
  - `HeatState` (interface): interface HeatState — Serializable heat-system state — round-trips through `createHeatState`/`advanceHeat` each tick.
1777
2214
  - `HeightSampler` (type): type HeightSampler = (x: number, z: number) => number — A height sampler over the ground: world elevation at any `x`/`z`.
1778
- - `HiddenStateSource` (interface): interface HiddenStateSource — ⚠ undocumented
2215
+ - `HiddenStateSource` (interface): interface HiddenStateSource { id: string; position: EntityPosition; variables: Readonly<Record<string, HiddenStateValue>> } — ⚠ undocumented · used by `useHiddenStateProbe` (@jgengine/shell/vision/HiddenStateProbeHud): Reads a hidden zone/entity state variable in range (EMF / thermometer / geiger style sensor verb, #116).
1779
2216
  - `HitInput` (interface): interface HitInput — A single incoming hit to register on a {@link DamageDirectionTracker}. The angle is relative to the player's facing (renderer-agnostic): `0` points at the front/top of the reticle and increases clockwise, so a game passes the bearing from the player toward the attacker without knowing anything about the screen.
1780
2217
  - `InterestCensus` (interface): interface InterestCensus — Aggregate counts of active vs dormant gates — the metric the issue asks a scheduler to expose.
1781
2218
  - `InterestCensusAccumulator` (interface): interface InterestCensusAccumulator — A running census accumulator; call `record` inside the caller's existing tick loop (no extra pass).
@@ -1786,9 +2223,9 @@
1786
2223
  - `InterestState` (type): type InterestState = "active" | "dormant" — Interest scheduling: the scale primitive that lets far-away agents sleep instead of running acquisition and pathing every frame. A per-agent gate decides — from proximity to the nearest interest source plus explicit wake signals — whether this tick does expensive work, at what cadence, with hysteresis so it never thrashes at the boundary and deterministic staggering so a thousand siblings do not all wake on the same frame. State is a plain serializable object; the caller drives it from a bounded spatial query, never a full-world scan.
1787
2224
  - `InterestTier` (interface): interface InterestTier — A distance-keyed cadence tier: nearer agents tick faster, farther-but-awake agents tick slower.
1788
2225
  - `IntersectionStreet` (interface): interface IntersectionStreet — One street to trim + mesh through {@link buildTrimmedIntersections}.
1789
- - `Job` (interface): interface Job — ⚠ undocumented
1790
- - `JobDef` (interface): interface JobDef — ⚠ undocumented
1791
- - `JobReport` (interface): interface JobReport — ⚠ undocumented
2226
+ - `Job` (interface): interface Job — ⚠ undocumented · used by `activeJobs` (@jgengine/core/gameplay): Jobs currently progressing.
2227
+ - `JobDef` (interface): interface JobDef { id?: string; station: NavPoint; work: number; priority?: number; arriveRadius?: number; repeat?: boolean } — ⚠ undocumented
2228
+ - `JobReport` (interface): interface JobReport { jobId: string; workerId: string; cycle: number } — ⚠ undocumented
1792
2229
  - `JunctionApproach` (interface): interface JunctionApproach — One approach feeding {@link buildJunctionSurface}: the exact draped corner vertices a ribbon ends at.
1793
2230
  - `JunctionGeometryOptions` (interface): interface JunctionGeometryOptions — Tunables shared by {@link trimPathAtJunctions}, {@link buildJunctionSurface}, and {@link buildTrimmedIntersections}.
1794
2231
  - `KinematicChassisTuning` (interface): interface KinematicChassisTuning — Mass-and-force chassis layer (#1051); when present it supersedes `engineAccel`/`brakeAccel` with force/mass dynamics. Drive/brake become forces divided by `massKg`, a per-tick tire friction budget (`tireGrip` * grip curve * surface * downforce * m * g) is split lateral-first then longitudinal so hard slides and launches saturate, and `comHeight`/`trackWidth` set weight-transfer washout and body lean. Coasting decelerates from physical road load, not a per-vehicle constant: rolling resistance `μ_rr · m · g` always, plus engine braking `ENGINE_BRAKE_FRACTION · engineForce` routed through the current gear (so it strengthens as the car downshifts) whenever the throttle is lifted and a `powertrain` is configured. All fields are required; omit the whole block for the legacy model.
@@ -1796,8 +2233,8 @@
1796
2233
  - `KinematicPowertrainTuning` (interface): interface KinematicPowertrainTuning — Data-first gearbox and torque-curve tuning for a kinematic ground vehicle.
1797
2234
  - `KinematicSteeringTuning` (interface): interface KinematicSteeringTuning — Bicycle-model steering settings; all angles are radians.
1798
2235
  - `KinematicVehicle` (interface): interface KinematicVehicle — The pure-kinematic arcade car every racing game hand-rolled (#282.1): steer-yaw scaled by speed, throttle/brake acceleration, and a grip-curve lateral-slip bleed — no `PhysicsWorld`, no wheels, just the drift-friendly integration the three shipped racers proved out. Games keep their flavor (drift meters, boost, off-track rules) via `surfaceFriction`/`dragAt` hooks and the returned slip.
1799
- - `KinematicVehicleStep` (interface): interface KinematicVehicleStep — ⚠ undocumented
1800
- - `KinematicVehicleTuning` (interface): interface KinematicVehicleTuning — ⚠ undocumented
2236
+ - `KinematicVehicleStep` (interface): interface KinematicVehicleStep { position: readonly [number, number, number]; heading: number; forwardSpeed: number; lateralSpeed: number; slip: number; surface: number; gear: number; rpm: number; steerAngle: number; yawRate: number; longitudinalAcceleration: number; tra… — ⚠ undocumented · used by `tickDrivableVehicle`: Connects an `AxisInput` sample straight through a ground-vehicle sim (`KinematicVehicle` or `VehicleDynamics`) to a scene entity's pose for …
2237
+ - `KinematicVehicleTuning` (interface): interface KinematicVehicleTuning { engineAccel: number; brakeAccel: number; topSpeed: number; reverseSpeed: number; turnRate: number; turnSpeedRef: number; grip?: GripCurve; gripStrength: number; handbrakeGrip: number; rollingResistance?: number; coastDeceleration?: number… — ⚠ undocumented · used by `createKinematicVehicle`: Arcade ground-vehicle sim (car, kart, bike) with throttle, brake, steer, drift and retunable handling.
1801
2238
  - `LANDMARK_HARD_CAP` (const): const LANDMARK_HARD_CAP: 12 — Hard cap on grand plots emitted regardless of dial/city size.
1802
2239
  - `LOCK_ACTIONS` (const): const LOCK_ACTIONS: readonly LockAction[] — The five pick actions, in display order (shallow → deep).
1803
2240
  - `LineFormationOptions` (interface): interface LineFormationOptions — Options for {@link lineFormation}.
@@ -1809,16 +2246,16 @@
1809
2246
  - `LockTierSpec` (interface): interface LockTierSpec — Difficulty dials for one lock: board size, forgiveness band, gates, fog window, traps.
1810
2247
  - `MOVEMENT_TUNING` (const): const MOVEMENT_TUNING: { readonly standEyeHeight: 1.7; readonly crouchEyeHeight: 1.15; readonly walkSpeedMultiplier: 1.75; readonly runSpeedMultiplier: 2.25; readonly crouchSpeedMultiplier: 0.45; readonly backpedalSpeedMultiplier: 0.65; readonly groundAcceleration: 26; readonly airAcceleration: 12; … — Kinematics + feel tuning for the first-person controller. Centralised here so movement feel lives in one place rather than scattered through the renderer.
1811
2248
  - `MagnitudeOf` (type): type MagnitudeOf<P> = (membership: AreaMembership<P>) => number — Read a comparable magnitude from a membership (e.g. buff strength, damage per tick).
1812
- - `MapCellStates` (interface): interface MapCellStates — ⚠ undocumented
2249
+ - `MapCellStates` (interface): interface MapCellStates { id: string; origin: MapXZ; cellSize: number; cells: readonly {col: number; row: number; tone: MapLayerTone; opacity?: number}[] } — ⚠ undocumented
1813
2250
  - `MapMarker` (interface): interface MapMarker<TMeta = unknown> extends MarkerView<TMeta> — A marker owned by {@link MarkerSet}, including its lifecycle and query fields.
1814
2251
  - `MapNote` (interface): interface MapNote — A text note pinned at a world point.
1815
- - `MapRoute` (interface): interface MapRoute — ⚠ undocumented
2252
+ - `MapRoute` (interface): interface MapRoute { id: string; points: readonly MapXZ[]; tone?: MapLayerTone; forecast?: boolean; width?: number; closed?: boolean } — ⚠ undocumented
1816
2253
  - `MapShapeAnnotation` (interface): interface MapShapeAnnotation — A drawn area annotation (circle/rect/polygon), reusing the map-zone shape vocabulary.
1817
2254
  - `MapStroke` (interface): interface MapStroke — A freehand drawn line on the map — a world-XZ polyline.
1818
- - `MapZone` (interface): interface MapZone — ⚠ undocumented
2255
+ - `MapZone` (interface): interface MapZone { id: string; shape: MapZoneShape; tone?: MapLayerTone; opacity?: number; forecast?: boolean; label?: string } — ⚠ undocumented
1819
2256
  - `MarkerCollection` (type): type MarkerCollection<TMarker extends MarkerView = MarkerView> = | readonly TMarker[] | MarkerSource<TMarker> | MarkerSet — Marker data accepted by portable consumers: static views, an external source, or a native set.
1820
2257
  - `MarkerKindStyle` (interface): interface MarkerKindStyle — Visual descriptor for a marker kind. Games supply their own palette; the engine ships `DEFAULT_MARKER_KINDS` as a content-agnostic starting set that the react minimap/compass read for colors and glyphs.
1821
- - `MarkerSet` (interface): interface MarkerSet<TMeta = unknown> — ⚠ undocumented
2258
+ - `MarkerSet` (interface): interface MarkerSet<TMeta = unknown> { add(marker: MarkerInput<TMeta>): string; remove(id: string): boolean; get(id: string): MapMarker<TMeta> | null; list(): readonly MapMarker<TMeta>[]; query(query: MarkerQuery): MapMarker<TMeta>[]; prune(now: number): number; clear(): void;… — ⚠ undocumented · used by `useLiveMarkers` (@jgengine/react): A self-ticking {@link MarkerSet} kept in sync with the live scene: on a heartbeat (default 100ms, and once immediately) it clears the set an…
1822
2259
  - `MarkerSource` (interface): interface MarkerSource<TMarker extends MarkerView = MarkerView> — Observable marker snapshots owned by an external project. `getSnapshot` must return the same array identity until the source changes and calls its subscribers, matching React's external-store contract.
1823
2260
  - `MarkerSourceOptions` (interface): interface MarkerSourceOptions<TEntity, TMarker extends MarkerView = MarkerView> — Configuration for projecting a caller-owned collection into display-only markers.
1824
2261
  - `MarkerView` (interface): interface MarkerView<TMeta = unknown> — Small, display-only marker shape consumed by map renderers. Existing games can project their own entities to this view without adopting marker lifecycle storage or duplicating them into a {@link MarkerSet}.
@@ -1829,8 +2266,8 @@
1829
2266
  - `MinimapBakePalette` (interface): interface MinimapBakePalette — The height→color ramp and water color used by the bake.
1830
2267
  - `MinimapBakeSource` (interface): interface MinimapBakeSource — The authored world a bake reads — a height sampler, its bounds, and optional zones/water.
1831
2268
  - `MinimapBakeZone` (interface): interface MinimapBakeZone — One biome/region tint painted over the terrain shade where the ground falls inside its polygon.
1832
- - `MinimapView` (interface): interface MinimapView — ⚠ undocumented
1833
- - `ModelAssetRef` (interface): interface ModelAssetRef — ⚠ undocumented
2269
+ - `MinimapView` (interface): interface MinimapView { center: WorldXZ; worldRadius: number; size: number; rotate?: number } — ⚠ undocumented · used by `projectToMinimap`: Project a world XZ (or XYZ) point into minimap pixel space.
2270
+ - `ModelAssetRef` (interface): interface ModelAssetRef { url: string; dims?: ModelDims; collisionMesh?: CollisionMeshData; space?: AssetSpace; clips?: readonly string[] } — ⚠ undocumented · used by `createHostedWorldSessionAsync` (@jgengine/core/runtime/hostedWorldSession): Build a hosted session from an asynchronous persistence backend.
1834
2271
  - `ModelDims` (interface): interface ModelDims — Measured horizontal footprint, footprint center, and lowest Y of a model in model space.
1835
2272
  - `ModelNode` (interface): interface ModelNode — Generic named-socket reader for loaded 3D models. Walks a node tree (any object with `.name`, `.position`, and `.children` — structurally satisfied by `THREE.Object3D`) and collects the local offsets of nodes whose name marks an attachment point. Genre-agnostic: wire anchors on a pylon, muzzle/hand mounts on a character, hardpoints on a ship, seat/decal slots on furniture — anything an artist tags with an empty in the GLB. Pure data (no three.js import), so it lives in core.
1836
2273
  - `MountController` (class): class MountController — Mount / rideable control-transfer (issue #83). Registers rideables (each with one or more seats — a control seat drives, the rest ride) and tracks who is on what. It owns no camera or physics: game code reads `cameraTarget(riderId)` to point the follow camera at the mount, and `driveTarget(riderId)` to route that rider's {@link import("../physics/vehicleBody").AxisInput}-driven input at the mount's movement kit — the same seam a horse, a truck, or a shared multi-seat ship all plug into.
@@ -1838,16 +2275,24 @@
1838
2275
  - `MovementPose` (type): type MovementPose = "standing" | "crouch" | "prone" | "running" — ⚠ undocumented
1839
2276
  - `MusicInstrument` (type): type MusicInstrument = | "strings" | "flute" | "harp" | "horn" | "choir" | "bell" | "timpani" | "bass" | "stacc" | "pad" | "lute" | "dulcimer" | "frameDrum" | "warDrum" | "reed" | "pipe" | "squareLead" | "woodBlock" | "tinyBell" | "piano" | "shaker" | "brassStab" | "cymSwell" | "oboe" — Named synthesised instrument. Each maps to a voice in the shell's instrument library (`@jgengine/shell/audio/musicVoices`); an unknown name falls back to a plain sine voice so a theme is never silent.
1840
2277
  - `MusicTheme` (interface): interface MusicTheme — A through-composed, looping music track. `events` need not be sorted; the director schedules them ahead against a fixed anchor so loops are seamless.
1841
- - `NavGrid` (interface): interface NavGrid — ⚠ undocumented
1842
- - `NavPoint` (type): type NavPoint = readonly [number, number] — ⚠ undocumented
2278
+ - `NOCLIP_FLIGHT_TUNING` (const): const NOCLIP_FLIGHT_TUNING: FreeFlightTuning — Preset for noclip — weightless, noclips, yaw-relative with independent vertical.
2279
+ - `NavGrid` (interface): interface NavGrid { readonly cols: number; readonly rows: number; readonly cellSize: number; readonly bounds: Aabb; readonly diagonal: boolean; isWalkable(col: number, row: number): boolean; setWalkable(col: number, row: number, walkable: boolean): void; blo… — ⚠ undocumented · used by `findPath`: A* over the walkable grid.
2280
+ - `NavMeshAdjacency` (interface): interface NavMeshAdjacency — Neighbor relationship for one navigation polygon.
2281
+ - `NavMeshData` (interface): interface NavMeshData — Serializable polygon navigation mesh data. Treat it as immutable once queried; queries cache derived geometry per object.
2282
+ - `NavMeshLink` (interface): interface NavMeshLink — Explicit traversable connection between two navigation polygons.
2283
+ - `NavMeshPath` (interface): interface NavMeshPath — Route points and polygons selected through a navigation mesh.
2284
+ - `NavMeshQuery` (interface): interface NavMeshQuery — Cached, allocation-light queries over one {@link NavMeshData}.
2285
+ - `NavMeshQueryOptions` (interface): interface NavMeshQueryOptions — Tunable pricing and bounds for a {@link NavMeshQuery}.
2286
+ - `NavMeshQuerySnapshot` (interface): interface NavMeshQuerySnapshot — Serializable tuning of a {@link NavMeshQuery}.
2287
+ - `NavPoint` (type): type NavPoint = readonly [number, number] — ⚠ undocumented · used by `findPath`: A* over the walkable grid.
1843
2288
  - `NoiseFieldConfig` (interface): interface NoiseFieldConfig — Configuration for {@link noiseField}: seed, amplitude, and fractal noise shaping.
1844
2289
  - `NoiseVoice` (interface): interface NoiseVoice — A filtered white-noise burst — impacts, whooshes, breath, crackle. Realised from a shared 1s noise buffer at a randomised playback rate and start offset, decaying exponentially to silence at `duration * decay`.
1845
2290
  - `NoteEvent` (interface): interface NoteEvent — One scheduled note in a theme, positioned on the loop's quarter-note grid.
1846
2291
  - `ObjectSlotRejection` (type): type ObjectSlotRejection = | "unknown-object" | "no-slot-inventory" | "unknown-inventory" | "no-space" | "wrong-kind" | "slot-occupied" | "invalid-slot" | "insufficient" — Why an object slot mutation was refused — the instance, its catalog entry, the player inventory, or the declared `accepts`/capacity.
1847
2292
  - `ObjectSlotResult` (type): type ObjectSlotResult = { status: "ok" } | { status: "rejected"; reason: ObjectSlotRejection } — Outcome of an object slot mutation: applied, or refused with a reason and no state change on either side.
1848
2293
  - `ObjectSlotTransfer` (interface): interface ObjectSlotTransfer — Which player inventory a transfer moves between, and what it moves.
1849
- - `ObjectVisual` (interface): interface ObjectVisual — ⚠ undocumented
1850
- - `OceanEnvironmentDescriptor` (type): type OceanEnvironmentDescriptor = { kind: "ocean" } & Required< Pick<OceanEnvironmentConfig, "bounds" | "level" | "waveHeight" | "waveScale" | "waveSpeed" | "color"> > & Pick<OceanEnvironmentConfig, "position" | "levelAt"> — ⚠ undocumented
2294
+ - `ObjectVisual` (interface): interface ObjectVisual { scale?: number | readonly [number, number, number]; color?: string; opacity?: number } — ⚠ undocumented
2295
+ - `OceanEnvironmentDescriptor` (type): type OceanEnvironmentDescriptor = { kind: "ocean" } & Required< Pick<OceanEnvironmentConfig, "bounds" | "level" | "waveHeight" | "waveScale" | "waveSpeed" | "color"> > & Pick<OceanEnvironmentConfig, "position" | "levelAt"> — ⚠ undocumented · used by `ocean`: Declares an ocean water body for `environment()` — bounds, level, and wave tuning.
1851
2296
  - `Order` (interface): interface Order<TPayload = unknown> — One issued order. Fully serializable: `kind` is a registry key (not a closure), `payload` is the caller's plain data, and `state` is the kind's own plain progress scratch (e.g. a patrol waypoint index) written during `start`/`update`. Never holds functions, so the whole queue round-trips through `JSON`/`structuredClone`.
1852
2297
  - `OrderCancelReason` (type): type OrderCancelReason = "replaced" | "preempted" | "requested" | "invalid" | "failed" | "cleared" — Why an order left the queue without completing. `replaced`/`preempted` come from a newer order taking over; `requested` from explicit `cancelActive`; `invalid` when the kind's `start` rejects; `failed` when `update` reports failure; `cleared` from a full `clear`/`cancelAll`.
1853
2298
  - `OrderEvent` (interface): interface OrderEvent — A lifecycle event emitted synchronously as orders move through the queue.
@@ -1872,9 +2317,9 @@
1872
2317
  - `OrderVec3` (type): type OrderVec3 = readonly [number, number, number] — Composable entity orders: a serializable command queue with lifecycle, preemption, and pluggable order kinds (#912). Player- or AI-issued intent ("move here", "attack that", "patrol this route") becomes reusable data instead of a hard-coded RTS verb kit. The queue owns issue -> activate -> tick -> complete/cancel lifecycle and deterministic preemption policy; each order KIND owns what "running" means, composed over narrow world adapters. Engine code never branches on `move`, `attack`, or any game verb -- kinds are looked up by string in a registry, so a game adds a verb by registering data.
1873
2318
  - `POLE_LINE_SCHEMA` (const): const POLE_LINE_SCHEMA: ParamSchema — The pole-line parameter schema — drives the inspector and `meta` parse via the studio seam.
1874
2319
  - `POSE_HITBOX` (const): const POSE_HITBOX: Record<MovementPose, PoseHitbox> — ⚠ undocumented
1875
- - `PadEnvironmentDescriptor` (type): type PadEnvironmentDescriptor = { kind: "pad" } & Required< Pick<PadEnvironmentConfig, "center" | "size" | "height" | "color"> > & Pick<PadEnvironmentConfig, "rotationY" | "elevation"> — ⚠ undocumented
2320
+ - `PadEnvironmentDescriptor` (type): type PadEnvironmentDescriptor = { kind: "pad" } & Required< Pick<PadEnvironmentConfig, "center" | "size" | "height" | "color"> > & Pick<PadEnvironmentConfig, "rotationY" | "elevation"> — ⚠ undocumented · used by `padFlattenMasks` (@jgengine/core/world/features): Derives implicit `TerrainFlattenMask`s carving each pad's footprint into the terrain beneath it.
1876
2321
  - `PadSize` (type): type PadSize = readonly [number, number] | { radius: number } — ⚠ undocumented
1877
- - `PaintStroke` (interface): interface PaintStroke — ⚠ undocumented
2322
+ - `PaintStroke` (interface): interface PaintStroke { u: number; v: number; radius: number; color: string } — ⚠ undocumented
1878
2323
  - `ParamField` (type): type ParamField = | RangeParamField | NumberParamField | BoolParamField | SelectParamField | ColorParamField | TextParamField | SeedParamField | WeightedListParamField | ActionParamField — One row in a kind's parameter schema — the union the generic inspector knows how to render.
1879
2324
  - `ParamPreset` (interface): interface ParamPreset — A named slider/weight bundle for a kind — a saved set of field values the inspector (or the `apply_preset` verb) writes into an object's `meta` in one patch, ready to tweak afterwards. Presets are plain data on the schema, so kinds ship archetypes and games can override the registration with their own.
1880
2325
  - `ParamSchema` (interface): interface ParamSchema — A kind's full parameter surface: an ordered list of fields the inspector renders top-to-bottom.
@@ -1882,57 +2327,57 @@
1882
2327
  - `ParticleBuffers` (interface): interface ParticleBuffers — Read-only packed buffers of the live particles, laid out for a renderer to upload directly (Structure-of-Arrays, no per-particle objects). Only the first `count` entries are live; the arrays themselves are reused every frame.
1883
2328
  - `ParticleSnapshot` (interface): interface ParticleSnapshot — Serializable simulation state for save/restore and deterministic replay.
1884
2329
  - `ParticleSystem` (interface): interface ParticleSystem — A live, dt-driven particle simulation.
1885
- - `PathFollowConfig` (interface): interface PathFollowConfig — ⚠ undocumented
2330
+ - `PathFollowConfig` (interface): interface PathFollowConfig { waypoints: readonly Waypoint[]; speed: number; loop?: boolean } — ⚠ undocumented · used by `advancePathFollow`: Advance a path-follower by `speed * dt` along its authored polyline.
1886
2331
  - `PathFollowProgress` (interface): interface PathFollowProgress — Read-only progress readout for inspection/debug tooling, produced by {@link pathFollowProgress}.
1887
- - `PathFollowState` (interface): interface PathFollowState — ⚠ undocumented
2332
+ - `PathFollowState` (interface): interface PathFollowState { position: Waypoint; target: number; heading: number; done: boolean; distanceTravelled: number } — ⚠ undocumented · used by `advancePathFollow`: Advance a path-follower by `speed * dt` along its authored polyline.
1888
2333
  - `PathHeightPolicy` (type): type PathHeightPolicy = | { readonly kind: "sample" } | { readonly kind: "fixed"; readonly height: number } | { readonly kind: "grade"; readonly start: number; readonly end: number } — Where a path corridor drives its centerline height: - `sample` — follow the base terrain under the centerline, so the corridor drapes level across its width while still tracking the hills the path crosses (the natural policy for a road or trail). - `fixed` — hold one constant height for the whole corridor (a level causeway, runway, or dam crest). - `grade` — interpolate linearly from `start` to `end` height along the path's arc length, a constant-slope ramp between two anchors (a switchback, a graded rail bed, an accessibility ramp).
1889
2334
  - `PathProgress` (type): type PathProgress = | { readonly kind: "normalized"; readonly value: number } /** World-distance travelled from the first waypoint (looping paths wrap; clamped otherwise). */ | { readonly kind: "distance"; readonly value: number } /** Segment `index` (0-based) plus `fraction` `0..1` along that segme… — Semantic seek target for {@link pathFollowSeek} — the caller-facing progress vocabulary a stateful path behavior restores from, so a follower can start at a distributed phase or resume a serialized route without knowing waypoint internals. `direction` (forward heading) falls out of the resulting {@link PathFollowState.heading}, so it is an output rather than a seek input.
1890
2335
  - `PathRetaining` (interface): interface PathRetaining — Retaining behavior for a path corridor's shoulders. A wall rises only where the corridor already cuts or fills into the surrounding ground by at least `threshold` — gentle stretches stay open — so a road through a canyon gets held banks while the same profile on flat ground does not. The wall fades in smoothly across `taper` above the threshold so it never steps on or off between adjacent samples.
1891
2336
  - `PatrolOrderPayload` (interface): interface PatrolOrderPayload — Payload for a patrol: walk a waypoint route, optionally looping forever.
1892
2337
  - `PatrolOrderState` (interface): interface PatrolOrderState — Serializable patrol progress.
1893
- - `PhysicsStats` (interface): interface PhysicsStats — ⚠ undocumented
2338
+ - `PhysicsStats` (interface): interface PhysicsStats { count: number; awake: number; sleeping: number; contacts: number; pairs: number; substeps: number; stepMs: number } — ⚠ undocumented
1894
2339
  - `PhysicsWorld` (class): class PhysicsWorld — ⚠ undocumented
1895
2340
  - `PlaceAssetResult` (interface): interface PlaceAssetResult — Shared place-asset verb: one resolved payload for editor `place_asset` and in-game build-mode commits. Convert with {@link toStructureInput} / {@link toEditorMarker}.
1896
2341
  - `PlaceConfig` (interface): interface PlaceConfig — Input to {@link world}: place identity, substrate, and the laws of this place.
1897
2342
  - `PlaceWorldFeature` (interface): interface PlaceWorldFeature — A declared place — the `world()` result carried on `GameDefinition.world`.
1898
- - `PlacedStructure` (interface): interface PlacedStructure — ⚠ undocumented
1899
- - `PlacementCommit` (interface): interface PlacementCommit — ⚠ undocumented
1900
- - `PlacementController` (interface): interface PlacementController — ⚠ undocumented
1901
- - `PlacementPreview` (interface): interface PlacementPreview — ⚠ undocumented
2343
+ - `PlacedStructure` (interface): interface PlacedStructure { id: string; catalogId: string; position: StructureVec3; rotationY: number; plotId?: string; data?: Readonly<Record<string, unknown>> } — ⚠ undocumented
2344
+ - `PlacementCommit` (interface): interface PlacementCommit { center: Vec2; y: number; rotationY: number; quarterTurns: number; footprint: Footprint; aabb: Aabb; slotId?: string } — ⚠ undocumented · used by `placeAssetFromCommit`: Bridge a {@link PlacementCommit} into the shared place-asset verb.
2345
+ - `PlacementController` (interface): interface PlacementController { hover(hit: PlacementHit): PlacementPreview; current(): PlacementPreview | null; rotate(steps?: number): PlacementPreview | null; setSnapMode(mode: SnapMode): PlacementPreview | null; cycleSnapMode(): SnapMode; setFootprint(footprint: Foot… — ⚠ undocumented · used by `createPlacementController`: Headless placement ghost: hover → valid/invalid preview, rotate, grid/free/surface snap, commit.
2346
+ - `PlacementPreview` (interface): interface PlacementPreview { center: Vec2; y: number; quarterTurns: number; footprint: Footprint; aabb: Aabb; valid: boolean; reason?: "out-of-bounds" | "overlap" | "no-slot" | "territory.blocked"; snapMode: SnapMode; normal: PlacementVec3; slotId?: string } — ⚠ undocumented
1902
2347
  - `PlacementRotationPolicy` (type): type PlacementRotationPolicy = | { readonly mode: "locked"; readonly degrees?: number } | { readonly mode: "snap"; readonly snapDegrees: number } | { readonly mode: "free" } — A per-asset/per-tool rotation constraint, authored as data instead of hardcoded in build code: `locked` pins every placement to one heading, `snap` quantizes to an increment (15, 45, …), and `free` allows any heading. Serializable — this is the shape stored on a catalog entry or a tool.
1903
- - `PlacementRules` (interface): interface PlacementRules — ⚠ undocumented
2348
+ - `PlacementRules` (interface): interface PlacementRules { bounds?: Aabb; obstacles?: readonly PlacementObstacle[]; snap?: number; territory?: (aabb: Aabb) => {ok: boolean} } — ⚠ undocumented · used by `validatePlacement`: Footprint validity: bounds + obstacle overlap after optional grid snap.
1904
2349
  - `PlatformCarry` (class): class PlatformCarry — Carries bodies standing on a moving platform by composing their transform with the platform's per-`step` delta — moving/rotating lifts and conveyor floors (Fall Guys, Gang Beasts). The platform is a body the game repositions each frame; riders are detected by overlap on its top face.
1905
2350
  - `Point3` (type): type Point3 = readonly [number, number, number] — Deterministic spatial sampling — draw one or many positions from a geometric region under explicit constraints, with an injected RNG, bounded attempts, and a structured pass/fail result.
1906
2351
  - `PointGravityOptions` (interface): interface PointGravityOptions — Center, strength, and falloff for radial gravity.
1907
- - `PositionedPrompt` (interface): interface PositionedPrompt — ⚠ undocumented
2352
+ - `PositionedPrompt` (interface): interface PositionedPrompt { id: string; position: PromptPoint; priority?: number; prompt: ProximityPrompt } — ⚠ undocumented · used by `resolveActivePrompt`: Nearest prompt strictly within its radius wins; a higher-priority prompt in range beats any lower-priority one regardless of distance; equal…
1908
2353
  - `PositionedPromptPatch` (type): type PositionedPromptPatch = Partial<Omit<PositionedPrompt, "id">> — A partial edit applied to an already-registered {@link PositionedPrompt} by {@link PromptRegistry.update}. Any subset of the mutable fields — everything but the stable `id` — may be supplied; omitted fields keep their prior value.
1909
2354
  - `PromptRegistry` (interface): interface PromptRegistry — A live, observable set of interaction prompts that OWNS the registered {@link PositionedPrompt}s and tracks which one is active for a player. It is a thin stateful layer over {@link resolveActivePrompt}: registration/order lives here, the nearest-within-radius / higher-priority selection stays in the pure resolver. {@link resolve} is the per-frame hot path — call it as the player moves; subscribers fire only when the active prompt actually CHANGES.
1910
2355
  - `PromptRegistrySnapshot` (interface): interface PromptRegistrySnapshot — The serializable shape {@link PromptRegistry.snapshot} returns and {@link PromptRegistry.restore} consumes: the full set of positioned prompts (in registration order) plus the id of the prompt that was active when the snapshot was taken. Prompt display/command payloads are free strings and ids — keep them serializable and this round-trips through a save cleanly.
1911
- - `ProximityPrompt` (interface): interface ProximityPrompt — ⚠ undocumented
1912
- - `QteStep` (interface): interface QteStep — ⚠ undocumented
2356
+ - `ProximityPrompt` (interface): interface ProximityPrompt { radius: number; display: ProximityPromptDisplay; invoke: PromptCommand | null } — ⚠ undocumented
2357
+ - `QteStep` (interface): interface QteStep { id: string; action: string; windowStart: number; windowEnd: number } — ⚠ undocumented · used by `evaluateQteSequence`: Evaluate a quick-time-event input sequence against timed hit windows.
1913
2358
  - `RadialDistribution` (type): type RadialDistribution = "area" | "radial" — Fill policy for a circle/ring: `"area"` = area-uniform (even density); `"radial"` = radius-uniform (clumps toward center).
1914
- - `RainEnvironmentDescriptor` (type): type RainEnvironmentDescriptor = { kind: "rain" } & Required< Pick<RainEnvironmentConfig, "area" | "density" | "speed" | "dropLength" | "wind" | "color" | "width" | "opacity"> > — ⚠ undocumented
2359
+ - `RainEnvironmentDescriptor` (type): type RainEnvironmentDescriptor = { kind: "rain" } & Required< Pick<RainEnvironmentConfig, "area" | "density" | "speed" | "dropLength" | "wind" | "color" | "width" | "opacity"> > — ⚠ undocumented · used by `rain`: Declares a rainfall weather effect for `environment()` — area, density, speed, wind, and drop width/opacity.
1915
2360
  - `Range` (interface): interface Range — A `[min, max]` range a spawned particle draws uniformly from.
1916
2361
  - `RecallBookmarkOptions` (interface): interface RecallBookmarkOptions — Caller hooks for {@link recallSelectionBookmark} — kept out of the store so focus and validity stay genre-owned.
1917
- - `RecordingBuffer` (interface): interface RecordingBuffer<T> — ⚠ undocumented
1918
- - `RecordingBufferOptions` (interface): interface RecordingBufferOptions — ⚠ undocumented
1919
- - `RegionField` (interface): interface RegionField<T = unknown> extends TerrainField — ⚠ undocumented
2362
+ - `RecordingBuffer` (interface): interface RecordingBuffer<T> { append(t: number, data: T): void; seek(t: number): RecordingFrame<T> | null; seekPair(t: number): RecordingPair<T>; range(fromT: number, toT: number): RecordingFrame<T>[]; clear(): void; duration(): number; frames(): readonly RecordingFra… — ⚠ undocumented · used by `useSessionRecorder` (@jgengine/shell/replay/useSessionRecorder): Session-recording buffer (#120) for replay / photo mode / kill-cam: records an entity's pose on game-time every frame into a `RecordingBuffe…
2363
+ - `RecordingBufferOptions` (interface): interface RecordingBufferOptions { maxDurationSeconds?: number; maxFrames?: number } — ⚠ undocumented · used by `useSessionRecorder` (@jgengine/shell/replay/useSessionRecorder): Session-recording buffer (#120) for replay / photo mode / kill-cam: records an entity's pose on game-time every frame into a `RecordingBuffe…
2364
+ - `RegionField` (interface): interface RegionField<T = unknown> extends TerrainField { sampleRegion(x: number, z: number): RegionSample<T>; readonly regions: readonly RegionDef<T>[]; readonly seaLevel: number; readonly seed: number } — ⚠ undocumented · used by `scatterItems`: Deterministically place opaque items across `area`, grounded on a region field.
1920
2365
  - `Renderable` (interface): interface Renderable — A scene object the visibility system considers. A normal game object already carries a position and a version counter, so it becomes cullable automatically — no separate "cullable" component. Everything else is optional override.
1921
2366
  - `ResolvedCity` (interface): interface ResolvedCity — A resolved city district: world-space network, zoned lots, parks, and furniture.
1922
2367
  - `ResolvedCityLot` (interface): interface ResolvedCityLot — One plot enriched with its zone/class/floors/massing — the renderer instances `pieces` at `center`.
1923
- - `ResolvedCollider` (interface): interface ResolvedCollider — ⚠ undocumented
2368
+ - `ResolvedCollider` (interface): interface ResolvedCollider { name: string; purpose: ColliderPurpose; shape: ColliderShape; damageEligible: boolean; blocks: boolean } — ⚠ undocumented
1924
2369
  - `ResolvedGround` (type): type ResolvedGround = FlatGround | RoundGround | VoxelGround | ResolvedBoardGround — A place's ground after `world()` normalization.
1925
2370
  - `ResolvedPoleLine` (interface): interface ResolvedPoleLine — The renderable payload the resolver returns and the shell renderer consumes.
1926
- - `ResolvedTerrainDetail` (type): type ResolvedTerrainDetail = Required<Omit<TerrainDetailConfig, "waterLevel" | "material">> & { waterLevel: number; material?: ResolvedTerrainDetailMaterial; } — A {@link TerrainDetailConfig} with every field resolved to a concrete value — the shape the shell's detail material consumes.
1927
- - `ResolvedWeather` (interface): interface ResolvedWeather — ⚠ undocumented
1928
- - `RevealHit` (interface): interface RevealHit — ⚠ undocumented
1929
- - `RevealQuery` (interface): interface RevealQuery — ⚠ undocumented
2371
+ - `ResolvedTerrainDetail` (type): type ResolvedTerrainDetail = Required<Omit<TerrainDetailConfig, "waterLevel" | "material" | "sweeps">> & { waterLevel: number; material?: ResolvedTerrainDetailMaterial; sweeps: { dry: readonly [number, number, number]; wet: readonly [number, number, number] }; } — A {@link TerrainDetailConfig} with every field resolved to a concrete value — the shape the shell's detail material consumes.
2372
+ - `ResolvedWeather` (interface): interface ResolvedWeather { grip: number; visibility: number; structureDamage: number; chill: number; ignition: number; spread: number } — ⚠ undocumented
2373
+ - `RevealHit` (interface): interface RevealHit { instanceId: string; distance: number; tags: readonly string[] } — ⚠ undocumented · used by `useRevealHits` (@jgengine/shell/vision/RevealVision): Occlusion-ignoring tagged-entity radius query (#115), bound to the live scene.
2374
+ - `RevealQuery` (interface): interface RevealQuery { inRadius(center: EntityPosition | string, radius: number, tags: readonly string[]): RevealHit[] } — ⚠ undocumented
1930
2375
  - `RoadCut` (interface): interface RoadCut — One trim of a ribbon end back to a junction boundary — the seam the welded surface attaches to.
1931
2376
  - `RoadEnvironmentDescriptor` (type): type RoadEnvironmentDescriptor = { kind: "road" } & Required< Pick<RoadEnvironmentConfig, "path" | "width" | "color" | "markings" | "markingColor" | "elevation"> > & { /** Resolved sidewalk band, or `false` when the road has none. */ sidewalk: { width: number; color: string } | false; } — Resolved road descriptor produced by {@link road} and rendered by the shell environment scene.
1932
2377
  - `RoadJunctionInput` (interface): interface RoadJunctionInput — The minimal junction shape this geometry needs — a node position plus its outgoing arms. Matches the structural subset of `StreetJunction` (streetGenerator) so a network's `junctions` can be fed straight in. Arm `angle` follows the generator convention `atan2(dx, dz)`, i.e. the outward unit direction of an arm is `[sin(angle), cos(angle)]`.
1933
2378
  - `RoadSurfaceOptions` (interface): interface RoadSurfaceOptions — Grip levels and blend width for {@link roadSurfaceSampler}; each field is optional and defaulted.
1934
- - `RoofPlan` (interface): interface RoofPlan — ⚠ undocumented
1935
- - `RosterEntry` (interface): interface RosterEntry — ⚠ undocumented
2379
+ - `RoofPlan` (interface): interface RoofPlan { style: RoofStyle; ridge: readonly [Vec2, Vec2]; apexHeight: number; eaveHeight: number; faces: readonly (readonly WallVec3[])[] } — ⚠ undocumented
2380
+ - `RosterEntry` (interface): interface RosterEntry { id: string; catalogId: string; capturedAt: number; equipped: boolean } — ⚠ undocumented
1936
2381
  - `RoundGround` (interface): interface RoundGround — A planet/sphere you play on the outside of. Sized by `radius` only.
1937
2382
  - `RoundGroundSize` (interface): interface RoundGroundSize — Size of a `round` ground: the planet/sphere radius in world units. Nothing else.
1938
2383
  - `SCATTER_COVERAGE_SPECS` (const): const SCATTER_COVERAGE_SPECS: Record<ScatterCoverageKind, ScatterCoverageSpec> — The coverage spec per scatterable kind — the single source for its unit + budget.
@@ -1942,6 +2387,7 @@
1942
2387
  - `SHAPE_SPHERE` (const): const SHAPE_SPHERE: 1 — ⚠ undocumented
1943
2388
  - `SOIL_KIND` (const): const SOIL_KIND: "soil" — The editor volume kind marking a box as a soil crack/moss patch.
1944
2389
  - `SOIL_SCHEMA` (const): const SOIL_SCHEMA: ParamSchema — The soil parameter schema — drives the inspector and `meta` parse via the studio seam.
2390
+ - `SPECTATOR_FLIGHT_TUNING` (const): const SPECTATOR_FLIGHT_TUNING: FreeFlightTuning — Preset for spectator — weightless, noclips, flies where the camera looks.
1945
2391
  - `SampleBatchOptions` (interface): interface SampleBatchOptions<P extends SamplePoint = SamplePoint> — Inputs for a {@link sampleBatch} draw of many spaced points.
1946
2392
  - `SampleBatchResult` (interface): interface SampleBatchResult<P extends SamplePoint = SamplePoint> — Structured batch outcome: the placed points plus whether the full count was met.
1947
2393
  - `SampleConstraints` (interface): interface SampleConstraints<P extends SamplePoint = SamplePoint> — Post-draw gates a candidate must clear. All are optional; an empty constraint set accepts every in-region draw. `exclude` discs/spheres are the keep-out distance primitive ("no closer than R to this center"); `accept` is a free-form caller predicate (biome, slope, ownership); `project` snaps a candidate onto a surface/navmesh before validation and may reject by returning `null`.
@@ -1953,16 +2399,16 @@
1953
2399
  - `ScatterCoverage` (interface): interface ScatterCoverage — A resolved coverage readout: how many instances an authored patch WANTS (`requested`, when it can be computed cheaply from geometry × density), how many it will actually place after the budget clamp (`count`), the `budget` ceiling, and whether the request hit it (`capped`). `requested` is `null` for kinds whose pre-cap ask is not knowable without running the generator (city, where the count comes from the resolved street fabric).
1954
2400
  - `ScatterCoverageKind` (type): type ScatterCoverageKind = "grass_field" | "scatter" | "city" — The shared "how much stuff grows here" contract for scatterable scene kinds (`grass_field` / `scatter` / `city`). Every scatterable kind fills an authored AREA with instances at a DENSITY, and every kind caps the placed count at a bounded BUDGET so a huge or dense request can never generate unbounded work. Before this module each kind hand-rolled its own readout and clamp story (grass silently capped in the renderer, scatter never capped, city had no budget note); this is the one place that
1955
2401
  - `ScatterCoverageSpec` (interface): interface ScatterCoverageSpec — Per-kind coverage descriptor: the unit noun, whether density is per-m², and the placement budget.
1956
- - `ScatterInstance` (interface): interface ScatterInstance — ⚠ undocumented
1957
- - `ScatterPoint` (interface): interface ScatterPoint — ⚠ undocumented
2402
+ - `ScatterInstance` (interface): interface ScatterInstance — ⚠ undocumented · used by `resolveScatter`: Every scatter region's placements across a document, grounded on `terrain` when provided.
2403
+ - `ScatterPoint` (interface): interface ScatterPoint { x: number; z: number; index: number } — ⚠ undocumented
1958
2404
  - `ScatterTerrain` (interface): interface ScatterTerrain — Ground sampler a scatter resolve reads height/normal from (the sculpt terrain or the game's ground).
1959
- - `SceneEntity` (interface): interface SceneEntity<TMeta = unknown> — ⚠ undocumented
2405
+ - `SceneEntity` (interface): interface SceneEntity<TMeta = unknown> { id: string; name: string; position: EntityPosition; rotationY: number; rotationX: number; rotationZ: number; velocity: EntityPosition; role: EntityRole; movement: EntityMovement; behaviors: readonly BehaviorDescriptor[]; hidden?: boolean;… — ⚠ undocumented · used by `entityMetaOf`: Narrow `entity.meta` with a type guard — prefer this over `entity.meta as T` so failed shapes return `null` instead of lying to the type che…
1960
2406
  - `SceneKindObject` (interface): interface SceneKindObject — The raw document object a resolver receives — shape shared by markers, volumes, and paths.
1961
2407
  - `SceneKindResolveContext` (interface): interface SceneKindResolveContext — Ground sampler + options a resolver may read (terrain height/normal snap).
1962
- - `SceneObject` (interface): interface SceneObject — ⚠ undocumented
2408
+ - `SceneObject` (interface): interface SceneObject { instanceId: string; catalogId: string; position: EntityPosition; rotationY: number; parentSpace?: string; visual?: ObjectVisual; animation?: ModelAnimationConfig | "auto" | "none"; state?: Record<string, unknown>; slots?: InventoryState } — ⚠ undocumented · used by `fromRuntimeObjectRow` (@jgengine/core/runtime/objectRows): Inverse of {@link toRuntimeObjectRow}: rebuild the live placed object a host persisted.
1963
2409
  - `SceneObjectSlots` (interface): interface SceneObjectSlots — Per-instance container contents for placed objects whose catalog entry declares `slotInventory` — the engine side of "install a GPU into a rack", "put an item in a chest". Contents live on `SceneObject.slots`, so they replicate and save with the object rather than needing a game-owned table keyed by `instanceId`, and every mutation is validated against the declared `accepts` and stack limits.
1964
- - `SceneRaycastApi` (interface): interface SceneRaycastApi — ⚠ undocumented
1965
- - `SceneRaycastHit` (interface): interface SceneRaycastHit — ⚠ undocumented
2410
+ - `SceneRaycastApi` (interface): interface SceneRaycastApi { raycast(input: SceneRaycastInput): SceneRaycastHit | null; raycastAll(input: SceneRaycastInput): SceneRaycastHit[] } — ⚠ undocumented
2411
+ - `SceneRaycastHit` (interface): interface SceneRaycastHit { targetKind: SceneRaycastTargetKind; instanceId: string; catalogId?: string; colliderName: string; purpose: ColliderPurpose; damageEligible: boolean; blocks: boolean; distance: number; point: EntityPosition; normal: EntityPosition } — ⚠ undocumented · used by `firstImpact`: First impact: nearest hit that blocks, or nearest hit if none block.
1966
2412
  - `ScreenEffect` (interface): interface ScreenEffect — A live effect in the current composite: its label, color, region, and the eased opacity `0..1` to draw *right now*. These objects are pooled and reused across {@link ScreenEffectsController.composite} calls — read them, don't retain.
1967
2413
  - `ScreenEffectEasing` (type): type ScreenEffectEasing = "linear" | "easeIn" | "easeOut" | "easeInOut" — How a transient effect's intensity curves from peak to zero over its life.
1968
2414
  - `ScreenEffectShape` (type): type ScreenEffectShape = "full" | "vignette" — The screen region an effect tints. `"full"` grades the whole frame (a flash); `"vignette"` grades only the edges, leaving the center clear (a directional or ambient border tint). Purely a shape hint for the renderer — no genre meaning.
@@ -1970,13 +2416,13 @@
1970
2416
  - `ScreenEffectsController` (interface): interface ScreenEffectsController — A live, clock-driven screen-feedback controller.
1971
2417
  - `ScreenEffectsOptions` (interface): interface ScreenEffectsOptions — Options for {@link createScreenEffects}.
1972
2418
  - `ScreenEffectsSnapshot` (interface): interface ScreenEffectsSnapshot — Serializable state of every active effect, for save/restore and replay.
1973
- - `ScreenRect` (interface): interface ScreenRect — ⚠ undocumented
2419
+ - `ScreenRect` (interface): interface ScreenRect { minX: number; minY: number; maxX: number; maxY: number } — ⚠ undocumented · used by `isMarquee`: True when the drag is large enough to be a marquee rather than a click.
1974
2420
  - `SelectionBookmarkSnapshot` (interface): interface SelectionBookmarkSnapshot — The serializable shape of a {@link SelectionBookmarks} store: each key maps to its ordered, deduplicated id list. Plain data — safe to persist in a save file or replicate over the wire, and the exact input {@link createSelectionBookmarks} restores.
1975
2421
  - `SelectionBookmarks` (interface): interface SelectionBookmarks — A generic, keyed store of saved id sets ("bookmarks") over stable string ids — the reusable layer under RTS control groups, camera bookmarks, saved squads, editor selection presets, and accessibility recall. It owns storage only: binding, recall, enumeration, pruning, and serialization. It never touches the active {@link SelectionSet} or the camera — replacement/merge and focus stay caller hooks (see {@link recallSelectionBookmark}) so one store serves any genre, input scheme, or focus policy.
1976
2422
  - `SelectionPruneResult` (interface): interface SelectionPruneResult — Outcome of a {@link SelectionBookmarks.prune} pass — what the validity predicate removed.
1977
- - `SelectionSet` (interface): interface SelectionSet — ⚠ undocumented
1978
- - `SensorProbeOptions` (interface): interface SensorProbeOptions — ⚠ undocumented
1979
- - `SensorReading` (interface): interface SensorReading — ⚠ undocumented
2423
+ - `SelectionSet` (interface): interface SelectionSet { add(id: string): void; remove(id: string): void; toggle(id: string): void; has(id: string): boolean; replace(ids: Iterable<string>): void; clear(): void; list(): string[]; size(): number } — ⚠ undocumented · used by `createSelectionSet`: An ordered, deduplicated set of selected instance ids for RTS unit-command routing.
2424
+ - `SensorProbeOptions` (interface): interface SensorProbeOptions { range: number; variableId: string; falloff?: "linear" | "none" } — ⚠ undocumented · used by `useHiddenStateProbe` (@jgengine/shell/vision/HiddenStateProbeHud): Reads a hidden zone/entity state variable in range (EMF / thermometer / geiger style sensor verb, #116).
2425
+ - `SensorReading` (interface): interface SensorReading { sourceId: string; variableId: string; value: HiddenStateValue; strength: number; distance: number } — ⚠ undocumented · used by `useHiddenStateProbe` (@jgengine/shell/vision/HiddenStateProbeHud): Reads a hidden zone/entity state variable in range (EMF / thermometer / geiger style sensor verb, #116).
1980
2426
  - `SequenceCue` (interface): interface SequenceCue<Payload = unknown> — One scheduled beat of a cutscene: a typed cue that fires when the playhead reaches `atMs`.
1981
2427
  - `SequenceDirector` (interface): interface SequenceDirector<Payload = unknown> — A data-driven cutscene: an ordered timeline of typed cues that fire on a single injected clock. See {@link createSequenceDirector}.
1982
2428
  - `SequenceDirectorOptions` (interface): interface SequenceDirectorOptions<Payload = unknown> — Options for {@link createSequenceDirector}.
@@ -1984,28 +2430,28 @@
1984
2430
  - `SequenceState` (interface): interface SequenceState — A read-only view of the director's playback state, returned by {@link SequenceDirector.state}.
1985
2431
  - `SharedAnnotations` (interface): interface SharedAnnotations — Local annotation edits that also broadcast, plus `apply` for inbound edits. `add*`/`remove`/`clear` mirror {@link AnnotationLayer} but return globally-unique ids so two clients never collide.
1986
2432
  - `SharedAnnotationsDeps` (interface): interface SharedAnnotationsDeps — Construction options for {@link createSharedAnnotations}.
1987
- - `SimClock` (interface): interface SimClock — ⚠ undocumented
1988
- - `SkillCheckConfig` (interface): interface SkillCheckConfig — ⚠ undocumented
1989
- - `SkillCheckResult` (interface): interface SkillCheckResult — ⚠ undocumented
2433
+ - `SimClock` (interface): interface SimClock { advance(realDt: number): number; now(): number; snapshot(): ClockSnapshot; hydrate(snapshot: ClockSnapshot): void; calendar(): CalendarTime; isPaused(): boolean; speed(): number; pause(): void; play(): void; toggle(): void; setSpeed(multi… — ⚠ undocumented
2434
+ - `SkillCheckConfig` (interface): interface SkillCheckConfig { trackWidth: number; zone: SkillCheckZone; markerPeriod: number; window: number; zoneDriftPerSecond?: number } — ⚠ undocumented · used by `skillCheckZoneAt`: A timing-bar skill check that succeeds when the moving marker is released inside the target zone.
2435
+ - `SkillCheckResult` (interface): interface SkillCheckResult { success: boolean; timedOut: boolean; markerPosition: number; zone: SkillCheckZone } — ⚠ undocumented
1990
2436
  - `SkyEnvironmentDescriptor` (type): type SkyEnvironmentDescriptor = { kind: "sky" } & Required< Pick<SkyEnvironmentConfig, "preset" | "timeOfDay"> > & Omit<SkyEnvironmentConfig, "preset" | "timeOfDay"> — ⚠ undocumented
1991
2437
  - `SlotAssignmentOptions` (interface): interface SlotAssignmentOptions — Tuning for {@link assignFormationSlots}' stable, low-churn matching.
1992
2438
  - `SnapMode` (type): type SnapMode = "grid" | "free" | "surface" — ⚠ undocumented
1993
- - `SnowEnvironmentDescriptor` (type): type SnowEnvironmentDescriptor = { kind: "snow" } & Required< Pick<SnowEnvironmentConfig, "area" | "density" | "speed" | "flakeSize" | "drift" | "wind" | "color" | "opacity"> > — ⚠ undocumented
2439
+ - `SnowEnvironmentDescriptor` (type): type SnowEnvironmentDescriptor = { kind: "snow" } & Required< Pick<SnowEnvironmentConfig, "area" | "density" | "speed" | "flakeSize" | "drift" | "wind" | "color" | "opacity"> > — ⚠ undocumented · used by `snow`: Declares a snowfall weather effect for `environment()` — area, density, drift, wind, and flake opacity.
1994
2440
  - `SoilRules` (interface): interface SoilRules — Fully-defaulted soil params parsed from a volume's `meta`.
1995
- - `SoundDef` (interface): interface SoundDef — ⚠ undocumented
2441
+ - `SoundDef` (interface): interface SoundDef { id: string; url?: string; synth?: SynthPatch; bus: AudioBusId; gain?: number; loop?: boolean; positional?: boolean; falloff?: AudioFalloffConfig; doppler?: number; spatial?: {panning: "hrtf" | "equalpower"; refDistance?: number; maxDistan… — ⚠ undocumented
1996
2442
  - `SpatialGrid` (class): class SpatialGrid — A uniform-grid broad-phase over the x/z plane, separate from the rigid-body sim, for cheap same-tick proximity across hundreds–thousands of simple movers (swarm enemies). Rebuild each tick from the caller's own position arrays, then `queryCircle` (enemies hitting the player / an AoE) or `forEachPair` (mutual separation). Both are precise: no false negatives, no false positives beyond the exact distance test.
1997
- - `SpawnDirectorConfig` (interface): interface SpawnDirectorConfig — ⚠ undocumented
1998
- - `SpawnDirectorState` (interface): interface SpawnDirectorState — ⚠ undocumented
1999
- - `SpawnEntry` (interface): interface SpawnEntry — ⚠ undocumented
2000
- - `SpawnRequest` (interface): interface SpawnRequest — ⚠ undocumented
2443
+ - `SpawnDirectorConfig` (interface): interface SpawnDirectorConfig { waves: readonly WaveManifest[]; maxAlive?: number; escalationPerSecond?: number; alertBudgetPerSecond?: number; alertDecayPerSecond?: number; playerBudgetPerSecond?: number; maxSpawnsPerTick?: number; loop?: boolean; seed?: number; spawnP… — ⚠ undocumented
2444
+ - `SpawnDirectorState` (interface): interface SpawnDirectorState { wave: number; elapsed: number; waveElapsed: number; budget: number; alert: number; spawnedThisWave: number; spawnedTotal: number; rng: RandomSeed; done: boolean } — ⚠ undocumented
2445
+ - `SpawnEntry` (interface): interface SpawnEntry { id: string; cost: number; weight?: number; minWave?: number } — ⚠ undocumented
2446
+ - `SpawnRequest` (interface): interface SpawnRequest { entryId: string; cost: number; wave: number; point?: NavPoint; laneId?: number } — ⚠ undocumented
2001
2447
  - `StatCatalog` (type): type StatCatalog = Record<string, { max: number; min?: number; current?: number }> — ⚠ undocumented
2002
2448
  - `StatValue` (interface): interface StatValue extends StatPool — Native entity-stat name retained as a compatibility bridge to the portable pool model.
2003
2449
  - `Station` (interface): interface Station — ⚠ undocumented
2004
2450
  - `StoredScreenEffect` (interface): interface StoredScreenEffect — A persisted effect record (all spec fields resolved plus its start time and id).
2005
2451
  - `StratifiedOptions` (interface): interface StratifiedOptions — Inputs for {@link sampleStratified}: a grid over `area` with one jittered point per cell.
2006
2452
  - `StructureGraph` (class): class StructureGraph — A structural-integrity graph over a building — nodes are pieces (walls, beams, floors), edges are load-bearing connections, some nodes are anchored foundations. `damage`/`damageEdge` wear pieces and connections down; when a piece shatters or an edge severs, the graph recomputes which pieces still reach an anchor and hands back every newly-disconnected piece as one `CollapseEvent`. Feed that to `toDebris` to sink the fallen pieces into a `PhysicsWorld` as rigid bodies ("The Finals" smooth destruction, Rainbow Six walls). Coarse by design: it replicates the collapse event, not per fragment.
2007
- - `StructureMaterial` (interface): interface StructureMaterial — ⚠ undocumented
2008
- - `SupportResult` (interface): interface SupportResult — ⚠ undocumented
2453
+ - `StructureMaterial` (interface): interface StructureMaterial { id: string; strength: number; mass?: number } — ⚠ undocumented
2454
+ - `SupportResult` (interface): interface SupportResult { supported: readonly string[]; unsupported: readonly string[]; distance: Readonly<Record<string, number>> } — ⚠ undocumented
2009
2455
  - `SurfaceDelta` (interface): interface SurfaceDelta — A compact record of the surface-material cells a paint stroke touched: parallel `indices`/`before`/`after` arrays into the per-cell surface grid. One per stroke keeps paint undo history small.
2010
2456
  - `SurfaceGridLine` (interface): interface SurfaceGridLine — One draped grid line from {@link surfaceGridLines}: its axis, emphasis, and draped vertices.
2011
2457
  - `SurfaceGridOptions` (interface): interface SurfaceGridOptions — Shaping for {@link surfaceGridLines}: region, spacing, emphasis cadence, and draping.
@@ -2020,23 +2466,23 @@
2020
2466
  - `TerraformFalloff` (type): type TerraformFalloff = "smooth" | "linear" | "none" — How a brush's strength fades from its center to its rim.
2021
2467
  - `TerraformMode` (type): type TerraformMode = "raise" | "lower" | "smooth" | "flatten" | "noise" | "ramp" | "paint" — A sculpt operation kind: heightfield brushes plus the surface-paint brush.
2022
2468
  - `TerraformShape` (type): type TerraformShape = "circle" | "square" — A brush footprint: a round disc or an axis-aligned square.
2023
- - `TerraformSnapshot` (interface): interface TerraformSnapshot — ⚠ undocumented
2469
+ - `TerraformSnapshot` (interface): interface TerraformSnapshot { bounds: Aabb; cellSize: number; cols: number; rows: number; offsets: readonly number[]; surfaces: readonly (string | null)[]; layers?: readonly TerrainMaterialLayer[]; weights?: readonly number[] } — ⚠ undocumented · used by `applyDeltaToSnapshot`: Returns a new snapshot with a delta's `after` offsets applied (copy-on-write — inputs untouched).
2024
2470
  - `TerraformStroke` (interface): interface TerraformStroke — Accumulates a whole drag — many brush stamps — into one compact {@link TerraformDelta}. Keeps each vertex's first `before` and latest `after`, so undo replays the stroke as a single step even though the pointer fired dozens of moves.
2025
2471
  - `TerrainCircleRegion` (interface): interface TerrainCircleRegion extends TerrainRegionStyle — A circular palette zone painted over the base terrain palette — snow caps, ash wastes, spawn circles.
2026
2472
  - `TerrainDetailConfig` (interface): interface TerrainDetailConfig — Procedural detail-surface layer for terrain: a noise-driven shader that keeps the biome-tinted base ground (from `colors`/`biomeBands`) and blends distinct rock, sand, and snow over it by slope, height, and waterline — turning a flat vertex-colour surface into varied, textured-reading ground with no image assets.
2027
2473
  - `TerrainDetailMaterialConfig` (interface): interface TerrainDetailMaterialConfig — Real PBR texture applied over the ground surface — the seam that lets a game put a `buildMaterialCatalog` material on terrain. Blends with, never replaces, the procedural detail shader: color/roughness/ao tile the maps by world position, `strength` fades them over the existing vertex-colour + noise look.
2028
- - `TerrainEnvironmentDescriptor` (type): type TerrainEnvironmentDescriptor = { kind: "terrain" } & Required< Pick<TerrainEnvironmentConfig, "bounds" | "height"> > & Omit<TerrainEnvironmentConfig, "bounds" | "height"> — ⚠ undocumented
2474
+ - `TerrainEnvironmentDescriptor` (type): type TerrainEnvironmentDescriptor = { kind: "terrain" } & Required< Pick<TerrainEnvironmentConfig, "bounds" | "height"> > & Omit<TerrainEnvironmentConfig, "bounds" | "height"> — ⚠ undocumented · used by `terrain`: Declares a heightfield terrain patch for `environment()` — bounds, noise, materials, and flatten masks.
2029
2475
  - `TerrainField` (interface): interface TerrainField — A sampleable ground surface: height and normal at any x/z, with optional bounds and water level.
2030
- - `TerrainFlattenMask` (interface): interface TerrainFlattenMask — ⚠ undocumented
2476
+ - `TerrainFlattenMask` (interface): interface TerrainFlattenMask { center: EnvironmentVec2; radius: number; height?: number; falloff?: number } — ⚠ undocumented · used by `padFlattenMasks` (@jgengine/core/world/features): Derives implicit `TerrainFlattenMask`s carving each pad's footprint into the terrain beneath it.
2031
2477
  - `TerrainMaterialLayer` (interface): interface TerrainMaterialLayer — One material layer in a terrain's reorderable stack: a palette `surface` id (drives the base color) plus its render parameters. Array order is the stack order — lower index paints under higher. `roughness`/`tiling`/`triplanar`/`tint`/`opacity` are carried as data so a runtime game reads them straight off the snapshot.
2032
2478
  - `TerrainMaterialRegion` (type): type TerrainMaterialRegion = TerrainCircleRegion | TerrainPolylineRegion | TerrainRectRegion — A palette zone painted over the base terrain palette. Circle (the default when no `shape` is given), `polyline` ribbons for roads/rivers, and rotatable `rect` districts all paint fully inside their core and blend back across `falloff`; later regions in the list win overlaps.
2033
- - `TerrainPalette` (interface): interface TerrainPalette — ⚠ undocumented
2479
+ - `TerrainPalette` (interface): interface TerrainPalette { low: string; high: string; waterline: string } — ⚠ undocumented
2034
2480
  - `TerrainPathProfile` (interface): interface TerrainPathProfile — A serializable path-driven terrain modifier. The `points` centerline reshapes the heightfield across a corridor of `width`, feathering back to the surrounding ground across `shoulder`. `height` sets the centerline target (sample / fixed / grade); `depth` carves a channel below it (deepest at the centerline, easing to zero at the core edge — rivers and trenches); `retaining` raises walls where the cut/fill exceeds a threshold; `maxCut`/`maxFill` cap how far the ground may move from its base height. All fields are plain data (numbers, string enums, point arrays) so a profile round-trips through the scene document and evaluates identically at author time and runtime.
2035
2481
  - `TerrainPolylineRegion` (interface): interface TerrainPolylineRegion extends TerrainRegionStyle — A ribbon palette zone following a centerline — roads and rivers, instead of chaining overlapping circles.
2036
2482
  - `TerrainRectRegion` (interface): interface TerrainRectRegion extends TerrainRegionStyle — A rectangular palette zone, optionally rotated about the world y axis — plazas, fields, districts.
2037
2483
  - `TerrainRegionStyle` (interface): interface TerrainRegionStyle — Palette and blend fields shared by every `TerrainMaterialRegion` shape.
2038
2484
  - `TerrainSurfaceRule` (interface): interface TerrainSurfaceRule — A height/slope predicate for auto-painting a surface layer (e.g. rock on steep slopes, snow up high).
2039
- - `ThreatTable` (interface): interface ThreatTable — ⚠ undocumented
2485
+ - `ThreatTable` (interface): interface ThreatTable { add(sourceId: string, amount: number): number; set(sourceId: string, amount: number): void; threatOf(sourceId: string): number; decay(dt: number): void; highest(options?: HighestThreatOptions): string | null; ranked(): ThreatEntry[]; taun… — ⚠ undocumented
2040
2486
  - `TimerDirection` (type): type TimerDirection = "down" | "up" — A serializable set of named countdown / countup timers evaluated against an injected clock. One primitive covers round timers, respawn clocks, and ability cooldown/charge — they are the same mechanic (elapsed vs. duration on a clock), so `id` and any labels are free strings the engine never interprets.
2041
2487
  - `TimerExpiryListener` (type): type TimerExpiryListener = (id: string) => void — Listener notified when a timer newly expires. Receives the timer id.
2042
2488
  - `TimerRead` (interface): interface TimerRead — A single timer's resolved state for one read. All fields are plain numbers so a HUD can render without touching the model. For a looping timer the values describe the current cycle; `expired` is only ever `true` for a finished non-looping timer (loops signal completion through {@link TimerSet.poll}).
@@ -2059,7 +2505,7 @@
2059
2505
  - `VISIBILITY_HIDDEN` (const): const VISIBILITY_HIDDEN: 0 — Numeric code for a cell no group member has seen, or has fully forgotten.
2060
2506
  - `VISIBILITY_OBSERVED` (const): const VISIBILITY_OBSERVED: 2 — Numeric code for a cell a group currently observes.
2061
2507
  - `VISIBILITY_REMEMBERED` (const): const VISIBILITY_REMEMBERED: 1 — Numeric code for a cell seen before but not currently in view (last-known).
2062
- - `Vec3` (type): type Vec3 = EntityPosition — ⚠ undocumented
2508
+ - `Vec3` (type): type Vec3 = EntityPosition — ⚠ undocumented · used by `catenaryCurve`: True hyperbolic catenary between two anchors — the shape a uniform cable actually takes under gravity.
2063
2509
  - `VehicleImpact` (interface): interface VehicleImpact — A single blocked-move event a car can react to (#1051): crash damage, screen shake, a metal-crunch cue. Reported once, when a move is first vetoed, then consumed by {@link VehicleObstacleClamp.takeImpact}.
2064
2510
  - `VehicleObstacleClamp` (interface): interface VehicleObstacleClamp — A planar move clamp for a kinematic car: feed {@link clampMove} to a vehicle's `clampMove` hook so an attempted XZ displacement slides along world solids instead of driving through them, and read {@link takeImpact} once per tick for the crash it produced.
2065
2511
  - `VehicleSeats` (class): class VehicleSeats — Composes `scene/mount`'s control-transfer bookkeeping with the seat/camera/movement-mode transition every enter/exit-vehicle flow needs (#533.2): boarding resolves a free seat and reports the camera target, drive target, and rider movement-lock patch in one call; leaving computes a side-door placement next to the vehicle and reports the same triad in reverse. Pure — no entity/camera side effects — the caller applies `riderMovementPatch`/`placement`/`cameraTarget` via its own `ctx`.
@@ -2072,24 +2518,24 @@
2072
2518
  - `VisibilityGroupState` (interface): interface VisibilityGroupState — Sparse serialized knowledge for one group — only non-hidden cells are stored.
2073
2519
  - `VisibilityMemory` (type): type VisibilityMemory = | { readonly kind: "permanent" } | { readonly kind: "none" } | { readonly kind: "decay"; readonly updates: number } — How a cell decays after a group stops observing it — the terrain-memory policy. `permanent` keeps last-known terrain forever (RTS explored map); `none` drops it straight back to hidden the moment it leaves view (pure line-of-sight stealth); `decay` remembers it for `updates` observe cycles, then hides it. Day/night, height, sensor, and stealth rules are NOT encoded here — the caller bakes those into which cells it reports as observed each update.
2074
2520
  - `VisibilityState` (type): type VisibilityState = "hidden" | "remembered" | "observed" — One viewer group's knowledge of a cell: never/forgotten, last-known, or live.
2075
- - `VisibilitySystem` (interface): interface VisibilitySystem — ⚠ undocumented
2521
+ - `VisibilitySystem` (interface): interface VisibilitySystem { update(): VisibilityResult; isVisible(id: string): boolean; isPreloaded(id: string): boolean; boundsOf(id: string): RenderBounds | undefined; settings(): CullingSettings; setSettings(patch: Partial<CullingSettings>): void; stats(): Visibi… — ⚠ undocumented
2076
2522
  - `VolumeDistribution` (type): type VolumeDistribution = "volume" | "radial" — Fill policy for a sphere/shell: `"volume"` = volume-uniform (even density); `"radial"` = radius-uniform.
2077
2523
  - `VolumetricCloudsConfig` (interface): interface VolumetricCloudsConfig — Volumetric cloud layer config for `sky()` — a raymarched cloud slab mounted from the environment `sky` seam. Pure config + defaulting here; the raymarch shader lives in the `shell` renderer (`environment/VolumetricClouds.tsx`), mounted alongside `SkyDome` whenever a sky descriptor carries this field. Off by default — omit `volumetricClouds` on `sky({...})` and no layer mounts.
2078
2524
  - `VolumetricCloudsRules` (interface): interface VolumetricCloudsRules — Fully-defaulted volumetric cloud params, resolved from a `VolumetricCloudsConfig`.
2079
2525
  - `VoxelFace` (type): type VoxelFace = "px" | "nx" | "py" | "ny" | "pz" | "nz" — ⚠ undocumented
2080
2526
  - `VoxelGround` (interface): interface VoxelGround — A procedural volume of blocks. `size` is the generator domain; `generator` is algorithm params only.
2081
2527
  - `VoxelGroundSize` (interface): interface VoxelGroundSize — Size of a `voxel` ground: the generator's domain per axis; axes may be `Infinity` for streaming volumes.
2082
- - `VoxelMaterial` (interface): interface VoxelMaterial — ⚠ undocumented
2528
+ - `VoxelMaterial` (interface): interface VoxelMaterial { id: number; name: string; strength: number; drop?: string } — ⚠ undocumented
2083
2529
  - `VoxelVolume` (class): class VoxelVolume — A runtime-editable dense voxel grid — the carve/deposit op behind destructible dig worlds (Deep Rock Galactic tunnels, Astroneer terrain). Cells hold a material id (0 = empty); `carve` clears a sphere of solid cells that a tool is strong enough to break and returns how many it removed (feed that to a loot roll), `deposit` fills a sphere with a material. World↔cell mapping is `origin`+`scale`.
2084
2530
  - `WATER_SCHEMA` (const): const WATER_SCHEMA: ParamSchema — The water parameter schema — drives the inspector and `meta` parse via the studio seam.
2085
2531
  - `WaterRules` (interface): interface WaterRules — Fully-defaulted water surface params parsed from a volume's `meta`.
2086
- - `WaterSurface` (interface): interface WaterSurface — ⚠ undocumented
2087
- - `WaveManifest` (interface): interface WaveManifest — ⚠ undocumented
2532
+ - `WaterSurface` (interface): interface WaterSurface { readonly level: number; readonly waves: readonly GerstnerWave[]; height(x: number, z: number, time: number): number; normal(x: number, z: number, time: number): WaterNormal; displace(x: number, z: number, time: number): readonly [number, … — ⚠ undocumented
2533
+ - `WaveManifest` (interface): interface WaveManifest { budget: number; entries: readonly SpawnEntry[]; duration?: number; budgetPerSecond?: number } — ⚠ undocumented
2088
2534
  - `WaveRunner` (interface): interface WaveRunner — A live, observable, serializable wave/spawn runner over a seeded spawn director.
2089
2535
  - `WaveRunnerConfig` (interface): interface WaveRunnerConfig extends SpawnDirectorConfig — Configuration for {@link createWaveRunner}: the full {@link SpawnDirectorConfig} (escalating waves, budgets, seed, spawn points) plus an optional {@link WaveSpawnSink}. The runner owns the director state — you never pass a `SpawnDirectorState` here.
2090
2536
  - `WaveSpawnSink` (type): type WaveSpawnSink = (request: SpawnRequest) => void — A callback the wave runner hands each {@link SpawnRequest} the underlying spawn director emits. The runner never instantiates entities itself — it forwards the request (a free-string `entryId` "kind", cost, wave, optional point/lane) to the game, which decides what to build. Keeps the runner genre-agnostic.
2091
2537
  - `WaveView` (interface): interface WaveView — A pooled, per-frame readout of the current wave — the "brain behind WAVE 3". Reused across {@link WaveRunner.view} calls (never per-frame allocated), so read it and render it, don't retain it.
2092
- - `Waypoint` (type): type Waypoint = readonly [number, number, number] — ⚠ undocumented
2538
+ - `Waypoint` (type): type Waypoint = readonly [number, number, number] — ⚠ undocumented · used by `useWaypoints` (@jgengine/react): Subscribe to a {@link WaypointTracker} and re-render on every change, returning its current waypoints.
2093
2539
  - `WaypointEntry` (interface): interface WaypointEntry — A single player-placed waypoint. World-XZ only — serializable and renderer-free.
2094
2540
  - `WaypointGuidance` (interface): interface WaypointGuidance — Direction/range to the tracked waypoint, for an on-screen guide arrow.
2095
2541
  - `WaypointSnapshot` (interface): interface WaypointSnapshot — Whole serializable state of a {@link WaypointStore} — drop into a save blob.
@@ -2097,17 +2543,18 @@
2097
2543
  - `WaypointStoreDeps` (interface): interface WaypointStoreDeps — Construction options for {@link createWaypointStore}.
2098
2544
  - `WeatherEnvironmentDescriptor` (type): type WeatherEnvironmentDescriptor = RainEnvironmentDescriptor | SnowEnvironmentDescriptor — ⚠ undocumented
2099
2545
  - `WeatherModifierTable` (type): type WeatherModifierTable<K extends string = string> = Record<K, WeatherModifier> — ⚠ undocumented
2100
- - `WeatherState` (interface): interface WeatherState — ⚠ undocumented
2546
+ - `WeatherState` (interface): interface WeatherState { kind: WeatherKind; intensity: number; wind?: WindVector } — ⚠ undocumented
2101
2547
  - `WedgeFormationOptions` (interface): interface WedgeFormationOptions — Options for {@link wedgeFormation}.
2102
2548
  - `WeightedParamEntry` (interface): interface WeightedParamEntry — One weighted entry in a `weightedList` param — an item id and its relative spawn weight.
2103
2549
  - `WeightedRegionEntry` (interface): interface WeightedRegionEntry<P extends SamplePoint = SamplePoint> — A weighted member of a {@link weightedRegion} composite.
2104
- - `WindField` (interface): interface WindField — ⚠ undocumented
2550
+ - `WindField` (interface): interface WindField { readonly direction: WindVector; readonly speed: number; at(time: number): WindVector; atPoint(x: number, z: number, time: number): WindVector; strengthAt(x: number, z: number, time: number): number } — ⚠ undocumented
2105
2551
  - `WorldFeature` (type): type WorldFeature = | PlaceWorldFeature | ({ kind: "biomes" } & BiomesWorldConfig) | ({ kind: "voxel" } & VoxelWorldConfig) | ({ kind: "plots" } & PlotsWorldConfig) | ({ kind: "tilemap" } & TilemapWorldConfig) | EnvironmentWorldFeature | { kind: "flat" } — A declared world shape passed to `defineGame`. The preferred model is the place feature from `world()` (`@jgengine/core/world/place`): substrate + laws, with all dressing authored in the editor. The remaining members — biomes, voxel grid, plots, tilemap, environment, flat — are the legacy code-declared shapes kept for existing games.
2106
- - `WorldGridCell` (interface): interface WorldGridCell — ⚠ undocumented
2552
+ - `WorldGridCell` (interface): interface WorldGridCell { x: number; z: number; height?: number; color?: string } — ⚠ undocumented
2107
2553
  - `WorldGridConfig` (interface): interface WorldGridConfig — Shared by `biomes()`/`voxel()`/`plots()`/`tilemap()` so the shell can render their declared content as instanced boxes without a hand-written renderer.
2108
- - `WorldXZ` (type): type WorldXZ = readonly [number, number] — ⚠ undocumented
2554
+ - `WorldXZ` (type): type WorldXZ = readonly [number, number] — ⚠ undocumented · used by `compassBearing`: Compass bearing (radians, 0 = map north = −Z, increasing clockwise toward +X = east) from one world XZ point to another.
2109
2555
  - `acquireTarget` (function): function acquireTarget(policy: AcquisitionPolicy, selfId: string, held: string | null = null): AcquisitionResult — Run one acquisition pass and pick the best target under `policy`. Pass the currently `held` target so retention hysteresis (`switchMargin`, `dropRangeScale`) can keep the lock stable; pass `null` for a cold acquire. Pure and allocation-light — the caller owns the held-target state.
2110
2556
  - `advanceBehaviors` (function): function advanceBehaviors(ctx: GameContext, dt: number): void — Advance every spawned entity carrying a `patrol` or `wander` {@link BehaviorDescriptor} one tick — the engine reads the descriptor, keeps the per-entity nav state itself, and poses the entity, so ambient traffic and idle NPC routes are register-once (attach the behavior at spawn) instead of a per-game per-frame `advancePathFollow` + `setPose` loop. Instances that are paused or disabled through {@link behaviorControl} retain their state and are skipped. The shell/host call this each frame; a game never does.
2557
+ - `advanceFreeFlight` (function): function advanceFreeFlight(state: FreeFlightState, intent: FreeFlightIntent, yaw: number, pitch: number | undefined, dt: number, tuning: FreeFlightTuning): FreeFlightStep — Advance one frame of free-flight kinematics. Horizontal uses yaw-relative strafe (A = left, D = right) — never roll/bank. Vertical is independent of pitch unless `alignWithLook` is true (spectator).
2111
2558
  - `advanceInterestGate` (function): function advanceInterestGate(state: InterestGateState, config: InterestSchedulerConfig, dt: number, input: InterestGateInput = {}): InterestGateStep — Advance one gate by `dt` seconds against this tick's `input`, mutating `state` in place and returning what the caller should do. Sleeping skips the expensive work (`active: false`) while the gate's timers keep advancing, so state is preserved; a `wake` signal or crossing `wakeRadius` flips it back to active and fires an immediate tick.
2112
2559
  - `advancePathFollow` (function): function advancePathFollow(config: PathFollowConfig, state: PathFollowState, dt: number): PathFollowState — Advance a path-follower by `speed * dt` along its authored polyline. Pure — returns the next state. Crosses multiple waypoints in one step, loops when configured, and reports `done` at the end of a non-looping path. No navmesh required (#52); feed it a navmesh route via `pathFromNav` for click-to-move (#51).
2113
2560
  - `advanceSpawnDirector` (function): function advanceSpawnDirector(config: SpawnDirectorConfig, state: SpawnDirectorState, dt: number, ctx: DirectorContext): DirectorStep — ⚠ undocumented
@@ -2131,6 +2578,7 @@
2131
2578
  - `budgetWarning` (function): function budgetWarning(coverage: ScatterCoverage): string — The shared clamp-and-warn clause every scatterable kind appends, worded identically: `""` when under budget, else ` · requested N, capped at M (budget)` when the pre-cap ask is known, or ` · capped at M (budget)` when only the ceiling is (city). This is the "surfaced, never silent" budget signal from #1112.
2132
2579
  - `buildContextMenu` (function): function buildContextMenu(input: BuildContextMenuInput): ContextMenu | null — Assemble a menu from a target's catalog verbs; null when the target lists none.
2133
2580
  - `buildJunctionSurface` (function): function buildJunctionSurface(junction: { x: number; z: number }, approaches: readonly JunctionApproach[], sampleHeight: (x: number, z: number) => number, options: JunctionGeometryOptions = {}): RoadRibbon — Weld one triangulated junction surface onto the corner vertices its incident ribbons END at (from {@link trimPathAtJunctions}). Corners are grouped by approach (so unequal widths cannot interleave a neighbour between a mouth pair), ordered around the node, and bridged as follows:
2581
+ - `buildNavAdjacency` (function): function buildNavAdjacency(mesh: NavMeshData): NavMeshAdjacency[] — Build polygon adjacency from shared edges and explicit off-mesh links.
2134
2582
  - `buildRoadRibbon` (function): function buildRoadRibbon(path: readonly RoadPoint[], width: number, sampleHeight: (x: number, z: number) => number, options: RoadRibbonOptions = {}): RoadRibbon — Triangulate a road centerline into a ground-draped ribbon mesh: the polyline is subdivided, each vertex is offset half a `width` along the local perpendicular, and every vertex sits at `sampleHeight(x, z) + elevation`. Pure geometry — the shell (or any renderer) turns the result into a mesh, and tests can assert on it directly.
2135
2583
  - `buildTrimmedIntersections` (function): function buildTrimmedIntersections(streets: readonly IntersectionStreet[], junctions: readonly RoadJunctionInput[], sampleHeight: (x: number, z: number) => number, options: JunctionGeometryOptions = {}): TrimmedIntersections — Trim a set of streets against a set of junctions and weld the crossing surfaces in one call — the ergonomic entry the shell/playground consume for meshing.
2136
2584
  - `building` (function): function building(config: BuildingEnvironmentConfig = {}): BuildingEnvironmentDescriptor — Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style. Pass `along` to line road frontage instead of gridding around `position`.
@@ -2143,6 +2591,7 @@
2143
2591
  - `circleFormation` (function): function circleFormation(options: CircleFormationOptions): FormationSlotGenerator — An evenly spaced ring around the destination — a guard cordon, a huddle, or a surround. Slot 0 sits `startAngle` from forward; slots advance evenly around the circle.
2144
2592
  - `clampToMinimapEdge` (function): function clampToMinimapEdge(point: MinimapPoint, size: number): { x: number; y: number } — Clamp a projected point to the minimap edge, preserving direction (edge markers).
2145
2593
  - `clearanceZonesFrom` (function): function clearanceZonesFrom(doc: SceneDocumentLike, options: ClearanceOptions = {}): AvoidZone[] — Point-pad clearance **discs** from a document's markers/volumes — the terrain-flatten set (spawns, plots, POIs get a level pad). A marker/volume contributes a disc when it carries `meta.clearance` or its kind is in `kinds`. Paths are *not* included (they render draped, never flattened — see {@link clearanceMasksFrom} for their foliage corridor). Pass `ids`/`kinds` to scope it.
2594
+ - `closestPoint` (function): function closestPoint(mesh: NavMeshData, point: Vec3): Vec3 | null — Return the closest point on the mesh surface, or null for an empty mesh.
2146
2595
  - `collectAuthoredTriggers` (function): function collectAuthoredTriggers(document: SceneDocumentLike): AuthoredTrigger[] — Collect every authored trigger on a document's markers and volumes. Pure — no runtime state. Action params use the live {@link registerTriggerAction} registry when present.
2147
2596
  - `combineGravity` (function): function combineGravity(fields: readonly GravityField[]): GravityField — Adds several gravity sources into one field.
2148
2597
  - `command` (function): function command(name: string, input?: unknown): PromptCommand — ⚠ undocumented
@@ -2153,7 +2602,7 @@
2153
2602
  - `contextVerb` (function): function contextVerb(label: string, command: string, args?: Record<string, unknown>): ContextVerb — Builds a {@link ContextVerb} for a right-click menu entry.
2154
2603
  - `contextVerbInput` (function): function contextVerbInput(menu: ContextMenu, verb: ContextVerb): Record<string, unknown> — Command input a chosen verb dispatches: the verb's own args, plus the target id and the world point, so a single handler can walk the actor to the target then perform it.
2155
2604
  - `controlGroupKey` (function): function controlGroupKey(digit: number, options: ControlGroupOptions = {}): string — The stable bookmark key for a control-group `digit` under `options.keyPrefix` — the key a caller passes to `SelectionBookmarks.bind`/`recall` to store a group without going through {@link resolveControlGroupIntent}.
2156
- - `createAircraftDynamics` (function): function createAircraftDynamics(tuning: AircraftTuning, options: AircraftOptions = {}): AircraftDynamics — Six-degree-of-freedom arcade flight model for fixed-wing, helicopter, and VTOL aircraft.
2605
+ - `createAircraftDynamics` (function): function createAircraftDynamics(initialTuning: AircraftTuning, options: AircraftOptions = {}): AircraftDynamics — Six-degree-of-freedom arcade flight model for fixed-wing, helicopter, and VTOL aircraft.
2157
2606
  - `createAnnotationLayer` (function): function createAnnotationLayer(options: AnnotationLayerOptions = {}): AnnotationLayer — Player-drawn map annotation layer: freehand `strokes`, area `shapes`, and pinned `notes`, all world-XZ and serializable. `routes()`/`zones()` project strokes/shapes into the exact shapes `Minimap`/`WorldMap`/`FullscreenMap` already render via their `routes`/`zones` props, so drawing needs no new renderer. State is plain data; `snapshot`/`restore` round-trip through a save.
2158
2607
  - `createAreaEffectField` (function): function createAreaEffectField<P = unknown>(state?: AreaFieldState<P>): AreaEffectField<P> — Build a continuous area-effect field. Drive it with `setSource` (once per live source per tick, so shapes follow their emitters) and `step` (to reconcile membership and drain enter/refresh/leave edges). Optionally restore prior membership by passing a `serialize()` snapshot; re-`setSource` live shapes before the first `step` after restore, since shapes are transient.
2159
2608
  - `createAssetCatalog` (function): function createAssetCatalog<TMeta extends ModelAssetRef = ModelAssetRef>(): AssetCatalog<TMeta> — ⚠ undocumented
@@ -2174,17 +2623,20 @@
2174
2623
  - `createFireGrid` (function): function createFireGrid(config: FireGridConfig): FireGrid — ⚠ undocumented
2175
2624
  - `createFogField` (function): function createFogField(config: FogConfig): FogField — ⚠ undocumented
2176
2625
  - `createFootprintGrid` (function): function createFootprintGrid(options: FootprintGridOptions = {}): FootprintGrid — Multi-cell footprint occupancy/reservation on a shared build grid — `world/placementController` only owns the ghost preview; this is the persistent claim a committed placement holds so the next hover's `isFree` check (or another player's, in a shared world) sees it. Bridge into `world/placement`'s `PlacementRules.obstacles` with {@link footprintObstacles} instead of hand-rolling an occupancy map per game.
2626
+ - `createFreeFlightController` (function): function createFreeFlightController(initialTuning: FreeFlightTuning, options: { yaw?: number; pitch?: number; state?: FreeFlightState } = {}): FreeFlightController — Totally free flight for any actor — character, camera, drone, or debug rig. Horizontal is always yaw-relative strafe; vertical is jump/crouch. Use `alignWithLook` for a 6DOF spectator that flies where the camera looks.
2627
+ - `createFreeFlightState` (function): function createFreeFlightState(): FreeFlightState — Create an empty flight velocity state.
2177
2628
  - `createGlideModel` (function): function createGlideModel(config: GlideModelConfig = {}): GlideModel — Gliding/wingsuit descent control — lift, drag, and steering from a launch.
2178
2629
  - `createGrappleSwing` (function): function createGrappleSwing(config: GrappleSwingConfig = {}): GrappleSwing — Grappling-hook rope swing physics with anchor, pendulum motion, and reel-in.
2179
2630
  - `createInterestCensus` (function): function createInterestCensus(): InterestCensusAccumulator — Create a census accumulator so the caller can tally active/dormant gates during the loop it already runs, avoiding any separate full-world scan just to report scheduler metrics.
2180
2631
  - `createInterestGateState` (function): function createInterestGateState(config: InterestSchedulerConfig, phase = 0): InterestGateState — Create a dormant gate state, staggered by `phase` (`[0,1)`, typically {@link interestPhase} of the agent id) so siblings created together do not all fire their first active tick on the same frame.
2181
- - `createKinematicVehicle` (function): function createKinematicVehicle(initialTuning: KinematicVehicleTuning, options: KinematicVehicleOptions = {}): KinematicVehicle — ⚠ undocumented
2632
+ - `createKinematicVehicle` (function): function createKinematicVehicle(initialTuning: KinematicVehicleTuning, options: KinematicVehicleOptions = {}): KinematicVehicle — Arcade ground-vehicle sim (car, kart, bike) with throttle, brake, steer, drift and retunable handling.
2182
2633
  - `createLeaderTrail` (function): function createLeaderTrail(config: LeaderTrailConfig): LeaderTrail — A trailing follower formation that chases a leader along its past path — snake/convoy trails.
2183
2634
  - `createLodScheduler` (function): function createLodScheduler(config: LodSchedulerConfig): LodScheduler — ⚠ undocumented
2184
2635
  - `createMarkerSet` (function): function createMarkerSet<TMeta = unknown>(now: () => number = Date.now): MarkerSet<TMeta> — ⚠ undocumented
2185
2636
  - `createMarkerSource` (function): function createMarkerSource<TEntity, TMarker extends MarkerView = MarkerView>(options: MarkerSourceOptions<TEntity, TMarker>): MarkerSource<TMarker> — Adapt a caller-owned array/store to an observable marker source. Projection is cached between source changes, so React reads do not copy the collection per frame. The caller retains ownership of entities, updates, persistence, and subscription scheduling.
2186
2637
  - `createMountController` (function): function createMountController(): MountController — ⚠ undocumented
2187
2638
  - `createNavGrid` (function): function createNavGrid(config: NavGridConfig): NavGrid — ⚠ undocumented
2639
+ - `createNavMeshQuery` (function): function createNavMeshQuery(mesh: NavMeshData, options: NavMeshQueryOptions = {}): NavMeshQuery — Create a cached query over a nav mesh: height-aware polygon lookup through a uniform grid, binary-heap A* priced by area costs and bounded by `maxNodes`, portal-funnel path straightening, and edge-walking raycasts.
2188
2640
  - `createOrderQueue` (function): function createOrderQueue<TCtx, TPayload = unknown>(registry: OrderRegistry<TCtx>, options: OrderQueueOptions<TPayload> = {}): OrderQueue<TCtx, TPayload> — Create a per-entity order queue over a shared kind registry. The queue owns the deterministic lifecycle and preemption policy; the kinds own behavior. Nothing here is random or unbounded: id generation is injected, activation is bounded by the pending count, and a single `tick` advances at most the active order plus one activation.
2189
2641
  - `createOrderRegistry` (function): function createOrderRegistry<TCtx>(): OrderRegistry<TCtx> — Build an empty order-kind registry. Register the built-in compositions from `orders/orderKinds` or your own verbs, then hand it to `createOrderQueue`. One registry is shared by many per-entity queues.
2190
2642
  - `createParticleSystem` (function): function createParticleSystem(config: EmitterConfig = {}): ParticleSystem — A generic, allocation-aware particle system: one emitter, a fixed pool, and Structure-of-Arrays buffers a renderer uploads straight to the GPU. It is dt-driven (call `update(dt)` each frame) and deterministic — all randomness flows from an injected `seed`, so the same seed and dt sequence reproduce the same frames, and `snapshot`/`restore` round-trips the live pool. Nothing here is combat- or genre-specific: configure it for smoke, sparks, rain, dust, embers, magic, or confetti. Travel/gameplay stays elsewhere; this owns only the spawn-integrate-fade lifecycle.
@@ -2313,18 +2765,20 @@
2313
2765
  - `polygonArea` (function): function polygonArea(polygon: readonly Vec2[]): number — Shoelace area of a polygon (always non-negative), in square meters.
2314
2766
  - `polygonBounds` (function): function polygonBounds(polygon: readonly Vec2[]): Aabb | null — Axis-aligned bounds of a polygon, or null if it has no points.
2315
2767
  - `polygonRegion` (function): function polygonRegion(polygon: readonly Vec2[]): SampleRegion<Vec2> — An arbitrary closed polygon on the XZ plane. Candidates are drawn uniformly from the polygon's bounding box and gated by point-in-polygon `contains`, so a run's draw count stays fixed (the sampler's attempt budget bounds the rejection, not a hidden inner loop).
2316
- - `populateNavGridFromEnvironment` (function): function populateNavGridFromEnvironment(grid: NavObstacleGrid, world: EnvironmentWorldFeature): number — Expands every structure descriptor on an environment world feature into its generated buildings and blocks their footprints on `grid`. Returns the number of buildings blocked.
2768
+ - `populateNavGridFromEnvironment` (function): function populateNavGridFromEnvironment(grid: NavObstacleGrid, world: EnvironmentWorldFeature): number — Blocks the footprint of every solid building an environment feature's `structures` generate — the same set `ctx.world.solids` holds for it. Returns the number of buildings blocked.
2317
2769
  - `projectToMinimap` (function): function projectToMinimap(world: WorldXZ | readonly [number, number, number], view: MinimapView): MinimapPoint — Project a world XZ (or XYZ) point into minimap pixel space. Origin is the top-left of the `size×size` box; north (−Z) maps to −Y (up). Pass `view.rotate` to spin the map under a fixed north-up player arrow.
2318
2770
  - `proximityPrompt` (function): function proximityPrompt({ radius, display, invoke = null }: ProximityPromptConfig): ProximityPrompt — ⚠ undocumented
2319
2771
  - `quarterTurnsToRotationY` (function): function quarterTurnsToRotationY(quarterTurns: number): number — Maps 0–3 quarter turns onto radians for ghost/commit rotation.
2320
2772
  - `rain` (function): function rain(config: RainEnvironmentConfig = {}): RainEnvironmentDescriptor — Declares a rainfall weather effect for `environment()` — area, density, speed, wind, and drop width/opacity.
2321
2773
  - `raiseAlert` (function): function raiseAlert(state: SpawnDirectorState, amount: number): SpawnDirectorState — ⚠ undocumented
2774
+ - `raycastNav` (function): function raycastNav(mesh: NavMeshData, from: Vec3, to: Vec3): boolean — True when the segment remains over walkable polygons.
2322
2775
  - `readNamedSockets` (function): function readNamedSockets(root: ModelNode, pattern: RegExp = SOCKET_PATTERN): ModelSocket[] — Depth-first collect every socket-named node's local offset, sorted by descending Y then ascending X so socket indices are stable across loads (top first, left-to-right). Empty when the model tags none — callers then fall back to computed offsets. Pass a custom `pattern` for a bespoke naming convention.
2323
2776
  - `readScatterPalette` (function): function readScatterPalette(meta: Record<string, unknown> | undefined): ScatterPaletteEntry[] — Parses a scatter region's palette from meta: a weighted `palette` array, else a single `item`.
2324
2777
  - `readScatterRules` (function): function readScatterRules(path: ScenePathLike): ScatterRegionRules | null — The path's scatter rules with defaults filled in; null for non-scatter paths.
2325
2778
  - `recallSelectionBookmark` (function): function recallSelectionBookmark(bookmarks: SelectionBookmarks, key: string, selection: SelectionSet, options: RecallBookmarkOptions = {}): string[] — Compose a bookmark recall onto an active {@link SelectionSet}: optionally prune stale ids (updating the stored bookmark), fold the survivors into the selection by `mode`, then fire the caller's focus hook. This is the one place the store, the selection, and the camera meet — kept as an explicit helper, not a store side effect, so games opt into the exact replacement/merge and focus policy they want. Returns the surviving ids that were applied.
2326
2779
  - `rectRegion` (function): function rectRegion(area: Aabb, options: { distribution?: AreaDistribution; edgeThickness?: number } = {}): SampleRegion<Vec2> — An axis-aligned rectangle on the XZ plane. `"uniform"` spreads evenly (draws x then z); `"edge"` biases onto a boundary band of `edgeThickness` meters (perimeter-weighted side, then inward depth) — the two are never conflated, the caller opts in.
2327
2780
  - `registerAssetGenerator` (function): function registerAssetGenerator(definition: AssetGeneratorDefinition): void — Register a parametric asset generator. Idempotent per id (last wins); call at module load.
2781
+ - `registerBehaviorActions` (function): function registerBehaviorActions(id: string, actions: Record<string, BehaviorAction>, options: BehaviorActionOptions = {}): () => void — Register the named actions used by decision graph behavior descriptors.
2328
2782
  - `registerSceneKind` (function): function registerSceneKind<TResolved>(definition: SceneKindDefinition<TResolved>): void — Register a scene kind — the plug-in point for a new parametric studio. Idempotent per `kind` (last registration wins), so a game's registration overrides a default. Call at module load; the editor inspector, `+ Add` menu, and `AuthoredScene` renderer lookup all read this registry.
2329
2783
  - `registerTriggerAction` (function): function registerTriggerAction(definition: TriggerActionDefinition): void — Declare a game action the editor can assign to volume/marker triggers. Idempotent per `id` (last registration wins). Call at module load next to catalogs.
2330
2784
  - `relativeBearing` (function): function relativeBearing(bearing: number, reference: number): number — Signed offset of `bearing` from `reference`, wrapped into (−π, π].
@@ -2336,6 +2790,9 @@
2336
2790
  - `resolveControlGroupIntent` (function): function resolveControlGroupIntent(input: ControlGroupInput, options: ControlGroupOptions = {}): ControlGroupIntent — Resolve a control-group key press into a {@link ControlGroupIntent}: Ctrl+digit binds, a bare digit recalls, and a second recall of the same group within `doubleTapMs` focuses. Pure — the caller applies the intent against the store and its own focus hook, and records the returned recall for the next call.
2337
2791
  - `resolveEmitterGain` (function): function resolveEmitterGain(distance: number, sound: Pick<SoundDef, "gain" | "positional" | "falloff">, busGain: number): number — ⚠ undocumented
2338
2792
  - `resolveFacingRotationY` (function): function resolveFacingRotationY(headingDegrees: number, space?: Pick<AssetSpace, "forwardDegrees">): number — The Three.js Y-rotation that makes a model whose front is authored at `forwardDegrees` visually point `headingDegrees` (engine north = `0`). This is the catalog-owned replacement for per-game corrective yaw: a model authored facing south (`forwardDegrees: 180`) placed toward north resolves to `Math.PI`.
2793
+ - `resolveFlightStep` (function): function resolveFlightStep(position: readonly [number, number, number], stepX: number, stepY: number, stepZ: number, obstacles: readonly CollisionObstacle[], radius: number = DEFAULT_OBSTACLE_PLAYER_RADIUS): { stepX: number; stepY: number; stepZ: number } — Resolve a flight step against world solids (XZ slide + Y clamp).
2794
+ - `resolveFreeFlightIntent` (function): function resolveFreeFlightIntent(keys: MovementKeysState, analog: AnalogMoveIntent | null | undefined): FreeFlightIntent — Translate held keys + analog into a free-flight intent. Vertical is `space - (control|c)` so jump ascends and crouch descends — the same keys that walk/jump/crouch use, re-mapped for flight without re-binding.
2795
+ - `resolveFreeFlightIntentFromInput` (function): function resolveFreeFlightIntentFromInput(isDown: (action: string) => boolean, value: (action: string) => number, pointer: PointerAxisState | null, bindings?: FreeFlightBindings): FreeFlightIntent — Translate live input (held actions + analog + pointer) into a flight intent using per-profile axis bindings. Unlisted bindings fall back to the defaults above so existing games keep WASD/Space/Ctrl/Shift without declaring anything.
2339
2796
  - `resolveGridInstances` (function): function resolveGridInstances(config: WorldGridConfig | GridWorldFeature): readonly GridInstanceTransform[] — ⚠ undocumented
2340
2797
  - `resolveLocalAvoidance` (function): function resolveLocalAvoidance(agents: AvoidanceAgent[], options: LocalAvoidanceOptions = {}): number — Resolve overlaps in `agents` in place and return how many overlapping pairs remained on the final pass (`0` = fully separated). Uses a bounded uniform hash grid sized to the largest agent, so only nearby agents are ever compared. Deterministic: corrections are accumulated then applied per pass, independent of agent order. Pass `weights` to pin or differentially push agents.
2341
2798
  - `resolvePlaceAsset` (function): function resolvePlaceAsset(input: ResolvePlaceAssetInput): PlaceAssetResult — Resolve a place-asset intent into a shared payload (editor + games, one verb).
@@ -2386,7 +2843,7 @@
2386
2843
  - `sphereRegion` (function): function sphereRegion(center: Point3, radius: number, options: { distribution?: VolumeDistribution } = {}): SampleRegion<Point3> — A filled ball. `"volume"` is volume-uniform (∛-corrected radius); `"radial"` is radius-uniform. Direction is drawn first (two draws), then radius.
2387
2844
  - `steerYaw` (function): function steerYaw(yaw: number, steerRight: number, turnRatePerSecond: number, dt: number): number — Integrate one steering step. `steerRight` is the signed steer input (+1 = turn right, matching `DRIVE_AXIS_BINDINGS`' KeyD/ArrowRight), `turnRatePerSecond` is radians per second at full lock. Steering right decreases yaw in the engine frame; this helper owns that sign so game code never re-derives it.
2388
2845
  - `stepLock` (function): function stepLock(spec: LockSpec, col: number, row: number, action: LockAction): { result: LockStepResult; col: number; row: number } — Authoritative single step. The caller owns the lives economy: a slip/bind/trap does not advance the pick and should cost a life; advanced/success move the pick.
2389
- - `stepPlayerMovement` (function): function stepPlayerMovement(ctx: GameContext, userId: string, input: InputFrame, dt: number, tuning: PlayerMovementTuning, heading?: number): void — Integrate one player's movement for a tick from their held-input frame and commit the pose — the single genre-agnostic controller both the shell (its local player) and a host (each connected player in `onTick`) call, so single-player and server-authoritative movement are identical. Reads the player's controlled entity, terrain, scene solids, and pending motion impulses; writes the entity pose via `setPose`. Retains heading + kinematic body per `userId` on the `ctx`. Pass `heading` to override the internally-integrated yaw (the shell owns yaw for its camera); omit it and the controller turns from the frame's `turnLeft`/`turnRight` actions.
2846
+ - `stepPlayerMovement` (function): function stepPlayerMovement(ctx: GameContext, userId: string, input: InputFrame, dt: number, tuning: PlayerMovementTuning, heading?: number, pitch?: number): void — Integrate one player's movement for a tick from their held-input frame and commit the pose — the single genre-agnostic controller both the shell (its local player) and a host (each connected player in `onTick`) call, so single-player and server-authoritative movement are identical. Reads the player's controlled entity, terrain, scene solids, and pending motion impulses; writes the entity pose via `setPose`. Retains heading + kinematic body per `userId` on the `ctx`. Pass `heading` to override the internally-integrated yaw (the shell owns yaw for its camera); omit it and the controller turns from the frame's `turnLeft`/`turnRight` actions. Pass `pitch` for 6DOF spectator flight when `alignWithLook` is set.
2390
2847
  - `sumMagnitude` (function): function sumMagnitude<P>(memberships: readonly AreaMembership<P>[], magnitudeOf: MagnitudeOf<P>): number — Sum a numeric magnitude across memberships — additive aggregation for a total field strength (total damage per tick, total slow). A terminal reducer, not a filter, so it returns the number.
2391
2848
  - `summarizeElevation` (function): function summarizeElevation(sampleHeight: HeightSampler, region: GuideRegion, resolution = 64, maxSamples = 256): ElevationSummary — Summarises elevation across a region on a bounded sample grid: min, max, mean, relief range, and the world points of the extremes — the selection min/max and legend feedback the readability overlay reports, and the input to {@link chooseContourInterval}. Pure math, renderer-agnostic.
2392
2849
  - `summarizeEnvironment` (function): function summarizeEnvironment(feature: EnvironmentWorldFeature): EnvironmentSummary — ⚠ undocumented
@@ -2396,7 +2853,7 @@
2396
2853
  - `terrain` (function): function terrain(config: TerrainEnvironmentConfig = {}): TerrainEnvironmentDescriptor — Declares a heightfield terrain patch for `environment()` — bounds, noise, materials, and flatten masks.
2397
2854
  - `terrainContourGuides` (function): function terrainContourGuides(field: Pick<TerrainField, "sampleHeight">, region: GuideRegion, targetLines = 12, resolution = 128): { interval: number; summary: ElevationSummary; contours: ContourLine[] } — Convenience over {@link extractContours} that auto-picks the interval from the field's own relief: summarises the region, chooses a readable interval for `targetLines` bands, and traces the contours — the one call the editor overlay makes to turn a `TerrainField` into ready-to-draw guides. Returns an empty list for flat ground.
2398
2855
  - `themeLoopSeconds` (function): function themeLoopSeconds(theme: MusicTheme): number — Loop length of a theme in seconds.
2399
- - `tickDrivableVehicle` (function): function tickDrivableVehicle(vehicle: KinematicVehicle, dt: number, axis: AxisInput, options: DrivableVehicleOptions = {}): DrivableVehicleStep — Connects an `AxisInput` sample straight through a {@link KinematicVehicle} to a scene entity's pose for one tick (#533.1) — the throttle/steer/handbrake → sim → `setPose` loop every drivable-vehicle game hand-rolled. Ground-snaps the result when `groundHeight` is given (terrain-following cars, not just flat racetracks). Pair with `scene/vehicleSeat` for who is allowed to drive and where the camera points; this function only steps the sim and shapes the pose patch, nothing else.
2856
+ - `tickDrivableVehicle` (function): function tickDrivableVehicle<TStep extends DrivableSimStep = KinematicVehicleStep, TModifiers = KinematicVehicleModifiers>(vehicle: DrivableSim<TModifiers, TStep>, dt: number, axis: AxisInput, options: DrivableVehicleOptions<TModifiers> = {}): DrivableVehicleStep<TStep> — Connects an `AxisInput` sample straight through a ground-vehicle sim (`KinematicVehicle` or `VehicleDynamics`) to a scene entity's pose for one tick (#533.1) — the throttle/steer/handbrake → sim → `setPose` loop every drivable-vehicle game hand-rolled. Ground-snaps the result when `groundHeight` is given (terrain-following cars, not just flat racetracks). Pair with `scene/vehicleSeat` for who is allowed to drive and where the camera points; this function only steps the sim and shapes the pose patch, nothing else.
2400
2857
  - `tierForStanding` (function): function tierForStanding(tiers: readonly ReputationTier[], standing: number): ReputationTier — Map a faction standing value to its named reputation tier.
2401
2858
  - `tilemap` (function): function tilemap(config: TilemapWorldConfig): WorldFeature — Declares a 2D tilemap world from a map string.
2402
2859
  - `toDebrisBodies` (function): function toDebrisBodies(pieces: readonly SupportPiece[], collapsedIds: readonly string[], options: DebrisOptions = {}): AddBodyOptions[] — ⚠ undocumented
@@ -2446,6 +2903,13 @@
2446
2903
  - `placeAuthoredObjectsFromDocument` (function): function placeAuthoredObjectsFromDocument(store: AuthoredObjectPlaceTarget, document: AuthoredObjectsDocumentLike, sampleHeight: (x: number, z: number) => number, options: PlaceAuthoredObjectsOptions = {}): string[] — Convenience: resolve a document then place every authored catalog prop.
2447
2904
  - `resolveAuthoredObjects` (function): function resolveAuthoredObjects(document: AuthoredObjectsDocumentLike, options: ResolveAuthoredObjectsOptions = {}): AuthoredObject[] — Every marker carrying a catalog id, as placeable props — pure, no terrain sample. Parallel to {@link resolveScatter}: games and headless tests read the same list `<AuthoredObjects>` places. Entity-spawn kinds (`mob`/`boss`) are skipped by default — they carry a `catalogId` for their entity definition, but are spawned via `authoredEntitySpawns`, not placed as static meshes.
2448
2905
 
2906
+ ## @jgengine/core/world/authoredSolids
2907
+
2908
+ - `AUTHORED_SOLID_LAYER_PREFIX` (const): const AUTHORED_SOLID_LAYER_PREFIX: "authored:" — Layer prefix `syncAuthoredSolids` owns in `ctx.world.solids`; one layer per document object.
2909
+ - `AuthoredSolidsDocumentLike` (interface): interface AuthoredSolidsDocumentLike — Minimal editor document shape {@link resolveAuthoredSolids} walks; any `EditorDocument` satisfies it.
2910
+ - `resolveAuthoredSolids` (function): function resolveAuthoredSolids(document: AuthoredSolidsDocumentLike, sampleHeight?: (x: number, z: number) => number): Map<string, readonly WorldSolid[]> — Solids for every document object whose scene kind declares `solids`, keyed by object id. Objects whose kind has no `solids` hook, or whose hook returns none, are left out.
2911
+ - `syncAuthoredSolids` (function): function syncAuthoredSolids(solids: WorldSolids, document: AuthoredSolidsDocumentLike, sampleHeight?: (x: number, z: number) => number): void — Write a document's studio solids into `solids` (usually `ctx.world.solids`), one `authored:<objectId>` layer per object, dropping authored layers the document no longer has. Call again whenever the document changes.
2912
+
2449
2913
  ## @jgengine/core/world/authoredSpawn
2450
2914
 
2451
2915
  - `AuthoredSpawnDocumentLike` (interface): interface AuthoredSpawnDocumentLike — Minimal document shape spawn queries walk; any `EditorDocument` satisfies it.
@@ -2458,14 +2922,14 @@
2458
2922
 
2459
2923
  ## @jgengine/core/world/buildPermissions
2460
2924
 
2461
- - `BuildActor` (interface): interface BuildActor — ⚠ undocumented
2925
+ - `BuildActor` (interface): interface BuildActor { userId: string; guildId?: string } — ⚠ undocumented
2462
2926
  - `BuildRole` (type): type BuildRole = "owner" | "editor" | "viewer" — ⚠ undocumented
2463
2927
  - `ContributionGoal` (type): type ContributionGoal = Readonly<Record<string, number>> — ⚠ undocumented
2464
- - `ContributionPool` (interface): interface ContributionPool — ⚠ undocumented
2465
- - `ContributionResult` (interface): interface ContributionResult — ⚠ undocumented
2466
- - `PlotPermissionConfig` (interface): interface PlotPermissionConfig — ⚠ undocumented
2467
- - `PlotPermissionSnapshot` (interface): interface PlotPermissionSnapshot — ⚠ undocumented
2468
- - `PlotPermissions` (interface): interface PlotPermissions — ⚠ undocumented
2928
+ - `ContributionPool` (interface): interface ContributionPool { contribute(userId: string, resource: string, amount: number): ContributionResult; totals(): Readonly<Record<string, number>>; remaining(): Readonly<Record<string, number>>; byContributor(userId: string): Readonly<Record<string, number>>; … — ⚠ undocumented
2929
+ - `ContributionResult` (interface): interface ContributionResult { accepted: number; overflow: number; complete: boolean } — ⚠ undocumented
2930
+ - `PlotPermissionConfig` (interface): interface PlotPermissionConfig { plotId: string; ownerId: string; guildId?: string; roles?: Readonly<Record<string, BuildRole>>; guildRole?: BuildRole } — ⚠ undocumented
2931
+ - `PlotPermissionSnapshot` (interface): interface PlotPermissionSnapshot { plotId: string; ownerId: string; guildId?: string; roles: Readonly<Record<string, BuildRole>>; guildRole?: BuildRole } — ⚠ undocumented
2932
+ - `PlotPermissions` (interface): interface PlotPermissions { roleOf(actor: BuildActor): BuildRole | null; canEdit(actor: BuildActor): boolean; canView(actor: BuildActor): boolean; grant(userId: string, role: BuildRole): void; revoke(userId: string): void; setGuild(guildId: string | null, role?: Bui… — ⚠ undocumented
2469
2933
  - `createContributionPool` (function): function createContributionPool(goal: ContributionGoal): ContributionPool — ⚠ undocumented
2470
2934
  - `createPlotPermissions` (function): function createPlotPermissions(config: PlotPermissionConfig): PlotPermissions — ⚠ undocumented
2471
2935
 
@@ -2496,8 +2960,8 @@
2496
2960
 
2497
2961
  ## @jgengine/core/world/buildingIndex
2498
2962
 
2499
- - `BuildingHit` (interface): interface BuildingHit — ⚠ undocumented
2500
- - `BuildingIndex` (interface): interface BuildingIndex — ⚠ undocumented
2963
+ - `BuildingHit` (interface): interface BuildingHit { building: GeneratedBuilding; distance: number } — ⚠ undocumented
2964
+ - `BuildingIndex` (interface): interface BuildingIndex { readonly buildings: readonly GeneratedBuilding[]; at(point: Vec2): GeneratedBuilding | undefined; within(area: Aabb): GeneratedBuilding[]; nearest(point: Vec2): BuildingHit | undefined; isInside(point: Vec2): boolean; blockers(margin?: nu… — ⚠ undocumented
2501
2965
  - `buildingIndex` (function): function buildingIndex(buildings: readonly GeneratedBuilding[]): BuildingIndex — ⚠ undocumented
2502
2966
 
2503
2967
  ## @jgengine/core/world/buildingKit
@@ -2524,43 +2988,49 @@
2524
2988
 
2525
2989
  ## @jgengine/core/world/buildings
2526
2990
 
2527
- - `BUILDING_STYLE_PALETTES` (const): const BUILDING_STYLE_PALETTES: Record<BuildingStyle, BuildingPalette> — ⚠ undocumented
2528
- - `BuildingCellRef` (interface): interface BuildingCellRef — ⚠ undocumented
2529
- - `BuildingConfig` (interface): interface BuildingConfig — ⚠ undocumented
2530
- - `BuildingConfigInput` (type): type BuildingConfigInput = Partial< Omit<BuildingConfig, "probabilities" | "variants"> > & { probabilities?: Partial<BuildingProbabilities>; variants?: Partial<BuildingVariantCounts>; } — ⚠ undocumented
2991
+ - `BUILDING_STYLE_PALETTES` (const): const BUILDING_STYLE_PALETTES: Record<BuildingStyle, Record<BuildingPartKind, string>> — ⚠ undocumented
2992
+ - `BUILDING_STYLE_WALL_TONES` (const): const BUILDING_STYLE_WALL_TONES: Record<BuildingStyle, readonly string[]> — Per-style facade-tone family: the wall colours a district spreads across its buildings so neighbours differ in hue and value while the block stays one palette. Index 0 is the palette's own `wall`; the rest fan warmer/cooler and lighter/darker around it.
2993
+ - `BuildingCellRef` (interface): interface BuildingCellRef { facade: BuildingFacade; level: number; bay: number } — ⚠ undocumented
2994
+ - `BuildingConfig` (interface): interface BuildingConfig { id: string; seed: BuildingSeed; center: Vec2; floors: number; baysWide: number; baysDeep: number; bayWidth: number; floorHeight: number; facadeDepth: number; roofOverhang: number; probabilities: BuildingProbabilities; variants: BuildingVa… — ⚠ undocumented · used by `createBuildingConfig`: Fill a partial building description out to a complete {@link BuildingConfig}, clamping counts and probabilities.
2995
+ - `BuildingConfigInput` (type): type BuildingConfigInput = Partial< Omit<BuildingConfig, "probabilities" | "variants"> > & { probabilities?: Partial<BuildingProbabilities>; variants?: Partial<BuildingVariantCounts>; } — ⚠ undocumented · used by `createBuildingConfig`: Fill a partial building description out to a complete {@link BuildingConfig}, clamping counts and probabilities.
2531
2996
  - `BuildingFacade` (type): type BuildingFacade = "front" | "back" | "left" | "right" | "roof" — ⚠ undocumented
2532
- - `BuildingGridConfig` (interface): interface BuildingGridConfig — ⚠ undocumented
2533
- - `BuildingKitSlot` (interface): interface BuildingKitSlot — ⚠ undocumented
2534
- - `BuildingLot` (interface): interface BuildingLot — ⚠ undocumented
2535
- - `BuildingPalette` (type): type BuildingPalette = Record<BuildingPartKind, string> — ⚠ undocumented
2997
+ - `BuildingGridConfig` (interface): interface BuildingGridConfig { rows: number; columns: number; origin?: Vec2; lotSize?: Footprint; streetWidth?: number; seed?: BuildingSeed; idPrefix?: string; base?: BuildingConfigInput; floorRange?: readonly [number, number] } — ⚠ undocumented · used by `generateBuildingDistrict`: Generate a grid of buildings on lots sized by `lotSize` and separated by `streetWidth`, each with its floor count rolled from `floorRange`.
2998
+ - `BuildingKitSlot` (interface): interface BuildingKitSlot { key: string; variant: number } — ⚠ undocumented · used by `resolveBuildingKitPart` (@jgengine/core/world/buildingKit): Resolves one generated part against a kit.
2999
+ - `BuildingLot` (interface): interface BuildingLot { id: string; center: Vec2; footprint: Footprint; quarterTurns: number; config: BuildingConfig } — ⚠ undocumented
3000
+ - `BuildingPalette` (type): type BuildingPalette = Record<BuildingPartKind, BuildingSurface> — ⚠ undocumented
2536
3001
  - `BuildingPaletteOverrides` (type): type BuildingPaletteOverrides = Partial<BuildingPalette> — ⚠ undocumented
2537
- - `BuildingPartKind` (type): type BuildingPartKind = | "wall" | "window" | "awning" | "airConditioner" | "clothesline" | "storefront" | "shutter" | "storeSign" | "roof" | "roofProp" | "guardrail" | "corner" — ⚠ undocumented
2538
- - `BuildingPartPlacement` (interface): interface BuildingPartPlacement — ⚠ undocumented
3002
+ - `BuildingPartKind` (type): type BuildingPartKind = | "wall" | "window" | "awning" | "airConditioner" | "clothesline" | "storefront" | "shutter" | "storeSign" | "roof" | "roofProp" | "guardrail" | "corner" — ⚠ undocumented · used by `resolveBuildingKitPart` (@jgengine/core/world/buildingKit): Resolves one generated part against a kit.
3003
+ - `BuildingPartPlacement` (interface): interface BuildingPartPlacement { id: string; buildingId: string; kind: BuildingPartKind; facade: BuildingFacade; position: Vec3; rotationY: number; scale: Vec3; kit: BuildingKitSlot; cell?: BuildingCellRef; tags?: readonly BuildingPartTag[] } — ⚠ undocumented
2539
3004
  - `BuildingPartTag` (type): type BuildingPartTag = "ground" | "upper" | "open" | "closed" | "decor" | "structure" — ⚠ undocumented
2540
- - `BuildingProbabilities` (interface): interface BuildingProbabilities — ⚠ undocumented
3005
+ - `BuildingProbabilities` (interface): interface BuildingProbabilities { window: number; openStore: number; awning: number; airConditioner: number; clothesline: number; storeSign: number; roofProp: number } — ⚠ undocumented
2541
3006
  - `BuildingSeed` (type): type BuildingSeed = number | string — ⚠ undocumented
2542
- - `BuildingStyle` (type): type BuildingStyle = | "generic" | "capital" | "village" | "desert" | "industrial" | "coastal" | "neon" | "ruin" | "frontier" | "aerial" — ⚠ undocumented
2543
- - `BuildingVariantCounts` (interface): interface BuildingVariantCounts — ⚠ undocumented
3007
+ - `BuildingStyle` (type): type BuildingStyle = | "generic" | "capital" | "village" | "desert" | "industrial" | "coastal" | "neon" | "ruin" | "frontier" | "aerial" — ⚠ undocumented · used by `BUILDING_STYLE_WALL_TONES`: Per-style facade-tone family: the wall colours a district spreads across its buildings so neighbours differ in hue and value while the block…
3008
+ - `BuildingSurface` (type): type BuildingSurface = string | BuildingSurfaceMaterial — What a building part kind is painted with: a hex colour, or a colour plus tiled PBR maps.
3009
+ - `BuildingSurfaceMaps` (interface): interface BuildingSurfaceMaps — URLs of the PBR maps a building surface tiles; `buildMaterialCatalog(...).resolve(id)!.maps` fits directly.
3010
+ - `BuildingSurfaceMaterial` (interface): interface BuildingSurfaceMaterial — A textured building surface: a base colour plus optional tiled PBR maps. With `maps`, `color` multiplies the albedo (leave it light to show the map as authored); without, it is the flat colour the part has always had.
3011
+ - `BuildingVariantCounts` (interface): interface BuildingVariantCounts { wall: number; window: number; awning: number; airConditioner: number; clothesline: number; storefront: number; shutter: number; storeSign: number; roofProp: number } — ⚠ undocumented · used by `buildingKitVariantCounts` (@jgengine/core/world/buildingKit): The variant counts a kit actually supplies, shaped for `BuildingConfigInput.variants`.
2544
3012
  - `DEFAULT_BUILDING_CONFIG` (const): const DEFAULT_BUILDING_CONFIG: BuildingConfig — ⚠ undocumented
2545
3013
  - `DEFAULT_BUILDING_STYLE` (const): const DEFAULT_BUILDING_STYLE: BuildingStyle — ⚠ undocumented
2546
- - `GeneratedBuilding` (interface): interface GeneratedBuilding — ⚠ undocumented
2547
- - `Vec3` (type): type Vec3 = readonly [number, number, number] — ⚠ undocumented
3014
+ - `GeneratedBuilding` (interface): interface GeneratedBuilding { id: string; seed: BuildingSeed; center: Vec2; footprint: Footprint; floors: number; floorHeight: number; bounds: Aabb; parts: readonly BuildingPartPlacement[]; rotationY?: number } — ⚠ undocumented · used by `generateBuilding`: Generate one building as a flat list of placed facade parts: bays × floors per facade, a ground row, corners, and a roof, with every decorat…
3015
+ - `Vec3` (type): type Vec3 = readonly [number, number, number] — ⚠ undocumented · used by `coverPoints` (@jgengine/core/ai/tacticalQueries): Returns boundary locations that are hidden from a threat.
3016
+ - `buildingSurfaceColor` (function): function buildingSurfaceColor(surface: BuildingSurface | undefined, fallback = "#808080"): string — The flat colour of a surface: the hex itself, or a material's `color`, else `fallback`.
2548
3017
  - `createBuildingConfig` (function): function createBuildingConfig(input: BuildingConfigInput = {}): BuildingConfig — Fill a partial building description out to a complete {@link BuildingConfig}, clamping counts and probabilities. Use it to inspect or adjust the resolved shape before generating.
2549
3018
  - `generateBuilding` (function): function generateBuilding(input: BuildingConfigInput = {}): GeneratedBuilding — Generate one building as a flat list of placed facade parts: bays × floors per facade, a ground row, corners, and a roof, with every decorative part rolled from `probabilities` and every part tagged with a `kit` slot the renderer binds to a model (see `world/buildingKit`). Deterministic from `seed`.
2550
3019
  - `generateBuildingDistrict` (function): function generateBuildingDistrict(config: BuildingGridConfig): GeneratedBuilding[] — Generate a grid of buildings on lots sized by `lotSize` and separated by `streetWidth`, each with its floor count rolled from `floorRange`.
3020
+ - `resolveBuildingSurface` (function): function resolveBuildingSurface(surface: BuildingSurface): BuildingSurfaceMaterial — Normalises a surface to its material form so a renderer reads one shape.
2551
3021
 
2552
3022
  ## @jgengine/core/world/carve
2553
3023
 
2554
3024
  - `CarvableField` (class): class CarvableField implements TerrainField — A `TerrainField` you can write craters and mounds into at runtime — the height-field side of destructible terrain (Helldivers 2 explosion craters, engineer-deposited berms). Wraps a base field and layers smooth radial deformations on top, so `sampleHeight` (and therefore ground-snap, collision, and the shell's terrain mesh) all read the deformed surface. `carve` digs a bowl, `deposit` raises a mound.
2555
- - `CarveOp` (interface): interface CarveOp — ⚠ undocumented
2556
- - `CraterOp` (interface): interface CraterOp — ⚠ undocumented
2557
- - `DepositOp` (interface): interface DepositOp — ⚠ undocumented
3025
+ - `CarveOp` (interface): interface CarveOp { center: readonly [number, number, number]; radius: number; toolStrength?: number } — ⚠ undocumented
3026
+ - `CraterOp` (interface): interface CraterOp { x: number; z: number; radius: number; depth: number } — ⚠ undocumented
3027
+ - `DepositOp` (interface): interface DepositOp { center: readonly [number, number, number]; radius: number; material: number } — ⚠ undocumented
2558
3028
  - `EMPTY_VOXEL` (const): const EMPTY_VOXEL: 0 — ⚠ undocumented
2559
- - `MoundOp` (interface): interface MoundOp — ⚠ undocumented
2560
- - `VoxelMaterial` (interface): interface VoxelMaterial — ⚠ undocumented
3029
+ - `MoundOp` (interface): interface MoundOp { x: number; z: number; radius: number; height: number } — ⚠ undocumented
3030
+ - `VoxelMaterial` (interface): interface VoxelMaterial { id: number; name: string; strength: number; drop?: string } — ⚠ undocumented
2561
3031
  - `VoxelMaterialTable` (type): type VoxelMaterialTable = Readonly<Record<number, VoxelMaterial>> — ⚠ undocumented
2562
3032
  - `VoxelVolume` (class): class VoxelVolume — A runtime-editable dense voxel grid — the carve/deposit op behind destructible dig worlds (Deep Rock Galactic tunnels, Astroneer terrain). Cells hold a material id (0 = empty); `carve` clears a sphere of solid cells that a tool is strong enough to break and returns how many it removed (feed that to a loot roll), `deposit` fills a sphere with a material. World↔cell mapping is `origin`+`scale`.
2563
- - `VoxelVolumeConfig` (interface): interface VoxelVolumeConfig — ⚠ undocumented
3033
+ - `VoxelVolumeConfig` (interface): interface VoxelVolumeConfig { dims: readonly [number, number, number]; origin?: readonly [number, number, number]; scale?: number; fill?: number; materials?: VoxelMaterialTable } — ⚠ undocumented
2564
3034
  - `carvableTerrain` (function): function carvableTerrain(base: TerrainField): CarvableField — ⚠ undocumented
2565
3035
 
2566
3036
  ## @jgengine/core/world/catenary
@@ -2571,9 +3041,9 @@
2571
3041
 
2572
3042
  ## @jgengine/core/world/cellStates
2573
3043
 
2574
- - `CellRef` (interface): interface CellRef — ⚠ undocumented
3044
+ - `CellRef` (interface): interface CellRef { col: number; row: number } — ⚠ undocumented
2575
3045
  - `CellStateGrid` (interface): interface CellStateGrid<TState extends string> — A uniform world grid whose cells step through a discrete state ladder — pristine → cracked → burning → ruined — driven by whatever world events the game routes in (#284.8). Pure storage plus ladder mechanics; the game decides *when* to escalate, the grid guarantees ordered, clamped steps and cheap queries. `version()` bumps on every change for dirty-checked rendering.
2576
- - `CellStateGridConfig` (interface): interface CellStateGridConfig<TState extends string> — ⚠ undocumented
3046
+ - `CellStateGridConfig` (interface): interface CellStateGridConfig<TState extends string> { cols: number; rows: number; states: readonly TState[]; origin?: readonly [number, number]; cellSize?: number } — ⚠ undocumented
2577
3047
  - `createCellStateGrid` (function): function createCellStateGrid<TState extends string>(config: CellStateGridConfig<TState>): CellStateGrid<TState> — ⚠ undocumented
2578
3048
 
2579
3049
  ## @jgengine/core/world/cityBlocks
@@ -2691,24 +3161,33 @@
2691
3161
  - `CityParcelFrontageOut` (interface): interface CityParcelFrontageOut — One street-frontage edge of a parcel.
2692
3162
  - `CityPark` (interface): interface CityPark — One intentional open space: an unbuilt block, a block-interior courtyard, or a buffer sliver.
2693
3163
  - `CityParking` (interface): interface CityParking — One parking pad behind a commercial lot.
3164
+ - `CityRaceGridSlot` (interface): interface CityRaceGridSlot — One staggered spawn behind the start line.
3165
+ - `CityRaceKerb` (interface): interface CityRaceKerb — One kerb strip hugging a corner's road edge, as a world-space polyline to stripe.
3166
+ - `CityRaceSeal` (interface): interface CityRaceSeal — One street closed off where it leaves the race lap: world XZ, the yaw down the sealed street, and the width the barrier run spans.
3167
+ - `CityRaceStart` (interface): interface CityRaceStart — The start/finish line: where it is, which way cars face, and the painted line across the road.
2694
3168
  - `CityResolveContext` (interface): interface CityResolveContext extends SceneKindResolveContext — Extended resolve context: sibling `cityzone` volumes that override the band/mix locally.
2695
3169
  - `CityRules` (interface): interface CityRules — Fully-defaulted city params parsed from a volume's `meta`.
3170
+ - `CitySignal` (interface): interface CitySignal — One junction control on an approach arm: an arterial mast-arm signal, or a plain sign post.
2696
3171
  - `CityStreet` (interface): interface CityStreet — One synthesized street: a world-space XZ polyline with width, hierarchy level, and surface.
2697
3172
  - `CityTree` (interface): interface CityTree — One placed tree: world XZ, species, and seeded scale/color jitter.
2698
3173
  - `CityTunnel` (interface): interface CityTunnel — One tunnel bore piercing a ridge: portal-to-portal polyline held at bank height.
3174
+ - `CityVehicle` (interface): interface CityVehicle — One parked vehicle standing at a curb or nose-in inside a parking pad.
3175
+ - `CityVehicleKind` (type): type CityVehicleKind = "car" | "van" | "truck" — Silhouette class of a parked vehicle — sizes the body the renderer instances.
2699
3176
  - `ResolvedCity` (interface): interface ResolvedCity — A resolved city district: world-space network, zoned lots, parks, and furniture.
3177
+ - `ResolvedRace` (interface): interface ResolvedRace — An instanced street race lifted out of the district's OWN streets: a closed lap through the city, with every side street leaving it sealed off. World space, like the rest of {@link ResolvedCity}.
3178
+ - `citySolids` (function): function citySolids(city: ResolvedCity, sampleHeight: (x: number, z: number) => number = () => 0): WorldSolid[] — One solid per wall and roof piece of every lot, grounded the way the city renderer grounds it: grade at the highest lot corner, foundations down to half a metre under the lowest.
2700
3179
  - `resolveCityObject` (function): function resolveCityObject(object: SceneKindObject, context?: CityResolveContext): ResolvedCity | null — Synthesize the deterministic city plan for one `city` volume: streets → bridges → parks → zoned frontage lots with massing pieces → furniture, all in the volume's local frame and then rotated/translated into world space. Same volume (id, footprint, meta) over the same terrain always resolves to the identical plan. When `context` provides a ground sampler, lots respect the `maxSlope` cliff rule — hillside and canyon districts keep their steep faces open. When `context.zoneOverrides` carries sibling `cityzone` volumes, lots inside them adopt the override band/mix. Returns null without a usable footprint.
2701
3180
 
2702
3181
  ## @jgengine/core/world/connectors
2703
3182
 
2704
- - `ConnectorPieceDef` (interface): interface ConnectorPieceDef — ⚠ undocumented
3183
+ - `ConnectorPieceDef` (interface): interface ConnectorPieceDef { kind: string; sockets: readonly ConnectorSocket[] } — ⚠ undocumented
2705
3184
  - `ConnectorRegistry` (type): type ConnectorRegistry = (kind: string) => ConnectorPieceDef | null — ⚠ undocumented
2706
- - `ConnectorSocket` (interface): interface ConnectorSocket — ⚠ undocumented
3185
+ - `ConnectorSocket` (interface): interface ConnectorSocket { id: string; type: string; offset: ConnectorVec3; accepts?: readonly string[] } — ⚠ undocumented
2707
3186
  - `ConnectorVec3` (type): type ConnectorVec3 = readonly [number, number, number] — ⚠ undocumented
2708
- - `PlacedPiece` (interface): interface PlacedPiece — ⚠ undocumented
2709
- - `SnapOptions` (interface): interface SnapOptions — ⚠ undocumented
2710
- - `SnapResult` (interface): interface SnapResult — ⚠ undocumented
2711
- - `WorldSocket` (interface): interface WorldSocket — ⚠ undocumented
3187
+ - `PlacedPiece` (interface): interface PlacedPiece { id: string; kind: string; position: ConnectorVec3; rotationY: number } — ⚠ undocumented
3188
+ - `SnapOptions` (interface): interface SnapOptions { snapDistance?: number; rotationY?: number } — ⚠ undocumented
3189
+ - `SnapResult` (interface): interface SnapResult { socketId: string; targetPieceId: string; targetSocketId: string; position: ConnectorVec3; rotationY: number; distance: number } — ⚠ undocumented
3190
+ - `WorldSocket` (interface): interface WorldSocket { pieceId: string; socket: ConnectorSocket; position: ConnectorVec3 } — ⚠ undocumented
2712
3191
  - `collectWorldSockets` (function): function collectWorldSockets(registry: ConnectorRegistry, pieces: readonly PlacedPiece[]): WorldSocket[] — ⚠ undocumented
2713
3192
  - `snapToNearest` (function): function snapToNearest(registry: ConnectorRegistry, placed: readonly PlacedPiece[], movingDef: ConnectorPieceDef, cursor: ConnectorVec3, options: SnapOptions = {}): SnapResult | null — ⚠ undocumented
2714
3193
  - `socketWorldPosition` (function): function socketWorldPosition(socket: ConnectorSocket, origin: ConnectorVec3, rotationY: number): ConnectorVec3 — ⚠ undocumented
@@ -2717,9 +3196,9 @@
2717
3196
 
2718
3197
  ## @jgengine/core/world/envField
2719
3198
 
2720
- - `EnvironmentField` (interface): interface EnvironmentField — ⚠ undocumented
2721
- - `EnvironmentFieldConfig` (interface): interface EnvironmentFieldConfig — ⚠ undocumented
2722
- - `EnvironmentSample` (interface): interface EnvironmentSample — ⚠ undocumented
3199
+ - `EnvironmentField` (interface): interface EnvironmentField { sample(x: number, z: number, time: number, y?: number): EnvironmentSample; temperature(x: number, z: number, time: number, y?: number): number; wetness(x: number, z: number, time: number): number; lightExposure(x: number, z: number, time:… — ⚠ undocumented · used by `createEnvironmentField`: A sampleable environment field: read temperature, wetness, sun/sky exposure, and ambient light at any world position and time.
3200
+ - `EnvironmentFieldConfig` (interface): interface EnvironmentFieldConfig { dayLength?: number; baseTemperature?: number; nightDrop?: number; altitudeLapse?: number; seaLevel?: number; terrain?: TerrainField; rain?: ScalarField; occluders?: ShadeProvider; heatSources?: readonly HeatSource[]; ambientFloor?: number… — ⚠ undocumented · used by `createEnvironmentField`: A sampleable environment field: read temperature, wetness, sun/sky exposure, and ambient light at any world position and time.
3201
+ - `EnvironmentSample` (interface): interface EnvironmentSample { temperature: number; wetness: number; lightExposure: number; ambientLight: number; sheltered: boolean } — ⚠ undocumented
2723
3202
  - `HeatSource` (interface): interface HeatSource — A localized warmth source — campfire, forge, geothermal vent.
2724
3203
  - `OccluderRect` (interface): interface OccluderRect — A sky-occluding footprint — a roof, dense canopy, a cave mouth. `shade` 0..1 = fraction of sky blocked.
2725
3204
  - `ScalarField` (type): type ScalarField = number | ((x: number, z: number, time: number) => number) — ⚠ undocumented
@@ -2728,16 +3207,16 @@
2728
3207
 
2729
3208
  ## @jgengine/core/world/environmentSummary
2730
3209
 
2731
- - `EnvironmentCounts` (interface): interface EnvironmentCounts — ⚠ undocumented
2732
- - `EnvironmentSummary` (interface): interface EnvironmentSummary — ⚠ undocumented
2733
- - `IslandSummary` (interface): interface IslandSummary extends TerrainSummary — ⚠ undocumented
3210
+ - `EnvironmentCounts` (interface): interface EnvironmentCounts { terrain: number; islands: number; structureGroups: number; buildings: number; buildingParts: number; vegetationFields: number; waterBodies: number; weatherSystems: number; roads: number } — ⚠ undocumented
3211
+ - `EnvironmentSummary` (interface): interface EnvironmentSummary { terrain?: TerrainSummary; islands: readonly IslandSummary[]; structures: readonly StructureSummary[]; vegetation: readonly VegetationSummary[]; water: readonly WaterSummary[]; weather: readonly WeatherSummary[]; roads: readonly RoadSummar… — ⚠ undocumented
3212
+ - `IslandSummary` (interface): interface IslandSummary extends TerrainSummary { origin: readonly [number, number] } — ⚠ undocumented
2734
3213
  - `RoadSummary` (interface): interface RoadSummary — One road descriptor's resolved footprint: vertex count, width, and total centerline length.
2735
- - `StructureSummary` (interface): interface StructureSummary — ⚠ undocumented
2736
- - `TerrainHeightStats` (interface): interface TerrainHeightStats — ⚠ undocumented
2737
- - `TerrainSummary` (interface): interface TerrainSummary — ⚠ undocumented
2738
- - `VegetationSummary` (interface): interface VegetationSummary — ⚠ undocumented
2739
- - `WaterSummary` (interface): interface WaterSummary — ⚠ undocumented
2740
- - `WeatherSummary` (interface): interface WeatherSummary — ⚠ undocumented
3214
+ - `StructureSummary` (interface): interface StructureSummary { style: BuildingStyle; palette: BuildingPalette; requested: number; buildings: number; parts: number; bounds: Aabb } — ⚠ undocumented
3215
+ - `TerrainHeightStats` (interface): interface TerrainHeightStats { min: number; max: number; mean: number; finite: boolean } — ⚠ undocumented
3216
+ - `TerrainSummary` (interface): interface TerrainSummary { bounds: WorldBounds; height: TerrainHeightStats; palette: TerrainPalette; waterLevel?: number } — ⚠ undocumented
3217
+ - `VegetationSummary` (interface): interface VegetationSummary { area: EnvironmentArea; density: number } — ⚠ undocumented
3218
+ - `WaterSummary` (interface): interface WaterSummary { level: number; bounds: WorldBounds } — ⚠ undocumented
3219
+ - `WeatherSummary` (interface): interface WeatherSummary { kind: "rain" | "snow"; area: EnvironmentArea; density: number } — ⚠ undocumented
2741
3220
  - `resolveStructureBuildings` (function): function resolveStructureBuildings(descriptor: BuildingEnvironmentDescriptor): GeneratedBuilding[] — ⚠ undocumented
2742
3221
  - `summarizeEnvironment` (function): function summarizeEnvironment(feature: EnvironmentWorldFeature): EnvironmentSummary — ⚠ undocumented
2743
3222
 
@@ -2755,56 +3234,57 @@
2755
3234
  - `BiomeBand` (interface): interface BiomeBand — A z-ordered ground palette zone — the linear-boundary counterpart to the radial `materialRegions`. Adjacent bands cross-fade into each other across a `fade`-wide window centered on the midpoint z between their centers, so a multi-biome world (vale → marsh → peaks along z) blends its ground color instead of hard-switching. Bands may also carry per-zone `fog`, `sky`, and `weather`. Order the list by ascending `z`.
2756
3235
  - `BiomeFog` (interface): interface BiomeFog — Per-band fog override cross-faded along z by `createBiomeFogSampler`; unset fields fall through to the base sky fog.
2757
3236
  - `BiomeSky` (interface): interface BiomeSky — Per-band sky/light override cross-faded along z by `createBiomeSkySampler`; unset fields fall through to the base sky.
2758
- - `BiomesWorldConfig` (interface): interface BiomesWorldConfig extends WorldGridConfig — ⚠ undocumented
2759
- - `BuildingEnvironmentConfig` (interface): interface BuildingEnvironmentConfig — ⚠ undocumented
2760
- - `BuildingEnvironmentDescriptor` (type): type BuildingEnvironmentDescriptor = { kind: "building" } & Required< Pick<BuildingEnvironmentConfig, "count" | "footprint" | "stories" | "storyHeight" | "spacing" | "style"> > & Pick<BuildingEnvironmentConfig, "seed" | "position" | "palette" | "along" | "kit"> — ⚠ undocumented
3237
+ - `BiomesWorldConfig` (interface): interface BiomesWorldConfig extends WorldGridConfig { map: string; zones: string; bounds?: WorldBounds } — ⚠ undocumented · used by `biomes`: Declares a biome-painted world — the whole-world alternative to a single `environment()` terrain.
3238
+ - `BuildingEnvironmentConfig` (interface): interface BuildingEnvironmentConfig { count?: number; position?: EnvironmentVec2; footprint?: WorldBounds; stories?: readonly [number, number]; storyHeight?: number; spacing?: number; style?: BuildingStyle; palette?: BuildingPaletteOverrides; seed?: string; along?: BuildingFr… — ⚠ undocumented · used by `building`: Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style.
3239
+ - `BuildingEnvironmentDescriptor` (type): type BuildingEnvironmentDescriptor = { kind: "building" } & Required< Pick<BuildingEnvironmentConfig, "count" | "footprint" | "stories" | "storyHeight" | "spacing" | "style"> > & Pick<BuildingEnvironmentConfig, "seed" | "position" | "palette" | "along" | "kit" | "solid"> — ⚠ undocumented · used by `building`: Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style.
2761
3240
  - `BuildingFrontageConfig` (interface): interface BuildingFrontageConfig — Street-aware placement for `building()`: instead of a grid scattered around `position`, lots are stepped along each road's frontage, offset by a consistent setback (a curb + sidewalk strip), and turned so every building FRONT faces its road. `footprint` (`w` = frontage width, `d` = depth) and `spacing` (along-road gap) are shared with the grid mode. Deterministic and bounded by `maxLots`.
2762
3241
  - `BuildingFrontageRoad` (interface): interface BuildingFrontageRoad — One road a `building({ along })` frontage lines with buildings: centerline + full width.
2763
- - `EnvironmentArea` (interface): interface EnvironmentArea extends WorldBounds — ⚠ undocumented
3242
+ - `EnvironmentArea` (interface): interface EnvironmentArea extends WorldBounds { h?: number; position?: EnvironmentVec2 } — ⚠ undocumented
2764
3243
  - `EnvironmentDescriptorList` (type): type EnvironmentDescriptorList<T> = T | readonly T[] — ⚠ undocumented
2765
3244
  - `EnvironmentVec2` (type): type EnvironmentVec2 = readonly [number, number] — ⚠ undocumented
2766
- - `EnvironmentWorldConfig` (interface): interface EnvironmentWorldConfig — ⚠ undocumented
2767
- - `EnvironmentWorldFeature` (interface): interface EnvironmentWorldFeature — ⚠ undocumented
2768
- - `GrassEnvironmentConfig` (interface): interface GrassEnvironmentConfig — ⚠ undocumented
2769
- - `GrassEnvironmentDescriptor` (type): type GrassEnvironmentDescriptor = { kind: "grass" } & Required< Pick<GrassEnvironmentConfig, "area" | "density" | "bladeHeight" | "bladeWidth" | "windStrength" | "colors"> > & Pick<GrassEnvironmentConfig, "seed"> — ⚠ undocumented
2770
- - `OceanEnvironmentConfig` (interface): interface OceanEnvironmentConfig — ⚠ undocumented
2771
- - `OceanEnvironmentDescriptor` (type): type OceanEnvironmentDescriptor = { kind: "ocean" } & Required< Pick<OceanEnvironmentConfig, "bounds" | "level" | "waveHeight" | "waveScale" | "waveSpeed" | "color"> > & Pick<OceanEnvironmentConfig, "position" | "levelAt"> — ⚠ undocumented
2772
- - `PadEnvironmentConfig` (interface): interface PadEnvironmentConfig — ⚠ undocumented
2773
- - `PadEnvironmentDescriptor` (type): type PadEnvironmentDescriptor = { kind: "pad" } & Required< Pick<PadEnvironmentConfig, "center" | "size" | "height" | "color"> > & Pick<PadEnvironmentConfig, "rotationY" | "elevation"> — ⚠ undocumented
3245
+ - `EnvironmentWorldConfig` (interface): interface EnvironmentWorldConfig { terrain?: TerrainEnvironmentDescriptor; islands?: readonly TerrainIslandDescriptor[]; sky?: SkyEnvironmentDescriptor; weather?: EnvironmentDescriptorList<WeatherEnvironmentDescriptor>; vegetation?: EnvironmentDescriptorList<VegetationEnvi… — ⚠ undocumented · used by `environment`: Composes an `environment()` feature from terrain, sky, weather, vegetation, water, structures, roads, and pads.
3246
+ - `EnvironmentWorldFeature` (interface): interface EnvironmentWorldFeature { kind: "environment"; terrain?: TerrainEnvironmentDescriptor; islands?: readonly TerrainIslandDescriptor[]; sky?: SkyEnvironmentDescriptor; weather?: readonly WeatherEnvironmentDescriptor[]; vegetation?: readonly VegetationEnvironmentDescr… — ⚠ undocumented · used by `environment`: Composes an `environment()` feature from terrain, sky, weather, vegetation, water, structures, roads, and pads.
3247
+ - `GrassEnvironmentConfig` (interface): interface GrassEnvironmentConfig { area?: EnvironmentArea; position?: EnvironmentVec2; density?: number; bladeHeight?: readonly [number, number]; bladeWidth?: number; windStrength?: number; colors?: readonly string[]; seed?: string; bladeBend?: readonly [number, number]; t… — ⚠ undocumented · used by `grass`: Declares a grass vegetation patch for `environment()` — area, blade sizing, density, and colors.
3248
+ - `GrassEnvironmentDescriptor` (type): type GrassEnvironmentDescriptor = { kind: "grass" } & Required< Pick<GrassEnvironmentConfig, "area" | "density" | "bladeHeight" | "bladeWidth" | "windStrength" | "colors"> > & Pick<GrassEnvironmentConfig, "seed" | "bladeBend" | "tuftRadius" | "colorVariation" | "normalLift"> — ⚠ undocumented · used by `grass`: Declares a grass vegetation patch for `environment()` — area, blade sizing, density, and colors.
3249
+ - `OceanEnvironmentConfig` (interface): interface OceanEnvironmentConfig { bounds?: WorldBounds; position?: EnvironmentVec2; level?: number; levelAt?: (time: number) => number; waveHeight?: number; waveScale?: number; waveSpeed?: number; color?: string } — ⚠ undocumented · used by `ocean`: Declares an ocean water body for `environment()` — bounds, level, and wave tuning.
3250
+ - `OceanEnvironmentDescriptor` (type): type OceanEnvironmentDescriptor = { kind: "ocean" } & Required< Pick<OceanEnvironmentConfig, "bounds" | "level" | "waveHeight" | "waveScale" | "waveSpeed" | "color"> > & Pick<OceanEnvironmentConfig, "position" | "levelAt"> — ⚠ undocumented · used by `ocean`: Declares an ocean water body for `environment()` — bounds, level, and wave tuning.
3251
+ - `PadEnvironmentConfig` (interface): interface PadEnvironmentConfig { center: EnvironmentVec2; size: PadSize; height?: number; elevation?: number; color?: string; rotationY?: number } — ⚠ undocumented
3252
+ - `PadEnvironmentDescriptor` (type): type PadEnvironmentDescriptor = { kind: "pad" } & Required< Pick<PadEnvironmentConfig, "center" | "size" | "height" | "color"> > & Pick<PadEnvironmentConfig, "rotationY" | "elevation"> — ⚠ undocumented · used by `padFlattenMasks`: Derives implicit `TerrainFlattenMask`s carving each pad's footprint into the terrain beneath it.
2774
3253
  - `PadSize` (type): type PadSize = readonly [number, number] | { radius: number } — ⚠ undocumented
2775
- - `PlotsWorldConfig` (interface): interface PlotsWorldConfig extends WorldGridConfig — ⚠ undocumented
2776
- - `RainEnvironmentConfig` (interface): interface RainEnvironmentConfig — ⚠ undocumented
2777
- - `RainEnvironmentDescriptor` (type): type RainEnvironmentDescriptor = { kind: "rain" } & Required< Pick<RainEnvironmentConfig, "area" | "density" | "speed" | "dropLength" | "wind" | "color" | "width" | "opacity"> > — ⚠ undocumented
3254
+ - `PlotsWorldConfig` (interface): interface PlotsWorldConfig extends WorldGridConfig { city?: string; interiors?: string } — ⚠ undocumented · used by `plots`: Declares a subdivided-plots world — farming, base-building, and other parcel-based layouts.
3255
+ - `RainEnvironmentConfig` (interface): interface RainEnvironmentConfig { area?: EnvironmentArea; position?: EnvironmentVec2; density?: number; speed?: number; dropLength?: number; wind?: EnvironmentVec2; color?: string; width?: number; opacity?: number } — ⚠ undocumented · used by `rain`: Declares a rainfall weather effect for `environment()` — area, density, speed, wind, and drop width/opacity.
3256
+ - `RainEnvironmentDescriptor` (type): type RainEnvironmentDescriptor = { kind: "rain" } & Required< Pick<RainEnvironmentConfig, "area" | "density" | "speed" | "dropLength" | "wind" | "color" | "width" | "opacity"> > — ⚠ undocumented · used by `rain`: Declares a rainfall weather effect for `environment()` — area, density, speed, wind, and drop width/opacity.
2778
3257
  - `RoadEnvironmentConfig` (interface): interface RoadEnvironmentConfig — Config for {@link road}: a flat asphalt ribbon draped over the terrain along a centerline.
2779
3258
  - `RoadEnvironmentDescriptor` (type): type RoadEnvironmentDescriptor = { kind: "road" } & Required< Pick<RoadEnvironmentConfig, "path" | "width" | "color" | "markings" | "markingColor" | "elevation"> > & { /** Resolved sidewalk band, or `false` when the road has none. */ sidewalk: { width: number; color: string } | false; } — Resolved road descriptor produced by {@link road} and rendered by the shell environment scene.
2780
- - `SkyEnvironmentConfig` (interface): interface SkyEnvironmentConfig — ⚠ undocumented
3259
+ - `SkyEnvironmentConfig` (interface): interface SkyEnvironmentConfig { preset?: "day" | "dusk" | "night"; timeOfDay?: boolean; horizonColor?: string; zenithColor?: string; sunIntensity?: number; ambientIntensity?: number; sun?: SkySunConfig; radius?: number; hazeStrength?: number; sunGlowStrength?: number; g… — ⚠ undocumented · used by `CINEMATIC_SKY` (@jgengine/core/render/lookPreset): A static day sky: a real dome plus the shell's view-following shadow-casting sun and hemisphere fill.
2781
3260
  - `SkyEnvironmentDescriptor` (type): type SkyEnvironmentDescriptor = { kind: "sky" } & Required< Pick<SkyEnvironmentConfig, "preset" | "timeOfDay"> > & Omit<SkyEnvironmentConfig, "preset" | "timeOfDay"> — ⚠ undocumented
2782
- - `SnowEnvironmentConfig` (interface): interface SnowEnvironmentConfig — ⚠ undocumented
2783
- - `SnowEnvironmentDescriptor` (type): type SnowEnvironmentDescriptor = { kind: "snow" } & Required< Pick<SnowEnvironmentConfig, "area" | "density" | "speed" | "flakeSize" | "drift" | "wind" | "color" | "opacity"> > — ⚠ undocumented
3261
+ - `SkySunConfig` (interface): interface SkySunConfig — Where the sun sits, as a compass bearing and a height above the horizon, both in degrees. `azimuth` 0 points toward -Z (north), 90 toward +X (east); `elevation` 90 is straight overhead.
3262
+ - `SnowEnvironmentConfig` (interface): interface SnowEnvironmentConfig { area?: EnvironmentArea; position?: EnvironmentVec2; density?: number; speed?: number; flakeSize?: number; drift?: number; wind?: EnvironmentVec2; color?: string; opacity?: number } — ⚠ undocumented · used by `snow`: Declares a snowfall weather effect for `environment()` — area, density, drift, wind, and flake opacity.
3263
+ - `SnowEnvironmentDescriptor` (type): type SnowEnvironmentDescriptor = { kind: "snow" } & Required< Pick<SnowEnvironmentConfig, "area" | "density" | "speed" | "flakeSize" | "drift" | "wind" | "color" | "opacity"> > — ⚠ undocumented · used by `snow`: Declares a snowfall weather effect for `environment()` — area, density, drift, wind, and flake opacity.
2784
3264
  - `StructureEnvironmentDescriptor` (type): type StructureEnvironmentDescriptor = BuildingEnvironmentDescriptor — ⚠ undocumented
2785
3265
  - `TerrainCircleRegion` (interface): interface TerrainCircleRegion extends TerrainRegionStyle — A circular palette zone painted over the base terrain palette — snow caps, ash wastes, spawn circles.
2786
- - `TerrainColors` (interface): interface TerrainColors — ⚠ undocumented
3266
+ - `TerrainColors` (interface): interface TerrainColors { low?: string; high?: string; waterline?: string } — ⚠ undocumented
2787
3267
  - `TerrainDetailConfig` (interface): interface TerrainDetailConfig — Procedural detail-surface layer for terrain: a noise-driven shader that keeps the biome-tinted base ground (from `colors`/`biomeBands`) and blends distinct rock, sand, and snow over it by slope, height, and waterline — turning a flat vertex-colour surface into varied, textured-reading ground with no image assets.
2788
3268
  - `TerrainDetailMaterialConfig` (interface): interface TerrainDetailMaterialConfig — Real PBR texture applied over the ground surface — the seam that lets a game put a `buildMaterialCatalog` material on terrain. Blends with, never replaces, the procedural detail shader: color/roughness/ao tile the maps by world position, `strength` fades them over the existing vertex-colour + noise look.
2789
- - `TerrainEnvironmentConfig` (interface): interface TerrainEnvironmentConfig — ⚠ undocumented
2790
- - `TerrainEnvironmentDescriptor` (type): type TerrainEnvironmentDescriptor = { kind: "terrain" } & Required< Pick<TerrainEnvironmentConfig, "bounds" | "height"> > & Omit<TerrainEnvironmentConfig, "bounds" | "height"> — ⚠ undocumented
2791
- - `TerrainFlattenMask` (interface): interface TerrainFlattenMask — ⚠ undocumented
3269
+ - `TerrainEnvironmentConfig` (interface): interface TerrainEnvironmentConfig { bounds?: WorldBounds; height?: number; heightMap?: string; heightField?: (x: number, z: number) => number; material?: TerrainMaterial; colors?: TerrainColors; materialRegions?: readonly TerrainMaterialRegion[]; biomeBands?: readonly Biome… — ⚠ undocumented · used by `terrain`: Declares a heightfield terrain patch for `environment()` — bounds, noise, materials, and flatten masks.
3270
+ - `TerrainEnvironmentDescriptor` (type): type TerrainEnvironmentDescriptor = { kind: "terrain" } & Required< Pick<TerrainEnvironmentConfig, "bounds" | "height"> > & Omit<TerrainEnvironmentConfig, "bounds" | "height"> — ⚠ undocumented · used by `terrain`: Declares a heightfield terrain patch for `environment()` — bounds, noise, materials, and flatten masks.
3271
+ - `TerrainFlattenMask` (interface): interface TerrainFlattenMask { center: EnvironmentVec2; radius: number; height?: number; falloff?: number } — ⚠ undocumented · used by `padFlattenMasks`: Derives implicit `TerrainFlattenMask`s carving each pad's footprint into the terrain beneath it.
2792
3272
  - `TerrainIslandConfig` (interface): interface TerrainIslandConfig extends TerrainEnvironmentConfig — A bounded terrain patch floating at its own altitude — sky islands, arena platforms, split landmasses with void between.
2793
3273
  - `TerrainIslandDescriptor` (type): type TerrainIslandDescriptor = Omit<TerrainEnvironmentDescriptor, "kind"> & { kind: "island"; origin: EnvironmentVec2; } — ⚠ undocumented
2794
- - `TerrainMaterial` (type): type TerrainMaterial = "grass" | "sand" | "snow" | "rock" | "ash" | "highland" | "slate" — ⚠ undocumented
3274
+ - `TerrainMaterial` (type): type TerrainMaterial = "grass" | "sand" | "snow" | "rock" | "ash" | "highland" | "slate" — ⚠ undocumented · used by `TERRAIN_MATERIALS` (@jgengine/editor): The default terrain paint palette (surface id → color) shared by the panel and the mesh.
2795
3275
  - `TerrainMaterialMaps` (interface): interface TerrainMaterialMaps — PBR map URLs for a real ground texture — the same shape `buildMaterialCatalog({ basePath }).resolve(id)!.maps` from `@jgengine/assets` returns. Kept dependency-free here so `core` never imports the assets package; any URLs (pulled maps, a CDN, a data URI) satisfy it.
2796
3276
  - `TerrainMaterialRegion` (type): type TerrainMaterialRegion = TerrainCircleRegion | TerrainPolylineRegion | TerrainRectRegion — A palette zone painted over the base terrain palette. Circle (the default when no `shape` is given), `polyline` ribbons for roads/rivers, and rotatable `rect` districts all paint fully inside their core and blend back across `falloff`; later regions in the list win overlaps.
2797
3277
  - `TerrainPolylineRegion` (interface): interface TerrainPolylineRegion extends TerrainRegionStyle — A ribbon palette zone following a centerline — roads and rivers, instead of chaining overlapping circles.
2798
3278
  - `TerrainRectRegion` (interface): interface TerrainRectRegion extends TerrainRegionStyle — A rectangular palette zone, optionally rotated about the world y axis — plazas, fields, districts.
2799
3279
  - `TerrainRegionStyle` (interface): interface TerrainRegionStyle — Palette and blend fields shared by every `TerrainMaterialRegion` shape.
2800
- - `TilemapWorldConfig` (interface): interface TilemapWorldConfig extends WorldGridConfig — ⚠ undocumented
3280
+ - `TilemapWorldConfig` (interface): interface TilemapWorldConfig extends WorldGridConfig { map: string; tileSet?: {atlas: SpriteAtlas; tiles: Record<string, string>}; sortingLayer?: string } — ⚠ undocumented · used by `tilemap`: Declares a 2D tilemap world from a map string.
2801
3281
  - `VegetationEnvironmentDescriptor` (type): type VegetationEnvironmentDescriptor = GrassEnvironmentDescriptor — ⚠ undocumented
2802
- - `VoxelWorldConfig` (interface): interface VoxelWorldConfig extends WorldGridConfig — ⚠ undocumented
3282
+ - `VoxelWorldConfig` (interface): interface VoxelWorldConfig extends WorldGridConfig { seed: string; generate?: string; streaming?: {radius: number} } — ⚠ undocumented · used by `voxel`: Declares a voxel-grid world for block-based games.
2803
3283
  - `WaterEnvironmentDescriptor` (type): type WaterEnvironmentDescriptor = OceanEnvironmentDescriptor — ⚠ undocumented
2804
3284
  - `WeatherEnvironmentDescriptor` (type): type WeatherEnvironmentDescriptor = RainEnvironmentDescriptor | SnowEnvironmentDescriptor — ⚠ undocumented
2805
- - `WorldBounds` (interface): interface WorldBounds — ⚠ undocumented
3285
+ - `WorldBounds` (interface): interface WorldBounds { w: number; d: number } — ⚠ undocumented · used by `terrainBoundsFromDocument` (@jgengine/core/editor): The origin-centered terrain footprint that covers every authored object in a document, padded and floored to `minBounds`.
2806
3286
  - `WorldFeature` (type): type WorldFeature = | PlaceWorldFeature | ({ kind: "biomes" } & BiomesWorldConfig) | ({ kind: "voxel" } & VoxelWorldConfig) | ({ kind: "plots" } & PlotsWorldConfig) | ({ kind: "tilemap" } & TilemapWorldConfig) | EnvironmentWorldFeature | { kind: "flat" } — A declared world shape passed to `defineGame`. The preferred model is the place feature from `world()` (`@jgengine/core/world/place`): substrate + laws, with all dressing authored in the editor. The remaining members — biomes, voxel grid, plots, tilemap, environment, flat — are the legacy code-declared shapes kept for existing games.
2807
- - `WorldGridCell` (interface): interface WorldGridCell — ⚠ undocumented
3287
+ - `WorldGridCell` (interface): interface WorldGridCell { x: number; z: number; height?: number; color?: string } — ⚠ undocumented
2808
3288
  - `WorldGridConfig` (interface): interface WorldGridConfig — Shared by `biomes()`/`voxel()`/`plots()`/`tilemap()` so the shell can render their declared content as instanced boxes without a hand-written renderer.
2809
3289
  - `biomes` (function): function biomes(config: BiomesWorldConfig): WorldFeature — Declares a biome-painted world — the whole-world alternative to a single `environment()` terrain.
2810
3290
  - `building` (function): function building(config: BuildingEnvironmentConfig = {}): BuildingEnvironmentDescriptor — Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style. Pass `along` to line road frontage instead of gridding around `position`.
@@ -2826,9 +3306,9 @@
2826
3306
 
2827
3307
  ## @jgengine/core/world/fog
2828
3308
 
2829
- - `FogBounds` (interface): interface FogBounds — ⚠ undocumented
2830
- - `FogCells` (interface): interface FogCells — ⚠ undocumented
2831
- - `FogConfig` (interface): interface FogConfig — ⚠ undocumented
3309
+ - `FogBounds` (interface): interface FogBounds { minX: number; minZ: number; maxX: number; maxZ: number } — ⚠ undocumented
3310
+ - `FogCells` (interface): interface FogCells { cols: number; rows: number; minX: number; minZ: number; cellSize: number; revealed: readonly boolean[]; revealedCount: number } — ⚠ undocumented
3311
+ - `FogConfig` (interface): interface FogConfig { bounds: FogBounds; cellSize: number; revealed?: readonly number[] } — ⚠ undocumented
2832
3312
  - `FogField` (interface): interface FogField — Reveal-on-event fog of war over a fixed grid. Walking (`revealAlong`) and digging/acting (`reveal`) clear cells; once revealed a cell stays revealed. Pure and renderer-free — the shell/react map draws `cells()`.
2833
3313
  - `createFogField` (function): function createFogField(config: FogConfig): FogField — ⚠ undocumented
2834
3314
 
@@ -2837,6 +3317,7 @@
2837
3317
  - `AdjacentCell` (interface): interface AdjacentCell — One occupied neighbor cell reported by {@link boundaryNeighbors}.
2838
3318
  - `FootprintGrid` (interface): interface FootprintGrid — Handle returned by {@link createFootprintGrid}.
2839
3319
  - `FootprintGridOptions` (interface): interface FootprintGridOptions — Config for {@link createFootprintGrid}.
3320
+ - `FootprintGridState` (interface): interface FootprintGridState — Plain JSON state of a {@link FootprintGrid}: live reservations in claim order.
2840
3321
  - `FootprintReservation` (interface): interface FootprintReservation — A live claim on a {@link FootprintGrid}: which cells `id` (a `kind` tag for adjacency checks) holds.
2841
3322
  - `GridCell` (interface): interface GridCell — One integer cell address on a {@link FootprintGrid}.
2842
3323
  - `boundaryNeighbors` (function): function boundaryNeighbors(grid: FootprintGrid, cells: readonly GridCell[]): AdjacentCell[] — Every occupied cell orthogonally touching `cells` but outside them — the connective-piece neighbor set.
@@ -2846,14 +3327,14 @@
2846
3327
 
2847
3328
  ## @jgengine/core/world/geometry
2848
3329
 
2849
- - `Aabb` (interface): interface Aabb — ⚠ undocumented
3330
+ - `Aabb` (interface): interface Aabb { minX: number; minZ: number; maxX: number; maxZ: number } — ⚠ undocumented · used by `polygonBounds` (@jgengine/core/world): Axis-aligned bounds of a polygon, or null if it has no points.
2850
3331
  - `AvoidCorridor` (interface): interface AvoidCorridor — A clearance *corridor* along a polyline (a path/road): scatter is repelled within `halfWidth` of the centerline, feathered over the outer band. Clean straight edges — unlike approximating a corridor with a scalloped chain of discs.
2851
3332
  - `AvoidMasks` (interface): interface AvoidMasks — A clearance region: point discs (spawns/plots) plus centerline corridors (paths).
2852
3333
  - `AvoidZone` (interface): interface AvoidZone — A circular clearance around a gameplay spot (spawn, plot, path point, POI): scatter is repelled from it and terrain is flattened toward its center. `feather` (meters) is the soft outer band — full effect within `radius - feather`, ramping to zero at `radius`.
2853
3334
  - `Ellipse` (interface): interface Ellipse — An axis-aligned ellipse: `center` with semi-axes `radiusX` and `radiusY`.
2854
- - `Footprint` (interface): interface Footprint — ⚠ undocumented
2855
- - `MoveOptions` (interface): interface MoveOptions — ⚠ undocumented
2856
- - `Vec2` (type): type Vec2 = readonly [number, number] — ⚠ undocumented
3335
+ - `Footprint` (interface): interface Footprint { w: number; d: number } — ⚠ undocumented · used by `rotatedFootprint` (@jgengine/core/scene/assetSpace): The axis-aligned footprint extent after rotating a rectangular {@link Footprint} by `headingDegrees` — footprint-aware placement: a 90-degre…
3336
+ - `MoveOptions` (interface): interface MoveOptions { bounds?: Aabb; radius?: number } — ⚠ undocumented
3337
+ - `Vec2` (type): type Vec2 = readonly [number, number] — ⚠ undocumented · used by `assignFormationSlots` (@jgengine/core/movement/formation): Match `members` to `slots` by a deterministic greedy nearest assignment: every (member, slot) pair is ranked by squared travel distance (min…
2857
3338
  - `Vec3` (type): type Vec3 = readonly [number, number, number] — A 3D point/vector as an `[x, y, z]` tuple — the engine's zero-allocation spatial primitive.
2858
3339
 
2859
3340
  ## @jgengine/core/world/grassKind
@@ -2866,7 +3347,7 @@
2866
3347
 
2867
3348
  ## @jgengine/core/world/gridInstances
2868
3349
 
2869
- - `GridInstanceTransform` (interface): interface GridInstanceTransform — ⚠ undocumented
3350
+ - `GridInstanceTransform` (interface): interface GridInstanceTransform { position: readonly [number, number, number]; scale: readonly [number, number, number]; color: string } — ⚠ undocumented
2870
3351
  - `resolveGridCells` (function): function resolveGridCells(config: WorldGridConfig | GridWorldFeature): readonly WorldGridCell[] — ⚠ undocumented
2871
3352
  - `resolveGridInstances` (function): function resolveGridInstances(config: WorldGridConfig | GridWorldFeature): readonly GridInstanceTransform[] — ⚠ undocumented
2872
3353
 
@@ -2876,19 +3357,20 @@
2876
3357
 
2877
3358
  ## @jgengine/core/world/interiors
2878
3359
 
2879
- - `EntityLocation` (interface): interface EntityLocation — ⚠ undocumented
2880
- - `Exterior` (interface): interface Exterior — ⚠ undocumented
2881
- - `Interior` (interface): interface Interior — ⚠ undocumented
2882
- - `Interiors` (interface): interface Interiors — ⚠ undocumented
2883
- - `InteriorsConfig` (interface): interface InteriorsConfig — ⚠ undocumented
3360
+ - `EntityLocation` (interface): interface EntityLocation { space: SpaceRef; position: Vec2 } — ⚠ undocumented
3361
+ - `Exterior` (interface): interface Exterior { bounds?: Aabb; obstacles?: readonly Aabb[] } — ⚠ undocumented
3362
+ - `Interior` (interface): interface Interior { id: string; origin: Vec2; rotation?: number; bounds: Aabb; obstacles?: readonly Aabb[] } — ⚠ undocumented
3363
+ - `Interiors` (interface): interface Interiors { move(location: EntityLocation, delta: Vec2): EntityLocation; enter(location: EntityLocation, id: string): EntityLocation | null; leave(location: EntityLocation): EntityLocation | null; toInterior(id: string, exterior: Vec2): Vec2 | null; … — ⚠ undocumented · used by `createInteriors`: Frame conversion and bounded movement across an exterior and its interiors; holds config only, no play state.
3364
+ - `InteriorsConfig` (interface): interface InteriorsConfig { exterior?: Exterior; interiors?: readonly Interior[]; radius?: number } — ⚠ undocumented · used by `createInteriors`: Frame conversion and bounded movement across an exterior and its interiors; holds config only, no play state.
2884
3365
  - `SpaceRef` (type): type SpaceRef = { kind: "exterior" } | { kind: "interior"; id: string } — ⚠ undocumented
2885
- - `createInteriors` (function): function createInteriors(config: InteriorsConfig = {}): Interiors — ⚠ undocumented
3366
+ - `createInteriors` (function): function createInteriors(config: InteriorsConfig = {}): Interiors — Frame conversion and bounded movement across an exterior and its interiors; holds config only, no play state.
2886
3367
 
2887
3368
  ## @jgengine/core/world/lod
2888
3369
 
2889
- - `LodBand` (interface): interface LodBand — ⚠ undocumented
2890
- - `LodScheduler` (interface): interface LodScheduler — ⚠ undocumented
2891
- - `LodSchedulerConfig` (interface): interface LodSchedulerConfig — ⚠ undocumented
3370
+ - `LodBand` (interface): interface LodBand { maxDistance: number; interval: number } — ⚠ undocumented
3371
+ - `LodScheduler` (interface): interface LodScheduler { bandIndex(distance: number): number; step(id: string, distance: number, dtSeconds: number): number; remove(id: string): void; clear(): void; size(): number; snapshot(): LodSchedulerState; restore(next: LodSchedulerState): void } — ⚠ undocumented
3372
+ - `LodSchedulerConfig` (interface): interface LodSchedulerConfig { bands: readonly LodBand[]; beyondInterval?: number | null; stagger?: boolean } — ⚠ undocumented
3373
+ - `LodSchedulerState` (interface): interface LodSchedulerState — Plain JSON state of a {@link LodScheduler}: each id's accumulated seconds.
2892
3374
  - `createLodScheduler` (function): function createLodScheduler(config: LodSchedulerConfig): LodScheduler — ⚠ undocumented
2893
3375
 
2894
3376
  ## @jgengine/core/world/mapAnnotations
@@ -2904,12 +3386,12 @@
2904
3386
  ## @jgengine/core/world/mapLayers
2905
3387
 
2906
3388
  - `MAP_LAYER_TONE_COLORS` (const): const MAP_LAYER_TONE_COLORS: Record<MapLayerTone, string> — ⚠ undocumented
2907
- - `MapCellStates` (interface): interface MapCellStates — ⚠ undocumented
3389
+ - `MapCellStates` (interface): interface MapCellStates { id: string; origin: MapXZ; cellSize: number; cells: readonly {col: number; row: number; tone: MapLayerTone; opacity?: number}[] } — ⚠ undocumented
2908
3390
  - `MapLayerTone` (type): type MapLayerTone = "danger" | "warning" | "info" | "safe" | "neutral" — ⚠ undocumented
2909
- - `MapRoute` (interface): interface MapRoute — ⚠ undocumented
3391
+ - `MapRoute` (interface): interface MapRoute { id: string; points: readonly MapXZ[]; tone?: MapLayerTone; forecast?: boolean; width?: number; closed?: boolean } — ⚠ undocumented
2910
3392
  - `MapXZ` (type): type MapXZ = readonly [number, number] — ⚠ undocumented
2911
- - `MapZone` (interface): interface MapZone — ⚠ undocumented
2912
- - `MapZoneShape` (type): type MapZoneShape = | { kind: "circle"; center: MapXZ; radius: number } | { kind: "rect"; center: MapXZ; w: number; d: number; rotate?: number } | { kind: "polygon"; points: readonly MapXZ[] } — ⚠ undocumented
3393
+ - `MapZone` (interface): interface MapZone { id: string; shape: MapZoneShape; tone?: MapLayerTone; opacity?: number; forecast?: boolean; label?: string } — ⚠ undocumented
3394
+ - `MapZoneShape` (type): type MapZoneShape = | { kind: "circle"; center: MapXZ; radius: number } | { kind: "rect"; center: MapXZ; w: number; d: number; rotate?: number } | { kind: "polygon"; points: readonly MapXZ[] } — ⚠ undocumented · used by `pointInMapZone`: Renderer-free overlay data for map surfaces (#285.1-2): zones with live + forecast states, route polylines, and per-cell status heatmaps.
2913
3395
  - `mapLayerColor` (function): function mapLayerColor(tone: MapLayerTone | undefined): string — ⚠ undocumented
2914
3396
  - `pointInMapZone` (function): function pointInMapZone(zone: MapZoneShape, x: number, z: number): boolean — Renderer-free overlay data for map surfaces (#285.1-2): zones with live + forecast states, route polylines, and per-cell status heatmaps. `@jgengine/react/map`'s `Minimap`/`WorldMap` take these straight in; `pointInMapZone` answers gameplay queries against the same data, so the HUD and the rules can never disagree about where the storm is.
2915
3397
 
@@ -2918,11 +3400,11 @@
2918
3400
  - `DEFAULT_MARKER_KINDS` (const): const DEFAULT_MARKER_KINDS: Record<string, MarkerKindStyle> — ⚠ undocumented
2919
3401
  - `MapMarker` (interface): interface MapMarker<TMeta = unknown> extends MarkerView<TMeta> — A marker owned by {@link MarkerSet}, including its lifecycle and query fields.
2920
3402
  - `MarkerCollection` (type): type MarkerCollection<TMarker extends MarkerView = MarkerView> = | readonly TMarker[] | MarkerSource<TMarker> | MarkerSet — Marker data accepted by portable consumers: static views, an external source, or a native set.
2921
- - `MarkerInput` (interface): interface MarkerInput<TMeta = unknown> — ⚠ undocumented
3403
+ - `MarkerInput` (interface): interface MarkerInput<TMeta = unknown> { id?: string; kind: string; position: MarkerPosition; label?: string; heading?: number; owner?: string; createdAt?: number; expiresAt?: number; meta?: TMeta } — ⚠ undocumented
2922
3404
  - `MarkerKindStyle` (interface): interface MarkerKindStyle — Visual descriptor for a marker kind. Games supply their own palette; the engine ships `DEFAULT_MARKER_KINDS` as a content-agnostic starting set that the react minimap/compass read for colors and glyphs.
2923
3405
  - `MarkerPosition` (type): type MarkerPosition = readonly [number, number, number] — ⚠ undocumented
2924
- - `MarkerQuery` (interface): interface MarkerQuery — ⚠ undocumented
2925
- - `MarkerSet` (interface): interface MarkerSet<TMeta = unknown> — ⚠ undocumented
3406
+ - `MarkerQuery` (interface): interface MarkerQuery { kind?: string; owner?: string; near?: MarkerPosition; radius?: number } — ⚠ undocumented
3407
+ - `MarkerSet` (interface): interface MarkerSet<TMeta = unknown> { add(marker: MarkerInput<TMeta>): string; remove(id: string): boolean; get(id: string): MapMarker<TMeta> | null; list(): readonly MapMarker<TMeta>[]; query(query: MarkerQuery): MapMarker<TMeta>[]; prune(now: number): number; clear(): void;… — ⚠ undocumented · used by `useLiveMarkers` (@jgengine/react): A self-ticking {@link MarkerSet} kept in sync with the live scene: on a heartbeat (default 100ms, and once immediately) it clears the set an…
2926
3408
  - `MarkerSource` (interface): interface MarkerSource<TMarker extends MarkerView = MarkerView> — Observable marker snapshots owned by an external project. `getSnapshot` must return the same array identity until the source changes and calls its subscribers, matching React's external-store contract.
2927
3409
  - `MarkerSourceOptions` (interface): interface MarkerSourceOptions<TEntity, TMarker extends MarkerView = MarkerView> — Configuration for projecting a caller-owned collection into display-only markers.
2928
3410
  - `MarkerView` (interface): interface MarkerView<TMeta = unknown> — Small, display-only marker shape consumed by map renderers. Existing games can project their own entities to this view without adopting marker lifecycle storage or duplicating them into a {@link MarkerSet}.
@@ -2948,9 +3430,9 @@
2948
3430
  ## @jgengine/core/world/minimap
2949
3431
 
2950
3432
  - `Cardinal` (type): type Cardinal = "N" | "NE" | "E" | "SE" | "S" | "SW" | "W" | "NW" — ⚠ undocumented
2951
- - `MinimapPoint` (interface): interface MinimapPoint — ⚠ undocumented
2952
- - `MinimapView` (interface): interface MinimapView — ⚠ undocumented
2953
- - `WorldXZ` (type): type WorldXZ = readonly [number, number] — ⚠ undocumented
3433
+ - `MinimapPoint` (interface): interface MinimapPoint { x: number; y: number; distance: number; inside: boolean } — ⚠ undocumented · used by `clampToMinimapEdge`: Clamp a projected point to the minimap edge, preserving direction (edge markers).
3434
+ - `MinimapView` (interface): interface MinimapView { center: WorldXZ; worldRadius: number; size: number; rotate?: number } — ⚠ undocumented · used by `projectToMinimap`: Project a world XZ (or XYZ) point into minimap pixel space.
3435
+ - `WorldXZ` (type): type WorldXZ = readonly [number, number] — ⚠ undocumented · used by `compassBearing`: Compass bearing (radians, 0 = map north = −Z, increasing clockwise toward +X = east) from one world XZ point to another.
2954
3436
  - `bearingToCardinal` (function): function bearingToCardinal(bearing: number): Cardinal — ⚠ undocumented
2955
3437
  - `clampToMinimapEdge` (function): function clampToMinimapEdge(point: MinimapPoint, size: number): { x: number; y: number } — Clamp a projected point to the minimap edge, preserving direction (edge markers).
2956
3438
  - `compassBearing` (function): function compassBearing(from: WorldXZ, to: WorldXZ): number — Compass bearing (radians, 0 = map north = −Z, increasing clockwise toward +X = east) from one world XZ point to another. Feeds both the minimap direction and the compass strip.
@@ -3027,30 +3509,30 @@
3027
3509
 
3028
3510
  ## @jgengine/core/world/placedStructureStore
3029
3511
 
3030
- - `AddStructureInput` (interface): interface AddStructureInput — ⚠ undocumented
3031
- - `PlacedStructure` (interface): interface PlacedStructure — ⚠ undocumented
3032
- - `PlacedStructureSnapshot` (interface): interface PlacedStructureSnapshot — ⚠ undocumented
3033
- - `PlacedStructureStore` (interface): interface PlacedStructureStore — ⚠ undocumented
3034
- - `StructureFilter` (interface): interface StructureFilter — ⚠ undocumented
3512
+ - `AddStructureInput` (interface): interface AddStructureInput { id?: string; catalogId: string; position: StructureVec3; rotationY?: number; plotId?: string; data?: Readonly<Record<string, unknown>> } — ⚠ undocumented · used by `toStructureInput` (@jgengine/core/world): Game-state form: feed {@link createPlacedStructureStore}.add.
3513
+ - `PlacedStructure` (interface): interface PlacedStructure { id: string; catalogId: string; position: StructureVec3; rotationY: number; plotId?: string; data?: Readonly<Record<string, unknown>> } — ⚠ undocumented
3514
+ - `PlacedStructureSnapshot` (interface): interface PlacedStructureSnapshot { structures: readonly PlacedStructure[] } — ⚠ undocumented
3515
+ - `PlacedStructureStore` (interface): interface PlacedStructureStore { add(input: AddStructureInput): PlacedStructure; move(id: string, position: StructureVec3): boolean; rotate(id: string, rotationY: number): boolean; remove(id: string): boolean; get(id: string): PlacedStructure | null; list(filter?: Struct… — ⚠ undocumented
3516
+ - `StructureFilter` (interface): interface StructureFilter { plotId?: string; catalogId?: string } — ⚠ undocumented
3035
3517
  - `StructureVec3` (type): type StructureVec3 = readonly [number, number, number] — ⚠ undocumented
3036
3518
  - `createPlacedStructureStore` (function): function createPlacedStructureStore(): PlacedStructureStore — ⚠ undocumented
3037
3519
 
3038
3520
  ## @jgengine/core/world/placement
3039
3521
 
3040
- - `PlacementObstacle` (interface): interface PlacementObstacle — ⚠ undocumented
3041
- - `PlacementRequest` (interface): interface PlacementRequest — ⚠ undocumented
3042
- - `PlacementResult` (type): type PlacementResult = | { status: "ok"; center: Vec2; aabb: Aabb } | { status: "rejected"; reason: "out-of-bounds" } | { status: "rejected"; reason: "overlap"; obstacle: PlacementObstacle; index: number } — ⚠ undocumented
3043
- - `PlacementRules` (interface): interface PlacementRules — ⚠ undocumented
3522
+ - `PlacementObstacle` (interface): interface PlacementObstacle { aabb: Aabb; id?: string } — ⚠ undocumented · used by `footprintObstacles` (@jgengine/core/world): Bridges live reservations into `world/placement`'s `PlacementRules.obstacles` so `validatePlacement`/`createPlacementController` see the gri…
3523
+ - `PlacementRequest` (interface): interface PlacementRequest { center: Vec2; footprint: Footprint; quarterTurns?: number } — ⚠ undocumented · used by `validatePlacement`: Footprint validity: bounds + obstacle overlap after optional grid snap.
3524
+ - `PlacementResult` (type): type PlacementResult = | { status: "ok"; center: Vec2; aabb: Aabb } | { status: "rejected"; reason: "out-of-bounds" } | { status: "rejected"; reason: "territory.blocked" } | { status: "rejected"; reason: "overlap"; obstacle: PlacementObstacle; index: number } — ⚠ undocumented · used by `validatePlacement`: Footprint validity: bounds + obstacle overlap after optional grid snap.
3525
+ - `PlacementRules` (interface): interface PlacementRules { bounds?: Aabb; obstacles?: readonly PlacementObstacle[]; snap?: number; territory?: (aabb: Aabb) => {ok: boolean} } — ⚠ undocumented · used by `validatePlacement`: Footprint validity: bounds + obstacle overlap after optional grid snap.
3044
3526
  - `footprintObstacle` (function): function footprintObstacle(request: PlacementRequest, id?: string): PlacementObstacle — ⚠ undocumented
3045
3527
  - `validatePlacement` (function): function validatePlacement(request: PlacementRequest, rules: PlacementRules = {}): PlacementResult — Footprint validity: bounds + obstacle overlap after optional grid snap.
3046
3528
 
3047
3529
  ## @jgengine/core/world/placementController
3048
3530
 
3049
- - `PlacementCommit` (interface): interface PlacementCommit — ⚠ undocumented
3050
- - `PlacementController` (interface): interface PlacementController — ⚠ undocumented
3051
- - `PlacementControllerConfig` (interface): interface PlacementControllerConfig — ⚠ undocumented
3052
- - `PlacementHit` (interface): interface PlacementHit — ⚠ undocumented
3053
- - `PlacementPreview` (interface): interface PlacementPreview — ⚠ undocumented
3531
+ - `PlacementCommit` (interface): interface PlacementCommit { center: Vec2; y: number; rotationY: number; quarterTurns: number; footprint: Footprint; aabb: Aabb; slotId?: string } — ⚠ undocumented · used by `placeAssetFromCommit` (@jgengine/core/world): Bridge a {@link PlacementCommit} into the shared place-asset verb.
3532
+ - `PlacementController` (interface): interface PlacementController { hover(hit: PlacementHit): PlacementPreview; current(): PlacementPreview | null; rotate(steps?: number): PlacementPreview | null; setSnapMode(mode: SnapMode): PlacementPreview | null; cycleSnapMode(): SnapMode; setFootprint(footprint: Foot… — ⚠ undocumented · used by `createPlacementController`: Headless placement ghost: hover → valid/invalid preview, rotate, grid/free/surface snap, commit.
3533
+ - `PlacementControllerConfig` (interface): interface PlacementControllerConfig { footprint: Footprint; rules?: PlacementRules; snapMode?: SnapMode; grid?: number; quarterTurns?: number; slots?: readonly PlacementSlot[]; slotRadius?: number } — ⚠ undocumented · used by `createPlacementController`: Headless placement ghost: hover → valid/invalid preview, rotate, grid/free/surface snap, commit.
3534
+ - `PlacementHit` (interface): interface PlacementHit { point: PlacementVec3; normal: PlacementVec3 } — ⚠ undocumented
3535
+ - `PlacementPreview` (interface): interface PlacementPreview { center: Vec2; y: number; quarterTurns: number; footprint: Footprint; aabb: Aabb; valid: boolean; reason?: "out-of-bounds" | "overlap" | "no-slot" | "territory.blocked"; snapMode: SnapMode; normal: PlacementVec3; slotId?: string } — ⚠ undocumented
3054
3536
  - `PlacementSlot` (interface): interface PlacementSlot — A fixed buildable slot the placement controller snaps to instead of grid/free positioning.
3055
3537
  - `PlacementVec3` (type): type PlacementVec3 = readonly [number, number, number] — ⚠ undocumented
3056
3538
  - `SnapMode` (type): type SnapMode = "grid" | "free" | "surface" — ⚠ undocumented
@@ -3071,12 +3553,28 @@
3071
3553
  - `Polyline` (interface): interface Polyline — A polyline prepared for repeated distance/fraction sampling, with cumulative arc-length precomputed.
3072
3554
  - `PolylineHit` (interface): interface PolylineHit — The closest point on a polyline to a query point, with where it lands along the line.
3073
3555
 
3556
+ ## @jgengine/core/world/raceCircuit
3557
+
3558
+ - `CIRCUIT_ROUTE_DEFAULTS` (const): const CIRCUIT_ROUTE_DEFAULTS: CircuitRouteRules — Defaults: a ~2.4 km arterial street lap with 12 gates, 3 laps, and barriered side streets.
3559
+ - `CircuitCorner` (interface): interface CircuitCorner — One analyzed corner: where the lap turns, how hard, and which way.
3560
+ - `CircuitGate` (interface): interface CircuitGate — One checkpoint trigger volume, shaped to hand straight to `raceTrack({ checkpoints })`.
3561
+ - `CircuitGridSlot` (interface): interface CircuitGridSlot — One grid slot: a staggered spawn behind the start line.
3562
+ - `CircuitKerb` (interface): interface CircuitKerb — One kerb strip on the outside or inside of a corner, as an offset polyline to stripe.
3563
+ - `CircuitKerbOptions` (interface): interface CircuitKerbOptions — Kerb strips on the outside and inside of every real corner.
3564
+ - `CircuitRoute` (interface): interface CircuitRoute — A closed race lap lifted out of a street network, with everything a race needs hung off it.
3565
+ - `CircuitRouteRules` (interface): interface CircuitRouteRules — Fully-defaulted sliders the route search answers to.
3566
+ - `CircuitSeal` (interface): interface CircuitSeal — One street closed off where it leaves the lap — the thing that turns public roads into an instanced event. Stands just off the junction, spanning the sealed street's full width.
3567
+ - `CircuitSealKind` (type): type CircuitSealKind = "barrier" | "cones" | "fence" — How a sealed-off side street is closed: hard barriers, a cone line, or temporary fencing.
3568
+ - `CircuitStart` (interface): interface CircuitStart — The start/finish line: where it is, which way cars face, and the painted line across the road.
3569
+ - `circuitKerbs` (function): function circuitKerbs(route: CircuitRoute, options: CircuitKerbOptions = {}): CircuitKerb[] — Red/white kerb strips hugging both road edges through each corner. Returns the polylines and stripe pitch as data; the renderer owns the mesh and the colors.
3570
+ - `extractCircuitRoute` (function): function extractCircuitRoute(network: StreetNetwork, rules: Partial<CircuitRouteRules> = {}): CircuitRoute | null — Lift a closed, sealed-off race lap out of an existing street network. Returns `null` when the network has no drivable cycle (a pure tree of dead-end streets), so callers can fall back or warn rather than render a broken race.
3571
+
3074
3572
  ## @jgengine/core/world/realm
3075
3573
 
3076
- - `ComposedRealm` (interface): interface ComposedRealm — ⚠ undocumented
3574
+ - `ComposedRealm` (interface): interface ComposedRealm { params: RealmEnvironmentParams; weather: WeatherState; spawnTable: Record<string, number>; aesthetics: readonly string[]; cards: readonly RealmCard[]; environmentField(extra?: Omit<EnvironmentFieldConfig, "baseTemperature" | "nightDrop" |… — ⚠ undocumented · used by `composeRealm`: Assemble a played realm instance at runtime from a deck of modifier cards — the Nightingale "realm card" model.
3077
3575
  - `DEFAULT_REALM_ENVIRONMENT` (const): const DEFAULT_REALM_ENVIRONMENT: RealmEnvironmentParams — ⚠ undocumented
3078
- - `RealmBase` (interface): interface RealmBase — ⚠ undocumented
3079
- - `RealmCard` (interface): interface RealmCard — ⚠ undocumented
3576
+ - `RealmBase` (interface): interface RealmBase { environment?: Partial<RealmEnvironmentParams>; weather?: WeatherState; spawn?: Record<string, number> } — ⚠ undocumented · used by `composeRealm`: Assemble a played realm instance at runtime from a deck of modifier cards — the Nightingale "realm card" model.
3577
+ - `RealmCard` (interface): interface RealmCard { id: string; kind: "major" | "minor"; environment?: Partial<RealmEnvironmentParams>; weather?: Partial<WeatherState>; spawn?: SpawnTableOverride; aesthetic?: string } — ⚠ undocumented · used by `composeRealm`: Assemble a played realm instance at runtime from a deck of modifier cards — the Nightingale "realm card" model.
3080
3578
  - `RealmEnvironmentParams` (interface): interface RealmEnvironmentParams — The recomposable environment parameters a realm card can override.
3081
3579
  - `SpawnTableOverride` (interface): interface SpawnTableOverride — Spawn-table edits a card layers on: replace weights, add/scale, or remove ids.
3082
3580
  - `composeRealm` (function): function composeRealm(base: RealmBase, cards: readonly RealmCard[]): ComposedRealm — Assemble a played realm instance at runtime from a deck of modifier cards — the Nightingale "realm card" model. A major card is the biome base; minor cards layer weather, day length, and spawn edits. The result recomposes both the environment (into a sampleable field via `environmentField()`) and the spawn table, and it depends on the weather hooks in this group (#92) to turn its `weather` into gameplay modifiers. Cards apply in array order; sort your deck (majors first) before composing.
@@ -3085,10 +3583,10 @@
3085
3583
 
3086
3584
  - `ColorInput` (type): type ColorInput = string | Rgb — ⚠ undocumented
3087
3585
  - `RegionDef` (interface): interface RegionDef<T = unknown> — A content-agnostic region. The engine blends `height` and the visual/physical knobs (`tint`, `water`, `fog`, `speedMultiplier`, …) across region borders and selects the dominant region by nearest center in `selector` space. `data` is an opaque payload the engine never inspects — games hang their own content off it (spawn tables, prop palettes, structure ids, names, …).
3088
- - `RegionField` (interface): interface RegionField<T = unknown> extends TerrainField — ⚠ undocumented
3089
- - `RegionFieldConfig` (interface): interface RegionFieldConfig<T = unknown> — ⚠ undocumented
3090
- - `RegionHeight` (interface): interface RegionHeight — ⚠ undocumented
3091
- - `RegionSample` (interface): interface RegionSample<T = unknown> — ⚠ undocumented
3586
+ - `RegionField` (interface): interface RegionField<T = unknown> extends TerrainField { sampleRegion(x: number, z: number): RegionSample<T>; readonly regions: readonly RegionDef<T>[]; readonly seaLevel: number; readonly seed: number } — ⚠ undocumented · used by `scatterItems` (@jgengine/core/world): Deterministically place opaque items across `area`, grounded on a region field.
3587
+ - `RegionFieldConfig` (interface): interface RegionFieldConfig<T = unknown> { regions: readonly RegionDef<T>[]; seed?: number; bounds?: WorldBounds; seaLevel?: number; selectorFrequencies?: readonly number[]; axisWeights?: readonly number[]; sharpness?: number; warp?: number } — ⚠ undocumented
3588
+ - `RegionHeight` (interface): interface RegionHeight { baseHeight: number; amplitude: number; frequency: number; octaves?: number; lacunarity?: number; persistence?: number; ridged?: boolean } — ⚠ undocumented
3589
+ - `RegionSample` (interface): interface RegionSample<T = unknown> { region: RegionDef<T>; weight: number; selector: readonly number[]; tint: Rgb; steepTint: Rgb; water: Rgb | null; fog: Rgb | null; fogDensity: number; speedMultiplier: number; data: T | undefined } — ⚠ undocumented · used by `scatterItems` (@jgengine/core/world): Deterministically place opaque items across `area`, grounded on a region field.
3092
3590
  - `Rgb` (type): type Rgb = readonly [number, number, number] — ⚠ undocumented
3093
3591
  - `createRegionField` (function): function createRegionField<T = unknown>(config: RegionFieldConfig<T>): RegionField<T> — ⚠ undocumented
3094
3592
  - `isRegionField` (function): function isRegionField(field: TerrainField): field is RegionField — ⚠ undocumented
@@ -3142,9 +3640,9 @@
3142
3640
 
3143
3641
  ## @jgengine/core/world/scatter
3144
3642
 
3145
- - `ScatterArea` (interface): interface ScatterArea — ⚠ undocumented
3146
- - `ScatterConfig` (interface): interface ScatterConfig — ⚠ undocumented
3147
- - `ScatterPoint` (interface): interface ScatterPoint — ⚠ undocumented
3643
+ - `ScatterArea` (interface): interface ScatterArea { w: number; d: number; center?: Vec2 } — ⚠ undocumented
3644
+ - `ScatterConfig` (interface): interface ScatterConfig { area: ScatterArea | Aabb; count?: number; density?: number; seed?: string | number; minDistance?: number; avoid?: readonly Aabb[]; avoidMargin?: number; jitter?: number; maxAttempts?: number } — ⚠ undocumented
3645
+ - `ScatterPoint` (interface): interface ScatterPoint { x: number; z: number; index: number } — ⚠ undocumented
3148
3646
  - `scatter` (function): function scatter(config: ScatterConfig): ScatterPoint[] — ⚠ undocumented
3149
3647
  - `scatterAabb` (function): function scatterAabb(area: ScatterArea | Aabb): Aabb — ⚠ undocumented
3150
3648
 
@@ -3165,7 +3663,7 @@
3165
3663
 
3166
3664
  ## @jgengine/core/world/scatterItems
3167
3665
 
3168
- - `ScatterInstance` (interface): interface ScatterInstance — ⚠ undocumented
3666
+ - `ScatterInstance` (interface): interface ScatterInstance { id: string; item: string; x: number; z: number; y: number; scale: number; rotation: number; regionId: string } — ⚠ undocumented · used by `scatterItems`: Deterministically place opaque items across `area`, grounded on a region field.
3169
3667
  - `ScatterLayer` (interface): interface ScatterLayer — One placeable class. `item` is an opaque id the caller maps to a mesh/entity.
3170
3668
  - `pickWeighted` (function): function pickWeighted<T>(entries: readonly { value: T; weight: number }[], roll: number): T | null — Weighted pick from opaque entries; `roll` in [0, 1). Returns null when empty.
3171
3669
  - `scatterItems` (function): function scatterItems<T>(field: RegionField<T>, area: Aabb, layersFor: (sample: RegionSample<T>) => readonly ScatterLayer[], options: { cell?: number; max?: number; saltKey?: number } = {}): ScatterInstance[] — Deterministically place opaque items across `area`, grounded on a region field. For each grid cell it asks `layersFor` which items may appear in that region and rolls one against their densities. The engine never interprets `item` — a game maps it to a mesh or entity. Content scatter (region-driven density) as opposed to `scatter` in `./scatter`, which is renderer-free geometric point distribution.
@@ -3316,24 +3814,25 @@
3316
3814
 
3317
3815
  ## @jgengine/core/world/support
3318
3816
 
3319
- - `DebrisOptions` (interface): interface DebrisOptions — ⚠ undocumented
3320
- - `SupportConfig` (interface): interface SupportConfig — ⚠ undocumented
3321
- - `SupportLink` (interface): interface SupportLink — ⚠ undocumented
3322
- - `SupportPiece` (interface): interface SupportPiece — ⚠ undocumented
3323
- - `SupportResult` (interface): interface SupportResult — ⚠ undocumented
3817
+ - `DebrisOptions` (interface): interface DebrisOptions { scatter?: number; seed?: number } — ⚠ undocumented
3818
+ - `SupportConfig` (interface): interface SupportConfig { maxDistance?: number } — ⚠ undocumented
3819
+ - `SupportLink` (interface): interface SupportLink { a: string; b: string } — ⚠ undocumented
3820
+ - `SupportPiece` (interface): interface SupportPiece { id: string; grounded?: boolean; position?: ConnectorVec3; halfExtents?: ConnectorVec3; mass?: number } — ⚠ undocumented
3821
+ - `SupportResult` (interface): interface SupportResult { supported: readonly string[]; unsupported: readonly string[]; distance: Readonly<Record<string, number>> } — ⚠ undocumented
3324
3822
  - `solveSupport` (function): function solveSupport(pieces: readonly SupportPiece[], links: readonly SupportLink[], config: SupportConfig = {}): SupportResult — ⚠ undocumented
3325
3823
  - `toDebrisBodies` (function): function toDebrisBodies(pieces: readonly SupportPiece[], collapsedIds: readonly string[], options: DebrisOptions = {}): AddBodyOptions[] — ⚠ undocumented
3326
3824
 
3327
3825
  ## @jgengine/core/world/terraform
3328
3826
 
3329
3827
  - `BlendStroke` (interface): interface BlendStroke — Accumulates a whole blend-paint drag into one compact {@link WeightDelta}. Keeps each weight slot's first `before` and latest `after`, so undo replays the blend as a single step.
3330
- - `EditableTerrain` (interface): interface EditableTerrain extends TerrainField — ⚠ undocumented
3331
- - `EditableTerrainConfig` (interface): interface EditableTerrainConfig — ⚠ undocumented
3828
+ - `EditableTerrain` (interface): interface EditableTerrain extends TerrainField { readonly cols: number; readonly rows: number; readonly cellSize: number; apply(edit: TerraformEdit): number; applyRecording(edit: TerraformEdit, record: TerraformDeltaRecorder): number; editDelta(edit: TerraformEdit): TerraformDelta; appl… — ⚠ undocumented · used by `beginSurfaceStroke`: Opens a paint-stroke recorder over `terrain`; stamp paint edits into it, then read one net delta.
3829
+ - `EditableTerrainConfig` (interface): interface EditableTerrainConfig { bounds: Aabb; base?: TerrainField; cellSize?: number } — ⚠ undocumented · used by `createTerrainSnapshot`: A fresh, unedited terrain snapshot sized to `bounds`/`cellSize` — the seed for a new sculpt document.
3332
3830
  - `SurfaceDelta` (interface): interface SurfaceDelta — A compact record of the surface-material cells a paint stroke touched: parallel `indices`/`before`/`after` arrays into the per-cell surface grid. One per stroke keeps paint undo history small.
3333
3831
  - `SurfaceDeltaRecorder` (type): type SurfaceDeltaRecorder = (index: number, before: string | null, after: string | null) => void — Reports each changed cell during a recorded paint: grid index, prior surface id, new surface id.
3334
3832
  - `SurfaceStroke` (interface): interface SurfaceStroke — Accumulates a whole paint drag — many surface stamps — into one compact {@link SurfaceDelta}. Keeps each cell's first `before` and latest `after`, so undo replays the paint as a single step.
3335
- - `TerraformBrush` (interface): interface TerraformBrush — ⚠ undocumented
3336
- - `TerraformBrushConfig` (interface): interface TerraformBrushConfig — ⚠ undocumented
3833
+ - `TerraformBrush` (interface): interface TerraformBrush { raise(center: Vec2): number; lower(center: Vec2): number; flatten(center: Vec2, target?: number): number; paint(center: Vec2, surface?: string): number; setRadius(radius: number): void; setStrength(strength: number): void; config(): Requi… — ⚠ undocumented
3834
+ - `TerraformBrushConfig` (interface): interface TerraformBrushConfig { radius?: number; strength?: number; falloff?: TerraformFalloff; surface?: string } — ⚠ undocumented
3835
+ - `TerraformBrushState` (interface): interface TerraformBrushState — Plain JSON state of a {@link TerraformBrush}.
3337
3836
  - `TerraformDelta` (interface): interface TerraformDelta — A compact record of the vertices a sculpt stroke touched: parallel `indices`/`before`/`after` arrays into the offset grid. Storing one of these per stroke keeps undo history small — the whole terrain document is never copied.
3338
3837
  - `TerraformDeltaRecorder` (type): type TerraformDeltaRecorder = (index: number, before: number, after: number) => void — Reports each changed vertex during a recorded edit: grid index, prior offset, new offset.
3339
3838
  - `TerraformEdit` (interface): interface TerraformEdit — A single sculpt stamp: which brush, where, and its shaping parameters.
@@ -3341,7 +3840,7 @@
3341
3840
  - `TerraformHeightLimit` (interface): interface TerraformHeightLimit — Clamp bounds applied to the resulting terrain height after a heightfield edit.
3342
3841
  - `TerraformMode` (type): type TerraformMode = "raise" | "lower" | "smooth" | "flatten" | "noise" | "ramp" | "paint" — A sculpt operation kind: heightfield brushes plus the surface-paint brush.
3343
3842
  - `TerraformShape` (type): type TerraformShape = "circle" | "square" — A brush footprint: a round disc or an axis-aligned square.
3344
- - `TerraformSnapshot` (interface): interface TerraformSnapshot — ⚠ undocumented
3843
+ - `TerraformSnapshot` (interface): interface TerraformSnapshot { bounds: Aabb; cellSize: number; cols: number; rows: number; offsets: readonly number[]; surfaces: readonly (string | null)[]; layers?: readonly TerrainMaterialLayer[]; weights?: readonly number[] } — ⚠ undocumented · used by `applyDeltaToSnapshot`: Returns a new snapshot with a delta's `after` offsets applied (copy-on-write — inputs untouched).
3345
3844
  - `TerraformStroke` (interface): interface TerraformStroke — Accumulates a whole drag — many brush stamps — into one compact {@link TerraformDelta}. Keeps each vertex's first `before` and latest `after`, so undo replays the stroke as a single step even though the pointer fired dozens of moves.
3346
3845
  - `TerrainMaterialLayer` (interface): interface TerrainMaterialLayer — One material layer in a terrain's reorderable stack: a palette `surface` id (drives the base color) plus its render parameters. Array order is the stack order — lower index paints under higher. `roughness`/`tiling`/`triplanar`/`tint`/`opacity` are carried as data so a runtime game reads them straight off the snapshot.
3347
3846
  - `TerrainSurfaceRule` (interface): interface TerrainSurfaceRule — A height/slope predicate for auto-painting a surface layer (e.g. rock on steep slopes, snow up high).
@@ -3363,29 +3862,29 @@
3363
3862
  ## @jgengine/core/world/terrain
3364
3863
 
3365
3864
  - `ARENA_WATER_LEVEL` (const): const ARENA_WATER_LEVEL: -0.9 — ⚠ undocumented
3366
- - `ArenaFieldConfig` (interface): interface ArenaFieldConfig — ⚠ undocumented
3865
+ - `ArenaFieldConfig` (interface): interface ArenaFieldConfig { seed?: string | number; bounds?: WorldBounds } — ⚠ undocumented
3367
3866
  - `BiomeFogValue` (interface): interface BiomeFogValue — A concrete fog look — the shape `createBiomeFogSampler` resolves per z from a band's `fog` over the base fog.
3368
3867
  - `BiomeSkyValue` (interface): interface BiomeSkyValue — A concrete sky look — the shape `createBiomeSkySampler` resolves per z from a band's `sky` over the base sky.
3369
3868
  - `DEFAULT_MAX_WALK_SLOPE` (const): const DEFAULT_MAX_WALK_SLOPE: 0.6 — ⚠ undocumented
3370
3869
  - `DEFAULT_TERRAIN_MATERIAL` (const): const DEFAULT_TERRAIN_MATERIAL: TerrainMaterial — ⚠ undocumented
3371
3870
  - `FLAT_FIELD` (const): const FLAT_FIELD: TerrainField — ⚠ undocumented
3372
3871
  - `FractalNoiseConfig` (interface): interface FractalNoiseConfig — Octave settings for {@link fractalNoise}: frequency, layering, and optional ridged shaping.
3373
- - `GroundSnapEntityStore` (interface): interface GroundSnapEntityStore — ⚠ undocumented
3374
- - `GroundSnapTarget` (interface): interface GroundSnapTarget — ⚠ undocumented
3872
+ - `GroundSnapEntityStore` (interface): interface GroundSnapEntityStore { get(id: string): GroundSnapTarget | null; setPose(id: string, pose: {position?: readonly [number, number, number]}): boolean } — ⚠ undocumented
3873
+ - `GroundSnapTarget` (interface): interface GroundSnapTarget { position: readonly [number, number, number] } — ⚠ undocumented
3375
3874
  - `HeightFieldRayBounds` (interface): interface HeightFieldRayBounds — XZ region a {@link raycastHeightField} march is clipped to.
3376
3875
  - `HeightFieldRayHit` (interface): interface HeightFieldRayHit — Where a {@link raycastHeightField} march crossed the surface.
3377
3876
  - `HeightFieldRaycastOptions` (interface): interface HeightFieldRaycastOptions — Tuning for {@link raycastHeightField}: march resolution and refinement depth.
3378
- - `HeightMapFieldConfig` (interface): interface HeightMapFieldConfig — ⚠ undocumented
3877
+ - `HeightMapFieldConfig` (interface): interface HeightMapFieldConfig { columns: number; rows: number; samples: ArrayLike<number>; bounds?: WorldBounds; heightScale?: number; baseHeight?: number; waterLevel?: number } — ⚠ undocumented
3379
3878
  - `ISLAND_VOID_HEIGHT` (const): const ISLAND_VOID_HEIGHT: -256 — Ground height between islands when no base terrain exists — deep enough to read as a fall into the void, finite so physics stays sane.
3380
3879
  - `NoiseFieldConfig` (interface): interface NoiseFieldConfig — Configuration for {@link noiseField}: seed, amplitude, and fractal noise shaping.
3381
- - `ResolvedTerrainDetail` (type): type ResolvedTerrainDetail = Required<Omit<TerrainDetailConfig, "waterLevel" | "material">> & { waterLevel: number; material?: ResolvedTerrainDetailMaterial; } — A {@link TerrainDetailConfig} with every field resolved to a concrete value — the shape the shell's detail material consumes.
3880
+ - `ResolvedTerrainDetail` (type): type ResolvedTerrainDetail = Required<Omit<TerrainDetailConfig, "waterLevel" | "material" | "sweeps">> & { waterLevel: number; material?: ResolvedTerrainDetailMaterial; sweeps: { dry: readonly [number, number, number]; wet: readonly [number, number, number] }; } — A {@link TerrainDetailConfig} with every field resolved to a concrete value — the shape the shell's detail material consumes.
3382
3881
  - `ResolvedTerrainDetailMaterial` (interface): interface ResolvedTerrainDetailMaterial — A resolved {@link TerrainDetailMaterialConfig} — `repeat`/`strength` filled with defaults, `maps` passed through.
3383
- - `RollingFieldConfig` (interface): interface RollingFieldConfig — ⚠ undocumented
3882
+ - `RollingFieldConfig` (interface): interface RollingFieldConfig { seed?: string | number; amplitude?: number; frequency?: number; bounds?: WorldBounds } — ⚠ undocumented
3384
3883
  - `TERRAIN_MATERIAL_PALETTES` (const): const TERRAIN_MATERIAL_PALETTES: Record<TerrainMaterial, TerrainPalette> — ⚠ undocumented
3385
3884
  - `TerrainField` (interface): interface TerrainField — A sampleable ground surface: height and normal at any x/z, with optional bounds and water level.
3386
3885
  - `TerrainNormal` (type): type TerrainNormal = readonly [number, number, number] — A surface normal vector at a terrain sample point.
3387
- - `TerrainPalette` (interface): interface TerrainPalette — ⚠ undocumented
3388
- - `TerrainSlopeSample` (interface): interface TerrainSlopeSample — ⚠ undocumented
3886
+ - `TerrainPalette` (interface): interface TerrainPalette { low: string; high: string; waterline: string } — ⚠ undocumented
3887
+ - `TerrainSlopeSample` (interface): interface TerrainSlopeSample { downhill: readonly [number, number]; steepness: number } — ⚠ undocumented
3389
3888
  - `applyPathProfiles` (function): function applyPathProfiles(field: TerrainField, profiles: readonly TerrainPathProfile[]): TerrainField — Composes authored path profiles onto a field — the shared seam that turns a scene road/river/ramp path into flattened, graded, carved, or retained ground. Applies after `flatten` masks in `resolveTerrainField` so a corridor grades over already-leveled pads; call it directly to layer profiles onto any field a game builds by hand. Returns the field unchanged when no profile is given.
3390
3889
  - `raycastHeightField` (function): function raycastHeightField(sampleHeight: (x: number, z: number) => number, origin: readonly [number, number, number], direction: readonly [number, number, number], options: HeightFieldRaycastOptions): HeightFieldRayHit | null — Intersects a ray with a `sampleHeight` field by fixed-step raymarching plus bisection — the O(steps) editor/gameplay picking seam that replaces brute-force triangle raycasts against a tessellated ground mesh (tens of thousands of triangle tests per pick on a sculpt-sized grid). The ray is clipped to `bounds` on XZ first, marched at `step`, and the first above→below crossing is bisected. An origin already under the surface hits immediately at entry. Returns null when the clipped ray never crosses the surface.
3391
3890
 
@@ -3410,6 +3909,23 @@
3410
3909
  - `surfaceRing` (function): function surfaceRing(sampleHeight: HeightSampler, center: GroundPoint, radius: number, segments = 48, options: DrapeOptions = {}): number[] — A closed circle draped on the surface — the surface-following placement guide ring under a cursor or a selected object. Returns flat `[x, y, z, ...]` world triples forming a loop (last vertex repeats the first). `segments` sets the smoothness of the ring.
3411
3910
  - `terrainContourGuides` (function): function terrainContourGuides(field: Pick<TerrainField, "sampleHeight">, region: GuideRegion, targetLines = 12, resolution = 128): { interval: number; summary: ElevationSummary; contours: ContourLine[] } — Convenience over {@link extractContours} that auto-picks the interval from the field's own relief: summarises the region, chooses a readable interval for `targetLines` bands, and traces the contours — the one call the editor overlay makes to turn a `TerrainField` into ready-to-draw guides. Returns an empty list for flat ground.
3412
3911
 
3912
+ ## @jgengine/core/world/territory
3913
+
3914
+ - `Territory` (type): type Territory = ReturnType<typeof createTerritory> — Snapshot-backed claim, release, owner and starter-grant operations.
3915
+ - `TerritoryCell` (type): type TerritoryCell = { x: number; z: number } — Integer cell coordinates used for ownership on the ground plane.
3916
+ - `TerritoryPlan` (type): type TerritoryPlan = { ok: true; cells: TerritoryCell[]; cost: number } | { ok: false; reason: "territory.blocked" | "territory.unaffordable" } — Read-only footprint quote or a blocked/insufficient-balance rejection.
3917
+ - `TerritoryPolicy` (type): type TerritoryPolicy = { gapCells?: number; cellSize?: number; chunkSize?: number; currency?: string; price?: (ownedCount: number) => number; starterBlock?: number; nowMs?: number; } — Cell size, foreign-owner gap, growth price, currency and starter-grant policy.
3918
+ - `TerritoryResult` (type): type TerritoryResult = { ok: true; snapshot: GameRuntimeSnapshot; cost: number } | { ok: false; reason: "territory.blocked" | "territory.unaffordable" } — Atomic claim outcome with the replacement snapshot and total charge.
3919
+ - `TerritoryStorage` (interface): interface TerritoryStorage — Host-owned snapshot access used by the territory facade.
3920
+ - `claimTerritory` (function): function claimTerritory(snapshot: GameRuntimeSnapshot, userId: string, cells: readonly TerritoryCell[], policy: TerritoryPolicy = {}): TerritoryResult — Atomically buy every unowned footprint cell, leaving the input untouched on failure.
3921
+ - `createTerritory` (function): function createTerritory(storage: TerritoryStorage, policy: () => TerritoryPolicy = () => ({})): { snapshot: () => GameRuntimeSnapshot; restore: (snapshot: GameRuntimeSnapshot) => void; ownerOf: (cell: TerritoryCell) => string | null; canUse: (userId: string, cell: TerritoryCell) => boolean; claim(u… — Snapshot-backed territory facade with host-owned storage and live policy.
3922
+ - `placeWithTerritory` (function): function placeWithTerritory(snapshot: GameRuntimeSnapshot, userId: string, bounds: Aabb, policy: TerritoryPolicy, place: (snapshot: GameRuntimeSnapshot) => { ok: true; snapshot: GameRuntimeSnapshot } | { ok: false; reason: string }): { ok: true; snapshot: GameRuntimeSnapshot; cost: number } | { ok: … — Placement transaction: rejected object placement also rolls back territory and its charge.
3923
+ - `planFootprintClaims` (function): function planFootprintClaims(snapshot: GameRuntimeSnapshot, userId: string, footprint: readonly TerritoryCell[], policy: TerritoryPolicy = {}): TerritoryPlan — Price and validate a footprint without mutating or charging; reuse for placement previews.
3924
+ - `territoryChunkKey` (function): function territoryChunkKey(cell: TerritoryCell, policy: TerritoryPolicy = {}): string — Persisted chunk key containing one territory cell.
3925
+ - `territoryChunkKeys` (function): function territoryChunkKeys(cells: readonly TerritoryCell[], policy: TerritoryPolicy = {}): string[] — Exact chunks needed to validate a footprint and its foreign-owner gap.
3926
+ - `territoryFootprintCells` (function): function territoryFootprintCells(bounds: Aabb, cellSize = 1): TerritoryCell[] — Cells touched by a placement, excluding cells that only touch its outer edge.
3927
+ - `territoryOwnerOf` (function): function territoryOwnerOf(snapshot: GameRuntimeSnapshot, cell: TerritoryCell, policy: TerritoryPolicy = {}): string | null — Owner of a loaded cell; hosts load the target and gap neighborhood before evaluating claims.
3928
+
3413
3929
  ## @jgengine/core/world/vegetation
3414
3930
 
3415
3931
  - `VEGETATION_DEFAULTS` (const): const VEGETATION_DEFAULTS: VegetationSettings — Defaults a bare `kind: "vegetation"` volume grows with: grass at 4 blades/m².
@@ -3442,34 +3958,35 @@
3442
3958
 
3443
3959
  - `VOXEL_FACES` (const): const VOXEL_FACES: readonly VoxelFace[] — ⚠ undocumented
3444
3960
  - `VOXEL_FACE_NORMALS` (const): const VOXEL_FACE_NORMALS: Record<VoxelFace, VoxelCoord> — ⚠ undocumented
3445
- - `VoxelBounds` (interface): interface VoxelBounds — ⚠ undocumented
3446
- - `VoxelCell` (interface): interface VoxelCell<T extends string = string> — ⚠ undocumented
3961
+ - `VoxelBounds` (interface): interface VoxelBounds { min: VoxelCoord; max: VoxelCoord } — ⚠ undocumented
3962
+ - `VoxelCell` (interface): interface VoxelCell<T extends string = string> { x: number; y: number; z: number; type: T } — ⚠ undocumented
3447
3963
  - `VoxelCoord` (type): type VoxelCoord = readonly [number, number, number] — ⚠ undocumented
3448
3964
  - `VoxelFace` (type): type VoxelFace = "px" | "nx" | "py" | "ny" | "pz" | "nz" — ⚠ undocumented
3449
- - `VoxelField` (interface): interface VoxelField<T extends string = string> — ⚠ undocumented
3450
- - `VoxelFieldConfig` (interface): interface VoxelFieldConfig — ⚠ undocumented
3451
- - `VoxelFieldSummary` (interface): interface VoxelFieldSummary<T extends string = string> — ⚠ undocumented
3452
- - `VoxelHit` (interface): interface VoxelHit<T extends string = string> — ⚠ undocumented
3965
+ - `VoxelField` (interface): interface VoxelField<T extends string = string> { set(x: number, y: number, z: number, type: T): boolean; remove(x: number, y: number, z: number): boolean; get(x: number, y: number, z: number): T | null; has(x: number, y: number, z: number): boolean; fill(min: VoxelCoord, max: VoxelCoord… — ⚠ undocumented
3966
+ - `VoxelFieldConfig` (interface): interface VoxelFieldConfig { chunkSize?: number } — ⚠ undocumented
3967
+ - `VoxelFieldSummary` (interface): interface VoxelFieldSummary<T extends string = string> { blocks: number; types: Record<T, number>; bounds: VoxelBounds | null } — ⚠ undocumented
3968
+ - `VoxelHit` (interface): interface VoxelHit<T extends string = string> { x: number; y: number; z: number; type: T; face: VoxelFace; adjacent: VoxelCoord; distance: number } — ⚠ undocumented
3453
3969
  - `createVoxelField` (function): function createVoxelField<T extends string = string>(config?: VoxelFieldConfig): VoxelField<T> — ⚠ undocumented
3454
3970
 
3455
3971
  ## @jgengine/core/world/walls
3456
3972
 
3457
- - `EnclosedFootprint` (interface): interface EnclosedFootprint — ⚠ undocumented
3973
+ - `EnclosedFootprint` (interface): interface EnclosedFootprint { polygon: readonly Vec2[]; aabb: Aabb; area: number; perimeter: number; closed: boolean } — ⚠ undocumented
3458
3974
  - `PaintTarget` (type): type PaintTarget = "floor" | "wall" — ⚠ undocumented
3459
- - `RoofConfig` (interface): interface RoofConfig — ⚠ undocumented
3460
- - `RoofPlan` (interface): interface RoofPlan — ⚠ undocumented
3975
+ - `RoofConfig` (interface): interface RoofConfig { style?: RoofStyle; eaveHeight?: number; pitch?: number; overhang?: number } — ⚠ undocumented
3976
+ - `RoofPlan` (interface): interface RoofPlan { style: RoofStyle; ridge: readonly [Vec2, Vec2]; apexHeight: number; eaveHeight: number; faces: readonly (readonly WallVec3[])[] } — ⚠ undocumented
3461
3977
  - `RoofStyle` (type): type RoofStyle = "hip" | "gable" | "flat" — ⚠ undocumented
3462
- - `SurfacePaintStore` (interface): interface SurfacePaintStore — ⚠ undocumented
3463
- - `WallDrawTool` (interface): interface WallDrawTool — ⚠ undocumented
3464
- - `WallSegment` (interface): interface WallSegment — ⚠ undocumented
3978
+ - `SurfacePaintStore` (interface): interface SurfacePaintStore { paint(target: PaintTarget, key: string, surface: string): void; clear(target: PaintTarget, key: string): void; get(target: PaintTarget, key: string): string | null; entries(target: PaintTarget): readonly (readonly [string, string])[]; sna… — ⚠ undocumented
3979
+ - `WallDrawTool` (interface): interface WallDrawTool { addPoint(point: Vec2, snap?: number): Vec2; undo(): void; close(): void; clear(): void; points(): readonly Vec2[]; segments(): WallSegment[]; isClosed(): boolean; footprint(): EnclosedFootprint | null; roof(config?: RoofConfig): RoofPlan … — ⚠ undocumented
3980
+ - `WallDrawToolState` (interface): interface WallDrawToolState — Plain JSON state of a {@link WallDrawTool}: the drawn points and whether the loop is closed.
3981
+ - `WallSegment` (interface): interface WallSegment { from: Vec2; to: Vec2; length: number; angle: number } — ⚠ undocumented · used by `wallSolids` (@jgengine/core/world/worldSolids): One oriented solid per wall segment (see `wallSegments` in `world/walls`).
3465
3982
  - `WallVec3` (type): type WallVec3 = readonly [number, number, number] — ⚠ undocumented
3466
3983
 
3467
3984
  ## @jgengine/core/world/water
3468
3985
 
3469
- - `GerstnerWave` (interface): interface GerstnerWave — ⚠ undocumented
3986
+ - `GerstnerWave` (interface): interface GerstnerWave { direction: readonly [number, number]; wavelength: number; amplitude: number; steepness: number; speed: number } — ⚠ undocumented
3470
3987
  - `WaterNormal` (type): type WaterNormal = readonly [number, number, number] — ⚠ undocumented
3471
- - `WaterSurface` (interface): interface WaterSurface — ⚠ undocumented
3472
- - `WaterSurfaceConfig` (interface): interface WaterSurfaceConfig — ⚠ undocumented
3988
+ - `WaterSurface` (interface): interface WaterSurface { readonly level: number; readonly waves: readonly GerstnerWave[]; height(x: number, z: number, time: number): number; normal(x: number, z: number, time: number): WaterNormal; displace(x: number, z: number, time: number): readonly [number, … — ⚠ undocumented
3989
+ - `WaterSurfaceConfig` (interface): interface WaterSurfaceConfig { level?: number; levelAt?: (time: number) => number; waveHeight?: number; waveScale?: number; waveSpeed?: number; waves?: number; choppiness?: number } — ⚠ undocumented
3473
3990
  - `synthesizeWaves` (function): function synthesizeWaves(config: WaterSurfaceConfig = {}): GerstnerWave[] — ⚠ undocumented
3474
3991
  - `waterSurface` (function): function waterSurface(config: WaterSurfaceConfig = {}): WaterSurface — ⚠ undocumented
3475
3992
  - `waterSurfaceFromDescriptor` (function): function waterSurfaceFromDescriptor(descriptor: OceanEnvironmentDescriptor, waves?: number): WaterSurface — ⚠ undocumented
@@ -3493,32 +4010,62 @@
3493
4010
 
3494
4011
  ## @jgengine/core/world/weather
3495
4012
 
3496
- - `FireCell` (interface): interface FireCell — ⚠ undocumented
4013
+ - `FireCell` (interface): interface FireCell { fuel: number; heat: number; state: FireCellState } — ⚠ undocumented
3497
4014
  - `FireCellState` (type): type FireCellState = "unburnt" | "burning" | "burnt" — ⚠ undocumented
3498
- - `FireGrid` (interface): interface FireGrid — ⚠ undocumented
3499
- - `FireGridConfig` (interface): interface FireGridConfig — ⚠ undocumented
3500
- - `FireStepOptions` (interface): interface FireStepOptions — ⚠ undocumented
3501
- - `ResolvedWeather` (interface): interface ResolvedWeather — ⚠ undocumented
4015
+ - `FireGrid` (interface): interface FireGrid { readonly cols: number; readonly rows: number; step(dt: number, options?: FireStepOptions): void; igniteCell(col: number, row: number): void; ignite(x: number, z: number): boolean; cell(col: number, row: number): FireCell; cellAt(x: number… — ⚠ undocumented
4016
+ - `FireGridConfig` (interface): interface FireGridConfig { cols: number; rows: number; cellSize: number; origin?: readonly [number, number]; fuelAt?: (col: number, row: number) => number; ignitionThreshold?: number; spreadRate?: number; burnRate?: number; wind?: WindVector; windBias?: number } — ⚠ undocumented
4017
+ - `FireStepOptions` (interface): interface FireStepOptions { spread?: number; wetnessAt?: (col: number, row: number) => number } — ⚠ undocumented
4018
+ - `ResolvedWeather` (interface): interface ResolvedWeather { grip: number; visibility: number; structureDamage: number; chill: number; ignition: number; spread: number } — ⚠ undocumented
3502
4019
  - `WeatherKind` (type): type WeatherKind = string — ⚠ undocumented
3503
4020
  - `WeatherKindOf` (type): type WeatherKindOf<TTable extends WeatherModifierTable> = Extract<keyof TTable, string> — ⚠ undocumented
3504
- - `WeatherModifier` (interface): interface WeatherModifier — ⚠ undocumented
4021
+ - `WeatherModifier` (interface): interface WeatherModifier { grip?: number; visibility?: number; structureDamage?: number; chill?: number; ignition?: number; spread?: number } — ⚠ undocumented
3505
4022
  - `WeatherModifierTable` (type): type WeatherModifierTable<K extends string = string> = Record<K, WeatherModifier> — ⚠ undocumented
3506
- - `WeatherState` (interface): interface WeatherState — ⚠ undocumented
4023
+ - `WeatherState` (interface): interface WeatherState { kind: WeatherKind; intensity: number; wind?: WindVector } — ⚠ undocumented
3507
4024
  - `createFireGrid` (function): function createFireGrid(config: FireGridConfig): FireGrid — ⚠ undocumented
3508
4025
  - `resolveWeather` (function): function resolveWeather<TTable extends WeatherModifierTable>(state: WeatherState, table: TTable): ResolvedWeather — ⚠ undocumented
3509
4026
 
3510
4027
  ## @jgengine/core/world/wind
3511
4028
 
3512
- - `WindField` (interface): interface WindField — ⚠ undocumented
3513
- - `WindFieldConfig` (interface): interface WindFieldConfig — ⚠ undocumented
4029
+ - `WindField` (interface): interface WindField { readonly direction: WindVector; readonly speed: number; at(time: number): WindVector; atPoint(x: number, z: number, time: number): WindVector; strengthAt(x: number, z: number, time: number): number } — ⚠ undocumented
4030
+ - `WindFieldConfig` (interface): interface WindFieldConfig { direction?: WindVector; speed?: number; gust?: number; gustFrequency?: number; turbulence?: number; seed?: string | number } — ⚠ undocumented
3514
4031
  - `WindVector` (type): type WindVector = readonly [number, number] — ⚠ undocumented
3515
4032
  - `windField` (function): function windField(config: WindFieldConfig = {}): WindField — ⚠ undocumented
3516
4033
 
3517
4034
  ## @jgengine/core/world/windZones
3518
4035
 
3519
- - `WindShiftForecast` (interface): interface WindShiftForecast — ⚠ undocumented
3520
- - `WindZoneConfig` (interface): interface WindZoneConfig — ⚠ undocumented
3521
- - `WindZoneState` (interface): interface WindZoneState — ⚠ undocumented
4036
+ - `WindShiftForecast` (interface): interface WindShiftForecast { zoneId: string; at: number; inSeconds: number; next: WindZoneState } — ⚠ undocumented
4037
+ - `WindZoneConfig` (interface): interface WindZoneConfig { id: string; center: readonly [number, number]; radius: number; phases: readonly SchedulePhase<WindZoneState>[]; offsetSeconds?: number } — ⚠ undocumented
4038
+ - `WindZoneState` (interface): interface WindZoneState { direction: WindVector; speed: number; label?: string } — ⚠ undocumented
3522
4039
  - `WindZones` (interface): interface WindZones — Named, discrete wind zones over an ambient field — each zone runs a deterministic `StateSchedule` of wind states, so games get scheduled shifts with advance announcement (`forecastShift` drives the "gale in 12s" countdown) instead of one continuous field.
3523
- - `WindZonesConfig` (interface): interface WindZonesConfig — ⚠ undocumented
4040
+ - `WindZonesConfig` (interface): interface WindZonesConfig { zones: readonly WindZoneConfig[]; ambient?: WindField } — ⚠ undocumented
3524
4041
  - `createWindZones` (function): function createWindZones(config: WindZonesConfig): WindZones — ⚠ undocumented
4042
+
4043
+ ## @jgengine/core/world/worldSolids
4044
+
4045
+ - `WallSolidOptions` (interface): interface WallSolidOptions — Wall height, thickness and base for {@link wallSolids}.
4046
+ - `WorldSolid` (interface): interface WorldSolid — One solid box in world space: the collision half of generated or authored world geometry.
4047
+ - `WorldSolids` (interface): interface WorldSolids — Static collision for world geometry that is not a scene object: generated buildings, studio volumes like `city`, wall runs. Solids live in named layers so a feature can replace or drop its own set without touching the rest. `solidObstaclesNear` (player and NPC movement), `syncWorldColliders` (physics backends) and `populateNavGridFromSolids` all read this one store.
4048
+ - `WorldSolidsState` (interface): interface WorldSolidsState — Serializable contents of a {@link WorldSolids}: every layer's solids by layer id.
4049
+ - `buildingSolids` (function): function buildingSolids(buildings: readonly GeneratedBuilding[], groundHeight: (x: number, z: number) => number = () => 0): WorldSolid[] — One solid per generated building: its `bounds` footprint turned by `rotationY` about `center`, from the ground under its center up through its floors. `groundHeight` defaults to flat `0`.
4050
+ - `createWorldSolids` (function): function createWorldSolids(options: { cellSize?: number } = {}): WorldSolids — A store of static world solids in named layers.
4051
+ - `structureSolids` (function): function structureSolids(world: EnvironmentWorldFeature, groundHeight?: (x: number, z: number) => number): WorldSolid[] — Solids for every `structures` descriptor on an environment feature, skipping any marked `solid: false`.
4052
+ - `wallSolids` (function): function wallSolids(segments: readonly WallSegment[], options: WallSolidOptions): WorldSolid[] — One oriented solid per wall segment (see `wallSegments` in `world/walls`).
4053
+ - `worldSolidBounds` (function): function worldSolidBounds(solid: WorldSolid): { min: [number, number, number]; max: [number, number, number]; } — Yaw-expanded world AABB of an oriented solid box.
4054
+ - `worldSolidFootprint` (function): function worldSolidFootprint(solid: WorldSolid): Aabb — XZ footprint of a solid's world AABB, for 2D consumers such as nav grids.
4055
+
4056
+ ## @jgengine/navbake
4057
+
4058
+ - `BakeNavMeshOptions` (interface): interface BakeNavMeshOptions — Walkable geometry and agent dimensions for {@link bakeNavMesh}.
4059
+ - `bakeNavMesh` (function): function bakeNavMesh(options: BakeNavMeshOptions): NavMeshData — Voxelize indexed triangles with recast and return the walkable surface as convex polygons in the engine's serializable nav-mesh format: eroded by `agentRadius`, cut where clearance is under `agentHeight`, and split at slopes over `maxSlope` or steps over `maxClimb`. Requires {@link initNavBake}.
4060
+ - `initNavBake` (function): function initNavBake(): Promise<void> — Load the recast WebAssembly module once; await before the first {@link bakeNavMesh}.
4061
+ - `navBakeReady` (function): function navBakeReady(): boolean — Whether {@link initNavBake} has finished and {@link bakeNavMesh} can run synchronously.
4062
+
4063
+ ## @jgengine/rapier
4064
+
4065
+ - `RapierBackendOptions` (interface): interface RapierBackendOptions extends PhysicsBackendConfig — Construction options for the Rapier-backed {@link PhysicsBackend}.
4066
+ - `createRapierBackend` (function): function createRapierBackend(options: RapierBackendOptions = {}): Promise<PhysicsBackend> — Create a Rapier-backed {@link PhysicsBackend}; initialization loads Rapier's WASM module asynchronously.
4067
+
4068
+ ## @jgengine/rapier/rapierBackend
4069
+
4070
+ - `RapierBackendOptions` (interface): interface RapierBackendOptions extends PhysicsBackendConfig — Construction options for the Rapier-backed {@link PhysicsBackend}.
4071
+ - `createRapierBackend` (function): function createRapierBackend(options: RapierBackendOptions = {}): Promise<PhysicsBackend> — Create a Rapier-backed {@link PhysicsBackend}; initialization loads Rapier's WASM module asynchronously.