@jgengine/shell 0.14.0 → 0.15.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 (115) hide show
  1. package/CHANGELOG.md +500 -1
  2. package/dist/GamePlayerShell.js +25 -5
  3. package/dist/Shell3dPresentation.d.ts +6 -6
  4. package/dist/Shell3dPresentation.js +4 -4
  5. package/dist/audio/synthEngine.js +12 -2
  6. package/dist/camera/ControllerCameraShake.d.ts +31 -0
  7. package/dist/camera/ControllerCameraShake.js +34 -0
  8. package/dist/camera/GameCameraRig.js +10 -5
  9. package/dist/camera/GameOrbitCamera.js +1 -10
  10. package/dist/camera/cameraRigs.js +12 -4
  11. package/dist/camera/index.d.ts +1 -0
  12. package/dist/camera/index.js +1 -0
  13. package/dist/camera/rigMath.d.ts +2 -0
  14. package/dist/camera/rigMath.js +7 -0
  15. package/dist/devtools/CollisionDebugWorld.js +2 -2
  16. package/dist/devtools/DevtoolsOverlay.js +2 -0
  17. package/dist/drivers/FrameDriver.d.ts +4 -1
  18. package/dist/drivers/FrameDriver.js +5 -3
  19. package/dist/environment/DayNightSky.d.ts +33 -0
  20. package/dist/environment/DayNightSky.js +51 -0
  21. package/dist/environment/Daylight.d.ts +3 -1
  22. package/dist/environment/Daylight.js +7 -3
  23. package/dist/environment/EnvironmentScene.js +6 -6
  24. package/dist/environment/RoadJunctions.d.ts +8 -4
  25. package/dist/environment/RoadJunctions.js +16 -15
  26. package/dist/environment/RoadRibbons.d.ts +42 -6
  27. package/dist/environment/RoadRibbons.js +150 -27
  28. package/dist/environment/VolumetricClouds.js +3 -3
  29. package/dist/environment/index.d.ts +1 -0
  30. package/dist/environment/index.js +1 -0
  31. package/dist/gameKit.d.ts +7 -4
  32. package/dist/gameKit.js +8 -5
  33. package/dist/inputSink.js +14 -0
  34. package/dist/materialOverride.js +30 -0
  35. package/dist/postfx/PostProcessing.d.ts +3 -2
  36. package/dist/postfx/PostProcessing.js +11 -3
  37. package/dist/postfx/ScreenEffectsOverlay.d.ts +32 -0
  38. package/dist/postfx/ScreenEffectsOverlay.js +70 -0
  39. package/dist/presentationResolve.d.ts +3 -2
  40. package/dist/presentationResolve.js +11 -6
  41. package/dist/render/CascadedShadows.d.ts +13 -0
  42. package/dist/render/CascadedShadows.js +96 -0
  43. package/dist/render/EnvironmentLighting.d.ts +23 -7
  44. package/dist/render/EnvironmentLighting.js +69 -10
  45. package/dist/render/PartMotion.js +4 -4
  46. package/dist/render/SceneLighting.js +7 -0
  47. package/dist/render/SceneModels.d.ts +37 -1
  48. package/dist/render/SceneModels.js +40 -11
  49. package/dist/render/modelLoad.d.ts +41 -5
  50. package/dist/render/modelLoad.js +85 -18
  51. package/dist/render/sceneCapture.d.ts +27 -0
  52. package/dist/render/sceneCapture.js +43 -0
  53. package/dist/render/useDisposable.d.ts +16 -0
  54. package/dist/render/useDisposable.js +24 -0
  55. package/dist/render/useModelAnimation.js +47 -4
  56. package/dist/scene/AuthoredScene.js +14 -24
  57. package/dist/scene/CityRenderer.js +103 -36
  58. package/dist/scene/GrassFieldRenderer.js +4 -1
  59. package/dist/scene/PoleLineRenderer.js +7 -16
  60. package/dist/settings/QuickControls.js +5 -3
  61. package/dist/settings/SettingsMenu.js +6 -3
  62. package/dist/settings/appliedSettings.d.ts +3 -1
  63. package/dist/settings/appliedSettings.js +17 -5
  64. package/dist/settings/settingsController.js +11 -5
  65. package/dist/shellMovement.d.ts +15 -1
  66. package/dist/shellMovement.js +15 -1
  67. package/dist/structures/GeneratedBuilding.js +4 -5
  68. package/dist/structures/TransformGizmo.js +6 -5
  69. package/dist/terrain/CarvedTerrain.js +3 -7
  70. package/dist/terrain/GrassField.js +2 -2
  71. package/dist/terrain/ProceduralGround.js +3 -5
  72. package/dist/terrain/grassMaterial.d.ts +8 -2
  73. package/dist/terrain/grassMaterial.js +24 -5
  74. package/dist/terrain/index.d.ts +1 -1
  75. package/dist/terrain/terrainDetailMaterial.js +11 -2
  76. package/dist/terrain/terrainMath.d.ts +38 -1
  77. package/dist/terrain/terrainMath.js +86 -64
  78. package/dist/touch/TouchControlsOverlay.d.ts +6 -2
  79. package/dist/touch/TouchControlsOverlay.js +136 -17
  80. package/dist/vfx/ParticleField.d.ts +32 -0
  81. package/dist/vfx/ParticleField.js +91 -0
  82. package/dist/vfx/WorldFloatingText.d.ts +32 -0
  83. package/dist/vfx/WorldFloatingText.js +32 -0
  84. package/dist/water/Ocean.js +3 -6
  85. package/dist/weather/LightningStrike.js +3 -9
  86. package/dist/weather/RainField.js +3 -7
  87. package/dist/weather/SnowField.js +3 -7
  88. package/dist/world/DataObjects.js +3 -6
  89. package/dist/world/GridWorldScene.js +3 -6
  90. package/dist/world/InstancedBodies.js +3 -6
  91. package/dist/world/InstancedJoints.js +2 -2
  92. package/dist/world/SpriteBatch.js +3 -6
  93. package/dist/world/WorldEntityFrames.d.ts +47 -0
  94. package/dist/world/WorldEntityFrames.js +75 -0
  95. package/dist/world/WorldHud.js +7 -5
  96. package/dist/world/WorldPings.d.ts +26 -0
  97. package/dist/world/WorldPings.js +68 -0
  98. package/dist/world/WorldScene.js +9 -4
  99. package/dist/world/pingPulse.d.ts +21 -0
  100. package/dist/world/pingPulse.js +17 -0
  101. package/package.json +5 -5
  102. package/skills/ce-handoff/SKILL.md +149 -0
  103. package/skills/game-design/SKILL.md +2 -0
  104. package/skills/jgengine/SKILL.md +3 -1
  105. package/skills/jgengine/api.md +17 -7
  106. package/skills/jgengine/capabilities.md +12 -0
  107. package/skills/jgengine/recipes/minimal-game.md +7 -4
  108. package/skills/jgengine-ui/SKILL.md +5 -3
  109. package/skills/jgengine-ui/api.md +708 -19
  110. package/skills/jgengine-ui/capabilities.md +362 -1
  111. package/skills/jgengine-ui/recipes/overhead-entity-frames.md +136 -0
  112. package/skills/jgengine-ui/reference.md +7 -4
  113. package/skills/jgengine-world/api.md +397 -11
  114. package/skills/jgengine-world/capabilities.md +123 -2
  115. package/skills/jgengine-world/reference.md +15 -1
@@ -14,6 +14,34 @@
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/difficulty
18
+
19
+ - `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.
20
+ - `DifficultyProfile` (interface): interface DifficultyProfile — Serializable decision-quality data. All fields are plain numbers so a profile can live in a save, an encounter definition, or a per-entity spawn record.
21
+ - `DifficultyTier` (type): type DifficultyTier = "easy" | "standard" | "expert" — Difficulty is decision *quality*, owned in one place: a serializable {@link DifficultyProfile} describing how fast, how accurately, and how far ahead an agent decides, plus appliers at the universal decision seams every opponent shares — reacting to new information, choosing among scored options, executing with error, spending abilities, and planning ahead. The same profile tunes an RTS grunt, a street enemy, a boss's special-ability discipline, or a turn-based lookahead player; the game supplies the domain (candidates, scores, moves) and this module degrades or sharpens the choice. Three canonical tiers ({@link DIFFICULTY_TIERS}) cover "kinda dumb / smart / super smart"; per-game overrides stay data.
22
+ - `LookaheadDomain` (interface): interface LookaheadDomain<S, M> — The game-owned decision domain {@link planLookahead} searches. States and moves are caller types; the planner never inspects them.
23
+ - `ReactionGateState` (interface): interface ReactionGateState<T> — Serializable reaction-gate state: the value the agent is currently acting on plus the newer value it has noticed but not yet committed to. `T` should be serializable (ids, positions as tuples) if the gate lives in saved state.
24
+ - `ScoredOption` (interface): interface ScoredOption<T> — One candidate with a caller-computed score; higher is better.
25
+ - `advanceReactionGate` (function): function advanceReactionGate<T>(state: ReactionGateState<T>, dt: number, desired: T, profile: DifficultyProfile): T — Advance one reaction step and return the value to act on. `desired` is what a perfect agent would act on this frame (current best target, latest known player position); the gate holds the previously committed value until `desired` has been stable for `profile.reactionSeconds`, restarting the delay whenever `desired` changes again (compared with `Object.is`). Feed the returned value — not `desired` — into pursuit/aim/ability logic. Mutates `state` in place; allocation-free.
26
+ - `createReactionGate` (function): function createReactionGate<T>(initial: T): ReactionGateState<T> — A fresh gate already committed to `initial`.
27
+ - `difficultyProfile` (function): function difficultyProfile(tier: DifficultyTier, overrides?: Partial<DifficultyProfile>): DifficultyProfile — A fresh profile from a canonical tier with optional per-game overrides — e.g. an "easy" boss that still reacts fast: `difficultyProfile("easy", { reactionSeconds: 0.2 })`.
28
+ - `executionError` (function): function executionError(profile: DifficultyProfile, rng: () => number, scale = 1): number — Symmetric execution error in `[-scale * executionJitter, +scale * executionJitter]` — add it to a yaw, a lead time, a throw power, or a release timestamp. `scale` maps the unitless jitter onto the caller's units (e.g. pass max miss radians).
29
+ - `pickScored` (function): function pickScored<T>(options: readonly ScoredOption<T>[], profile: DifficultyProfile, rng: () => number): T | null — Choose from a scored option list at the profile's quality: with probability `profile.decisionNoise` the pick is uniform over all options (the "wrong target / bad move" mistake), otherwise it is the best score (first wins ties). Works over any decision the game can score — acquisition candidates, ability choices, retreat routes, chess moves. Returns `null` for an empty list. Allocation-free scan; one rng draw plus one more on a noisy pick.
30
+ - `planLookahead` (function): function planLookahead<S, M>(root: S, domain: LookaheadDomain<S, M>, profile: DifficultyProfile, rng: () => number): M | null — Pick the agent's next move by bounded lookahead: a depth-limited negamax (or single-perspective sequence search when `adversarial: false`) over the caller's {@link LookaheadDomain}, exploring at most `profile.planWidth` moves per ply to `profile.planDepth` plies, with the final root choice run through {@link pickScored} so `decisionNoise` still injects tier-appropriate blunders. Depth `1` is greedy — an easy profile literally cannot see the fork coming; an expert profile finds multi-ply tactics. Work is bounded by `planWidth ** planDepth` domain calls; run it at decision cadence (turns, ability windows, order re-evaluation), not per frame.
31
+ - `shouldUseAbility` (function): function shouldUseAbility(opportunity: number, profile: DifficultyProfile, rng: () => number): boolean — Should the agent spend an ability now? `opportunity` is the caller-scored quality of this moment in `0..1` (targets clumped for the AoE, player mid-animation, burn phase). The perceived opportunity is fuzzed by `decisionNoise` and compared against `abilityDiscipline`: an easy profile (low discipline, high noise) wastes cooldowns on weak moments and sometimes sits on a perfect window; an expert profile fires exactly on strong windows. One rng draw when noisy.
32
+
33
+ ## @jgengine/core/ai/driver
34
+
35
+ - `DrivePathPoint` (type): type DrivePathPoint = readonly [number, number] — A 2D polyline point (`[x, z]`), structurally compatible with authored road path centerlines.
36
+ - `DriverGoal` (interface): interface DriverGoal — Where the driver is trying to go this step.
37
+ - `DriverPose` (interface): interface DriverPose — A difficulty-aware driver brain: pose + goal in, the shared {@link AxisInput} (`throttle`/`brake`/`steer`/`handbrake`) out, ready for `tickDrivableVehicle` — the chase/traffic steering loop every game with AI cars hand-rolls as `steer = error * k, throttle = 1`. A {@link DifficultyProfile} decides how *well* it drives: reaction time trails the target, corners shed speed instead of orbiting at full throttle, obstacles are noticed late on low tiers, the wheel wobbles by `executionJitter`, and a stuck car backs out with counter-steer after grinding for a tier-scaled while. State is one small serializable object; randomness is injected; every step is allocation-light scalar math. The caller owns the sim, collision, and all spatial queries — this module never scans the world.
38
+ - `DriverState` (interface): interface DriverState — Serializable per-driver state advanced in place by {@link driveStep}.
39
+ - `DriverStep` (interface): interface DriverStep extends AxisInput — {@link driveStep}'s result: the axis sample to feed the vehicle sim, plus arrival.
40
+ - `DriverTuning` (interface): interface DriverTuning — Vehicle-feel numbers the game supplies; everything has a sensible default except `maxSpeed`.
41
+ - `createDriverState` (function): function createDriverState(targetX = 0, targetZ = 0): DriverState — Fresh driver state committed to an initial target (usually the spawn-time goal or the spawn position itself).
42
+ - `driveStep` (function): function driveStep(state: DriverState, dt: number, pose: DriverPose, goal: DriverGoal, profile: DifficultyProfile, tuning: DriverTuning, rng: () => number, obstacleAhead: number | null = null): DriverStep — Advance one driving step, mutating `state`, and return the {@link AxisInput} to feed the vehicle sim. `obstacleAhead` is the caller-measured distance to the nearest blocker in the driving corridor this step (`null`/omitted when clear) — the driver perceives it late by `speed * reactionSeconds`, so easy tiers brake at the last moment and expert tiers with proper margin. The steering target is a delay-line over the goal — resampled every `reactionSeconds`, so it trails a moving goal by up to that long, which is what makes an easy chaser visibly cut toward where the target *was*. When throttle produces no motion for a tier-scaled while the driver reverses out with counter-steer (brake past standstill — the shared sim's reverse).
43
+ - `pathTargetAhead` (function): function pathTargetAhead(path: readonly DrivePathPoint[], x: number, z: number, lookahead: number, loop = false): DrivePathPoint | null — The pure-pursuit target for street/route following: the point `lookahead` meters further along the polyline from wherever the vehicle currently projects onto it. Feed the result to {@link driveStep} as the goal each tick and the driver follows the road; `loop` wraps a circuit (traffic block, race lap) instead of pinning at the final point. Returns `null` for a degenerate path. Give sharper tiers a longer `lookahead` to cut corners cleanly and duller tiers a short one so they steer segment-to-segment.
44
+
17
45
  ## @jgengine/core/ai/flock
18
46
 
19
47
  - `FlockAgent` (interface): interface FlockAgent — ⚠ undocumented
@@ -139,6 +167,14 @@
139
167
  - `ThreatTableConfig` (interface): interface ThreatTableConfig — ⚠ undocumented
140
168
  - `createThreatTable` (function): function createThreatTable(config: ThreatTableConfig = {}): ThreatTable — ⚠ undocumented
141
169
 
170
+ ## @jgengine/core/ai/waveRunner
171
+
172
+ - `WaveRunner` (interface): interface WaveRunner — A live, observable, serializable wave/spawn runner over a seeded spawn director.
173
+ - `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.
174
+ - `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.
175
+ - `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
+ - `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
+
142
178
  ## @jgengine/core/anim/easing
143
179
 
144
180
  - `Easing` (type): type Easing = (t: number) => number — ⚠ undocumented
@@ -187,6 +223,25 @@
187
223
  - `notesInWindow` (function): function notesInWindow(theme: MusicTheme, anchorSec: number, fromSec: number, toSec: number): ScheduledNote[] — Pure lookahead scheduler: every note occurrence of `theme` whose onset falls in the half-open window `(fromSec, toSec]`, given the theme's loop-zero at `anchorSec`. Handles any number of loop wraps, so a director calls it once per tick with a non-overlapping window and never double-schedules a note.
188
224
  - `themeLoopSeconds` (function): function themeLoopSeconds(theme: MusicTheme): number — Loop length of a theme in seconds.
189
225
 
226
+ ## @jgengine/core/audio/musicState
227
+
228
+ - `MusicStateConfig` (interface): interface MusicStateConfig — The tier ladder plus the release margin that keeps a hovering intensity from flapping between tiers.
229
+ - `MusicStateInput` (interface): interface MusicStateInput — The current intensity signal and clock reading for one resolve.
230
+ - `MusicStateResult` (interface): interface MusicStateResult — Next state, the theme that should be playing, and whether this advance is the one that changed it.
231
+ - `MusicStateSnapshot` (interface): interface MusicStateSnapshot — Which tier is playing and when it was entered, on the caller's clock. Serialisable.
232
+ - `MusicTier` (interface): interface MusicTier — Hysteretic music-state selector: turns a continuous intensity signal (nearby threat, alert count, chase proximity) into a stable theme id. The engine can already crossfade a soundtrack; this decides *when*, without the flapping a bare threshold produces when one enemy walks in and out of range.
233
+ - `createMusicState` (function): function createMusicState(): MusicStateSnapshot — Fresh state with no tier entered, so the first resolve always settles and reports `changed`.
234
+ - `resolveMusicState` (function): function resolveMusicState(state: MusicStateSnapshot, input: MusicStateInput, config: MusicStateConfig): MusicStateResult — Pick the theme for the current intensity. Escalation is immediate; de-escalation waits for the tier's `holdMs` and needs the intensity to fall a `release` margin below the tier it is leaving.
235
+
236
+ ## @jgengine/core/audio/stepCadence
237
+
238
+ - `StepCadenceConfig` (interface): interface StepCadenceConfig — Distance-driven footstep cadence. Pure state-in/state-out: feed it how far a mover travelled this frame and it tells you how many steps landed, so foley stays locked to ground distance instead of a wall-clock timer that desyncs when speed changes.
239
+ - `StepCadenceInput` (interface): interface StepCadenceInput — What the mover did this advance: ground distance covered, whether feet are planting, and the stride multiplier.
240
+ - `StepCadenceResult` (interface): interface StepCadenceResult — Outcome of one advance: the next state plus how many steps landed and which foot led.
241
+ - `StepCadenceState` (interface): interface StepCadenceState — Cadence bookkeeping between advances — banked distance, last moving state, and the step count whose parity is the foot.
242
+ - `advanceStepCadence` (function): function advanceStepCadence(state: StepCadenceState, input: StepCadenceInput, config: StepCadenceConfig): StepCadenceResult — Bank this advance's distance and report the steps it completed. Pure — same state and input always give the same result, so footstep timing is testable headless and replays identically.
243
+ - `createStepCadenceState` (function): function createStepCadenceState(): StepCadenceState — Fresh cadence state for a mover that is standing still.
244
+
190
245
  ## @jgengine/core/audio/synth
191
246
 
192
247
  - `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`.
@@ -299,6 +354,23 @@
299
354
  - `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.
300
355
  - `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]`.
301
356
 
357
+ ## @jgengine/core/input/rebindSession
358
+
359
+ - `RebindActionConfig` (interface): interface RebindActionConfig — One rebindable action as declared to {@link createRebindSession}. The `id` and `label` are FREE strings the session never interprets — the game owns their meaning and display text. `defaultCodes` is the authored binding the session resets back to.
360
+ - `RebindConflict` (interface): interface RebindConflict — A group of actions bound to the same normalized code — the conflict this session detects.
361
+ - `RebindRow` (interface): interface RebindRow — One controls-list row: an action, its effective binding, and any conflicts.
362
+ - `RebindSession` (interface): interface RebindSession — A live, observable, conflict-aware key-remap editor over the action-binding model.
363
+ - `RebindSessionActionsConfig` (interface): interface RebindSessionActionsConfig extends RebindSessionCommon — Declare actions explicitly, in list order.
364
+ - `RebindSessionConfig` (type): type RebindSessionConfig = RebindSessionActionsConfig | RebindSessionMapConfig — Config for {@link createRebindSession}: an explicit action list, or an {@link ActionCodesMap} + labels.
365
+ - `RebindSessionMapConfig` (interface): interface RebindSessionMapConfig extends RebindSessionCommon — Declare actions from an authored {@link ActionCodesMap}, labelled by `labels` (falling back to the id).
366
+ - `RebindSessionSnapshot` (interface): interface RebindSessionSnapshot — Serializable session state for save/restore.
367
+ - `createRebindSession` (function): function createRebindSession(config: RebindSessionConfig): RebindSession — A conflict-aware key-remap session over the action-binding model — the missing editor behind a controls-settings menu. It takes the game's authored actions ({@link RebindActionConfig}s, or an {@link ActionCodesMap} + labels) plus the player's saved {@link BindingOverrides}, and tracks the *effective* binding per action (default merged with the override via `applyBindingOverrides`). `rows()` exposes each action's label, current key glyph (via `bindingLabel`), whether it is still the default, and which other actions it collides with; `conflicts()` groups every action pair sharing a normalized code (the value-add a raw override map can't give you). `beginCapture`/`capture`/`cancelCapture` drive a "press a key" rebind (codes normalized via `normalizeKeyCode`), `reset`/ `resetAll` return to defaults, and `overrides()`/`apply()` hand the caller the `BindingOverrides` to persist. Nothing here is genre-specific: action ids and labels are free strings the session never interprets, and hold/toggle/repeat binding shapes survive a rebind. `snapshot`/`restore` round-trips the editor (including the in-flight capture) through a save.
368
+
369
+ ## @jgengine/core/input/touchControlsMode
370
+
371
+ - `activeTouchControlsMode` (function): function activeTouchControlsMode(ctx: GameContext): string | null — The active touch control mode, `null` when the base config applies.
372
+ - `setTouchControlsMode` (function): function setTouchControlsMode(ctx: GameContext, mode: string | null): void — Activate a named touch control mode, or `null` to return to the base config.
373
+
302
374
  ## @jgengine/core/input/touchGestures
303
375
 
304
376
  - `TouchGestureEnd` (type): type TouchGestureEnd = "tap" | "hold-end" | null — ⚠ undocumented
@@ -308,10 +380,13 @@
308
380
 
309
381
  ## @jgengine/core/input/touchScheme
310
382
 
383
+ - `DEFAULT_TOUCH_JOYSTICK_VARIANT` (const): const DEFAULT_TOUCH_JOYSTICK_VARIANT: TouchJoystickVariant — Variant used when the player has not picked one.
311
384
  - `DEFAULT_TOUCH_STYLE` (const): const DEFAULT_TOUCH_STYLE: TouchStyle — Skin used when neither the game nor the player picks one.
312
385
  - `DeriveTouchSchemeOptions` (interface): interface DeriveTouchSchemeOptions — ⚠ undocumented
313
386
  - `ResolvedTouchLayout` (interface): interface ResolvedTouchLayout — The dock zone each cluster resolved to, after applying game config over the bottom-layout defaults.
314
387
  - `TOUCH_CODE_PREFIX` (const): const TOUCH_CODE_PREFIX: "touch:" — ⚠ undocumented
388
+ - `TOUCH_JOYSTICK_VARIANTS` (const): const TOUCH_JOYSTICK_VARIANTS: readonly TouchJoystickVariant[] — Every joystick variant id, in menu order.
389
+ - `TOUCH_JOYSTICK_VARIANT_OPTIONS` (const): const TOUCH_JOYSTICK_VARIANT_OPTIONS: readonly { value: TouchJoystickVariant; label: string }[] — Joystick variants as `{ value, label }` rows for the Settings → Controls selector.
315
390
  - `TOUCH_STYLES` (const): const TOUCH_STYLES: readonly TouchStyle[] — Every touch skin id, in menu order.
316
391
  - `TOUCH_STYLE_OPTIONS` (const): const TOUCH_STYLE_OPTIONS: readonly { value: TouchStyle; label: string }[] — Touch skins as `{ value, label }` rows for the Settings → Controls selector.
317
392
  - `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.
@@ -319,15 +394,17 @@
319
394
  - `TouchButtonKind` (type): type TouchButtonKind = "primary" | "utility" — ⚠ undocumented
320
395
  - `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.
321
396
  - `TouchButtonSpec` (interface): interface TouchButtonSpec — ⚠ undocumented
322
- - `TouchControlsConfig` (interface): interface TouchControlsConfig — ⚠ undocumented
397
+ - `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
+ - `TouchControlsModeConfig` (type): type TouchControlsModeConfig = Omit<TouchControlsConfig, "modes"> — One named control context's touch config — the same shape as the base config, minus nested modes.
323
399
  - `TouchDragBinding` (interface): interface TouchDragBinding — ⚠ undocumented
324
400
  - `TouchGestureBindings` (interface): interface TouchGestureBindings — ⚠ undocumented
325
401
  - `TouchJoystick` (interface): interface TouchJoystick — ⚠ undocumented
402
+ - `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.
326
403
  - `TouchLayoutConfig` (interface): interface TouchLayoutConfig — Where each touch cluster docks; unset falls back to the classic bottom layout.
327
404
  - `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.
328
405
  - `TouchScheme` (interface): interface TouchScheme — ⚠ undocumented
329
406
  - `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.
330
- - `deriveTouchScheme` (function): function deriveTouchScheme(input: ActionCodesMap | undefined, { reserved, firstPerson, config }: DeriveTouchSchemeOptions): TouchScheme | null — Null means "render no touch controls" — either the game opted out or there is nothing to synthesize.
407
+ - `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.
331
408
  - `touchActionLabel` (function): function touchActionLabel(action: string): string — ⚠ undocumented
332
409
  - `touchButtonKind` (function): function touchButtonKind(action: string): TouchButtonKind — ⚠ undocumented
333
410
  - `touchButtonShape` (function): function touchButtonShape(action: string): TouchButtonShape — Default silhouette for an action; `circle` when nothing more specific fits.
@@ -360,6 +437,13 @@
360
437
  - `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.
361
438
  - `visibleCells` (function): function visibleCells(spec: LockSpec, col: number, window: number): LockCell[] — The render-safe slice: every open cell in columns [0, col + window]. The single source of truth for fog and the anti-cheat boundary — never serialize the full spec to a client.
362
439
 
440
+ ## @jgengine/core/interaction/promptRegistry
441
+
442
+ - `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.
443
+ - `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.
444
+ - `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.
445
+ - `createPromptRegistry` (function): function createPromptRegistry(): PromptRegistry — Create a live, observable interaction-prompt registry over the pure {@link resolveActivePrompt} resolver. Register positioned "press E" prompts, `resolve(playerPosition)` each frame as the hero moves, and read `active()` — the nearest strictly-in-range prompt (higher `priority` beats closer). The set is owned here (register/update/unregister/clear/all); selection stays pure. Subscribers are notified only when the active prompt *changes*, so a HUD does not thrash per frame, and `snapshot`/`restore` round-trip the prompts plus the active id through a save (display payloads are free strings/ids the game owns — the registry never branches on their meaning). Allocation-aware: `all()` and `resolve()` reuse a cached array instead of rebuilding per call.
446
+
363
447
  ## @jgengine/core/interaction/proximityPrompt
364
448
 
365
449
  - `GaugePromptDisplay` (interface): interface GaugePromptDisplay — ⚠ undocumented
@@ -470,6 +554,7 @@
470
554
 
471
555
  ## @jgengine/core/movement/movementModel
472
556
 
557
+ - `AnalogMoveIntent` (interface): interface AnalogMoveIntent — Analog movement vector (camera-relative, each axis in [-1, 1]) from a continuous source — a virtual joystick or gamepad stick. When present it replaces the digital WASD axes so a slight tilt walks slightly instead of slamming a full strafe.
473
558
  - `CollisionObstacle` (interface): interface CollisionObstacle — A placed scene object the walking player collides against as a circle-vs-AABB obstacle.
474
559
  - `MAX_JUMP_OFFSET` (const): const MAX_JUMP_OFFSET: 1.15 — Peak jump height from MOVEMENT_TUNING.jumpVelocity + gravity, with small buffer.
475
560
  - `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.
@@ -712,6 +797,7 @@
712
797
 
713
798
  ## @jgengine/core/physics/kinematicVehicle
714
799
 
800
+ - `DEFAULT_REVERSE_FORCE_SCALE` (const): const DEFAULT_REVERSE_FORCE_SCALE: 0.48 — Default reverse drive force as a fraction of forward `engineForce` / `engineAccel`.
715
801
  - `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.
716
802
  - `KinematicDynamicsTuning` (interface): interface KinematicDynamicsTuning — Aerodynamic and electronic-assist settings layered over tire grip.
717
803
  - `KinematicPowertrainTuning` (interface): interface KinematicPowertrainTuning — Data-first gearbox and torque-curve tuning for a kinematic ground vehicle.
@@ -721,7 +807,7 @@
721
807
  - `KinematicVehicleOptions` (interface): interface KinematicVehicleOptions — ⚠ undocumented
722
808
  - `KinematicVehicleStep` (interface): interface KinematicVehicleStep — ⚠ undocumented
723
809
  - `KinematicVehicleTuning` (interface): interface KinematicVehicleTuning — ⚠ undocumented
724
- - `createKinematicVehicle` (function): function createKinematicVehicle(tuning: KinematicVehicleTuning, options: KinematicVehicleOptions = {}): KinematicVehicle — ⚠ undocumented
810
+ - `createKinematicVehicle` (function): function createKinematicVehicle(initialTuning: KinematicVehicleTuning, options: KinematicVehicleOptions = {}): KinematicVehicle — ⚠ undocumented
725
811
 
726
812
  ## @jgengine/core/physics/physicsWorld
727
813
 
@@ -931,7 +1017,7 @@
931
1017
 
932
1018
  - `CaptureCheckInput` (interface): interface CaptureCheckInput — ⚠ undocumented
933
1019
  - `captureChance` (function): function captureChance(input: CaptureCheckInput): number — ⚠ undocumented
934
- - `rollCapture` (function): function rollCapture(input: CaptureCheckInput, rng: () => number = Math.random): boolean — ⚠ undocumented
1020
+ - `rollCapture` (function): function rollCapture(input: CaptureCheckInput, rng?: () => number): boolean — ⚠ undocumented
935
1021
 
936
1022
  ## @jgengine/core/scene/colliders
937
1023
 
@@ -989,7 +1075,7 @@
989
1075
  - `EntityPosition` (type): type EntityPosition = readonly [number, number, number] — ⚠ undocumented
990
1076
  - `EntityRole` (type): type EntityRole = "player" | "npc" | "prop" — ⚠ undocumented
991
1077
  - `EntityStore` (interface): interface EntityStore<TMeta = unknown> — ⚠ undocumented
992
- - `EntityUpdatePatch` (type): type EntityUpdatePatch<TMeta = unknown> = Partial< Pick<SceneEntity<TMeta>, "name" | "rotationY" | "rotationX" | "rotationZ" | "role" | "movement" | "behaviors" | "meta"> > & { /** Accepts the same friendly shapes as `spawn`/`setPose` (#286.13). Raw patch semantics — velocity is not derived; use `se… — ⚠ undocumented
1078
+ - `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
993
1079
  - `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.
994
1080
  - `PoseConstraintFrame` (interface): interface PoseConstraintFrame — ⚠ undocumented
995
1081
  - `SceneEntity` (interface): interface SceneEntity<TMeta = unknown> — ⚠ undocumented
@@ -1110,6 +1196,7 @@
1110
1196
  - `TextParamField` (interface): interface TextParamField — A free string input.
1111
1197
  - `WeightedListParamField` (interface): interface WeightedListParamField — A repeatable list of weighted `{ item, weight }` rows (species palette, book set, …).
1112
1198
  - `WeightedParamEntry` (interface): interface WeightedParamEntry — One weighted entry in a `weightedList` param — an item id and its relative spawn weight.
1199
+ - `definePlaceableMarkerKind` (function): function definePlaceableMarkerKind(options: { kind: string; label: string; /** `+ Add` menu section header this kind groups under. Defaults to `"Custom"`. */ category?: string; /** Accent hex for the menu entry + inspector header. */ accent?: string; /** Optional inspector fields written into each m… — Declare a game's own **click-to-place** marker kind in one call — the light path for logical markers a game reads off the document by `kind` (a stash, checkpoint, spawn point, bounty…), with none of a full studio's schema/resolver boilerplate. Registering it makes the kind a click-to-place tool in the editor's `+ Add` menu (grouped under `category`) and gives its markers an inspector for any `fields` you pass. Call at module load from a module the editor loads (a game's `editorLayers` import graph). Rendering is unaffected — the game still reads `kind` off `editorLayers.markers`.
1113
1200
  - `findSchemaPreset` (function): function findSchemaPreset(schema: ParamSchema, id: string): ParamPreset | undefined — Look up a schema preset by id, or undefined — the seam `apply_preset` and games resolve bundles through.
1114
1201
  - `parseParams` (function): function parseParams(schema: ParamSchema, meta: Record<string, unknown> | undefined): ParsedParams — Parse a raw `meta` bag against a schema into typed params — every field present, invalid/missing values replaced by the field default, numbers clamped to their range. The single parser every studio shares instead of hand-writing its own `metaNumber`/`metaBool` ladder.
1115
1202
  - `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.
@@ -1151,6 +1238,17 @@
1151
1238
  - `createSelectionBookmarks` (function): function createSelectionBookmarks(snapshot?: SelectionBookmarkSnapshot): SelectionBookmarks — Create a keyed bookmark store, optionally restored from a {@link serialize} snapshot. Restoration re-dedupes and drops empty sets, so a hand-authored or migrated snapshot always normalizes to the same invariants a live store holds.
1152
1239
  - `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.
1153
1240
 
1241
+ ## @jgengine/core/scene/sequenceDirector
1242
+
1243
+ - `CueListener` (type): type CueListener<Payload = unknown> = (emitted: EmittedCue<Payload>) => void — A cue listener, called once per cue as it fires. Returns nothing.
1244
+ - `EmittedCue` (interface): interface EmittedCue<Payload = unknown> — A cue plus the resolved firing context passed to {@link SequenceDirector.onCue} listeners.
1245
+ - `SequenceCue` (interface): interface SequenceCue<Payload = unknown> — One scheduled beat of a cutscene: a typed cue that fires when the playhead reaches `atMs`.
1246
+ - `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}.
1247
+ - `SequenceDirectorOptions` (interface): interface SequenceDirectorOptions<Payload = unknown> — Options for {@link createSequenceDirector}.
1248
+ - `SequenceSnapshot` (interface): interface SequenceSnapshot — Serializable snapshot — enough to resume a cutscene exactly where a save left it.
1249
+ - `SequenceState` (interface): interface SequenceState — A read-only view of the director's playback state, returned by {@link SequenceDirector.state}.
1250
+ - `createSequenceDirector` (function): function createSequenceDirector<Payload = unknown>(options: SequenceDirectorOptions<Payload>): SequenceDirector<Payload> — A serializable cutscene / sequence director: an ordered timeline of typed cues (`{ atMs, kind, payload }`) advanced by one injected clock, firing each cue once and in order as its time passes — even across a large seek — with play/pause/ seek/skip/stop controls. The director only *schedules and emits* cues; it never interprets what a `kind` means, so the same primitive drives camera moves, dialogue lines, fades, or any game event. `snapshot`/`restore` round-trip the playhead and which cues have fired. Deterministic (no wall clock beyond the injected `now`) and allocation-free on the tick path.
1251
+
1154
1252
  ## @jgengine/core/scene/spatial
1155
1253
 
1156
1254
  - `Aim` (type): type Aim = | { origin: EntityPosition; direction: EntityPosition } | { yaw: number; pitch: number; spread?: number } — ⚠ undocumented
@@ -1263,6 +1361,15 @@
1263
1361
 
1264
1362
  - `GameTime` (interface): interface GameTime — ⚠ undocumented
1265
1363
 
1364
+ ## @jgengine/core/time/dayNightCycle
1365
+
1366
+ - `DayNightCycle` (interface): interface DayNightCycle — A running, observable, serializable day-night cycle. A presenter renders `sample()`.
1367
+ - `DayNightCycleOptions` (interface): interface DayNightCycleOptions — Options for {@link createDayNightCycle}.
1368
+ - `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.
1369
+ - `DayNightSample` (interface): interface DayNightSample — The interpolated day-night look at a moment: day fraction, active phase, and blended colors.
1370
+ - `DayNightSnapshot` (interface): interface DayNightSnapshot — Serializable day-night position — accumulated clock offset, pause state, and speed — for save/load.
1371
+ - `createDayNightCycle` (function): function createDayNightCycle(options: DayNightCycleOptions): DayNightCycle — Creates a turnkey day-night cycle: a serializable model that advances a normalized day fraction on an injected clock and blends per-keyframe phase labels and tint/light colors. Wire this one model, then drive an existing sky/daylight seam from `sample()` (or drop it straight into a `{ calendar(): { dayFraction } }` seam via `calendar()`) to get a moving day-night cycle with color grading — no hand-rolled clock or lerp. `phase` labels and colors are free-form; the model never interprets their meaning.
1372
+
1266
1373
  ## @jgengine/core/time/gameClock
1267
1374
 
1268
1375
  - `DEFAULT_TIME_SCALE` (const): const DEFAULT_TIME_SCALE: 24 — Simulation clock: real time scaled into game time, plus the derived game-day counter.
@@ -1308,6 +1415,58 @@
1308
1415
  - `createStateSchedule` (function): function createStateSchedule<T>(config: StateScheduleConfig<T>): StateSchedule<T> — ⚠ undocumented
1309
1416
  - `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.
1310
1417
 
1418
+ ## @jgengine/core/time/timerSet
1419
+
1420
+ - `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.
1421
+ - `TimerExpiryListener` (type): type TimerExpiryListener = (id: string) => void — Listener notified when a timer newly expires. Receives the timer id.
1422
+ - `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}).
1423
+ - `TimerSet` (interface): interface TimerSet — A named set of countdown / countup timers on an injected clock. Start, pause, resume, stop, reset, and read timers by free-string id; observe structural changes with {@link TimerSet.subscribe} and expiry edges with {@link TimerSet.poll} / {@link TimerSet.onExpire}.
1424
+ - `TimerSetOptions` (interface): interface TimerSetOptions — Options for {@link createTimerSet}.
1425
+ - `TimerSetSnapshot` (interface): interface TimerSetSnapshot — Serializable state of a whole {@link TimerSet}.
1426
+ - `TimerSnapshot` (interface): interface TimerSnapshot — One timer's serializable state — elapsed resolved at snapshot time, ready to re-anchor on restore.
1427
+ - `TimerStartOptions` (interface): interface TimerStartOptions — Options for {@link TimerSet.start}.
1428
+ - `createTimerSet` (function): function createTimerSet(options: TimerSetOptions = {}): TimerSet — Create a serializable set of named countdown / countup timers on an injected clock — one primitive for round timers, respawn clocks, and ability cooldown/charge. Start/pause/resume/stop/reset timers by free-string id, read `{ remainingMs, elapsedMs, durationMs, progress01, running, expired }` for a mm:ss readout or a radial/bar fill, and `poll` for expiry edges. Ids and labels carry no genre meaning; `snapshot`/`restore` round-trip through a save.
1429
+
1430
+ ## @jgengine/core/vfx/cameraShake
1431
+
1432
+ - `CameraShakeConfig` (interface): interface CameraShakeConfig — Configuration for {@link createCameraShake}. Every field has a game-feel default.
1433
+ - `CameraShakeController` (interface): interface CameraShakeController — A live, dt-driven, trauma-based camera shake controller.
1434
+ - `CameraShakeOffset` (interface): interface CameraShakeOffset — A per-frame camera shake offset: three positional axes plus three rotational axes (radians).
1435
+ - `CameraShakeSnapshot` (interface): interface CameraShakeSnapshot — Serializable state for save/restore and deterministic replay.
1436
+ - `createCameraShake` (function): function createCameraShake(config: CameraShakeConfig = {}): CameraShakeController — A seeded, serializable, trauma-based camera shake / impulse controller. A game calls `add(amount, kind?)` on impacts (a hit, an explosion, a landing) to raise trauma in `[0, 1]`; `update(dt)` bleeds it off over time; and `offset()` returns a pooled `{ x, y, z, pitch, yaw, roll }` kick equal to `trauma^exponent` times per-axis maxima times deterministic seeded value-noise sampled along an internal time cursor. A shell consumer applies that offset to the active camera each frame so the view visibly shakes. Nothing here is genre-specific: `kind` is a free label the game styles, all amplitudes/decay are parameters, and `snapshot`/ `restore` round-trips the shake through a save. Deterministic from `seed`: the same seed and dt sequence reproduce the same offsets.
1437
+
1438
+ ## @jgengine/core/vfx/damageDirection
1439
+
1440
+ - `DamageDirectionOptions` (interface): interface DamageDirectionOptions — Options for {@link createDamageDirectionTracker}.
1441
+ - `DamageDirectionSnapshot` (interface): interface DamageDirectionSnapshot — Serializable state for save/restore — the clock reading plus every live indicator.
1442
+ - `DamageDirectionTracker` (interface): interface DamageDirectionTracker — A serializable, allocation-aware brain that tracks where recent damage came from. Each registered hit becomes a directional indicator that fades over a fixed duration on the injected clock; {@link DamageDirectionTracker.active} reports the live ones with their eased current strength.
1443
+ - `DamageIndicator` (interface): interface DamageIndicator — A live directional indicator with its eased, time-decayed strength, produced by {@link DamageDirectionTracker.active}. The `intensity` here is the *current* eased value (peak faded over the elapsed lifetime), ready to drive opacity/scale.
1444
+ - `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.
1445
+ - `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.
1446
+
1447
+ ## @jgengine/core/vfx/particles
1448
+
1449
+ - `Curve` (interface): interface Curve — A per-life start→end curve (linear interpolation from birth to death).
1450
+ - `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.
1451
+ - `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.
1452
+ - `ParticleSnapshot` (interface): interface ParticleSnapshot — Serializable simulation state for save/restore and deterministic replay.
1453
+ - `ParticleSystem` (interface): interface ParticleSystem — A live, dt-driven particle simulation.
1454
+ - `Range` (interface): interface Range — A `[min, max]` range a spawned particle draws uniformly from.
1455
+ - `Vec3` (type): type Vec3 = readonly [number, number, number] — A 3D vector `[x, y, z]`.
1456
+ - `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.
1457
+
1458
+ ## @jgengine/core/vfx/screenEffects
1459
+
1460
+ - `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.
1461
+ - `ScreenEffectEasing` (type): type ScreenEffectEasing = "linear" | "easeIn" | "easeOut" | "easeInOut" — How a transient effect's intensity curves from peak to zero over its life.
1462
+ - `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.
1463
+ - `ScreenEffectSpec` (interface): interface ScreenEffectSpec — One screen-feedback effect, fully data-first so a whole controller serializes. `kind` is a free label the game assigns and styles ("damage", "heal", "poison", "boost", …); the model never interprets it. Everything visible is a parameter: color, peak intensity, region shape, easing, and either a transient duration or a sustained (optionally oscillating) hold.
1464
+ - `ScreenEffectsController` (interface): interface ScreenEffectsController — A live, clock-driven screen-feedback controller.
1465
+ - `ScreenEffectsOptions` (interface): interface ScreenEffectsOptions — Options for {@link createScreenEffects}.
1466
+ - `ScreenEffectsSnapshot` (interface): interface ScreenEffectsSnapshot — Serializable state of every active effect, for save/restore and replay.
1467
+ - `StoredScreenEffect` (interface): interface StoredScreenEffect — A persisted effect record (all spec fields resolved plus its start time and id).
1468
+ - `createScreenEffects` (function): function createScreenEffects(options: ScreenEffectsOptions = {}): ScreenEffectsController — A serializable screen-feedback controller: a game triggers transient flashes and edge vignettes (a red damage hit, a green heal flash) or sustained, optionally oscillating tints (a low-health pulse), and reads back a composite of the effects to draw right now with their eased opacities. It is clock-driven — call `advance()` each frame against an injected `now` — and allocation-aware: the composite array and its entries are pooled and reused, so steady-state ticking never allocates. Nothing here is genre-specific: `kind` is a free label the game owns and styles, and vignette / flash / pulse are just parameterizations of the same data (region shape, decay easing, sustained oscillation). A shell overlay subscribes and renders; `snapshot`/`restore` round-trips through a save.
1469
+
1311
1470
  ## @jgengine/core/visibility/assetStreaming
1312
1471
 
1313
1472
  - `AssetLoadResult` (interface): interface AssetLoadResult — ⚠ undocumented
@@ -1401,6 +1560,7 @@
1401
1560
 
1402
1561
  ## @jgengine/core/world
1403
1562
 
1563
+ - `ANNOTATION_FEED_ACTION` (const): const ANNOTATION_FEED_ACTION: "map.annotation" — Feed action shared drawings ride by default (pair with the party feed, like pings).
1404
1564
  - `Aabb` (interface): interface Aabb — ⚠ undocumented
1405
1565
  - `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.
1406
1566
  - `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.
@@ -1413,6 +1573,11 @@
1413
1573
  - `AircraftOptions` (interface): interface AircraftOptions — Spawn state and injectable world-field samplers for an aircraft instance.
1414
1574
  - `AircraftStep` (interface): interface AircraftStep — Pose and aerodynamic telemetry returned after one flight tick.
1415
1575
  - `AircraftTuning` (interface): interface AircraftTuning — Data-first physical tuning shared by all aircraft instances of one catalog type.
1576
+ - `AnnotationBroadcast` (type): type AnnotationBroadcast = | { op: "stroke"; from: string; id: string; points: readonly WorldXZ[]; tone?: MapLayerTone; width?: number } | { op: "shape"; from: string; id: string; shape: MapZoneShape; tone?: MapLayerTone; label?: string } | { op: "note"; from: string; id: string; position: WorldXZ; … — A serializable map-annotation edit broadcast to other players.
1577
+ - `AnnotationFeedSink` (interface): interface AnnotationFeedSink — The feed sink shared annotations push to — an alias of the ping/feed `push` seam.
1578
+ - `AnnotationLayer` (interface): interface AnnotationLayer — Player-drawn map annotation layer — strokes, shapes, and notes over caller-owned map data.
1579
+ - `AnnotationLayerOptions` (interface): interface AnnotationLayerOptions — Options for {@link createAnnotationLayer}.
1580
+ - `AnnotationSnapshot` (interface): interface AnnotationSnapshot — Whole serializable state of an annotation layer — drop into a save blob.
1416
1581
  - `AreaDistribution` (type): type AreaDistribution = "uniform" | "edge" — Fill policy for a rect/box: `"uniform"` = even coverage; `"edge"` = biased to a boundary band.
1417
1582
  - `AreaEffectEvent` (interface): interface AreaEffectEvent<P> — One membership edge emitted by `step`, `removeSource`, or `clear`.
1418
1583
  - `AreaEffectField` (interface): interface AreaEffectField<P> — Runtime handle tracking continuous area membership across ticks.
@@ -1438,6 +1603,7 @@
1438
1603
  - `AvoidanceAgent` (interface): interface AvoidanceAgent — A circular agent that avoidance may push on the XZ plane.
1439
1604
  - `BallisticSweep` (type): type BallisticSweep = ( origin: readonly [number, number, number], velocity: readonly [number, number, number], gravity: number, maxTime: number, ) => BallisticSweepHit | null — ⚠ undocumented
1440
1605
  - `BallisticSweepHit` (interface): interface BallisticSweepHit — ⚠ undocumented
1606
+ - `BandTrimOptions` (interface): interface BandTrimOptions extends JunctionGeometryOptions — Options for {@link trimBandAtJunctions} — junction geometry tunables plus a band-specific clearance.
1441
1607
  - `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}.
1442
1608
  - `BehaviorDescriptor` (type): type BehaviorDescriptor = | WanderBehavior | PatrolBehavior | PromptableBehavior | PlayerBehavior — ⚠ undocumented
1443
1609
  - `BehaviorInspection` (interface): interface BehaviorInspection — Inspection readout for editor/debug tooling, from {@link BehaviorControl.inspect}/{@link BehaviorControl.list}.
@@ -1457,12 +1623,19 @@
1457
1623
  - `BuildingStyle` (type): type BuildingStyle = | "generic" | "capital" | "village" | "desert" | "industrial" | "coastal" | "neon" | "ruin" | "frontier" | "aerial" — ⚠ undocumented
1458
1624
  - `CITY_BUILDING_BUDGET` (const): const CITY_BUILDING_BUDGET: 2600 — Max buildings a single `city` district generates — the block/parcel pipeline's bounded lot cap.
1459
1625
  - `CITY_DEFAULTS` (const): const CITY_DEFAULTS: CityRules — City defaults: a zoned mixed metropolis — towers downtown, slabs mid-ring, houses at the edge.
1626
+ - `CITY_FILLER_CLASSES` (const): const CITY_FILLER_CLASSES: readonly CityFillerClass[] — All filler classes, for validation and interior-pass allow-lists.
1460
1627
  - `CITY_KIND` (const): const CITY_KIND: "city" — The editor volume kind marking a box as a procedural city district.
1628
+ - `CITY_LANDMARK_CLASSES` (const): const CITY_LANDMARK_CLASSES: readonly CityLandmarkClass[] — All landmark classes, for schema hints, validation, and default allow-lists.
1461
1629
  - `CITY_LOT_CLASSES` (const): const CITY_LOT_CLASSES: readonly CityLotClass[] — All classes, for schema hints and validation.
1630
+ - `CITY_PLOT_TIERS` (const): const CITY_PLOT_TIERS: readonly CityPlotTier[] — All plot tiers, for schema hints and validation.
1462
1631
  - `CITY_SCHEMA` (const): const CITY_SCHEMA: ParamSchema — The city parameter schema — drives the inspector sliders and `meta` parse via the studio seam.
1463
1632
  - `CITY_TREE_SPECIES` (const): const CITY_TREE_SPECIES: readonly CityTreeSpecies[] — All species, for schema hints and validation.
1464
1633
  - `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.
1465
1634
  - `CITY_ZONE_SCHEMA` (const): const CITY_ZONE_SCHEMA: ParamSchema — Zone-override schema for `cityzone` volumes: pin a band and optionally a bespoke class mix.
1635
+ - `CameraShakeConfig` (interface): interface CameraShakeConfig — Configuration for {@link createCameraShake}. Every field has a game-feel default.
1636
+ - `CameraShakeController` (interface): interface CameraShakeController — A live, dt-driven, trauma-based camera shake controller.
1637
+ - `CameraShakeOffset` (interface): interface CameraShakeOffset — A per-frame camera shake offset: three positional axes plus three rotational axes (radians).
1638
+ - `CameraShakeSnapshot` (interface): interface CameraShakeSnapshot — Serializable state for save/restore and deterministic replay.
1466
1639
  - `CameraView` (type): type CameraView = PerspectiveView | OrthographicView — ⚠ undocumented
1467
1640
  - `CameraVisibilityContext` (interface): interface CameraVisibilityContext — A camera's contribution to visibility. The VisibilitySystem unions results across every active context: an object stays renderable/loaded if *any* relevant camera needs it. A camera can opt out of driving asset streaming (e.g. a minimap that only needs positions, not loaded meshes) via `influencesStreaming: false`.
1468
1641
  - `Cardinal` (type): type Cardinal = "N" | "NE" | "E" | "SE" | "S" | "SW" | "W" | "NW" — ⚠ undocumented
@@ -1472,9 +1645,15 @@
1472
1645
  - `CityBlock` (interface): interface CityBlock — One closed city block: a face of the road graph, inset to curb and land boundaries.
1473
1646
  - `CityBlockKind` (type): type CityBlockKind = "buildable" | "park" | "plaza" | "field" | "buffer" — How a block (a face of the road graph) is used.
1474
1647
  - `CityBridge` (interface): interface CityBridge — One bridge deck spanning water: bank-to-bank polyline plus the silhouette style.
1648
+ - `CityContentOptions` (interface): interface CityContentOptions extends CityContentOverrides — Full options for {@link resolveCityLotContent}: the city geometry frame plus content overrides.
1649
+ - `CityContentOverrides` (interface): interface CityContentOverrides — Tunable overrides for {@link resolveCityLotContent} (seed/halfExtents/laneFrontage are supplied).
1475
1650
  - `CityDriveway` (interface): interface CityDriveway — One driveway ribbon from a street to a lot.
1651
+ - `CityFillerClass` (type): type CityFillerClass = "garage" | "depot" — Filler classes used ONLY by the block-interior fill pass (`resolveCityLotContent` at a high `blockFill`). They are deliberately kept OUT of {@link CITY_LOT_CLASSES} so a zone mix can never weight them onto street frontage — they exist to pack the backs of Manhattan-style blocks with parking structures and warehouses/depots, mixed in with ordinary zone classes.
1652
+ - `CityGeneratorOptions` (interface): interface CityGeneratorOptions — Options for {@link generateCity}: a seed, street-dial overrides, and plot pass-through options.
1476
1653
  - `CityHedge` (interface): interface CityHedge — One hedge run: a thin box strip (estate perimeter).
1477
1654
  - `CityIntersection` (interface): interface CityIntersection — One crossing of two through streets: patch center/radius plus crosswalk arm directions.
1655
+ - `CityLandmarkClass` (type): type CityLandmarkClass = "hall" | "arena" | "market" | "campus" — A block-scale landmark class. Unlike {@link CityLotClass} these are never weighted into a zone mix — the landmark pass in `resolveCityLotContent` picks clusters of adjacent lots and stamps one of these over them. Each expresses with the same four piece shapes (box/gable/cylinder/dome) at a much larger footprint (~40–90 m).
1656
+ - `CityLevelClassBias` (type): type CityLevelClassBias = Record<StreetLevel, Partial<Record<CityLotClass, number>>> — Per-street-level class weight multipliers applied to the band mix before the class pick, so towers and slabs bias toward wide boulevard/avenue frontage while houses bias toward lanes and quiet streets. A missing class ⇒ multiplier 1. Pure data modulating the weighted mixes.
1478
1657
  - `CityLight` (interface): interface CityLight — One street light: curb position plus the yaw its arm faces (over the road).
1479
1658
  - `CityLot` (interface): interface CityLot — One building lot: footprint, zone band, class, seeded floors, massing pieces, street anchor.
1480
1659
  - `CityLotClass` (type): type CityLotClass = | "tower" | "slab" | "shop" | "rowhouse" | "house" | "mansion" | "farmhouse" | "barn" | "silo" — A building class a zone mix can weight — drives lot size, floors, setback, and massing.
@@ -1485,12 +1664,18 @@
1485
1664
  - `CityParking` (interface): interface CityParking — One parking pad behind a commercial lot.
1486
1665
  - `CityPieceRole` (type): type CityPieceRole = "wall" | "roof" | "trim" | "accent" — Palette role a piece colors from (wall/roof/trim/accent map onto the district's style palette).
1487
1666
  - `CityPieceShape` (type): type CityPieceShape = "box" | "gable" | "cylinder" | "dome" — Primitive shapes massing pieces instance — the renderer keeps one InstancedMesh per shape.
1667
+ - `CityPlot` (interface): interface CityPlot — One polygonal plot cut from a block's street frontage. Every plot fronts a street.
1668
+ - `CityPlotFrontage` (interface): interface CityPlotFrontage — The street frontage a plot faces: which street, and the frontage chord along it.
1669
+ - `CityPlotOptions` (interface): interface CityPlotOptions — Options for {@link deriveCityPlots}.
1670
+ - `CityPlotResult` (interface): interface CityPlotResult — Output of {@link deriveCityPlots}: the plots plus whole-block park polygons.
1671
+ - `CityPlotTier` (type): type CityPlotTier = "small" | "medium" | "large" | "grand" — Size tier a plot was cut at. `grand` is the block-scale tier that used to be a landmark pass.
1488
1672
  - `CityResolveContext` (interface): interface CityResolveContext extends SceneKindResolveContext — Extended resolve context: sibling `cityzone` volumes that override the band/mix locally.
1489
1673
  - `CityRules` (interface): interface CityRules — Fully-defaulted city params parsed from a volume's `meta`.
1490
1674
  - `CityStreet` (interface): interface CityStreet — One synthesized street: a world-space XZ polyline with width, hierarchy level, and surface.
1491
1675
  - `CityTree` (interface): interface CityTree — One placed tree: world XZ, species, and seeded scale/color jitter.
1492
1676
  - `CityTreeSpecies` (type): type CityTreeSpecies = "broadleaf" | "conifer" | "palm" | "cypress" — Tree species a district's tree mix can weight — the renderer keeps one canopy mesh per species.
1493
1677
  - `CityZoneBand` (type): type CityZoneBand = "core" | "mid" | "edge" — Zone band a lot falls in: dense core, middle ring, or the district edge.
1678
+ - `CityZoneMixes` (interface): interface CityZoneMixes — Weighted building-class mix per zone band; the radial profile decides which band a lot falls in.
1494
1679
  - `CityZoneProfile` (type): type CityZoneProfile = "core-out" | "inverted" | "uniform" — How the radial zone metric maps to bands.
1495
1680
  - `ClockSnapshot` (interface): interface ClockSnapshot — ⚠ undocumented
1496
1681
  - `CollapseEvent` (interface): interface CollapseEvent — ⚠ undocumented
@@ -1505,15 +1690,32 @@
1505
1690
  - `ControlGroupInput` (interface): interface ControlGroupInput — A decoded control-group key press plus the memory needed to detect a double-tap.
1506
1691
  - `ControlGroupIntent` (type): type ControlGroupIntent = | { kind: "bind"; key: string } /** Digit: recall the set saved under `key` into the active selection. */ | { kind: "recall"; key: string } /** Second digit tap within the double-tap window: recall and focus the camera on `key`. */ | { kind: "focus"; key: string } — Optional RTS binding composition over the genre-agnostic selection-bookmark store (`@jgengine/core/scene/selectionBookmarks`). It maps the classic control- group idiom — Ctrl+digit binds, digit recalls, a second digit tap within a window focuses — onto opaque bookmark keys, without pulling input mapping into the store. Games that want a different scheme (named bookmarks, gamepad, touch) skip this and call the store directly.
1507
1692
  - `ControlGroupOptions` (interface): interface ControlGroupOptions — Tuning for the control-group idiom: the double-tap focus window and the bookmark-key namespace.
1693
+ - `CueListener` (type): type CueListener<Payload = unknown> = (emitted: EmittedCue<Payload>) => void — A cue listener, called once per cue as it fires. Returns nothing.
1694
+ - `Curve` (interface): interface Curve — A per-life start→end curve (linear interpolation from birth to death).
1695
+ - `DEFAULT_BLOCK_FILL` (const): const DEFAULT_BLOCK_FILL: 0.45 — Default `blockFill`: gently gapped frontage — plots with breathing room, parks reserved.
1696
+ - `DEFAULT_CITY_LEVEL_BIAS` (const): const DEFAULT_CITY_LEVEL_BIAS: CityLevelClassBias — Default street-level bias — boulevards favor big massing, lanes favor small/rural massing.
1697
+ - `DEFAULT_CITY_ZONE_MIXES` (const): const DEFAULT_CITY_ZONE_MIXES: CityZoneMixes — Default zoned-metropolis mixes: towers/slabs downtown, slabs+rowhouses mid, houses at the edge.
1508
1698
  - `DEFAULT_FORWARD` (const): const DEFAULT_FORWARD: readonly [number, number, number] — The forward-axis convention: a generator or scene kind declares which way its "front" faces (a bookcase's open/book face, a building's entrance) once, as data, instead of leaving every placement to hand-tuned `rotationY` trial-and-error. `StudioStage`'s `faceCamera` (`@jgengine/shell/scene/ StudioStage`) reads the declared axis to auto-orient a product shot; a placement tool can read the same field to face a freshly dropped asset toward the camera/path by default. `DEFAULT_FORWARD` (+Z) is what a generator/scene-kind gets when it omits `forward` — build your front toward it.
1509
1699
  - `DEFAULT_GRIP_CURVE` (const): const DEFAULT_GRIP_CURVE: GripCurve — ⚠ undocumented
1700
+ - `DEFAULT_LANDMARK_SHARE` (const): const DEFAULT_LANDMARK_SHARE: 0.04 — Default grand-plot share dial — a handful of block-scale parcels per default city.
1510
1701
  - `DEFAULT_MARKER_KINDS` (const): const DEFAULT_MARKER_KINDS: Record<string, MarkerKindStyle> — ⚠ undocumented
1511
1702
  - `DEFAULT_MINIMAP_PALETTE` (const): const DEFAULT_MINIMAP_PALETTE: MinimapBakePalette — The built-in height→color ramp and water color a bake uses when no palette override is given.
1512
1703
  - `DEFAULT_REPUTATION_TIERS` (const): const DEFAULT_REPUTATION_TIERS: readonly ReputationTier[] — ⚠ undocumented
1704
+ - `DamageDirectionOptions` (interface): interface DamageDirectionOptions — Options for {@link createDamageDirectionTracker}.
1705
+ - `DamageDirectionSnapshot` (interface): interface DamageDirectionSnapshot — Serializable state for save/restore — the clock reading plus every live indicator.
1706
+ - `DamageDirectionTracker` (interface): interface DamageDirectionTracker — A serializable, allocation-aware brain that tracks where recent damage came from. Each registered hit becomes a directional indicator that fades over a fixed duration on the injected clock; {@link DamageDirectionTracker.active} reports the live ones with their eased current strength.
1707
+ - `DamageIndicator` (interface): interface DamageIndicator — A live directional indicator with its eased, time-decayed strength, produced by {@link DamageDirectionTracker.active}. The `intensity` here is the *current* eased value (peak faded over the elapsed lifetime), ready to drive opacity/scale.
1708
+ - `DayNightCycle` (interface): interface DayNightCycle — A running, observable, serializable day-night cycle. A presenter renders `sample()`.
1709
+ - `DayNightCycleOptions` (interface): interface DayNightCycleOptions — Options for {@link createDayNightCycle}.
1710
+ - `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.
1711
+ - `DayNightSample` (interface): interface DayNightSample — The interpolated day-night look at a moment: day fraction, active phase, and blended colors.
1712
+ - `DayNightSnapshot` (interface): interface DayNightSnapshot — Serializable day-night position — accumulated clock offset, pause state, and speed — for save/load.
1513
1713
  - `DrapeOptions` (interface): interface DrapeOptions — Shaping for surface draping: subdivision spacing and a lift to keep the line off the ground.
1514
1714
  - `EditableTerrain` (interface): interface EditableTerrain extends TerrainField — ⚠ undocumented
1515
1715
  - `ElevationReadout` (interface): interface ElevationReadout — Measurable elevation readout at a single world point — the cursor/hover feedback value.
1516
1716
  - `ElevationSummary` (interface): interface ElevationSummary — Aggregate elevation statistics over a region — the selection min/max/mean and legend range.
1717
+ - `EmittedCue` (interface): interface EmittedCue<Payload = unknown> — A cue plus the resolved firing context passed to {@link SequenceDirector.onCue} listeners.
1718
+ - `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.
1517
1719
  - `EmptyOrderPayload` (type): type EmptyOrderPayload = Record<string, never> — Payload for stop/hold orders — no data; the verb is the intent.
1518
1720
  - `EnclosedFootprint` (interface): interface EnclosedFootprint — ⚠ undocumented
1519
1721
  - `EngagementKindConfig` (interface): interface EngagementKindConfig extends OrderKindConfig — Move + engagement config carrying the default radii the payload may override.
@@ -1524,6 +1726,9 @@
1524
1726
  - `EnvironmentWorldFeature` (interface): interface EnvironmentWorldFeature — ⚠ undocumented
1525
1727
  - `FactionDef` (interface): interface FactionDef — ⚠ undocumented
1526
1728
  - `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.
1729
+ - `FastTravelNetwork` (interface): interface FastTravelNetwork<TMeta = unknown> — A network of fast-travel points with per-player discovery + distance queries.
1730
+ - `FastTravelOptions` (interface): interface FastTravelOptions<TMeta = unknown> — Options for {@link createFastTravelNetwork}.
1731
+ - `FastTravelSnapshot` (interface): interface FastTravelSnapshot — Serializable discovery state.
1527
1732
  - `FireGrid` (interface): interface FireGrid — ⚠ undocumented
1528
1733
  - `FlatGround` (interface): interface FlatGround — A 3D walkable plane/slab. `Infinity` axes are unbounded; no separate "infinite" mode exists.
1529
1734
  - `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.
@@ -1543,7 +1748,9 @@
1543
1748
  - `FrustumSensor` (interface): interface FrustumSensor — ⚠ undocumented
1544
1749
  - `FrustumTarget` (interface): interface FrustumTarget — ⚠ undocumented
1545
1750
  - `GRASS_SCHEMA` (const): const GRASS_SCHEMA: ParamSchema — The grass parameter schema — drives the inspector and `meta` parse via the studio seam.
1751
+ - `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.
1546
1752
  - `GeneratedAsset` (interface): interface GeneratedAsset — A resolved generator asset: its parts plus the overall local-space bounds (min/max corners).
1753
+ - `GeneratedCity` (interface): interface GeneratedCity — A generated city: streets, plots (with rect building lots as a compat view), and park blocks.
1547
1754
  - `GeneratedPart` (interface): interface GeneratedPart — One generated primitive part — a box/panel placed in the asset's local space.
1548
1755
  - `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.
1549
1756
  - `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.
@@ -1563,6 +1770,7 @@
1563
1770
  - `HeatState` (interface): interface HeatState — Serializable heat-system state — round-trips through `createHeatState`/`advanceHeat` each tick.
1564
1771
  - `HeightSampler` (type): type HeightSampler = (x: number, z: number) => number — A height sampler over the ground: world elevation at any `x`/`z`.
1565
1772
  - `HiddenStateSource` (interface): interface HiddenStateSource — ⚠ undocumented
1773
+ - `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.
1566
1774
  - `InterestCensus` (interface): interface InterestCensus — Aggregate counts of active vs dormant gates — the metric the issue asks a scheduler to expose.
1567
1775
  - `InterestCensusAccumulator` (interface): interface InterestCensusAccumulator — A running census accumulator; call `record` inside the caller's existing tick loop (no extra pass).
1568
1776
  - `InterestGateInput` (interface): interface InterestGateInput — Per-tick input the caller supplies to a gate.
@@ -1571,9 +1779,12 @@
1571
1779
  - `InterestSchedulerConfig` (interface): interface InterestSchedulerConfig — Static configuration shared by every gate of one behavior class.
1572
1780
  - `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.
1573
1781
  - `InterestTier` (interface): interface InterestTier — A distance-keyed cadence tier: nearer agents tick faster, farther-but-awake agents tick slower.
1782
+ - `IntersectionStreet` (interface): interface IntersectionStreet — One street to trim + mesh through {@link buildTrimmedIntersections}.
1574
1783
  - `Job` (interface): interface Job — ⚠ undocumented
1575
1784
  - `JobDef` (interface): interface JobDef — ⚠ undocumented
1576
1785
  - `JobReport` (interface): interface JobReport — ⚠ undocumented
1786
+ - `JunctionApproach` (interface): interface JunctionApproach — One approach feeding {@link buildJunctionSurface}: the exact draped corner vertices a ribbon ends at.
1787
+ - `JunctionGeometryOptions` (interface): interface JunctionGeometryOptions — Tunables shared by {@link trimPathAtJunctions}, {@link buildJunctionSurface}, and {@link buildTrimmedIntersections}.
1577
1788
  - `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.
1578
1789
  - `KinematicDynamicsTuning` (interface): interface KinematicDynamicsTuning — Aerodynamic and electronic-assist settings layered over tire grip.
1579
1790
  - `KinematicPowertrainTuning` (interface): interface KinematicPowertrainTuning — Data-first gearbox and torque-curve tuning for a kinematic ground vehicle.
@@ -1581,6 +1792,7 @@
1581
1792
  - `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.
1582
1793
  - `KinematicVehicleStep` (interface): interface KinematicVehicleStep — ⚠ undocumented
1583
1794
  - `KinematicVehicleTuning` (interface): interface KinematicVehicleTuning — ⚠ undocumented
1795
+ - `LANDMARK_HARD_CAP` (const): const LANDMARK_HARD_CAP: 12 — Hard cap on grand plots emitted regardless of dial/city size.
1584
1796
  - `LOCK_ACTIONS` (const): const LOCK_ACTIONS: readonly LockAction[] — The five pick actions, in display order (shallow → deep).
1585
1797
  - `LineFormationOptions` (interface): interface LineFormationOptions — Options for {@link lineFormation}.
1586
1798
  - `LocalAvoidanceOptions` (interface): interface LocalAvoidanceOptions — Tuning for {@link resolveLocalAvoidance}.
@@ -1593,7 +1805,10 @@
1593
1805
  - `MagnitudeOf` (type): type MagnitudeOf<P> = (membership: AreaMembership<P>) => number — Read a comparable magnitude from a membership (e.g. buff strength, damage per tick).
1594
1806
  - `MapCellStates` (interface): interface MapCellStates — ⚠ undocumented
1595
1807
  - `MapMarker` (interface): interface MapMarker<TMeta = unknown> extends MarkerView<TMeta> — A marker owned by {@link MarkerSet}, including its lifecycle and query fields.
1808
+ - `MapNote` (interface): interface MapNote — A text note pinned at a world point.
1596
1809
  - `MapRoute` (interface): interface MapRoute — ⚠ undocumented
1810
+ - `MapShapeAnnotation` (interface): interface MapShapeAnnotation — A drawn area annotation (circle/rect/polygon), reusing the map-zone shape vocabulary.
1811
+ - `MapStroke` (interface): interface MapStroke — A freehand drawn line on the map — a world-XZ polyline.
1597
1812
  - `MapZone` (interface): interface MapZone — ⚠ undocumented
1598
1813
  - `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.
1599
1814
  - `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.
@@ -1601,6 +1816,7 @@
1601
1816
  - `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.
1602
1817
  - `MarkerSourceOptions` (interface): interface MarkerSourceOptions<TEntity, TMarker extends MarkerView = MarkerView> — Configuration for projecting a caller-owned collection into display-only markers.
1603
1818
  - `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}.
1819
+ - `MassingFootprint` (interface): interface MassingFootprint — Axis-aligned massing extents (lot-local): full width along x and depth along z.
1604
1820
  - `MinimapBake` (interface): interface MinimapBake — A baked minimap image: RGBA pixels plus the world bounds they span.
1605
1821
  - `MinimapBakeBounds` (interface): interface MinimapBakeBounds — Deterministic minimap terrain bake (#1036): rasterize an authored world's terrain (plus optional biome zones and water) into a top-down RGBA image and a matching world-bounds rectangle, then encode it as a PNG data URI. The editor runs this as a bake action and stores the result on the scene document; runtime feeds it straight into the existing `Minimap` / `WorldMap` `background` + `mapBounds` props — no new runtime render path, and the same authored world always bakes the same image (safe for verify/CI). Pure: no canvas, no DOM, `core` still imports nothing external.
1606
1822
  - `MinimapBakeOptions` (interface): interface MinimapBakeOptions — Options for {@link bakeMinimapImage}.
@@ -1654,6 +1870,9 @@
1654
1870
  - `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.
1655
1871
  - `ParamSchema` (interface): interface ParamSchema — A kind's full parameter surface: an ordered list of fields the inspector renders top-to-bottom.
1656
1872
  - `ParsedParams` (type): type ParsedParams = Record<string, number | boolean | string | WeightedParamEntry[]> — Parsed params after `parseParams`: every schema field present with a validated, defaulted value.
1873
+ - `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.
1874
+ - `ParticleSnapshot` (interface): interface ParticleSnapshot — Serializable simulation state for save/restore and deterministic replay.
1875
+ - `ParticleSystem` (interface): interface ParticleSystem — A live, dt-driven particle simulation.
1657
1876
  - `PathFollowConfig` (interface): interface PathFollowConfig — ⚠ undocumented
1658
1877
  - `PathFollowProgress` (interface): interface PathFollowProgress — Read-only progress readout for inspection/debug tooling, produced by {@link pathFollowProgress}.
1659
1878
  - `PathFollowState` (interface): interface PathFollowState — ⚠ undocumented
@@ -1677,16 +1896,21 @@
1677
1896
  - `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.
1678
1897
  - `PointGravityOptions` (interface): interface PointGravityOptions — Center, strength, and falloff for radial gravity.
1679
1898
  - `PositionedPrompt` (interface): interface PositionedPrompt — ⚠ undocumented
1899
+ - `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.
1900
+ - `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.
1901
+ - `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.
1680
1902
  - `ProximityPrompt` (interface): interface ProximityPrompt — ⚠ undocumented
1681
1903
  - `QteStep` (interface): interface QteStep — ⚠ undocumented
1682
1904
  - `RadialDistribution` (type): type RadialDistribution = "area" | "radial" — Fill policy for a circle/ring: `"area"` = area-uniform (even density); `"radial"` = radius-uniform (clumps toward center).
1683
1905
  - `RainEnvironmentDescriptor` (type): type RainEnvironmentDescriptor = { kind: "rain" } & Required< Pick<RainEnvironmentConfig, "area" | "density" | "speed" | "dropLength" | "wind" | "color" | "width" | "opacity"> > — ⚠ undocumented
1906
+ - `Range` (interface): interface Range — A `[min, max]` range a spawned particle draws uniformly from.
1684
1907
  - `RecallBookmarkOptions` (interface): interface RecallBookmarkOptions — Caller hooks for {@link recallSelectionBookmark} — kept out of the store so focus and validity stay genre-owned.
1685
1908
  - `RecordingBuffer` (interface): interface RecordingBuffer<T> — ⚠ undocumented
1686
1909
  - `RecordingBufferOptions` (interface): interface RecordingBufferOptions — ⚠ undocumented
1687
1910
  - `RegionField` (interface): interface RegionField<T = unknown> extends TerrainField — ⚠ undocumented
1688
1911
  - `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.
1689
1912
  - `ResolvedCity` (interface): interface ResolvedCity — A resolved city district: world-space network, zoned lots, parks, and furniture.
1913
+ - `ResolvedCityLot` (interface): interface ResolvedCityLot — One plot enriched with its zone/class/floors/massing — the renderer instances `pieces` at `center`.
1690
1914
  - `ResolvedCollider` (interface): interface ResolvedCollider — ⚠ undocumented
1691
1915
  - `ResolvedGround` (type): type ResolvedGround = FlatGround | RoundGround | VoxelGround | ResolvedBoardGround — A place's ground after `world()` normalization.
1692
1916
  - `ResolvedPoleLine` (interface): interface ResolvedPoleLine — The renderable payload the resolver returns and the shell renderer consumes.
@@ -1694,7 +1918,9 @@
1694
1918
  - `ResolvedWeather` (interface): interface ResolvedWeather — ⚠ undocumented
1695
1919
  - `RevealHit` (interface): interface RevealHit — ⚠ undocumented
1696
1920
  - `RevealQuery` (interface): interface RevealQuery — ⚠ undocumented
1921
+ - `RoadCut` (interface): interface RoadCut — One trim of a ribbon end back to a junction boundary — the seam the welded surface attaches to.
1697
1922
  - `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.
1923
+ - `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)]`.
1698
1924
  - `RoadSurfaceOptions` (interface): interface RoadSurfaceOptions — Grip levels and blend width for {@link roadSurfaceSampler}; each field is optional and defaulted.
1699
1925
  - `RoofPlan` (interface): interface RoofPlan — ⚠ undocumented
1700
1926
  - `RosterEntry` (interface): interface RosterEntry — ⚠ undocumented
@@ -1727,6 +1953,13 @@
1727
1953
  - `SceneObject` (interface): interface SceneObject — ⚠ undocumented
1728
1954
  - `SceneRaycastApi` (interface): interface SceneRaycastApi — ⚠ undocumented
1729
1955
  - `SceneRaycastHit` (interface): interface SceneRaycastHit — ⚠ undocumented
1956
+ - `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.
1957
+ - `ScreenEffectEasing` (type): type ScreenEffectEasing = "linear" | "easeIn" | "easeOut" | "easeInOut" — How a transient effect's intensity curves from peak to zero over its life.
1958
+ - `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.
1959
+ - `ScreenEffectSpec` (interface): interface ScreenEffectSpec — One screen-feedback effect, fully data-first so a whole controller serializes. `kind` is a free label the game assigns and styles ("damage", "heal", "poison", "boost", …); the model never interprets it. Everything visible is a parameter: color, peak intensity, region shape, easing, and either a transient duration or a sustained (optionally oscillating) hold.
1960
+ - `ScreenEffectsController` (interface): interface ScreenEffectsController — A live, clock-driven screen-feedback controller.
1961
+ - `ScreenEffectsOptions` (interface): interface ScreenEffectsOptions — Options for {@link createScreenEffects}.
1962
+ - `ScreenEffectsSnapshot` (interface): interface ScreenEffectsSnapshot — Serializable state of every active effect, for save/restore and replay.
1730
1963
  - `ScreenRect` (interface): interface ScreenRect — ⚠ undocumented
1731
1964
  - `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.
1732
1965
  - `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.
@@ -1734,6 +1967,13 @@
1734
1967
  - `SelectionSet` (interface): interface SelectionSet — ⚠ undocumented
1735
1968
  - `SensorProbeOptions` (interface): interface SensorProbeOptions — ⚠ undocumented
1736
1969
  - `SensorReading` (interface): interface SensorReading — ⚠ undocumented
1970
+ - `SequenceCue` (interface): interface SequenceCue<Payload = unknown> — One scheduled beat of a cutscene: a typed cue that fires when the playhead reaches `atMs`.
1971
+ - `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}.
1972
+ - `SequenceDirectorOptions` (interface): interface SequenceDirectorOptions<Payload = unknown> — Options for {@link createSequenceDirector}.
1973
+ - `SequenceSnapshot` (interface): interface SequenceSnapshot — Serializable snapshot — enough to resume a cutscene exactly where a save left it.
1974
+ - `SequenceState` (interface): interface SequenceState — A read-only view of the director's playback state, returned by {@link SequenceDirector.state}.
1975
+ - `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.
1976
+ - `SharedAnnotationsDeps` (interface): interface SharedAnnotationsDeps — Construction options for {@link createSharedAnnotations}.
1737
1977
  - `SimClock` (interface): interface SimClock — ⚠ undocumented
1738
1978
  - `SkillCheckConfig` (interface): interface SkillCheckConfig — ⚠ undocumented
1739
1979
  - `SkillCheckResult` (interface): interface SkillCheckResult — ⚠ undocumented
@@ -1751,6 +1991,7 @@
1751
1991
  - `StatCatalog` (type): type StatCatalog = Record<string, { max: number; min?: number; current?: number }> — ⚠ undocumented
1752
1992
  - `StatValue` (interface): interface StatValue extends StatPool — Native entity-stat name retained as a compatibility bridge to the portable pool model.
1753
1993
  - `Station` (interface): interface Station — ⚠ undocumented
1994
+ - `StoredScreenEffect` (interface): interface StoredScreenEffect — A persisted effect record (all spec fields resolved plus its start time and id).
1754
1995
  - `StratifiedOptions` (interface): interface StratifiedOptions — Inputs for {@link sampleStratified}: a grid over `area` with one jittered point per cell.
1755
1996
  - `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.
1756
1997
  - `StructureMaterial` (interface): interface StructureMaterial — ⚠ undocumented
@@ -1786,12 +2027,24 @@
1786
2027
  - `TerrainRegionStyle` (interface): interface TerrainRegionStyle — Palette and blend fields shared by every `TerrainMaterialRegion` shape.
1787
2028
  - `TerrainSurfaceRule` (interface): interface TerrainSurfaceRule — A height/slope predicate for auto-painting a surface layer (e.g. rock on steep slopes, snow up high).
1788
2029
  - `ThreatTable` (interface): interface ThreatTable — ⚠ undocumented
2030
+ - `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.
2031
+ - `TimerExpiryListener` (type): type TimerExpiryListener = (id: string) => void — Listener notified when a timer newly expires. Receives the timer id.
2032
+ - `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}).
2033
+ - `TimerSet` (interface): interface TimerSet — A named set of countdown / countup timers on an injected clock. Start, pause, resume, stop, reset, and read timers by free-string id; observe structural changes with {@link TimerSet.subscribe} and expiry edges with {@link TimerSet.poll} / {@link TimerSet.onExpire}.
2034
+ - `TimerSetOptions` (interface): interface TimerSetOptions — Options for {@link createTimerSet}.
2035
+ - `TimerSetSnapshot` (interface): interface TimerSetSnapshot — Serializable state of a whole {@link TimerSet}.
2036
+ - `TimerSnapshot` (interface): interface TimerSnapshot — One timer's serializable state — elapsed resolved at snapshot time, ready to re-anchor on restore.
2037
+ - `TimerStartOptions` (interface): interface TimerStartOptions — Options for {@link TimerSet.start}.
1789
2038
  - `ToneVoice` (interface): interface ToneVoice — A pitched oscillator voice: a 12ms linear attack to `gain`, then an exponential decay to silence across `duration`, with an optional exponential pitch slide from `freq` to `slideTo`.
2039
+ - `TravelPointDef` (interface): interface TravelPointDef<TMeta = unknown> — A fast-travel destination the game defines. Discovery is tracked separately.
2040
+ - `TravelPointView` (interface): interface TravelPointView<TMeta = unknown> extends TravelPointDef<TMeta> — A destination plus its discovery state (and distance from a query origin, when given).
1790
2041
  - `TriggerActionDefinition` (interface): interface TriggerActionDefinition — A game-declared action the editor can assign to a volume/marker trigger. Schema drives the inspector params; `targets`/`events` optionally narrow where it appears.
1791
2042
  - `TriggerDispatchEvent` (interface): interface TriggerDispatchEvent — Fired when a watched actor trips an authored trigger edge.
1792
2043
  - `TriggerEvent` (type): type TriggerEvent = "enter" | "exit" | "interact" — Event edge that can fire an authored trigger.
1793
2044
  - `TriggerHandlers` (type): type TriggerHandlers = Readonly<Record<string, (event: TriggerDispatchEvent) => void>> — Handler map keyed by action id — unknown actions are skipped unless `onDispatch` is set.
1794
2045
  - `TriggerSourceKind` (type): type TriggerSourceKind = "marker" | "volume" — Document collection a trigger source lives on.
2046
+ - `TrimmedIntersections` (interface): interface TrimmedIntersections — Renderer-ready output of {@link buildTrimmedIntersections}: trimmed ribbons + welded junction surfaces.
2047
+ - `TrimmedRoad` (interface): interface TrimmedRoad — A street sub-path after trimming, plus the cuts (0–2) that shortened it. Feed `path` to {@link buildRoadRibbon}.
1795
2048
  - `VEGETATION_VOLUME_KIND` (const): const VEGETATION_VOLUME_KIND: "vegetation" — The editor volume kind that marks an area as vegetation fill.
1796
2049
  - `VISIBILITY_HIDDEN` (const): const VISIBILITY_HIDDEN: 0 — Numeric code for a cell no group member has seen, or has fully forgotten.
1797
2050
  - `VISIBILITY_OBSERVED` (const): const VISIBILITY_OBSERVED: 2 — Numeric code for a cell a group currently observes.
@@ -1822,7 +2075,16 @@
1822
2075
  - `WaterRules` (interface): interface WaterRules — Fully-defaulted water surface params parsed from a volume's `meta`.
1823
2076
  - `WaterSurface` (interface): interface WaterSurface — ⚠ undocumented
1824
2077
  - `WaveManifest` (interface): interface WaveManifest — ⚠ undocumented
2078
+ - `WaveRunner` (interface): interface WaveRunner — A live, observable, serializable wave/spawn runner over a seeded spawn director.
2079
+ - `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.
2080
+ - `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.
2081
+ - `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.
1825
2082
  - `Waypoint` (type): type Waypoint = readonly [number, number, number] — ⚠ undocumented
2083
+ - `WaypointEntry` (interface): interface WaypointEntry — A single player-placed waypoint. World-XZ only — serializable and renderer-free.
2084
+ - `WaypointGuidance` (interface): interface WaypointGuidance — Direction/range to the tracked waypoint, for an on-screen guide arrow.
2085
+ - `WaypointSnapshot` (interface): interface WaypointSnapshot — Whole serializable state of a {@link WaypointStore} — drop into a save blob.
2086
+ - `WaypointStore` (interface): interface WaypointStore — Player-owned waypoint layer — place/track/clear pins, mirror to a `MarkerSet`, and read guide-arrow data.
2087
+ - `WaypointStoreDeps` (interface): interface WaypointStoreDeps — Construction options for {@link createWaypointStore}.
1826
2088
  - `WeatherEnvironmentDescriptor` (type): type WeatherEnvironmentDescriptor = RainEnvironmentDescriptor | SnowEnvironmentDescriptor — ⚠ undocumented
1827
2089
  - `WeatherModifierTable` (type): type WeatherModifierTable<K extends string = string> = Record<K, WeatherModifier> — ⚠ undocumented
1828
2090
  - `WeatherState` (interface): interface WeatherState — ⚠ undocumented
@@ -1858,7 +2120,9 @@
1858
2120
  - `boxRegion` (function): function boxRegion(min: Point3, max: Point3): SampleRegion<Point3> — An axis-aligned box `[min..max]` in 3D. Uniform density; draws x, y, z in order.
1859
2121
  - `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.
1860
2122
  - `buildContextMenu` (function): function buildContextMenu(input: BuildContextMenuInput): ContextMenu | null — Assemble a menu from a target's catalog verbs; null when the target lists none.
2123
+ - `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:
1861
2124
  - `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.
2125
+ - `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.
1862
2126
  - `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`.
1863
2127
  - `buildingIndex` (function): function buildingIndex(buildings: readonly GeneratedBuilding[]): BuildingIndex — ⚠ undocumented
1864
2128
  - `cappedStacks` (function): function cappedStacks<P>(limit: number, magnitudeOf?: MagnitudeOf<P>): AreaStackPolicy<P> — Keep at most `limit` memberships per `stackKey` (the highest-magnitude ones when `magnitudeOf` is given, else the first-seen). Models capped stacks — e.g. a poison that stacks up to 5 times.
@@ -1880,18 +2144,23 @@
1880
2144
  - `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.
1881
2145
  - `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}.
1882
2146
  - `createAircraftDynamics` (function): function createAircraftDynamics(tuning: AircraftTuning, options: AircraftOptions = {}): AircraftDynamics — Six-degree-of-freedom arcade flight model for fixed-wing, helicopter, and VTOL aircraft.
2147
+ - `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.
1883
2148
  - `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.
1884
2149
  - `createAssetCatalog` (function): function createAssetCatalog<TMeta extends ModelAssetRef = ModelAssetRef>(): AssetCatalog<TMeta> — ⚠ undocumented
1885
2150
  - `createAuthoredTriggerRuntime` (function): function createAuthoredTriggerRuntime(options: { document: SceneDocumentLike; handlers?: TriggerHandlers; /** Invoked for every dispatch after the matching handler (if any). */ onDispatch?: (event: TriggerDispatchEvent) => void; /** Override the collected trigger list (tests / hot-reload). Default: … — Build a runtime that watches a document's authored triggers against moving actors and dispatches to per-action handlers (and optional catch-all). Pure membership math; the game supplies actors each tick from its own player/entity poses.
1886
2151
  - `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.
1887
2152
  - `createBodyBind` (function): function createBodyBind(deps: BodyBindDeps): BodyBind — Mirror a sim's body snapshots onto scene entities each tick — spawn on first sight, pose while bound, despawn on drop — replacing a per-body `setPose` loop plus its `despawn`/`spawn` respawn dance.
1888
2153
  - `createBuoyantBody` (function): function createBuoyantBody(world: PhysicsWorld, config: BuoyantBodyConfig): BuoyantBody — ⚠ undocumented
2154
+ - `createCameraShake` (function): function createCameraShake(config: CameraShakeConfig = {}): CameraShakeController — A seeded, serializable, trauma-based camera shake / impulse controller. A game calls `add(amount, kind?)` on impacts (a hit, an explosion, a landing) to raise trauma in `[0, 1]`; `update(dt)` bleeds it off over time; and `offset()` returns a pooled `{ x, y, z, pitch, yaw, roll }` kick equal to `trauma^exponent` times per-axis maxima times deterministic seeded value-noise sampled along an internal time cursor. A shell consumer applies that offset to the active camera each frame so the view visibly shakes. Nothing here is genre-specific: `kind` is a free label the game styles, all amplitudes/decay are parameters, and `snapshot`/ `restore` round-trips the shake through a save. Deterministic from `seed`: the same seed and dt sequence reproduce the same offsets.
1889
2155
  - `createContributionPool` (function): function createContributionPool(goal: ContributionGoal): ContributionPool — ⚠ undocumented
2156
+ - `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.
1890
2157
  - `createDamageModel` (function): function createDamageModel(config: DamageModelConfig): DamageModel — ⚠ undocumented
2158
+ - `createDayNightCycle` (function): function createDayNightCycle(options: DayNightCycleOptions): DayNightCycle — Creates a turnkey day-night cycle: a serializable model that advances a normalized day fraction on an injected clock and blends per-keyframe phase labels and tint/light colors. Wire this one model, then drive an existing sky/daylight seam from `sample()` (or drop it straight into a `{ calendar(): { dayFraction } }` seam via `calendar()`) to get a moving day-night cycle with color grading — no hand-rolled clock or lerp. `phase` labels and colors are free-form; the model never interprets their meaning.
1891
2159
  - `createEditableTerrain` (function): function createEditableTerrain(config: EditableTerrainConfig): EditableTerrain — ⚠ undocumented
1892
2160
  - `createEnvironmentField` (function): function createEnvironmentField(config: EnvironmentFieldConfig = {}): EnvironmentField — A sampleable environment field: read temperature, wetness, sun/sky exposure, and ambient light at any world position and time. Built on the same renderer-free footing as terrain/wind/water so meters, spawn gating, and damage-in-sunlight read the world the shell renders — no three.js. Instantaneous and pure (no accumulation); stateful build-up belongs to a decay meter reading this field.
1893
2161
  - `createFactionGraph` (function): function createFactionGraph(config: FactionGraphConfig): FactionGraph — ⚠ undocumented
1894
2162
  - `createFactionRoster` (function): function createFactionRoster(graph: FactionGraph): FactionRoster — ⚠ undocumented
2163
+ - `createFastTravelNetwork` (function): function createFastTravelNetwork<TMeta = unknown>(options: FastTravelOptions<TMeta>): FastTravelNetwork<TMeta> — A fast-travel network: defined destinations plus per-player discovery, with distance-sorted queries, a `nearest` lookup, a `canTravel` gate, an `onDiscover` seam, and serializable `snapshot`/`restore`. Travel itself is a teleport the game applies to `TravelPointView.position`; this owns the unlock/where-can-I-go state. Points marked `initial` start discovered.
1895
2164
  - `createFireGrid` (function): function createFireGrid(config: FireGridConfig): FireGrid — ⚠ undocumented
1896
2165
  - `createFogField` (function): function createFogField(config: FogConfig): FogField — ⚠ undocumented
1897
2166
  - `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.
@@ -1899,7 +2168,7 @@
1899
2168
  - `createGrappleSwing` (function): function createGrappleSwing(config: GrappleSwingConfig = {}): GrappleSwing — Grappling-hook rope swing physics with anchor, pendulum motion, and reel-in.
1900
2169
  - `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.
1901
2170
  - `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.
1902
- - `createKinematicVehicle` (function): function createKinematicVehicle(tuning: KinematicVehicleTuning, options: KinematicVehicleOptions = {}): KinematicVehicle — ⚠ undocumented
2171
+ - `createKinematicVehicle` (function): function createKinematicVehicle(initialTuning: KinematicVehicleTuning, options: KinematicVehicleOptions = {}): KinematicVehicle — ⚠ undocumented
1903
2172
  - `createLeaderTrail` (function): function createLeaderTrail(config: LeaderTrailConfig): LeaderTrail — A trailing follower formation that chases a leader along its past path — snake/convoy trails.
1904
2173
  - `createLodScheduler` (function): function createLodScheduler(config: LodSchedulerConfig): LodScheduler — ⚠ undocumented
1905
2174
  - `createMarkerSet` (function): function createMarkerSet<TMeta = unknown>(now: () => number = Date.now): MarkerSet<TMeta> — ⚠ undocumented
@@ -1908,28 +2177,36 @@
1908
2177
  - `createNavGrid` (function): function createNavGrid(config: NavGridConfig): NavGrid — ⚠ undocumented
1909
2178
  - `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.
1910
2179
  - `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.
2180
+ - `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.
1911
2181
  - `createPathFollow` (function): function createPathFollow(config: PathFollowConfig): PathFollowState — ⚠ undocumented
1912
2182
  - `createPlacedStructureStore` (function): function createPlacedStructureStore(): PlacedStructureStore — ⚠ undocumented
1913
2183
  - `createPlacementController` (function): function createPlacementController(config: PlacementControllerConfig): PlacementController — Headless placement ghost: hover → valid/invalid preview, rotate, grid/free/surface snap, commit. Pair with `@jgengine/shell/structures` `PlacementGhost` and {@link placeAssetFromCommit}.
1914
2184
  - `createPlotPermissions` (function): function createPlotPermissions(config: PlotPermissionConfig): PlotPermissions — ⚠ undocumented
1915
2185
  - `createPoseState` (function): function createPoseState(resolveAllowed: (instanceId: string) => PoseAllowedStates | null | undefined): PoseState — Stance/pose transitions — stand, crouch, prone — that change the hitbox and movement.
2186
+ - `createPromptRegistry` (function): function createPromptRegistry(): PromptRegistry — Create a live, observable interaction-prompt registry over the pure {@link resolveActivePrompt} resolver. Register positioned "press E" prompts, `resolve(playerPosition)` each frame as the hero moves, and read `active()` — the nearest strictly-in-range prompt (higher `priority` beats closer). The set is owned here (register/update/unregister/clear/all); selection stays pure. Subscribers are notified only when the active prompt *changes*, so a HUD does not thrash per frame, and `snapshot`/`restore` round-trip the prompts plus the active id through a save (display payloads are free strings/ids the game owns — the registry never branches on their meaning). Allocation-aware: `all()` and `resolve()` reuse a cached array instead of rebuilding per call.
1916
2187
  - `createRagdoll` (function): function createRagdoll(world: PhysicsWorld, config: RagdollConfig): Ragdoll — ⚠ undocumented
1917
2188
  - `createRegionField` (function): function createRegionField<T = unknown>(config: RegionFieldConfig<T>): RegionField<T> — ⚠ undocumented
1918
2189
  - `createReputationLedger` (function): function createReputationLedger(config: ReputationLedgerConfig = {}): ReputationLedger — ⚠ undocumented
2190
+ - `createScreenEffects` (function): function createScreenEffects(options: ScreenEffectsOptions = {}): ScreenEffectsController — A serializable screen-feedback controller: a game triggers transient flashes and edge vignettes (a red damage hit, a green heal flash) or sustained, optionally oscillating tints (a low-health pulse), and reads back a composite of the effects to draw right now with their eased opacities. It is clock-driven — call `advance()` each frame against an injected `now` — and allocation-aware: the composite array and its entries are pooled and reused, so steady-state ticking never allocates. Nothing here is genre-specific: `kind` is a free label the game owns and styles, and vignette / flash / pulse are just parameterizations of the same data (region shape, decay easing, sustained oscillation). A shell overlay subscribes and renders; `snapshot`/`restore` round-trips through a save.
1919
2191
  - `createSelectionBookmarks` (function): function createSelectionBookmarks(snapshot?: SelectionBookmarkSnapshot): SelectionBookmarks — Create a keyed bookmark store, optionally restored from a {@link serialize} snapshot. Restoration re-dedupes and drops empty sets, so a hand-authored or migrated snapshot always normalizes to the same invariants a live store holds.
1920
2192
  - `createSelectionSet` (function): function createSelectionSet(initial?: Iterable<string>): SelectionSet — An ordered, deduplicated set of selected instance ids for RTS unit-command routing.
2193
+ - `createSequenceDirector` (function): function createSequenceDirector<Payload = unknown>(options: SequenceDirectorOptions<Payload>): SequenceDirector<Payload> — A serializable cutscene / sequence director: an ordered timeline of typed cues (`{ atMs, kind, payload }`) advanced by one injected clock, firing each cue once and in order as its time passes — even across a large seek — with play/pause/ seek/skip/stop controls. The director only *schedules and emits* cues; it never interprets what a `kind` means, so the same primitive drives camera moves, dialogue lines, fades, or any game event. `snapshot`/`restore` round-trip the playhead and which cues have fired. Deterministic (no wall clock beyond the injected `now`) and allocation-free on the tick path.
2194
+ - `createSharedAnnotations` (function): function createSharedAnnotations(deps: SharedAnnotationsDeps): SharedAnnotations — Make a map annotation layer collaborative: local `addStroke`/`addShape`/ `addNote`/`remove`/`clear` apply then broadcast a serializable edit over the party feed (the same seam `createPingSystem` uses), and `apply` mirrors inbound edits from other players — dropping our own echoes. Ids are globally unique per client so two players' strokes never collide. Transport-agnostic: wire `feed` to any replicated feed and route received entries into `apply`.
1921
2195
  - `createSpawnDirectorState` (function): function createSpawnDirectorState(config: SpawnDirectorConfig): SpawnDirectorState — ⚠ undocumented
1922
2196
  - `createStationClaim` (function): function createStationClaim(controller?: MountController): StationClaim — ⚠ undocumented
1923
2197
  - `createTargetAcquirer` (function): function createTargetAcquirer(policy: AcquisitionPolicy): TargetAcquirer — Wrap an {@link AcquisitionPolicy} in a small object that remembers the held target between passes, so callers get retention hysteresis for free without threading the previous target by hand. The only state is the held id (a string) — trivially serializable; round-trip it with {@link TargetAcquirer.hold}.
1924
2198
  - `createTerraformBrush` (function): function createTerraformBrush(terrain: Pick<EditableTerrain, "apply">, config: TerraformBrushConfig = {}): TerraformBrush — ⚠ undocumented
1925
2199
  - `createTerrainSnapshot` (function): function createTerrainSnapshot(config: EditableTerrainConfig): TerraformSnapshot — A fresh, unedited terrain snapshot sized to `bounds`/`cellSize` — the seed for a new sculpt document.
1926
2200
  - `createThreatTable` (function): function createThreatTable(config: ThreatTableConfig = {}): ThreatTable — ⚠ undocumented
2201
+ - `createTimerSet` (function): function createTimerSet(options: TimerSetOptions = {}): TimerSet — Create a serializable set of named countdown / countup timers on an injected clock — one primitive for round timers, respawn clocks, and ability cooldown/charge. Start/pause/resume/stop/reset timers by free-string id, read `{ remainingMs, elapsedMs, durationMs, progress01, running, expired }` for a mm:ss readout or a radial/bar fill, and `poll` for expiry edges. Ids and labels carry no genre meaning; `snapshot`/`restore` round-trip through a save.
1927
2202
  - `createVehicleBody` (function): function createVehicleBody(world: PhysicsWorld, config: VehicleBodyConfig): VehicleBody — ⚠ undocumented
1928
2203
  - `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}).
1929
2204
  - `createVehicleSeats` (function): function createVehicleSeats(controller?: MountController): VehicleSeats — Builds a {@link VehicleSeats}, optionally over an existing `MountController` to share its occupancy.
1930
2205
  - `createVisibilityField` (function): function createVisibilityField(config: VisibilityFieldConfig): VisibilityField — Build a per-group gameplay visibility field. First adopters: an RTS/stealth team whose scout observes terrain (which stays remembered after it leaves) while enemy units re-hide once no scout observes their cell, and any authoritative host that must filter hidden entities out of a client's replica.
1931
2206
  - `createVisibilitySystem` (function): function createVisibilitySystem(options: VisibilitySystemOptions): VisibilitySystem — ⚠ undocumented
1932
2207
  - `createVoxelField` (function): function createVoxelField<T extends string = string>(config?: VoxelFieldConfig): VoxelField<T> — ⚠ undocumented
2208
+ - `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.
2209
+ - `createWaypointStore` (function): function createWaypointStore(deps: WaypointStoreDeps = {}): WaypointStore — Player-owned waypoint layer: place/track/clear pins, mirror them into a shared `MarkerSet` (so `Minimap`/`WorldMap`/`Compass` render them for free), and read bearing/distance guidance for an on-screen arrow to the tracked one. State is plain data — `snapshot()`/`restore()` round-trip through any save blob.
1933
2210
  - `customRegion` (function): function customRegion<P extends SamplePoint>(spec: { dimensions: 2 | 3; sample: (rng: () => number) => P; contains: (point: P) => boolean; isEmpty?: boolean; }): SampleRegion<P> — Wrap a caller-defined sampler and bounds test as a {@link SampleRegion} — the escape hatch for regions the built-ins do not cover (a navmesh cell, a heightfield mask, a spline tube).
1934
2211
  - `dashSegments` (function): function dashSegments(path: readonly RoadPoint[], dashLength = 3, gapLength = 3, exclude: readonly DashExclusion[] = []): readonly (readonly RoadPoint[])[] — Split a centerline into dash sub-polylines for lane markings: `dashLength` of painted line, `gapLength` of asphalt, repeated along the path's arc length. Feed each returned sub-path back through {@link buildRoadRibbon} with a thin width to mesh the dashes. Pass `exclude` circles (junction patches) to interrupt the center line through intersections — any dash whose midpoint lands inside an exclusion is dropped.
1935
2212
  - `defineAttackMoveOrder` (function): function defineAttackMoveOrder<TCtx extends OrderMover & OrderTargeting>(config: EngagementKindConfig = {}): OrderKind<TCtx, AttackMoveOrderPayload> — Attack-move: advance toward a destination but break off to engage any hostile acquired within `aggroRadius`, pursuing it to `attackRange` and writing the engagement intent into `order.state` for the game to act on. Completes on reaching the destination with nothing to engage.
@@ -1939,6 +2216,7 @@
1939
2216
  - `defineStopOrder` (function): function defineStopOrder<TCtx extends OrderMover>(config: OrderKindConfig = {}): OrderKind<TCtx, EmptyOrderPayload> — Stop: halt immediately and complete the same tick — the interrupt that clears a unit's intent to standstill.
1940
2217
  - `defineTargetedOrder` (function): function defineTargetedOrder<TCtx extends OrderMover & OrderTargeting>(config: EngagementKindConfig = {}): OrderKind<TCtx, TargetedOrderPayload> — Targeted action: pursue one specific target until within `range`, writing the engagement intent into `order.state`. Completes when the target is gone (despawned/dead), so the game's effect loop runs while `inRange` is true.
1941
2218
  - `densityCoverage` (function): function densityCoverage(kind: "grass_field" | "scatter", area: number, density: number): ScatterCoverage — Coverage for a per-m² kind (`grass_field` / `scatter`): `requested = floor(density × area)`, clamped to the kind's budget. `capped` is true when the request exceeds the budget.
2219
+ - `deriveCityPlots` (function): function deriveCityPlots(network: StreetNetwork, options: CityPlotOptions): CityPlotResult — Subdivide every buildable block's street frontage into size-tiered polygonal plots. Blocks come from the street network's planar faces ({@link extractBlocks}), so every plot fronts a real street; block interiors stay open (courtyards) and a seeded fraction of whole blocks becomes parks. Grand plots — the old "landmarks" — are just the biggest tier of the same pass. Deterministic per seed, bounded by `maxPlots` and per-block caps.
1942
2220
  - `describeScatterCoverage` (function): function describeScatterCoverage(coverage: ScatterCoverage): string — The full one-line coverage readout: `≈ N unit · A m²` plus the {@link budgetWarning} when capped.
1943
2221
  - `discRegion` (function): function discRegion(center: Vec2, radius: number, options: { distribution?: RadialDistribution } = {}): SampleRegion<Vec2> — A filled circle. `"area"` is area-uniform (√-corrected radius, even density); `"radial"` is radius-uniform (clumps toward the center). Angle is drawn first, then radius — matching the common `angle = rng()·2π; r = rng()·R` idiom so migrations keep their stream.
1944
2222
  - `distance` (function): function distance(a: Vec3, b: Vec3): number — ⚠ undocumented
@@ -1963,11 +2241,13 @@
1963
2241
  - `footprintObstacles` (function): function footprintObstacles(grid: FootprintGrid): PlacementObstacle[] — Bridges live reservations into `world/placement`'s `PlacementRules.obstacles` so `validatePlacement`/`createPlacementController` see the grid's committed footprints unchanged.
1964
2242
  - `furnitureSpots` (function): function furnitureSpots(road: RoadEnvironmentDescriptor, options: FurnitureSpotOptions = {}): readonly FurnitureSpot[] — Evenly spaced street-furniture anchors along a road's curb lines — streetlights, palms, signs, hydrants, benches. Each spot sits just outside the asphalt (plus `outset`), faces away from the street, and alternates sides by default so lights stagger like a real avenue. This is the answer to "where do I put it": furniture is an asset of the street, never a hand-typed coordinate.
1965
2243
  - `gauge` (function): function gauge(gaugeId: string): GaugePromptDisplay — ⚠ undocumented
2244
+ - `generateCity` (function): function generateCity(options: CityGeneratorOptions, hx: number, hz: number): GeneratedCity — Grow a street network inside the `hx`/`hz` half-extents, extract its blocks, and subdivide their frontage into plots. Deterministic: identical options ⇒ identical city.
1966
2245
  - `generateLock` (function): function generateLock(seed: string | number, tier: LockTierSpec): LockSpec — Generate a solvable depth-puzzle lock: a "Tumbler's Path" board with a guaranteed solution path carved first, an open-row forgiveness band wrapped around it, tumbler gate columns that pinch to a single exact row, and optional ward-traps that look open but jam on contact. Deterministic: the same (seed, tier) always yields the same board.
1967
2246
  - `getCurrentGameTimestamp` (function): function getCurrentGameTimestamp(createdAt: number, now: number, timeScale?: number | null): number — ⚠ undocumented
1968
2247
  - `getTriggerAction` (function): function getTriggerAction(id: string): TriggerActionDefinition | undefined — Registered definition for an action id, or undefined when the game never declared it.
1969
2248
  - `grass` (function): function grass(config: GrassEnvironmentConfig = {}): GrassEnvironmentDescriptor — Declares a grass vegetation patch for `environment()` — area, blade sizing, density, and colors.
1970
2249
  - `groundSpeed` (function): function groundSpeed(entity: SceneEntity<unknown>): number — Ground speed (horizontal magnitude of velocity) in world units per second. Scale to km/h or mph in game code.
2250
+ - `grounded` (function): function grounded(ctx: Pick<GameContext, "world">, x: number, z: number): readonly [number, number, number] — Ground an XZ point onto the live world surface as `[x, groundY, z]`.
1971
2251
  - `hasValidAdjacency` (function): function hasValidAdjacency(grid: FootprintGrid, cells: readonly GridCell[], accepts: (neighborKind: string) => boolean, requireConnection = false): boolean — Connective-piece adjacency validity: every occupied neighbor of `cells` must satisfy `accepts` (no incompatible piece touching), and when `requireConnection` is true at least one neighbor must (a road/pipe/belt segment placed with nothing to connect to is invalid). An empty-bordered footprint (no occupied neighbors at all) passes unless `requireConnection` demands one.
1972
2252
  - `headingToBearing` (function): function headingToBearing(yaw: number): number — Bearing of an entity facing direction given its `rotationY` (yaw) in radians.
1973
2253
  - `headingToRotationY` (function): function headingToRotationY(headingDegrees: number): number — Convert a compass heading (degrees, `0` = engine north, increasing clockwise) into the Three.js Y-rotation (radians, wrapped to `(-PI, PI]`) a renderer applies. Sign matches `world/placementController.quarterTurnsToRotationY`, so heading `90` equals one clockwise quarter turn. This is the one place degrees cross into the private radian space Three.js requires.
@@ -2041,6 +2321,7 @@
2041
2321
  - `resolveActivePrompt` (function): function resolveActivePrompt<T extends PositionedPrompt>(playerPosition: PromptPoint, prompts: readonly T[]): T | null — Nearest prompt strictly within its radius wins; a higher-priority prompt in range beats any lower-priority one regardless of distance; equal priority and distance keep the earliest prompt in the list.
2042
2322
  - `resolveAnchorOffset` (function): function resolveAnchorOffset(space?: Pick<AssetSpace, "anchor" | "footprint">): Vec2 — The pivot's offset from the footprint center, in engine meters, implied by {@link AssetSpace.anchor} and {@link AssetSpace.footprint}. `center` yields `[0, 0]`; `corner` yields the min corner; a normalized `{ x, z }` scales by the footprint. Subtract it to seat a footprint centered on a point.
2043
2323
  - `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.
2324
+ - `resolveCityLotContent` (function): function resolveCityLotContent(city: Pick<GeneratedCity, "network" | "lots"> & Partial<Pick<GeneratedCity, "plots" | "parks">>, options: CityContentOptions): ResolvedCityLot[] — Enrich a generated city's plots into classed, massed buildings: each plot gets its zone band (radial position under a {@link CityZoneProfile}), a building class rolled from the band's weighted mix — biased by street level AND plot size, with grand plots rolling a landmark class — floors, and the deterministic massing pieces the class composes, sized to the plot's building rect. Deterministic per `seed` via {@link seededStreams}, bounded (one pass over `city.lots`), and pure. Same seed + city ⇒ identical resolved lots.
2044
2325
  - `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.
2045
2326
  - `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.
2046
2327
  - `resolveEmitterGain` (function): function resolveEmitterGain(distance: number, sound: Pick<SoundDef, "gain" | "positional" | "falloff">, busGain: number): number — ⚠ undocumented
@@ -2112,6 +2393,8 @@
2112
2393
  - `toEditorMarker` (function): function toEditorMarker(result: PlaceAssetResult): { id: string; kind: string; position: PlaceAssetVec3; rotationY: number; label: string; color: string; meta: Record<string, unknown>; } — Scene-document form: feed editor `addMarker` / `place_asset` path.
2113
2394
  - `toEngineUnits` (function): function toEngineUnits(sourceValue: number, space?: Pick<AssetSpace, "unitScale">): number — Convert a source-space length to engine meters through the asset's {@link AssetSpace.unitScale} — the data-owned replacement for per-game scale constants (a native ~4-unit kit tile down to a 1-unit grid).
2114
2395
  - `toStructureInput` (function): function toStructureInput(result: PlaceAssetResult): AddStructureInput — Game-state form: feed {@link createPlacedStructureStore}.add.
2396
+ - `trimBandAtJunctions` (function): function trimBandAtJunctions(bandPath: readonly RoadPoint[], bandWidth: number, junctions: readonly RoadJunctionInput[], options: BandTrimOptions = {}): RoadPoint[][] — Cut an offset band (a polyline running PARALLEL to a street — e.g. a sidewalk from `Street.sidewalks.{left,right}`) out of every junction's apron, so the band stops at the crossing instead of sailing straight through it. Unlike {@link trimPathAtJunctions} the band never passes through a node, so it is clipped by DISTANCE: each junction contributes a circular apron of radius `max arm half-width + apronMargin + bandWidth/2 + clearance` (plus a small curb-return allowance), and any part of the band inside any apron circle is removed, splitting the band into the sub-paths that survive outside. Entry/exit points land exactly on the apron boundary. A band that never enters an apron passes through as a single untouched copy.
2397
+ - `trimPathAtJunctions` (function): function trimPathAtJunctions(path: readonly RoadPoint[], width: number, junctions: readonly RoadJunctionInput[], options: JunctionGeometryOptions = {}): TrimmedRoad[] — Cut a street centerline back from the junctions it passes through so its ribbon ENDS at the junction boundary instead of ploughing through the node. Junctions are matched to path vertices within `nodeEpsilon` (endpoints and interior vertices alike); a junction sitting on an interior vertex SPLITS the path into two independently-trimmed sub-paths. Each cut records the exact boundary point and the road's left/right edge corners there, so {@link buildJunctionSurface} can weld its polygon onto the identical vertices with no overlap.
2115
2398
  - `uniformGravity` (function): function uniformGravity(vector: GravityVector = [0, -9.81, 0]): GravityField — Constant vector gravity for ordinary worlds, space stations, and sideways-gravity levels.
2116
2399
  - `uniqueByStackKey` (function): function uniqueByStackKey<P>(magnitudeOf?: MagnitudeOf<P>): AreaStackPolicy<P> — Keep at most one membership per `stackKey`. With `magnitudeOf` the strongest per key wins (ties broken by `sourceId` for determinism); without it the first-seen per key wins. Use for unique-by-key buffs where reapplying the same aura should not stack.
2117
2400
  - `unprojectFromMinimap` (function): function unprojectFromMinimap(point: { x: number; y: number }, view: MinimapView): WorldXZ — Invert `projectToMinimap` (#285.6): minimap pixel → world XZ, rotate-aware — click-to-pin, tap-to-ping, drag-to-set-waypoint map interactions.
@@ -2139,6 +2422,7 @@
2139
2422
 
2140
2423
  ## @jgengine/core/world/authoredObjects
2141
2424
 
2425
+ - `AuthoredAnimation` (type): type AuthoredAnimation = ModelAnimationConfig | "auto" | "none" — A placement's authored rig animation override — the stored `marker.meta.animation` contract (#1274).
2142
2426
  - `AuthoredObject` (interface): interface AuthoredObject — One authored catalog prop resolved from an editor marker — grounded at `x`/`z` with yaw, ready for `ctx.scene.object.place` or {@link placeAuthoredObjects}.
2143
2427
  - `AuthoredObjectMarkerLike` (interface): interface AuthoredObjectMarkerLike extends SceneMarkerLike — Minimal marker shape {@link resolveAuthoredObjects} reads; any `EditorMarker` satisfies it.
2144
2428
  - `AuthoredObjectPlaceTarget` (interface): interface AuthoredObjectPlaceTarget — Structural place target — any `ObjectStore` satisfies it.
@@ -2146,6 +2430,7 @@
2146
2430
  - `ENTITY_MARKER_KINDS` (const): const ENTITY_MARKER_KINDS: readonly string[] — Marker kinds that are spawnable entities (materialized by `authoredEntitySpawns`), not static catalog props. {@link resolveAuthoredObjects} skips them by default so a placed `mob`/`boss` is spawned once as an entity and never also placed as a static mesh.
2147
2431
  - `PlaceAuthoredObjectsOptions` (interface): interface PlaceAuthoredObjectsOptions — Options for {@link placeAuthoredObjects}.
2148
2432
  - `ResolveAuthoredObjectsOptions` (interface): interface ResolveAuthoredObjectsOptions — Options for {@link resolveAuthoredObjects}.
2433
+ - `markerAnimation` (function): function markerAnimation(marker: AuthoredObjectMarkerLike): AuthoredAnimation | undefined — The authored per-placement rig animation override stored at `marker.meta.animation` (#1274), or `undefined` when absent/malformed. `"auto"` / `"none"` pass through as the string modes; any other object is a `ModelAnimationConfig` the shell applies verbatim (validated at author time in the editor). Runtime trusts the persisted document here exactly like it trusts position and rotation.
2149
2434
  - `markerCatalogId` (function): function markerCatalogId(marker: AuthoredObjectMarkerLike): string | null — Catalog id for a marker: first-class `catalogId` field, else `meta.catalogId` migration alias. Returns null when the marker is not an authored catalog prop (spawn, mob, generator, …).
2150
2435
  - `placeAuthoredObjects` (function): function placeAuthoredObjects(store: AuthoredObjectPlaceTarget, objects: readonly AuthoredObject[], sampleHeight: (x: number, z: number) => number, options: PlaceAuthoredObjectsOptions = {}): string[] — Places resolved authored objects into an object store, grounding each on `sampleHeight(x,z)` plus per-object and options vertical offsets. Returns the instance ids that were placed (or kept).
2151
2436
  - `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.
@@ -2208,10 +2493,12 @@
2208
2493
  ## @jgengine/core/world/buildingLots
2209
2494
 
2210
2495
  - `BuildingLotOptions` (interface): interface BuildingLotOptions — Options for {@link deriveBuildingLots}.
2496
+ - `FRONTAGE_FILL_REFERENCE` (const): const FRONTAGE_FILL_REFERENCE: 0.45 — Frontage-fill reference point: at this dial value the compaction is a no-op (legacy spacing/width), so callers can leave `blockFill` unset for the classic look and this value reproduces it exactly.
2211
2497
  - `LotArea` (interface): interface LotArea — Rectangular clip region lots must fall within (world center + half-extents).
2212
2498
  - `PlacedBuildingLot` (interface): interface PlacedBuildingLot — One placed building lot: where a building stands and how it is turned to face its road.
2499
+ - `PlotVariant` (interface): interface PlotVariant extends WorldBounds — One weighted plot size a frontage can mix in: `w` along the road, `d` into the block.
2213
2500
  - `RoadFrontage` (interface): interface RoadFrontage — One road the frontage placer lines with buildings: a centerline polyline and its full width.
2214
- - `deriveBuildingLots` (function): function deriveBuildingLots(options: BuildingLotOptions): PlacedBuildingLot[] — Derive street-aligned building lots from road frontage. Lots are stepped along each road at `footprint.w + spacing`, offset to each side by `width / 2 + setback + footprint.d / 2`, and turned to face the road. Cross-road overlaps are rejected by a bounded nearest-neighbour test, so two roads meeting at a corner don't stack buildings. Deterministic: identical inputs (including seed) always yield the identical list.
2501
+ - `deriveBuildingLots` (function): function deriveBuildingLots(options: BuildingLotOptions): PlacedBuildingLot[] — Derive street-aligned building lots (PLOTS) from road frontage. Each side of each road walks the frontage placing plots at `plot.w + spacing` pitch — rolling the next plot size from the weighted `footprint` variants when several are given — offset outward by `width / 2 + setback + plot.d / 2` and turned to face the road. The PLOT CONTRACT is enforced here, exactly: no two plots ever overlap (true oriented-rect separation with the spacing gap, so corners and curved frontage can't stack buildings), and no plot footprint ever touches any road corridor in `roads` or `avoid` — not just its own frontage road. Deterministic: identical inputs (including seed) always yield the identical list.
2215
2502
 
2216
2503
  ## @jgengine/core/world/buildings
2217
2504
 
@@ -2274,6 +2561,9 @@
2274
2561
  - `CityParcelLocal` (interface): interface CityParcelLocal — One polygonal parcel subdivided out of a block's street frontage.
2275
2562
  - `FabricParams` (interface): interface FabricParams — Everything block extraction needs from the district rules.
2276
2563
  - `FabricStreet` (interface): interface FabricStreet — Minimal street shape the fabric needs (matches cityKind's LocalStreet).
2564
+ - `GraphBlockEdge` (interface): interface GraphBlockEdge — One street-graph edge {@link extractGraphBlocks} traces block faces through.
2565
+ - `GraphBlockNode` (interface): interface GraphBlockNode — Minimal node/edge shapes {@link extractGraphBlocks} needs (matches `StreetNetwork.nodes`/`edges`).
2566
+ - `GraphBlockRings` (interface): interface GraphBlockRings — One block from {@link extractGraphBlocks}: the face polygon and its inset land ring.
2277
2567
  - `GraphFace` (interface): interface GraphFace — One extracted face: closed centerline polygon + the street index along each polygon edge.
2278
2568
  - `ParcelCut` (interface): interface ParcelCut — Inputs for one parcel strip cut from a block ring.
2279
2569
  - `RingWalker` (class): class RingWalker — Arc-length station lookup along a closed ring.
@@ -2282,14 +2572,19 @@
2282
2572
  - `conformPolygonToRing` (function): function conformPolygonToRing(poly: readonly Vec2[], ring: readonly Vec2[]): Vec2[] — Conform a polygon to a containing ring: sample every edge (a straight edge can bulge across a concave notch even when its endpoints hug the boundary), then pull each escaping point to its nearest boundary point. Callers re-run this after any operation that adds mid-edge vertices.
2283
2573
  - `cutParcel` (function): function cutParcel(walker: RingWalker, blockRing: readonly Vec2[], cut: ParcelCut): Vec2[] | null — Cut one polygonal parcel out of a block land ring: the frontage arc between two stations, extruded inward along the station normals, clipped back to the block. Returns null when the strip collapses (over-tight corner, sliver arc).
2284
2574
  - `extractBlocks` (function): function extractBlocks(streets: readonly FabricStreet[], hx: number, hz: number, params: FabricParams): { blocks: BlockRings[]; deadEnds: { pts: Vec2[]; width: number }[] } — Extract closed blocks from the street network: planar faces of the graph, each inset to its curb ring (pavement edge) and land ring (behind the sidewalk band). Faces that collapse under the inset come back with an empty `land` and are the caller's slivers/buffers.
2575
+ - `extractGraphBlocks` (function): function extractGraphBlocks(nodes: readonly GraphBlockNode[], edges: readonly GraphBlockEdge[], params: { sidewalkBase: number; curbMargin: number }): { blocks: GraphBlockRings[]; deadEnds: { pts: Vec2[]; width: number; level: FabricStreet["level"]; street?: number }[] } — Extract closed blocks from an EXACT street graph — the `nodes`/`edges` a street network already carries — instead of re-deriving topology from welded polylines. Half-edges are ordered by true departure angle at each node, dangling chains are pruned first (returned as `deadEnds` for corridor carving), interior faces are traced through the rotation system, and each face is inset to its land ring by the bordering edges' half-widths (+ curb + sidewalk). Robust against wandered and arc-filleted centerlines, which defeat proximity welding. Pure bounded geometry.
2285
2576
  - `isSliverBlock` (function): function isSliverBlock(land: readonly Vec2[], minArea: number, minWidth: number): boolean — Deterministic sliver verdict shared by classification and tests.
2286
2577
  - `pointsInPolygon` (function): function pointsInPolygon(ring: readonly Vec2[], count: number, rng: () => number, margin = 1.5): Vec2[] — Sample deterministic points inside a polygon by seeded rejection over its bounds.
2287
2578
  - `sidewalkWidthFor` (function): function sidewalkWidthFor(level: FabricStreet["level"], base: number): number — Sidewalk band width by street hierarchy (base = the district's street-level width).
2288
2579
 
2289
2580
  ## @jgengine/core/world/cityContent
2290
2581
 
2582
+ - `CITY_FILLER_CLASSES` (const): const CITY_FILLER_CLASSES: readonly CityFillerClass[] — All filler classes, for validation and interior-pass allow-lists.
2583
+ - `CITY_LANDMARK_CLASSES` (const): const CITY_LANDMARK_CLASSES: readonly CityLandmarkClass[] — All landmark classes, for schema hints, validation, and default allow-lists.
2291
2584
  - `CITY_LOT_CLASSES` (const): const CITY_LOT_CLASSES: readonly CityLotClass[] — All classes, for schema hints and validation.
2292
2585
  - `CITY_TREE_SPECIES` (const): const CITY_TREE_SPECIES: readonly CityTreeSpecies[] — All species, for schema hints and validation.
2586
+ - `CityFillerClass` (type): type CityFillerClass = "garage" | "depot" — Filler classes used ONLY by the block-interior fill pass (`resolveCityLotContent` at a high `blockFill`). They are deliberately kept OUT of {@link CITY_LOT_CLASSES} so a zone mix can never weight them onto street frontage — they exist to pack the backs of Manhattan-style blocks with parking structures and warehouses/depots, mixed in with ordinary zone classes.
2587
+ - `CityLandmarkClass` (type): type CityLandmarkClass = "hall" | "arena" | "market" | "campus" — A block-scale landmark class. Unlike {@link CityLotClass} these are never weighted into a zone mix — the landmark pass in `resolveCityLotContent` picks clusters of adjacent lots and stamps one of these over them. Each expresses with the same four piece shapes (box/gable/cylinder/dome) at a much larger footprint (~40–90 m).
2293
2588
  - `CityLotClass` (type): type CityLotClass = | "tower" | "slab" | "shop" | "rowhouse" | "house" | "mansion" | "farmhouse" | "barn" | "silo" — A building class a zone mix can weight — drives lot size, floors, setback, and massing.
2294
2589
  - `CityLotPiece` (interface): interface CityLotPiece — One massing piece in LOT-LOCAL space: x along frontage width, z into the block, y up from grade.
2295
2590
  - `CityPieceRole` (type): type CityPieceRole = "wall" | "roof" | "trim" | "accent" — Palette role a piece colors from (wall/roof/trim/accent map onto the district's style palette).
@@ -2300,12 +2595,32 @@
2300
2595
 
2301
2596
  ## @jgengine/core/world/cityGenerator
2302
2597
 
2303
- - `CityGeneratorOptions` (interface): interface CityGeneratorOptions — Options for {@link generateCity}: a seed, street-dial overrides, and lot pass-through options.
2304
- - `GeneratedCity` (interface): interface GeneratedCity — A generated city: the street network and the building lots lining its frontage.
2305
- - `generateCity` (function): function generateCity(options: CityGeneratorOptions, hx: number, hz: number): GeneratedCity — Grow a street network inside the `hx`/`hz` half-extents and line its frontage with building lots. Deterministic: identical options ⇒ identical city.
2598
+ - `CITY_PLOT_TIERS` (const): const CITY_PLOT_TIERS: readonly CityPlotTier[] — All plot tiers, for schema hints and validation.
2599
+ - `CityContentOptions` (interface): interface CityContentOptions extends CityContentOverrides — Full options for {@link resolveCityLotContent}: the city geometry frame plus content overrides.
2600
+ - `CityContentOverrides` (interface): interface CityContentOverrides — Tunable overrides for {@link resolveCityLotContent} (seed/halfExtents/laneFrontage are supplied).
2601
+ - `CityGeneratorOptions` (interface): interface CityGeneratorOptions — Options for {@link generateCity}: a seed, street-dial overrides, and plot pass-through options.
2602
+ - `CityLevelClassBias` (type): type CityLevelClassBias = Record<StreetLevel, Partial<Record<CityLotClass, number>>> — Per-street-level class weight multipliers applied to the band mix before the class pick, so towers and slabs bias toward wide boulevard/avenue frontage while houses bias toward lanes and quiet streets. A missing class ⇒ multiplier 1. Pure data modulating the weighted mixes.
2603
+ - `CityPlot` (interface): interface CityPlot — One polygonal plot cut from a block's street frontage. Every plot fronts a street.
2604
+ - `CityPlotFrontage` (interface): interface CityPlotFrontage — The street frontage a plot faces: which street, and the frontage chord along it.
2605
+ - `CityPlotOptions` (interface): interface CityPlotOptions — Options for {@link deriveCityPlots}.
2606
+ - `CityPlotResult` (interface): interface CityPlotResult — Output of {@link deriveCityPlots}: the plots plus whole-block park polygons.
2607
+ - `CityPlotTier` (type): type CityPlotTier = "small" | "medium" | "large" | "grand" — Size tier a plot was cut at. `grand` is the block-scale tier that used to be a landmark pass.
2608
+ - `CityZoneMixes` (interface): interface CityZoneMixes — Weighted building-class mix per zone band; the radial profile decides which band a lot falls in.
2609
+ - `DEFAULT_BLOCK_FILL` (const): const DEFAULT_BLOCK_FILL: 0.45 — Default `blockFill`: gently gapped frontage — plots with breathing room, parks reserved.
2610
+ - `DEFAULT_CITY_LEVEL_BIAS` (const): const DEFAULT_CITY_LEVEL_BIAS: CityLevelClassBias — Default street-level bias — boulevards favor big massing, lanes favor small/rural massing.
2611
+ - `DEFAULT_CITY_ZONE_MIXES` (const): const DEFAULT_CITY_ZONE_MIXES: CityZoneMixes — Default zoned-metropolis mixes: towers/slabs downtown, slabs+rowhouses mid, houses at the edge.
2612
+ - `DEFAULT_LANDMARK_SHARE` (const): const DEFAULT_LANDMARK_SHARE: 0.04 — Default grand-plot share dial — a handful of block-scale parcels per default city.
2613
+ - `GeneratedCity` (interface): interface GeneratedCity — A generated city: streets, plots (with rect building lots as a compat view), and park blocks.
2614
+ - `LANDMARK_HARD_CAP` (const): const LANDMARK_HARD_CAP: 12 — Hard cap on grand plots emitted regardless of dial/city size.
2615
+ - `MassingFootprint` (interface): interface MassingFootprint — Axis-aligned massing extents (lot-local): full width along x and depth along z.
2616
+ - `ResolvedCityLot` (interface): interface ResolvedCityLot — One plot enriched with its zone/class/floors/massing — the renderer instances `pieces` at `center`.
2617
+ - `deriveCityPlots` (function): function deriveCityPlots(network: StreetNetwork, options: CityPlotOptions): CityPlotResult — Subdivide every buildable block's street frontage into size-tiered polygonal plots. Blocks come from the street network's planar faces ({@link extractBlocks}), so every plot fronts a real street; block interiors stay open (courtyards) and a seeded fraction of whole blocks becomes parks. Grand plots — the old "landmarks" — are just the biggest tier of the same pass. Deterministic per seed, bounded by `maxPlots` and per-block caps.
2618
+ - `generateCity` (function): function generateCity(options: CityGeneratorOptions, hx: number, hz: number): GeneratedCity — Grow a street network inside the `hx`/`hz` half-extents, extract its blocks, and subdivide their frontage into plots. Deterministic: identical options ⇒ identical city.
2619
+ - `resolveCityLotContent` (function): function resolveCityLotContent(city: Pick<GeneratedCity, "network" | "lots"> & Partial<Pick<GeneratedCity, "plots" | "parks">>, options: CityContentOptions): ResolvedCityLot[] — Enrich a generated city's plots into classed, massed buildings: each plot gets its zone band (radial position under a {@link CityZoneProfile}), a building class rolled from the band's weighted mix — biased by street level AND plot size, with grand plots rolling a landmark class — floors, and the deterministic massing pieces the class composes, sized to the plot's building rect. Deterministic per `seed` via {@link seededStreams}, bounded (one pass over `city.lots`), and pure. Same seed + city ⇒ identical resolved lots.
2306
2620
 
2307
2621
  ## @jgengine/core/world/cityGeometry
2308
2622
 
2623
+ - `OrientedRect` (interface): interface OrientedRect — A rotated rectangle: center, half-extents, and yaw in the engine rotationY convention.
2309
2624
  - `Vec2` (type): type Vec2 = readonly [number, number] — Deterministic 2D polygon math for the `city` studio's block/parcel pipeline: signed areas, point-in-polygon, half-plane clipping, per-edge inward insets (the curb → sidewalk → land and parcel → buildable transforms), simple-loop recovery after aggressive insets, and rotated-rect fitting inside arbitrary polygons. Pure functions over `[x, z]` tuples — no allocation-heavy classes, no rendering, no randomness — so every consumer from the resolver to the tests shares one geometric truth.
2310
2625
  - `clipHalfPlane` (function): function clipHalfPlane(ring: readonly Vec2[], normal: Vec2, limit: number): Vec2[] — Clip a polygon to the half-plane `dot(p, normal) <= limit` (Sutherland–Hodgman step). Returns the surviving ring, possibly empty. The subject may be concave; the output of a single half-plane clip of a simple ring is always a valid (possibly pinched) ring.
2311
2626
  - `dedupeRing` (function): function dedupeRing(ring: readonly Vec2[], epsilon = 1e-6): Vec2[] — Remove consecutive (near-)duplicate vertices; returns [] when fewer than 3 survive.
@@ -2323,8 +2638,10 @@
2323
2638
  - `polygonSignedArea` (function): function polygonSignedArea(ring: readonly Vec2[]): number — Signed area of a polygon ring (positive = counter-clockwise in XZ).
2324
2639
  - `polygonsOverlap` (function): function polygonsOverlap(a: readonly Vec2[], b: readonly Vec2[], shrink = 0.05): boolean — Conservative polygon-overlap test: any vertex of one strictly inside the other, or any edges crossing.
2325
2640
  - `rayDistanceToRing` (function): function rayDistanceToRing(ring: readonly Vec2[], origin: Vec2, dir: Vec2, minT = 0.6): number — Distance from `origin` along `dir` to the first ring-boundary crossing (ignoring hits closer than `minT`, e.g. the edge the origin sits on). Infinity when the ray never leaves — degenerate.
2641
+ - `rectClearsPolyline` (function): function rectClearsPolyline(rect: OrientedRect, path: readonly Vec2[], clearance: number): boolean — True when a rotated rect stays at least `clearance` away from every segment of a polyline — the plot-contract test that keeps building plots off road corridors (pass the road half-width as the clearance). Exact segment-vs-expanded-rect intersection, not corner sampling.
2326
2642
  - `rectCorners` (function): function rectCorners(cx: number, cz: number, hw: number, hd: number, rotationY: number): Vec2[] — All four corners of a rotated rect (center, half-extents, yaw in engine rotationY convention).
2327
2643
  - `rectInsidePolygon` (function): function rectInsidePolygon(ring: readonly Vec2[], cx: number, cz: number, hw: number, hd: number, rotationY: number): boolean — True when the whole rotated rect (corners + edge midpoints) sits inside the ring.
2644
+ - `rectsSeparated` (function): function rectsSeparated(a: OrientedRect, b: OrientedRect): boolean — Separating-axis test for two rotated rectangles: true when a gap exists (no overlap).
2328
2645
  - `ringBounds` (function): function ringBounds(ring: readonly Vec2[]): { minX: number; minZ: number; maxX: number; maxZ: number } — Axis-aligned bounding box of a ring.
2329
2646
  - `ringSelfIntersects` (function): function ringSelfIntersects(ring: readonly Vec2[]): boolean — True when any two non-adjacent edges of the ring properly cross. O(n²), fine for block-scale n.
2330
2647
  - `splitByLine` (function): function splitByLine(ring: readonly Vec2[], normal: Vec2, limit: number): { below: Vec2[]; above: Vec2[] } — Split a polygon by the line `dot(p, normal) = limit` into the `<=` and `>=` sides.
@@ -2399,6 +2716,15 @@
2399
2716
  - `resolveStructureBuildings` (function): function resolveStructureBuildings(descriptor: BuildingEnvironmentDescriptor): GeneratedBuilding[] — ⚠ undocumented
2400
2717
  - `summarizeEnvironment` (function): function summarizeEnvironment(feature: EnvironmentWorldFeature): EnvironmentSummary — ⚠ undocumented
2401
2718
 
2719
+ ## @jgengine/core/world/fastTravel
2720
+
2721
+ - `FastTravelNetwork` (interface): interface FastTravelNetwork<TMeta = unknown> — A network of fast-travel points with per-player discovery + distance queries.
2722
+ - `FastTravelOptions` (interface): interface FastTravelOptions<TMeta = unknown> — Options for {@link createFastTravelNetwork}.
2723
+ - `FastTravelSnapshot` (interface): interface FastTravelSnapshot — Serializable discovery state.
2724
+ - `TravelPointDef` (interface): interface TravelPointDef<TMeta = unknown> — A fast-travel destination the game defines. Discovery is tracked separately.
2725
+ - `TravelPointView` (interface): interface TravelPointView<TMeta = unknown> extends TravelPointDef<TMeta> — A destination plus its discovery state (and distance from a query origin, when given).
2726
+ - `createFastTravelNetwork` (function): function createFastTravelNetwork<TMeta = unknown>(options: FastTravelOptions<TMeta>): FastTravelNetwork<TMeta> — A fast-travel network: defined destinations plus per-player discovery, with distance-sorted queries, a `nearest` lookup, a `canTravel` gate, an `onDiscover` seam, and serializable `snapshot`/`restore`. Travel itself is a teleport the game applies to `TravelPointView.position`; this owns the unlock/where-can-I-go state. Points marked `initial` start discovered.
2727
+
2402
2728
  ## @jgengine/core/world/features
2403
2729
 
2404
2730
  - `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`.
@@ -2519,6 +2845,10 @@
2519
2845
  - `resolveGridCells` (function): function resolveGridCells(config: WorldGridConfig | GridWorldFeature): readonly WorldGridCell[] — ⚠ undocumented
2520
2846
  - `resolveGridInstances` (function): function resolveGridInstances(config: WorldGridConfig | GridWorldFeature): readonly GridInstanceTransform[] — ⚠ undocumented
2521
2847
 
2848
+ ## @jgengine/core/world/grounded
2849
+
2850
+ - `grounded` (function): function grounded(ctx: Pick<GameContext, "world">, x: number, z: number): readonly [number, number, number] — Ground an XZ point onto the live world surface as `[x, groundY, z]`.
2851
+
2522
2852
  ## @jgengine/core/world/interiors
2523
2853
 
2524
2854
  - `EntityLocation` (interface): interface EntityLocation — ⚠ undocumented
@@ -2536,6 +2866,16 @@
2536
2866
  - `LodSchedulerConfig` (interface): interface LodSchedulerConfig — ⚠ undocumented
2537
2867
  - `createLodScheduler` (function): function createLodScheduler(config: LodSchedulerConfig): LodScheduler — ⚠ undocumented
2538
2868
 
2869
+ ## @jgengine/core/world/mapAnnotations
2870
+
2871
+ - `AnnotationLayer` (interface): interface AnnotationLayer — Player-drawn map annotation layer — strokes, shapes, and notes over caller-owned map data.
2872
+ - `AnnotationLayerOptions` (interface): interface AnnotationLayerOptions — Options for {@link createAnnotationLayer}.
2873
+ - `AnnotationSnapshot` (interface): interface AnnotationSnapshot — Whole serializable state of an annotation layer — drop into a save blob.
2874
+ - `MapNote` (interface): interface MapNote — A text note pinned at a world point.
2875
+ - `MapShapeAnnotation` (interface): interface MapShapeAnnotation — A drawn area annotation (circle/rect/polygon), reusing the map-zone shape vocabulary.
2876
+ - `MapStroke` (interface): interface MapStroke — A freehand drawn line on the map — a world-XZ polyline.
2877
+ - `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.
2878
+
2539
2879
  ## @jgengine/core/world/mapLayers
2540
2880
 
2541
2881
  - `MAP_LAYER_TONE_COLORS` (const): const MAP_LAYER_TONE_COLORS: Record<MapLayerTone, string> — ⚠ undocumented
@@ -2744,17 +3084,36 @@
2744
3084
 
2745
3085
  ## @jgengine/core/world/roads
2746
3086
 
3087
+ - `BandTrimOptions` (interface): interface BandTrimOptions extends JunctionGeometryOptions — Options for {@link trimBandAtJunctions} — junction geometry tunables plus a band-specific clearance.
2747
3088
  - `DashExclusion` (interface): interface DashExclusion — A circular exclusion zone: dashes whose midpoint falls inside are dropped (e.g. junction patches).
3089
+ - `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.
3090
+ - `IntersectionMarkingIntent` (interface): interface IntersectionMarkingIntent — Paint intent carried through trimming without renderer inference.
3091
+ - `IntersectionMarkingLine` (interface): interface IntersectionMarkingLine — One longitudinal lane-marking ribbon, offset left (+) or right (-) from the authored centerline.
3092
+ - `IntersectionMarkingOptions` (interface): interface IntersectionMarkingOptions — Tunables for {@link buildIntersectionMarkings}.
3093
+ - `IntersectionSidewalkWidths` (interface): interface IntersectionSidewalkWidths — Widths of renderer-neutral sidewalk bands on each authored side of a street.
3094
+ - `IntersectionStreet` (interface): interface IntersectionStreet — One street to trim + mesh through {@link buildTrimmedIntersections}.
3095
+ - `JunctionApproach` (interface): interface JunctionApproach — One approach feeding {@link buildJunctionSurface}: the exact draped corner vertices a ribbon ends at.
3096
+ - `JunctionGeometryOptions` (interface): interface JunctionGeometryOptions — Tunables shared by {@link trimPathAtJunctions}, {@link buildJunctionSurface}, and {@link buildTrimmedIntersections}.
3097
+ - `RoadCut` (interface): interface RoadCut — One trim of a ribbon end back to a junction boundary — the seam the welded surface attaches to.
3098
+ - `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)]`.
2748
3099
  - `RoadPoint` (type): type RoadPoint = readonly [number, number] — A road centerline vertex in world XZ.
2749
3100
  - `RoadRibbon` (interface): interface RoadRibbon — Renderer-ready triangle ribbon: flat position triples plus triangle indices.
2750
3101
  - `RoadRibbonOptions` (interface): interface RoadRibbonOptions — Options for {@link buildRoadRibbon}.
2751
3102
  - `RoadSample` (interface): interface RoadSample — Result of {@link nearestOnPath}: closest point on the centerline plus distance and tangent.
2752
- - `buildJunctionPatch` (function): function buildJunctionPatch(center: RoadPoint, radius: number, sampleHeight: (x: number, z: number) => number, options: { elevation?: number; segments?: number } = {}): RoadRibbon — Build a flat, ground-draped disc patch centered on `center` — the welded junction surface that covers crossing road ribbons so they read as one intersection instead of stacking/z-fighting. A triangle fan of `segments` sides (default 16), every vertex draped at `sampleHeight + elevation`. Pure geometry; the shell meshes the result with the asphalt material.
3103
+ - `TrimmedIntersections` (interface): interface TrimmedIntersections — Renderer-ready output of {@link buildTrimmedIntersections}: trimmed ribbons + welded junction surfaces.
3104
+ - `TrimmedRoad` (interface): interface TrimmedRoad — A street sub-path after trimming, plus the cuts (0–2) that shortened it. Feed `path` to {@link buildRoadRibbon}.
3105
+ - `buildIntersectionMarkings` (function): function buildIntersectionMarkings(intersections: TrimmedIntersections, sampleHeight: (x: number, z: number) => number, options: IntersectionMarkingOptions = {}): RoadRibbon[] — Mesh the paint declared on streets passed to {@link buildTrimmedIntersections}. Longitudinal ribbons follow the trimmed road paths. At degree-2 nodes corresponding lines are joined by a tangent-continuous cubic (signed offsets are preserved); at multi-arm nodes lines deliberately stop short of the mouth and optional transverse stop lines make that termination readable.
3106
+ - `buildJunctionConnector` (function): function buildJunctionConnector(junction: { x: number; z: number }, approaches: readonly JunctionApproach[], segments = 8): RoadPoint[] | null — Build a tangent-continuous centerline through a two-arm junction. This is the shared path for paint, medians, curbs, or other linear dressing that should follow a bend but stop at crossings. Returns `null` for anything other than exactly two approaches.
3107
+ - `buildJunctionPatch` (function): function buildJunctionPatch(center: RoadPoint, radius: number, sampleHeight: (x: number, z: number) => number, options: { elevation?: number; segments?: number } = {}): RoadRibbon — Build a flat, ground-draped disc patch centered on `center` — a triangle fan of `segments` sides (default 16), every vertex draped at `sampleHeight + elevation`.
3108
+ - `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:
2753
3109
  - `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.
3110
+ - `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.
2754
3111
  - `dashSegments` (function): function dashSegments(path: readonly RoadPoint[], dashLength = 3, gapLength = 3, exclude: readonly DashExclusion[] = []): readonly (readonly RoadPoint[])[] — Split a centerline into dash sub-polylines for lane markings: `dashLength` of painted line, `gapLength` of asphalt, repeated along the path's arc length. Feed each returned sub-path back through {@link buildRoadRibbon} with a thin width to mesh the dashes. Pass `exclude` circles (junction patches) to interrupt the center line through intersections — any dash whose midpoint lands inside an exclusion is dropped.
2755
3112
  - `isOnRoad` (function): function isOnRoad(path: readonly RoadPoint[], width: number, x: number, z: number): boolean — True when the query point lies within half the road `width` of the centerline.
2756
3113
  - `nearestOnPath` (function): function nearestOnPath(path: readonly RoadPoint[], x: number, z: number): RoadSample | null — Closest-point query against a road centerline — the seam traffic AI, spawn placement, and "am I on the road" checks share. Returns null for a degenerate path.
2757
3114
  - `pathLength` (function): function pathLength(path: readonly RoadPoint[]): number — Total arc length of a centerline in world units.
3115
+ - `trimBandAtJunctions` (function): function trimBandAtJunctions(bandPath: readonly RoadPoint[], bandWidth: number, junctions: readonly RoadJunctionInput[], options: BandTrimOptions = {}): RoadPoint[][] — Cut an offset band (a polyline running PARALLEL to a street — e.g. a sidewalk from `Street.sidewalks.{left,right}`) out of every junction's apron, so the band stops at the crossing instead of sailing straight through it. Unlike {@link trimPathAtJunctions} the band never passes through a node, so it is clipped by DISTANCE: each junction contributes a circular apron of radius `max arm half-width + apronMargin + bandWidth/2 + clearance` (plus a small curb-return allowance), and any part of the band inside any apron circle is removed, splitting the band into the sub-paths that survive outside. Entry/exit points land exactly on the apron boundary. A band that never enters an apron passes through as a single untouched copy.
3116
+ - `trimPathAtJunctions` (function): function trimPathAtJunctions(path: readonly RoadPoint[], width: number, junctions: readonly RoadJunctionInput[], options: JunctionGeometryOptions = {}): TrimmedRoad[] — Cut a street centerline back from the junctions it passes through so its ribbon ENDS at the junction boundary instead of ploughing through the node. Junctions are matched to path vertices within `nodeEpsilon` (endpoints and interior vertices alike); a junction sitting on an interior vertex SPLITS the path into two independently-trimmed sub-paths. Each cut records the exact boundary point and the road's left/right edge corners there, so {@link buildJunctionSurface} can weld its polygon onto the identical vertices with no overlap.
2758
3117
 
2759
3118
  ## @jgengine/core/world/scatter
2760
3119
 
@@ -2828,6 +3187,15 @@
2828
3187
  - `circleVsSegment` (function): function circleVsSegment(center: Vec2, radius: number, a: Vec2, b: Vec2, thickness = 0): CircleSegmentHit | null — Circle (center + `radius`) against a capsule segment `a`→`b` of half-thickness `thickness` (0 for a thin wall). Returns the contact — surface normal, penetration depth, contact point, and the separated center — or `null` when they do not overlap. Endpoints are rounded (the segment is a capsule), so a ball never catches on a corner. Reflect the velocity across `normal` for the bounce; the pure geometry every 2D ball game (pinball, breakout, air hockey) reimplemented per wall, bumper, and paddle.
2829
3188
  - `closestPointOnSegment` (function): function closestPointOnSegment(p: Vec2, a: Vec2, b: Vec2): ClosestOnSegment — Closest point on the segment `a`→`b` to point `p`, with the clamped parameter `t` (0 at `a`, 1 at `b`).
2830
3189
 
3190
+ ## @jgengine/core/world/sharedAnnotations
3191
+
3192
+ - `ANNOTATION_FEED_ACTION` (const): const ANNOTATION_FEED_ACTION: "map.annotation" — Feed action shared drawings ride by default (pair with the party feed, like pings).
3193
+ - `AnnotationBroadcast` (type): type AnnotationBroadcast = | { op: "stroke"; from: string; id: string; points: readonly WorldXZ[]; tone?: MapLayerTone; width?: number } | { op: "shape"; from: string; id: string; shape: MapZoneShape; tone?: MapLayerTone; label?: string } | { op: "note"; from: string; id: string; position: WorldXZ; … — A serializable map-annotation edit broadcast to other players.
3194
+ - `AnnotationFeedSink` (interface): interface AnnotationFeedSink — The feed sink shared annotations push to — an alias of the ping/feed `push` seam.
3195
+ - `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.
3196
+ - `SharedAnnotationsDeps` (interface): interface SharedAnnotationsDeps — Construction options for {@link createSharedAnnotations}.
3197
+ - `createSharedAnnotations` (function): function createSharedAnnotations(deps: SharedAnnotationsDeps): SharedAnnotations — Make a map annotation layer collaborative: local `addStroke`/`addShape`/ `addNote`/`remove`/`clear` apply then broadcast a serializable edit over the party feed (the same seam `createPingSystem` uses), and `apply` mirrors inbound edits from other players — dropping our own echoes. Ids are globally unique per client so two players' strokes never collide. Transport-agnostic: wire `feed` to any replicated feed and route received entries into `apply`.
3198
+
2831
3199
  ## @jgengine/core/world/soilKind
2832
3200
 
2833
3201
  - `ResolvedSoil` (interface): interface ResolvedSoil — A resolved soil patch: world-space area center at ground height, footprint size (XZ), and rules.
@@ -2867,6 +3235,14 @@
2867
3235
  - `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.
2868
3236
  - `weightedRegion` (function): function weightedRegion<P extends SamplePoint>(entries: readonly WeightedRegionEntry<P>[]): SampleRegion<P> — A composite that first picks one member by weight, then delegates to its sampler — the "weighted subregions" distribution policy. `contains` is true when any member contains the point.
2869
3237
 
3238
+ ## @jgengine/core/world/spawnOverride
3239
+
3240
+ - `SpawnOverride` (interface): interface SpawnOverride — Per-session player-spawn override — a capture-harness ergonomics seam that lets a single screenshot or drive run place the player somewhere other than the authored `player_spawn` marker *without mutating `editor.scene.json`*. The runner installs one from the `?spawn=` URL overlay (mirroring `?cam=`); {@link authoredSpawnPosition} consults it for the default player-spawn resolution only, so authored content is untouched and the override evaporates the moment the page reloads without the param.
3241
+ - `clearSpawnOverride` (function): function clearSpawnOverride(): void — Clear any installed player-spawn override.
3242
+ - `installSpawnOverride` (function): function installSpawnOverride(override: SpawnOverride | null): void — Install (or, with `null`, clear) the active player-spawn override. Idempotent; last write wins.
3243
+ - `parseSpawnOverride` (function): function parseSpawnOverride(raw: string | null | undefined): SpawnOverride | null — Parse a `?spawn=` / `--spawn` value into a {@link SpawnOverride}, or `null` when it is absent or malformed. Accepts `"x,y,z"` and `"x,y,z,yaw"` (yaw in radians); whitespace around components is tolerated. A non-finite or short tuple yields `null` so a typo never silently teleports the player to `NaN`.
3244
+ - `readSpawnOverride` (function): function readSpawnOverride(): SpawnOverride | null — The currently installed player-spawn override, or `null` when none is active.
3245
+
2870
3246
  ## @jgengine/core/world/streetGenerator
2871
3247
 
2872
3248
  - `Street` (interface): interface Street — One chained through-street: a maximal run of edges through degree-2 nodes, for rendering + furniture.
@@ -2882,6 +3258,7 @@
2882
3258
  - `StreetNetworkMode` (type): type StreetNetworkMode = "net" | "circuit" — The generator's chosen topology family: an open street `net`, or a closed `circuit` loop.
2883
3259
  - `StreetNetworkRules` (interface): interface StreetNetworkRules — Fully-defaulted slider set the generator reads.
2884
3260
  - `StreetNode` (interface): interface StreetNode — One graph node: a junction, a dead end, or a mid-street bend, with its connection count.
3261
+ - `StreetSidewalks` (interface): interface StreetSidewalks — Left/right pedestrian bands flanking a street's asphalt, as offset polylines.
2885
3262
  - `StreetVec2` (type): type StreetVec2 = readonly [number, number] — A path vertex in the volume-local XZ frame.
2886
3263
  - `generateStreets` (function): function generateStreets(rules: StreetNetworkRules, hx: number, hz: number, context: StreetNetworkContext = {}): StreetNetwork — Resolve a full path network from its rules inside a volume of half-extents `hx`×`hz`. Deterministic per `(rules.seed, hx, hz, context)`. Pass a {@link StreetNetworkContext} with a ground sampler to turn water gaps into bridges and ridges into tunnels. Coordinates are volume-local; the caller maps to world space.
2887
3264
 
@@ -3080,6 +3457,15 @@
3080
3457
  - `WATER_VOLUME_KIND` (const): const WATER_VOLUME_KIND: "water" — The editor volume kind marking a box as a water surface.
3081
3458
  - `WaterRules` (interface): interface WaterRules — Fully-defaulted water surface params parsed from a volume's `meta`.
3082
3459
 
3460
+ ## @jgengine/core/world/waypoints
3461
+
3462
+ - `WaypointEntry` (interface): interface WaypointEntry — A single player-placed waypoint. World-XZ only — serializable and renderer-free.
3463
+ - `WaypointGuidance` (interface): interface WaypointGuidance — Direction/range to the tracked waypoint, for an on-screen guide arrow.
3464
+ - `WaypointSnapshot` (interface): interface WaypointSnapshot — Whole serializable state of a {@link WaypointStore} — drop into a save blob.
3465
+ - `WaypointStore` (interface): interface WaypointStore — Player-owned waypoint layer — place/track/clear pins, mirror to a `MarkerSet`, and read guide-arrow data.
3466
+ - `WaypointStoreDeps` (interface): interface WaypointStoreDeps — Construction options for {@link createWaypointStore}.
3467
+ - `createWaypointStore` (function): function createWaypointStore(deps: WaypointStoreDeps = {}): WaypointStore — Player-owned waypoint layer: place/track/clear pins, mirror them into a shared `MarkerSet` (so `Minimap`/`WorldMap`/`Compass` render them for free), and read bearing/distance guidance for an on-screen arrow to the tracked one. State is plain data — `snapshot()`/`restore()` round-trip through any save blob.
3468
+
3083
3469
  ## @jgengine/core/world/weather
3084
3470
 
3085
3471
  - `FireCell` (interface): interface FireCell — ⚠ undocumented