@jgengine/convex 0.49.1 → 0.51.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.
@@ -6,7 +6,7 @@
6
6
 
7
7
  - `CHANGELOG` (const): const CHANGELOG: Record<string, ChangelogEntry> — Per-version engine changelog keyed by semver string (e.g. `"0.10.0"`).
8
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.49.1" — Installed `@jgengine/core` semver - compare against {@link CHANGELOG} keys when migrating.
9
+ - `VERSION` (const): const VERSION: "0.51.0" — Installed `@jgengine/core` semver - compare against {@link CHANGELOG} keys when migrating.
10
10
 
11
11
  ## @jgengine/core/authoring
12
12
 
@@ -32,7 +32,8 @@
32
32
  - `SceneOwnershipManifest` (interface): interface SceneOwnershipManifest — Serializable record of a world's ownership declarations — persisted next to the scene document or shipped by a game.
33
33
  - `SceneProvenance` (type): type SceneProvenance = | AuthoredProvenance | GeneratedProvenance | RuntimeProvenance | TransientProvenance — The provenance of one editor-visible object — authored, generated, runtime, or transient.
34
34
  - `SceneProvenanceKind` (type): type SceneProvenanceKind = "authored" | "generated" | "runtime" | "transient" — Scene ownership boundary — gives every editor-visible object an explicit provenance and a single verdict (expose / bake / reject) so the editor never presents unauthored content as broken authored content.
35
- - `SpawnPointDistanceBias` (type): type SpawnPointDistanceBias = "near" | "far" | "none" — Preference for picking a spawn point relative to `avoid` positions: closer, farther, or unweighted.
35
+ - `SpawnPointBiasStrength` (type): type SpawnPointBiasStrength = "subtle" | "moderate" | "strong" — How strongly the distance preference weighs candidates — a named intent, not a weighting exponent.
36
+ - `SpawnPointDistanceBias` (type): type SpawnPointDistanceBias = "near" | "far" | "none" — Which way a spawn's chance leans, relative to `avoid`: closer, farther, or unweighted.
36
37
  - `SpawnPointSelectionOptions` (interface): interface SpawnPointSelectionOptions — Semantic options for selecting a spawn point without exposing weighting internals.
37
38
  - `TransientProvenance` (interface): interface TransientProvenance — An ephemeral simulation object — a spawned agent, projectile, or particle that never persists.
38
39
  - `WorldFeature` (type): type WorldFeature = | PlaceWorldFeature | ({ kind: "biomes" } & BiomesWorldConfig) | ({ kind: "voxel" } & VoxelWorldConfig) | ({ kind: "plots" } & PlotsWorldConfig) | ({ kind: "tilemap" } & TilemapWorldConfig) | EnvironmentWorldFeature | { kind: "flat" } — A declared world shape passed to `defineGame`. The preferred model is the place feature from `world()` (`@jgengine/core/placement/place`): substrate + laws, with all dressing authored in the editor. The remaining members — biomes, voxel grid, plots, tilemap, environment, flat — are the legacy code-declared shapes kept for existing games.
@@ -54,6 +55,7 @@
54
55
  - `road` (function): function road(config: RoadEnvironmentConfig): RoadEnvironmentDescriptor — Declare a road ribbon for an `environment()` world; the shell drapes and renders it over the terrain.
55
56
  - `seededRng` (function): function seededRng(seed: string | number): SeededRng — Deterministic pseudo-random generator seeded from a string or number — same seed, same sequence.
56
57
  - `seededStreams` (function): function seededStreams(seed: string | number): (stream: string) => () => number — Derives independent, deterministic {@link seededRng} streams from one base seed, keyed by stream name.
58
+ - `selectSpawnPoint` (function): function selectSpawnPoint(options: SpawnPointSelectionOptions): NavPoint | null — Select a spawn point by game intent, keeping the weighting in the placement part's candidate table.
57
59
  - `snow` (function): function snow(config: SnowEnvironmentConfig = {}): SnowEnvironmentDescriptor — Declares a snowfall weather effect for `environment()` — area, density, drift, wind, and flake opacity.
58
60
  - `terrain` (function): function terrain(config: TerrainEnvironmentConfig = {}): TerrainEnvironmentDescriptor — Declares a heightfield terrain patch for `environment()` — bounds, noise, materials, and flatten masks.
59
61
  - `tilemap` (function): function tilemap(config: TilemapWorldConfig): WorldFeature — Declares a 2D tilemap world from a map string.
@@ -273,10 +275,12 @@
273
275
 
274
276
  - `FrameModule` (interface): interface FrameModule — Frame subsystem exposing the frame-timing, profiling, and render-sample facades.
275
277
  - `createFrameModule` (const): const createFrameModule: (deps: { readProbes: () => Record<string, unknown>; }) => FrameModule — Create the frame subsystem that records frame/sim/phase timings, computes stats, and captures long-frame events.
278
+ - `percentile` (function): function percentile(sorted: readonly number[], fraction: number): number — Value at `fraction` (0-1) of an ascending-sorted list; 0 when empty.
276
279
 
277
280
  ## @jgengine/core/devtools/frameBreakdown
278
281
 
279
282
  - `DrawCost` (interface): interface DrawCost — One object or material's share of the draws: totals while gathering, per-frame averages in a summary.
283
+ - `FrameBreakdown` (interface): interface FrameBreakdown — A running breakdown, as `installFrameBreakdown` returns it and `window.__jgFrameBreakdown` holds it.
280
284
  - `FrameBreakdownRecord` (interface): interface FrameBreakdownRecord — One frame, as the hooks saw it. GPU times arrive a few frames late; `gpu` is null until they do.
281
285
  - `FrameBreakdownSummary` (interface): interface FrameBreakdownSummary — A window of frames, summarized for a person or a diff.
282
286
  - `HITCH_MS` (const): const HITCH_MS: 33 — Where each frame goes: the record of one frame (CPU per system, GPU per render pass, draws, shader compiles, uploads, heap) and the summary of a window of them (percentiles, the costliest systems, passes, objects and materials, and every hitch with what caused it). This file is the arithmetic; `frameBreakdown.draw.ts` fills the records from a live renderer.
@@ -286,9 +290,6 @@
286
290
 
287
291
  ## @jgengine/core/devtools/frameBreakdown.draw
288
292
 
289
- - `BreakdownRenderer` (interface): interface BreakdownRenderer — What the breakdown needs from a three.js WebGLRenderer.
290
- - `BreakdownStore` (interface): interface BreakdownStore — What it needs from the r3f store: the subscriber list and the subscribe call.
291
- - `FrameBreakdown` (interface): interface FrameBreakdown — A running breakdown.
292
293
  - `measureComposerPasses` (function): function measureComposerPasses(composer: { passes: readonly object[] }): void — Time each post pass of a composer by name, CPU and GPU. Cheap when no breakdown is installed; call it each frame before `composer.render` so passes added later are timed too.
293
294
 
294
295
  ## @jgengine/core/devtools/frameSampler.view
@@ -333,6 +334,12 @@
333
334
 
334
335
  - `diagnose` (function): function diagnose(frame: NonNullable<ReturnType<typeof devtools.frame.stats>>, longs: readonly LongFrameEvent[]): string | null — ⚠ undocumented
335
336
 
337
+ ## @jgengine/core/devtools/perfOverlay.draw
338
+
339
+ - `PERF_OVERLAY_FRAMES` (const): const PERF_OVERLAY_FRAMES: 120 — Frames the FPS graph keeps.
340
+ - `PerfOverlay` (function): function PerfOverlay({ sample }: { sample: PerfOverlaySample }): ReactElement — The F3 performance overlay every game gets: an FPS graph of the last frames, draws, triangles, scene nodes, linked programs and the costliest subsystems from the devtools frame breakdown. Pair it with {@link PerfOverlayProbe} inside the Canvas, sharing one sample.
341
+ - `PerfOverlaySample` (interface): interface PerfOverlaySample — What the overlay draws, filled in place by {@link PerfOverlayProbe} and read by {@link PerfOverlay}.
342
+
336
343
  ## @jgengine/core/devtools/report
337
344
 
338
345
  - `FrameWindow` (interface): interface FrameWindow — Frame timings over the measured window, as the player sees them.
@@ -438,7 +445,7 @@
438
445
 
439
446
  - `CHANGELOG` (const): const CHANGELOG: Record<string, ChangelogEntry> — Per-version engine changelog keyed by semver string (e.g. `"0.10.0"`).
440
447
  - `ChangelogEntry` (interface): interface ChangelogEntry — One release's migrate steps plus added/changed/removed notes (typed mirror of CHANGELOG.md).
441
- - `VERSION` (const): const VERSION: "0.49.1" — Installed `@jgengine/core` semver - compare against {@link CHANGELOG} keys when migrating.
448
+ - `VERSION` (const): const VERSION: "0.51.0" — Installed `@jgengine/core` semver - compare against {@link CHANGELOG} keys when migrating.
442
449
 
443
450
  ## @jgengine/core/runtime/adapter
444
451
 
@@ -478,7 +485,7 @@
478
485
  - `CameraDirector` (interface): interface CameraDirector — Runtime camera policy at `ctx.camera`: follow target, rig overlay, cinematic, chase tuning, FOV kicks and RTS pan jumps.
479
486
  - `CameraDirectorSnapshot` (type): type CameraDirectorSnapshot = CameraSerialized<CameraDirectorState> — JSON-safe camera policy; documented instant chase responses use an explicit Infinity marker.
480
487
  - `CameraDirectorState` (interface): interface CameraDirectorState — Camera policy state before the JSON-safe snapshot number encoding.
481
- - `CameraRigConfig` (type): type CameraRigConfig = Omit<GameCameraConfig, "rig" | "projection" | "pixelPerfect" | "frustum" | "playerFov" | "weapon" | "onCameraFollow"> — Data overlay for an existing rig; callbacks and Canvas projection/preferences remain configured by the game.
488
+ - `CameraRigConfig` (type): type CameraRigConfig = Omit<GameCameraConfig, "rig" | "lens" | "follow"> & { follow?: Omit<GameCameraFollowConfig, "weapon" | "onCameraFollow"> } — Data overlay for an existing rig; callbacks and Canvas projection/preferences remain configured by the game.
482
489
  - `CameraRigOverride` (interface): interface CameraRigOverride — Runtime rig selection and detached data overlay over the configured camera.
483
490
  - `ChaseCameraTuning` (type): type ChaseCameraTuning = Partial< Pick< ChaseCameraConfig, | "distance" | "height" | "lookHeight" | "springDamping" | "fov" | "lead" | "bank" | "shakePerSpeed" | "velocityYaw" | "yawResponse" | "headingSource" | "distanceBySpeed" | "pitchFollow" | "fovKick" | "lookBackAction" | "collision" | "view" … — Runtime patch over the static `camera.chase` config — distance/height/fov retuning from gameplay events (#286.11), a whole driving-feel overlay applied only while a vehicle is piloted (#1299), or a `view` switch between chase and seat cameras.
484
491
  - `nextChaseView` (function): function nextChaseView(current: ChaseView, views: readonly ChaseView[] = CHASE_VIEWS): ChaseView — The view after `current` in `views`, wrapping at the end; a view missing from the list starts the cycle over. Pair with `setChaseTuning` to bind a "change camera" key: `ctx.camera.setChaseTuning({ ...ctx.camera.chaseTuning(), view: nextChaseView(view) })`.
@@ -499,7 +506,7 @@
499
506
  - `GameContext` (interface): interface GameContext — The live engine handle a game's loop, systems, commands, and UI read and mutate — entities, objects, the reactive store, opted-in `game.*` subsystems, world queries, and the sim clock. One context = one running world.
500
507
  - `GameContextCards` (interface): interface GameContextCards { pile(id: string, config?: CardPileConfig): CardPile } — ⚠ undocumented
501
508
  - `GameContextCommands` (interface): interface GameContextCommands { define<TInput>(name: string, definition: CommandDefinition<GameContext, TInput>): void; has(name: string): boolean; names(): string[]; run(name: string, input: unknown): CommandResult<GameContext>; runAs(actorUserId: string, name: string,… — ⚠ undocumented
502
- - `GameContextContent` (interface): interface GameContextContent { itemById?(itemId: string): GameContextItemEntry | null | undefined; entityById?(catalogId: string): GameContextEntityEntry | null | undefined; objectById?(catalogId: string): GameContextObjectEntry | null | undefined } — ⚠ undocumented
509
+ - `GameContextContent` (interface): interface GameContextContent { defaultRarity?: string; itemById?(itemId: string): GameContextItemEntry | null | undefined; entityById?(catalogId: string): GameContextEntityEntry | null | undefined; objectById?(catalogId: string): GameContextObjectEntry | null | undefin… — ⚠ undocumented
503
510
  - `GameContextEconomy` (interface): interface GameContextEconomy { balance(userId: string, currencyId: string | CurrencyDefinition): number; grant(userId: string, currencyId: string | CurrencyDefinition, amount: number): void; charge(userId: string, currencyId: string | CurrencyDefinition, amount: number… — ⚠ undocumented
504
511
  - `GameContextEntityEntry` (interface): interface GameContextEntityEntry { stats?: StatCatalog; receive?: ReceiveMap; onDeath?: OnDeathSpec; movement?: PoseAllowedStates & {walkSpeed?: number}; role?: CatalogEntityRole; verbs?: readonly ContextVerb[]; colliders?: EntityColliderSet; scale?: number } — ⚠ undocumented · used by `entityEntryFromCatalog` (@jgengine/core/editor): Turns an authored entity row into the runtime {@link GameContextEntityEntry} a spawn consumes: looks up `entityId` in the document's {@link …
505
512
  - `GameContextFeed` (interface): interface GameContextFeed extends Omit<GameFeed, "bind"> { bind(action: keyof GameEventMap): () => void } — ⚠ undocumented
@@ -530,7 +537,7 @@
530
537
  - `GameContext` (interface): interface GameContext — The live engine handle a game's loop, systems, commands, and UI read and mutate — entities, objects, the reactive store, opted-in `game.*` subsystems, world queries, and the sim clock. One context = one running world.
531
538
  - `GameContextCards` (interface): interface GameContextCards { pile(id: string, config?: CardPileConfig): CardPile } — ⚠ undocumented
532
539
  - `GameContextCommands` (interface): interface GameContextCommands { define<TInput>(name: string, definition: CommandDefinition<GameContext, TInput>): void; has(name: string): boolean; names(): string[]; run(name: string, input: unknown): CommandResult<GameContext>; runAs(actorUserId: string, name: string,… — ⚠ undocumented
533
- - `GameContextContent` (interface): interface GameContextContent { itemById?(itemId: string): GameContextItemEntry | null | undefined; entityById?(catalogId: string): GameContextEntityEntry | null | undefined; objectById?(catalogId: string): GameContextObjectEntry | null | undefined } — ⚠ undocumented
540
+ - `GameContextContent` (interface): interface GameContextContent { defaultRarity?: string; itemById?(itemId: string): GameContextItemEntry | null | undefined; entityById?(catalogId: string): GameContextEntityEntry | null | undefined; objectById?(catalogId: string): GameContextObjectEntry | null | undefin… — ⚠ undocumented
534
541
  - `GameContextEconomy` (interface): interface GameContextEconomy { balance(userId: string, currencyId: string | CurrencyDefinition): number; grant(userId: string, currencyId: string | CurrencyDefinition, amount: number): void; charge(userId: string, currencyId: string | CurrencyDefinition, amount: number… — ⚠ undocumented
535
542
  - `GameContextEntityEntry` (interface): interface GameContextEntityEntry { stats?: StatCatalog; receive?: ReceiveMap; onDeath?: OnDeathSpec; movement?: PoseAllowedStates & {walkSpeed?: number}; role?: CatalogEntityRole; verbs?: readonly ContextVerb[]; colliders?: EntityColliderSet; scale?: number } — ⚠ undocumented · used by `entityEntryFromCatalog` (@jgengine/core/editor): Turns an authored entity row into the runtime {@link GameContextEntityEntry} a spawn consumes: looks up `entityId` in the document's {@link …
536
543
  - `GameContextFeed` (interface): interface GameContextFeed extends Omit<GameFeed, "bind"> { bind(action: keyof GameEventMap): () => void } — ⚠ undocumented
@@ -576,7 +583,7 @@
576
583
  ## @jgengine/core/runtime/hostPersistence
577
584
 
578
585
  - `FEED_RING_LIMIT` (const): const FEED_RING_LIMIT: 20 — ⚠ undocumented
579
- - `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
586
+ - `GameServerRecord` (type): type GameServerRecord = { serverId: string; gameId: string; status: GameServerStatus; mode?: string | undefined; modeConfig?: unknown; label?: string; visibility?: SessionVisibility | undefined; joinCode?: string | undefined; tags?: string[]; memberUserIds: string[]; slotsPerServer: number; save: Sa… — ⚠ undocumented
580
587
  - `GameServerStatus` (type): type GameServerStatus = "open" | "running" | "closed" — ⚠ undocumented · used by `statusAfterLeave` (@jgengine/core/runtime/hostPolicy): Status after a leave: empty rooms reopen; non-empty rooms keep their current status.
581
588
  - `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 · used by `memoryPersistence` (@jgengine/node): Creates an in-memory `HostPersistence` implementation, useful for tests and ephemeral hosts.
582
589
  - `LEADERBOARD_PENDING_KEY` (const): const LEADERBOARD_PENDING_KEY: "leaderboardPending" — ⚠ undocumented
@@ -596,9 +603,12 @@
596
603
 
597
604
  ## @jgengine/core/runtime/hostPolicy
598
605
 
606
+ - `DEFAULT_HOST_SAVE_INTERVAL_MS` (const): const DEFAULT_HOST_SAVE_INTERVAL_MS: 1000 — Milliseconds between auto-saves of a hosted world that changed; 0 saves after every changed tick.
607
+ - `DEFAULT_HOST_TICK_MS` (const): const DEFAULT_HOST_TICK_MS: 50 — Authoritative host tick interval every host uses unless the game sets one: 20 Hz.
599
608
  - `JG_MAX_MEMBERS_PER_SERVER` (const): const JG_MAX_MEMBERS_PER_SERVER: 256 — Room-topology ceiling on `slotsPerServer`; shared membership uses indexed rows instead.
600
609
  - `JoinCandidate` (type): type JoinCandidate = { memberUserIds: readonly string[]; slotsPerServer: number; visibility?: SessionVisibility | undefined; createdAt: number; } — A row `selectJoinTarget` can choose between — the matchmaking-relevant fields of a server record.
601
610
  - `JoinTarget` (type): type JoinTarget<T extends JoinCandidate> = | { kind: "join"; row: T } | { kind: "create" } | { kind: "refuse"; reason: string } — What a join should do with the candidate rows it found.
611
+ - `MAX_HOST_TICK_MS` (const): const MAX_HOST_TICK_MS: 1000 — Longest tick interval a host accepts; 1 Hz is the floor for a world that still feels live.
602
612
  - `MAX_SESSION_ID_LENGTH` (const): const MAX_SESSION_ID_LENGTH: 128 — Longest accepted client join/leave `sessionId`, in UTF-16 code units.
603
613
  - `MatchmakingMode` (type): type MatchmakingMode = "auto" | "singleton" — How auto-match behaves when no `serverId` is supplied.
604
614
  - `canJoinPrivateServer` (function): function canJoinPrivateServer(args: { isMember: boolean; joinCode: string | undefined; suppliedCode: string | undefined; }): boolean — Private-server join-code gate. Existing members always pass; non-members must present a matching `joinCode` (loose-normalized via {@link normalizeJoinCode}). Callers still decide whether the server is private — this only answers the code/membership half.
@@ -607,6 +617,7 @@
607
617
  - `isPrivateJoinBlocked` (function): function isPrivateJoinBlocked(args: { visibility: SessionVisibility | undefined; memberUserIds: readonly string[]; userId: string; joinCode: string | undefined; suppliedCode: string | undefined; }): boolean — Whether a private-visibility server blocks this join (non-member without a matching code). Public / undefined visibility never blocks.
608
618
  - `isServerFull` (function): function isServerFull(memberCount: number, slotsPerServer: number, isMember: boolean): boolean — True when the server has no free slots for a non-member. Existing members never count as "full" so rejoin/leave cycles keep working.
609
619
  - `isServerMember` (function): function isServerMember(memberUserIds: readonly string[], userId: string): boolean — Whether `userId` is already on the server's member roster.
620
+ - `resolveHostTickMs` (function): function resolveHostTickMs(tickMs: number | undefined): number — Validate a host tick interval in milliseconds (greater than zero, at most {@link MAX_HOST_TICK_MS}); `undefined` yields {@link DEFAULT_HOST_TICK_MS}.
610
621
  - `selectJoinTarget` (function): function selectJoinTarget<T extends JoinCandidate>(rows: readonly T[], args: { userId: string; mode?: MatchmakingMode; /** Capacity to judge rows against — the host's current option, when it supersedes the stored value. */ slotsPerServer?: number; }): JoinTarget<T> — Resolve an auto-match join against the game's joinable rows under a {@link MatchmakingMode}. Reach for it instead of hand-rolling the "find a room with space, else make one" scan, which is where a singleton world silently shards into per-player copies.
611
622
  - `statusAfterLeave` (function): function statusAfterLeave(remainingMemberCount: number, currentStatus: GameServerStatus): GameServerStatus — Status after a leave: empty rooms reopen; non-empty rooms keep their current status.
612
623
  - `validateSlotsPerServer` (function): function validateSlotsPerServer(slotsPerServer: number, topology: "rooms" | "shared" = "rooms"): { ok: true } | { ok: false; reason: string } — Whether a `slotsPerServer` value is a capacity a single hosted server row can actually hold.
@@ -709,11 +720,12 @@
709
720
 
710
721
  ## @jgengine/core/runtime/simLoop
711
722
 
723
+ - `DEFAULT_SIM_HZ` (const): const DEFAULT_SIM_HZ: 60 — Steps per second a loop runs at when `hz` is not set: the physics backends' own substep rate, so one sim step is one solver step.
712
724
  - `SimAdvanceResult` (interface): interface SimAdvanceResult — What one {@link SimLoop.advance} did.
713
725
  - `SimLoop` (interface): interface SimLoop — The stepper handle: advance with real time, read the tick and interpolation alpha, retune the rate, snapshot and restore.
714
726
  - `SimLoopState` (interface): interface SimLoopState — Serializable loop position: the tick count and the real seconds accumulated toward the next fixed step.
715
727
  - `SimulationConfig` (interface): interface SimulationConfig — How the simulation is stepped: a fixed rate with a catch-up cap, or once per frame with the frame's dt.
716
- - `createSimLoop` (function): function createSimLoop(initial?: SimulationConfig): SimLoop — The simulation stepper every driver (shell frame, headless runner, authoritative host) advances through, so the sim sees the same dt sequence regardless of who drives it. Fixed mode accumulates real time and steps in equal slices with a catch-up cap; variable mode steps once per advance.
728
+ - `createSimLoop` (function): function createSimLoop(initial?: SimulationConfig): SimLoop — The simulation stepper every driver (shell frame, headless runner, authoritative host) advances through, so the sim sees the same dt sequence regardless of who drives it. Fixed mode accumulates real time and steps in equal slices with a catch-up cap (60 Hz unless the game picks another rate); variable mode steps once per advance.
717
729
 
718
730
  ## @jgengine/core/runtime/simSnapshot
719
731
 
@@ -750,7 +762,7 @@
750
762
  - `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
751
763
  - `GameRuntimePlayerView` (type): type GameRuntimePlayerView = { userId: string; gameId: string; playerState: unknown; updatedAt: number; } — ⚠ undocumented
752
764
  - `GameRuntimeServerView` (type): type GameRuntimeServerView = { serverId: string; gameId: string; revision: number; memberUserIds: string[]; serverState: unknown | WorldSyncFrame; updatedAt: number; } — ⚠ undocumented
753
- - `GameRuntimeTransport` (type): type GameRuntimeTransport = { /** * Join a server. `sessionId` names this client session (one tab, one mounted view) so the host keeps * the user a member while any of their sessions is still live. */ joinServer: (args: { gameId: string; serverId?: string; role?: MultiplayerRole; sessionId?: string … — ⚠ undocumented · used by `useServerSession` (@jgengine/core/session/useServerSession.view): Joins a host and exposes a retryable blocking state until membership is confirmed.
765
+ - `GameRuntimeTransport` (type): type GameRuntimeTransport = { /** * Join a server. `sessionId` names this client session (one tab, one mounted view) so the host keeps * the user a member while any of their sessions is still live. */ joinServer: (args: { gameId: string; serverId?: string | undefined; role?: MultiplayerRole; session… — ⚠ undocumented · used by `useServerSession` (@jgengine/core/session/useServerSession.view): Joins a host and exposes a retryable blocking state until membership is confirmed.
754
766
  - `JoinServerOutcome` (type): type JoinServerOutcome = | (JoinServerResult & { ok: true }) | { ok: false; reason: "full" | "closed" | "unauthorized" } — Join failures are returned to the caller so the triggering surface can offer retry.
755
767
  - `JoinServerResult` (type): type JoinServerResult = { serverId: string; isNew: boolean; resumeTicket?: ResumeTicket; } — ⚠ undocumented
756
768
  - `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
@@ -793,9 +805,12 @@
793
805
 
794
806
  ## @jgengine/core/runtime/worldReplication
795
807
 
808
+ - `ReplicatorView` (interface): interface ReplicatorView — Narrows {@link WorldReplicator.diff} to one viewer's interest.
796
809
  - `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}.
797
810
  - `WorldReplicator` (type): type WorldReplicator = ReturnType<typeof createWorldReplicator> — The stateful diff tracker returned by {@link createWorldReplicator}: `commit()`, `diff(sinceRevision)`, `revision()`.
798
811
  - `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.
812
+ - `WorldViewState` (interface): interface WorldViewState — What one viewer has been sent, held by whoever serves that viewer (one per connection and world). `sent` is the entity ids the viewer's mirror holds; `null` means no baseline has been served yet. `all` marks a viewer that holds every entity (no interest radius applied to it), so narrowing later knows what to drop.
813
+ - `createWorldViewState` (function): function createWorldViewState(): WorldViewState — A fresh {@link WorldViewState}: the next pull is a baseline.
799
814
 
800
815
  ## @jgengine/core/runtime/worldSnapshot
801
816
 
@@ -833,8 +848,8 @@
833
848
  - `HudCanvas` (function): function HudCanvas({ layout, editChord, showDuring, className, style, children, }: { layout: HudLayoutStore; editChord?: HudEditChord | false; /** Opt-in play-phase gate: render the HUD only during these phases (e.g. `["playing"]`). Omit for always-visible (default). */ showDuring?: readonly GamePha… — Full-viewport HUD surface. Each `HudPanel` names an anchor and a priority; the canvas measures every panel and places them all at once so none lands on another, at any screen size. Panels sharing an anchor stack outward from that edge; a panel that would cover a neighbour slides along its edge to the nearest free spot; when the screen is too small, the lowest-priority panels fold into a toggle, and only then does the whole HUD shrink. Device safe areas and every touch control (any region registered as kind `control` or `system`) are kept clear. Games declare panels, never place them per size.
834
849
  - `HudFade` (function): function HudFade({ watch, idleMs = 3500, dimTo = 0.18, hold = false, children, className, style }: HudFadeProps): ReactNode — A HUD group that steps back when nothing is happening: it fades after a quiet spell and comes back the moment a watched value changes, so the world fills the screen and the HUD speaks only when it has news. Hovering it also brings it back.
835
850
  - `HudPanel` (function): function HudPanel({ id, anchor = "top-left", order, chip, interactive, inset, locked, showDuring, priority, mobileBehavior, allowOverlapWith, collisionGroup, region = true, width, height, type, className, style, children, }: { id: string; anchor?: HudAnchor; /** Stack position within the anchor, asc… — A HUD block anchored to a corner, edge or the centre. `HudCanvas` places every panel together: panels sharing an anchor stack outward from the screen edge in ascending `order`, and a panel that would cover another slides to the nearest free spot. When the screen is too small, lower-`priority` panels fold into a toggle first. On fine pointers panels stay draggable through the edit chord; a dragged panel leaves the flow and keeps its custom placement.
836
- - `HudSlots` (function): function HudSlots({ storageKey, slots, overlay, showDuring = DEFAULT_SLOT_PHASES }: HudSlotsProps): ReactNode — The play HUD in one line: a few small panels pinned to the screen's edges, scaled from a 1600x900 design to any window and movable by the player (the layout is remembered per `storageKey`). Keep it to a handful of slots; the world is the picture.
837
- - `PlayableGame` (type): type PlayableGame<TProbe extends ProbeReadings = ProbeReadings> = PlayableGameContract< ComponentType, ComponentType, RenderEntity, RenderObject, ComponentType<ViewmodelProps>, ComponentType<WorldOverlayProps>, TProbe > & { /** HUD theme the shell applies at the `GameUI` root. Unset uses `defaultHud… — The concrete React-bound playable a shell `defineGame` returns and `GameHost` mounts — the one PlayableGame games handle. `TProbe` is what the game's `capture.probe` returns, so a proof flow over `typeof game` names only real probes.
851
+ - `HudSlots` (function): function HudSlots({ storageKey, slots = {}, panels = {}, overlay, showDuring = DEFAULT_SLOT_PHASES, className }: HudSlotsProps): ReactNode — The play HUD in one line: a few small panels pinned to the screen's edges, scaled from a 1600x900 design to any window and movable by the player (the layout is remembered per `storageKey`). Keep it to a handful of slots; the world is the picture.
852
+ - `PlayableGame` (type): type PlayableGame<TProbe extends ProbeReadings = ProbeReadings> = PlayableGameContract< ComponentType, ComponentType, RenderEntity, RenderObject, ComponentType<ViewmodelProps>, ComponentType<WorldOverlayProps>, TProbe, ComponentType<RemotePlayersProps> > & { /** HUD theme the shell applies at the `G… — The concrete React-bound playable a shell `defineGame` returns and `GameHost` mounts — the one PlayableGame games handle. `TProbe` is what the game's `capture.probe` returns, so a proof flow over `typeof game` names only real probes.
838
853
  - `StoreHandle` (interface): interface StoreHandle<T> — A typed, cast-free handle onto one slot of the reactive game store (`ctx.game.store`). The single type parameter is fixed at definition; `read`/`write`/`update` never widen to `unknown`, so no call site repeats `store.get(key) as T`. Writes flow through the engine store, so they bump `ctx.version()`, serialize into a {@link WorldSnapshot}, and replay under host authority — the same guarantees a hand-rolled `store.get`/`store.set` pair gives up the moment it forks run state into a module-level singleton.
839
854
  - `SystemDefinition` (interface): interface SystemDefinition — A reusable game capability — lifecycle, timing, events, and optional save / replication / reset / disposal. Pass instances via `defineGame({ systems })`. Prefer one system per meaningful capability (`combat`, `quests`), not per micro-tick.
840
855
  - `authoredSpawnPosition` (function): function authoredSpawnPosition(document: AuthoredSpawnDocumentLike, options: AuthoredSpawnOptions = {}): [number, number, number] | null — Position of the authored spawn marker as a spawn-ready `[x, y, z]` tuple, or null when the document has none. Reads the first `player_spawn` marker by default, so dragging the marker in the editor moves where players spawn — no coordinates copied into game code.
@@ -168,6 +168,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
168
168
 
169
169
  - `SceneObjectSlots` (interface) · `import { SceneObjectSlots } from "@jgengine/core/runtime/context/objectSlots"`
170
170
 
171
+ ## perf-overlay — F3 in-game performance overlay — FPS graph, draws, nodes, programs and the costliest subsystems
172
+
173
+ - `PerfOverlay` (function) · `import { PerfOverlay } from "@jgengine/core/devtools/perfOverlay.draw"`
174
+
171
175
  ## placed-object-rehydrate — rebuild live placed objects, with their state and slot contents, from persisted snapshot rows
172
176
 
173
177
  - `fromRuntimeObjectRow` (function) · `import { fromRuntimeObjectRow } from "@jgengine/core/runtime/objectRows"`
@@ -214,6 +218,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
214
218
 
215
219
  - `createSimSnapshotRegistry` (function) · `import { createSimSnapshotRegistry } from "@jgengine/core/runtime/simSnapshot"`
216
220
 
221
+ ## spawn-point-select — select a spawn location by its distance preference from avoided positions
222
+
223
+ - `selectSpawnPoint` (function) · `import { selectSpawnPoint } from "@jgengine/core/authoring"`
224
+
217
225
  ## tune-control-labels — find a Tune panel field by its control name (drive --fill, screen readers)
218
226
 
219
227
  - `tuneControlLabels` (function) · `import { tuneControlLabels } from "@jgengine/core/devtools/TunePanel.view"`