@jgengine/editor 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +12 -0
  3. package/dist/AssetBrowser.d.ts +26 -1
  4. package/dist/AssetBrowser.js +54 -1
  5. package/dist/AssetDropZone.d.ts +9 -0
  6. package/dist/AssetDropZone.js +65 -0
  7. package/dist/CatalogsPanel.d.ts +4 -2
  8. package/dist/CatalogsPanel.js +162 -9
  9. package/dist/CityPreview.d.ts +11 -0
  10. package/dist/CityPreview.js +45 -0
  11. package/dist/CollectionsPanel.js +5 -5
  12. package/dist/DebugDraw.d.ts +3 -1
  13. package/dist/DebugDraw.js +37 -19
  14. package/dist/EditorApp.d.ts +9 -1
  15. package/dist/EditorApp.js +147 -35
  16. package/dist/EditorChrome.d.ts +25 -6
  17. package/dist/EditorChrome.js +310 -130
  18. package/dist/InspectorPanel.d.ts +17 -7
  19. package/dist/InspectorPanel.js +173 -27
  20. package/dist/LightingPanel.d.ts +11 -0
  21. package/dist/LightingPanel.js +99 -0
  22. package/dist/MaterialsWorkspacePanel.d.ts +12 -0
  23. package/dist/MaterialsWorkspacePanel.js +86 -0
  24. package/dist/ParentPickerMenu.d.ts +13 -0
  25. package/dist/ParentPickerMenu.js +33 -0
  26. package/dist/PerfProbe.js +33 -0
  27. package/dist/PrefabsPanel.js +5 -5
  28. package/dist/RuntimePlayBridge.d.ts +5 -3
  29. package/dist/RuntimePlayBridge.js +6 -13
  30. package/dist/ScatterPreview.d.ts +3 -1
  31. package/dist/ScatterPreview.js +10 -7
  32. package/dist/SchemaInspector.js +21 -8
  33. package/dist/ScriptingPanel.d.ts +15 -0
  34. package/dist/ScriptingPanel.js +46 -0
  35. package/dist/SelectionGizmo.js +114 -30
  36. package/dist/StandaloneEditor.d.ts +16 -9
  37. package/dist/StandaloneEditor.js +19 -20
  38. package/dist/TerrainPanel.d.ts +3 -2
  39. package/dist/TerrainPanel.js +16 -5
  40. package/dist/TerrainSculpt.js +98 -59
  41. package/dist/agent/AgentPanel.d.ts +5 -2
  42. package/dist/agent/AgentPanel.js +11 -6
  43. package/dist/agent/toolBridge.js +5 -0
  44. package/dist/assetImport.d.ts +36 -0
  45. package/dist/assetImport.js +66 -0
  46. package/dist/authoredComponentMeta.d.ts +25 -0
  47. package/dist/authoredComponentMeta.js +65 -0
  48. package/dist/gizmoPivot.d.ts +4 -0
  49. package/dist/gizmoPivot.js +34 -0
  50. package/dist/handlers/catalogs.d.ts +3 -0
  51. package/dist/handlers/catalogs.js +137 -0
  52. package/dist/handlers/collections.d.ts +3 -0
  53. package/dist/handlers/collections.js +57 -0
  54. package/dist/handlers/context.d.ts +36 -0
  55. package/dist/handlers/context.js +1 -0
  56. package/dist/handlers/document.d.ts +3 -0
  57. package/dist/handlers/document.js +350 -0
  58. package/dist/handlers/grids.d.ts +3 -0
  59. package/dist/handlers/grids.js +142 -0
  60. package/dist/handlers/hierarchy.d.ts +3 -0
  61. package/dist/handlers/hierarchy.js +55 -0
  62. package/dist/handlers/index.d.ts +8 -0
  63. package/dist/handlers/index.js +23 -0
  64. package/dist/handlers/minimap.d.ts +9 -0
  65. package/dist/handlers/minimap.js +32 -0
  66. package/dist/handlers/runtime.d.ts +3 -0
  67. package/dist/handlers/runtime.js +191 -0
  68. package/dist/handlers/terrain.d.ts +3 -0
  69. package/dist/handlers/terrain.js +204 -0
  70. package/dist/index.d.ts +3 -2
  71. package/dist/index.js +3 -2
  72. package/dist/listDocumentTriggers.d.ts +42 -0
  73. package/dist/listDocumentTriggers.js +49 -0
  74. package/dist/materialAssignments.d.ts +63 -0
  75. package/dist/materialAssignments.js +84 -0
  76. package/dist/mcp/fieldSpec.d.ts +32 -0
  77. package/dist/mcp/fieldSpec.js +173 -0
  78. package/dist/mcp/rpcRequest.d.ts +8 -5
  79. package/dist/mcp/rpcRequest.js +72 -93
  80. package/dist/mcp/tools.js +104 -912
  81. package/dist/networkSnapshot.d.ts +82 -0
  82. package/dist/networkSnapshot.js +73 -0
  83. package/dist/parentCandidates.d.ts +12 -0
  84. package/dist/parentCandidates.js +25 -0
  85. package/dist/session.d.ts +77 -4
  86. package/dist/session.js +36 -1017
  87. package/dist/shell/AnimationPanel.d.ts +17 -0
  88. package/dist/shell/AnimationPanel.js +134 -0
  89. package/dist/shell/AssetThumbnail.d.ts +12 -0
  90. package/dist/shell/AssetThumbnail.js +23 -0
  91. package/dist/shell/BottomDock.d.ts +25 -0
  92. package/dist/shell/BottomDock.js +40 -0
  93. package/dist/shell/CommandPalette.d.ts +12 -0
  94. package/dist/shell/CommandPalette.js +56 -0
  95. package/dist/shell/ConsolePanel.d.ts +8 -0
  96. package/dist/shell/ConsolePanel.js +45 -0
  97. package/dist/shell/ContentBrowser.d.ts +21 -0
  98. package/dist/shell/ContentBrowser.js +130 -0
  99. package/dist/shell/HierarchyPanel.d.ts +26 -0
  100. package/dist/shell/HierarchyPanel.js +387 -0
  101. package/dist/shell/NetworkWorkspacePanel.d.ts +11 -0
  102. package/dist/shell/NetworkWorkspacePanel.js +49 -0
  103. package/dist/shell/PlayModeBar.d.ts +12 -0
  104. package/dist/shell/PlayModeBar.js +27 -0
  105. package/dist/shell/ProfilerPanel.d.ts +10 -0
  106. package/dist/shell/ProfilerPanel.js +41 -0
  107. package/dist/shell/SceneToolbar.d.ts +43 -0
  108. package/dist/shell/SceneToolbar.js +122 -0
  109. package/dist/shell/StatusBar.d.ts +18 -0
  110. package/dist/shell/StatusBar.js +41 -0
  111. package/dist/shell/TopAppBar.d.ts +33 -0
  112. package/dist/shell/TopAppBar.js +64 -0
  113. package/dist/shell/ViewportOverlays.d.ts +23 -0
  114. package/dist/shell/ViewportOverlays.js +136 -0
  115. package/dist/shell/WorkspaceRail.d.ts +20 -0
  116. package/dist/shell/WorkspaceRail.js +31 -0
  117. package/dist/shell/cameraTelemetry.d.ts +27 -0
  118. package/dist/shell/cameraTelemetry.js +24 -0
  119. package/dist/shell/commandRegistry.d.ts +58 -0
  120. package/dist/shell/commandRegistry.js +133 -0
  121. package/dist/shell/consoleSink.d.ts +11 -0
  122. package/dist/shell/consoleSink.js +17 -0
  123. package/dist/shell/consoleStore.d.ts +27 -0
  124. package/dist/shell/consoleStore.js +43 -0
  125. package/dist/shell/fields.d.ts +39 -0
  126. package/dist/shell/fields.js +104 -0
  127. package/dist/shell/formatSavedRelative.d.ts +2 -0
  128. package/dist/shell/formatSavedRelative.js +14 -0
  129. package/dist/shell/glbThumbnailCache.d.ts +45 -0
  130. package/dist/shell/glbThumbnailCache.js +241 -0
  131. package/dist/shell/hierarchyA11y.d.ts +21 -0
  132. package/dist/shell/hierarchyA11y.js +35 -0
  133. package/dist/shell/icons.d.ts +13 -0
  134. package/dist/shell/icons.js +85 -0
  135. package/dist/shell/layoutStore.d.ts +68 -0
  136. package/dist/shell/layoutStore.js +156 -0
  137. package/dist/shell/pathFlythrough.d.ts +37 -0
  138. package/dist/shell/pathFlythrough.js +54 -0
  139. package/dist/shell/perfHistory.d.ts +70 -0
  140. package/dist/shell/perfHistory.js +130 -0
  141. package/dist/shell/renameObject.d.ts +3 -0
  142. package/dist/shell/renameObject.js +25 -0
  143. package/dist/shell/theme.d.ts +36 -0
  144. package/dist/shell/theme.js +37 -0
  145. package/dist/shell/ui.d.ts +84 -0
  146. package/dist/shell/ui.js +90 -0
  147. package/dist/shell/useGlbThumbnail.d.ts +8 -0
  148. package/dist/shell/useGlbThumbnail.js +19 -0
  149. package/dist/uiStore.d.ts +27 -0
  150. package/dist/uiStore.js +10 -0
  151. package/dist/viewportContextMenu.d.ts +4 -2
  152. package/dist/viewportContextMenu.js +5 -1
  153. package/package.json +4 -4
  154. package/skills/jgengine/SKILL.md +7 -4
  155. package/skills/jgengine/api.md +172 -79
  156. package/skills/jgengine/capabilities.md +104 -2
  157. package/skills/jgengine/recipes/minimal-game.md +88 -0
  158. package/skills/jgengine-editor/SKILL.md +18 -3
  159. package/skills/jgengine-editor/api.md +397 -18
  160. package/skills/jgengine-editor/capabilities.md +46 -0
  161. package/skills/jgengine-editor/reference.md +87 -0
  162. package/skills/level-design/SKILL.md +54 -0
  163. package/skills/level-design/agents/openai.yaml +4 -0
  164. package/skills/level-design/references/application-playbook.md +192 -0
  165. package/skills/level-design/references/field-guide.md +337 -0
  166. package/skills/level-design/references/live-editor-loop.md +179 -0
  167. package/dist/OutlinerPanel.d.ts +0 -14
  168. package/dist/OutlinerPanel.js +0 -84
  169. package/skills/jgengine/reference-cartridge.md +0 -72
@@ -0,0 +1,82 @@
1
+ import { type MultiplayerAdapterConfig, type MultiplayerAuthority } from "@jgengine/core/runtime/adapter";
2
+ import type { PresencePoseRow } from "@jgengine/core/runtime/transport";
3
+ /** Transport kind declared by the game, or `"unknown"` when the config is unreadable. */
4
+ export type EditorNetworkAdapterKind = MultiplayerAdapterConfig["kind"] | "unknown";
5
+ /**
6
+ * One online actor from a host-supplied presence feed. Fields mirror
7
+ * {@link PresencePoseRow} so hosts can forward backend rows without inventing shape.
8
+ */
9
+ export interface EditorNetworkPresenceActor {
10
+ userId: string;
11
+ position: {
12
+ x: number;
13
+ y: number;
14
+ z: number;
15
+ };
16
+ rotationY: number;
17
+ rotationPitch?: number;
18
+ lastSeenAt?: number;
19
+ }
20
+ /**
21
+ * Optional live session identity when a multiplayer backend is attached.
22
+ * Omit entirely when the host has no session — the panel reports offline honestly.
23
+ */
24
+ export interface EditorNetworkSession {
25
+ userId: string;
26
+ /** Joined room/server id when known; `null` means joined but id not reported. */
27
+ serverId?: string | null;
28
+ feedActions?: readonly string[];
29
+ }
30
+ /**
31
+ * Host-facing network inspection payload for the editor Network workspace.
32
+ *
33
+ * - Adapter fields come from the game definition (always real config).
34
+ * - `session` is present only when the host attached a live multiplayer backend.
35
+ * - `online` is `undefined` when the host has not supplied a presence feed; `[]` when
36
+ * the feed is connected but empty. Never fabricate actors.
37
+ */
38
+ export interface EditorNetworkSnapshot {
39
+ gameId: string;
40
+ adapterKind: EditorNetworkAdapterKind;
41
+ /** `null` for offline / single-player games. */
42
+ authority: MultiplayerAuthority | null;
43
+ /** Optional topology string from the adapter when declared. */
44
+ topology?: string;
45
+ /** Optional endpoint hint from the adapter (ws/socketio url, lan port, p2p room). */
46
+ endpoint?: string;
47
+ session?: EditorNetworkSession;
48
+ /**
49
+ * Online presence roster from the host.
50
+ * - `undefined` — no feed supplied (honest empty / waiting).
51
+ * - array — real rows only (may be empty).
52
+ */
53
+ online?: readonly EditorNetworkPresenceActor[];
54
+ /** Wall-clock ms of the last presence update when the host tracks it. */
55
+ updatedAt?: number;
56
+ }
57
+ /** Optional live presence/session injection from the editor host. */
58
+ export interface EditorNetworkPresenceInput {
59
+ userId?: string;
60
+ serverId?: string | null;
61
+ feedActions?: readonly string[];
62
+ online?: readonly PresencePoseRow[] | readonly EditorNetworkPresenceActor[];
63
+ updatedAt?: number;
64
+ }
65
+ /**
66
+ * Builds a Network workspace snapshot from the game's multiplayer config plus optional live
67
+ * presence rows. Adapter fields always reflect declared config; presence is only included when
68
+ * the host passes it.
69
+ *
70
+ * @internal
71
+ */
72
+ export declare function buildEditorNetworkSnapshot(args: {
73
+ gameId: string;
74
+ multiplayer: unknown;
75
+ presence?: EditorNetworkPresenceInput;
76
+ }): EditorNetworkSnapshot;
77
+ /**
78
+ * True when the snapshot represents a multiplayer-capable game (not offline/unknown-null).
79
+ *
80
+ * @internal
81
+ */
82
+ export declare function isNetworkMultiplayerConfigured(snapshot: EditorNetworkSnapshot): boolean;
@@ -0,0 +1,73 @@
1
+ import { adapterOf, resolveAuthority, } from "@jgengine/core/runtime/adapter";
2
+ function endpointOf(adapter) {
3
+ if (adapter === null)
4
+ return undefined;
5
+ if (adapter.kind === "ws" || adapter.kind === "socketio")
6
+ return adapter.url;
7
+ if (adapter.kind === "lan") {
8
+ const port = adapter.port ?? 8080;
9
+ const path = adapter.path ?? "/ws";
10
+ return `port ${port}${path}`;
11
+ }
12
+ if (adapter.kind === "p2p")
13
+ return adapter.room;
14
+ return undefined;
15
+ }
16
+ function topologyOf(adapter) {
17
+ if (adapter === null || adapter.kind === "offline")
18
+ return undefined;
19
+ return "topology" in adapter ? adapter.topology : undefined;
20
+ }
21
+ /**
22
+ * Builds a Network workspace snapshot from the game's multiplayer config plus optional live
23
+ * presence rows. Adapter fields always reflect declared config; presence is only included when
24
+ * the host passes it.
25
+ *
26
+ * @internal
27
+ */
28
+ export function buildEditorNetworkSnapshot(args) {
29
+ const adapter = adapterOf(args.multiplayer);
30
+ const adapterKind = adapter?.kind ?? "unknown";
31
+ const authority = resolveAuthority(args.multiplayer);
32
+ const snapshot = {
33
+ gameId: args.gameId,
34
+ adapterKind,
35
+ authority,
36
+ };
37
+ const topology = topologyOf(adapter);
38
+ if (topology !== undefined)
39
+ snapshot.topology = topology;
40
+ const endpoint = endpointOf(adapter);
41
+ if (endpoint !== undefined)
42
+ snapshot.endpoint = endpoint;
43
+ const presence = args.presence;
44
+ if (presence !== undefined) {
45
+ if (typeof presence.userId === "string" && presence.userId.length > 0) {
46
+ snapshot.session = {
47
+ userId: presence.userId,
48
+ ...(presence.serverId !== undefined ? { serverId: presence.serverId } : {}),
49
+ ...(presence.feedActions !== undefined ? { feedActions: presence.feedActions } : {}),
50
+ };
51
+ }
52
+ if (presence.online !== undefined) {
53
+ snapshot.online = presence.online.map((row) => ({
54
+ userId: row.userId,
55
+ position: { x: row.position.x, y: row.position.y, z: row.position.z },
56
+ rotationY: row.rotationY,
57
+ ...(row.rotationPitch !== undefined ? { rotationPitch: row.rotationPitch } : {}),
58
+ ...("lastSeenAt" in row && row.lastSeenAt !== undefined ? { lastSeenAt: row.lastSeenAt } : {}),
59
+ }));
60
+ }
61
+ if (presence.updatedAt !== undefined)
62
+ snapshot.updatedAt = presence.updatedAt;
63
+ }
64
+ return snapshot;
65
+ }
66
+ /**
67
+ * True when the snapshot represents a multiplayer-capable game (not offline/unknown-null).
68
+ *
69
+ * @internal
70
+ */
71
+ export function isNetworkMultiplayerConfigured(snapshot) {
72
+ return snapshot.adapterKind !== "offline" && snapshot.adapterKind !== "unknown" && snapshot.authority !== null;
73
+ }
@@ -0,0 +1,12 @@
1
+ import { type EditorDocument } from "@jgengine/core/editor/index";
2
+ /** One option in the Parent-to… picker / inspector parent field. @internal */
3
+ export interface ParentCandidate {
4
+ id: string;
5
+ label: string;
6
+ }
7
+ /**
8
+ * Placeable objects that may become parents of every id in `childIds` without creating a cycle:
9
+ * excludes the children themselves and all of their descendants.
10
+ * @internal
11
+ */
12
+ export declare function listParentCandidates(document: EditorDocument, childIds: readonly string[]): ParentCandidate[];
@@ -0,0 +1,25 @@
1
+ import { collectDescendants, } from "@jgengine/core/editor/index";
2
+ /**
3
+ * Placeable objects that may become parents of every id in `childIds` without creating a cycle:
4
+ * excludes the children themselves and all of their descendants.
5
+ * @internal
6
+ */
7
+ export function listParentCandidates(document, childIds) {
8
+ if (childIds.length === 0)
9
+ return [];
10
+ const banned = collectDescendants(document, childIds);
11
+ for (const id of childIds)
12
+ banned.add(id);
13
+ const labelOf = (node) => node.label ?? node.id;
14
+ const candidates = [
15
+ ...document.markers.map((m) => ({ id: m.id, label: labelOf(m) })),
16
+ ...document.volumes.map((v) => ({ id: v.id, label: labelOf(v) })),
17
+ ...document.paths.map((p) => ({ id: p.id, label: labelOf(p) })),
18
+ ...document.annotations.map((n) => ({
19
+ id: n.id,
20
+ label: n.text.slice(0, 30) || n.id,
21
+ })),
22
+ ].filter((entry) => !banned.has(entry.id));
23
+ candidates.sort((a, b) => a.label.localeCompare(b.label) || a.id.localeCompare(b.id));
24
+ return candidates;
25
+ }
package/dist/session.d.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  import { type DocumentLiveSync, type DocumentPatch, type EditorCatalogDefinition, type EditorCommand, type EditorDocument, type EditorGridPaletteEntry, type EditorKindVisibility, type EditorLayersInput, type EditorSession, type EditorSessionState, type RuntimeEntityState, type RuntimePlayControl } from "@jgengine/core/editor/index";
2
- import { type TerraformMode, type TerrainMaterialLayer } from "@jgengine/core/world/terraform";
3
- /** How the editor hosts the game: frozen placement view, roamable world, or the real game. */
4
- export type EditorRunMode = "edit" | "walk" | "play";
2
+ import type { TerraformMode, TerrainMaterialLayer } from "@jgengine/core/world/terraform";
3
+ import type { ParamSchema } from "@jgengine/core/scene/sceneKinds";
4
+ import type { TerrainField } from "@jgengine/core/world/terrain";
5
+ /** How the editor hosts the game: frozen placement view, roamable world, the real game, or HUD-layout authoring. */
6
+ export type EditorRunMode = "edit" | "walk" | "play" | "hud";
7
+ /** The accepted run modes, in canonical order — the runtime guard behind {@link EditorRunMode}. @internal */
8
+ export declare const EDITOR_RUN_MODES: readonly EditorRunMode[];
5
9
  /** RPC request shapes the editor host understands, used by the MCP bridge and UI. */
6
10
  export type EditorBridgeRequest = {
7
11
  method: "editor_status";
@@ -24,6 +28,29 @@ export type EditorBridgeRequest = {
24
28
  entryId: string;
25
29
  patch: Record<string, unknown>;
26
30
  label?: string;
31
+ } | {
32
+ method: "add_catalog_entry";
33
+ catalogId: string;
34
+ entryId: string;
35
+ meta?: Record<string, unknown>;
36
+ label?: string;
37
+ } | {
38
+ method: "remove_catalog_entry";
39
+ catalogId: string;
40
+ entryId: string;
41
+ } | {
42
+ method: "add_catalog";
43
+ catalogId: string;
44
+ label?: string;
45
+ schema?: ParamSchema;
46
+ } | {
47
+ method: "remove_catalog";
48
+ catalogId: string;
49
+ } | {
50
+ method: "set_catalog_schema";
51
+ catalogId: string;
52
+ schema: ParamSchema;
53
+ label?: string;
27
54
  } | {
28
55
  method: "list_selection";
29
56
  } | {
@@ -72,6 +99,10 @@ export type EditorBridgeRequest = {
72
99
  method: "set_meta";
73
100
  id: string;
74
101
  patch: Record<string, unknown>;
102
+ } | {
103
+ method: "apply_preset";
104
+ id: string;
105
+ preset: string;
75
106
  } | {
76
107
  method: "select";
77
108
  ids: string[];
@@ -164,6 +195,11 @@ export type EditorBridgeRequest = {
164
195
  } | {
165
196
  method: "convert_scatter";
166
197
  pathId: string;
198
+ } | {
199
+ method: "bake_minimap";
200
+ padding?: number;
201
+ resolution?: number;
202
+ waterLevel?: number;
167
203
  } | {
168
204
  method: "add_foliage";
169
205
  points: {
@@ -236,6 +272,11 @@ export type EditorBridgeRequest = {
236
272
  } | {
237
273
  method: "select_collection";
238
274
  id: string;
275
+ } | {
276
+ method: "set_object_flags";
277
+ ids: string[];
278
+ locked?: boolean;
279
+ hidden?: boolean;
239
280
  } | {
240
281
  method: "batch_set_properties";
241
282
  ids: string[];
@@ -402,6 +443,11 @@ export interface EditorAssetInfo {
402
443
  }
403
444
  /** Rolling frame-rate sample published by the in-canvas PerfProbe. */
404
445
  export interface EditorPerfSample {
446
+ /**
447
+ * JS heap used in megabytes when the browser exposes `performance.memory` (Chromium).
448
+ * Omitted entirely when unavailable — never fabricated.
449
+ */
450
+ memoryMb?: number;
405
451
  fps: number;
406
452
  frameMs: number;
407
453
  drawCalls: number;
@@ -419,6 +465,25 @@ export interface EditorPerfSample {
419
465
  rebuildMs?: number;
420
466
  /** raycastMs + rebuildMs — total authoring overhead separated from the frame/sim budget. */
421
467
  authoringMs?: number;
468
+ /**
469
+ * Average sim-driver time (ms) from core `devtools.frame` when FrameDriver has recorded frames.
470
+ * Same source as `debug_snapshot` / F2+D Perf panel — omitted when no frame samples exist
471
+ * (e.g. pure edit mode with no runtime tick). Never fabricated.
472
+ */
473
+ simMs?: number;
474
+ /**
475
+ * Average outside-sim time (ms) = frame − sim (render / React / GPU / GC / vsync miss).
476
+ * Same availability rule as `simMs`. Matches `FrameStats.avgOutsideMs`.
477
+ */
478
+ outsideMs?: number;
479
+ /**
480
+ * Top named sim phases (avg ms) from the same frame window when `measure("name", …)` marks exist.
481
+ * Omitted when the frame tracker has no named phases.
482
+ */
483
+ phases?: readonly {
484
+ name: string;
485
+ avgMs: number;
486
+ }[];
422
487
  }
423
488
  /** The live editor's global control surface — session, visibility, camera focus, assets, mode, RPC. */
424
489
  export interface EditorHostApi {
@@ -449,12 +514,20 @@ export interface EditorHostApi {
449
514
  getCatalogDefinitions(): readonly EditorCatalogDefinition[];
450
515
  getPerf(): EditorPerfSample | null;
451
516
  setPerf(sample: EditorPerfSample): void;
517
+ /**
518
+ * The live composed ground field (base procedural terrain + document sculpt) from the mounted
519
+ * viewport, or null when no viewport is mounted. `bake_minimap` reads it to rasterize authored
520
+ * terrain; it exists only while the editor world is mounted, so headless CLIs get a null here.
521
+ */
522
+ getTerrainSampler(): TerrainField | null;
523
+ setTerrainSampler(field: TerrainField | null): void;
452
524
  getMode(): EditorRunMode;
453
525
  setMode(mode: EditorRunMode): void;
454
526
  subscribeMode(listener: (mode: EditorRunMode) => void): () => void;
455
527
  /** Play-mode pause/step gate consumed by the runtime publisher. */
456
528
  getPlayControl(): RuntimePlayControl;
457
- setPlayControl(next: RuntimePlayControl): void;
529
+ /** Normalizes and stores the play control, notifies listeners, and returns the applied value. */
530
+ setPlayControl(next: RuntimePlayControl): RuntimePlayControl;
458
531
  subscribePlayControl(listener: (play: RuntimePlayControl) => void): () => void;
459
532
  handle(request: EditorBridgeRequest): EditorBridgeResponse;
460
533
  }