@unboxy/phaser-sdk 0.2.18 → 0.2.19

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/SDK-GUIDE.md CHANGED
@@ -638,6 +638,7 @@ The `scene-data-architecture` agent skill has the full guidance. The `scene-data
638
638
 
639
639
  ## Changelog
640
640
 
641
+ - **0.2.19** — fix: editor `enter` arriving while BootScene is still preloading (the post-flush iframe-rebuild path) had nothing to pause, so the world scene resumed running freely once it started up. Now the bridge re-attempts the pause + scene snapshot for ~3 seconds after enter, catching the scene as it transitions from BootScene → GameScene. Snapshot is also re-posted once a scene file lands in cache. Surfaced when slice-2's auto-flush rebuilt the iframe and the user found the sprite started moving again post-save (2026-05-07).
641
642
  - **0.2.18** — added editor bridge (visual editor slice 2). Replaces the slice-1 `unboxy:setEditMode` message with a full editor protocol: `unboxy:editor:enter`/`:exit` (toggles edit mode + launches the overlay scene), `:applyEdit` (mutates a live entity from the host), `:setSelection` (host pushes selection), `:panZoom` (editor camera control), plus SDK→host `:sceneLoaded` (initial snapshot), `:pickEntity` (pointer-down selection), `:dragEnd` (entity dragged to new position). New module `src/editor/` with `EditorOverlayScene` (high-depth Phaser.Scene drawing selection rect + world bounds, capturing pointer events) and `EditorBridge` (postMessage handler + applyEdit logic). New exports: `setupEditorBridge`, `EditorOverlayScene`, `EDITOR_OVERLAY_KEY`, plus all editor protocol types. `setupEditorModeListener` is preserved as a thin wrapper that delegates to the bridge so existing `createUnboxyGame` wiring continues to work. Pairs with home-ui's new Hierarchy + Inspector panels and `useEditorDraft` hook.
642
643
  - **0.2.17** — added scene-as-data foundation (visual editor slice 1). New exports: `loadWorldScene`, `preloadManifest`, `getManifest`, `preloadSceneAssets`, `spawnEntity`, `EntityRegistry`, `attachEntityRegistry`, `getEntityRegistry`, `setupEditorModeListener`, `isEditMode`, `parseColor`, `SCHEMA_VERSION`, plus all schema types (`Manifest`, `WorldScene`, `WorldEntity`, `Transform`, `AssetRecord`, etc.). New games that ship with `public/scenes/manifest.json` load entities + camera config from JSON; `GameScene.ts` becomes a generic loader that calls `await loadWorldScene(this, sceneId)`. `createUnboxyGame` now also wires `setupEditorModeListener` so the host (home-ui) can pause active scenes via `postMessage({ type: 'unboxy:setEditMode', enabled: boolean })`. Purely additive — existing scene-as-code games are unaffected. Migration to scene-as-data is opt-in via the `scene-data-migration` agent skill.
643
644
  - **0.2.16** — added orientation presets. `createUnboxyGame` now accepts an `orientation: 'portrait' | 'landscape'` option as an alternative to explicit `width`/`height` (TS union — pass one or the other). New exports: `Orientation` type and `ORIENTATION_DIMENSIONS` map (`landscape: 1280×720`, `portrait: 720×1280`). Lets games declare orientation once and have a single source of truth for canvas dimensions.
@@ -60,6 +60,36 @@ function enterEdit(game) {
60
60
  if (getEditorState(game).active)
61
61
  return;
62
62
  setEditorActive(game, true);
63
+ pauseActiveNonEditor(game);
64
+ // Launch the overlay AFTER pausing world scenes so it sits on top in render
65
+ // order (Phaser renders scenes in the order they were started).
66
+ const overlayInit = buildOverlayInit(game);
67
+ if (!game.scene.isActive(EDITOR_OVERLAY_KEY)) {
68
+ game.scene.run(EDITOR_OVERLAY_KEY, overlayInit);
69
+ }
70
+ // Send the initial scene snapshot so home-ui can populate Hierarchy /
71
+ // Inspector without a separate getScene round-trip.
72
+ postSceneSnapshot(game);
73
+ // Race-window catch: when home-ui sends `enter` right after iframe load
74
+ // (which is exactly the auto-flush rebuild path), BootScene may still be
75
+ // in preload / GameScene may not have started, so the synchronous pause
76
+ // above had nothing to pause and the snapshot found no scene file in
77
+ // cache yet. Re-attempt for ~3 seconds. Each attempt is cheap and stops
78
+ // automatically once the user exits edit mode.
79
+ let attempts = 0;
80
+ const reattempt = () => {
81
+ if (!getEditorState(game).active)
82
+ return;
83
+ pauseActiveNonEditor(game);
84
+ if (!hasPostedSnapshot(game))
85
+ postSceneSnapshot(game);
86
+ attempts += 1;
87
+ if (attempts < 30)
88
+ setTimeout(reattempt, 100);
89
+ };
90
+ setTimeout(reattempt, 100);
91
+ }
92
+ function pauseActiveNonEditor(game) {
63
93
  for (const scene of game.scene.getScenes(true)) {
64
94
  const key = scene.scene.key;
65
95
  if (BOOT_SCENE_KEYS.has(key))
@@ -69,19 +99,14 @@ function enterEdit(game) {
69
99
  if (scene.scene.isActive())
70
100
  scene.scene.pause();
71
101
  }
72
- // Launch the overlay AFTER pausing world scenes so it sits on top in render
73
- // order (Phaser renders scenes in the order they were started).
74
- const overlayInit = buildOverlayInit(game);
75
- game.scene.run(EDITOR_OVERLAY_KEY, overlayInit);
76
- // Send the initial scene snapshot so home-ui can populate Hierarchy /
77
- // Inspector without a separate getScene round-trip.
78
- postSceneSnapshot(game);
79
102
  }
80
103
  function exitEdit(game) {
81
104
  if (!getEditorState(game).active)
82
105
  return;
83
106
  setEditorActive(game, false);
84
107
  setSelection(game, null);
108
+ // Allow next enter to re-post the snapshot (scene file may have changed).
109
+ delete game[SNAPSHOT_POSTED_FLAG];
85
110
  if (game.scene.isActive(EDITOR_OVERLAY_KEY)) {
86
111
  game.scene.stop(EDITOR_OVERLAY_KEY);
87
112
  }
@@ -116,6 +141,7 @@ function buildOverlayInit(game) {
116
141
  };
117
142
  }
118
143
  // --- Snapshot -------------------------------------------------------------
144
+ const SNAPSHOT_POSTED_FLAG = '__unboxyEditorSnapshotPostedFor';
119
145
  function postSceneSnapshot(game) {
120
146
  const sceneFile = readActiveSceneFile(game);
121
147
  if (!sceneFile)
@@ -125,6 +151,10 @@ function postSceneSnapshot(game) {
125
151
  sceneId: sceneFile.id,
126
152
  sceneFile,
127
153
  });
154
+ game[SNAPSHOT_POSTED_FLAG] = sceneFile.id;
155
+ }
156
+ function hasPostedSnapshot(game) {
157
+ return !!game[SNAPSHOT_POSTED_FLAG];
128
158
  }
129
159
  function readActiveSceneFile(game) {
130
160
  // The active world scene cached its scene file in Phaser's JSON cache via
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unboxy/phaser-sdk",
3
- "version": "0.2.18",
3
+ "version": "0.2.19",
4
4
  "description": "Unboxy Phaser 3 SDK — game infrastructure for the Unboxy platform",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",