@umicat/phaser-sdk 1.0.13 → 1.0.15

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.
@@ -109,6 +109,20 @@ export function preloadSceneAssets(scene, sceneFile, manifest) {
109
109
  queueAssetLoad(scene, asset);
110
110
  state.requestedAssetIds.add(id);
111
111
  }
112
+ // Audio assets are GLOBAL — BGM / SFX are played from code (`sound.play(key)`),
113
+ // not attached to a scene entity — so the entity walk above never collects
114
+ // them and they'd never load. Eagerly load every audio asset in the manifest
115
+ // so `cache.audio.has(key)` is true and the game can play it with no manual
116
+ // BootScene preload. (Without this, registering BGM in the manifest silently
117
+ // produced no sound — the asset existed but was never queued.)
118
+ for (const asset of manifest.assets ?? []) {
119
+ if (asset.kind !== 'audio')
120
+ continue;
121
+ if (state.requestedAssetIds.has(asset.id))
122
+ continue;
123
+ queueAssetLoad(scene, asset);
124
+ state.requestedAssetIds.add(asset.id);
125
+ }
112
126
  }
113
127
  function collectAssetIds(entities, manifest, resolveTilemapFile) {
114
128
  const ids = new Set();
@@ -345,10 +359,15 @@ function queueAssetLoad(scene, asset) {
345
359
  }
346
360
  return;
347
361
  case 'audio':
348
- scene.load.audio(asset.textureKey, asset.path);
362
+ // Fall back to `id` when `textureKey` is absent. Audio (and json) entries
363
+ // are naturally written as `{ id, path, kind:'audio' }` — "textureKey" is
364
+ // a misnomer for a sound — so an agent/human routinely omits it. Without
365
+ // the fallback the clip loads under key `undefined` and `sound.play(id)`
366
+ // silently no-ops (the "generated BGM never plays" bug).
367
+ scene.load.audio(asset.textureKey || asset.id, asset.path);
349
368
  return;
350
369
  case 'json':
351
- scene.load.json(asset.textureKey, asset.path);
370
+ scene.load.json(asset.textureKey || asset.id, asset.path);
352
371
  return;
353
372
  default: {
354
373
  const exhaustive = asset.kind;
@@ -16,8 +16,52 @@ export function setupScreenshotListener(game) {
16
16
  console.error('[UmicatSDK] Screenshot failed:', e);
17
17
  }
18
18
  }
19
+ else if (event.data?.type === 'screenshotRegion') {
20
+ // Marquee-to-chat: the host drew a selection rect over the iframe (in
21
+ // iframe-relative CSS px); crop the canvas to it here, where the canvas's
22
+ // on-screen position + intrinsic resolution are known (handles letterbox
23
+ // bars + display scaling). Responds with the cropped PNG.
24
+ try {
25
+ const r = event.data.rect;
26
+ const dataUrl = cropCanvasRegion(game, r);
27
+ window.parent.postMessage({ type: 'screenshot_region_result', dataUrl, requestId: event.data.requestId }, '*');
28
+ }
29
+ catch (e) {
30
+ console.error('[UmicatSDK] Region screenshot failed:', e);
31
+ window.parent.postMessage({ type: 'screenshot_region_result', dataUrl: null, requestId: event.data?.requestId }, '*');
32
+ }
33
+ }
19
34
  });
20
35
  }
36
+ /**
37
+ * Crop the game canvas to a rect given in iframe-relative CSS pixels (the host's
38
+ * marquee). Maps display px → intrinsic canvas px via the canvas's bounding rect
39
+ * + resolution (uniform scale — Phaser FIT preserves aspect), clamps to bounds.
40
+ */
41
+ function cropCanvasRegion(game, rect) {
42
+ const canvas = game.canvas;
43
+ const cr = canvas.getBoundingClientRect();
44
+ if (cr.width <= 0 || cr.height <= 0)
45
+ return null;
46
+ const scale = canvas.width / cr.width; // intrinsic px per displayed px
47
+ let sx = Math.round((rect.x - cr.x) * scale);
48
+ let sy = Math.round((rect.y - cr.y) * scale);
49
+ let sw = Math.round(rect.width * scale);
50
+ let sh = Math.round(rect.height * scale);
51
+ // Clamp to the canvas (the marquee can run past the letterboxed edges).
52
+ sx = Math.max(0, Math.min(sx, canvas.width - 1));
53
+ sy = Math.max(0, Math.min(sy, canvas.height - 1));
54
+ sw = Math.max(1, Math.min(sw, canvas.width - sx));
55
+ sh = Math.max(1, Math.min(sh, canvas.height - sy));
56
+ const out = document.createElement('canvas');
57
+ out.width = sw;
58
+ out.height = sh;
59
+ const ctx = out.getContext('2d');
60
+ if (!ctx)
61
+ return null;
62
+ ctx.drawImage(canvas, sx, sy, sw, sh, 0, 0, sw, sh);
63
+ return out.toDataURL('image/png');
64
+ }
21
65
  /**
22
66
  * Take a screenshot programmatically (e.g., from within a scene).
23
67
  * Returns a base64 data URL of the current canvas.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umicat/phaser-sdk",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "Umicat Phaser 3 SDK — game infrastructure for the Umicat platform",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",