@umicat/phaser-sdk 1.0.5 → 1.0.7
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/dist/editor/EditorBridge.js +97 -3
- package/dist/editor/EditorOverlayScene.d.ts +0 -14
- package/dist/editor/EditorOverlayScene.js +9 -33
- package/dist/editor/EditorState.d.ts +10 -0
- package/dist/editor/EditorState.js +7 -0
- package/dist/index.d.ts +1 -1
- package/dist/protocol.d.ts +31 -1
- package/dist/scene/types.d.ts +21 -0
- package/package.json +1 -1
|
@@ -11,7 +11,7 @@ import { resolveRenderScript } from '../scene/renderScripts.js';
|
|
|
11
11
|
import { getManifest } from '../scene/SceneLoader.js';
|
|
12
12
|
import { getRules, patchRule } from '../scene/Rules.js';
|
|
13
13
|
import { EditorOverlayScene, EDITOR_OVERLAY_KEY } from './EditorOverlayScene.js';
|
|
14
|
-
import { getEditorState, setEditorActive, setSelection, getSelection, getEditorMode, setEditorMode, setDebugOverlayState, setTilemapToolState, } from './EditorState.js';
|
|
14
|
+
import { getEditorState, setEditorActive, setSelection, getSelection, getEditorMode, setEditorMode, getActiveSceneId, setActiveSceneId, setDebugOverlayState, setTilemapToolState, } from './EditorState.js';
|
|
15
15
|
import { applyHudPatch, createHudEntityInScene, deleteHudEntityFromScene, findHudRegistry, findHudSceneFile, UMICAT_HUD_SCENE_KEY, } from '../scene/HudRuntime.js';
|
|
16
16
|
/**
|
|
17
17
|
* EditorBridge wires the host (home-ui) to the iframe's Phaser game during
|
|
@@ -126,7 +126,67 @@ function handleMessage(game, msg) {
|
|
|
126
126
|
// load when manifestAsset present); fire-and-forget the promise.
|
|
127
127
|
void handleEditTilemap(game, msg.entityId, msg.ops, msg.manifestAsset);
|
|
128
128
|
break;
|
|
129
|
+
case 'umicat:editor:loadScene':
|
|
130
|
+
// Scene browser (design 01 §6.1) — switch to a different world scene.
|
|
131
|
+
handleLoadScene(game, msg.sceneId, msg.sceneFile, msg.manifest);
|
|
132
|
+
break;
|
|
133
|
+
case 'umicat:editor:updateManifest':
|
|
134
|
+
// Scene browser — non-switch structural op (create / rename / reorder
|
|
135
|
+
// / folders / set-initial) refreshed the manifest on disk; mirror it
|
|
136
|
+
// into the iframe's cache so it never goes stale.
|
|
137
|
+
handleUpdateManifest(game, msg.manifest);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// --- Scene browser (design 01 §6.1) ----------------------------------------
|
|
142
|
+
/**
|
|
143
|
+
* Replace the game-global JSON cache entry under `key` with `value`. The
|
|
144
|
+
* remove + add pair changes object identity, which is what makes
|
|
145
|
+
* SceneLoader's `getOrInitState` rebuild its assetsById index on the next
|
|
146
|
+
* `getManifest` call.
|
|
147
|
+
*/
|
|
148
|
+
function replaceJsonCacheEntry(game, key, value) {
|
|
149
|
+
if (game.cache.json.exists(key))
|
|
150
|
+
game.cache.json.remove(key);
|
|
151
|
+
game.cache.json.add(key, value);
|
|
152
|
+
}
|
|
153
|
+
function handleLoadScene(game, sceneId, sceneFile, manifest) {
|
|
154
|
+
if (manifest)
|
|
155
|
+
replaceJsonCacheEntry(game, 'umicat:manifest', manifest);
|
|
156
|
+
if (sceneFile)
|
|
157
|
+
replaceJsonCacheEntry(game, `umicat:scene:${sceneId}`, sceneFile);
|
|
158
|
+
setActiveSceneId(game, sceneId);
|
|
159
|
+
setSelection(game, null);
|
|
160
|
+
// Allow the post-restart enterEdit to post a fresh snapshot — that
|
|
161
|
+
// snapshot (a new `sceneLoaded`) is the host's switch ACK.
|
|
162
|
+
delete game[SNAPSHOT_POSTED_FLAG];
|
|
163
|
+
const scene = findWorldScene(game);
|
|
164
|
+
if (!scene) {
|
|
165
|
+
// Boot race — no world scene yet. The activeSceneId is set; when the
|
|
166
|
+
// scene boots it loads whatever the template's init data says, and the
|
|
167
|
+
// PRE_STEP hook completes editor install. Rare enough to warn.
|
|
168
|
+
// eslint-disable-next-line no-console
|
|
169
|
+
console.warn('[umicat/editor] loadScene: no world scene to restart yet');
|
|
170
|
+
return;
|
|
129
171
|
}
|
|
172
|
+
// Tear down editor chrome BEFORE the restart. The restart destroys the
|
|
173
|
+
// scene's cameras, but the game-bag EDITOR_CAM_KEY ref would go stale
|
|
174
|
+
// (still truthy) — the PRE_STEP late-boot hook checks `!getEditorCamera`
|
|
175
|
+
// and would never re-run enterEdit. Uninstalling clears the key so the
|
|
176
|
+
// hook fires once the scene rebuilds, exactly like the boot-flag path.
|
|
177
|
+
uninstallVoidFill(game);
|
|
178
|
+
uninstallEditorCameras(game);
|
|
179
|
+
// Restart with the new sceneId. The template's GameScene.init({ sceneId })
|
|
180
|
+
// accepts this; loadWorldScene then reads the scene JSON we just cached.
|
|
181
|
+
// The PRE_STEP late-boot hook (1.0.6) re-runs the idempotent enterEdit
|
|
182
|
+
// once the scene rebuilds, re-installing editor chrome and posting the
|
|
183
|
+
// fresh sceneLoaded.
|
|
184
|
+
scene.scene.restart({ sceneId });
|
|
185
|
+
}
|
|
186
|
+
function handleUpdateManifest(game, manifest) {
|
|
187
|
+
if (!manifest)
|
|
188
|
+
return;
|
|
189
|
+
replaceJsonCacheEntry(game, 'umicat:manifest', manifest);
|
|
130
190
|
}
|
|
131
191
|
// --- Enter / exit ---------------------------------------------------------
|
|
132
192
|
function enterEdit(game) {
|
|
@@ -233,6 +293,17 @@ function installPauseEnforcement(game) {
|
|
|
233
293
|
if (!getEditorState(game).active)
|
|
234
294
|
return;
|
|
235
295
|
pauseActiveNonEditor(game);
|
|
296
|
+
// Late-boot completion (1.0.6). The boot-flag path (`umicatEdit=1`)
|
|
297
|
+
// runs enterEdit BEFORE any scene exists — the scene-dependent
|
|
298
|
+
// installs (editor cameras, canvas expand, void fill, overlay launch)
|
|
299
|
+
// all no-op'd, leaving an editor that is paused and snapshotted but
|
|
300
|
+
// can't pan/zoom or pick. Once the world scene appears, re-run the
|
|
301
|
+
// full idempotent enterEdit to install them. The editor-camera check
|
|
302
|
+
// makes this fire at most once per enter: after a successful install
|
|
303
|
+
// it's permanently truthy (cheap per-frame no-op otherwise).
|
|
304
|
+
if (!getEditorCamera(game) && findWorldScene(game)) {
|
|
305
|
+
enterEdit(game);
|
|
306
|
+
}
|
|
236
307
|
};
|
|
237
308
|
game.events.on(Phaser.Core.Events.PRE_STEP, handler);
|
|
238
309
|
bag[PAUSE_ENFORCER_FLAG] = handler;
|
|
@@ -412,6 +483,10 @@ function postSceneSnapshot(game) {
|
|
|
412
483
|
manifest,
|
|
413
484
|
});
|
|
414
485
|
game[SNAPSHOT_POSTED_FLAG] = sceneFile.id;
|
|
486
|
+
// Scene browser — pin the active-scene tracker on the boot snapshot so
|
|
487
|
+
// readActiveSceneFile stays deterministic after later scene switches.
|
|
488
|
+
if (!getActiveSceneId(game))
|
|
489
|
+
setActiveSceneId(game, sceneFile.id);
|
|
415
490
|
}
|
|
416
491
|
// Also post the HUD scene if attached + loaded. The host stashes both
|
|
417
492
|
// snapshots so the World/HUD toggle is purely a UI switch — no fresh
|
|
@@ -620,9 +695,19 @@ function hasPostedSnapshot(game) {
|
|
|
620
695
|
return !!game[SNAPSHOT_POSTED_FLAG];
|
|
621
696
|
}
|
|
622
697
|
function readActiveSceneFile(game) {
|
|
698
|
+
// Scene browser — once two scenes have been visited, the JSON cache holds
|
|
699
|
+
// multiple `umicat:scene:*` entries and the scan below becomes ambiguous.
|
|
700
|
+
// Prefer the exact entry for the tracked active scene when set.
|
|
701
|
+
const activeId = getActiveSceneId(game);
|
|
702
|
+
if (activeId) {
|
|
703
|
+
const exact = game.cache.json.get(`umicat:scene:${activeId}`);
|
|
704
|
+
if (isWorldScene(exact))
|
|
705
|
+
return exact;
|
|
706
|
+
}
|
|
623
707
|
// The active world scene cached its scene file in Phaser's JSON cache via
|
|
624
708
|
// SceneLoader. Pull it from there. We pick the first non-Boot scene we
|
|
625
|
-
// find with a JSON entry matching `umicat:scene:<id>`.
|
|
709
|
+
// find with a JSON entry matching `umicat:scene:<id>`. (Boot path / old
|
|
710
|
+
// hosts — activeSceneId not yet set.)
|
|
626
711
|
for (const scene of game.scene.getScenes(false)) {
|
|
627
712
|
const key = scene.scene.key;
|
|
628
713
|
if (BOOT_SCENE_KEYS.has(key))
|
|
@@ -1961,7 +2046,16 @@ function restoreHudCamera(game) {
|
|
|
1961
2046
|
* `postCameraState`, and the overlay scene's mirror in `create`.
|
|
1962
2047
|
*/
|
|
1963
2048
|
export function getEditorCamera(game) {
|
|
1964
|
-
|
|
2049
|
+
const cam = game[EDITOR_CAM_KEY] ?? null;
|
|
2050
|
+
// Scene browser — a scene restart (loadScene switch) destroys the scene's
|
|
2051
|
+
// cameras but leaves this game-bag ref dangling. Phaser's BaseCamera
|
|
2052
|
+
// .destroy() nulls `cam.scene`; treat such a camera as absent and clear
|
|
2053
|
+
// the stale key so the PRE_STEP late-boot hook can re-run enterEdit.
|
|
2054
|
+
if (cam && !cam.scene) {
|
|
2055
|
+
delete game[EDITOR_CAM_KEY];
|
|
2056
|
+
return null;
|
|
2057
|
+
}
|
|
2058
|
+
return cam;
|
|
1965
2059
|
}
|
|
1966
2060
|
/**
|
|
1967
2061
|
* Toggle HUD scene rendering. HUD widgets are canvas-relative (anchor-
|
|
@@ -304,20 +304,6 @@ export declare class EditorOverlayScene extends Phaser.Scene {
|
|
|
304
304
|
* replays the `before` patch through the normal applyEdit path.
|
|
305
305
|
*/
|
|
306
306
|
private commitEntityResize;
|
|
307
|
-
/**
|
|
308
|
-
* Render the CORNER resize handles around the selected rect entity —
|
|
309
|
-
* Figma convention (2026-06-11): no edge-midpoint squares. On a small
|
|
310
|
-
* entity 8 handles visually swallowed the rect (a 3×3 grid of squares
|
|
311
|
-
* with the entity peeking through the middle). Edges stay fully
|
|
312
|
-
* resizable — the entire selection edge is a hit target and the cursor
|
|
313
|
-
* flips to ns/ew-resize on hover, which is affordance enough. No bounds
|
|
314
|
-
* outline (the blue selection rect already draws it) and no ghost rect
|
|
315
|
-
* (the live GO resizes in place during the drag).
|
|
316
|
-
*
|
|
317
|
-
* Visual is 10px; the hit target stays 14px (see hitTestResizeHandlesAt)
|
|
318
|
-
* — bigger-than-visible click zones are standard.
|
|
319
|
-
*/
|
|
320
|
-
private drawEntityResizeOverlay;
|
|
321
307
|
update(): void;
|
|
322
308
|
/**
|
|
323
309
|
* Render the 8 resize handles (when paint mode is active) and the
|
|
@@ -1691,36 +1691,12 @@ export class EditorOverlayScene extends Phaser.Scene {
|
|
|
1691
1691
|
// The selection rect changed size — refresh the host's anchor rect.
|
|
1692
1692
|
postSelectionRect(this.game);
|
|
1693
1693
|
}
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
* flips to ns/ew-resize on hover, which is affordance enough. No bounds
|
|
1701
|
-
* outline (the blue selection rect already draws it) and no ghost rect
|
|
1702
|
-
* (the live GO resizes in place during the drag).
|
|
1703
|
-
*
|
|
1704
|
-
* Visual is 10px; the hit target stays 14px (see hitTestResizeHandlesAt)
|
|
1705
|
-
* — bigger-than-visible click zones are standard.
|
|
1706
|
-
*/
|
|
1707
|
-
drawEntityResizeOverlay() {
|
|
1708
|
-
const info = this.entityResizeHandlePositions();
|
|
1709
|
-
if (!info)
|
|
1710
|
-
return;
|
|
1711
|
-
const cam = this.findActiveEditorCamera();
|
|
1712
|
-
const zoom = cam?.zoom ?? 1;
|
|
1713
|
-
const handleSize = 10 / zoom; // 10px on screen regardless of zoom
|
|
1714
|
-
const half = handleSize / 2;
|
|
1715
|
-
for (const h of info.handles) {
|
|
1716
|
-
if (h.id !== 'nw' && h.id !== 'ne' && h.id !== 'sw' && h.id !== 'se')
|
|
1717
|
-
continue;
|
|
1718
|
-
this.graphics.fillStyle(0xffffff, 1);
|
|
1719
|
-
this.graphics.fillRect(h.x - half, h.y - half, handleSize, handleSize);
|
|
1720
|
-
this.graphics.fillStyle(SELECTION_COLOR, 1);
|
|
1721
|
-
this.graphics.fillRect(h.x - half + 1.5 / zoom, h.y - half + 1.5 / zoom, handleSize - 3 / zoom, handleSize - 3 / zoom);
|
|
1722
|
-
}
|
|
1723
|
-
}
|
|
1694
|
+
// Rect entities draw NO handle squares at all (2026-06-11, user decision
|
|
1695
|
+
// after comparing with Figma) — the blue selection outline is the whole
|
|
1696
|
+
// visual. Resizability is communicated by the hover cursor: ns/ew-resize
|
|
1697
|
+
// along the edges, nwse/nesw-resize in the corner zones. Hit targets are
|
|
1698
|
+
// unchanged (entityResizeHandlePositions + hitTestResizeHandlesAt still
|
|
1699
|
+
// serve all 8 zones for the pointer logic).
|
|
1724
1700
|
update() {
|
|
1725
1701
|
this.graphics.clear();
|
|
1726
1702
|
// Slice 6 Phase B (fix): sync tilemap layer world positions to their
|
|
@@ -1844,9 +1820,9 @@ export class EditorOverlayScene extends Phaser.Scene {
|
|
|
1844
1820
|
// host Inspector). Ghost rect preview shows the new bounds during
|
|
1845
1821
|
// an active resize drag.
|
|
1846
1822
|
this.drawTilemapResizeOverlay();
|
|
1847
|
-
// Rect-entity resize handles
|
|
1848
|
-
//
|
|
1849
|
-
|
|
1823
|
+
// (Rect-entity resize handles draw nothing — resize affordance is the
|
|
1824
|
+
// hover cursor on the selection edges/corners. See the note above
|
|
1825
|
+
// entityResizeHandlePositions' draw section, 2026-06-11.)
|
|
1850
1826
|
// Snap-to-align guide lines — render while a drag is snapped (2026-06-11).
|
|
1851
1827
|
this.drawSnapGuides();
|
|
1852
1828
|
}
|
|
@@ -62,6 +62,14 @@ interface EditorStateShape {
|
|
|
62
62
|
active: boolean;
|
|
63
63
|
selectedId: string | null;
|
|
64
64
|
mode: EditorMode;
|
|
65
|
+
/**
|
|
66
|
+
* Scene browser (design 01 §6.1) — which world scene the editor is
|
|
67
|
+
* currently editing. Set by `umicat:editor:loadScene` and by the first
|
|
68
|
+
* scene snapshot. Once two scenes have been visited, the JSON cache holds
|
|
69
|
+
* multiple `umicat:scene:*` entries — this disambiguates which one
|
|
70
|
+
* `readActiveSceneFile` should return.
|
|
71
|
+
*/
|
|
72
|
+
activeSceneId: string | null;
|
|
65
73
|
/**
|
|
66
74
|
* Drag-in-progress info. While set, the overlay scene mutates the entity's
|
|
67
75
|
* x/y directly per pointermove without going through the host. On
|
|
@@ -219,6 +227,8 @@ export declare function getEditorState(game: AnyObject): EditorStateShape;
|
|
|
219
227
|
export declare function setEditorActive(game: AnyObject, active: boolean): void;
|
|
220
228
|
export declare function getEditorMode(game: AnyObject): EditorMode;
|
|
221
229
|
export declare function setEditorMode(game: AnyObject, mode: EditorMode): void;
|
|
230
|
+
export declare function getActiveSceneId(game: AnyObject): string | null;
|
|
231
|
+
export declare function setActiveSceneId(game: AnyObject, id: string | null): void;
|
|
222
232
|
export declare function setSelection(game: AnyObject, id: string | null): void;
|
|
223
233
|
export declare function getSelection(game: AnyObject): string | null;
|
|
224
234
|
export declare function startDrag(game: AnyObject, entityId: string, startWorld: {
|
|
@@ -19,6 +19,7 @@ export function getEditorState(game) {
|
|
|
19
19
|
active: false,
|
|
20
20
|
selectedId: null,
|
|
21
21
|
mode: 'world',
|
|
22
|
+
activeSceneId: null,
|
|
22
23
|
drag: null,
|
|
23
24
|
debugOverlay: { showHitboxes: false },
|
|
24
25
|
tilemap: {
|
|
@@ -45,6 +46,12 @@ export function getEditorMode(game) {
|
|
|
45
46
|
export function setEditorMode(game, mode) {
|
|
46
47
|
getEditorState(game).mode = mode;
|
|
47
48
|
}
|
|
49
|
+
export function getActiveSceneId(game) {
|
|
50
|
+
return getEditorState(game).activeSceneId;
|
|
51
|
+
}
|
|
52
|
+
export function setActiveSceneId(game, id) {
|
|
53
|
+
getEditorState(game).activeSceneId = id;
|
|
54
|
+
}
|
|
48
55
|
export function setSelection(game, id) {
|
|
49
56
|
getEditorState(game).selectedId = id;
|
|
50
57
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -39,5 +39,5 @@ export { setupEditorBridge } from './editor/EditorBridge.js';
|
|
|
39
39
|
export { EditorOverlayScene, EDITOR_OVERLAY_KEY } from './editor/EditorOverlayScene.js';
|
|
40
40
|
export type { EditorEntityPatch, EditorEnterMessage, EditorExitMessage, EditorGetSceneMessage, EditorApplyEditMessage, EditorSetSelectionMessage, EditorPanZoomMessage, EditorHostToSdkMessage, EditorSceneLoadedMessage, EditorSelectionPickedMessage, EditorDragEndMessage, EditorShortcutMessage, EditorCreateEntityMessage, EditorDeleteEntityMessage, EditorSetEditModeMessage, EditorSelectionRectMessage, EditorSdkToHostMessage, } from './protocol.js';
|
|
41
41
|
export { SCHEMA_VERSION, isPerFrameNinePatch, isPerFrameHitbox, } from './scene/types.js';
|
|
42
|
-
export type { Manifest, SceneRef, HudRef, AssetRecord, AssetKind, SceneType, SceneFile, WorldScene, HudScene, WorldSceneConfig, CameraConfig, WorldEntity, WorldEntityKind, NonGroupWorldEntity, RenderableEntity, SpriteEntity, RectEntity, CircleEntity, CodeRenderedEntity, GroupEntity, TilemapEntity, TilemapLayer, TilesetMetadata, TileMetadata, TilesetAutotile, TilesetAnimation, WangTerrain, TriggerEntity, TriggerShape, HudEntity, HudEntityKind, HudEntityBase, HudTextEntity, HudImageEntity, HudIconButtonEntity, HudProgressBarEntity, HudPanelEntity, HudTextSource, HudNumberSource, HudLayer, Transform, Anchor, AnchorSide, NinePatchConfig, NinePatchPerFrame, HitboxRect, HitboxPerFrame, DepthAnchor, } from './scene/types.js';
|
|
42
|
+
export type { Manifest, ManifestGroup, SceneRef, HudRef, AssetRecord, AssetKind, SceneType, SceneFile, WorldScene, HudScene, WorldSceneConfig, CameraConfig, WorldEntity, WorldEntityKind, NonGroupWorldEntity, RenderableEntity, SpriteEntity, RectEntity, CircleEntity, CodeRenderedEntity, GroupEntity, TilemapEntity, TilemapLayer, TilesetMetadata, TileMetadata, TilesetAutotile, TilesetAnimation, WangTerrain, TriggerEntity, TriggerShape, HudEntity, HudEntityKind, HudEntityBase, HudTextEntity, HudImageEntity, HudIconButtonEntity, HudProgressBarEntity, HudPanelEntity, HudTextSource, HudNumberSource, HudLayer, Transform, Anchor, AnchorSide, NinePatchConfig, NinePatchPerFrame, HitboxRect, HitboxPerFrame, DepthAnchor, } from './scene/types.js';
|
|
43
43
|
export { PROTOCOL_VERSION, type HelloMessage, type InitMessage, type RpcRequestMessage, type RpcResultOk, type RpcResultError, type HostToSdkMessage, type SdkToHostMessage, type RpcErrorPayload, type RpcMethod, type SavesGetParams, type SavesGetResult, type SavesSetParams, type SavesSetResult, type SavesDeleteParams, type SavesDeleteResult, type SavesListResult, type GameDataGetParams, type GameDataGetResult, type GameDataSetParams, type GameDataSetResult, type GameDataDeleteParams, type GameDataDeleteResult, type GameDataListResult, type RealtimeGetTokenParams, type RealtimeGetTokenResult, } from './protocol.js';
|
package/dist/protocol.d.ts
CHANGED
|
@@ -580,7 +580,37 @@ export type TilemapEditOp = {
|
|
|
580
580
|
y: number;
|
|
581
581
|
};
|
|
582
582
|
};
|
|
583
|
-
|
|
583
|
+
/**
|
|
584
|
+
* Switch the editor to a different world scene (scene browser — design 01
|
|
585
|
+
* §6.1). The iframe loads scene JSON from the deployed dist, NOT the
|
|
586
|
+
* workspace, so the host pushes the current on-disk truth here (fetched via
|
|
587
|
+
* the session-server's `request_workspace_file`) instead of letting the
|
|
588
|
+
* iframe fetch a stale copy.
|
|
589
|
+
*
|
|
590
|
+
* The bridge overwrites the Phaser JSON cache entries, then restarts the
|
|
591
|
+
* world scene with `{ sceneId }` init data. The restart destroys the editor
|
|
592
|
+
* camera; the PRE_STEP late-boot-completion hook (1.0.6) detects that and
|
|
593
|
+
* re-runs the idempotent `enterEdit`, which re-installs editor chrome and
|
|
594
|
+
* posts a fresh `sceneLoaded` — that snapshot is the host's switch ACK.
|
|
595
|
+
*/
|
|
596
|
+
export interface EditorLoadSceneMessage {
|
|
597
|
+
type: 'umicat:editor:loadScene';
|
|
598
|
+
sceneId: string;
|
|
599
|
+
/** Scene file content (workspace truth). When present, replaces the cached copy. */
|
|
600
|
+
sceneFile?: unknown;
|
|
601
|
+
/** Updated manifest (new scenes / groups / initialScene). Replaces cache entry. */
|
|
602
|
+
manifest?: unknown;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Replace the iframe's cached manifest without a scene switch — used after
|
|
606
|
+
* structural scene ops (create / rename / reorder / folders / set-initial)
|
|
607
|
+
* so the cached copy never goes stale relative to the workspace.
|
|
608
|
+
*/
|
|
609
|
+
export interface EditorUpdateManifestMessage {
|
|
610
|
+
type: 'umicat:editor:updateManifest';
|
|
611
|
+
manifest: unknown;
|
|
612
|
+
}
|
|
613
|
+
export type EditorHostToSdkMessage = EditorEnterMessage | EditorExitMessage | EditorGetSceneMessage | EditorApplyEditMessage | EditorSetSelectionMessage | EditorPanZoomMessage | EditorCreateEntityMessage | EditorDeleteEntityMessage | EditorSetEditModeMessage | EditorAssetUpdateMessage | EditorSetDebugOverlayMessage | EditorEditPrefabMessage | EditorPatchRuleMessage | EditorSetTilemapToolMessage | EditorEditTilemapMessage | EditorLoadSceneMessage | EditorUpdateManifestMessage;
|
|
584
614
|
export interface EditorSceneLoadedMessage {
|
|
585
615
|
type: 'umicat:editor:sceneLoaded';
|
|
586
616
|
sceneId: string;
|
package/dist/scene/types.d.ts
CHANGED
|
@@ -11,12 +11,28 @@ export declare const SCHEMA_VERSION = 1;
|
|
|
11
11
|
export type SceneType = 'world' | 'hud';
|
|
12
12
|
export interface SceneRef {
|
|
13
13
|
id: string;
|
|
14
|
+
/**
|
|
15
|
+
* Display name shown in the editor's scene browser (design 01 §6.1).
|
|
16
|
+
* Denormalized copy of the scene file's `name`; kept in sync by the
|
|
17
|
+
* editor's rename op. Optional — display falls back to `id`.
|
|
18
|
+
*/
|
|
19
|
+
name?: string;
|
|
14
20
|
type: SceneType;
|
|
15
21
|
/** Path under `public/scenes/`, e.g. `"world/level-1-1.json"`. */
|
|
16
22
|
file: string;
|
|
17
23
|
/** Optional HUD scene id to overlay (world scenes only). Null = no HUD. */
|
|
18
24
|
hud?: string | null;
|
|
19
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Editor-only scene folder (scene browser — design 03 §3.1's "loose
|
|
28
|
+
* enhancement"). Groups scenes for display; the runtime ignores it.
|
|
29
|
+
* Scenes not in any group render below a separator in `scenes[]` order.
|
|
30
|
+
*/
|
|
31
|
+
export interface ManifestGroup {
|
|
32
|
+
id: string;
|
|
33
|
+
name: string;
|
|
34
|
+
sceneIds: string[];
|
|
35
|
+
}
|
|
20
36
|
export interface HudRef {
|
|
21
37
|
id: string;
|
|
22
38
|
/** Path under `public/scenes/`, e.g. `"hud/game-hud.json"`. */
|
|
@@ -526,6 +542,11 @@ export interface Manifest {
|
|
|
526
542
|
* spawning) can omit this field.
|
|
527
543
|
*/
|
|
528
544
|
prefabs?: PrefabRecord[];
|
|
545
|
+
/**
|
|
546
|
+
* Editor-only scene folders (scene browser). Optional + purely additive —
|
|
547
|
+
* runtime never reads it. See {@link ManifestGroup}.
|
|
548
|
+
*/
|
|
549
|
+
groups?: ManifestGroup[];
|
|
529
550
|
globals?: {
|
|
530
551
|
physics?: {
|
|
531
552
|
gravity?: {
|