@dreamboard-games/cli 0.1.30-alpha.0 → 0.1.30-alpha.10
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/README.md +179 -22
- package/dist/agent-verifier/agent-workspace-verifier.mjs +31 -30
- package/dist/agent-verifier/agent-workspace-verifier.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-2NZNKIND.mjs → chunk-3IJBOLGT.mjs} +4 -12
- package/dist/agent-verifier/chunk-3IJBOLGT.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-6A5HRJMQ.mjs → chunk-4GU3PCHV.mjs} +62 -99
- package/dist/agent-verifier/chunk-4GU3PCHV.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-SYPLYRGB.mjs → chunk-6XRC5PWB.mjs} +119 -310
- package/dist/agent-verifier/chunk-6XRC5PWB.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-BVVNBJM4.mjs → chunk-COB56ESI.mjs} +2 -1
- package/dist/agent-verifier/chunk-COB56ESI.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-2GBBP27W.mjs → chunk-F2DIOJJZ.mjs} +1 -0
- package/dist/agent-verifier/chunk-F2DIOJJZ.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-CFU5EWIC.mjs → chunk-G42BGGG2.mjs} +7 -6
- package/dist/agent-verifier/chunk-G42BGGG2.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-XYDL7GY6.mjs → chunk-H6XDQJ3N.mjs} +1 -0
- package/dist/agent-verifier/{chunk-LM3OZLZG.mjs → chunk-IAYRNVUC.mjs} +1 -0
- package/dist/agent-verifier/chunk-IAYRNVUC.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-2QMNAVV4.mjs → chunk-JZTH3EMV.mjs} +2 -1
- package/dist/agent-verifier/chunk-JZTH3EMV.mjs.map +1 -0
- package/dist/agent-verifier/chunk-KK47X7RV.mjs +14 -0
- package/dist/agent-verifier/chunk-KK47X7RV.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-SHUMAVAP.mjs → chunk-M7UVBANQ.mjs} +8 -9
- package/dist/agent-verifier/chunk-M7UVBANQ.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-RJBLBYHX.mjs → chunk-MGXX4WFR.mjs} +87 -22
- package/dist/agent-verifier/chunk-MGXX4WFR.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-2E5P5NWG.mjs → chunk-NAK77WXW.mjs} +58 -126
- package/dist/agent-verifier/chunk-NAK77WXW.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-CEQ2VJWN.mjs → chunk-POBFNXD4.mjs} +2 -1
- package/dist/agent-verifier/chunk-POBFNXD4.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-6UUJEYDV.mjs → chunk-QBAF7EYR.mjs} +1 -0
- package/dist/agent-verifier/chunk-QBAF7EYR.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-7653FPGJ.mjs → chunk-RHI6S4SU.mjs} +3 -2
- package/dist/agent-verifier/chunk-RHI6S4SU.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-MINCYHXN.mjs → chunk-TAEQKBJB.mjs} +1 -0
- package/dist/agent-verifier/chunk-TAEQKBJB.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-PM3SVG6R.mjs → chunk-TLYGTHXU.mjs} +3 -2
- package/dist/agent-verifier/chunk-TLYGTHXU.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-EIQWDQWJ.mjs → chunk-UWJIZML3.mjs} +13 -14
- package/dist/agent-verifier/chunk-UWJIZML3.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-DTMJCPS4.mjs → chunk-VLOIZDR6.mjs} +15 -31
- package/dist/agent-verifier/chunk-VLOIZDR6.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-HJFQDSTU.mjs → chunk-W2MDP5ZN.mjs} +6 -5
- package/dist/agent-verifier/chunk-W2MDP5ZN.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-CEDUHGNH.mjs → chunk-XKCJBIRY.mjs} +2 -1
- package/dist/agent-verifier/chunk-XKCJBIRY.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-VYJTHSYR.mjs → chunk-YDIOW2BO.mjs} +2 -1
- package/dist/agent-verifier/chunk-YDIOW2BO.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-MRCUP5SW.mjs → chunk-YE7UAO3T.mjs} +1 -0
- package/dist/agent-verifier/chunk-YE7UAO3T.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-EOQIV6PS.mjs → chunk-YR664DJX.mjs} +111 -116
- package/dist/agent-verifier/chunk-YR664DJX.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-2SZHMP6F.mjs → chunk-Z6OZWUIZ.mjs} +6 -9
- package/dist/agent-verifier/chunk-Z6OZWUIZ.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-RBDDIIPM.mjs → chunk-ZEELHSY3.mjs} +1 -0
- package/dist/agent-verifier/chunk-ZEELHSY3.mjs.map +1 -0
- package/dist/agent-verifier/{compile-WNCQQVOF.mjs → compile-C2VIP6VC.mjs} +27 -27
- package/dist/agent-verifier/compile-C2VIP6VC.mjs.map +1 -0
- package/dist/agent-verifier/{global-config-WX3ZZIVU.mjs → global-config-XHL7BCKN.mjs} +6 -5
- package/dist/agent-verifier/global-config-XHL7BCKN.mjs.map +1 -0
- package/dist/agent-verifier/{keychain-backend-TNOPQV3Z.mjs → keychain-backend-A3MRWLPF.mjs} +2 -1
- package/dist/agent-verifier/keychain-backend-A3MRWLPF.mjs.map +1 -0
- package/dist/agent-verifier/{local-files-MTPLP62S.mjs → local-files-ZW52HSVT.mjs} +10 -11
- package/dist/agent-verifier/local-files-ZW52HSVT.mjs.map +1 -0
- package/dist/agent-verifier/local-typecheck-3JXL2NMG.mjs +10 -0
- package/dist/agent-verifier/local-typecheck-3JXL2NMG.mjs.map +1 -0
- package/dist/agent-verifier/{materialize-workspace-EWGZIVOY.mjs → materialize-workspace-BKZLLFI4.mjs} +20 -20
- package/dist/agent-verifier/materialize-workspace-BKZLLFI4.mjs.map +1 -0
- package/dist/agent-verifier/{project-state-7GR6BQTQ.mjs → project-state-XKUSCFSV.mjs} +3 -2
- package/dist/agent-verifier/project-state-XKUSCFSV.mjs.map +1 -0
- package/dist/agent-verifier/{prompt-3BAINGAQ.mjs → prompt-VKHMCQT6.mjs} +2 -1
- package/dist/agent-verifier/prompt-VKHMCQT6.mjs.map +1 -0
- package/dist/agent-verifier/{reducer-bundle-preflight-C73LEXI2.mjs → reducer-bundle-preflight-7NYZF5ZT.mjs} +6 -9
- package/dist/agent-verifier/reducer-bundle-preflight-7NYZF5ZT.mjs.map +1 -0
- package/dist/agent-verifier/reducer-contract-preflight-COD2CO22.mjs +11 -0
- package/dist/agent-verifier/reducer-contract-preflight-COD2CO22.mjs.map +1 -0
- package/dist/agent-verifier/{reducer-native-test-harness-GMWBUISX.mjs → reducer-native-test-harness-D4VWPIAC.mjs} +14 -17
- package/dist/agent-verifier/reducer-native-test-harness-D4VWPIAC.mjs.map +1 -0
- package/dist/agent-verifier/static-scaffold-JCRBDKEH.mjs +26 -0
- package/dist/agent-verifier/static-scaffold-JCRBDKEH.mjs.map +1 -0
- package/dist/agent-verifier/{sync-LOQAH4RC.mjs → sync-UTL2IIZV.mjs} +35 -39
- package/dist/agent-verifier/sync-UTL2IIZV.mjs.map +1 -0
- package/dist/agent-verifier/{test-YOJERVHN.mjs → test-H26XCBFA.mjs} +29 -31
- package/dist/agent-verifier/test-H26XCBFA.mjs.map +1 -0
- package/dist/agent-verifier/workspace-codegen-WPZHMATU.mjs +10 -0
- package/dist/agent-verifier/workspace-codegen-WPZHMATU.mjs.map +1 -0
- package/dist/agent-verifier/{workspace-dependencies-HZ6VVS4G.mjs → workspace-dependencies-ULZZZPNX.mjs} +5 -4
- package/dist/agent-verifier/workspace-dependencies-ULZZZPNX.mjs.map +1 -0
- package/dist/{chunk-TSJVWTJO.js → chunk-GXM7RRZJ.js} +14 -11
- package/dist/chunk-GXM7RRZJ.js.map +1 -0
- package/dist/{chunk-3XNJT3RK.js → chunk-P5TITCD3.js} +808 -17878
- package/dist/chunk-P5TITCD3.js.map +1 -0
- package/dist/{global-config-UKSWNDTX.js → global-config-WPJRXVDO.js} +2 -2
- package/dist/global-config-WPJRXVDO.js.map +1 -0
- package/dist/index.js +987 -255
- package/dist/index.js.map +1 -1
- package/dist/internal.js +2 -3
- package/package.json +8 -7
- package/skills/dreamboard/references/building-your-first-game.md +510 -0
- package/skills/dreamboard/references/cli.md +104 -0
- package/skills/dreamboard/references/game-interface.md +548 -0
- package/skills/dreamboard/references/manifest-authoring.md +597 -0
- package/skills/dreamboard/references/quickstart.md +66 -0
- package/skills/dreamboard/references/reducer.md +864 -0
- package/skills/dreamboard/references/rule-authoring.md +147 -0
- package/skills/dreamboard/references/testing.md +249 -0
- package/skills/dreamboard/scripts/events-extract.mjs +218 -0
- package/dist/agent-verifier/chunk-54TAYXUD.mjs +0 -12
- package/dist/agent-verifier/chunk-HBNDKQT5.mjs +0 -8381
- package/dist/agent-verifier/chunk-LI3ZR3BI.mjs +0 -41
- package/dist/agent-verifier/chunk-U6OJN7XS.mjs +0 -8092
- package/dist/agent-verifier/local-typecheck-QFYYAZOK.mjs +0 -9
- package/dist/agent-verifier/reducer-contract-preflight-22X7DSZW.mjs +0 -10
- package/dist/agent-verifier/static-scaffold-4YEQME5N.mjs +0 -28
- package/dist/agent-verifier/testing-5K2BJYF2.mjs +0 -674
- package/dist/agent-verifier/workspace-codegen-JDZJRSDV.mjs +0 -11
- package/dist/chunk-3XNJT3RK.js.map +0 -1
- package/dist/chunk-7FOO4AJI.js +0 -50
- package/dist/chunk-7FOO4AJI.js.map +0 -1
- package/dist/chunk-TSJVWTJO.js.map +0 -1
- package/dist/internal.d.ts +0 -311
- package/dist/runtime-packages/ui-host-runtime/src/actor-principal.ts +0 -71
- package/dist/runtime-packages/ui-host-runtime/src/browser-interaction.ts +0 -139
- package/dist/runtime-packages/ui-host-runtime/src/components/host-controls.tsx +0 -374
- package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback-toaster.tsx +0 -266
- package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback.tsx +0 -212
- package/dist/runtime-packages/ui-host-runtime/src/components/host-primitives.tsx +0 -271
- package/dist/runtime-packages/ui-host-runtime/src/components/host-session-metadata.tsx +0 -135
- package/dist/runtime-packages/ui-host-runtime/src/components/index.ts +0 -5
- package/dist/runtime-packages/ui-host-runtime/src/components/perf-overlay.tsx +0 -194
- package/dist/runtime-packages/ui-host-runtime/src/gameplay-authority-transport.ts +0 -626
- package/dist/runtime-packages/ui-host-runtime/src/host-controls.tsx +0 -1
- package/dist/runtime-packages/ui-host-runtime/src/host-feedback.tsx +0 -1
- package/dist/runtime-packages/ui-host-runtime/src/host-session-transport.ts +0 -294
- package/dist/runtime-packages/ui-host-runtime/src/index.ts +0 -3
- package/dist/runtime-packages/ui-host-runtime/src/logger.ts +0 -11
- package/dist/runtime-packages/ui-host-runtime/src/perf.ts +0 -324
- package/dist/runtime-packages/ui-host-runtime/src/plugin-bridge.ts +0 -195
- package/dist/runtime-packages/ui-host-runtime/src/plugin-health-check.ts +0 -138
- package/dist/runtime-packages/ui-host-runtime/src/plugin-messages.ts +0 -159
- package/dist/runtime-packages/ui-host-runtime/src/plugin-session-gateway.ts +0 -551
- package/dist/runtime-packages/ui-host-runtime/src/runtime/index.ts +0 -13
- package/dist/runtime-packages/ui-host-runtime/src/screenshot/projection-to-snapshot.ts +0 -122
- package/dist/runtime-packages/ui-host-runtime/src/screenshot/static-store-api.ts +0 -26
- package/dist/runtime-packages/ui-host-runtime/src/session-ingress-controller.ts +0 -583
- package/dist/runtime-packages/ui-host-runtime/src/session-ingress.ts +0 -219
- package/dist/runtime-packages/ui-host-runtime/src/session-live-runtime.ts +0 -117
- package/dist/runtime-packages/ui-host-runtime/src/session-model.ts +0 -431
- package/dist/runtime-packages/ui-host-runtime/src/session-projection.ts +0 -211
- package/dist/runtime-packages/ui-host-runtime/src/session-recovery.ts +0 -80
- package/dist/runtime-packages/ui-host-runtime/src/session-state-reducer.ts +0 -1034
- package/dist/runtime-packages/ui-host-runtime/src/sse-manager.ts +0 -416
- package/dist/runtime-packages/ui-host-runtime/src/unified-session-store.ts +0 -184
- package/dist/testing-KLSV6CPJ.js +0 -674
- package/dist/testing-KLSV6CPJ.js.map +0 -1
- /package/dist/{global-config-UKSWNDTX.js.map → agent-verifier/chunk-H6XDQJ3N.mjs.map} +0 -0
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
<!-- Generated by apps/dreamboard-cli/scripts/sync-skill-docs.ts. -->
|
|
2
|
+
<!-- Source: docs/reference/game-interface.mdx -->
|
|
3
|
+
|
|
4
|
+
# Game interface
|
|
5
|
+
|
|
6
|
+
Reference for authoring Dreamboard game interfaces.
|
|
7
|
+
|
|
8
|
+
`@dreamboard/ui-sdk` is Dreamboard's game interface package. Use
|
|
9
|
+
it to create UI for the game using projected game view, handle player actions and render prompts
|
|
10
|
+
windows.
|
|
11
|
+
|
|
12
|
+
## Package boundary
|
|
13
|
+
|
|
14
|
+
Use `@dreamboard/ui-sdk` for:
|
|
15
|
+
|
|
16
|
+
- runtime bootstrap and loading/error shell
|
|
17
|
+
- reducer-view reads for the controlling seat
|
|
18
|
+
- typed action, prompt, and window submission
|
|
19
|
+
- lobby and session metadata
|
|
20
|
+
- presentational UI and board primitives
|
|
21
|
+
|
|
22
|
+
## Import surface
|
|
23
|
+
|
|
24
|
+
Game UIs should import from `@dreamboard/ui-sdk` only.
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import {
|
|
28
|
+
ErrorBoundary,
|
|
29
|
+
GameSkeleton,
|
|
30
|
+
PluginRuntime,
|
|
31
|
+
ToastProvider,
|
|
32
|
+
useActions,
|
|
33
|
+
useGameSelector,
|
|
34
|
+
useGameView,
|
|
35
|
+
useGameplayPrompts,
|
|
36
|
+
useGameplayWindows,
|
|
37
|
+
useLobby,
|
|
38
|
+
useMe,
|
|
39
|
+
usePlayerInfo,
|
|
40
|
+
usePluginSession,
|
|
41
|
+
} from "@dreamboard/ui-sdk";
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Runtime shell
|
|
45
|
+
|
|
46
|
+
### `PluginRuntime`
|
|
47
|
+
|
|
48
|
+
`PluginRuntime` waits for the first reducer-native state-sync snapshot and then
|
|
49
|
+
provides runtime, session, and plugin-state context to authored hooks.
|
|
50
|
+
|
|
51
|
+
| Prop | Required | Notes |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| `children` | Yes | Rendered after runtime initialization succeeds |
|
|
54
|
+
| `timeout` | No | Milliseconds to wait for first state-sync snapshot; defaults to `10000` |
|
|
55
|
+
| `loadingComponent` | No | Replaces the default loading shell |
|
|
56
|
+
| `errorComponent` | No | Receives the runtime boot error string |
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { PluginRuntime } from "@dreamboard/ui-sdk";
|
|
60
|
+
import { createRoot } from "react-dom/client";
|
|
61
|
+
|
|
62
|
+
createRoot(document.getElementById("root")!).render(
|
|
63
|
+
<PluginRuntime timeout={15000}>
|
|
64
|
+
<App />
|
|
65
|
+
</PluginRuntime>,
|
|
66
|
+
);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### `ErrorBoundary`
|
|
70
|
+
|
|
71
|
+
Wrap the root UI so authored render failures stay inside the plugin instead of
|
|
72
|
+
blanking the whole frame.
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { ErrorBoundary, PluginRuntime } from "@dreamboard/ui-sdk";
|
|
76
|
+
|
|
77
|
+
<ErrorBoundary>
|
|
78
|
+
<PluginRuntime>
|
|
79
|
+
<App />
|
|
80
|
+
</PluginRuntime>
|
|
81
|
+
</ErrorBoundary>;
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `ToastProvider` and `useToast()`
|
|
85
|
+
|
|
86
|
+
Use `ToastProvider` once near the root. Use `useToast()` from children when the
|
|
87
|
+
UI needs transient feedback that is not reducer state.
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
import { ToastProvider, useToast } from "@dreamboard/ui-sdk";
|
|
91
|
+
|
|
92
|
+
function EndTurnButton() {
|
|
93
|
+
const { success } = useToast();
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<button onClick={() => success("Turn submitted")}>
|
|
97
|
+
End turn
|
|
98
|
+
</button>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`useToast()` returns:
|
|
104
|
+
|
|
105
|
+
- `toasts`
|
|
106
|
+
- `show(message, type?, duration?)`
|
|
107
|
+
- `dismiss(id)`
|
|
108
|
+
- `success(message, duration?)`
|
|
109
|
+
- `error(message, duration?)`
|
|
110
|
+
- `info(message, duration?)`
|
|
111
|
+
- `warning(message, duration?)`
|
|
112
|
+
|
|
113
|
+
### `GameSkeleton`
|
|
114
|
+
|
|
115
|
+
Use `GameSkeleton` while the plugin session is still loading or when the UI
|
|
116
|
+
needs a fallback shell.
|
|
117
|
+
|
|
118
|
+
| Prop | Required | Notes |
|
|
119
|
+
| --- | --- | --- |
|
|
120
|
+
| `variant` | No | One of `default`, `cards`, `players`, or `minimal` |
|
|
121
|
+
| `message` | No | Loading or placeholder text |
|
|
122
|
+
| `className` | No | Additional container classes |
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
import { GameSkeleton, usePluginSession } from "@dreamboard/ui-sdk";
|
|
126
|
+
|
|
127
|
+
function AppLoader() {
|
|
128
|
+
const { status } = usePluginSession();
|
|
129
|
+
|
|
130
|
+
if (status === "loading") {
|
|
131
|
+
return <GameSkeleton variant="default" message="Loading game..." />;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return <App />;
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## View and session hooks
|
|
139
|
+
|
|
140
|
+
### `useGameView()`
|
|
141
|
+
|
|
142
|
+
Reads the full reducer-projected view for the controlling seat.
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
const view = useGameView();
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Use this when the component genuinely needs the whole view object. Otherwise,
|
|
149
|
+
prefer `useGameSelector(...)`.
|
|
150
|
+
|
|
151
|
+
### `useGameSelector(selector, equalityFn?)`
|
|
152
|
+
|
|
153
|
+
Reads one derived slice from the projected reducer view and only re-renders
|
|
154
|
+
when that slice changes according to `equalityFn`.
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
const legalCardIds = useGameSelector(
|
|
158
|
+
(view) => new Set(view.legalCardIds),
|
|
159
|
+
(left, right) =>
|
|
160
|
+
left.size === right.size && [...left].every((cardId) => right.has(cardId)),
|
|
161
|
+
);
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Use selector hooks for:
|
|
165
|
+
|
|
166
|
+
- compact status text
|
|
167
|
+
- legal-target hints
|
|
168
|
+
- small card or resource subsets
|
|
169
|
+
- board-specific render inputs
|
|
170
|
+
|
|
171
|
+
### `usePluginSession()`
|
|
172
|
+
|
|
173
|
+
Returns runtime session metadata for the current plugin.
|
|
174
|
+
|
|
175
|
+
| Field | Type | Notes |
|
|
176
|
+
| --- | --- | --- |
|
|
177
|
+
| `status` | `"loading" \| "ready"` | Session initialization status |
|
|
178
|
+
| `sessionId` | `string \| null` | Current session ID |
|
|
179
|
+
| `controllablePlayerIds` | `string[]` | Seats the user can control |
|
|
180
|
+
| `controllingPlayerId` | `string \| null` | Currently selected seat |
|
|
181
|
+
| `userId` | `string \| null` | Current user ID |
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
const { controllingPlayerId, controllablePlayerIds, status } =
|
|
185
|
+
usePluginSession();
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### `useLobby()`
|
|
189
|
+
|
|
190
|
+
Returns the current lobby snapshot from state-sync.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
const lobby = useLobby();
|
|
194
|
+
const seatCount = lobby.seats.length;
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Use this for seat order, display names, colours, and host markers.
|
|
198
|
+
|
|
199
|
+
### `useMe()`
|
|
200
|
+
|
|
201
|
+
Returns the player currently being controlled by this user.
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
const me = useMe();
|
|
205
|
+
// me.playerId
|
|
206
|
+
// me.name
|
|
207
|
+
// me.color
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
This throws if there is no controlling player, so it is for playable seats, not
|
|
211
|
+
spectator-only UI.
|
|
212
|
+
|
|
213
|
+
### `usePlayerInfo()`
|
|
214
|
+
|
|
215
|
+
Builds a `Map<PlayerId, Player>` from the current lobby snapshot.
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
const players = usePlayerInfo();
|
|
219
|
+
const judge = players.get("player-1");
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Use it when the reducer view contains player IDs and the UI needs labels,
|
|
223
|
+
colours, or host markers.
|
|
224
|
+
|
|
225
|
+
## Actions, prompts, and windows
|
|
226
|
+
|
|
227
|
+
### `useActions()`
|
|
228
|
+
|
|
229
|
+
`useActions()` is the typed reducer action surface for the current phase.
|
|
230
|
+
|
|
231
|
+
| Field | Notes |
|
|
232
|
+
| --- | --- |
|
|
233
|
+
| `phase` | Current runtime phase |
|
|
234
|
+
| `commands` | Typed reducer action factories for the current phase |
|
|
235
|
+
| `availableActions` | `ReadonlySet` of currently available action names |
|
|
236
|
+
| `can(name)` | Whether an action is currently available |
|
|
237
|
+
| `dispatch(command)` | Submit one action |
|
|
238
|
+
| `validate(command)` | Validate one action without submitting it |
|
|
239
|
+
| `respondToPrompt(prompt, response)` | Submit a prompt response |
|
|
240
|
+
| `submitWindowAction(window, command)` | Submit a gameplay-window action |
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
const phase = useActions();
|
|
244
|
+
|
|
245
|
+
if (phase.phase === "placeThing") {
|
|
246
|
+
await phase.dispatch(
|
|
247
|
+
phase.commands.placeThing({
|
|
248
|
+
cardId: "a-dog",
|
|
249
|
+
ringId: "ring-1",
|
|
250
|
+
}),
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Use `phase.commands.<action>(...)` instead of hand-writing `{ type, params }`
|
|
256
|
+
objects. The command and phase types come from the generated UI contract.
|
|
257
|
+
|
|
258
|
+
`dispatch(...)`, `validate(...)`, `respondToPrompt(...)`, and
|
|
259
|
+
`submitWindowAction(...)` reject when runtime validation or submission fails.
|
|
260
|
+
|
|
261
|
+
### `useGameplayPrompts(promptId?)`
|
|
262
|
+
|
|
263
|
+
Returns active prompts for the controlling seat. Pass a prompt ID to narrow the
|
|
264
|
+
result to one prompt family.
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
const judgePrompts = useGameplayPrompts("judge-placement");
|
|
268
|
+
|
|
269
|
+
if (judgePrompts[0]) {
|
|
270
|
+
await phase.respondToPrompt(judgePrompts[0], "ring-2");
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Use prompts for reducer-owned deferred input, not ad hoc local modal state.
|
|
275
|
+
|
|
276
|
+
Typed prompt response example:
|
|
277
|
+
|
|
278
|
+
```tsx
|
|
279
|
+
import type { PromptResponse } from "@dreamboard/ui-contract";
|
|
280
|
+
import { useActions, useGameplayPrompts } from "@dreamboard/ui-sdk";
|
|
281
|
+
|
|
282
|
+
export function JudgePromptActions() {
|
|
283
|
+
const phase = useActions();
|
|
284
|
+
const prompts = useGameplayPrompts("judge-placement");
|
|
285
|
+
const activePrompt = prompts[0];
|
|
286
|
+
|
|
287
|
+
if (!activePrompt) {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const chooseRing = async (ringId: "ring-1" | "ring-2" | "ring-3") => {
|
|
292
|
+
const response: PromptResponse<"judge-placement"> = ringId;
|
|
293
|
+
await phase.respondToPrompt(activePrompt, response);
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
return (
|
|
297
|
+
<>
|
|
298
|
+
<button onClick={() => void chooseRing("ring-1")}>Ring 1</button>
|
|
299
|
+
<button onClick={() => void chooseRing("ring-2")}>Ring 2</button>
|
|
300
|
+
<button onClick={() => void chooseRing("ring-3")}>Ring 3</button>
|
|
301
|
+
</>
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### `useGameplayWindows(windowId?)`
|
|
307
|
+
|
|
308
|
+
Returns active gameplay windows for the controlling seat. Pass a window ID to
|
|
309
|
+
filter the result.
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
const tradeWindows = useGameplayWindows("trade-offer");
|
|
313
|
+
|
|
314
|
+
if (tradeWindows[0]) {
|
|
315
|
+
await phase.submitWindowAction(tradeWindows[0], {
|
|
316
|
+
type: "acceptTrade",
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Window actions are still reducer-defined and typed from the generated contract.
|
|
322
|
+
|
|
323
|
+
Typed window action example:
|
|
324
|
+
|
|
325
|
+
```tsx
|
|
326
|
+
import { windowCommands } from "../shared/generated/ui-contract";
|
|
327
|
+
import { useActions, useGameplayWindows } from "@dreamboard/ui-sdk";
|
|
328
|
+
|
|
329
|
+
export function TradeWindowActions() {
|
|
330
|
+
const phase = useActions();
|
|
331
|
+
const windows = useGameplayWindows("trade-offer");
|
|
332
|
+
const activeWindow = windows[0];
|
|
333
|
+
|
|
334
|
+
if (!activeWindow) {
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const acceptTrade = async () => {
|
|
339
|
+
await phase.submitWindowAction(
|
|
340
|
+
activeWindow,
|
|
341
|
+
windowCommands["trade-offer"].acceptTrade({
|
|
342
|
+
offerId: "offer-1",
|
|
343
|
+
}),
|
|
344
|
+
);
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
const declineTrade = async () => {
|
|
348
|
+
await phase.submitWindowAction(
|
|
349
|
+
activeWindow,
|
|
350
|
+
windowCommands["trade-offer"].declineTrade(),
|
|
351
|
+
);
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
return (
|
|
355
|
+
<>
|
|
356
|
+
<button onClick={() => void acceptTrade()}>Accept</button>
|
|
357
|
+
<button onClick={() => void declineTrade()}>Decline</button>
|
|
358
|
+
</>
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Import `windowCommands` from your workspace's generated
|
|
364
|
+
`shared/generated/ui-contract.ts` file.
|
|
365
|
+
|
|
366
|
+
## Presentational primitives
|
|
367
|
+
|
|
368
|
+
These components are presentational. Feed them from reducer view data and
|
|
369
|
+
explicit props.
|
|
370
|
+
|
|
371
|
+
| Export | Use it for |
|
|
372
|
+
| --- | --- |
|
|
373
|
+
| `Card` | One authored card face |
|
|
374
|
+
| `Hand` | Responsive hand layout with render props |
|
|
375
|
+
| `PlayArea` | Shared played-card or centre-table region |
|
|
376
|
+
| `PlayerInfo` | Player badges, scores, and active-seat markers |
|
|
377
|
+
| `ActionButton` | One action with availability, loading, and cost state |
|
|
378
|
+
| `ActionPanel` / `ActionGroup` | Grouped action regions |
|
|
379
|
+
| `ResourceCounter` | Resource totals |
|
|
380
|
+
| `CostDisplay` | Cost breakdowns |
|
|
381
|
+
| `PhaseIndicator` | Current phase or step status |
|
|
382
|
+
| `GameEndDisplay` | Final rankings and scores |
|
|
383
|
+
| `DiceRoller` | Reducer-driven dice results |
|
|
384
|
+
| `Drawer` and related exports | Mobile overflow or detail panels |
|
|
385
|
+
|
|
386
|
+
`DiceRoller` is display-only. In reducer-native games, dice values are
|
|
387
|
+
typically driven by authored die state updated through reducer runtime effects
|
|
388
|
+
such as `effects.rollDie(...)`.
|
|
389
|
+
|
|
390
|
+
### `Card`
|
|
391
|
+
|
|
392
|
+
`Card` renders one `CardItem`. Use `renderContent` when the default face is not
|
|
393
|
+
enough.
|
|
394
|
+
|
|
395
|
+
```tsx
|
|
396
|
+
<Card
|
|
397
|
+
card={card}
|
|
398
|
+
selected={selectedIds.includes(card.id)}
|
|
399
|
+
onCardClick={(cardId) => setSelectedIds([cardId])}
|
|
400
|
+
renderContent={(item) => <ThingCardFace card={item} />}
|
|
401
|
+
/>
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### `Hand`
|
|
405
|
+
|
|
406
|
+
`Hand` is a render-prop primitive. You supply `renderCard`, `renderDrawer`, and
|
|
407
|
+
`renderEmpty`.
|
|
408
|
+
|
|
409
|
+
```tsx
|
|
410
|
+
<Hand
|
|
411
|
+
cards={view.handCards}
|
|
412
|
+
selectedIds={selectedIds}
|
|
413
|
+
renderCard={({ card, x, y, zIndex, isSelected }) => (
|
|
414
|
+
<div
|
|
415
|
+
key={card.id}
|
|
416
|
+
style={{
|
|
417
|
+
position: "absolute",
|
|
418
|
+
left: x,
|
|
419
|
+
transform: `translateY(${y}px)`,
|
|
420
|
+
zIndex,
|
|
421
|
+
}}
|
|
422
|
+
>
|
|
423
|
+
<Card
|
|
424
|
+
card={card}
|
|
425
|
+
selected={isSelected}
|
|
426
|
+
onCardClick={(cardId) => setSelectedIds([cardId])}
|
|
427
|
+
/>
|
|
428
|
+
</div>
|
|
429
|
+
)}
|
|
430
|
+
renderDrawer={({ cards }) => <button>View {cards.length} cards</button>}
|
|
431
|
+
renderEmpty={() => <p>No cards in hand</p>}
|
|
432
|
+
/>
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
Use `Hand` when you want SDK layout behaviour but game-specific card faces.
|
|
436
|
+
|
|
437
|
+
### `PlayArea`
|
|
438
|
+
|
|
439
|
+
`PlayArea` renders a shared card region from an array of `CardItem` values.
|
|
440
|
+
|
|
441
|
+
```tsx
|
|
442
|
+
<PlayArea
|
|
443
|
+
cards={view.trickCards}
|
|
444
|
+
layout="row"
|
|
445
|
+
renderCard={(card) => <ThingCardFace card={card} />}
|
|
446
|
+
/>
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### `ActionButton`
|
|
450
|
+
|
|
451
|
+
Use `ActionButton` for one reducer action. It can reflect availability,
|
|
452
|
+
resource affordability, and loading state.
|
|
453
|
+
|
|
454
|
+
```tsx
|
|
455
|
+
<ActionButton
|
|
456
|
+
label="Build road"
|
|
457
|
+
cost={{ brick: 1, lumber: 1 }}
|
|
458
|
+
currentResources={view.resources}
|
|
459
|
+
resourceDefs={resourceDefs}
|
|
460
|
+
available={phase.can("buildRoad")}
|
|
461
|
+
onClick={() => phase.dispatch(phase.commands.buildRoad())}
|
|
462
|
+
/>
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### `ActionPanel` and `ActionGroup`
|
|
466
|
+
|
|
467
|
+
Use these to keep the action surface grouped by phase or intent.
|
|
468
|
+
|
|
469
|
+
```tsx
|
|
470
|
+
<ActionPanel title="Your turn" state={phase.phase}>
|
|
471
|
+
<ActionGroup title="Build">
|
|
472
|
+
<ActionButton
|
|
473
|
+
label="Build road"
|
|
474
|
+
available={phase.can("buildRoad")}
|
|
475
|
+
onClick={() => phase.dispatch(phase.commands.buildRoad())}
|
|
476
|
+
/>
|
|
477
|
+
</ActionGroup>
|
|
478
|
+
</ActionPanel>
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### `PlayerInfo`
|
|
482
|
+
|
|
483
|
+
`PlayerInfo` is a display component. Pass display-ready values, not raw lobby
|
|
484
|
+
records.
|
|
485
|
+
|
|
486
|
+
```tsx
|
|
487
|
+
<PlayerInfo
|
|
488
|
+
playerId={me.playerId}
|
|
489
|
+
name={me.name}
|
|
490
|
+
color={me.color}
|
|
491
|
+
isCurrentPlayer
|
|
492
|
+
isActive={view.activePlayerId === me.playerId}
|
|
493
|
+
score={view.scores[me.playerId] ?? 0}
|
|
494
|
+
/>
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
## Board primitives
|
|
498
|
+
|
|
499
|
+
Use board primitives when the reducer view already contains render-ready board
|
|
500
|
+
data.
|
|
501
|
+
|
|
502
|
+
| Export | Use it for |
|
|
503
|
+
| --- | --- |
|
|
504
|
+
| `TrackBoard` | Linear, circular, or branching tracks |
|
|
505
|
+
| `SquareGrid` | Chess-like or tile-grid boards |
|
|
506
|
+
| `HexGrid` | Hex maps with tiles, edges, and vertices |
|
|
507
|
+
| `NetworkGraph` | Nodes, connections, and route graphs |
|
|
508
|
+
| `ZoneMap` | Region or area control boards |
|
|
509
|
+
| `SlotSystem` | Worker-placement and slot occupancy layouts |
|
|
510
|
+
|
|
511
|
+
```tsx
|
|
512
|
+
<TrackBoard
|
|
513
|
+
spaces={view.track.spaces}
|
|
514
|
+
pieces={view.track.pieces}
|
|
515
|
+
type="circular"
|
|
516
|
+
renderSpace={(space, pieces) => (
|
|
517
|
+
<g aria-label={space.name ?? space.id}>
|
|
518
|
+
<circle cx={space.position.x} cy={space.position.y} r={24} />
|
|
519
|
+
<text x={space.position.x} y={space.position.y}>
|
|
520
|
+
{pieces.length}
|
|
521
|
+
</text>
|
|
522
|
+
</g>
|
|
523
|
+
)}
|
|
524
|
+
/>
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
Board renderers are still UI code. The reducer should provide:
|
|
528
|
+
|
|
529
|
+
- legal targets
|
|
530
|
+
- ownership markers
|
|
531
|
+
- highlight states
|
|
532
|
+
- labels and annotations
|
|
533
|
+
- grouped piece and card data in the shape the component expects
|
|
534
|
+
|
|
535
|
+
## Exported types
|
|
536
|
+
|
|
537
|
+
Use these root exports when the UI needs to type reducer-owned runtime data.
|
|
538
|
+
|
|
539
|
+
| Type | Meaning |
|
|
540
|
+
| --- | --- |
|
|
541
|
+
| `PhaseActions<Phase>` | Current phase action API returned by `useActions()` |
|
|
542
|
+
| `ActionDefinition` | One available action from gameplay state |
|
|
543
|
+
| `GameplayPromptInstance` | One typed active prompt instance |
|
|
544
|
+
| `GameplayWindowInstance` | One typed active window instance |
|
|
545
|
+
| `GameplaySnapshot` | Transport state that sits alongside the projected view |
|
|
546
|
+
| `PluginStateSnapshot` | Complete state-sync payload delivered to the plugin |
|
|
547
|
+
| `LobbyState` | Current lobby seats and host metadata |
|
|
548
|
+
| `Player` | Simplified player metadata from the lobby |
|