@umicat/phaser-sdk 1.0.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/SDK-GUIDE.md +1726 -0
- package/dist/core/Transport.d.ts +28 -0
- package/dist/core/Transport.js +7 -0
- package/dist/core/Umicat.d.ts +45 -0
- package/dist/core/Umicat.js +60 -0
- package/dist/core/UmicatGame.d.ts +43 -0
- package/dist/core/UmicatGame.js +64 -0
- package/dist/core/UmicatScene.d.ts +19 -0
- package/dist/core/UmicatScene.js +38 -0
- package/dist/core/transports/LocalStorageTransport.d.ts +22 -0
- package/dist/core/transports/LocalStorageTransport.js +78 -0
- package/dist/core/transports/PostMessageTransport.d.ts +28 -0
- package/dist/core/transports/PostMessageTransport.js +105 -0
- package/dist/editor/EditorBridge.d.ts +114 -0
- package/dist/editor/EditorBridge.js +2608 -0
- package/dist/editor/EditorOverlayScene.d.ts +333 -0
- package/dist/editor/EditorOverlayScene.js +1896 -0
- package/dist/editor/EditorState.d.ts +251 -0
- package/dist/editor/EditorState.js +197 -0
- package/dist/gamedata/GameDataModule.d.ts +45 -0
- package/dist/gamedata/GameDataModule.js +59 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +43 -0
- package/dist/orientation.d.ts +5 -0
- package/dist/orientation.js +4 -0
- package/dist/protocol.d.ts +807 -0
- package/dist/protocol.js +3 -0
- package/dist/realtime/RealtimeModule.d.ts +93 -0
- package/dist/realtime/RealtimeModule.js +115 -0
- package/dist/realtime/UmicatRoom.d.ts +197 -0
- package/dist/realtime/UmicatRoom.js +353 -0
- package/dist/recording/RecordingManager.d.ts +11 -0
- package/dist/recording/RecordingManager.js +59 -0
- package/dist/saves/SavesModule.d.ts +23 -0
- package/dist/saves/SavesModule.js +37 -0
- package/dist/scene/EditorMode.d.ts +17 -0
- package/dist/scene/EditorMode.js +22 -0
- package/dist/scene/EntityRegistry.d.ts +39 -0
- package/dist/scene/EntityRegistry.js +103 -0
- package/dist/scene/GameConfig.d.ts +60 -0
- package/dist/scene/GameConfig.js +50 -0
- package/dist/scene/HudRuntime.d.ts +131 -0
- package/dist/scene/HudRuntime.js +1224 -0
- package/dist/scene/Prefabs.d.ts +92 -0
- package/dist/scene/Prefabs.js +175 -0
- package/dist/scene/Rules.d.ts +73 -0
- package/dist/scene/Rules.js +164 -0
- package/dist/scene/SceneLoader.d.ts +118 -0
- package/dist/scene/SceneLoader.js +615 -0
- package/dist/scene/Waves.d.ts +85 -0
- package/dist/scene/Waves.js +365 -0
- package/dist/scene/autotile.d.ts +103 -0
- package/dist/scene/autotile.js +321 -0
- package/dist/scene/renderScripts.d.ts +53 -0
- package/dist/scene/renderScripts.js +67 -0
- package/dist/scene/spawnEntity.d.ts +201 -0
- package/dist/scene/spawnEntity.js +1326 -0
- package/dist/scene/types.d.ts +1166 -0
- package/dist/scene/types.js +34 -0
- package/dist/screenshot/ScreenshotManager.d.ts +14 -0
- package/dist/screenshot/ScreenshotManager.js +33 -0
- package/package.json +35 -0
|
@@ -0,0 +1,807 @@
|
|
|
1
|
+
export declare const PROTOCOL_VERSION = 1;
|
|
2
|
+
export interface UmicatUser {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
avatar?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface HelloMessage {
|
|
8
|
+
type: 'umicat:hello';
|
|
9
|
+
protocolVersion: number;
|
|
10
|
+
sdkVersion: string;
|
|
11
|
+
}
|
|
12
|
+
export interface RpcRequestMessage {
|
|
13
|
+
type: 'umicat:rpc';
|
|
14
|
+
id: string;
|
|
15
|
+
method: string;
|
|
16
|
+
params?: unknown;
|
|
17
|
+
}
|
|
18
|
+
export type SdkToHostMessage = HelloMessage | RpcRequestMessage;
|
|
19
|
+
export interface InitMessage {
|
|
20
|
+
type: 'umicat:init';
|
|
21
|
+
protocolVersion: number;
|
|
22
|
+
gameId: string;
|
|
23
|
+
user: UmicatUser | null;
|
|
24
|
+
capabilities: string[];
|
|
25
|
+
/**
|
|
26
|
+
* WebSocket endpoint for umicat-realtime-service. Present only when the host
|
|
27
|
+
* has multiplayer configured (capabilities includes 'realtime'). SDK connects
|
|
28
|
+
* here after fetching a JWT via the 'realtime.getToken' RPC.
|
|
29
|
+
*/
|
|
30
|
+
realtimeUrl?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface RpcResultOk {
|
|
33
|
+
type: 'umicat:rpc.result';
|
|
34
|
+
id: string;
|
|
35
|
+
ok: true;
|
|
36
|
+
result: unknown;
|
|
37
|
+
}
|
|
38
|
+
export interface RpcErrorPayload {
|
|
39
|
+
code: string;
|
|
40
|
+
message: string;
|
|
41
|
+
}
|
|
42
|
+
export interface RpcResultError {
|
|
43
|
+
type: 'umicat:rpc.result';
|
|
44
|
+
id: string;
|
|
45
|
+
ok: false;
|
|
46
|
+
error: RpcErrorPayload;
|
|
47
|
+
}
|
|
48
|
+
export type HostToSdkMessage = InitMessage | RpcResultOk | RpcResultError;
|
|
49
|
+
/**
|
|
50
|
+
* Patch shape applied to a live entity. Only the fields present are updated;
|
|
51
|
+
* `null` is the explicit clear (drops the field).
|
|
52
|
+
*
|
|
53
|
+
* **Flat schema** (SDK 0.3.0). Visual / render fields live at the patch root,
|
|
54
|
+
* the same place they live on the entity. Sprite tint goes in `tint`, not
|
|
55
|
+
* `visual.tint`. Same rule for every renderable field across every entity kind.
|
|
56
|
+
*
|
|
57
|
+
* The bridge applies only the slot relevant to the entity's kind — passing
|
|
58
|
+
* `width` on a sprite is a no-op, same as `tint` on a panel.
|
|
59
|
+
*/
|
|
60
|
+
export interface EditorEntityPatch {
|
|
61
|
+
transform?: Partial<{
|
|
62
|
+
x: number;
|
|
63
|
+
y: number;
|
|
64
|
+
rotation: number;
|
|
65
|
+
scaleX: number;
|
|
66
|
+
scaleY: number;
|
|
67
|
+
depth: number;
|
|
68
|
+
}>;
|
|
69
|
+
/**
|
|
70
|
+
* HUD-only (slice 5). Updates an entity's anchor side / offset. Only one
|
|
71
|
+
* of `transform` (world entities) or `anchor` (HUD entities) is set per
|
|
72
|
+
* patch; the SDK picks the right path based on the active mode.
|
|
73
|
+
*/
|
|
74
|
+
anchor?: Partial<{
|
|
75
|
+
side: string;
|
|
76
|
+
offsetX: number;
|
|
77
|
+
offsetY: number;
|
|
78
|
+
}>;
|
|
79
|
+
/** HUD-only (slice 5). Render layer / z-order overrides. */
|
|
80
|
+
layer?: string;
|
|
81
|
+
z?: number;
|
|
82
|
+
/** Sprite / HUD-image tint + opacity controls. */
|
|
83
|
+
tint?: string | null;
|
|
84
|
+
alpha?: number;
|
|
85
|
+
flipX?: boolean;
|
|
86
|
+
flipY?: boolean;
|
|
87
|
+
/** Sprite / HUD-image frame index OR atlas frame name. */
|
|
88
|
+
frame?: string | number;
|
|
89
|
+
/** Primitive (rect / circle) + HUD widget dims. */
|
|
90
|
+
width?: number;
|
|
91
|
+
height?: number;
|
|
92
|
+
radius?: number;
|
|
93
|
+
fillColor?: string;
|
|
94
|
+
strokeColor?: string | null;
|
|
95
|
+
strokeWidth?: number;
|
|
96
|
+
/**
|
|
97
|
+
* For `code-rendered` entities — the entire params object replaces
|
|
98
|
+
* `params`. SDK re-calls `render(g, params)` on receipt.
|
|
99
|
+
*/
|
|
100
|
+
params?: Record<string, unknown>;
|
|
101
|
+
/**
|
|
102
|
+
* HUD text widgets — replaces `source` wholesale. Static→dynamic switches
|
|
103
|
+
* and prefix/suffix edits all land here.
|
|
104
|
+
*/
|
|
105
|
+
source?: Record<string, unknown>;
|
|
106
|
+
/** HUD text font / colour. */
|
|
107
|
+
fontFamily?: string;
|
|
108
|
+
fontSize?: number;
|
|
109
|
+
color?: string;
|
|
110
|
+
align?: 'left' | 'center' | 'right';
|
|
111
|
+
/** Sprite / HUD-image / HUD-icon-button asset references. */
|
|
112
|
+
assetId?: string;
|
|
113
|
+
iconAssetId?: string;
|
|
114
|
+
backgroundAssetId?: string | null;
|
|
115
|
+
backgroundFrame?: number;
|
|
116
|
+
backgroundRegion?: string;
|
|
117
|
+
/** HUD icon-button label + shape + colors. */
|
|
118
|
+
label?: string;
|
|
119
|
+
shape?: 'rounded-rect' | 'circle';
|
|
120
|
+
pressedFillColor?: string;
|
|
121
|
+
textColor?: string;
|
|
122
|
+
/** HUD progress-bar / panel — value + background. */
|
|
123
|
+
value?: Record<string, unknown>;
|
|
124
|
+
max?: Record<string, unknown>;
|
|
125
|
+
backgroundColor?: string;
|
|
126
|
+
backgroundAlpha?: number;
|
|
127
|
+
borderColor?: string | null;
|
|
128
|
+
borderWidth?: number;
|
|
129
|
+
borderRadius?: number;
|
|
130
|
+
role?: string | null;
|
|
131
|
+
properties?: Record<string, unknown>;
|
|
132
|
+
}
|
|
133
|
+
export interface EditorEnterMessage {
|
|
134
|
+
type: 'umicat:editor:enter';
|
|
135
|
+
}
|
|
136
|
+
export interface EditorExitMessage {
|
|
137
|
+
type: 'umicat:editor:exit';
|
|
138
|
+
}
|
|
139
|
+
export interface EditorGetSceneMessage {
|
|
140
|
+
/** Host requests a snapshot of what's currently loaded in the iframe. */
|
|
141
|
+
type: 'umicat:editor:getScene';
|
|
142
|
+
}
|
|
143
|
+
export interface EditorApplyEditMessage {
|
|
144
|
+
type: 'umicat:editor:applyEdit';
|
|
145
|
+
entityId: string;
|
|
146
|
+
patch: EditorEntityPatch;
|
|
147
|
+
/**
|
|
148
|
+
* Optional asset record to upsert into the iframe's manifest cache + lazy-
|
|
149
|
+
* load before the patch applies. Mirrors {@link EditorCreateEntityMessage}'s
|
|
150
|
+
* `manifestAsset` field. Used by the Inspector's Bg-image picker when the
|
|
151
|
+
* user picks an asset whose manifest entry needs flipping (e.g. region
|
|
152
|
+
* atlases — visual editor slice 10 — where the existing manifest entry
|
|
153
|
+
* was {@code kind: 'image'} but the asset is now atlas-format).
|
|
154
|
+
*
|
|
155
|
+
* <p>When present, the bridge:
|
|
156
|
+
* 1. Merges the asset into {@code scene.cache.json}'s manifest record
|
|
157
|
+
* 2. Lazy-loads the texture (and atlas-ninepatch sidecar JSON when
|
|
158
|
+
* {@code kind: 'atlas' + atlasFormat: 'json'})
|
|
159
|
+
* 3. Applies the entity patch
|
|
160
|
+
*/
|
|
161
|
+
manifestAsset?: unknown;
|
|
162
|
+
}
|
|
163
|
+
export interface EditorSetSelectionMessage {
|
|
164
|
+
type: 'umicat:editor:setSelection';
|
|
165
|
+
/** Empty array deselects. v1: max length 1 (multi-select is slice 2.5). */
|
|
166
|
+
entityIds: string[];
|
|
167
|
+
}
|
|
168
|
+
export interface EditorPanZoomMessage {
|
|
169
|
+
/** Editor camera control — separate from in-game camera. */
|
|
170
|
+
type: 'umicat:editor:panZoom';
|
|
171
|
+
scrollX?: number;
|
|
172
|
+
scrollY?: number;
|
|
173
|
+
/** Absolute zoom (1 = 100%). */
|
|
174
|
+
zoom?: number;
|
|
175
|
+
/** If true, deltas are added to current scroll. */
|
|
176
|
+
relative?: boolean;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Create a new entity in the active scene (slice 3 — drag-to-place).
|
|
180
|
+
* The SDK picks an asset record from `manifestAsset` (if present) so the
|
|
181
|
+
* texture can be lazy-loaded before spawn. Position can be supplied as
|
|
182
|
+
* world coords (preferred — host computed via 1:1 mapping in slice 3) or
|
|
183
|
+
* skipped if the entity already carries a transform.
|
|
184
|
+
*/
|
|
185
|
+
export interface EditorCreateEntityMessage {
|
|
186
|
+
type: 'umicat:editor:createEntity';
|
|
187
|
+
/** Full entity record. transform.x/y is authoritative. */
|
|
188
|
+
entity: unknown;
|
|
189
|
+
/** Asset record to add to runtime cache before spawn. Omit if assetId is already loaded. */
|
|
190
|
+
manifestAsset?: unknown;
|
|
191
|
+
}
|
|
192
|
+
export interface EditorDeleteEntityMessage {
|
|
193
|
+
type: 'umicat:editor:deleteEntity';
|
|
194
|
+
entityId: string;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Editor mode — slice 5. World mode edits the world scene; HUD mode edits
|
|
198
|
+
* the HUD scene attached to the active world. The host sends this when the
|
|
199
|
+
* user toggles the World/HUD switch in the editor canvas.
|
|
200
|
+
*
|
|
201
|
+
* The mode change does NOT clear selection at the SDK level; the host owns
|
|
202
|
+
* selection state per mode (separate selectedId for world / HUD drafts).
|
|
203
|
+
*/
|
|
204
|
+
export interface EditorSetEditModeMessage {
|
|
205
|
+
type: 'umicat:editor:setEditMode';
|
|
206
|
+
mode: 'world' | 'hud';
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Asset-level live update (slice 8 — hitbox / depthAnchor editing).
|
|
210
|
+
*
|
|
211
|
+
* When the user edits an Asset's hitbox or depthAnchor in the Hitbox Editor
|
|
212
|
+
* modal, the change is at the asset level — not tied to a specific entity
|
|
213
|
+
* patch. The host sends this message; the bridge:
|
|
214
|
+
* 1. Upserts the asset into the iframe's cached manifest
|
|
215
|
+
* 2. Walks the entity registry, finds every sprite entity using this asset
|
|
216
|
+
* (matched via `entityAssetId` data-manager stash), and re-applies
|
|
217
|
+
* `setOrigin(depthAnchor)` + `applyAssetHitbox` to each
|
|
218
|
+
*
|
|
219
|
+
* Unlike `applyEdit`, this is NOT scoped to a single entity — one asset edit
|
|
220
|
+
* can affect dozens of in-scene sprites simultaneously.
|
|
221
|
+
*/
|
|
222
|
+
export interface EditorAssetUpdateMessage {
|
|
223
|
+
type: 'umicat:editor:assetUpdate';
|
|
224
|
+
/** Full AssetRecord — replaces the existing manifest entry. */
|
|
225
|
+
asset: unknown;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Patch applied to a prefab record (slice 11 Phase B.5 / editor P0.2).
|
|
229
|
+
*
|
|
230
|
+
* Mirrors the slice-2 entity patch shape but scoped to prefab fields. Only
|
|
231
|
+
* the fields present in the patch are updated; unset fields are unchanged.
|
|
232
|
+
*
|
|
233
|
+
* The bridge merges the patch into `manifest.prefabs[<id>]` in the cached
|
|
234
|
+
* manifest, then walks `EntityRegistry.byPrefabId(id)` and re-applies the
|
|
235
|
+
* visual / physics changes to every live instance. Subsequent `spawnPrefab`
|
|
236
|
+
* calls pick up the new values automatically.
|
|
237
|
+
*
|
|
238
|
+
* Property edits are stamped on `getData('entityProperties')` so behavior
|
|
239
|
+
* code reading `go.getData('entityProperties').hp` sees the new value
|
|
240
|
+
* immediately. Role edits update the entity-registry's role map.
|
|
241
|
+
*/
|
|
242
|
+
/**
|
|
243
|
+
* Patch to a prefab record. Flat schema (SDK 0.3.0) — render fields
|
|
244
|
+
* (assetId / tint / fillColor / width / params / etc.) live at the patch
|
|
245
|
+
* root, exactly like world-entity patches.
|
|
246
|
+
*
|
|
247
|
+
* The bridge deep-merges the patch into `manifest.prefabs[<id>]` then
|
|
248
|
+
* re-applies the same fields to every live instance returned by
|
|
249
|
+
* `EntityRegistry.byPrefabId(id)`. Subsequent `spawnPrefab` calls pick up
|
|
250
|
+
* the new values automatically.
|
|
251
|
+
*/
|
|
252
|
+
export interface EditorPrefabPatch {
|
|
253
|
+
/** Sprite. */
|
|
254
|
+
assetId?: string;
|
|
255
|
+
frame?: string | number;
|
|
256
|
+
tint?: string | null;
|
|
257
|
+
alpha?: number;
|
|
258
|
+
flipX?: boolean;
|
|
259
|
+
flipY?: boolean;
|
|
260
|
+
/** Primitive (rect / circle). */
|
|
261
|
+
width?: number;
|
|
262
|
+
height?: number;
|
|
263
|
+
radius?: number;
|
|
264
|
+
fillColor?: string;
|
|
265
|
+
strokeColor?: string | null;
|
|
266
|
+
strokeWidth?: number;
|
|
267
|
+
/** Code-rendered — entire params object replaces existing. */
|
|
268
|
+
params?: Record<string, unknown>;
|
|
269
|
+
/** Patched physics fields — body size / offset / immovable / velocity / bounce. */
|
|
270
|
+
physics?: {
|
|
271
|
+
bodyW?: number;
|
|
272
|
+
bodyH?: number;
|
|
273
|
+
offsetX?: number;
|
|
274
|
+
offsetY?: number;
|
|
275
|
+
immovable?: boolean;
|
|
276
|
+
velocityX?: number;
|
|
277
|
+
velocityY?: number;
|
|
278
|
+
collideWorldBounds?: boolean;
|
|
279
|
+
bounceX?: number;
|
|
280
|
+
bounceY?: number;
|
|
281
|
+
};
|
|
282
|
+
/** Patched per-type properties — shallow-merged onto `prefab.properties`. */
|
|
283
|
+
properties?: Record<string, unknown>;
|
|
284
|
+
/** Patched role — `null` clears it from the prefab record. */
|
|
285
|
+
role?: string | null;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Patch a single rule (slice 11 Phase B.5 / editor P0.3 — 2026-05-16).
|
|
289
|
+
*
|
|
290
|
+
* Sent by the host when the Rules form commits a field change. Bridge
|
|
291
|
+
* delegates to `patchRule(scene, path, value)` in `Rules.ts`, which:
|
|
292
|
+
* 1. Writes the path-value pair into the cached rules tree.
|
|
293
|
+
* 2. Fires every subscriber whose path is the patched path OR an
|
|
294
|
+
* ancestor of it (so a subscriber to `'balance'` sees an edit to
|
|
295
|
+
* `'balance.lives'`).
|
|
296
|
+
*
|
|
297
|
+
* `path` is dot-notation (`'balance.lives'`, `'physics.gravity.y'`).
|
|
298
|
+
* `value` can be any JSON-serializable shape — primitive, array, or
|
|
299
|
+
* nested object. The host's draft layer mirrors this patch into its
|
|
300
|
+
* pending rules tree so the eventual flush writes the merged tree to
|
|
301
|
+
* `public/rules.json`.
|
|
302
|
+
*/
|
|
303
|
+
export interface EditorPatchRuleMessage {
|
|
304
|
+
type: 'umicat:editor:patchRule';
|
|
305
|
+
path: string;
|
|
306
|
+
value: unknown;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Snapshot of the cached rules tree posted by the SDK on enterEdit so
|
|
310
|
+
* the host's Rules panel can render the form without a separate fetch.
|
|
311
|
+
*
|
|
312
|
+
* Fires once per editor-enter, regardless of how many scenes are loaded
|
|
313
|
+
* (rules are game-level, not per-scene). Posts `{}` when the game has no
|
|
314
|
+
* `public/rules.json` or `preloadRules` was never called.
|
|
315
|
+
*/
|
|
316
|
+
export interface EditorRulesLoadedMessage {
|
|
317
|
+
type: 'umicat:editor:rulesLoaded';
|
|
318
|
+
rules: Record<string, unknown>;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Edit a prefab record (slice 11 Phase B.5 / editor P0.2 — 2026-05-16).
|
|
322
|
+
*
|
|
323
|
+
* Sent by the host when the Prefab Inspector commits a change. The bridge:
|
|
324
|
+
* 1. Deep-merges the patch into the cached `manifest.prefabs[<id>]`.
|
|
325
|
+
* 2. Walks `EntityRegistry.byPrefabId(id)` and re-applies the patched
|
|
326
|
+
* visual fields (via the same paths `applyEdit` uses for world
|
|
327
|
+
* entities — color/tint/alpha/code-rendered params/etc.) + physics
|
|
328
|
+
* block (re-applies body size/offset/immovable/etc.) + property
|
|
329
|
+
* stamps (via `setData('entityProperties', merged)`).
|
|
330
|
+
*
|
|
331
|
+
* Next `spawnPrefab` call picks up the new values automatically — no
|
|
332
|
+
* special path needed; the merged record is the new source of truth.
|
|
333
|
+
*/
|
|
334
|
+
export interface EditorEditPrefabMessage {
|
|
335
|
+
type: 'umicat:editor:editPrefab';
|
|
336
|
+
prefabId: string;
|
|
337
|
+
patch: EditorPrefabPatch;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Debug overlay toggle (slice 8 — "Show hitboxes" diagnostic).
|
|
341
|
+
*
|
|
342
|
+
* When the user toggles the scene-panel checkbox, the host sends this
|
|
343
|
+
* message. The overlay scene draws each sprite's hitbox rect (semi-
|
|
344
|
+
* transparent green) + depth-anchor crosshair (cyan ✚) for entities whose
|
|
345
|
+
* asset has those metadata fields set. Sprites without metadata get
|
|
346
|
+
* nothing drawn — chat-only Workflow A respect.
|
|
347
|
+
*
|
|
348
|
+
* Edit-mode only — complements Phaser's runtime `physics.world.createDebugGraphic`
|
|
349
|
+
* (which is the Play-mode tool), doesn't replace it.
|
|
350
|
+
*/
|
|
351
|
+
export interface EditorSetDebugOverlayMessage {
|
|
352
|
+
type: 'umicat:editor:setDebugOverlay';
|
|
353
|
+
showHitboxes: boolean;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Tilemap painter — active tool/tile/layer state (slice 6 Phase B).
|
|
357
|
+
*
|
|
358
|
+
* Host pushes this when the user selects a tilemap entity, switches paint
|
|
359
|
+
* tool (B/E/R/G/I), picks a different tile in the palette, or picks a
|
|
360
|
+
* different layer in the Hierarchy. SDK caches the values + uses them to
|
|
361
|
+
* drive paint behavior on canvas pointer events. `tilemapEditingId: null`
|
|
362
|
+
* deactivates paint mode (clearing both the cached state + ending any
|
|
363
|
+
* in-flight stroke).
|
|
364
|
+
*
|
|
365
|
+
* Why split state instead of per-pointer round-trip: pointer events fire
|
|
366
|
+
* many times per second; round-tripping each one through postMessage would
|
|
367
|
+
* add visible latency. SDK paints locally + posts ONE `tilemapEdited` per
|
|
368
|
+
* completed stroke for undo recording — same pattern as drag-to-move.
|
|
369
|
+
*/
|
|
370
|
+
export interface EditorSetTilemapToolMessage {
|
|
371
|
+
type: 'umicat:editor:setTilemapTool';
|
|
372
|
+
/**
|
|
373
|
+
* Tilemap entity being painted. Null clears paint mode (e.g. user
|
|
374
|
+
* selected a different entity kind, or explicitly exited tilemap mode).
|
|
375
|
+
*/
|
|
376
|
+
tilemapEditingId: string | null;
|
|
377
|
+
/** Which layer (within the tilemap) the brush affects. Null when no layer chosen. */
|
|
378
|
+
activeLayerId: string | null;
|
|
379
|
+
/**
|
|
380
|
+
* Active paint tool. v1 surfaces brush + eraser (Phase B.3); rect/fill/picker
|
|
381
|
+
* (Phase B.4) land additively without protocol change.
|
|
382
|
+
*/
|
|
383
|
+
tool: 'brush' | 'eraser' | 'rect' | 'fill' | 'picker';
|
|
384
|
+
/**
|
|
385
|
+
* Active tile index (0-based, row-major within the layer's tileset). Null
|
|
386
|
+
* means no tile picked yet — brush is no-op in that state. Eraser ignores
|
|
387
|
+
* this field.
|
|
388
|
+
*/
|
|
389
|
+
activeTile: number | null;
|
|
390
|
+
/**
|
|
391
|
+
* Active Wang terrain id (slice 6 Phase D — design doc 06 §7). When
|
|
392
|
+
* non-null AND the active layer's tileset has matching autotile
|
|
393
|
+
* metadata, the brush/eraser paints with the terrain (cascade + ruleMap
|
|
394
|
+
* lookup) instead of stamping `activeTile` literally. Null = stamp-mode
|
|
395
|
+
* brush (existing Phase B behavior). Mutually meaningful with
|
|
396
|
+
* `activeTile`: stamp mode ignores terrainId; terrain mode ignores
|
|
397
|
+
* activeTile.
|
|
398
|
+
*/
|
|
399
|
+
activeTerrainId?: string | null;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Explicit tilemap edit op pushed by the host (slice 6 Phase B).
|
|
403
|
+
*
|
|
404
|
+
* Used for: agent-authored writes ("paint a 5×5 grass patch"), undo/redo
|
|
405
|
+
* replay (host pushes the inverse op), and any future host-driven flow.
|
|
406
|
+
* Live painting via pointer events does NOT use this message — that path
|
|
407
|
+
* goes SDK→host (`tilemapEdited`) for undo recording.
|
|
408
|
+
*/
|
|
409
|
+
export interface EditorEditTilemapMessage {
|
|
410
|
+
type: 'umicat:editor:editTilemap';
|
|
411
|
+
entityId: string;
|
|
412
|
+
ops: TilemapEditOp[];
|
|
413
|
+
/**
|
|
414
|
+
* Optional manifest asset to upsert + load BEFORE the ops apply.
|
|
415
|
+
* Required when any op in this batch references an asset id that
|
|
416
|
+
* isn't yet in the iframe's cached manifest (typical case: addLayer
|
|
417
|
+
* with a freshly-picked tileset via Add Layer modal). Without this,
|
|
418
|
+
* the SDK handler hits a cache miss + skips the addLayer entirely
|
|
419
|
+
* → painter finds no layer → click falls through to drag.
|
|
420
|
+
*
|
|
421
|
+
* Pattern mirrors `EditorCreateEntityMessage.manifestAsset` (slice 3
|
|
422
|
+
* drag-to-place). The handler is async; upserts cache + awaits
|
|
423
|
+
* `ensureAssetLoaded` before invoking applyTilemapStructureOp.
|
|
424
|
+
*
|
|
425
|
+
* Typed `unknown` to avoid importing the AssetRecord type into
|
|
426
|
+
* protocol.ts (which has no runtime imports otherwise) — the SDK
|
|
427
|
+
* handler casts to AssetRecord.
|
|
428
|
+
*/
|
|
429
|
+
manifestAsset?: unknown;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* A single tilemap mutation. Cell coords are tile-grid coords (not pixels).
|
|
433
|
+
* paint/erase/fillRect/bucketFill mutate cell data within a layer (Phase B.3
|
|
434
|
+
* + B.4); addLayer/removeLayer/setLayerVisibility mutate the layer list
|
|
435
|
+
* itself (Phase B.5).
|
|
436
|
+
*/
|
|
437
|
+
export type TilemapEditOp = {
|
|
438
|
+
kind: 'paint';
|
|
439
|
+
layerId: string;
|
|
440
|
+
cells: Array<{
|
|
441
|
+
x: number;
|
|
442
|
+
y: number;
|
|
443
|
+
index: number;
|
|
444
|
+
}>;
|
|
445
|
+
} | {
|
|
446
|
+
kind: 'erase';
|
|
447
|
+
layerId: string;
|
|
448
|
+
cells: Array<{
|
|
449
|
+
x: number;
|
|
450
|
+
y: number;
|
|
451
|
+
}>;
|
|
452
|
+
} | {
|
|
453
|
+
kind: 'fillRect';
|
|
454
|
+
layerId: string;
|
|
455
|
+
x: number;
|
|
456
|
+
y: number;
|
|
457
|
+
w: number;
|
|
458
|
+
h: number;
|
|
459
|
+
/** When omitted, fillRect acts as an erase-rect. */
|
|
460
|
+
index?: number;
|
|
461
|
+
} | {
|
|
462
|
+
kind: 'bucketFill';
|
|
463
|
+
layerId: string;
|
|
464
|
+
x: number;
|
|
465
|
+
y: number;
|
|
466
|
+
index: number;
|
|
467
|
+
} | {
|
|
468
|
+
/**
|
|
469
|
+
* Wang 4-bit autotile paint (slice 6 Phase D — design doc 06 §7).
|
|
470
|
+
*
|
|
471
|
+
* Each entry in `cells` is a USER-CLICKED cell; the SDK runs the
|
|
472
|
+
* cascade across that cell's 3×3 neighborhood, sets the 4 vertices,
|
|
473
|
+
* recomputes each affected cell's bitmask, and writes the
|
|
474
|
+
* corresponding tile index from `terrain.ruleMap`.
|
|
475
|
+
*
|
|
476
|
+
* The accompanying `tilemapEdited` message's `previousCells` array
|
|
477
|
+
* carries every cell whose tile changed (the click cells AND their
|
|
478
|
+
* cascade neighbors) — that's how the host records the inverse
|
|
479
|
+
* stroke for undo. Replaying the inverse re-issues an
|
|
480
|
+
* `autotilePaint` with the same `cells` and `erase` toggled, so
|
|
481
|
+
* the vertex grid stays in sync after undo.
|
|
482
|
+
*/
|
|
483
|
+
kind: 'autotilePaint';
|
|
484
|
+
layerId: string;
|
|
485
|
+
/** Wang terrain id, references `tileset.autotile.terrains[].id`. */
|
|
486
|
+
terrainId: string;
|
|
487
|
+
cells: Array<{
|
|
488
|
+
x: number;
|
|
489
|
+
y: number;
|
|
490
|
+
}>;
|
|
491
|
+
/**
|
|
492
|
+
* When true the cells are UNPAINTED (4 vertices cleared, cascade
|
|
493
|
+
* recomputes). Omitted / false = paint.
|
|
494
|
+
*/
|
|
495
|
+
erase?: boolean;
|
|
496
|
+
/**
|
|
497
|
+
* Cascade-resolved cells with their final tile indices (D.2.5.2 fix).
|
|
498
|
+
*
|
|
499
|
+
* Populated by the SDK when posting `tilemapEdited` so the host can
|
|
500
|
+
* persist the autotile result without re-running cascade logic
|
|
501
|
+
* (which needs ruleMap + asset context the host doesn't have).
|
|
502
|
+
* One entry per cell mutated by the click + its cascade neighbors
|
|
503
|
+
* (3×3 around each click, deduped). `index = null` means the cell
|
|
504
|
+
* became empty (no tile in ruleMap for the resulting bitmask).
|
|
505
|
+
*
|
|
506
|
+
* Agent-written `editTilemap` ops can omit this — the SDK's
|
|
507
|
+
* `applyTilemapOp` recomputes via `applyAutotile`. Only required
|
|
508
|
+
* when the host materializes the op into `layer.data` (save flush).
|
|
509
|
+
*/
|
|
510
|
+
resolvedCells?: Array<{
|
|
511
|
+
x: number;
|
|
512
|
+
y: number;
|
|
513
|
+
index: number | null;
|
|
514
|
+
}>;
|
|
515
|
+
} | {
|
|
516
|
+
/**
|
|
517
|
+
* Add a new layer to the tilemap (Phase B.5). The new layer is
|
|
518
|
+
* appended at the end of the layers array (renders on top of
|
|
519
|
+
* existing layers); explicit `z` in `layer` overrides this.
|
|
520
|
+
*/
|
|
521
|
+
kind: 'addLayer';
|
|
522
|
+
layer: {
|
|
523
|
+
id: string;
|
|
524
|
+
name?: string;
|
|
525
|
+
tilesetIds?: string[];
|
|
526
|
+
z?: number;
|
|
527
|
+
visible?: boolean;
|
|
528
|
+
};
|
|
529
|
+
} | {
|
|
530
|
+
/** Remove a layer from the tilemap. The layer's data is captured in `previousCells` so undo can restore. */
|
|
531
|
+
kind: 'removeLayer';
|
|
532
|
+
layerId: string;
|
|
533
|
+
} | {
|
|
534
|
+
/** Toggle a layer's runtime visibility (and the editor-side checkbox). */
|
|
535
|
+
kind: 'setLayerVisibility';
|
|
536
|
+
layerId: string;
|
|
537
|
+
visible: boolean;
|
|
538
|
+
} | {
|
|
539
|
+
/**
|
|
540
|
+
* Rename a layer. Editor-only metadata — name has no runtime
|
|
541
|
+
* effect (SDK doesn't use it; layers are looked up by `id`).
|
|
542
|
+
* Persisted to scene JSON so Inspector + Hierarchy + future
|
|
543
|
+
* tooling show the user-chosen name across sessions.
|
|
544
|
+
*/
|
|
545
|
+
kind: 'setLayerName';
|
|
546
|
+
layerId: string;
|
|
547
|
+
name: string;
|
|
548
|
+
} | {
|
|
549
|
+
/**
|
|
550
|
+
* Resize the tilemap (Phase B.6). Affects all layers atomically —
|
|
551
|
+
* each layer's data grid is clipped (shrink) or padded with -1
|
|
552
|
+
* (grow) to match the new dims. Tile cells at coords (x >= newW)
|
|
553
|
+
* or (y >= newH) are LOST on shrink — UI guards with a confirm
|
|
554
|
+
* when painted cells would be discarded.
|
|
555
|
+
*
|
|
556
|
+
* SDK runtime: destroys + recreates each TilemapLayer with the
|
|
557
|
+
* new dims (Phaser tilemap dims are immutable post-creation; the
|
|
558
|
+
* cleanest "resize" is a full layer rebuild). Background grid
|
|
559
|
+
* sketch is redrawn to match.
|
|
560
|
+
*/
|
|
561
|
+
kind: 'resize';
|
|
562
|
+
width: number;
|
|
563
|
+
height: number;
|
|
564
|
+
/**
|
|
565
|
+
* Optional transform shift applied alongside resize (Phase B.6.1).
|
|
566
|
+
* Used by edge/corner handle drags to keep the opposite edge
|
|
567
|
+
* anchored. e.g. dragging the right edge to grow width: the LEFT
|
|
568
|
+
* edge must stay put → tilemap center.x shifts right by half the
|
|
569
|
+
* width delta → `transformDelta.x = delta/2`. Without this, the
|
|
570
|
+
* tilemap would grow symmetrically around center (Figma's symmetric
|
|
571
|
+
* resize via Alt-drag); we want one-edge-anchored as the default
|
|
572
|
+
* (matches Photoshop / Aseprite canvas resize).
|
|
573
|
+
*
|
|
574
|
+
* Number-input resize (B.6) sends no transformDelta → symmetric
|
|
575
|
+
* grow/shrink around center. Handle-drag resize (B.6.1) computes
|
|
576
|
+
* and sends transformDelta to anchor the opposite edge.
|
|
577
|
+
*/
|
|
578
|
+
transformDelta?: {
|
|
579
|
+
x: number;
|
|
580
|
+
y: number;
|
|
581
|
+
};
|
|
582
|
+
};
|
|
583
|
+
export type EditorHostToSdkMessage = EditorEnterMessage | EditorExitMessage | EditorGetSceneMessage | EditorApplyEditMessage | EditorSetSelectionMessage | EditorPanZoomMessage | EditorCreateEntityMessage | EditorDeleteEntityMessage | EditorSetEditModeMessage | EditorAssetUpdateMessage | EditorSetDebugOverlayMessage | EditorEditPrefabMessage | EditorPatchRuleMessage | EditorSetTilemapToolMessage | EditorEditTilemapMessage;
|
|
584
|
+
export interface EditorSceneLoadedMessage {
|
|
585
|
+
type: 'umicat:editor:sceneLoaded';
|
|
586
|
+
sceneId: string;
|
|
587
|
+
/**
|
|
588
|
+
* Discriminator (slice 5+). 'world' (default for back-compat) is the
|
|
589
|
+
* world scene; 'hud' is the HUD overlay scene. SDK posts one message per
|
|
590
|
+
* scene type when entering edit mode, so the host can populate both
|
|
591
|
+
* Hierarchy / Inspector drafts and switch between them via the
|
|
592
|
+
* World/HUD toggle without a fresh SDK round-trip.
|
|
593
|
+
*/
|
|
594
|
+
mode?: 'world' | 'hud';
|
|
595
|
+
/** Snapshot of the scene file's current entities. */
|
|
596
|
+
sceneFile: unknown;
|
|
597
|
+
/**
|
|
598
|
+
* Snapshot of the manifest (asset table + scene list). Slice 3+ — home-ui
|
|
599
|
+
* needs this to mutate the manifest when drag-to-place adds a new asset.
|
|
600
|
+
*/
|
|
601
|
+
manifest?: unknown;
|
|
602
|
+
}
|
|
603
|
+
export interface EditorSelectionPickedMessage {
|
|
604
|
+
/** Pointer-down on an entity in the canvas — host should update selection. */
|
|
605
|
+
type: 'umicat:editor:pickEntity';
|
|
606
|
+
entityId: string | null;
|
|
607
|
+
/**
|
|
608
|
+
* When the picked entity is a runtime-spawned prefab instance (tagged
|
|
609
|
+
* `entityPrefabId` by `spawnPrefab`), the source prefab id — slice 11 B.5
|
|
610
|
+
* / editor P0.2. Host uses this to route the click to the Prefab
|
|
611
|
+
* Inspector instead of the Entity Inspector. Editing one instance is
|
|
612
|
+
* editing the prefab type (= all instances), so the visible Inspector
|
|
613
|
+
* scope matches the change scope.
|
|
614
|
+
*
|
|
615
|
+
* Absent on authored scene entities (those have a real record in
|
|
616
|
+
* `sceneFile.entities[]` and edit per-instance).
|
|
617
|
+
*/
|
|
618
|
+
prefabId?: string;
|
|
619
|
+
/** Modifier keys at pointer-down so host can decide single/toggle/range. */
|
|
620
|
+
modifiers: {
|
|
621
|
+
shift: boolean;
|
|
622
|
+
cmdOrCtrl: boolean;
|
|
623
|
+
alt: boolean;
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
export interface EditorDragEndMessage {
|
|
627
|
+
/** Pointer-up after dragging an entity. delta is total movement in world coords. */
|
|
628
|
+
type: 'umicat:editor:dragEnd';
|
|
629
|
+
entityId: string;
|
|
630
|
+
/** Position before drag started. */
|
|
631
|
+
before: {
|
|
632
|
+
x: number;
|
|
633
|
+
y: number;
|
|
634
|
+
};
|
|
635
|
+
/** Position at release. */
|
|
636
|
+
after: {
|
|
637
|
+
x: number;
|
|
638
|
+
y: number;
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Editor keyboard shortcut intercepted inside the iframe (user clicked the
|
|
643
|
+
* canvas, so focus is on the iframe and the host window doesn't see the
|
|
644
|
+
* native keydown). The SDK forwards a small allowlist back to the host.
|
|
645
|
+
*/
|
|
646
|
+
export interface EditorShortcutMessage {
|
|
647
|
+
type: 'umicat:editor:shortcut';
|
|
648
|
+
action: 'undo' | 'redo' | 'save' | 'delete';
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* The selected entity's DOM screen rect (slice 4 — popover anchoring).
|
|
652
|
+
*
|
|
653
|
+
* Emitted on selection change, drag-end, and pan/zoom — NOT per frame. The
|
|
654
|
+
* host uses this to anchor the floating ✨ button + InlineAIPopover next
|
|
655
|
+
* to the entity. Coords are relative to the iframe element (not the
|
|
656
|
+
* entity's world coords); the host adds the iframe's own bounding rect to
|
|
657
|
+
* land in viewport space. Sent with `null` when nothing is selected, so
|
|
658
|
+
* the host can hide the ✨ button.
|
|
659
|
+
*
|
|
660
|
+
* Slice 4 only handles single-select. Multi-select (slice 4.5) will pass
|
|
661
|
+
* the union bounding box.
|
|
662
|
+
*/
|
|
663
|
+
export interface EditorSelectionRectMessage {
|
|
664
|
+
type: 'umicat:editor:selectionRect';
|
|
665
|
+
entityId: string | null;
|
|
666
|
+
/** null when nothing is selected. */
|
|
667
|
+
rect: {
|
|
668
|
+
x: number;
|
|
669
|
+
y: number;
|
|
670
|
+
width: number;
|
|
671
|
+
height: number;
|
|
672
|
+
} | null;
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Editor camera state (P1 infinite canvas — 2026-05-17).
|
|
676
|
+
*
|
|
677
|
+
* Posted by the SDK after every pan / zoom action — either host-driven
|
|
678
|
+
* (via `umicat:editor:panZoom`) or SDK-driven (mouse-wheel zoom in the
|
|
679
|
+
* canvas, middle-button drag, space+drag). The host uses it to render
|
|
680
|
+
* the zoom percentage indicator + "reset to 100%" button in the iframe
|
|
681
|
+
* toolbar, and to compute which entities are off-screen for the
|
|
682
|
+
* Hierarchy panel's dim-when-outside-viewport hint.
|
|
683
|
+
*
|
|
684
|
+
* `viewportWorld` is the world-coord rectangle currently visible inside
|
|
685
|
+
* the iframe — `scrollX / scrollY` plus the canvas dimensions divided
|
|
686
|
+
* by zoom. Convenient for the host so it doesn't have to know canvas
|
|
687
|
+
* size or zoom math.
|
|
688
|
+
*
|
|
689
|
+
* Fired only in world mode — HUD has an identity camera; pan/zoom is
|
|
690
|
+
* not meaningful there.
|
|
691
|
+
*/
|
|
692
|
+
export interface EditorCameraStateMessage {
|
|
693
|
+
type: 'umicat:editor:cameraState';
|
|
694
|
+
zoom: number;
|
|
695
|
+
scrollX: number;
|
|
696
|
+
scrollY: number;
|
|
697
|
+
viewportWorld: {
|
|
698
|
+
x: number;
|
|
699
|
+
y: number;
|
|
700
|
+
width: number;
|
|
701
|
+
height: number;
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Tilemap stroke completed (slice 6 Phase B — pointer-up after brush /
|
|
706
|
+
* eraser / rect / fill).
|
|
707
|
+
*
|
|
708
|
+
* Sent by the SDK after every painter stroke so the host can:
|
|
709
|
+
* 1. Push a command onto the undo stack (whole stroke = ONE undo step)
|
|
710
|
+
* 2. Mutate the cached scene draft so the next flush persists the change
|
|
711
|
+
*
|
|
712
|
+
* The SDK already applied the op locally before posting — so the iframe is
|
|
713
|
+
* already showing the painted cells. This message exists for undo +
|
|
714
|
+
* persistence, NOT live preview (mirrors how `dragEnd` works).
|
|
715
|
+
*/
|
|
716
|
+
export interface EditorTilemapEditedMessage {
|
|
717
|
+
type: 'umicat:editor:tilemapEdited';
|
|
718
|
+
entityId: string;
|
|
719
|
+
/** The forward op (replay on redo, reverse-derive on undo). */
|
|
720
|
+
op: TilemapEditOp;
|
|
721
|
+
/**
|
|
722
|
+
* Per-cell prior values that the op overwrote — host stores these to
|
|
723
|
+
* build the inverse op for undo. For paint/erase, indices match `op.cells`;
|
|
724
|
+
* for fillRect/bucketFill, this is a flat list of every cell the op
|
|
725
|
+
* changed (in row-major order from top-left of the affected region).
|
|
726
|
+
*/
|
|
727
|
+
previousCells: Array<{
|
|
728
|
+
x: number;
|
|
729
|
+
y: number;
|
|
730
|
+
index: number | null;
|
|
731
|
+
}>;
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Tile picked from the canvas (slice 6 Phase B.4 — Picker / eyedropper tool).
|
|
735
|
+
*
|
|
736
|
+
* Fires on pointerdown when the active tool is `picker`. The SDK reads the
|
|
737
|
+
* cell's current tile index and posts this message; the host's painter UI
|
|
738
|
+
* sets it as the active tile + auto-switches the tool back to brush (matches
|
|
739
|
+
* Photoshop / Aseprite eyedropper convention — pick once, paint next).
|
|
740
|
+
*
|
|
741
|
+
* `tileIndex: null` means the picked cell is empty.
|
|
742
|
+
*/
|
|
743
|
+
export interface EditorTilemapTilePickedMessage {
|
|
744
|
+
type: 'umicat:editor:tilemapTilePicked';
|
|
745
|
+
entityId: string;
|
|
746
|
+
layerId: string;
|
|
747
|
+
tileIndex: number | null;
|
|
748
|
+
}
|
|
749
|
+
export type EditorSdkToHostMessage = EditorSceneLoadedMessage | EditorSelectionPickedMessage | EditorDragEndMessage | EditorShortcutMessage | EditorSelectionRectMessage | EditorRulesLoadedMessage | EditorCameraStateMessage | EditorTilemapEditedMessage | EditorTilemapTilePickedMessage;
|
|
750
|
+
export type RpcMethod = 'saves.get' | 'saves.set' | 'saves.delete' | 'saves.list' | 'gameData.get' | 'gameData.set' | 'gameData.delete' | 'gameData.list' | 'realtime.getToken';
|
|
751
|
+
export interface SavesGetParams {
|
|
752
|
+
key: string;
|
|
753
|
+
}
|
|
754
|
+
export interface SavesGetResult {
|
|
755
|
+
value: unknown | null;
|
|
756
|
+
version: number | null;
|
|
757
|
+
}
|
|
758
|
+
export interface SavesSetParams {
|
|
759
|
+
key: string;
|
|
760
|
+
value: unknown;
|
|
761
|
+
ifVersion?: number;
|
|
762
|
+
}
|
|
763
|
+
export interface SavesSetResult {
|
|
764
|
+
version: number;
|
|
765
|
+
}
|
|
766
|
+
export interface SavesDeleteParams {
|
|
767
|
+
key: string;
|
|
768
|
+
}
|
|
769
|
+
export type SavesDeleteResult = {
|
|
770
|
+
deleted: boolean;
|
|
771
|
+
};
|
|
772
|
+
export interface SavesListResult {
|
|
773
|
+
keys: string[];
|
|
774
|
+
}
|
|
775
|
+
export interface GameDataGetParams {
|
|
776
|
+
key: string;
|
|
777
|
+
}
|
|
778
|
+
export interface GameDataGetResult {
|
|
779
|
+
value: unknown | null;
|
|
780
|
+
version: number | null;
|
|
781
|
+
}
|
|
782
|
+
export interface GameDataSetParams {
|
|
783
|
+
key: string;
|
|
784
|
+
value: unknown;
|
|
785
|
+
ifVersion?: number;
|
|
786
|
+
}
|
|
787
|
+
export interface GameDataSetResult {
|
|
788
|
+
version: number;
|
|
789
|
+
}
|
|
790
|
+
export interface GameDataDeleteParams {
|
|
791
|
+
key: string;
|
|
792
|
+
}
|
|
793
|
+
export type GameDataDeleteResult = {
|
|
794
|
+
deleted: boolean;
|
|
795
|
+
};
|
|
796
|
+
export interface GameDataListResult {
|
|
797
|
+
keys: string[];
|
|
798
|
+
}
|
|
799
|
+
export interface RealtimeGetTokenParams {
|
|
800
|
+
/** Opaque, forwarded to server-side auth (future use). */
|
|
801
|
+
purpose?: string;
|
|
802
|
+
}
|
|
803
|
+
export interface RealtimeGetTokenResult {
|
|
804
|
+
token: string;
|
|
805
|
+
/** Epoch millis when the token expires. */
|
|
806
|
+
expiresAt: number;
|
|
807
|
+
}
|