@jgengine/react 0.18.0 → 0.18.1

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.
@@ -12,10 +12,18 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
12
12
 
13
13
  - `collectAuthoredTriggers` (function) · `import { collectAuthoredTriggers } from "@jgengine/shell/gameKit"`
14
14
 
15
+ ## client-side — input prediction with replay reconciliation
16
+
17
+ - `createPredictionBuffer` (function) · `import { createPredictionBuffer } from "@jgengine/core/runtime/prediction"`
18
+
15
19
  ## collider-autofit — hitboxes and physical bodies fit each kind's rendered model bounds automatically — no hand-tuned sizes
16
20
 
17
21
  - `GameContextModels` (interface) · `import { GameContextModels } from "@jgengine/core/runtime/gameContext"`
18
22
 
23
+ ## command-quantity — validate bounded whole-item counts at command boundaries
24
+
25
+ - `readQuantity` (function) · `import { readQuantity } from "@jgengine/core/runtime/commandInput"`
26
+
19
27
  ## default-walk-codes — stock WASD + jump key codes for the shell walk controller
20
28
 
21
29
  - `DEFAULT_WALK_CODES` (const) · `import { DEFAULT_WALK_CODES } from "@jgengine/shell/gameKit"`
@@ -84,6 +92,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
84
92
 
85
93
  - `StatBar` (function) · `import { StatBar } from "@jgengine/shell/gameKit"`
86
94
 
95
+ ## input-recorder — tick-indexed input log for replay, rollback, and regression tests
96
+
97
+ - `createInputRecorder` (function) · `import { createInputRecorder } from "@jgengine/core/runtime/inputRecorder"`
98
+
87
99
  ## loot-table — validate a loot table definition for use with the registry
88
100
 
89
101
  - `lootTable` (function) · `import { lootTable } from "@jgengine/core/authoring"`
@@ -116,6 +128,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
116
128
 
117
129
  - `toRuntimeObjectRow` (function) · `import { toRuntimeObjectRow } from "@jgengine/core/runtime/objectRows"`
118
130
 
131
+ ## pose-interpolation — render entity poses between fixed simulation steps without stutter
132
+
133
+ - `createPoseHistory` (function) · `import { createPoseHistory } from "@jgengine/core/runtime/poseInterpolation"`
134
+
119
135
  ## render-fallback-diagnostics — Enable/disable the dev-only placeholder-fallback probe.
120
136
 
121
137
  - `armFallbackSeams` (function) · `import { armFallbackSeams } from "@jgengine/core/devtools/fallbackSeams"`
@@ -126,6 +142,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
126
142
  - `resetTextureErrors` (function) · `import { resetTextureErrors } from "@jgengine/core/devtools/textureErrors"`
127
143
  - `textureErrorsSnapshot` (function) · `import { textureErrorsSnapshot } from "@jgengine/core/devtools/textureErrors"`
128
144
 
145
+ ## runtime — snapshot interpolation
146
+
147
+ - `createSnapshotBuffer` (function) · `import { createSnapshotBuffer } from "@jgengine/core/runtime/snapshotBuffer"`
148
+
129
149
  ## runtime-save — save/load the whole game world through a pluggable backend, autosave or save points
130
150
 
131
151
  - `createRuntimeSave` (function) · `import { createRuntimeSave } from "@jgengine/core/runtime/runtimeSave"`
@@ -142,6 +162,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
142
162
 
143
163
  - `seededRng` (function) · `import { seededRng } from "@jgengine/shell/gameKit"`
144
164
 
165
+ ## sim-loop — fixed-step or variable simulation stepping with tick count, catch-up cap, and interpolation alpha
166
+
167
+ - `createSimLoop` (function) · `import { createSimLoop } from "@jgengine/core/runtime/simLoop"`
168
+
169
+ ## sim-snapshot — capture and restore whole-simulation state for replay, rollback, and regression tests
170
+
171
+ - `createSimSnapshotRegistry` (function) · `import { createSimSnapshotRegistry } from "@jgengine/core/runtime/simSnapshot"`
172
+
145
173
  ## typed-keyed-store — a cast-free typed handle onto a per-owner keyed family of reactive game-store slots, replayable and host-authoritative
146
174
 
147
175
  - `defineKeyedStore` (function) · `import { defineKeyedStore } from "@jgengine/shell/gameKit"`
@@ -39,6 +39,14 @@ Existing React games keep their entity store and use the focused
39
39
  - Layout and skin remain caller-controlled; shared primitives own reusable behavior, not product look.
40
40
  - SSR-visible output is hydration-stable; round computed SVG values at the boundary.
41
41
 
42
+ ## Shared-world interaction rules
43
+
44
+ - Every rejected verb displays its reason on the triggering surface. Use `useServerSession(transport, gameId)` for join lifecycle. Join failure blocks play with `JoinGate` and retry; returning `{ ok: false }` without feedback is incomplete.
45
+ - The first tutorial verb works within 60 seconds from spawn with starting inventory. Land, power, and slots are granted or purchasable in-context; tutorial locks must not hide prerequisites.
46
+ - Placement previews display claim cost and affordability inline with `TerritoryOverlay`.
47
+ - `ChatPanel` owns collapsed/expanded state, own-message styling, Enter focus and Escape blur; standalone hosts pass `messages`, `userId`, and `onSend` (typed `{ ok, reason }`), while context-backed games use channel props. Use native inputs so shell typing-target suspension applies.
48
+ - Register Tailwind `@source` for consumed package files and inspect `bun run shoot <gameId> --mode ui` captures of join, chat, and placement feedback.
49
+
42
50
  ## Traps
43
51
 
44
52
  - Do not put environment beautification, authored-scene rendering, or world placement here.
@@ -33,14 +33,21 @@
33
33
  - `createI18n` (function): function createI18n(options: I18nOptions): I18n — Create a translator over a message catalog: active-locale lookup with a fallback-locale chain, `{param}` interpolation, and `Intl.PluralRules`-based pluralization. Observable (`subscribe`) so React re-renders on `setLocale`; the catalog is caller-owned static data, the locale is the only state.
34
34
  - `interpolate` (function): function interpolate(template: string, params?: TParams): string — Replace `{name}` placeholders in `template` with `params[name]`. Unknown placeholders are left intact. Pure and locale-independent.
35
35
 
36
+ ## @jgengine/core/render/environment
37
+
38
+ - `EnvironmentSource` (type): type EnvironmentSource = | { kind: "gradient"; sky: string; ground: string; sun?: string; intensity?: number } /** Equirectangular HDR or EXR environment map loaded from `url`. */ | { kind: "hdri"; url: string; rotation?: number; intensity?: number } /** Six faces of a cube environment map, in three… — A declarative source for image-based scene lighting.
39
+
36
40
  ## @jgengine/core/render/lookPreset
37
41
 
38
42
  - `CINEMATIC_POST_PROCESSING` (const): const CINEMATIC_POST_PROCESSING: PostProcessingConfig — Tuned tone-map + bloom + gentle SSAO + vignette/grade stack — the shipped-game post look.
39
43
  - `CINEMATIC_SKY` (const): const CINEMATIC_SKY: SkyEnvironmentConfig — A static day sky: a real dome plus the shell's view-following shadow-casting sun and hemisphere fill.
40
44
  - `GameLookInput` (interface): interface GameLookInput — Explicit graphics knobs a game may set; the preset only fills the ones left undefined.
41
- - `LookPreset` (type): type LookPreset = "cinematic" | "flat" — Named default-look preset composing the existing lighting/sky/fog/post knobs into one field. `"cinematic"` (the default when unset) draws a scene lit like a shipped game — a real day sky with a view-following shadow-casting sun + hemisphere fill, a network-free image-based-lighting environment so PBR surfaces catch soft reflections, and a tuned tone-map/bloom/AO/vignette post stack. `"flat"` opts out of the sky/IBL/post rig to the bare ambient+directional default (pre-#773). The upgraded default primitive materials — tuned roughness/metalness plus subtle procedural surface detail so un-modeled boxes/capsules stop reading as flat plastic — apply under both presets.
45
+ - `LookPreset` (type): type LookPreset = "neutral" | "photoreal" | "toon" | "cinematic" | "flat" — Named look preset composing the existing lighting/sky/fog/post knobs into one field. `"neutral"` (the default when unset) keeps presentation unstyled; `"cinematic"` draws a scene lit like a shipped game — a real day sky with a view-following shadow-casting sun + hemisphere fill, a network-free image-based-lighting environment so PBR surfaces catch soft reflections, and a tuned tone-map/bloom/AO/vignette post stack. `"flat"` opts out of the sky/IBL/post rig to the bare ambient+directional default (pre-#773). The upgraded default primitive materials — tuned roughness/metalness plus subtle procedural surface detail so un-modeled boxes/capsules stop reading as flat plastic — apply under both presets.
46
+ - `NEUTRAL_POST_PROCESSING` (const): const NEUTRAL_POST_PROCESSING: PostProcessingConfig — Unstyled baseline: a stable linear presentation with no genre-specific grading.
47
+ - `PHOTOREAL_POST_PROCESSING` (const): const PHOTOREAL_POST_PROCESSING: PostProcessingConfig — High-contrast physically based presentation for authored HDR environments.
42
48
  - `ResolvedGameLook` (interface): interface ResolvedGameLook — Concrete lighting/backdrop/post the shell renders after the preset has filled unset knobs.
43
- - `resolveGameLook` (function): function resolveGameLook(input: GameLookInput): ResolvedGameLook — Expand a game's `look` into concrete lighting/backdrop/post. The default is `"cinematic"`, so a scene reads lit-like-a-game out of the box; `"flat"` passes the explicit knobs through untouched. Anything the game authored wins — the preset only fills unset knobs, and it never adds a sky when the world already owns one (so the sky's tuned sun/hemisphere serve as the lighting rig).
49
+ - `TOON_POST_PROCESSING` (const): const TOON_POST_PROCESSING: PostProcessingConfig — Clean graphic presentation; toon materials remain game-owned while this sets the grade.
50
+ - `resolveGameLook` (function): function resolveGameLook(input: GameLookInput): ResolvedGameLook — Expand a game's `look` into concrete lighting/backdrop/post. The default is `"neutral"`; `"flat"` passes the explicit knobs through untouched. Anything the game authored wins — the preset only fills unset knobs, and it never adds a sky when the world already owns one (so the sky's tuned sun/hemisphere serve as the lighting rig).
44
51
 
45
52
  ## @jgengine/core/render/postProcessing
46
53
 
@@ -53,6 +60,19 @@
53
60
  - `STUDIO_STAGE_POST` (const): const STUDIO_STAGE_POST: PostProcessingConfig — A cinematic "product shot" post preset — the full chain on (contact-AO, soft bloom, a warm film grade with vignette + a touch of grain + chromatic aberration). Meant for a `StudioStage` where a single parametric asset is framed on a backdrop, so every studio reads shipped, not intern-tier. DoF is left off by default (it needs a per-scene focus distance); set `dof` to enable it.
54
61
  - `ToneMappingMode` (type): type ToneMappingMode = "aces" | "agx" | "reinhard" | "cineon" | "linear" | "none" — Renderer tone-mapping curve applied by the post chain's output stage.
55
62
 
63
+ ## @jgengine/core/render/sprite2d
64
+
65
+ - `SortingLayers` (const): const SortingLayers: readonly ["background", "world", "actors", "effects", "foreground", "ui"] — Canonical layers used by 2D presentations.
66
+ - `SpriteClipState` (interface): interface SpriteClipState — Serializable playback position for a named sprite animation.
67
+ - `createSpriteClipPlayer` (function): function createSpriteClipPlayer(atlas: SpriteAtlas): { play(name: string): void; advance(dt: number): void; frame: () => { x: number; y: number; w: number; h: number; pivot?: [number, number] | undefined; } | undefined; snapshot: () => { animation: string; frameIndex: number; elapsed: number; done: … — Create a renderer-independent sprite animation player.
68
+ - `sortingOrder` (function): function sortingOrder(layers: readonly string[], layer: string, offset = 0): number — Resolve a layer name and local offset into a stable render order.
69
+
70
+ ## @jgengine/core/settings/graphicsProfile
71
+
72
+ - `DEFAULT_GRAPHICS_PROFILES` (const): const DEFAULT_GRAPHICS_PROFILES: Record<GraphicsQuality, GraphicsProfile> — Conservative defaults that preserve the existing high-quality shell behavior.
73
+ - `GraphicsProfile` (interface): interface GraphicsProfile — Serializable renderer budget selected by the player's graphics tier.
74
+ - `resolveGraphicsProfile` (function): function resolveGraphicsProfile(quality: GraphicsQuality, overrides?: Partial<GraphicsProfile>): GraphicsProfile — Resolve one tier and apply game-authored field and post-stage overrides.
75
+
56
76
  ## @jgengine/core/settings/settingsModel
57
77
 
58
78
  - `BUILT_IN_SETTING_CATEGORIES` (const): const BUILT_IN_SETTING_CATEGORIES: readonly BuiltInSettingCategory[] — ⚠ undocumented
@@ -141,7 +161,7 @@
141
161
  - `LayoutRect` (interface): interface LayoutRect — Axis-aligned rectangle in CSS pixels (origin top-left). Structurally compatible with a `DOMRect`'s edge fields.
142
162
  - `LayoutRegion` (interface): interface LayoutRegion — A physical rectangle a UI subsystem occupies, published to the shared registry.
143
163
  - `Locale` (type): type Locale = string — A locale tag (e.g. `"en"`, `"es"`, `"ja"`) — a key into a {@link Catalog}.
144
- - `LookPreset` (type): type LookPreset = "cinematic" | "flat" — Named default-look preset composing the existing lighting/sky/fog/post knobs into one field. `"cinematic"` (the default when unset) draws a scene lit like a shipped game — a real day sky with a view-following shadow-casting sun + hemisphere fill, a network-free image-based-lighting environment so PBR surfaces catch soft reflections, and a tuned tone-map/bloom/AO/vignette post stack. `"flat"` opts out of the sky/IBL/post rig to the bare ambient+directional default (pre-#773). The upgraded default primitive materials — tuned roughness/metalness plus subtle procedural surface detail so un-modeled boxes/capsules stop reading as flat plastic — apply under both presets.
164
+ - `LookPreset` (type): type LookPreset = "neutral" | "photoreal" | "toon" | "cinematic" | "flat" — Named look preset composing the existing lighting/sky/fog/post knobs into one field. `"neutral"` (the default when unset) keeps presentation unstyled; `"cinematic"` draws a scene lit like a shipped game — a real day sky with a view-following shadow-casting sun + hemisphere fill, a network-free image-based-lighting environment so PBR surfaces catch soft reflections, and a tuned tone-map/bloom/AO/vignette post stack. `"flat"` opts out of the sky/IBL/post rig to the bare ambient+directional default (pre-#773). The upgraded default primitive materials — tuned roughness/metalness plus subtle procedural surface detail so un-modeled boxes/capsules stop reading as flat plastic — apply under both presets.
145
165
  - `MODAL_CANCEL` (const): const MODAL_CANCEL: "cancel" — Conventional cancel/dismiss result (also the default auto-dismiss and pop result).
146
166
  - `MODAL_CONFIRM` (const): const MODAL_CONFIRM: "confirm" — Conventional confirm result for a two-button dialog — a shared string, not model behavior.
147
167
  - `Messages` (type): type Messages = Readonly<Record<string, string>> — Flat message table for one locale: key → template string with `{param}` slots.
@@ -254,7 +274,7 @@
254
274
  - `resizePanelSize` (function): function resizePanelSize(current: HudSize, delta: { dw: number; dh: number }, axes: HudResizeAxes, limits?: { minWidth?: number; maxWidth?: number; minHeight?: number; maxHeight?: number; }): HudSize — Semantic resize: apply pixel deltas only on growable axes, clamped to min/max. Never scales content — callers reflow layout size (track length, list rows).
255
275
  - `resolveAction` (function): function resolveAction(def: ActionDef): ResolvedAction — Resolve one {@link ActionDef} into a {@link ResolvedAction}: normalize label, compute `enabled`, and order the blocking `reasons`. Pure — the same input always yields the same view model.
256
276
  - `resolveActionCollection` (function): function resolveActionCollection(defs: readonly ActionDef[]): ResolvedAction[] — Resolve an ordered list of actions, preserving input order.
257
- - `resolveGameLook` (function): function resolveGameLook(input: GameLookInput): ResolvedGameLook — Expand a game's `look` into concrete lighting/backdrop/post. The default is `"cinematic"`, so a scene reads lit-like-a-game out of the box; `"flat"` passes the explicit knobs through untouched. Anything the game authored wins — the preset only fills unset knobs, and it never adds a sky when the world already owns one (so the sky's tuned sun/hemisphere serve as the lighting rig).
277
+ - `resolveGameLook` (function): function resolveGameLook(input: GameLookInput): ResolvedGameLook — Expand a game's `look` into concrete lighting/backdrop/post. The default is `"neutral"`; `"flat"` passes the explicit knobs through untouched. Anything the game authored wins — the preset only fills unset knobs, and it never adds a sky when the world already owns one (so the sky's tuned sun/hemisphere serve as the lighting rig).
258
278
  - `resolveHudFit` (function): function resolveHudFit(config: HudViewportConfig | undefined, mobile: boolean): Required<HudFitConfig> — ⚠ undocumented
259
279
  - `resolveHudPanelLayout` (function): function resolveHudPanelLayout(docPanel: EditorUiPanelLayout | undefined, fallback: HudPanelFallback): ResolvedHudPanelLayout — Resolve a panel's layout: document entry wins field-by-field over TSX fallback. TSX props are fallback-only — the scene document is the source of truth once authored.
260
280
  - `resolveOrientationRequirement` (function): function resolveOrientationRequirement(orientation: GameOrientation | undefined, platform: "mobile" | "desktop"): OrientationRequirement — Resolve the game's orientation declaration into a concrete requirement for a platform. Desktop is always unconstrained.
@@ -520,8 +540,8 @@
520
540
  - `ChatBubble` (interface): interface ChatBubble — ⚠ undocumented
521
541
  - `ChatBubblesOptions` (interface): interface ChatBubblesOptions — ⚠ undocumented
522
542
  - `ChatInput` (function): function ChatInput({ channelId, className, inputClassName, buttonClassName, placeholder, sendLabel, onSent, onRejected, }: { channelId: string; className?: string; inputClassName?: string; buttonClassName?: string; placeholder?: string; sendLabel?: ReactNode; onSent?: (message: ChatMessage) => void;… — ⚠ undocumented
523
- - `ChatLog` (function): function ChatLog({ channelId, limit, className, messageClassName, renderMessage, }: { channelId: string; limit?: number; className?: string; messageClassName?: string; renderMessage?: (message: ChatMessage) => ReactNode; }): React.JSX.Element — ⚠ undocumented
524
- - `ChatPanel` (function): function ChatPanel({ channels, initialChannel, limit, className, tabsClassName, tabClassName, activeTabClassName, logClassName, messageClassName, inputClassName, inputFieldClassName, sendButtonClassName, placeholder, renderMessage, renderTab, onRejected, }: { channels?: readonly string[]; initialCha… — ⚠ undocumented
543
+ - `ChatLog` (function): function ChatLog({ channelId, limit, className, messageClassName, ownMessageClassName, renderMessage, }: { channelId: string; limit?: number; className?: string; messageClassName?: string; ownMessageClassName?: string; renderMessage?: (message: ChatMessage) => ReactNode; }): React.JSX.Element — ⚠ undocumented
544
+ - `ChatPanel` (function): function ChatPanel<T extends ChatMessage = ChatMessage>(props: Parameters<typeof ContextChatPanel>[0] | StandaloneChatPanelProps<T>): React.JSX.Element — Chat behavior over a game context or externally supplied server messages.
525
545
  - `ClerkUserShape` (interface): interface ClerkUserShape — ⚠ undocumented
526
546
  - `ClerkUserState` (interface): interface ClerkUserState — ⚠ undocumented
527
547
  - `Clock` (function): function Clock({ format = "24h", showDay = true, controls = false, style, className, }: { format?: "24h" | "12h"; showDay?: boolean; controls?: boolean; style?: CSSProperties; className?: string; }): React.JSX.Element — A time-of-day clock reading the sim calendar — `Day N · HH:MM`, 24h or 12h. `controls` adds pause + the game's speed multipliers as clickable pills (the "fast-forward" bar), off by default so a game opts into letting the player scrub time.
@@ -620,6 +640,9 @@
620
640
  - `HudLayoutPersist` (type): type HudLayoutPersist = (id: string, panel: EditorUiPanelLayout) => void — Host-owned callback that commits one HUD panel layout into the scene document (typically an undoable `setUiPanel` dispatch). Injected by the editor so product UI never reaches for editor globals.
621
641
  - `HudLayoutPersistProvider` (function): function HudLayoutPersistProvider({ onPanelCommit, children, }: { onPanelCommit: HudLayoutPersist; children?: ReactNode; }): React.JSX.Element — Provides {@link HudLayoutPersist} / `onPanelCommit` to descendant `useHudLayout` calls. Mount around game UI when a host can accept document UI patches (editor). Absent provider → canvas moves/resizes are no-ops for document writes.
622
642
  - `HudPanel` (function): function HudPanel({ id, anchor = "top-left", order, compact: compactMode = "keep", chip, interactive, inset, locked, showDuring, priority, mobileBehavior, allowOverlapWith, collisionGroup, region = true, width, height, type, className, style, children, }: { id: string; anchor?: HudAnchor; /** Stack … — A HUD block that lives in one of the nine anchor regions. Panels sharing a region stack outward from the screen edge in ascending `order`. On fine pointers panels stay draggable through the edit chord; a dragged panel leaves the flow and keeps its custom placement. On compact displays custom placements are ignored and the `compact` behavior applies.
643
+ - `HudSkin` (interface): interface HudSkin — A game-authored visual skin layered over a {@link HudTheme}.
644
+ - `HudSkinMaterial` (interface): interface HudSkinMaterial — Optional raster-backed materials for shared HUD chrome.
645
+ - `HudSkinPreview` (function): function HudSkinPreview({ className }: { className?: string }): React.JSX.Element — Procedural two-skin fixture for visual regression captures.
623
646
  - `HudTheme` (interface): interface HudTheme — A full HUD theme. Author one with {@link hudTheme} or {@link deriveHudTheme}.
624
647
  - `HudThemeBar` (interface): interface HudThemeBar — Framed-trough tokens shared by every atomic bar.
625
648
  - `HudThemeFont` (interface): interface HudThemeFont — Typography roles. Any CSS `font-family` list.
@@ -835,6 +858,7 @@
835
858
  - `eventMeterNeedsHeartbeat` (function): function eventMeterNeedsHeartbeat(meter: EventMeter, previous: EventMeterView | null): boolean — True when `meter`'s value/fraction/tier/ready diverge from `previous` — the re-render check `useEventMeter` polls on its heartbeat.
836
859
  - `formatTimerMs` (function): function formatTimerMs(ms: number, format: TimerFormat = "mm:ss"): string — Format a millisecond duration as digital timer text — `mm:ss` (default), `m:ss.d` (with tenths), or `ss.d` (seconds + tenths). Negative inputs clamp to zero. No genre meaning: the same helper serves a round clock, a respawn countdown, or an ability charge readout.
837
860
  - `guestIdentity` (function): function guestIdentity(seed?: string): IdentitySource — ⚠ undocumented
861
+ - `hudSkinVars` (function): function hudSkinVars(skin?: HudSkin): CSSProperties — Converts a skin into the CSS variables consumed by shared HUD components.
838
862
  - `hudTheme` (function): function hudTheme(overrides: HudThemeOverrides): HudTheme — Builds a full {@link HudTheme} from per-group partials, filling the rest from {@link defaultHudTheme}. Reach for this when a game wants to name exact values; use {@link deriveHudTheme} when a seed color pair is enough.
839
863
  - `hudThemeVars` (function): function hudThemeVars(theme: HudTheme): CSSProperties — Emits the CSS custom properties for a theme — spread onto any HUD ancestor to re-skin the subtree.
840
864
  - `hudVisibleInPhase` (function): function hudVisibleInPhase(showDuring: readonly GamePhase[] | undefined, phase: GamePhase): boolean — Whether a HUD element opted into `showDuring` is visible in the current phase; `undefined` = always visible (default).
@@ -894,6 +918,7 @@
894
918
  - `useGameViewportLayout` (function): function useGameViewportLayout(): GameViewportLayout — The live shared viewport layout. Returns a neutral default outside a `GameViewportProvider` so it never throws in previews.
895
919
  - `useHasSettings` (function): function useHasSettings(): boolean — True when the game has any setting or game-action to show — gate your own settings entry on it.
896
920
  - `useHeldKeys` (function): function useHeldKeys(): (code: string) => boolean — Held-key predicate backed by window keydown/keyup/blur listeners (blur clears held state so a released-off-window key doesn't stick). SSR-safe: listeners attach in an effect, never at module scope. The returned predicate is stable across renders.
921
+ - `useHudFont` (function): function useHudFont(skin?: HudSkin): boolean — Loads a skin font in browsers and reports when it is available.
897
922
  - `useHudLayout` (function): function useHudLayout(options?: { storageKey?: string; snap?: number; locked?: boolean; /** * Scene-document `ui` section — source of truth for panel placement/size. * When provided, hydrates the layout store (and wins over legacy localStorage). */ documentUi?: EditorUiDocument; /** * When true (def… — Layout state for `HudCanvas` — panel placements, edit-mode drag/resize, and per-game persistence.
898
923
  - `useHudLayoutPersist` (function): function useHudLayoutPersist(): HudLayoutPersist | null — Injected panel-commit port, or `null` when no host has provided one.
899
924
  - `useHudViewport` (function): function useHudViewport(): HudViewportContextValue | null — ⚠ undocumented
@@ -1044,8 +1069,8 @@
1044
1069
 
1045
1070
  - `ChannelTabs` (function): function ChannelTabs({ channels, active, onSelect, className, tabClassName, activeTabClassName, renderTab, }: { channels?: readonly string[]; active: string; onSelect: (channelId: string) => void; className?: string; tabClassName?: string; activeTabClassName?: string; renderTab?: (channelId: string,… — ⚠ undocumented
1046
1071
  - `ChatInput` (function): function ChatInput({ channelId, className, inputClassName, buttonClassName, placeholder, sendLabel, onSent, onRejected, }: { channelId: string; className?: string; inputClassName?: string; buttonClassName?: string; placeholder?: string; sendLabel?: ReactNode; onSent?: (message: ChatMessage) => void;… — ⚠ undocumented
1047
- - `ChatLog` (function): function ChatLog({ channelId, limit, className, messageClassName, renderMessage, }: { channelId: string; limit?: number; className?: string; messageClassName?: string; renderMessage?: (message: ChatMessage) => ReactNode; }): React.JSX.Element — ⚠ undocumented
1048
- - `ChatPanel` (function): function ChatPanel({ channels, initialChannel, limit, className, tabsClassName, tabClassName, activeTabClassName, logClassName, messageClassName, inputClassName, inputFieldClassName, sendButtonClassName, placeholder, renderMessage, renderTab, onRejected, }: { channels?: readonly string[]; initialCha… — ⚠ undocumented
1072
+ - `ChatLog` (function): function ChatLog({ channelId, limit, className, messageClassName, ownMessageClassName, renderMessage, }: { channelId: string; limit?: number; className?: string; messageClassName?: string; ownMessageClassName?: string; renderMessage?: (message: ChatMessage) => ReactNode; }): React.JSX.Element — ⚠ undocumented
1073
+ - `ChatPanel` (function): function ChatPanel<T extends ChatMessage = ChatMessage>(props: Parameters<typeof ContextChatPanel>[0] | StandaloneChatPanelProps<T>): React.JSX.Element — Chat behavior over a game context or externally supplied server messages.
1049
1074
  - `chatTransportFromSync` (function): function chatTransportFromSync(sync: ChatSync): ChatTransport — Lifts a callback-style ChatSync (e.g. createWsBackend().chatSyncFor(serverId)) into the hook-shaped ChatTransport contract. Create once per sync — outside render or inside useMemo — so subscriptions survive re-renders.
1050
1075
 
1051
1076
  ## @jgengine/react/chatBubbles
@@ -1287,9 +1312,21 @@
1287
1312
  - `HudLayoutPersistProvider` (function): function HudLayoutPersistProvider({ onPanelCommit, children, }: { onPanelCommit: HudLayoutPersist; children?: ReactNode; }): React.JSX.Element — Provides {@link HudLayoutPersist} / `onPanelCommit` to descendant `useHudLayout` calls. Mount around game UI when a host can accept document UI patches (editor). Absent provider → canvas moves/resizes are no-ops for document writes.
1288
1313
  - `useHudLayoutPersist` (function): function useHudLayoutPersist(): HudLayoutPersist | null — Injected panel-commit port, or `null` when no host has provided one.
1289
1314
 
1315
+ ## @jgengine/react/hudSkin
1316
+
1317
+ - `HudSkin` (interface): interface HudSkin — A game-authored visual skin layered over a {@link HudTheme}.
1318
+ - `HudSkinMaterial` (interface): interface HudSkinMaterial — Optional raster-backed materials for shared HUD chrome.
1319
+ - `hudSkinVars` (function): function hudSkinVars(skin?: HudSkin): CSSProperties — Converts a skin into the CSS variables consumed by shared HUD components.
1320
+ - `useHudFont` (function): function useHudFont(skin?: HudSkin): boolean — Loads a skin font in browsers and reports when it is available.
1321
+
1322
+ ## @jgengine/react/hudSkinPreview
1323
+
1324
+ - `HudSkinPreview` (function): function HudSkinPreview({ className }: { className?: string }): React.JSX.Element — Procedural two-skin fixture for visual regression captures.
1325
+
1290
1326
  ## @jgengine/react/hudTheme
1291
1327
 
1292
1328
  - `HUD_THEME_PRESETS` (const): const HUD_THEME_PRESETS: { "arcane-stone": HudTheme; "survival-wood": HudTheme; "military-flat": HudTheme; "sleek-hex": HudTheme; "elemental-circle": HudTheme; "sandbox-slot": HudTheme; ember: HudTheme; synthwave: HudTheme; fieldkit: HudTheme; } — Built-in theme presets for demos/scaffold only — not product identity; games author their own theme.
1329
+ - `HudSkin` (interface): interface HudSkin — A game-authored visual skin layered over a {@link HudTheme}.
1293
1330
  - `HudTheme` (interface): interface HudTheme — A full HUD theme. Author one with {@link hudTheme} or {@link deriveHudTheme}.
1294
1331
  - `HudThemeBar` (interface): interface HudThemeBar — Framed-trough tokens shared by every atomic bar.
1295
1332
  - `HudThemeFont` (interface): interface HudThemeFont — Typography roles. Any CSS `font-family` list.
@@ -1304,6 +1341,7 @@
1304
1341
  - `HudThemeSurface` (interface): interface HudThemeSurface — Chrome surfaces, edges, and text — what panels, overlays, and menus are built out of.
1305
1342
  - `defaultHudTheme` (const): const defaultHudTheme: HudTheme — Default theme tokens for previews/scaffold — not a finished game look; author a custom theme.
1306
1343
  - `deriveHudTheme` (function): function deriveHudTheme(seed: HudThemeSeed): HudTheme — Derives a coherent full theme from an accent/surface pair — shades, edges, dim text, frames, bar troughs, and slots all fall out of the seed, so a game gets one consistent look across the `packages/react` primitives and the `registry/jgengine` blocks without naming 50 tokens. Hex seeds only (`#rgb` or `#rrggbb`).
1344
+ - `hudSkinVars` (function): function hudSkinVars(skin?: HudSkin): CSSProperties — Converts a skin into the CSS variables consumed by shared HUD components.
1307
1345
  - `hudTheme` (function): function hudTheme(overrides: HudThemeOverrides): HudTheme — Builds a full {@link HudTheme} from per-group partials, filling the rest from {@link defaultHudTheme}. Reach for this when a game wants to name exact values; use {@link deriveHudTheme} when a seed color pair is enough.
1308
1346
  - `hudThemeVars` (function): function hudThemeVars(theme: HudTheme): CSSProperties — Emits the CSS custom properties for a theme — spread onto any HUD ancestor to re-skin the subtree.
1309
1347
  - `resolveHudTheme` (function): function resolveHudTheme(theme?: HudThemePreset | HudTheme): HudTheme — Resolves a preset name (or a full theme) to a `HudTheme`; falls back to the default theme.
@@ -1608,6 +1646,11 @@
1608
1646
  - `WorldBrowser` (function): function WorldBrowser({ listings, onJoin, className, rowClassName, joinClassName, emptyState, renderListing, }: { listings: readonly SessionListing[]; onJoin: (listing: SessionListing) => void; className?: string; rowClassName?: string; joinClassName?: string; emptyState?: ReactNode; renderListing?:… — ⚠ undocumented
1609
1647
  - `WorldInviteToast` (function): function WorldInviteToast({ className, acceptClassName, declineClassName, onAccepted, renderInvite, }: { className?: string; acceptClassName?: string; declineClassName?: string; onAccepted: (target: WorldInviteTarget) => void; renderInvite?: (invite: WorldInvite) => ReactNode; }): React.JSX.Element … — ⚠ undocumented
1610
1648
 
1649
+ ## @jgengine/react/standaloneChatPanel
1650
+
1651
+ - `StandaloneChatPanel` (function): function StandaloneChatPanel<T extends ChatMessage>({ messages, userId, onSend, className, logClassName, inputClassName, inputFieldClassName, messageClassName, ownMessageClassName, style, defaultExpanded = false, collapsedLimit = 3, limit = 50, maxLength = DEFAULT_CHAT_BODY_LENGTH, hotkeysEnabled = … — Headless chat interaction for external message stores. Prefer the ChatPanel entrypoint.
1652
+ - `StandaloneChatPanelProps` (interface): interface StandaloneChatPanelProps<T extends ChatMessage = ChatMessage> — Message-store inputs and caller-owned styling for standalone chat.
1653
+
1611
1654
  ## @jgengine/react/startScreen
1612
1655
 
1613
1656
  - `ControlHint` (interface): interface ControlHint — One row of a control legend. Name the game action(s) whose bound key(s) to show (`action`) so the glyphs come straight from the keybind map — never re-typed — or give literal `keys` for controls that live outside the map (`"Mouse"`, `"LMB"`). `label` says what the control does.
@@ -1636,6 +1679,10 @@
1636
1679
  - `TalentTree` (function): function TalentTree<TStat extends string = string>({ view: viewProp, nodes, tree, onLearn, icon, label, branchLabel, title = "Talents", variation = "themed", nodeSize = 54, columnGap = 30, tierGap = 46, showPoints = true, className, style, }: TalentTreeProps<TStat>): ReactNode — Drop-in talent / skill-tree widget over the existing progression model (`@jgengine/core/game/talents` + its `talentTreeView` selector). The game passes its node definitions and a live `createTalentTree` instance; the widget lays nodes out by branch column and prerequisite-depth tier, draws SVG prerequisite edges, styles each node learned/available/locked/maxed, shows an icon + rank badge, and calls `onLearn(nodeId)` when the player clicks a node that is currently allocatable. All layout, edge-drawing, and eligibility come from the model/selector — the widget never re-derives topology. Unskinned and HudTheme-token driven; node ids/branches are opaque game data the game supplies icons and labels for.
1637
1680
  - `TalentTreeProps` (interface): interface TalentTreeProps<TStat extends string = string> — Props for {@link TalentTree}.
1638
1681
 
1682
+ ## @jgengine/react/tileLayerPreview
1683
+
1684
+ - `TileLayerPreview` (function): function TileLayerPreview({ className }: { className?: string }): React.JSX.Element — Deterministic canvas-backed tile-layer fixture for textured tile presentation evidence.
1685
+
1639
1686
  ## @jgengine/react/timerReadout
1640
1687
 
1641
1688
  - `TimerFormat` (type): type TimerFormat = "mm:ss" | "m:ss.d" | "ss.d" — Digital text format for a timer readout.
@@ -1653,6 +1700,10 @@
1653
1700
  - `DebouncedCommit` (interface): interface DebouncedCommit<T> — Live-mirrored, trailing-debounced commit binding for a single control value.
1654
1701
  - `useDebouncedCommit` (function): function useDebouncedCommit<T>(value: T, commit: (value: T) => void, delayMs = 180): DebouncedCommit<T> — See {@link DebouncedCommit}. `commit` and `delayMs` may change between renders (kept in refs); the binding identity stays stable except when `value` (the local mirror) changes.
1655
1702
 
1703
+ ## @jgengine/react/useServerSession
1704
+
1705
+ - `useServerSession` (function): function useServerSession(transport: GameRuntimeTransport, gameId: string, preferredServerId?: string): { retry: () => void; serverId: string | null; status: "joining" | "joined" | "failed"; failureReason: string | null; } — Joins a host and exposes a retryable blocking state until membership is confirmed.
1706
+
1656
1707
  ## @jgengine/react/voice
1657
1708
 
1658
1709
  - `MicToggle` (function): function MicToggle({ voice, className, mutedLabel, unmutedLabel, }: { voice: VoiceState; className?: string; mutedLabel?: ReactNode; unmutedLabel?: ReactNode; }): React.JSX.Element — ⚠ undocumented
@@ -1695,6 +1746,15 @@
1695
1746
  - `UiPreviewScenario` (type): type UiPreviewScenario = (ctx: GameContext, playable: PlayableGame) => void — ⚠ undocumented
1696
1747
  - `defaultUiScenario` (const): const defaultUiScenario: UiPreviewScenario — ⚠ undocumented
1697
1748
 
1749
+ ## @jgengine/shell/JoinGate
1750
+
1751
+ - `JoinGate` (function): function JoinGate({ status, failureReason, retry, joiningLabel = "Joining world…", failedLabel = "Unable to join", retryLabel = "Retry", className, children, renderJoining, renderFailure }: { status: "joining" | "joined" | "failed"; failureReason?: string | null; retry: () => void; joiningLabel?: Re… — Blocking join feedback; callers may supply their own copy and classes.
1752
+
1753
+ ## @jgengine/shell/TerritoryOverlay
1754
+
1755
+ - `TerritoryOverlay` (function): function TerritoryOverlay({ cells, cost, affordable, formatCost = String, renderCell, className, style }: { cells: readonly TerritoryPreviewCell[]; cost: number; affordable: boolean; formatCost?: (cost: number) => ReactNode; renderCell?: (cell: TerritoryPreviewCell) => ReactNode; className?: string;… — Placement footprint feedback with inline claim cost and affordability.
1756
+ - `TerritoryPreviewCell` (type): type TerritoryPreviewCell = { key: string; x: number; z: number; status: "owned" | "claimable" | "blocked" } — A placement footprint cell and its authoritative preview status.
1757
+
1698
1758
  ## @jgengine/shell/audio/AudioComponents
1699
1759
 
1700
1760
  - `AudioListener` (function): function AudioListener({ engine }: { engine: AudioEngine }): null — ⚠ undocumented
@@ -1706,6 +1766,7 @@
1706
1766
  - `AudioEmitterHandle` (interface): interface AudioEmitterHandle — ⚠ undocumented
1707
1767
  - `AudioEngine` (interface): interface AudioEngine — ⚠ undocumented
1708
1768
  - `AudioSceneConfig` (interface): interface AudioSceneConfig — ⚠ undocumented
1769
+ - `ListenerPose` (interface): interface ListenerPose — Position and orientation for a spatial-audio listener.
1709
1770
  - `Vec3` (interface): interface Vec3 — ⚠ undocumented
1710
1771
  - `createAudioEngine` (function): function createAudioEngine(config: AudioSceneConfig = {}): AudioEngine — ⚠ undocumented
1711
1772
 
@@ -1969,7 +2030,7 @@
1969
2030
 
1970
2031
  ## @jgengine/shell/drivers/FrameDriver
1971
2032
 
1972
- - `FrameDriver` (function): function FrameDriver({ ctx, playable, tracker, yawRef, pitchRef, primaryClickRef, pointerAxisRef, analogRef, gateRef, onRuntimeError, multiplayer, serverIdRef, pointerService, pointerAim, pingCommand, poster, onPosterSettled, }: { ctx: GameContext; playable: PlayableGame; tracker: ActionStateTracker… — ⚠ undocumented
2033
+ - `FrameDriver` (function): function FrameDriver({ ctx, playable, tracker, yawRef, pitchRef, primaryClickRef, pointerAxisRef, analogRef, gateRef, onRuntimeError, multiplayer, serverIdRef, pointerService, pointerAim, pingCommand, poster, onPosterSettled, authoritativeFrameRef, }: { ctx: GameContext; playable: PlayableGame; trac… — ⚠ undocumented
1973
2034
  - `POSTER_SETTLE_SECONDS` (const): const POSTER_SETTLE_SECONDS: 1.6 — ⚠ undocumented
1974
2035
 
1975
2036
  ## @jgengine/shell/drivers/HudOnlyDriver
@@ -2059,6 +2120,18 @@
2059
2120
 
2060
2121
  - `SkyLightOwnership` (type): type SkyLightOwnership = "authored" | "sky-default" — Policy for composing sky backdrops with `PlayableGame.lighting`: - authored lighting present → sky renders dome + fog only; lights stay game-owned - no authored lighting → sky may emit its default sun/hemisphere with the dome Time-of-day never rewrites configured lights; it only drives sky colors/fog (and sky-owned lights when the game did not author lighting).
2061
2122
 
2123
+ ## @jgengine/shell/input/gamepadMerge
2124
+
2125
+ - `GamepadInputFrame` (interface): interface GamepadInputFrame — Per-frame gamepad actions and analog values ready to merge with another input source.
2126
+ - `mergeGamepadFrame` (function): function mergeGamepadFrame(base: GamepadInputFrame, gamepad: GamepadFrame): GamepadInputFrame — Merge one resolved gamepad frame with another input source's semantic state.
2127
+ - `mergeGamepadInput` (function): function mergeGamepadInput(frames: readonly GamepadFrame[], base: GamepadInputFrame = { held: [], analog: {} }): GamepadInputFrame — Pure reducer used by the shell and synthetic gamepad tests.
2128
+
2129
+ ## @jgengine/shell/input/gamepadSource
2130
+
2131
+ - `GamepadSource` (function): function GamepadSource({ tracker, bindings, analogRef, input, }: { tracker: ActionStateTracker<string>; bindings: ActionCodesMap; analogRef: { current: Readonly<Record<string, number>> | null }; input: InputSnapshot; }): null — Poll browser gamepads and feed semantic actions into the shell tracker.
2132
+ - `mergeGamepadFrame` (function): function mergeGamepadFrame(base: GamepadInputFrame, gamepad: GamepadFrame): GamepadInputFrame — Merge one resolved gamepad frame with another input source's semantic state.
2133
+ - `mergeGamepadInput` (function): function mergeGamepadInput(frames: readonly GamepadFrame[], base: GamepadInputFrame = { held: [], analog: {} }): GamepadInputFrame — Pure reducer used by the shell and synthetic gamepad tests.
2134
+
2062
2135
  ## @jgengine/shell/input/mouseLook
2063
2136
 
2064
2137
  - `MouseLookAim` (interface): interface MouseLookAim — ⚠ undocumented
@@ -2124,7 +2197,7 @@
2124
2197
 
2125
2198
  ## @jgengine/shell/postfx/PostProcessing
2126
2199
 
2127
- - `PostProcessing` (function): function PostProcessing({ config, quality = "high" }: { config: PostProcessingConfig; quality?: GraphicsQuality }): null — Mounts an `EffectComposer` inside the shell Canvas and takes over rendering (priority-1 `useFrame`, which disables R3F auto-render) to run the configured post chain: RenderPass → GTAO → UnrealBloom → SMAA → OutputPass → Grade. Rendered only when `PlayableGame.postProcessing` is set, so games without it draw unchanged.
2200
+ - `PostProcessing` (function): function PostProcessing({ config, quality = "high", stages }: { config: PostProcessingConfig; quality?: GraphicsQuality; stages?: { ao: boolean; bloom: boolean; dof: boolean; smaa: boolean } }): null — Mounts an `EffectComposer` inside the shell Canvas and takes over rendering (priority-1 `useFrame`, which disables R3F auto-render) to run the configured post chain: RenderPass → GTAO → UnrealBloom → SMAA → OutputPass → Grade. Rendered only when `PlayableGame.postProcessing` is set, so games without it draw unchanged.
2128
2201
 
2129
2202
  ## @jgengine/shell/postfx/ScreenEffectsOverlay
2130
2203
 
@@ -2150,6 +2223,11 @@
2150
2223
  - `RenderObject` (type): type RenderObject = (object: SceneObject) => ReactNode — ⚠ undocumented
2151
2224
  - `resolveGameLoader` (function): function resolveGameLoader(registry: GameRegistry, gameId: string, fallbackGameId?: string): (() => Promise<PlayableGame>) | undefined — ⚠ undocumented
2152
2225
 
2226
+ ## @jgengine/shell/render/CascadedShadows
2227
+
2228
+ - `CsmMaterialSetup` (interface): interface CsmMaterialSetup — Structural slice of CSM so the patcher is testable without a renderer.
2229
+ - `patchSceneMaterials` (function): function patchSceneMaterials(scene: THREE.Scene, csm: CsmMaterialSetup, patched: WeakSet<THREE.Material>): void — Run CSM's `setupMaterial` over every unpatched standard material in the scene, chaining rather than clobbering a material's own `onBeforeCompile`. Called every frame (WeakSet-guarded) so streamed meshes never render lit by all cascades at once.
2230
+
2153
2231
  ## @jgengine/shell/render/EntityPreview
2154
2232
 
2155
2233
  - `EntityPreview` (function): function EntityPreview({ children, model, instanceId, mood = "studio", backdrop, turntable = 0, faceCamera = false, forward, environment = true, cameraPosition = [0, 1, 3], fov = 35, dpr = [1, 2], className, style, }: EntityPreviewProps): React.JSX.Element — Drop-in live 3D preview of a single entity — the character-screen portrait, unit inspector, or loadout viewer. It owns all the plumbing a game would otherwise re-derive by hand: a nested `<Canvas>`, the {@link GameContextBridge} that carries the running `GameContext` across the R3F reconciler boundary (so the subject's `useEntityRenderCues` / `useGameContext` hooks resolve and it mirrors the live game), a {@link StudioStage} 3-point lighting rig with optional turntable / face-camera, and a capture-friendly GL surface. The game keeps ownership of its `renderEntity`: pass it as `children`, or hand a native `model` (+ `instanceId`) for an engine-composed body. Bound to a live `instanceId`, the portrait walks, flinches, and topples in lockstep with the world instead of a canned spin.
@@ -2162,7 +2240,9 @@
2162
2240
  ## @jgengine/shell/render/SceneLighting
2163
2241
 
2164
2242
  - `BackdropFog` (function): function BackdropFog({ fog }: { fog: BackdropConfig["fog"] }): React.JSX.Element | null — ⚠ undocumented
2165
- - `ConfiguredLighting` (function): function ConfiguredLighting({ lighting }: { lighting: LightingConfig }): React.JSX.Element — ⚠ undocumented
2243
+ - `ConfiguredLighting` (function): function ConfiguredLighting({ lighting, profile }: { lighting: LightingConfig; profile?: GraphicsProfile }): React.JSX.Element — ⚠ undocumented
2244
+ - `POINT_LIGHT_BUDGET` (const): const POINT_LIGHT_BUDGET: 8 — Default cap for combined dynamic point and spot lights.
2245
+ - `syncShadowProjection` (function): function syncShadowProjection(light: DirectionalLight): void — Refresh a directional light's shadow projection after its frustum bounds change. R3F pierced `shadow-camera-*` props write the bounds but never call `updateProjectionMatrix()`, so depth renders with the stale default ~10×10 box and `shadowCameraSize` is silently inert.
2166
2246
 
2167
2247
  ## @jgengine/shell/render/SceneModels
2168
2248
 
@@ -2192,12 +2272,16 @@
2192
2272
 
2193
2273
  ## @jgengine/shell/render/modelLoad
2194
2274
 
2275
+ - `ModelLoaderConfig` (interface): interface ModelLoaderConfig — CDN-backed decoder configuration for compressed model and texture assets.
2276
+ - `configureModelLoaders` (function): function configureModelLoaders(options: ModelLoaderConfig = {}): Readonly<Required<ModelLoaderConfig>> — Configures shared Draco and KTX2 loaders. Repeated calls with the same paths are no-ops.
2277
+ - `detectKtx2Support` (function): function detectKtx2Support(renderer: THREE.WebGLRenderer): void — Detects GPU support for the configured KTX2 transcoder after a renderer exists.
2195
2278
  - `modelLoadFallbacks` (function): function modelLoadFallbacks(): readonly { url: string; message: string }[] — Every model the shared loader diagnosed as broken and replaced with a magenta placeholder, in load order.
2196
2279
  - `modelLoadIdleMs` (function): function modelLoadIdleMs(): number — How long the shared GLB loader has been idle, in ms — `0` while any model is still in flight. A capture host reads this to wait for streaming to finish instead of guessing a settle delay: models that pop in after the shot are why an establishing capture used to come back half-empty until someone hand-tuned `--settle`.
2197
2280
 
2198
2281
  ## @jgengine/shell/render/modelRender
2199
2282
 
2200
2283
  - `MaterialCache` (interface): interface MaterialCache — ⚠ undocumented
2284
+ - `ModelShadowMode` (type): type ModelShadowMode = "cast" | "receive" | "both" | "none" — Shadow participation applied to every mesh of a cloned model; mirrors `ModelConfig.shadows`.
2201
2285
  - `PAINT_TEXTURE_SIZE` (const): const PAINT_TEXTURE_SIZE: 512 — ⚠ undocumented
2202
2286
  - `PaintCanvas` (interface): interface PaintCanvas — ⚠ undocumented
2203
2287
 
@@ -2213,6 +2297,10 @@
2213
2297
  - `captureCanvas` (function): function captureCanvas(gl: CaptureRenderer): string | null — Read the current frame to a PNG data URL. Requires the R3F `<Canvas>` to have been created with `gl={{ preserveDrawingBuffer: true }}` (the shell's game canvas already is); returns null if the backing canvas can't be read.
2214
2298
  - `downloadImage` (function): function downloadImage(dataUrl: string, filename = "screenshot.png"): void — Trigger a browser download of an image data URL (the photo-mode "save" action).
2215
2299
 
2300
+ ## @jgengine/shell/render/testFixtures/proceduralTileLayer
2301
+
2302
+ - `drawProceduralTileLayer` (function): function drawProceduralTileLayer(canvas: CanvasFixture): TilemapWorldConfig — Draw the deterministic tile atlas used by textured tile-layer captures and tests.
2303
+
2216
2304
  ## @jgengine/shell/render/useDisposable
2217
2305
 
2218
2306
  - `Disposable` (interface): interface Disposable — Anything exposing dispose() — three.js geometries, materials, textures, render targets.
@@ -2223,9 +2311,14 @@
2223
2311
 
2224
2312
  - `useEntityRenderCues` (function): function useEntityRenderCues(instanceId: string | undefined, tuning?: RenderCueTuning): MutableRefObject<EntityRenderCues> — Live motion + animation cues for one entity, read from a mutable ref inside your own `useFrame` — no re-render per frame, no diffing the parent group's position, no game-side module map for attack/hit timing. Backs both custom `renderEntity` rigs and a custom first-person viewmodel (#542): call it with `entity.id` / the local player's userId and drive bob/recoil/reload poses from `cuesRef.current` inside the calling component's own `useFrame`.
2225
2313
 
2314
+ ## @jgengine/shell/render/useFootIk
2315
+
2316
+ - `applyFootIk` (function): function applyFootIk(scene: THREE.Object3D, config: FootIkConfig, raycast: GameContext["scene"]["raycast"], weight: number, cameraTarget?: readonly [number, number, number]): boolean — Applies one frame of foot IK to a loaded rig. Exported for renderer tests and custom model hosts.
2317
+ - `useFootIk` (function): function useFootIk(scene: THREE.Object3D, config: FootIkConfig | undefined, ctx: GameContext | null, instanceId?: string): void — Runs foot IK after the model animation mixer, fading the correction out while the entity is airborne.
2318
+
2226
2319
  ## @jgengine/shell/render/useModelAnimation
2227
2320
 
2228
- - `useModelAnimation` (function): function useModelAnimation(scene: THREE.Object3D, clips: THREE.AnimationClip[], animationInput: ModelAnimationConfig | "auto" | "none" | undefined, instanceId?: string): void — The engine's model animation driver as a standalone hook — the same mixer `EntityModel` runs, for games that render a cloned scene themselves (custom materials, procedural composition). Handles `"auto"` derivation from the GLB's clip names, speed-driven idle/walk/run crossfades read from the entity's live position when `instanceId` is set, one-shots fired from `entity.animation` / `combat.hitReaction` / `entity.died`, held poses, and the death clamp.
2321
+ - `useModelAnimation` (function): function useModelAnimation(scene: THREE.Object3D, clips: THREE.AnimationClip[], animationInput: ModelAnimationConfig | "auto" | "none" | undefined, instanceId?: string): void — The engine's model animation driver as a standalone hook — the same mixer `EntityModel` runs, for games that render a cloned scene themselves (custom materials, procedural composition). Handles `"auto"` derivation from the GLB's clip names, speed-driven idle/walk/run crossfades read from the entity's live position when `instanceId` is set, one-shots fired from `entity.animation` / `combat.hitReaction` / `entity.died`, held poses, and the death clamp. With `animation.graph` set, the headless `AnimGraph` runtime owns every clip's time and weight and the mixer only applies them; clip events surface as `animation.event`.
2229
2322
 
2230
2323
  ## @jgengine/shell/replay/useSessionRecorder
2231
2324
 
@@ -2301,7 +2394,7 @@
2301
2394
 
2302
2395
  - `AudioSettingsBridge` (function): function AudioSettingsBridge({ store, engine, buses, }: { store: SettingsStore; engine: AudioEngine; buses: Record<string, AudioBusDef> | undefined; }): null — ⚠ undocumented
2303
2396
  - `TOUCH_STYLE_AUTO` (const): const TOUCH_STYLE_AUTO: "auto" — Sentinel Controls value meaning "defer to the game's suggested touch skin".
2304
- - `useGraphicsSettings` (function): function useGraphicsSettings(store: SettingsStore, shadowsDefault: boolean): { shadows: boolean; dpr: number; uiScale: number; quality: GraphicsQuality } — ⚠ undocumented
2397
+ - `useGraphicsSettings` (function): function useGraphicsSettings(store: SettingsStore, shadowsDefault: boolean, overrides?: Partial<Record<GraphicsQuality, Partial<GraphicsProfile>>>): { shadows: boolean; dpr: number; uiScale: number; quality: GraphicsQuality; profile: GraphicsProfile } — ⚠ undocumented
2305
2398
  - `useSettingsRevision` (function): function useSettingsRevision(store: SettingsStore): number — ⚠ undocumented
2306
2399
 
2307
2400
  ## @jgengine/shell/settings/settingsController
@@ -2569,7 +2662,7 @@
2569
2662
 
2570
2663
  ## @jgengine/shell/useShellMultiplayerSync
2571
2664
 
2572
- - `useShellMultiplayerSync` (function): function useShellMultiplayerSync(ctx: GameContext | null, multiplayer: ShellMultiplayer | null, playable: PlayableGame, serverIdRef: { current: string | null }, setRemotePlayers: Dispatch<SetStateAction<PresencePoseRow[]>>): void — Joins the multiplayer server for the live context and wires presence, feed relay, and chat sync until teardown.
2665
+ - `useShellMultiplayerSync` (function): function useShellMultiplayerSync(ctx: GameContext | null, multiplayer: ShellMultiplayer | null, playable: PlayableGame, serverIdRef: { current: string | null }, setRemotePlayers: Dispatch<SetStateAction<PresencePoseRow[]>>, authoritativeFrameRef?: { current: AuthoritativeFrameHandler | null }): { st… — Joins the multiplayer server for the live context and wires presence, feed relay, and chat sync until teardown.
2573
2666
 
2574
2667
  ## @jgengine/shell/vfx/ParticleField
2575
2668
 
@@ -2584,7 +2677,7 @@
2584
2677
 
2585
2678
  ## @jgengine/shell/visibility/CullingProvider
2586
2679
 
2587
- - `CullingProvider` (function): function CullingProvider({ config, children }: { config: VisibilityConfig | undefined; children: ReactNode }): ReactNode — Drives automatic frustum + distance culling for every entity and placed object. It reads the live render camera each frame, updates the engine VisibilitySystem, and exposes a predicate the entity/object markers consult to toggle `group.visible` — objects fully outside the view (plus a conservative preload margin) are never submitted to the renderer, without unmounting them or touching gameplay. UI, sky, terrain, and environment live outside this subtree and are unaffected.
2680
+ - `CullingProvider` (function): function CullingProvider({ config, drawDistance, children }: { config: VisibilityConfig | undefined; drawDistance?: number; children: ReactNode }): ReactNode — Drives automatic frustum + distance culling for every entity and placed object. It reads the live render camera each frame, updates the engine VisibilitySystem, and exposes a predicate the entity/object markers consult to toggle `group.visible` — objects fully outside the view (plus a conservative preload margin) are never submitted to the renderer, without unmounting them or touching gameplay. UI, sky, terrain, and environment live outside this subtree and are unaffected.
2588
2681
  - `useRenderVisibility` (function): function useRenderVisibility(): MutableRefObject<VisiblePredicate> — Read the current render-visibility predicate. Backward compatible: with no CullingProvider mounted (or culling disabled) it returns an always-visible ref, so a marker that consults it behaves exactly as before this feature existed.
2589
2682
 
2590
2683
  ## @jgengine/shell/vision/FrustumSensorHud
@@ -2788,6 +2881,11 @@
2788
2881
  - `SpriteBatchInstance` (interface): interface SpriteBatchInstance — ⚠ undocumented
2789
2882
  - `SpriteBatchProps` (interface): interface SpriteBatchProps — ⚠ undocumented
2790
2883
 
2884
+ ## @jgengine/shell/world/TileLayerRenderer
2885
+
2886
+ - `TileLayerRenderer` (function): function TileLayerRenderer({ config, parallax = [1, 1], pixelated = true }: TileLayerRendererProps): React.JSX.Element | null — Renders a tilemap as one instanced quad mesh with atlas UV rectangles.
2887
+ - `TileLayerRendererProps` (interface): interface TileLayerRendererProps — Inputs for the instanced textured tile-layer renderer.
2888
+
2791
2889
  ## @jgengine/shell/world/WorldEntityFrames
2792
2890
 
2793
2891
  - `WorldEntityFrames` (function): function WorldEntityFrames<E extends EntityFrameEntry>({ entries, renderFrame, tickMs = 0, className, anchorTransform, ...layout }: WorldEntityFramesProps<E>): React.JSX.Element — R3F convenience that mounts inside the scene, samples the live camera each frame (throttled by `tickMs`), and renders `@jgengine/react`'s {@link EntityFrames} through a fullscreen `<Html>` overlay. This is the one-line way an R3F game gets overhead enemy nameplates/health bars from its own entity array without a store: pass `entries` + a `renderFrame` that composes the shipped bars. The projection, viewport culling, and stacking come for free.
@@ -2814,6 +2912,10 @@
2814
2912
 
2815
2913
  - `WorldItems` (function): function WorldItems({ config }: { config?: WorldItemRenderConfig }): React.JSX.Element — Rarity→beam/color/label render binding + loot-filter overlay (#32/#33) for every dropped `worldItem`.
2816
2914
 
2915
+ ## @jgengine/shell/world/WorldParticles
2916
+
2917
+ - `resolveParticleBudget` (function): function resolveParticleBudget(quality: GraphicsQuality, requested: number | undefined, particleCap?: number): number — The per-effect particle pool a graphics tier allows: the requested `max` clamped to the tier cap, so lower tiers degrade density instead of dropping effects entirely.
2918
+
2817
2919
  ## @jgengine/shell/world/WorldPings
2818
2920
 
2819
2921
  - `WorldPings` (function): function WorldPings({ markers, kindStyles, pingsOnly = true, height = 2.4, showCallout = true, renderCallout, }: WorldPingsProps): ReactNode — World-space pings — the in-scene side of a ping/marker: a bobbing downward arrowhead pointing at the spot, a ground ring, and a billboarded callout, colored by marker kind and fading in/out over the marker's lifetime. Reads a `MarkerSet` (typically the one a `createPingSystem` writes to), a marker source, or a static array; mount through `PlayableGame.WorldOverlay`.
@@ -2821,7 +2923,7 @@
2821
2923
 
2822
2924
  ## @jgengine/shell/world/WorldScene
2823
2925
 
2824
- - `RemotePlayers` (function): function RemotePlayers({ rows }: { rows: PresencePoseRow[] }): React.JSX.Element — ⚠ undocumented
2926
+ - `RemotePlayers` (function): function RemotePlayers({ rows, presenceInterpolationMs = 100 }: { rows: PresencePoseRow[]; presenceInterpolationMs?: number }): React.JSX.Element — ⚠ undocumented
2825
2927
  - `WorldView` (function): function WorldView({ entitySprites, entityModels, objectModels, objectStyles, environment, assets, renderEntity, renderObject, selectedIds, hideLocalActor, }: { entitySprites: Record<string, EntitySpriteConfig> | undefined; entityModels: Record<string, string | ModelConfig> | undefined; objectModels… — ⚠ undocumented
2826
2928
 
2827
2929
  ## @jgengine/shell/world/entityPose
@@ -2840,8 +2942,17 @@
2840
2942
  - `pingBobOffset` (function): function pingBobOffset(elapsedSeconds: number, amplitude = 0.18, speedHz = 1.1): number — Vertical bob offset (world units) for a hovering ping arrow at `elapsedSeconds`.
2841
2943
  - `pingOpacity` (function): function pingOpacity(input: PingOpacityInput): number — Alpha for a world ping in `[0, 1]`: ramps up over `fadeInMs` after it appears and ramps back down over `fadeOutMs` before it expires. Pure math so the lifecycle can be unit-tested without an R3F canvas.
2842
2944
 
2945
+ ## @jgengine/shell/world/tileLayerInstances
2946
+
2947
+ - `TileLayerInstance` (interface): interface TileLayerInstance — One resolved map cell with its world position and atlas UV rectangle.
2948
+ - `resolveTileLayerInstances` (function): function resolveTileLayerInstances(config: TilemapWorldConfig): readonly TileLayerInstance[] — Resolve map glyphs to atlas frames and normalized UV rectangles for deterministic tests and renderers.
2949
+
2843
2950
  ## @jgengine/shell/world/worldBarSamples
2844
2951
 
2845
2952
  - `NameplateSample` (interface): interface NameplateSample — One entity's projected nameplate: screen `x`/`y`, display `name`, health `percent` (or `null` when statless), and world `distance` from the player.
2846
2953
  - `Projectable` (interface): interface Projectable — ⚠ undocumented
2847
2954
  - `WorldBarSample` (interface): interface WorldBarSample — ⚠ undocumented
2955
+
2956
+ ## @jgengine/shell/worldSync
2957
+
2958
+ - `AuthoritativeFrameHandler` (type): type AuthoritativeFrameHandler = (revision: number) => void — Receives the revision of an authoritative world frame after it is applied locally.
@@ -286,6 +286,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
286
286
 
287
287
  - `InteractionPrompt` (function) · `import { InteractionPrompt } from "@jgengine/react"`
288
288
 
289
+ ## join-gate — block gameplay until joined and show failures with retry
290
+
291
+ - `JoinGate` (function) · `import { JoinGate } from "@jgengine/shell/JoinGate"`
292
+
289
293
  ## key-hint — keyboard/mouse control hint that hides itself on touch
290
294
 
291
295
  - `KeyHint` (function) · `import { KeyHint } from "@jgengine/react"`
@@ -499,6 +503,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
499
503
 
500
504
  - `SelectionPanel` (function) · `import { SelectionPanel } from "@jgengine/react"`
501
505
 
506
+ ## server-session — join a multiplayer host with status, retry, and teardown
507
+
508
+ - `useServerSession` (function) · `import { useServerSession } from "@jgengine/react/useServerSession"`
509
+
502
510
  ## shop-grid-host — drop-in vendor/shop grid over a caller-owned wallet — item cards with icon/price/stock, afford-aware Buy, optional Sell, and a balance readout, token-themed
503
511
 
504
512
  - `ShopGrid` (function) · `import { ShopGrid } from "@jgengine/react"`
@@ -507,6 +515,15 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
507
515
 
508
516
  - `formatSpeed` (function) · `import { formatSpeed } from "@jgengine/core/ui"`
509
517
 
518
+ ## sprite-2d — animate a sprite atlas clip from headless or rendered game code
519
+
520
+ - `createSpriteClipPlayer` (function) · `import { createSpriteClipPlayer } from "@jgengine/core/render/sprite2d"`
521
+ - `sortingOrder` (function) · `import { sortingOrder } from "@jgengine/core/render/sprite2d"`
522
+
523
+ ## standalone-chat — render persisted chat with focus controls and visible send failures
524
+
525
+ - `StandaloneChatPanel` (function) · `import { StandaloneChatPanel } from "@jgengine/react/standaloneChatPanel"`
526
+
510
527
  ## start-screen — headless title/attract overlay the game fills and skins
511
528
 
512
529
  - `StartScreen` (function) · `import { StartScreen } from "@jgengine/react"`
@@ -523,6 +540,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
523
540
 
524
541
  - `TalentTree` (function) · `import { TalentTree } from "@jgengine/react"`
525
542
 
543
+ ## territory-overlay — show footprint ownership, claim cost, and affordability
544
+
545
+ - `TerritoryOverlay` (function) · `import { TerritoryOverlay } from "@jgengine/shell/TerritoryOverlay"`
546
+
526
547
  ## timer-readout — live digital mm:ss/m:ss.d timer readout bound to a TimerSet
527
548
 
528
549
  - `TimerReadout` (function) · `import { TimerReadout } from "@jgengine/react"`
@@ -551,3 +551,6 @@ UI work is complete only when:
551
551
  - screenshots have been reviewed and revised
552
552
  - the implementation remains accessible and performant
553
553
  - future generated UI is explicitly prevented from falling back to generic website-card styling
554
+ ## 2D sprite presentation
555
+
556
+ Core owns renderer-independent atlas data and animation state. Convert Aseprite or TexturePacker JSON with `fromAseprite` / `fromTexturePacker` from `@jgengine/core/assets/spriteAtlas`, then drive a clip with `createSpriteClipPlayer` from `@jgengine/core/render/sprite2d`. Persist `snapshot()` and restore it on load; use `retune({ speed })` for runtime playback changes. Use `sortingOrder(layers, layer, offset)` when a game maps named presentation layers to renderer order.