@jgengine/github 0.1.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.
@@ -0,0 +1,416 @@
1
+ <!-- GENERATED by scripts/gen-skill-api.ts — do not edit. Regenerate: bun run gen:skill-api -->
2
+
3
+ # jgengine — exported API surface
4
+
5
+ ## @jgengine/core
6
+
7
+ - `CHANGELOG` (const): const CHANGELOG: Record<string, ChangelogEntry> — Per-version engine changelog keyed by semver string (e.g. `"0.10.0"`).
8
+ - `ChangelogEntry` (interface): interface ChangelogEntry — One release's migrate steps plus added/changed/removed notes (typed mirror of CHANGELOG.md).
9
+ - `VERSION` (const): const VERSION: "0.10.0" — Installed `@jgengine/core` semver — compare against {@link CHANGELOG} keys when migrating.
10
+
11
+ ## @jgengine/core/authoring
12
+
13
+ - `ActionCodesMap` (type): type ActionCodesMap<TAction extends string = string, TCode extends string = string> = Record< TAction, ActionCodes<TCode> > — Maps each game action name to the input codes (hold/toggle keys, repeat rate) that trigger it.
14
+ - `Drop` (interface): interface Drop — A resolved loot outcome — one item or currency grant with its rolled count.
15
+ - `GameDefinition` (interface): interface GameDefinition<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> — Fully-resolved game description produced by {@link defineGame} — assets, scene, and opted-in subsystems.
16
+ - `GameDefinitionConfig` (type): type GameDefinitionConfig<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> = Omit<GameDefinition<TAssetRef, TMultiplayer>, "scene" | "assets"> & { assets?: AssetCatalog<TAssetRef>; } — Input to {@link defineGame} — a `GameDefinition` with `scene` derived and `assets` optional.
17
+ - `GameLoop` (interface): interface GameLoop<TContext = unknown> — Lifecycle hooks a game implements to drive init, per-tick simulation, and player join/leave.
18
+ - `GameServerConfig` (type): type GameServerConfig = "persistent" | { mode: string; [key: string]: unknown } — Hosting mode for a game's multiplayer server: `"persistent"`, or a custom mode with its own options.
19
+ - `InventoryDeclaration` (interface): interface InventoryDeclaration — Shape of one named inventory a game declares — slot count, accepted item types, HUD binding.
20
+ - `LootEntry` (interface): interface LootEntry — One possible drop in a {@link LootTableDef} — an item, currency, or generated item, its count range, and its odds.
21
+ - `LootTableDef` (interface): interface LootTableDef — A named, validated loot table — its roll count, weighted-vs-independent mode, and candidate entries.
22
+ - `PhysicsConfig` (interface): interface PhysicsConfig — World gravity and jump tuning, plus scene-object collision opt-ins, for the game's physics step.
23
+ - `SpawnPointDistanceBias` (type): type SpawnPointDistanceBias = "near" | "far" | "none" — Preference for picking a spawn point relative to `avoid` positions: closer, farther, or unweighted.
24
+ - `SpawnPointSelectionOptions` (interface): interface SpawnPointSelectionOptions — Semantic options for selecting a spawn point without exposing weighting internals.
25
+ - `WorldFeature` (type): type WorldFeature = | ({ kind: "biomes" } & BiomesWorldConfig) | ({ kind: "voxel" } & VoxelWorldConfig) | ({ kind: "plots" } & PlotsWorldConfig) | ({ kind: "tilemap" } & TilemapWorldConfig) | EnvironmentWorldFeature | { kind: "flat" } — A declared world shape — biomes, voxel grid, plots, tilemap, environment, or flat — passed to `defineGame`.
26
+ - `biomes` (function): function biomes(config: BiomesWorldConfig): WorldFeature — Declares a biome-painted world — the whole-world alternative to a single `environment()` terrain.
27
+ - `building` (function): function building(config: BuildingEnvironmentConfig = {}): BuildingEnvironmentDescriptor — Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style.
28
+ - `contextVerb` (function): function contextVerb(label: string, command: string, args?: Record<string, unknown>): ContextVerb — Builds a {@link ContextVerb} for a right-click menu entry.
29
+ - `defineGame` (function): function defineGame<TAssetRef extends ModelAssetRef, TMultiplayer>(config: GameDefinitionConfig<TAssetRef, TMultiplayer>): GameDefinition<TAssetRef, TMultiplayer> — Task-first entry point for authoring a game: fills in `scene` and default `assets`, validates `name`, OR-merges `features` from installed systems, and composes `loop` from `systems` + any classic hooks.
30
+ - `environment` (function): function environment(config: EnvironmentWorldConfig = {}): EnvironmentWorldFeature — Composes an `environment()` world feature from terrain, sky, weather, vegetation, water, structures, roads, and pads.
31
+ - `flat` (function): function flat(): WorldFeature — Declares an empty flat world — the minimal `WorldFeature` for games with no terrain of their own.
32
+ - `grass` (function): function grass(config: GrassEnvironmentConfig = {}): GrassEnvironmentDescriptor — Declares a grass vegetation patch for `environment()` — area, blade sizing, density, and colors.
33
+ - `lootTable` (function): function lootTable(def: LootTableDef): LootTableDef — Validates a loot table definition and returns it unchanged, for use with {@link createLootRegistry}.
34
+ - `ocean` (function): function ocean(config: OceanEnvironmentConfig = {}): OceanEnvironmentDescriptor — Declares an ocean water body for `environment()` — bounds, level, and wave tuning.
35
+ - `plots` (function): function plots(config: PlotsWorldConfig = {}): WorldFeature — Declares a subdivided-plots world — farming, base-building, and other parcel-based layouts.
36
+ - `rain` (function): function rain(config: RainEnvironmentConfig = {}): RainEnvironmentDescriptor — Declares a rainfall weather effect for `environment()` — area, density, speed, wind, and drop width/opacity.
37
+ - `road` (function): function road(config: RoadEnvironmentConfig): RoadEnvironmentDescriptor — Declare a road ribbon for an `environment()` world; the shell drapes and renders it over the terrain.
38
+ - `seededRng` (function): function seededRng(seed: string | number): () => number — Deterministic pseudo-random generator seeded from a string or number — same seed, same sequence.
39
+ - `seededStreams` (function): function seededStreams(seed: string | number): (stream: string) => () => number — Derives independent, deterministic {@link seededRng} streams from one base seed, keyed by stream name.
40
+ - `snow` (function): function snow(config: SnowEnvironmentConfig = {}): SnowEnvironmentDescriptor — Declares a snowfall weather effect for `environment()` — area, density, drift, wind, and flake opacity.
41
+ - `terrain` (function): function terrain(config: TerrainEnvironmentConfig = {}): TerrainEnvironmentDescriptor — Declares a heightfield terrain patch for `environment()` — bounds, noise, materials, and flatten masks.
42
+ - `tilemap` (function): function tilemap(config: TilemapWorldConfig): WorldFeature — Declares a 2D tilemap world from a map string.
43
+ - `voxel` (function): function voxel(config: VoxelWorldConfig): WorldFeature — Declares a voxel-grid world for block-based games.
44
+
45
+ ## @jgengine/core/commands/commandRegistry
46
+
47
+ - `CommandDecodeResult` (type): type CommandDecodeResult<TInput> = | { ok: true; value: TInput } | { ok: false; reason: string } — ⚠ undocumented
48
+ - `CommandDecoder` (type): type CommandDecoder<TInput> = (input: unknown) => CommandDecodeResult<TInput> — Parses raw `unknown` transport input into `TInput`, rejecting anything that doesn't match the command's declared shape. Runs before `validate`/`apply`, so a malformed payload never reaches game logic.
49
+ - `CommandDefinition` (interface): interface CommandDefinition<TState, TInput> — ⚠ undocumented
50
+ - `CommandRegistry` (interface): interface CommandRegistry<TState> — ⚠ undocumented
51
+ - `CommandRejection` (interface): interface CommandRejection — ⚠ undocumented
52
+ - `CommandResult` (type): type CommandResult<TState> = | { status: "applied"; state: TState } | { status: "rejected"; reason: string } | { status: "unknown-command" } — ⚠ undocumented
53
+ - `createCommandRegistry` (function): function createCommandRegistry<TState>(): CommandRegistry<TState> — ⚠ undocumented
54
+
55
+ ## @jgengine/core/devtools/devtools
56
+
57
+ - `AngleUnit` (type): type AngleUnit = "rad" | "deg" — ⚠ undocumented
58
+ - `CONTROL_SCHEMA_VERSION` (const): const CONTROL_SCHEMA_VERSION: 1 — ⚠ undocumented
59
+ - `Devtools` (interface): interface Devtools — ⚠ undocumented
60
+ - `DevtoolsControl` (interface): interface DevtoolsControl — ⚠ undocumented
61
+ - `DevtoolsControlKind` (type): type DevtoolsControlKind = | "slider" | "toggle" | "color" | "select" | "text" | "vec2" | "vec3" | "vec4" | "interval" | "angle" | "enum" — ⚠ undocumented
62
+ - `DevtoolsLogEntry` (interface): interface DevtoolsLogEntry — ⚠ undocumented
63
+ - `DevtoolsLogLevel` (type): type DevtoolsLogLevel = "log" | "info" | "warn" | "error" — ⚠ undocumented
64
+ - `DevtoolsOverrides` (interface): interface DevtoolsOverrides — ⚠ undocumented
65
+ - `DevtoolsSnapshot` (interface): interface DevtoolsSnapshot — ⚠ undocumented
66
+ - `DiscoveredEntry` (interface): interface DiscoveredEntry — ⚠ undocumented
67
+ - `DiscoverySkip` (interface): interface DiscoverySkip — ⚠ undocumented
68
+ - `FrameRecordSample` (interface): interface FrameRecordSample — ⚠ undocumented
69
+ - `FrameStats` (interface): interface FrameStats — ⚠ undocumented
70
+ - `LONG_FRAME_MS` (const): const LONG_FRAME_MS: 33.4 — ⚠ undocumented
71
+ - `LatencyStats` (interface): interface LatencyStats — ⚠ undocumented
72
+ - `LongFrameEvent` (interface): interface LongFrameEvent — ⚠ undocumented
73
+ - `NormalizedColor` (interface): interface NormalizedColor — ⚠ undocumented
74
+ - `OVERRIDES_FORMAT_VERSION` (const): const OVERRIDES_FORMAT_VERSION: 1 — ⚠ undocumented
75
+ - `OverrideApplyDiagnostic` (interface): interface OverrideApplyDiagnostic — ⚠ undocumented
76
+ - `OverrideApplyResult` (interface): interface OverrideApplyResult — ⚠ undocumented
77
+ - `PhaseStats` (interface): interface PhaseStats — ⚠ undocumented
78
+ - `RenderSample` (interface): interface RenderSample — ⚠ undocumented
79
+ - `ScanFieldMeta` (interface): interface ScanFieldMeta extends TunableOptions — ⚠ undocumented
80
+ - `ScanMeta` (type): type ScanMeta = Readonly<Record<string, ScanFieldMeta>> — ⚠ undocumented
81
+ - `Tunable` (interface): interface Tunable<T> — ⚠ undocumented
82
+ - `TunableAccessor` (interface): interface TunableAccessor — ⚠ undocumented
83
+ - `TunableChoice` (interface): interface TunableChoice<T = unknown> — ⚠ undocumented
84
+ - `TunableInterval` (type): type TunableInterval = { min: number; max: number } — ⚠ undocumented
85
+ - `TunableOptions` (interface): interface TunableOptions<T = unknown> — ⚠ undocumented
86
+ - `TunableVec2` (type): type TunableVec2 = [number, number] — ⚠ undocumented
87
+ - `TunableVec3` (type): type TunableVec3 = [number, number, number] — ⚠ undocumented
88
+ - `TunableVec4` (type): type TunableVec4 = [number, number, number, number] — ⚠ undocumented
89
+ - `createDevtools` (function): function createDevtools(): Devtools — ⚠ undocumented
90
+ - `devtools` (const): const devtools: Devtools — ⚠ undocumented
91
+ - `formatLogMessage` (function): function formatLogMessage(args: readonly unknown[]): string — ⚠ undocumented
92
+ - `instrumentLatency` (function): function instrumentLatency<T extends object>(target: T, methods: readonly (keyof T)[], record: (ms: number) => void = devtools.latency.record): T — ⚠ undocumented
93
+ - `measureProfile` (function): function measureProfile<T>(name: string, fn: () => T): T — ⚠ undocumented
94
+ - `snapshotDevtools` (function): function snapshotDevtools(): DevtoolsSnapshot — ⚠ undocumented
95
+ - `tunable` (function): function tunable<T>(name: string, initial: T, options?: TunableOptions<T>): Tunable<T> — ⚠ undocumented
96
+
97
+ ## @jgengine/core/devtools/rewriteTunables
98
+
99
+ - `TunableDelta` (interface): interface TunableDelta — One changed tunable to write back into game source: which table, key path, and new value.
100
+
101
+ ## @jgengine/core/devtools/saveEndpoint
102
+
103
+ - `SaveEndpointInfo` (interface): interface SaveEndpointInfo — Where dev-time saves land: the endpoint URL plus the Games/<gameId> directory it targets.
104
+ - `SaveEndpointRequest` (type): type SaveEndpointRequest = | { kind: "editor-document"; gameId: string; json: string } | { kind: "tunables"; gameId: string; deltas: readonly { table: string; key: string; value: unknown }[]; } — One write request the dev save endpoint accepts: a scene document or tunable deltas.
105
+ - `SaveEndpointResponse` (interface): interface SaveEndpointResponse — Result envelope the dev save endpoint returns for every write request.
106
+
107
+ ## @jgengine/core/devtools/transformTunables
108
+
109
+ - `TunableTransformResult` (interface): interface TunableTransformResult — ⚠ undocumented
110
+
111
+ ## @jgengine/core/devtools/tunableSchema
112
+
113
+ - `AngleUnit` (type): type AngleUnit = "rad" | "deg" — ⚠ undocumented
114
+ - `CONTROL_SCHEMA_VERSION` (const): const CONTROL_SCHEMA_VERSION: 1 — ⚠ undocumented
115
+ - `DevtoolsControlKind` (type): type DevtoolsControlKind = | "slider" | "toggle" | "color" | "select" | "text" | "vec2" | "vec3" | "vec4" | "interval" | "angle" | "enum" — ⚠ undocumented
116
+ - `DevtoolsOverrides` (interface): interface DevtoolsOverrides — ⚠ undocumented
117
+ - `DiscoverySkip` (interface): interface DiscoverySkip — ⚠ undocumented
118
+ - `MAX_SCAN_DEPTH` (const): const MAX_SCAN_DEPTH: 5 — ⚠ undocumented
119
+ - `MAX_SCAN_TARGETS` (const): const MAX_SCAN_TARGETS: 512 — ⚠ undocumented
120
+ - `MAX_TABLE_ENTRIES` (const): const MAX_TABLE_ENTRIES: 64 — ⚠ undocumented
121
+ - `NormalizedColor` (interface): interface NormalizedColor — ⚠ undocumented
122
+ - `OVERRIDES_FORMAT_VERSION` (const): const OVERRIDES_FORMAT_VERSION: 1 — ⚠ undocumented
123
+ - `OverrideApplyDiagnostic` (interface): interface OverrideApplyDiagnostic — ⚠ undocumented
124
+ - `OverrideParseResult` (interface): interface OverrideParseResult — ⚠ undocumented
125
+ - `ResolvedAxisBounds` (interface): interface ResolvedAxisBounds — ⚠ undocumented
126
+ - `ScanFieldMeta` (interface): interface ScanFieldMeta extends TunableOptions — ⚠ undocumented
127
+ - `ScanMeta` (type): type ScanMeta = Readonly<Record<string, ScanFieldMeta>> — ⚠ undocumented
128
+ - `TunableChoice` (interface): interface TunableChoice<T = unknown> — ⚠ undocumented
129
+ - `TunableInterval` (type): type TunableInterval = { min: number; max: number } — ⚠ undocumented
130
+ - `TunableOptions` (interface): interface TunableOptions<T = unknown> — ⚠ undocumented
131
+ - `TunableVec2` (type): type TunableVec2 = [number, number] — ⚠ undocumented
132
+ - `TunableVec3` (type): type TunableVec3 = [number, number, number] — ⚠ undocumented
133
+ - `TunableVec4` (type): type TunableVec4 = [number, number, number, number] — ⚠ undocumented
134
+
135
+ ## @jgengine/core/meta/changelog
136
+
137
+ - `CHANGELOG` (const): const CHANGELOG: Record<string, ChangelogEntry> — Per-version engine changelog keyed by semver string (e.g. `"0.10.0"`).
138
+ - `ChangelogEntry` (interface): interface ChangelogEntry — One release's migrate steps plus added/changed/removed notes (typed mirror of CHANGELOG.md).
139
+ - `VERSION` (const): const VERSION: "0.10.0" — Installed `@jgengine/core` semver — compare against {@link CHANGELOG} keys when migrating.
140
+
141
+ ## @jgengine/core/runtime/adapter
142
+
143
+ - `MultiplayerAdapterConfig` (type): type MultiplayerAdapterConfig = | { kind: "convex"; topology?: MultiplayerTopology; authority?: MultiplayerAuthority } | { kind: "ws"; topology?: MultiplayerTopology; url?: string; authority?: MultiplayerAuthority } | { kind: "socketio"; topology?: MultiplayerTopology; url?: string; authority?: Mult… — ⚠ undocumented
144
+ - `MultiplayerAuthority` (type): type MultiplayerAuthority = "server" | "client" — Where the world simulation is authoritative.
145
+ - `MultiplayerTopology` (type): type MultiplayerTopology = "shared" | "lobbies" | "private" — ⚠ undocumented
146
+ - `ServersPoolConfig` (type): type ServersPoolConfig = { maxServers: number; slotsPerServer: number; minPlayersToStart?: number; adapter: MultiplayerAdapterConfig; } — ⚠ undocumented
147
+ - `adapterOf` (function): function adapterOf(multiplayer: unknown): MultiplayerAdapterConfig | null — ⚠ undocumented
148
+ - `convex` (function): function convex(config?: { topology?: MultiplayerTopology; authority?: MultiplayerAuthority }): MultiplayerAdapterConfig — Convex transport. Omitting `authority` (or passing `"client"`) is **presence-only** — prefer `convexPresence()` to name that intent explicitly. Pass `{ authority: "server" }` for a shared, host-authoritative world — see `examples/HOSTED.md`.
149
+ - `convexPresence` (function): function convexPresence(config?: { topology?: MultiplayerTopology }): MultiplayerAdapterConfig — Presence-only Convex transport — each client runs its own `onTick`; only presence/feeds/chat sync. Sugar for `convex({ ...config, authority: "client" })`.
150
+ - `fly` (function): function fly(config: { app: string; topology?: MultiplayerTopology; path?: string; authority?: MultiplayerAuthority }): MultiplayerAdapterConfig — ⚠ undocumented
151
+ - `isOffline` (function): function isOffline(multiplayer: unknown): boolean — True for a single-player world — no adapter, or an explicit `offline()` one. Gates offline-only wiring like local whole-world save.
152
+ - `isPresenceOnly` (function): function isPresenceOnly(multiplayer: unknown): boolean — True when multiplayer is on but the world sim is not host-authoritative — presence/feeds/chat only. Equivalent to `resolveAuthority(m) === "client"`.
153
+ - `isServerAuthoritative` (function): function isServerAuthoritative(multiplayer: unknown): boolean — True when the adapter opts into host-authoritative world replication (`authority: "server"`).
154
+ - `lan` (function): function lan(config?: { topology?: MultiplayerTopology; port?: number; path?: string; authority?: MultiplayerAuthority; }): MultiplayerAdapterConfig — ⚠ undocumented
155
+ - `multiplayerAdapterKind` (function): function multiplayerAdapterKind(multiplayer: unknown): string | null — ⚠ undocumented
156
+ - `offline` (function): function offline(): MultiplayerAdapterConfig — ⚠ undocumented
157
+ - `p2p` (function): function p2p(config?: { topology?: MultiplayerTopology; room?: string; authority?: MultiplayerAuthority }): MultiplayerAdapterConfig — ⚠ undocumented
158
+ - `resolveAuthority` (function): function resolveAuthority(multiplayer: unknown): MultiplayerAuthority | null — Resolved authority for a multiplayer config. - `offline` / missing adapter → `null` (single-player; not multiplayer authority). - unset or `"client"` → `"client"` (presence-only; each client ticks). - `"server"` → host-authoritative shared sim.
159
+ - `servers` (function): function servers(config: ServersPoolConfig): ServersPoolConfig — ⚠ undocumented
160
+ - `socketIo` (function): function socketIo(config?: { topology?: MultiplayerTopology; url?: string; authority?: MultiplayerAuthority }): MultiplayerAdapterConfig — ⚠ undocumented
161
+ - `ws` (function): function ws(config?: { topology?: MultiplayerTopology; url?: string; authority?: MultiplayerAuthority }): MultiplayerAdapterConfig — WebSocket transport. Omitting `authority` (or passing `"client"`) is **presence-only** — prefer `wsPresence()` to name that intent explicitly. Pass `{ authority: "server" }` for a shared, host-authoritative world — see `examples/HOSTED.md`.
162
+ - `wsPresence` (function): function wsPresence(config?: { topology?: MultiplayerTopology; url?: string }): MultiplayerAdapterConfig — Presence-only WebSocket transport — each client runs its own `onTick`; only presence/feeds/chat sync. Sugar for `ws({ ...config, authority: "client" })`.
163
+
164
+ ## @jgengine/core/runtime/cameraDirector
165
+
166
+ - `CameraDirector` (interface): interface CameraDirector — ⚠ undocumented
167
+ - `ChaseCameraTuning` (type): type ChaseCameraTuning = Partial< Pick<ChaseCameraConfig, "distance" | "height" | "lookHeight" | "springDamping" | "fov" | "lead" | "bank"> > — Runtime patch over the static `camera.chase` config — distance/height/fov retuning from gameplay events (#286.11).
168
+
169
+ ## @jgengine/core/runtime/commandRunner
170
+
171
+ - `CommandDef` (type): type CommandDef<TInput = unknown> = { validate: ( snapshot: GameRuntimeSnapshot, input: TInput, actorUserId: string, ) => CommandValidationError | null; apply: ( snapshot: GameRuntimeSnapshot, input: TInput, actorUserId: string, ) => GameRuntimeSnapshot; } — ⚠ undocumented
172
+ - `CommandValidationError` (type): type CommandValidationError = { reason: string } — ⚠ undocumented
173
+ - `RunCommandResult` (type): type RunCommandResult = | { ok: true; snapshot: GameRuntimeSnapshot } | { ok: false; reason: string } — ⚠ undocumented
174
+
175
+ ## @jgengine/core/runtime/gameContext
176
+
177
+ - `CatalogEntityRole` (type): type CatalogEntityRole = "player" | "enemy" | "hostile" | "npc" | "vehicle" — ⚠ undocumented
178
+ - `FloatTextInput` (interface): interface FloatTextInput — ⚠ undocumented
179
+ - `GameAudio` (interface): interface GameAudio — Reachable audio seam on `ctx.game`: `play`, `music`, and `resume` route through the `audio.play`/`audio.music`/`audio.resume` events the shell's audio engine listens on, so game code triggers sound without importing the shell.
180
+ - `GameContext` (interface): interface GameContext — ⚠ undocumented
181
+ - `GameContextCards` (interface): interface GameContextCards — ⚠ undocumented
182
+ - `GameContextCommands` (interface): interface GameContextCommands — ⚠ undocumented
183
+ - `GameContextContent` (interface): interface GameContextContent — ⚠ undocumented
184
+ - `GameContextEconomy` (interface): interface GameContextEconomy — ⚠ undocumented
185
+ - `GameContextEntityEntry` (interface): interface GameContextEntityEntry — ⚠ undocumented
186
+ - `GameContextFeed` (interface): interface GameContextFeed extends Omit<GameFeed, "bind"> — ⚠ undocumented
187
+ - `GameContextItemEntry` (interface): interface GameContextItemEntry — ⚠ undocumented
188
+ - `GameContextItemUse` (interface): interface GameContextItemUse — ⚠ undocumented
189
+ - `GameContextLoot` (interface): interface GameContextLoot — ⚠ undocumented
190
+ - `GameContextObjectEntry` (interface): interface GameContextObjectEntry — ⚠ undocumented
191
+ - `GameContextOptions` (interface): interface GameContextOptions<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> — ⚠ undocumented
192
+ - `GameContextRace` (interface): interface GameContextRace — ⚠ undocumented
193
+ - `GameContextTurn` (interface): interface GameContextTurn — ⚠ undocumented
194
+ - `GameContextWorld` (interface): interface GameContextWorld — ⚠ undocumented
195
+ - `HitReactionInput` (interface): interface HitReactionInput — ⚠ undocumented
196
+ - `MoveTowardCommitOptions` (interface): interface MoveTowardCommitOptions extends MoveTowardOptions — Options for {@link SceneEntityContext.moveTowardCommit}: {@link MoveTowardOptions} plus an optional facing turn.
197
+ - `SceneEntityContext` (interface): interface SceneEntityContext — ⚠ undocumented
198
+ - `SceneObjectContext` (interface): interface SceneObjectContext extends ObjectStore — ⚠ undocumented
199
+ - `SceneWorldItemContext` (interface): interface SceneWorldItemContext — ⚠ undocumented
200
+ - `TelegraphInput` (interface): interface TelegraphInput — ⚠ undocumented
201
+ - `VfxInput` (interface): interface VfxInput — Request a transient spell/ability VFX burst; `from`/`to` accept an instance id or a world point, `color` is a `0xRRGGBB` tint, and `durationMs` defaults per `kind`.
202
+ - `WorldItemPickupResult` (type): type WorldItemPickupResult = | { status: "ok"; record: WorldItemRecord } | { status: "rejected"; reason: string } — ⚠ undocumented
203
+ - `createGameContext` (function): function createGameContext<TAssetRef extends ModelAssetRef, TMultiplayer>(options: GameContextOptions<TAssetRef, TMultiplayer>): GameContext — ⚠ undocumented
204
+
205
+ ## @jgengine/core/runtime/gameRuntime
206
+
207
+ - `GameRuntime` (type): type GameRuntime = { gameId: string; save: SaveConfig; hydrate: (input: HydrateInput) => GameRuntimeSnapshot; runCommand: ( snapshot: GameRuntimeSnapshot, actorUserId: string, commandName: string, input: unknown, ) => ReturnType<typeof runCommand>; tick: (snapshot: GameRuntimeSnapshot, dtSeconds: nu… — ⚠ undocumented
208
+ - `GameRuntimeDefinition` (type): type GameRuntimeDefinition = { gameId: string; save: SaveConfig; commands: Record<string, CommandDef>; loop?: ServerLoopHooks; } — ⚠ undocumented
209
+ - `HydrateInput` (type): type HydrateInput = { gameId: string; serverId: string; serverRow: RuntimeServerRow; playersByUserId: Record<string, RuntimePlayerRow>; chunksByKey: Record<string, RuntimeChunkRow>; revision?: number; } — ⚠ undocumented
210
+ - `RuntimeInitContext` (type): type RuntimeInitContext = { snapshot: GameRuntimeSnapshot; setSnapshot: (snapshot: GameRuntimeSnapshot) => void; } — ⚠ undocumented
211
+ - `RuntimeLoopContext` (type): type RuntimeLoopContext = RuntimeInitContext & { player: { userId: string; isNew: boolean; }; } — ⚠ undocumented
212
+ - `RuntimeWorldContext` (type): type RuntimeWorldContext = RuntimeInitContext & { playerIds: readonly string[]; } — ⚠ undocumented
213
+ - `ServerLoopHooks` (type): type ServerLoopHooks = { onInit?: (ctx: RuntimeInitContext) => void; onNewPlayer?: (ctx: RuntimeLoopContext) => void; onTick?: (ctx: RuntimeWorldContext, dtSeconds: number) => void; } — ⚠ undocumented
214
+
215
+ ## @jgengine/core/runtime/headlessRunner
216
+
217
+ - `HeadlessInput` (interface): interface HeadlessInput — One step's worth of player intent handed to {@link HeadlessRunner.step} — the held-action set and pointer state the shell would otherwise publish from the browser each frame.
218
+ - `HeadlessRunner` (interface): interface HeadlessRunner — A renderer-free driver for a game loop: builds a {@link GameContext} from a {@link GameDefinition}, runs the init hooks, then advances the simulation one step at a time from injected input. No React, R3F, or three.js — the whole play path (time, input, `onTick`, behaviour nav, optional player movement) runs from `core` primitives alone, so a non-React host (a server tick, a test, a CLI replay) can play a real game and read its world snapshot. The shell's FrameDriver is one such driver bolted to `useFrame`; this is the same step distilled out of the render tree.
219
+ - `HeadlessRunnerOptions` (interface): interface HeadlessRunnerOptions<TAssetRef extends ModelAssetRef, TMultiplayer> — ⚠ undocumented
220
+ - `createHeadlessRunner` (function): function createHeadlessRunner<TAssetRef extends ModelAssetRef, TMultiplayer>(options: HeadlessRunnerOptions<TAssetRef, TMultiplayer>): HeadlessRunner — ⚠ undocumented
221
+
222
+ ## @jgengine/core/runtime/hostPersistence
223
+
224
+ - `FEED_RING_LIMIT` (const): const FEED_RING_LIMIT: 20 — ⚠ undocumented
225
+ - `GameServerRecord` (type): type GameServerRecord = { serverId: string; gameId: string; status: GameServerStatus; mode?: string; modeConfig?: unknown; label?: string; visibility?: SessionVisibility; joinCode?: string; tags?: string[]; memberUserIds: string[]; slotsPerServer: number; save: SaveConfig; serverState: RuntimeServer… — ⚠ undocumented
226
+ - `GameServerStatus` (type): type GameServerStatus = "open" | "running" | "closed" — ⚠ undocumented
227
+ - `HostPersistence` (type): type HostPersistence = { savePlan?: (plan: ServerPersistPlan) => Promise<void>; resetScenario?: (reset: NormalizedScenarioReset) => Promise<void>; loadServer: (serverId: string) => Promise<GameServerRecord | null>; saveServer: (record: GameServerRecord) => Promise<void>; listServers: (gameId: string… — ⚠ undocumented
228
+ - `LEADERBOARD_PENDING_KEY` (const): const LEADERBOARD_PENDING_KEY: "leaderboardPending" — ⚠ undocumented
229
+ - `LEADERBOARD_TOP_LIMIT` (const): const LEADERBOARD_TOP_LIMIT: 100 — ⚠ undocumented
230
+ - `LeaderboardEntry` (type): type LeaderboardEntry = { userId: string; value: number; } — ⚠ undocumented
231
+ - `LeaderboardIncrement` (type): type LeaderboardIncrement = { userId: string; stat: string; scope: LeaderboardScope; serverId?: string; by: number; } — ⚠ undocumented
232
+ - `LeaderboardRow` (type): type LeaderboardRow = { gameId: string; stat: string; scope: LeaderboardScope; serverId?: string; userId: string; value: number; updatedAt: number; } — ⚠ undocumented
233
+ - `OPEN_SERVER_LISTING_LIMIT` (const): const OPEN_SERVER_LISTING_LIMIT: 20 — ⚠ undocumented
234
+ - `OPEN_SERVER_LISTING_MAX` (const): const OPEN_SERVER_LISTING_MAX: 100 — ⚠ undocumented
235
+ - `PlayerProfileRecord` (type): type PlayerProfileRecord = { userId: string; gameId: string; playerState: RuntimePlayerRow; revision: number; updatedAt: number; } — ⚠ undocumented
236
+ - `ServerListing` (type): type ServerListing = { serverId: string; status: GameServerStatus; memberCount: number; slotsPerServer: number; mode?: string; label?: string; visibility?: SessionVisibility; joinCode?: string; tags?: string[]; updatedAt: number; } — ⚠ undocumented
237
+ - `ServerPersistPlan` (type): type ServerPersistPlan = { server: GameServerRecord; profiles: PlayerProfileRecord[]; chunks: WorldChunkRecord[]; deletedChunks: string[]; leaderboard: LeaderboardIncrement[]; } — ⚠ undocumented
238
+ - `SessionAttributes` (type): type SessionAttributes = { label?: string; mode?: string; visibility?: SessionVisibility; joinCode?: string; tags?: string[]; } — ⚠ undocumented
239
+ - `SessionVisibility` (type): type SessionVisibility = "public" | "private" — ⚠ undocumented
240
+ - `ToServerListingOptions` (type): type ToServerListingOptions = { includeJoinCode?: boolean; } — ⚠ undocumented
241
+ - `WorldChunkRecord` (type): type WorldChunkRecord = { serverId: string; chunkKey: string; snapshot: RuntimeChunkRow; updatedAt: number; } — ⚠ undocumented
242
+
243
+ ## @jgengine/core/runtime/hostedGameRunner
244
+
245
+ - `HostedGameRunner` (interface): interface HostedGameRunner — The GameContext-loop equivalent of the pure-reducer `createGameHost`: one authoritative `createGameContext` per world, driven server-side. `onInit` runs once at construction; `onNewPlayer`/`onPlayerLeave` fire per join/leave; `tick` advances `onTick` then commits a revision. Clients pull a full {@link WorldSnapshot} baseline once, then per-tick {@link WorldDiff}s from their last revision. Games ship only normal GameContext code — the runner adds no per-game surface.
246
+ - `HostedGameRunnerOptions` (interface): interface HostedGameRunnerOptions<TAssetRef extends ModelAssetRef, TMultiplayer> — Config for {@link createHostedGameRunner}: the game definition, its content lookup, and an optional host identity.
247
+ - `INPUT_COMMAND` (const): const INPUT_COMMAND: "engine.input" — Reserved command name the authoritative host intercepts on the existing `runCommand` transport to route a client's {@link InputFrame} to `session.input`, so per-tick input needs no separate wire.
248
+ - `InputFrame` (interface): interface InputFrame — One client's input for a tick — the semantic held-action set plus pointer state, the serializable, over-the-wire counterpart of {@link InputSnapshot} the host stores per connected player.
249
+
250
+ ## @jgengine/core/runtime/hostedWorldSession
251
+
252
+ - `HostedWorldRecord` (interface): interface HostedWorldRecord — One hosted world's persisted authoritative state — the unit a {@link HostedWorldStore} loads and saves.
253
+ - `HostedWorldSession` (interface): interface HostedWorldSession — The stateful host substrate a long-lived backend binds (ws server, browser P2P host): a live {@link HostedGameRunner} loaded from a {@link HostedWorldStore}, auto-persisted on tick, serving each client a baseline then diffs. The stateless Convex path doesn't use this — it reconstructs a runner from the same store per invocation and diffs with `diffSnapshots`. Either way the store seam and the game code are identical.
254
+ - `HostedWorldSessionOptions` (interface): interface HostedWorldSessionOptions<TAssetRef extends ModelAssetRef, TMultiplayer> — Config for {@link createHostedWorldSession}: the game, its persistence store, and the auto-save cadence.
255
+ - `HostedWorldStore` (interface): interface HostedWorldStore — Narrow persistence seam for a hosted world — the {@link HostedWorldRecord} counterpart of `HostPersistence`. Backends implement it (memory/file/sql/convex); the session never names one. A stateful host loads once and saves on a cadence; a stateless host reconstructs from `load()` each invocation.
256
+ - `HostedWorldSync` (type): type HostedWorldSync = | { kind: "baseline"; revision: number; snapshot: WorldSnapshot } | { kind: "diff"; diff: WorldDiff } — A client replication pull: a full baseline (first sync / fell behind) or a diff since the client's cursor.
257
+
258
+ ## @jgengine/core/runtime/inputSnapshot
259
+
260
+ - `InputFrame` (interface): interface InputFrame — One client's input for a tick — the semantic held-action set plus pointer state, the serializable, over-the-wire counterpart of {@link InputSnapshot} the host stores per connected player.
261
+ - `InputSnapshot` (interface): interface InputSnapshot — ⚠ undocumented
262
+ - `createInputSnapshot` (function): function createInputSnapshot(): InputSnapshot — ⚠ undocumented
263
+
264
+ ## @jgengine/core/runtime/motionIntents
265
+
266
+ - `MotionIntentBatch` (interface): interface MotionIntentBatch — ⚠ undocumented
267
+ - `MotionIntents` (interface): interface MotionIntents — Seam for game code to reach the motion the shell's FrameDriver otherwise owns privately (#162.4). Game code calls `impulse`, `pushHorizontal`, `setVerticalVelocity`, and/or `setY` from `onTick` or commands; the shell calls `takePending()` once per frame, before integrating gravity, to drain what accumulated. `setY` wins over physics for that frame; impulses add to the velocity the driver is about to integrate; a later `setVerticalVelocity` replaces that velocity outright. Horizontal pushes compose with the walk controller (#282.4): they add to its horizontal velocity and decay naturally as it re-blends toward input — knockback, dashes, explosion shoves without raw `setPose` offsets.
268
+
269
+ ## @jgengine/core/runtime/perContext
270
+
271
+ - `perContext` (function): function perContext<T>(init: (ctx: GameContext) => T): (ctx: GameContext) => T — Per-`GameContext` lazy state, keyed by context identity through a `WeakMap` so it is reclaimed when the context is — the seam a game uses instead of a module-global `Map`, which is process-global and bleeds across worlds when one host serves several `serverId`s (#632). `init` runs once per distinct context on first access; the same context always resolves to the same value. This mirrors the engine's built-in per-ctx pattern (`ctx.player.motion`, `stepPlayerMovement`).
272
+
273
+ ## @jgengine/core/runtime/persistenceScope
274
+
275
+ - `NormalizedScenarioReset` (interface): interface NormalizedScenarioReset — ⚠ undocumented
276
+ - `PersistenceScope` (type): type PersistenceScope = "run" | "meta" — ⚠ undocumented
277
+ - `ScenarioReset` (interface): interface ScenarioReset — ⚠ undocumented
278
+ - `ScopeSchema` (interface): interface ScopeSchema — ⚠ undocumented
279
+ - `ScopedState` (interface): interface ScopedState<T = Record<string, unknown>> — ⚠ undocumented
280
+ - `applyRunReset` (function): function applyRunReset(profile: PlayerProfileRecord, runFields: readonly string[], now: number): PlayerProfileRecord — ⚠ undocumented
281
+ - `clearRunFields` (function): function clearRunFields(player: RuntimePlayerRow, runFields: readonly string[]): RuntimePlayerRow — ⚠ undocumented
282
+ - `mergeScopes` (function): function mergeScopes<T extends Record<string, unknown>>(scoped: ScopedState<T>): Partial<T> — ⚠ undocumented
283
+ - `partitionScopes` (function): function partitionScopes<T extends Record<string, unknown>>(state: T, schema: ScopeSchema): ScopedState<T> — ⚠ undocumented
284
+ - `planScenarioReset` (function): function planScenarioReset(reset: ScenarioReset): NormalizedScenarioReset — ⚠ undocumented
285
+ - `resetRun` (function): function resetRun<T extends Record<string, unknown>>(scoped: ScopedState<T>): ScopedState<T> — ⚠ undocumented
286
+
287
+ ## @jgengine/core/runtime/runtimeSave
288
+
289
+ - `RuntimeSave` (interface): interface RuntimeSave — Whole-world save/load bound to a live world and a pluggable backend. `save()` captures `target.snapshot()` and writes it; `load()` reads it back and `target.hydrate()`s the whole world. In `autosave` mode it also writes on a debounce after any change. Named slots, versioned migration, and offline↔cloud (backend swap) all come for free from the underlying save store.
290
+ - `RuntimeSaveConfig` (interface): interface RuntimeSaveConfig — How {@link createRuntimeSave} is wired — the live world `target`, the `backend` it persists through, and optional mode/slot/versioning/cadence knobs.
291
+ - `RuntimeSaveMode` (type): type RuntimeSaveMode = "autosave" | "manual" — `"autosave"` writes a fresh capture on a debounce after any world change; `"manual"` writes only on an explicit `save()`/`checkpoint()` — the save-point / quest-trigger model.
292
+ - `RuntimeSaveOptions` (type): type RuntimeSaveOptions = Omit<RuntimeSaveConfig, "target"> — {@link RuntimeSaveConfig} without `target` — what a host (`createGameContext`) accepts to build `ctx.game.save` and bind it to the context itself.
293
+ - `RuntimeSaveTarget` (interface): interface RuntimeSaveTarget — The narrow slice of a live `GameContext` a runtime save reads and writes — a `GameContext` satisfies it directly (`ctx.snapshot`/`ctx.hydrate`/`ctx.subscribe`). Depending on this instead of the full context keeps the save controller a deep, decoupled module: it captures and restores the *whole* opted-in world without knowing any subsystem.
294
+ - `createRuntimeSave` (function): function createRuntimeSave(config: RuntimeSaveConfig): RuntimeSave — Bridge a live world to a pluggable save backend: whole-state capture/restore with autosave, save points, named slots, and versioned migration — the same call for offline (localStorage) and cloud (Convex), only the `backend` differs. The game keeps control of *when* it saves (the `mode` plus explicit `checkpoint()` calls from quests/areas) and *when* it restores (`load()` on boot), so any save mechanic — continuous autosave, manual save points, checkpoint triggers — is expressible without new engine code.
295
+
296
+ ## @jgengine/core/runtime/save
297
+
298
+ - `SaveConfig` (type): type SaveConfig = | "none" | { auto: string; scope: SaveScope; } — ⚠ undocumented
299
+ - `SaveScope` (type): type SaveScope = "player" | "chunks" | "player+chunks" — ⚠ undocumented
300
+
301
+ ## @jgengine/core/runtime/snapshot
302
+
303
+ - `GameRuntimeSnapshot` (type): type GameRuntimeSnapshot = { version: number; gameId: string; serverId: string; server: RuntimeServerRow; players: Record<string, RuntimePlayerRow>; chunks: Record<string, RuntimeChunkRow>; revision: number; dirty: { server: boolean; players: string[]; chunks: string[]; }; } — ⚠ undocumented
304
+ - `RUNTIME_SNAPSHOT_VERSION` (const): const RUNTIME_SNAPSHOT_VERSION: 1 — ⚠ undocumented
305
+ - `RuntimeChunkRow` (type): type RuntimeChunkRow = { chunkKey: string; objects: RuntimeObjectRow[]; entities: RuntimeEntityRow[]; flags?: Record<string, unknown>; } — ⚠ undocumented
306
+ - `RuntimeEntityRow` (type): type RuntimeEntityRow = { instanceId: string; catalogId: string; position?: [number, number, number]; rotationY?: number; parentSpace?: string; group?: string; stats?: Record<string, { current: number; max: number; min?: number }>; targetInstanceId?: string | null; userId?: string; } — ⚠ undocumented
307
+ - `RuntimeInventorySlot` (type): type RuntimeInventorySlot = { item: string; count: number; slot?: number; } — ⚠ undocumented
308
+ - `RuntimeObjectRow` (type): type RuntimeObjectRow = { instanceId: string; catalogId: string; position: [number, number, number]; rotationY?: number; parentSpace?: string; flags?: Record<string, unknown>; } — ⚠ undocumented
309
+ - `RuntimePlayerRow` (type): type RuntimePlayerRow = { userId: string; inventories: Record<string, RuntimeInventorySlot[]>; economy: Record<string, number>; unlocks: string[]; quests?: unknown; social?: unknown; leaderboard?: Record<string, number>; session?: Record<string, unknown>; } — ⚠ undocumented
310
+ - `RuntimeProfileRow` (type): type RuntimeProfileRow = { userId: string; gameId: string; player: RuntimePlayerRow; updatedAt: number; } — ⚠ undocumented
311
+ - `RuntimeServerRow` (type): type RuntimeServerRow = { entities: RuntimeEntityRow[]; objects: RuntimeObjectRow[]; session: Record<string, unknown>; feeds?: Record<string, unknown[]>; } — ⚠ undocumented
312
+
313
+ ## @jgengine/core/runtime/transport
314
+
315
+ - `FeedUnsubscribe` (type): type FeedUnsubscribe = () => void — ⚠ undocumented
316
+ - `GameBackend` (type): type GameBackend<TPresenceRow = unknown, TPresenceLocation = unknown, TGameId extends string = string> = { transport: GameRuntimeTransport; feeds?: GameRuntimeFeeds; presence?: PresenceTransport<TPresenceRow, TPresenceLocation, TGameId>; } — ⚠ undocumented
317
+ - `GameRuntimeFeedView` (type): type GameRuntimeFeedView = { action: string; entries: unknown[]; } — ⚠ undocumented
318
+ - `GameRuntimeFeeds` (type): type GameRuntimeFeeds = { subscribeServer: ( serverId: string, onChange: (view: GameRuntimeServerView | null) => void, ) => FeedUnsubscribe; subscribePlayer: ( args: { serverId: string }, onChange: (view: GameRuntimePlayerView | null) => void, ) => FeedUnsubscribe; subscribeFeed: ( args: { serverId:… — ⚠ undocumented
319
+ - `GameRuntimePlayerView` (type): type GameRuntimePlayerView = { userId: string; gameId: string; playerState: unknown; updatedAt: number; } — ⚠ undocumented
320
+ - `GameRuntimeServerView` (type): type GameRuntimeServerView = { serverId: string; gameId: string; revision: number; memberUserIds: string[]; serverState: unknown; updatedAt: number; } — ⚠ undocumented
321
+ - `GameRuntimeTransport` (type): type GameRuntimeTransport = { joinServer: (args: { gameId: string; serverId?: string }) => Promise<JoinServerResult>; leaveServer: (args: { serverId: string }) => Promise<void>; runCommand: (args: RunCommandArgs) => Promise<TransportRunCommandResult>; } — ⚠ undocumented
322
+ - `JoinServerResult` (type): type JoinServerResult = { serverId: string; isNew: boolean; } — ⚠ undocumented
323
+ - `LiveGameBackend` (type): type LiveGameBackend<TPresenceRow = unknown, TPresenceLocation = unknown, TGameId extends string = string> = GameBackend<TPresenceRow, TPresenceLocation, TGameId> & { presenceSync: PresenceSync; pushFeedEntry: (args: { serverId: string; action: string; entry: unknown }) => Promise<void>; chatSyncFor… — ⚠ undocumented
324
+ - `MultiplayerSession` (type): type MultiplayerSession = { gameId: string; userId: string; backend: LiveGameBackend; feedActions: string[]; } — ⚠ undocumented
325
+ - `PresencePoseRow` (type): type PresencePoseRow = { userId: string; position: { x: number; y: number; z: number }; rotationY: number; rotationPitch: number; lastSeenAt: number; } — ⚠ undocumented
326
+ - `PresenceSync` (type): type PresenceSync = { subscribe: (serverId: string, onChange: (rows: PresencePoseRow[]) => void) => FeedUnsubscribe; syncPose: (serverId: string, pose: PlayerPose) => void; } — ⚠ undocumented
327
+ - `RunCommandArgs` (type): type RunCommandArgs = { serverId: string; command: string; input: unknown; } — ⚠ undocumented
328
+ - `TransportRunCommandResult` (type): type TransportRunCommandResult = | { ok: true } | { ok: false; reason: string } — ⚠ undocumented
329
+
330
+ ## @jgengine/core/runtime/visibility
331
+
332
+ - `CameraVisibilityContext` (interface): interface CameraVisibilityContext — A camera's position and reach, as seen by the visibility system.
333
+ - `DEFAULT_VISIBILITY_SETTINGS` (const): const DEFAULT_VISIBILITY_SETTINGS: Readonly<VisibilityDefaults> — Default `VisibilityDefaults` a `VisibilitySystem` falls back to when unspecified.
334
+ - `VisibilityBounds` (interface): interface VisibilityBounds — Sphere bounds used for visibility/streaming distance checks.
335
+ - `VisibilityDecision` (interface): interface VisibilityDecision — Result of evaluating one object against the active cameras this tick.
336
+ - `VisibilityDefaults` (interface): interface VisibilityDefaults — Baseline policy settings a `VisibilitySystem` is constructed with.
337
+ - `VisibilityId` (type): type VisibilityId = string | number — Stable identifier for a visibility-tracked object or camera.
338
+ - `VisibilityObject` (interface): interface VisibilityObject — An entity/asset tracked by `VisibilitySystem.evaluate`.
339
+ - `VisibilityOverrides` (interface): interface VisibilityOverrides — Per-object escape hatches that bypass or tune the default visibility policy.
340
+ - `VisibilityPoint` (interface): interface VisibilityPoint — World-space point; `z` is optional for 2D adapters.
341
+
342
+ ## @jgengine/core/runtime/worldChannel
343
+
344
+ - `WorldClientFrame` (type): type WorldClientFrame = | { t: "join"; isNew: boolean } | { t: "leave" } | { t: "command"; name: string; input: unknown } | { t: "input"; frame: InputFrame } — Client→host frame: a player's session verbs. What a transport marshals upstream.
345
+ - `WorldClientLink` (interface): interface WorldClientLink — The client end of a {@link WorldHost} connection: applies server frames to a local `ctx`, sends session verbs upstream.
346
+ - `WorldHost` (interface): interface WorldHost — The transport-agnostic host: fans one {@link HostedWorldSession} out to many connections, each tracking its own revision cursor so a joiner gets a baseline and everyone else gets diffs. A ws server, a Convex function, or an in-process loopback all drive the same shape — decode a frame → `connection.receive`; after `session.tick` → `broadcast`. No wire format is assumed; frames are plain data a transport serializes however it likes.
347
+ - `WorldHostConnection` (interface): interface WorldHostConnection — One client's link on the host side: routes its upstream frames into the shared session, pushes it sync frames.
348
+ - `WorldServerFrame` (type): type WorldServerFrame = | { t: "baseline"; revision: number; snapshot: WorldSnapshot } | { t: "diff"; diff: WorldDiff } — Host→client frame: the full baseline a joiner needs, then per-tick diffs. What a transport marshals downstream.
349
+
350
+ ## @jgengine/core/runtime/worldMirror
351
+
352
+ - `WorldMirror` (interface): interface WorldMirror — The client end of host-authoritative replication: folds a host's baseline + {@link WorldDiff} stream onto a local {@link GameContext}. It keeps the last full {@link WorldSnapshot}, advances it with each diff, and pushes the result through `ctx.hydrate` — so the client mirrors exactly the subsystems its own game opted into and silently ignores host modules it lacks. This is the inverse of a {@link HostedWorldSession}; the transport in between (loopback, ws, Convex) is irrelevant.
353
+
354
+ ## @jgengine/core/runtime/worldReplication
355
+
356
+ - `WorldDiff` (interface): interface WorldDiff — A revision-stamped delta over a {@link WorldSnapshot}. The host sends one per tick to each client, carrying only what changed since that client's last acknowledged revision — entity/stat/store deltas plus whole snapshots of any other opted-in module (feed, leaderboard, chat, …) that changed. Fold it onto a prior baseline with {@link applyWorldDiff}.
357
+ - `WorldReplicator` (type): type WorldReplicator = ReturnType<typeof createWorldReplicator> — The stateful diff tracker returned by {@link createWorldReplicator}: `commit()`, `diff(sinceRevision)`, `revision()`.
358
+ - `WorldReplicatorOptions` (interface): interface WorldReplicatorOptions — Optional acceleration for {@link createWorldReplicator}: a monotone world-dirty counter (aggregated from each {@link SnapshotModule.version}). When it hasn't advanced since the last commit nothing mutated, so the replicator skips re-reading and re-serializing the whole world — the change-detection short-circuit item #28 asks for. Omit it (or pass a snapshot-only source) to keep the original full-re-serialize-per-commit behavior.
359
+
360
+ ## @jgengine/core/runtime/worldSnapshot
361
+
362
+ - `SnapshotModule` (interface): interface SnapshotModule<T = unknown> — The replication seam for host-authoritative shared worlds: the opt-in feature manifest *is* the replication schema. Each live subsystem a game opts into registers a {@link SnapshotModule} keyed by name; the host serializes exactly the registered set into a {@link WorldSnapshot} and a client hydrates the same keys back. Adding a replicated subsystem is a registration, never a new branch.
363
+ - `SnapshotViewer` (interface): interface SnapshotViewer — Who a host→client snapshot is being projected for — the identity a {@link SnapshotModule.project} filters against.
364
+ - `WorldSnapshot` (type): type WorldSnapshot = Record<string, unknown> — Full world baseline keyed by {@link SnapshotModule.key} — one entry per opted-in subsystem.
365
+
366
+ ## @jgengine/shell/cartridge
367
+
368
+ - `CartridgeAbilitySlot` (interface): interface CartridgeAbilitySlot — ⚠ undocumented
369
+ - `CartridgeConfig` (type): type CartridgeConfig = CartridgeSpec & { name: string; panels: CartridgePanels; hud: { storageKey?: string; panels: readonly CartridgeHudPanelSpec[] }; screens: CartridgeScreens; theme?: Record<string, string>; world?: GameConfig["world"]; physics?: GameConfig["physics"]; assets?: GameConfig["assets… — ⚠ undocumented
370
+ - `CartridgeHudPanelSpec` (interface): interface CartridgeHudPanelSpec — ⚠ undocumented
371
+ - `CartridgePanelItem` (type): type CartridgePanelItem = | { kind: "vital"; stat: string; label: string; tone?: string; width?: number } | { kind: "xp"; width?: number } | { kind: "timer"; label: string } | { kind: "score"; source: "kills"; label: string; digits?: number } | { kind: "abilityBar"; icons: Record<string, string> } |… — ⚠ undocumented
372
+ - `CartridgePanels` (interface): interface CartridgePanels — ⚠ undocumented
373
+ - `CartridgeResultLine` (type): type CartridgeResultLine = { label: string; accent?: boolean } & ( | { source: "kills" | "level" } | { value: string | number } ) — ⚠ undocumented
374
+ - `CartridgeScreens` (interface): interface CartridgeScreens — ⚠ undocumented
375
+ - `cartridge` (function): function cartridge(config: CartridgeConfig): PlayableGame — ⚠ undocumented
376
+
377
+ ## @jgengine/shell/cartridge/runtime
378
+
379
+ - `CartridgeRuntime` (interface): interface CartridgeRuntime — ⚠ undocumented
380
+ - `createCartridge` (function): function createCartridge(spec: CartridgeSpec): CartridgeRuntime — ⚠ undocumented
381
+
382
+ ## @jgengine/shell/cartridge/spec
383
+
384
+ - `BoltFx` (interface): interface BoltFx — ⚠ undocumented
385
+ - `CartridgeEnemy` (interface): interface CartridgeEnemy — ⚠ undocumented
386
+ - `CartridgeFlow` (interface): interface CartridgeFlow — ⚠ undocumented
387
+ - `CartridgePhase` (type): type CartridgePhase = "start" | "countdown" | "playing" | "won" | "lost" — ⚠ undocumented
388
+ - `CartridgePlayer` (interface): interface CartridgePlayer — ⚠ undocumented
389
+ - `CartridgeProgression` (interface): interface CartridgeProgression — ⚠ undocumented
390
+ - `CartridgeRules` (interface): interface CartridgeRules — ⚠ undocumented
391
+ - `CartridgeRun` (interface): interface CartridgeRun — ⚠ undocumented
392
+ - `CartridgeSpawning` (interface): interface CartridgeSpawning — ⚠ undocumented
393
+ - `CartridgeSpec` (interface): interface CartridgeSpec — ⚠ undocumented
394
+ - `CartridgeUpgrade` (interface): interface CartridgeUpgrade — ⚠ undocumented
395
+ - `CartridgeWeapon` (type): type CartridgeWeapon = | (WeaponCommon & { kind: "projectile"; range: number; speed: number }) | (WeaponCommon & { kind: "orbit"; blades: Leveled; radius: Leveled; hitRadius: number; angularSpeed: number; }) | (WeaponCommon & { kind: "pulse"; radius: Leveled; durationSeconds: number }) | (WeaponComm… — ⚠ undocumented
396
+ - `CartridgeXpGems` (interface): interface CartridgeXpGems — ⚠ undocumented
397
+ - `HIT_EFFECT` (const): const HIT_EFFECT: "hit" — ⚠ undocumented
398
+ - `Leveled` (type): type Leveled = | number | { base: number; perLevel: number; min?: number; max?: number } | { table: readonly number[] } — ⚠ undocumented
399
+ - `PulseFx` (interface): interface PulseFx — ⚠ undocumented
400
+ - `UpgradeEffect` (type): type UpgradeEffect = | { kind: "weaponLevel"; weapon: string } | { kind: "statBonus"; stat: string; amount: number } | { kind: "fieldAdd"; field: string; amount: number } | { kind: "fieldMultiply"; field: string; factor: number } | { kind: "custom"; apply(ctx: GameContext, run: CartridgeRun, stacks:… — ⚠ undocumented
401
+ - `WASD_KEYBINDS` (const): const WASD_KEYBINDS: ActionCodesMap — ⚠ undocumented
402
+ - `WeaponCommon` (interface): interface WeaponCommon — ⚠ undocumented
403
+ - `WeaponFireArgs` (interface): interface WeaponFireArgs — ⚠ undocumented
404
+ - `XP_GEM_BASE_TYPE` (const): const XP_GEM_BASE_TYPE: "xp_gem" — ⚠ undocumented
405
+ - `leveled` (function): function leveled(value: Leveled, level: number): number — ⚠ undocumented
406
+
407
+ ## @jgengine/shell/cartridge/testkit
408
+
409
+ - `CartridgeSmokeOptions` (interface): interface CartridgeSmokeOptions — ⚠ undocumented
410
+ - `bootCartridge` (function): function bootCartridge(spec: CartridgeSpec & { name?: string; world?: WorldFeature; physics?: PhysicsConfig }): { ctx: GameContext; cart: CartridgeRuntime } — ⚠ undocumented
411
+ - `cartridgeSmokeTest` (function): function cartridgeSmokeTest(spec: CartridgeSpec & { name?: string; world?: WorldFeature; physics?: PhysicsConfig }, options?: CartridgeSmokeOptions): void — ⚠ undocumented
412
+ - `tickCartridge` (function): function tickCartridge(ctx: GameContext, cart: CartridgeRuntime, seconds: number, step = 0.1): void — ⚠ undocumented
413
+
414
+ ## @jgengine/shell/cartridge/validate
415
+
416
+ - `validateCartridge` (function): function validateCartridge(spec: CartridgeSpec): string[] — ⚠ undocumented
@@ -0,0 +1,21 @@
1
+ <!-- GENERATED by scripts/gen-capability-index.ts — do not edit. Regenerate: bun run gen:capabilities -->
2
+
3
+ # jgengine — capability index
4
+
5
+ Reach for these before hand-rolling. Each row is *the thing you need* → *the primitive that already does it*.
6
+
7
+ ## define-game — single public game-authoring path — compose systems, world, and loop in one definition
8
+
9
+ - `defineGame` (function) · `import { defineGame } from "@jgengine/core/authoring"`
10
+
11
+ ## headless-runner — play a real game loop with no renderer — tick, feed input, read the world snapshot
12
+
13
+ - `HeadlessRunner` (interface) · `import { HeadlessRunner } from "@jgengine/core/runtime/headlessRunner"`
14
+
15
+ ## loot-table — validate a loot table definition for use with the registry
16
+
17
+ - `lootTable` (function) · `import { lootTable } from "@jgengine/core/authoring"`
18
+
19
+ ## runtime-save — save/load the whole game world through a pluggable backend, autosave or save points
20
+
21
+ - `createRuntimeSave` (function) · `import { createRuntimeSave } from "@jgengine/core/runtime/runtimeSave"`
@@ -0,0 +1,72 @@
1
+ # jgengine-api — Cartridge
2
+
3
+ Reference module for the [`jgengine`](./SKILL.md) skill. Load this when building a game as a **cartridge** — one declarative config instead of hand-wired loop/state/UI files. A cartridge game is ~75% smaller than the classic shape and nearly all of it is data; reach for `defineGame` + `defineSystem` ([reference-systems.md](./reference-systems.md)) when the simulation outgrows cartridge archetypes — same single authoring model, no rewrite cliff.
4
+
5
+ ## Why
6
+
7
+ Across the classic games, 78–91% of each game's LOC was generic wiring restated per game: a run-state store with subscribe/notify, chase-and-contact enemy loops, auto-fire weapon routines, magnet pickups, draft plumbing, phase-gated HUD trees, and tests for all of it. The cartridge layer owns every one of those; the game ships only its **data** (catalogs, tuning, layout) and any genuinely bespoke rules through typed escape hatches.
8
+
9
+ ## Shape
10
+
11
+ `game.config.ts` is the whole game — `cartridge({...})` from `@jgengine/shell/cartridge` compiles the config into a `PlayableGame` (validating it first — a bad reference throws at import with a list of problems). `loop.ts` and `world.ts` disappear; the spec carries the world feature and the loop is engine-owned. `main.tsx` is 5 lines via `mountGame` (`@/components/ui/mount`, registry). Sprites/SVG art stay in `src/game/assets.ts`; the game keeps one test file under `src/game/`.
12
+
13
+ ```ts
14
+ import { cartridge, type CartridgeConfig } from "@jgengine/shell/cartridge";
15
+ import { standardCartridgePanels } from "@/components/ui/cartridge-panels";
16
+
17
+ export const config: CartridgeConfig = {
18
+ name, seed, panels: standardCartridgePanels, assets, entitySprites,
19
+ flow: { start: "gate", countdownSeconds: 3, restart: true }, // press-to-start → 3-2-1 → playing; "restart" command
20
+ player: { kind, health, walkSpeed }, // compiled into content + spawned per player
21
+ enemies: { id: { label, health, walkSpeed, xp, contact: { damage, intervalSeconds }, behavior: "chase" | "none" } },
22
+ combat: { contactRadius },
23
+ spawning: { director: SpawnDirectorConfig, placement: { kind: "ring", radius } },
24
+ weapons: { id: { kind: "projectile" | "orbit" | "pulse" | "custom", damage, cooldownMs, maxLevel, ... } },
25
+ progression: { xp: Curve, maxLevel, draft: { choices, upgrades } },
26
+ fields: { magnetRadius, damageMultiplier }, // named run-scalars upgrades mutate
27
+ xpGems: { collectRadius, pullSpeed, rarityThresholds, defaultRarity },
28
+ rules: { win: { kind: "survive", seconds }, lose: { kind: "playerDeath" } | { kind: "custom", check }, killLeaderboardStat },
29
+ world, physics, camera, worldItem, theme, hud, screens, // screens: start/win/lose
30
+ };
31
+ export const game = cartridge(config);
32
+ ```
33
+
34
+ The run is a phase machine every game gets for free: `start → countdown → playing → won | lost`. `flow.start: "gate"` renders `screens.start` (TitleScreen binding) until begin; `flow.countdownSeconds` renders the big-number countdown; `flow.restart: true` registers a `restart` command that resets the run in place, clears cartridge entities, and restores player stats — no hand-rolled session store, phase union, or reset function. `run.playingSeconds` is the run clock (drives the survive rule and the timer panel), so pauses and pre-game phases never skew timing.
35
+
36
+ ## Cartridge surface (`@jgengine/shell/cartridge/`)
37
+
38
+ The survivor-shaped defaults (XP gems, contact-radius melee, orbit/pulse/projectile weapons) are a genre archetype, not a core primitive — the whole cartridge implementation lives in `@jgengine/shell` (opt-in, alongside its React binding), never in `@jgengine/core`. `core` only supplies the generic pieces it composes: `spawnDirector`, `abilityKit`, `leveling`/`progression`, `runDraft`, `autoTarget`. A puzzle or tactics game imports none of this.
39
+
40
+ - `@jgengine/shell/cartridge/spec` — the `CartridgeSpec` types, `Leveled` values (`number | { base, perLevel, min?, max? } | { table }` resolved by `leveled(value, level)`), `WASD_KEYBINDS` (the default when `input` is omitted).
41
+ - `@jgengine/shell/cartridge/runtime` — `createCartridge(spec)` → `{ content, loop, run(ctx), weaponKit(ctx), chooseUpgrade(ctx, offerId) }`. Owns the run store (outcome/kills/fields/weapon levels, subscribe/notify), spawn director advance + ring placement, chase + contact-damage enemies (terrain-grounded), the three weapon archetypes with auto-targeting, magnet xp-gem pickups feeding `leveling()`, pause-and-draft level-ups, kill → gem drop + leaderboard, and win/lose rules.
42
+ - `@jgengine/shell/cartridge/validate` — `validateCartridge(spec)` → problem list: spawn waves must reference declared enemies, upgrades must reference declared weapons/fields, stacks can't exceed weapon `maxLevel`, tuning must be positive, rarity thresholds descending. The game's test asserts it returns `[]`.
43
+
44
+ Weapon archetypes: `projectile` (auto-target nearest in `range`, travel-time bolt fx), `orbit` (leveled blade count/radius sweeping `hitRadius`), `pulse` (radial AoE with linear falloff and an expanding-ring fx). Upgrade effects: `weaponLevel` (+1 level per stack), `statBonus` (+max and +current on pick), `fieldAdd` / `fieldMultiply` (recomputed from stacks). Weapon damage is multiplied by the `damageMultiplier` field when declared.
45
+
46
+ ## Presentation (shell + registry)
47
+
48
+ `hud.panels` is a schema — items `vital | xp | timer | score | abilityBar | component`, anchored via the movable HUD layout; `screens.win/lose` render the results/death screens; the upgrade-draft modal appears whenever a draft is pending. The shell renders the frame and injects concrete components through the `panels` seam — `standardCartridgePanels` (registry `cartridge-panels`) binds the jgengine UI kit; swap any binding for a custom component without touching the engine. Weapon fx render engine-side from the run store's bolt/pulse feeds (`fxColor`/`fxEmissive` per weapon). `theme` is the `--jg-*` CSS var block — hand-pick it or derive from a few seed colors with `deriveJgTheme` (registry `jg-theme`).
49
+
50
+ ## Escape hatches — bespoke logic without leaving the cartridge
51
+
52
+ - `weapons.<id> = { kind: "custom", fire(ctx, run, args) }` — cooldown/level/damage handled for you; the fire shape is yours.
53
+ - `spawning.placement = { kind: "custom", position(ctx, run) }`.
54
+ - `rules.win = { kind: "custom", check(ctx, run) }`.
55
+ - `progression.draft.upgrades[].effect = { kind: "custom", apply(ctx, run, stacks) }`.
56
+ - `systems: [(ctx, run, dt) => ...]` — extra per-tick simulation after the built-ins, only while playing.
57
+ - `hud` items `{ kind: "component", Component }` — arbitrary React panels alongside the schema ones.
58
+
59
+ A game that is *mostly* bespoke simulation (custom physics, session machines) should keep `defineGame` and write its systems — the cartridge is for games whose shape the archetypes already cover.
60
+
61
+ ## Testing
62
+
63
+ Cartridge behaviors are engine-tested once (`packages/shell/src/cartridge/runtime.test.ts`); the game test is one call plus any game-specific assertions:
64
+
65
+ ```ts
66
+ import { bootCartridge, cartridgeSmokeTest, tickCartridge } from "@jgengine/shell/cartridge/testkit";
67
+ cartridgeSmokeTest(config); // validate + world summary + headless run/spawn/kill/gem smoke
68
+ ```
69
+
70
+ `bootCartridge`/`tickCartridge` build a headless `GameContext` and drive the loop (auto-choosing drafts) for custom assertions — see `@jgengine/shell/cartridge/testkit`. The testkit imports `bun:test`; import it from test files only.
71
+
72
+ Barrel surface tokens: createKeyValueStore createUnlocks durabilityFraction isComplete isOverdrawn memorySaveBackend partInSlot pruneToasts policyProjectsViewers projectByVisibleIds projectEntitiesForViewer projectPerUserForViewer visibleEntityIds applyDeltaToSnapshot applySurfaceDeltaToSnapshot boundaryNeighbors catenaryCurve distanceToPolygonEdge footprintObstacles hasValidAdjacency pointInPolygon polygonArea polygonBounds populateNavGridFromEnvironment readScatterPalette readScatterRules revertDeltaFromSnapshot revertSurfaceDeltaFromSnapshot slopeStepCost solveLock solveLockPath
@@ -0,0 +1,9 @@
1
+ # Barrel helpers (orphan anchors)
2
+
3
+ Surfaced so the orphan gate keeps public barrel re-exports discoverable.
4
+
5
+ Gameplay: `createKeyValueStore` `createUnlocks` `durabilityFraction` `isComplete` `isOverdrawn` `memorySaveBackend` `partInSlot` `pruneToasts`
6
+
7
+ World projection: `policyProjectsViewers` `projectByVisibleIds` `projectEntitiesForViewer` `projectPerUserForViewer` `visibleEntityIds`
8
+
9
+ World: `applyDeltaToSnapshot` `applySurfaceDeltaToSnapshot` `boundaryNeighbors` `catenaryCurve` `distanceToPolygonEdge` `footprintObstacles` `hasValidAdjacency` `pointInPolygon` `polygonArea` `polygonBounds` `populateNavGridFromEnvironment` `readScatterPalette` `readScatterRules` `revertDeltaFromSnapshot` `revertSurfaceDeltaFromSnapshot` `slopeStepCost` `solveLock` `solveLockPath`