@unboxy/phaser-sdk 0.2.9 → 0.2.11

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
@@ -11,6 +11,39 @@ Reference for AI agents building games on the Unboxy platform. Tracks the **inst
11
11
  - `unboxy.gameData` — **per-game** key-value store (read by anyone; write requires auth)
12
12
  - `unboxy.rooms` — **multiplayer rooms** (server-authoritative state sync, requires sign-in and host support)
13
13
 
14
+ ## `createUnboxyGame` options
15
+
16
+ | field | type | note |
17
+ |-------|------|------|
18
+ | `width` | `number` | required |
19
+ | `height` | `number` | required |
20
+ | `scenes` | `Phaser.Scene class[]` | required |
21
+ | `backgroundColor` | `string` | defaults to `'#1a1a2e'` |
22
+ | `pixelArt` | `boolean` | defaults to `false` |
23
+ | `physics` | `Phaser.Types.Core.PhysicsConfig` | defaults to arcade physics, no gravity |
24
+ | `plugins` | `Phaser.Types.Core.PluginObject` | forwarded as-is into the Phaser `GameConfig`. **Since 0.2.9.** Earlier versions silently dropped this field. |
25
+
26
+ Any field not listed is ignored. If you need something else (e.g. `callbacks`, custom `render` options), use plain `new Phaser.Game(config)` instead of `createUnboxyGame`.
27
+
28
+ ### Registering third-party Phaser plugins (e.g. rexUI)
29
+
30
+ Pass them via the `plugins` option — do NOT try to register them inside a scene's `preload`:
31
+
32
+ ```ts
33
+ import VirtualJoystickPlugin from 'phaser3-rex-plugins/plugins/virtualjoystick-plugin.js';
34
+
35
+ createUnboxyGame({
36
+ // ...
37
+ plugins: {
38
+ global: [
39
+ { key: 'rexVirtualJoystick', plugin: VirtualJoystickPlugin, start: true },
40
+ ],
41
+ },
42
+ });
43
+ ```
44
+
45
+ Then in a scene: `this.plugins.get('rexVirtualJoystick').add(this, { ... })`.
46
+
14
47
  ## Platform services
15
48
 
16
49
  Initialize once at module load — resolves the host (home-ui, standalone, etc.) and returns a bound instance. Scenes read from the resulting promise.
@@ -204,6 +237,52 @@ room.sessionId; // this connection's session id within the room
204
237
  room.state; // proxy of the server-authoritative schema
205
238
  ```
206
239
 
240
+ **Room type is always `'lobby'`.** This is the only room type the realtime server registers — there is no `'blokus'` / `'chess'` / `'mygame'` type. Passing any other name results in "no handler" and throws. To distinguish rooms (private matches, per-code lobbies, etc.) use the `roomCode` option, documented below.
241
+
242
+ #### Matchmaking — one game can have many rooms
243
+
244
+ By default (no `roomCode`), every player of the same game lands in **one shared room**. Fine for a single hangout or a "public lobby" — but not for games where users need to open *private* rooms (e.g. "play this match with my friend" / "create a room with code ABC123 and share it").
245
+
246
+ Use the `roomCode` option to bucket players. Two clients with the same `(gameId, roomCode)` join the same room; different codes create independent rooms.
247
+
248
+ ```ts
249
+ // --- Create a private room with a fresh code ---
250
+ const code = Math.random().toString(36).slice(2, 8).toUpperCase(); // e.g. 'AB3X7Y'
251
+ const hostRoom = await unboxy.rooms.joinOrCreate('lobby', {
252
+ roomCode: code,
253
+ maxClients: 4, // cap to 4 players (server clamps to [1, 16])
254
+ displayName: unboxy.user?.name ?? 'host',
255
+ });
256
+
257
+ // Show `code` in the UI; the host shares it with friends manually.
258
+
259
+ // --- Friend joins the same room with the shared code ---
260
+ const guestRoom = await unboxy.rooms.joinOrCreate('lobby', {
261
+ roomCode: 'AB3X7Y', // whatever the host shared
262
+ displayName: unboxy.user?.name ?? 'guest',
263
+ });
264
+ ```
265
+
266
+ **`roomCode` caveats:**
267
+ - Not a password. Anyone who knows the code can join. Use it for unguessable rather than *secret*.
268
+ - Defaults to empty string when omitted. Two clients that both omit `roomCode` share the same "default" room — useful for a single global lobby per game.
269
+ - Changing `roomCode` between joins does NOT transfer state; it's a different room. Leave the old room (`room.leave()`) before joining a new one.
270
+
271
+ **`maxClients` caveats:**
272
+ - Only honored by the client who CREATES the room (the first one in). Later joiners see the creator's choice.
273
+ - Server clamps to `[1, 16]`. Passing `maxClients: 1000` silently becomes 16.
274
+ - When full, `joinOrCreate` throws. Handle that in your UI (e.g. "Room is full. Ask your friend to create a smaller room or try a different code.").
275
+
276
+ **Quick match / public room pattern.** If you want a "click Play, get matched with someone" flow, omit `roomCode` — everyone lands in the same default room. Players are differentiated by their `sessionId`. Add your own ready / waiting logic in `room.data`.
277
+
278
+ ```ts
279
+ // Public quick match — no roomCode, everyone shares one room per game
280
+ const room = await unboxy.rooms.joinOrCreate('lobby', {
281
+ maxClients: 2,
282
+ displayName: unboxy.user?.name ?? 'guest',
283
+ });
284
+ ```
285
+
207
286
  #### Delta-synced state — `room.player` and `room.data`
208
287
 
209
288
  Use this for anything that represents the *current world*: positions, hp, score, turn state, scoreboard, etc. The server delta-syncs diffs to every client.
@@ -348,6 +427,8 @@ Don't blindly apply interpolation to everything. It's wrong for a chess piece an
348
427
 
349
428
  ## Changelog
350
429
 
430
+ - **0.2.10** — docs: added a `createUnboxyGame` options table (including the new `plugins` field) and a third-party Phaser plugin registration example. No code changes; version bumped so existing workspaces pick up the new guidance via `npm update @unboxy/phaser-sdk`.
431
+ - **0.2.9** — `createUnboxyGame` now forwards the optional `plugins` field to Phaser's `GameConfig`. Previously the option was accepted at the call site but silently dropped — any `phaser3-rex-plugins` (or similar) registration never took effect, and `this.plugins.get(key)` returned undefined at runtime. Purely additive; no effect on games that don't pass `plugins`. Lets the `phaser-rex-touch` agent skill work end-to-end.
351
432
  - **0.2.8** — docs: added "Making remote motion feel smooth" section to the multiplayer chapter with concrete examples for interpolation (continuous motion), extrapolation (projectiles), and snap (discrete/turn-based/infrequent). No code changes — version bumped so existing workspaces pick up the new guidance via `npm update @unboxy/phaser-sdk`.
352
433
  - **0.2.7** — fixed handshake race on slow-mounting hosts. `PostMessageTransport.connect` now retries `unboxy:hello` every 200 ms until `unboxy:init` arrives (previously one-shot → lost on Android/mobile where React mounted after the iframe first fired hello). Default handshake timeout bumped from 2 s → 5 s.
353
434
  - **0.2.6** — redesigned `unboxy.rooms` around two generic primitives: delta-synced KV state (`room.player.set/get/delete`, `room.data.set/get/delete`) + transient relay (`room.send` / `room.on`). Server no longer bakes in game-specific fields like x/y/color/ready or a `move` handler — games define their own shapes via opaque JSON values, same contract as `gameData` / `saves`.
@@ -3,6 +3,26 @@ import { UnboxyRoom } from './UnboxyRoom.js';
3
3
  export interface JoinOptions extends Record<string, unknown> {
4
4
  /** Optional display name passed to the server-side room on join. */
5
5
  displayName?: string;
6
+ /**
7
+ * Short code that distinguishes independent rooms for the same game.
8
+ * Empty / omitted means "the one shared room per game."
9
+ *
10
+ * Pass a non-empty value on `joinOrCreate` / `create` / `join` to bucket
11
+ * players into a private room. Two clients with the same `(gameId, roomCode)`
12
+ * land in the same room; different `roomCode` values create separate rooms.
13
+ * This is how you implement "Create Room" / "Join with code" UX — the
14
+ * server's `filterBy(["gameId", "roomCode"])` enforces the separation.
15
+ *
16
+ * Not a password: anyone who knows the code can join. Treat as an
17
+ * unguessability measure, not an access control.
18
+ */
19
+ roomCode?: string;
20
+ /**
21
+ * Cap on concurrent clients in the room the creator makes. Server clamps
22
+ * to [1, 16]. Defaults to 8 server-side. Only honored by the FIRST client
23
+ * (the creator) — later joiners see whatever the creator set.
24
+ */
25
+ maxClients?: number;
6
26
  }
7
27
  /**
8
28
  * Multiplayer rooms backed by unboxy-realtime-service (Colyseus under the hood).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unboxy/phaser-sdk",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
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",