@jgengine/editor 0.10.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.
- package/CHANGELOG.md +27 -1
- package/README.md +12 -0
- package/dist/AssetBrowser.d.ts +26 -1
- package/dist/AssetBrowser.js +54 -1
- package/dist/AssetDropZone.d.ts +9 -0
- package/dist/AssetDropZone.js +65 -0
- package/dist/CatalogsPanel.d.ts +4 -2
- package/dist/CatalogsPanel.js +162 -9
- package/dist/CityPreview.d.ts +11 -0
- package/dist/CityPreview.js +45 -0
- package/dist/CollectionsPanel.js +5 -5
- package/dist/DebugDraw.d.ts +3 -1
- package/dist/DebugDraw.js +37 -19
- package/dist/EditorApp.d.ts +9 -1
- package/dist/EditorApp.js +208 -37
- package/dist/EditorChrome.d.ts +25 -6
- package/dist/EditorChrome.js +310 -118
- package/dist/InspectorPanel.d.ts +17 -7
- package/dist/InspectorPanel.js +173 -27
- package/dist/LightingPanel.d.ts +11 -0
- package/dist/LightingPanel.js +99 -0
- package/dist/MaterialsWorkspacePanel.d.ts +12 -0
- package/dist/MaterialsWorkspacePanel.js +86 -0
- package/dist/ParentPickerMenu.d.ts +13 -0
- package/dist/ParentPickerMenu.js +33 -0
- package/dist/PerfProbe.js +69 -2
- package/dist/PrefabsPanel.js +5 -5
- package/dist/RuntimePlayBridge.d.ts +5 -3
- package/dist/RuntimePlayBridge.js +6 -13
- package/dist/ScatterPreview.d.ts +3 -1
- package/dist/ScatterPreview.js +10 -7
- package/dist/SchemaInspector.js +21 -8
- package/dist/ScriptingPanel.d.ts +15 -0
- package/dist/ScriptingPanel.js +46 -0
- package/dist/SelectionGizmo.js +114 -30
- package/dist/StandaloneEditor.d.ts +16 -9
- package/dist/StandaloneEditor.js +19 -20
- package/dist/TerrainPanel.d.ts +3 -2
- package/dist/TerrainPanel.js +16 -5
- package/dist/TerrainReadout.d.ts +17 -0
- package/dist/TerrainReadout.js +163 -0
- package/dist/TerrainReadoutHud.d.ts +9 -0
- package/dist/TerrainReadoutHud.js +20 -0
- package/dist/TerrainSculpt.js +98 -59
- package/dist/agent/AgentPanel.d.ts +5 -2
- package/dist/agent/AgentPanel.js +11 -6
- package/dist/agent/toolBridge.js +5 -0
- package/dist/assetImport.d.ts +36 -0
- package/dist/assetImport.js +66 -0
- package/dist/authoredComponentMeta.d.ts +25 -0
- package/dist/authoredComponentMeta.js +65 -0
- package/dist/gizmoPivot.d.ts +4 -0
- package/dist/gizmoPivot.js +34 -0
- package/dist/handlers/catalogs.d.ts +3 -0
- package/dist/handlers/catalogs.js +137 -0
- package/dist/handlers/collections.d.ts +3 -0
- package/dist/handlers/collections.js +57 -0
- package/dist/handlers/context.d.ts +36 -0
- package/dist/handlers/context.js +1 -0
- package/dist/handlers/document.d.ts +3 -0
- package/dist/handlers/document.js +350 -0
- package/dist/handlers/grids.d.ts +3 -0
- package/dist/handlers/grids.js +142 -0
- package/dist/handlers/hierarchy.d.ts +3 -0
- package/dist/handlers/hierarchy.js +55 -0
- package/dist/handlers/index.d.ts +8 -0
- package/dist/handlers/index.js +23 -0
- package/dist/handlers/minimap.d.ts +9 -0
- package/dist/handlers/minimap.js +32 -0
- package/dist/handlers/runtime.d.ts +3 -0
- package/dist/handlers/runtime.js +191 -0
- package/dist/handlers/terrain.d.ts +3 -0
- package/dist/handlers/terrain.js +204 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/listDocumentTriggers.d.ts +42 -0
- package/dist/listDocumentTriggers.js +49 -0
- package/dist/materialAssignments.d.ts +63 -0
- package/dist/materialAssignments.js +84 -0
- package/dist/mcp/fieldSpec.d.ts +32 -0
- package/dist/mcp/fieldSpec.js +173 -0
- package/dist/mcp/rpcRequest.d.ts +8 -5
- package/dist/mcp/rpcRequest.js +72 -83
- package/dist/mcp/tools.js +104 -763
- package/dist/networkSnapshot.d.ts +82 -0
- package/dist/networkSnapshot.js +73 -0
- package/dist/parentCandidates.d.ts +12 -0
- package/dist/parentCandidates.js +25 -0
- package/dist/perfPill.d.ts +21 -0
- package/dist/perfPill.js +20 -0
- package/dist/session.d.ts +167 -5
- package/dist/session.js +36 -879
- package/dist/shell/AnimationPanel.d.ts +17 -0
- package/dist/shell/AnimationPanel.js +134 -0
- package/dist/shell/AssetThumbnail.d.ts +12 -0
- package/dist/shell/AssetThumbnail.js +23 -0
- package/dist/shell/BottomDock.d.ts +25 -0
- package/dist/shell/BottomDock.js +40 -0
- package/dist/shell/CommandPalette.d.ts +12 -0
- package/dist/shell/CommandPalette.js +56 -0
- package/dist/shell/ConsolePanel.d.ts +8 -0
- package/dist/shell/ConsolePanel.js +45 -0
- package/dist/shell/ContentBrowser.d.ts +21 -0
- package/dist/shell/ContentBrowser.js +130 -0
- package/dist/shell/HierarchyPanel.d.ts +26 -0
- package/dist/shell/HierarchyPanel.js +387 -0
- package/dist/shell/NetworkWorkspacePanel.d.ts +11 -0
- package/dist/shell/NetworkWorkspacePanel.js +49 -0
- package/dist/shell/PlayModeBar.d.ts +12 -0
- package/dist/shell/PlayModeBar.js +27 -0
- package/dist/shell/ProfilerPanel.d.ts +10 -0
- package/dist/shell/ProfilerPanel.js +41 -0
- package/dist/shell/SceneToolbar.d.ts +43 -0
- package/dist/shell/SceneToolbar.js +122 -0
- package/dist/shell/StatusBar.d.ts +18 -0
- package/dist/shell/StatusBar.js +41 -0
- package/dist/shell/TopAppBar.d.ts +33 -0
- package/dist/shell/TopAppBar.js +64 -0
- package/dist/shell/ViewportOverlays.d.ts +23 -0
- package/dist/shell/ViewportOverlays.js +136 -0
- package/dist/shell/WorkspaceRail.d.ts +20 -0
- package/dist/shell/WorkspaceRail.js +31 -0
- package/dist/shell/cameraTelemetry.d.ts +27 -0
- package/dist/shell/cameraTelemetry.js +24 -0
- package/dist/shell/commandRegistry.d.ts +58 -0
- package/dist/shell/commandRegistry.js +133 -0
- package/dist/shell/consoleSink.d.ts +11 -0
- package/dist/shell/consoleSink.js +17 -0
- package/dist/shell/consoleStore.d.ts +27 -0
- package/dist/shell/consoleStore.js +43 -0
- package/dist/shell/fields.d.ts +39 -0
- package/dist/shell/fields.js +104 -0
- package/dist/shell/formatSavedRelative.d.ts +2 -0
- package/dist/shell/formatSavedRelative.js +14 -0
- package/dist/shell/glbThumbnailCache.d.ts +45 -0
- package/dist/shell/glbThumbnailCache.js +241 -0
- package/dist/shell/hierarchyA11y.d.ts +21 -0
- package/dist/shell/hierarchyA11y.js +35 -0
- package/dist/shell/icons.d.ts +13 -0
- package/dist/shell/icons.js +85 -0
- package/dist/shell/layoutStore.d.ts +68 -0
- package/dist/shell/layoutStore.js +156 -0
- package/dist/shell/pathFlythrough.d.ts +37 -0
- package/dist/shell/pathFlythrough.js +54 -0
- package/dist/shell/perfHistory.d.ts +70 -0
- package/dist/shell/perfHistory.js +130 -0
- package/dist/shell/renameObject.d.ts +3 -0
- package/dist/shell/renameObject.js +25 -0
- package/dist/shell/theme.d.ts +36 -0
- package/dist/shell/theme.js +37 -0
- package/dist/shell/ui.d.ts +84 -0
- package/dist/shell/ui.js +90 -0
- package/dist/shell/useGlbThumbnail.d.ts +8 -0
- package/dist/shell/useGlbThumbnail.js +19 -0
- package/dist/terrainReadoutStore.d.ts +19 -0
- package/dist/terrainReadoutStore.js +36 -0
- package/dist/uiStore.d.ts +33 -0
- package/dist/uiStore.js +13 -0
- package/dist/viewportContextMenu.d.ts +4 -2
- package/dist/viewportContextMenu.js +5 -1
- package/package.json +4 -4
- package/skills/jgengine/SKILL.md +35 -804
- package/skills/jgengine/api.md +190 -79
- package/skills/jgengine/capabilities.md +112 -2
- package/skills/jgengine/recipes/minimal-game.md +88 -0
- package/skills/jgengine-editor/SKILL.md +29 -362
- package/skills/jgengine-editor/api.md +519 -18
- package/skills/jgengine-editor/capabilities.md +91 -0
- package/skills/jgengine-editor/reference.md +113 -0
- package/skills/level-design/SKILL.md +54 -0
- package/skills/level-design/agents/openai.yaml +4 -0
- package/skills/level-design/references/application-playbook.md +192 -0
- package/skills/level-design/references/field-guide.md +337 -0
- package/skills/level-design/references/live-editor-loop.md +179 -0
- package/dist/OutlinerPanel.d.ts +0 -14
- package/dist/OutlinerPanel.js +0 -84
- package/skills/jgengine/reference-cartridge.md +0 -72
- package/skills/jgengine/reference-orphans.md +0 -9
- package/skills/jgengine/reference-systems.md +0 -60
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Toolbar perf-pill health, separating an idle render-on-demand loop from a genuinely slow frame. */
|
|
2
|
+
export type EditorPerfTone = "idle" | "healthy" | "busy";
|
|
3
|
+
/**
|
|
4
|
+
* FPS at or below which an *actively rendering* editor frame is treated as struggling.
|
|
5
|
+
* Only applied when the loop is active — an idle / browser-throttled loop never trips it.
|
|
6
|
+
*/
|
|
7
|
+
export declare const EDITOR_PERF_LOW_FPS = 30;
|
|
8
|
+
/**
|
|
9
|
+
* Classify a perf sample for the toolbar pill. The editor renders `frameloop="always"`, so a
|
|
10
|
+
* healthy visible loop sits at ~60fps; a low wall-clock fps only appears when the browser throttles
|
|
11
|
+
* rAF (backgrounded tab / headless screenshot) while nothing is happening. `PerfProbe` measures
|
|
12
|
+
* that idleness (no camera move, no raycast/rebuild, no scene change) and reports it as `active:false`,
|
|
13
|
+
* which classifies here as `"idle"` instead of the red danger cue. The danger cue (`"busy"`) is
|
|
14
|
+
* reserved for sustained low fps while the loop is genuinely active (orbit / drag / sculpt) — the
|
|
15
|
+
* regression actually worth surfacing.
|
|
16
|
+
* @internal — drives the editor toolbar perf pill; not game-facing.
|
|
17
|
+
*/
|
|
18
|
+
export declare function classifyEditorPerf(sample: {
|
|
19
|
+
fps: number;
|
|
20
|
+
active: boolean;
|
|
21
|
+
}): EditorPerfTone;
|
package/dist/perfPill.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FPS at or below which an *actively rendering* editor frame is treated as struggling.
|
|
3
|
+
* Only applied when the loop is active — an idle / browser-throttled loop never trips it.
|
|
4
|
+
*/
|
|
5
|
+
export const EDITOR_PERF_LOW_FPS = 30;
|
|
6
|
+
/**
|
|
7
|
+
* Classify a perf sample for the toolbar pill. The editor renders `frameloop="always"`, so a
|
|
8
|
+
* healthy visible loop sits at ~60fps; a low wall-clock fps only appears when the browser throttles
|
|
9
|
+
* rAF (backgrounded tab / headless screenshot) while nothing is happening. `PerfProbe` measures
|
|
10
|
+
* that idleness (no camera move, no raycast/rebuild, no scene change) and reports it as `active:false`,
|
|
11
|
+
* which classifies here as `"idle"` instead of the red danger cue. The danger cue (`"busy"`) is
|
|
12
|
+
* reserved for sustained low fps while the loop is genuinely active (orbit / drag / sculpt) — the
|
|
13
|
+
* regression actually worth surfacing.
|
|
14
|
+
* @internal — drives the editor toolbar perf pill; not game-facing.
|
|
15
|
+
*/
|
|
16
|
+
export function classifyEditorPerf(sample) {
|
|
17
|
+
if (!sample.active)
|
|
18
|
+
return "idle";
|
|
19
|
+
return sample.fps < EDITOR_PERF_LOW_FPS ? "busy" : "healthy";
|
|
20
|
+
}
|
package/dist/session.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import { type DocumentLiveSync, type DocumentPatch, type EditorCatalogDefinition, type EditorCommand, type EditorDocument, type EditorKindVisibility, type EditorLayersInput, type EditorSession, type EditorSessionState, type RuntimeEntityState, type RuntimePlayControl } from "@jgengine/core/editor/index";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
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, 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[];
|
|
@@ -246,6 +287,89 @@ export type EditorBridgeRequest = {
|
|
|
246
287
|
method: "assign_material";
|
|
247
288
|
ids: string[];
|
|
248
289
|
materialId: string;
|
|
290
|
+
} | {
|
|
291
|
+
method: "list_grids";
|
|
292
|
+
} | {
|
|
293
|
+
method: "get_grid_cell";
|
|
294
|
+
id: string;
|
|
295
|
+
col: number;
|
|
296
|
+
row: number;
|
|
297
|
+
} | {
|
|
298
|
+
method: "add_grid_layer";
|
|
299
|
+
id: string;
|
|
300
|
+
kind: string;
|
|
301
|
+
cols: number;
|
|
302
|
+
rows: number;
|
|
303
|
+
label?: string;
|
|
304
|
+
cellSize?: number;
|
|
305
|
+
origin?: {
|
|
306
|
+
x: number;
|
|
307
|
+
y: number;
|
|
308
|
+
z: number;
|
|
309
|
+
};
|
|
310
|
+
axes?: "xz" | "xy";
|
|
311
|
+
empty?: string;
|
|
312
|
+
palette?: EditorGridPaletteEntry[];
|
|
313
|
+
} | {
|
|
314
|
+
method: "remove_grid_layer";
|
|
315
|
+
id: string;
|
|
316
|
+
} | {
|
|
317
|
+
method: "set_grid_layer";
|
|
318
|
+
id: string;
|
|
319
|
+
label?: string;
|
|
320
|
+
kind?: string;
|
|
321
|
+
visible?: boolean;
|
|
322
|
+
empty?: string;
|
|
323
|
+
cellSize?: number;
|
|
324
|
+
origin?: {
|
|
325
|
+
x: number;
|
|
326
|
+
y: number;
|
|
327
|
+
z: number;
|
|
328
|
+
};
|
|
329
|
+
axes?: "xz" | "xy";
|
|
330
|
+
palette?: EditorGridPaletteEntry[];
|
|
331
|
+
} | {
|
|
332
|
+
method: "paint_grid_cells";
|
|
333
|
+
id: string;
|
|
334
|
+
cells: {
|
|
335
|
+
col: number;
|
|
336
|
+
row: number;
|
|
337
|
+
value: string;
|
|
338
|
+
}[];
|
|
339
|
+
} | {
|
|
340
|
+
method: "fill_grid_rect";
|
|
341
|
+
id: string;
|
|
342
|
+
col0: number;
|
|
343
|
+
row0: number;
|
|
344
|
+
col1: number;
|
|
345
|
+
row1: number;
|
|
346
|
+
value: string;
|
|
347
|
+
} | {
|
|
348
|
+
method: "flood_fill_grid";
|
|
349
|
+
id: string;
|
|
350
|
+
col: number;
|
|
351
|
+
row: number;
|
|
352
|
+
value: string;
|
|
353
|
+
} | {
|
|
354
|
+
method: "resize_grid_layer";
|
|
355
|
+
id: string;
|
|
356
|
+
cols: number;
|
|
357
|
+
rows: number;
|
|
358
|
+
} | {
|
|
359
|
+
method: "import_grid";
|
|
360
|
+
id: string;
|
|
361
|
+
kind: string;
|
|
362
|
+
format: "ascii" | "csv";
|
|
363
|
+
text: string;
|
|
364
|
+
empty?: string;
|
|
365
|
+
cellSize?: number;
|
|
366
|
+
origin?: {
|
|
367
|
+
x: number;
|
|
368
|
+
y: number;
|
|
369
|
+
z: number;
|
|
370
|
+
};
|
|
371
|
+
glyphMap?: Record<string, string>;
|
|
372
|
+
palette?: EditorGridPaletteEntry[];
|
|
249
373
|
} | {
|
|
250
374
|
method: "push_document_patch";
|
|
251
375
|
patch: DocumentPatch;
|
|
@@ -319,17 +443,47 @@ export interface EditorAssetInfo {
|
|
|
319
443
|
}
|
|
320
444
|
/** Rolling frame-rate sample published by the in-canvas PerfProbe. */
|
|
321
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;
|
|
322
451
|
fps: number;
|
|
323
452
|
frameMs: number;
|
|
324
453
|
drawCalls: number;
|
|
325
454
|
triangles: number;
|
|
326
455
|
sampledAt: number;
|
|
456
|
+
/**
|
|
457
|
+
* Whether the sampled window saw camera or edit activity. `false` means the render-on-demand /
|
|
458
|
+
* browser-throttled loop is idle, so a low `fps` is expected pacing rather than lag — the pill
|
|
459
|
+
* shows a neutral "idle" instead of the red danger cue.
|
|
460
|
+
*/
|
|
461
|
+
active: boolean;
|
|
327
462
|
/** Avg viewport raycast (pick) time this window — editor-authoring cost, not sim cost. */
|
|
328
463
|
raycastMs?: number;
|
|
329
464
|
/** Avg preview-mesh rebuild (displace) time this window — editor-authoring cost, not sim cost. */
|
|
330
465
|
rebuildMs?: number;
|
|
331
466
|
/** raycastMs + rebuildMs — total authoring overhead separated from the frame/sim budget. */
|
|
332
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
|
+
}[];
|
|
333
487
|
}
|
|
334
488
|
/** The live editor's global control surface — session, visibility, camera focus, assets, mode, RPC. */
|
|
335
489
|
export interface EditorHostApi {
|
|
@@ -360,12 +514,20 @@ export interface EditorHostApi {
|
|
|
360
514
|
getCatalogDefinitions(): readonly EditorCatalogDefinition[];
|
|
361
515
|
getPerf(): EditorPerfSample | null;
|
|
362
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;
|
|
363
524
|
getMode(): EditorRunMode;
|
|
364
525
|
setMode(mode: EditorRunMode): void;
|
|
365
526
|
subscribeMode(listener: (mode: EditorRunMode) => void): () => void;
|
|
366
527
|
/** Play-mode pause/step gate consumed by the runtime publisher. */
|
|
367
528
|
getPlayControl(): RuntimePlayControl;
|
|
368
|
-
|
|
529
|
+
/** Normalizes and stores the play control, notifies listeners, and returns the applied value. */
|
|
530
|
+
setPlayControl(next: RuntimePlayControl): RuntimePlayControl;
|
|
369
531
|
subscribePlayControl(listener: (play: RuntimePlayControl) => void): () => void;
|
|
370
532
|
handle(request: EditorBridgeRequest): EditorBridgeResponse;
|
|
371
533
|
}
|