dreamboard 0.1.7 → 0.1.9

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.
Files changed (92) hide show
  1. package/LICENSE +89 -0
  2. package/NOTICE +1 -0
  3. package/README.md +22 -178
  4. package/dist/{chunk-MP7IBNWW.js → chunk-BMYC6772.js} +577 -38
  5. package/dist/chunk-BMYC6772.js.map +1 -0
  6. package/dist/chunk-D4HDZEJT.js +37 -0
  7. package/dist/chunk-EM7NOFFC.js +19072 -0
  8. package/dist/chunk-EM7NOFFC.js.map +1 -0
  9. package/dist/chunk-SET56RVA.js +435 -0
  10. package/dist/chunk-SET56RVA.js.map +1 -0
  11. package/dist/{dist-B3R64F6G.js → dist-WJRJNFLI.js} +3 -3
  12. package/dist/global-config-VQJZ3JOA.js +15 -0
  13. package/dist/global-config-VQJZ3JOA.js.map +1 -0
  14. package/dist/index.js +23993 -24387
  15. package/dist/index.js.map +1 -1
  16. package/dist/keychain-backend-2DL3C6BS.js +125 -0
  17. package/dist/keychain-backend-2DL3C6BS.js.map +1 -0
  18. package/dist/{prompt-GMZABCJC.js → prompt-IV67HSPU.js} +2 -2
  19. package/dist/scaffold/assets/static/app/tsconfig.framework.json +24 -0
  20. package/dist/scaffold/assets/static/app/tsconfig.json +3 -0
  21. package/dist/scaffold/assets/static/ui/App.tsx +22 -0
  22. package/dist/scaffold/assets/static/ui/index.tsx +12 -0
  23. package/dist/scaffold/assets/static/ui/style.css +4 -0
  24. package/dist/scaffold/assets/static/ui/tsconfig.framework.json +31 -0
  25. package/dist/scaffold/assets/static/ui/tsconfig.json +5 -0
  26. package/dist/src-K2NK3A4P.js +626 -0
  27. package/dist/src-K2NK3A4P.js.map +1 -0
  28. package/package.json +41 -4
  29. package/skills/dreamboard/SKILL.md +126 -59
  30. package/skills/dreamboard/references/authoring-lifecycle.md +102 -0
  31. package/skills/dreamboard/references/board-surfaces.md +36 -0
  32. package/skills/dreamboard/references/board-topology.md +443 -0
  33. package/skills/dreamboard/references/boards-and-topology.md +100 -0
  34. package/skills/dreamboard/references/card-actions.md +107 -0
  35. package/skills/dreamboard/references/cli.md +120 -0
  36. package/skills/dreamboard/references/core-concepts.md +514 -0
  37. package/skills/dreamboard/references/custom-renderers.md +26 -0
  38. package/skills/dreamboard/references/derived-values.md +55 -0
  39. package/skills/dreamboard/references/effects.md +111 -0
  40. package/skills/dreamboard/references/game-contract.md +89 -0
  41. package/skills/dreamboard/references/game-definition.md +89 -0
  42. package/skills/dreamboard/references/game-shell.md +80 -0
  43. package/skills/dreamboard/references/hand-surfaces.md +33 -0
  44. package/skills/dreamboard/references/index.md +112 -0
  45. package/skills/dreamboard/references/inputs-and-targets.md +160 -0
  46. package/skills/dreamboard/references/interactions.md +158 -0
  47. package/skills/dreamboard/references/manifest-fields.md +137 -0
  48. package/skills/dreamboard/references/manifest.md +81 -0
  49. package/skills/dreamboard/references/package-surfaces.md +69 -0
  50. package/skills/dreamboard/references/phases.md +145 -0
  51. package/skills/dreamboard/references/prompts-and-choices.md +55 -0
  52. package/skills/dreamboard/references/quickstart.md +71 -0
  53. package/skills/dreamboard/references/rule-authoring.md +81 -77
  54. package/skills/dreamboard/references/setup-bootstrap.md +78 -0
  55. package/skills/dreamboard/references/stages-and-zones.md +59 -0
  56. package/skills/dreamboard/references/static-views.md +67 -0
  57. package/skills/dreamboard/references/table-queries-and-ops.md +103 -0
  58. package/skills/dreamboard/references/testing-bases.md +147 -0
  59. package/skills/dreamboard/references/testing-generated-contracts.md +142 -0
  60. package/skills/dreamboard/references/testing-runtime-assertions.md +124 -0
  61. package/skills/dreamboard/references/testing-scenarios.md +148 -0
  62. package/skills/dreamboard/references/testing-ui-tests.md +174 -0
  63. package/skills/dreamboard/references/testing.md +161 -0
  64. package/skills/dreamboard/references/ui-architecture.md +137 -0
  65. package/skills/dreamboard/references/ui-components.md +34 -0
  66. package/skills/dreamboard/references/views.md +72 -0
  67. package/skills/dreamboard/references/workspace-layout.md +136 -0
  68. package/dist/chunk-2H7UOFLK.js +0 -11
  69. package/dist/chunk-MP7IBNWW.js.map +0 -1
  70. package/dist/chunk-WM7TY7DV.js +0 -2328
  71. package/dist/chunk-WM7TY7DV.js.map +0 -1
  72. package/dist/embedded-harness-IHP7A2ZX.js +0 -344
  73. package/dist/embedded-harness-IHP7A2ZX.js.map +0 -1
  74. package/skills/dreamboard/references/adversarial-testing.md +0 -113
  75. package/skills/dreamboard/references/all-players-tracking.md +0 -75
  76. package/skills/dreamboard/references/api-reference.md +0 -197
  77. package/skills/dreamboard/references/app-best-practices.md +0 -98
  78. package/skills/dreamboard/references/building-your-first-game.md +0 -49
  79. package/skills/dreamboard/references/hands-vs-decks.md +0 -124
  80. package/skills/dreamboard/references/manifest-authoring.md +0 -328
  81. package/skills/dreamboard/references/phase-handlers.md +0 -134
  82. package/skills/dreamboard/references/scenario-format.md +0 -99
  83. package/skills/dreamboard/references/test-harness.md +0 -225
  84. package/skills/dreamboard/references/ui-best-practices.md +0 -156
  85. package/skills/dreamboard/references/ui-genre-resource-management.md +0 -187
  86. package/skills/dreamboard/references/ui-genre-trick-taking.md +0 -110
  87. package/skills/dreamboard/references/ui-genre-worker-placement.md +0 -143
  88. package/skills/dreamboard/references/ui-style-guide.md +0 -54
  89. package/skills/dreamboard/scripts/events-extract.mjs +0 -218
  90. /package/dist/{chunk-2H7UOFLK.js.map → chunk-D4HDZEJT.js.map} +0 -0
  91. /package/dist/{dist-B3R64F6G.js.map → dist-WJRJNFLI.js.map} +0 -0
  92. /package/dist/{prompt-GMZABCJC.js.map → prompt-IV67HSPU.js.map} +0 -0
@@ -1,143 +0,0 @@
1
- # UI Guide: Worker Placement Games
2
-
3
- Patterns for Agricola, Viticulture, Lords of Waterdeep, Caverna, and similar euro-style worker placement games.
4
-
5
- ## Game characteristics
6
-
7
- - Players place **worker tokens** on shared **action slots** to gain resources or take actions.
8
- - Slots may be exclusive (one player per round) or shared.
9
- - Phases typically include: placement, resolution/harvest, and cleanup.
10
- - Key UI signals: available slots, slot costs/rewards, number of workers remaining, resource counts.
11
-
12
- ## Recommended SDK components
13
-
14
- ### Primary
15
-
16
- | Component | Usage |
17
- | --------------------- | ----------------------------------------------------------------------------------------------------- |
18
- | `SlotSystem` | Core board — renders all action slots with occupants. Use `layout="grouped"` to organize by category. |
19
- | `DefaultSlotItem` | Pre-built slot renderer showing name, description, capacity, cost/reward labels. |
20
- | `DefaultSlotOccupant` | Pre-built worker token display with player color. |
21
- | `ResourceCounter` | Display each player's resource pool (wood, stone, food, etc.). |
22
- | `ActionButton` | "Place Worker" button with integrated cost display and affordability check. |
23
-
24
- ### Supporting
25
-
26
- | Component | Usage |
27
- | ----------------------------- | ------------------------------------------------------------ |
28
- | `ActionPanel` / `ActionGroup` | Group available actions (e.g., "Place Worker", "End Turn"). |
29
- | `CostDisplay` | Show resource costs on slot details. |
30
- | `PlayerInfo` | Show each player's name, workers remaining, and turn status. |
31
- | `PhaseIndicator` | Distinguish placement phase from harvest/scoring phases. |
32
- | `GameEndDisplay` | Final scoring with detailed breakdown. |
33
- | `Drawer` | Mobile drawer for detailed slot inspection. |
34
-
35
- ### Hooks
36
-
37
- | Hook | Usage |
38
- | --------------------------------- | ---------------------------------------------------------------------------------------------- |
39
- | `useSlotSystem(slots, occupants)` | Utility for slot lookups: `getSlot`, `isFull`, `getRemainingCapacity`, `getOccupantsByPlayer`. |
40
- | `useMyResources()` | Current player's resource pool. |
41
- | `useGameState` | Get `isMyTurn`, `currentState`, `currentPlayerIds`. |
42
- | `useAction` | Submit place-worker or end-turn actions. |
43
- | `useUIArgs` | Get phase-specific data (available slots, worker count, etc.). |
44
- | `usePlayerInfo` | Map player IDs to names and colors. |
45
-
46
- ## Key patterns
47
-
48
- ### Slot board with placement
49
-
50
- ```tsx
51
- const { placementPhase } = useUIArgs();
52
- const slots = placementPhase?.slots ?? [];
53
- const occupants = placementPhase?.occupants ?? [];
54
- const availableSlotIds = new Set(placementPhase?.availableSlotIds ?? []);
55
- const slotApi = useSlotSystem(slots, occupants);
56
-
57
- <SlotSystem
58
- slots={slots}
59
- occupants={occupants}
60
- layout="grouped"
61
- renderSlot={(slot, slotOccupants) => (
62
- <DefaultSlotItem
63
- name={slot.name}
64
- description={slot.description}
65
- capacity={slot.capacity}
66
- occupantCount={slotOccupants.length}
67
- isExclusive={slot.exclusive}
68
- isAvailable={availableSlotIds.has(slot.id)}
69
- costLabel={formatCost(slot.cost)}
70
- rewardLabel={formatReward(slot.reward)}
71
- onClick={() => handlePlaceWorker(slot.id)}
72
- renderOccupants={() => (
73
- <div className="flex gap-1">
74
- {slotOccupants.map((o) => (
75
- <DefaultSlotOccupant
76
- key={o.pieceId}
77
- color={playerColors[o.playerId]}
78
- label={playerInfo[o.playerId]?.name}
79
- />
80
- ))}
81
- </div>
82
- )}
83
- />
84
- )}
85
- />;
86
- ```
87
-
88
- ### Resource display
89
-
90
- ```tsx
91
- const resources = useMyResources();
92
-
93
- <ResourceCounter
94
- resources={[
95
- {
96
- type: "wood",
97
- label: "Wood",
98
- icon: TreePine,
99
- iconColor: "text-amber-700",
100
- },
101
- {
102
- type: "stone",
103
- label: "Stone",
104
- icon: Mountain,
105
- iconColor: "text-slate-400",
106
- },
107
- { type: "food", label: "Food", icon: Apple, iconColor: "text-red-400" },
108
- { type: "gold", label: "Gold", icon: Coins, iconColor: "text-yellow-400" },
109
- ]}
110
- counts={resources}
111
- layout="row"
112
- />;
113
- ```
114
-
115
- ### Action buttons with costs
116
-
117
- ```tsx
118
- <ActionButton
119
- label="Build Farm"
120
- cost={{ wood: 2, stone: 1 }}
121
- currentResources={resources}
122
- resourceDefs={resourceDefinitions}
123
- icon={Home}
124
- onClick={() => actions.buildActions.build({ buildingType: "farm" })}
125
- />
126
- ```
127
-
128
- ## UIArgs recommendations
129
-
130
- ```typescript
131
- // shared/ui-args.ts
132
- export interface PlacementPhaseUIArgs {
133
- slots: SlotDefinition[];
134
- occupants: SlotOccupant[];
135
- availableSlotIds: string[]; // Slots the current player can legally place on
136
- workersRemaining: number;
137
- }
138
-
139
- export interface HarvestPhaseUIArgs {
140
- feedingRequired: number; // Food needed
141
- currentFood: number;
142
- }
143
- ```
@@ -1,54 +0,0 @@
1
- # UI Style Guide
2
-
3
- This style guide details the design philosophy, visual tokens, and core components for the Dreamboard.games UI SDK. The framework uses a **Hand-Drawn** aesthetic that emphasizes human creativity over corporate polish.
4
-
5
- ## Design Philosophy
6
-
7
- The Hand-Drawn design style celebrates authentic imperfection and human touch in a digital world. It rejects clinical precision in favor of organic, playful irregularity that evokes sketches on paper, sticky notes on a wall, and napkin diagrams from a brainstorming session.
8
-
9
- ### Core Principles
10
-
11
- - **No Straight Lines**: Every border, shape, and container uses irregular border-radius values to create wobbly, hand-drawn edges that reject geometric perfection.
12
- - **Authentic Texture**: The design layer paper grain, dot patterns, and subtle background textures to simulate physical media (notebook paper, post-its, sketch pads).
13
- - **Playful Rotation**: Elements are deliberately tilted using small rotation transforms (`-rotate-1`, `rotate-2`) to break rigid grid alignment and create casual energy.
14
- - **Hard Offset Shadows**: Reject soft blur shadows entirely. Use solid, offset box-shadows (like `4px 4px 0px`) to create a cut-paper, layered collage aesthetic.
15
- - **Handwritten Typography**: Use exclusively handwritten or marker-style fonts (like Kalam for headings and Patrick Hand for body text) that feel human and approachable.
16
- - **Limited Color Palette**: Stick to pencil blacks (`#2d2d2d`), paper whites (`#fdfbf7`), correction marker red (`#ff4d4d`), post-it yellow (`#fff9c4`), and ballpoint blue (`#2d5da1`).
17
- - **Intentional Messiness**: Embrace overlap, asymmetry, and visual "mistakes" that make the design feel spontaneous.
18
-
19
- ## CSS Tokens & Utilities
20
-
21
- The platform provides several global CSS utilities designed for this aesthetic:
22
-
23
- - **Borders**: `.wobbly-border`, `.wobbly-border-md`, `.wobbly-border-lg` apply the irregular `border-radius` shapes. Used with `border-2`, `border-[3px]`, or `border-[4px]`.
24
- - **Shadows**: `.hard-shadow`, `.hard-shadow-md`, `.hard-shadow-lg` apply the solid offset shadows. Use `.hard-shadow-sm` for active states (buttons pressing flat).
25
-
26
- ## Implementing in Components
27
-
28
- When writing or modifying UI components in `ui/` or `ui-sdk/`:
29
-
30
- ### Containers & Cards
31
-
32
- - Add `wobbly-border-md` or `wobbly-border-lg`.
33
- - Use `border-[3px] border-border` to give it a thick pencil-like stroke.
34
- - Apply `bg-[#fdfbf7]` (warm paper) or `bg-white`.
35
- - Add a solid shadow with `hard-shadow` or `hard-shadow-lg`.
36
- - Slightly rotate the element with `rotate-1` or `-rotate-1`.
37
-
38
- ### Buttons
39
-
40
- - Use `wobbly-border`.
41
- - Normal state: `border-[3px] border-border bg-[#fdfbf7] text-foreground hard-shadow`.
42
- - Hover state: `hover:bg-primary hover:text-white hover:hard-shadow-sm hover:-translate-y-1`.
43
- - Active state: `active:shadow-none active:translate-y-1 active:translate-x-1`.
44
- - Secondary variants can use `bg-[#e5e0d8]` or `bg-[#fff9c4]`.
45
-
46
- ### Typography
47
-
48
- - Add `font-sans` for standard handwritten text or `font-display` for bold marker headings.
49
- - Make things bold! `font-bold` works well with handwritten fonts to make them legible.
50
-
51
- ### Decoration
52
-
53
- - For emphasis, wrap text in a post-it styling: `bg-[#fff9c4] px-2 py-1 border-2 border-border wobbly-border rotate-2 inline-block`.
54
- - Add "tape" to tops of containers: `<div className="absolute top-2 left-1/2 -translate-x-1/2 w-24 h-6 bg-[#e5e0d8] border border-border opacity-80 backdrop-blur-sm -rotate-2 z-10" />`.
@@ -1,218 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { access, readFile } from "node:fs/promises";
4
-
5
- const DEFAULT_EVENTS_PATH = ".dreamboard/run/events.ndjson";
6
-
7
- function printHelp() {
8
- console.log(`Extract fields from dreamboard run artifacts.
9
-
10
- Usage:
11
- node .agents/skills/dreamboard/scripts/events-extract.mjs [options]
12
-
13
- Options:
14
- --file, -f <path> NDJSON file path (default: ${DEFAULT_EVENTS_PATH})
15
- --type <eventType> Filter by event type (repeatable)
16
- --field <path> Dot path to extract (e.g. message.reason)
17
- --player <playerId> Filter by player ID across common message fields
18
- --limit <number> Limit output records
19
- --no-index Omit line index in output
20
- --help, -h Show this help
21
-
22
- Examples:
23
- node .agents/skills/dreamboard/scripts/events-extract.mjs --type YOUR_TURN
24
- node .agents/skills/dreamboard/scripts/events-extract.mjs --type ACTION_REJECTED --field message.reason
25
- node .agents/skills/dreamboard/scripts/events-extract.mjs --player player-2 --field message.availableActions
26
- `);
27
- }
28
-
29
- function parseCliArgs(argv) {
30
- const options = {
31
- filePath: DEFAULT_EVENTS_PATH,
32
- types: new Set(),
33
- includeIndex: true,
34
- };
35
-
36
- for (let index = 0; index < argv.length; index += 1) {
37
- const token = argv[index];
38
- const nextToken = argv[index + 1];
39
-
40
- if (token === "--help" || token === "-h") {
41
- printHelp();
42
- process.exit(0);
43
- }
44
- if (token === "--no-index") {
45
- options.includeIndex = false;
46
- continue;
47
- }
48
- if (token === "--file" || token === "-f") {
49
- if (!nextToken) {
50
- throw new Error("--file requires a value");
51
- }
52
- options.filePath = nextToken;
53
- index += 1;
54
- continue;
55
- }
56
- if (token === "--type") {
57
- if (!nextToken) {
58
- throw new Error("--type requires a value");
59
- }
60
- options.types.add(nextToken);
61
- index += 1;
62
- continue;
63
- }
64
- if (token === "--field") {
65
- if (!nextToken) {
66
- throw new Error("--field requires a value");
67
- }
68
- options.fieldPath = nextToken;
69
- index += 1;
70
- continue;
71
- }
72
- if (token === "--player") {
73
- if (!nextToken) {
74
- throw new Error("--player requires a value");
75
- }
76
- options.playerId = nextToken;
77
- index += 1;
78
- continue;
79
- }
80
- if (token === "--limit") {
81
- if (!nextToken) {
82
- throw new Error("--limit requires a value");
83
- }
84
- const parsed = Number.parseInt(nextToken, 10);
85
- if (!Number.isFinite(parsed) || parsed <= 0) {
86
- throw new Error("--limit must be a positive integer");
87
- }
88
- options.limit = parsed;
89
- index += 1;
90
- continue;
91
- }
92
-
93
- throw new Error(`Unknown argument: ${token}`);
94
- }
95
-
96
- return options;
97
- }
98
-
99
- function getByPath(value, path) {
100
- const segments = path.split(".").filter(Boolean);
101
- let current = value;
102
-
103
- for (const segment of segments) {
104
- if (current === null || current === undefined) {
105
- return undefined;
106
- }
107
- if (typeof current !== "object") {
108
- return undefined;
109
- }
110
- current = current[segment];
111
- }
112
-
113
- return current;
114
- }
115
-
116
- function extractPlayerCandidates(record) {
117
- const message = record.message ?? {};
118
- const players = new Set();
119
-
120
- const singleCandidates = [
121
- message.playerId,
122
- message.targetPlayer,
123
- message.toUser,
124
- ];
125
- for (const candidate of singleCandidates) {
126
- if (typeof candidate === "string") {
127
- players.add(candidate);
128
- }
129
- }
130
-
131
- const listCandidates = [
132
- message.activePlayers,
133
- message.previousPlayers,
134
- message.currentPlayers,
135
- message.controllablePlayerIds,
136
- message.eligiblePlayerIds,
137
- ];
138
- for (const candidate of listCandidates) {
139
- if (!Array.isArray(candidate)) {
140
- continue;
141
- }
142
- for (const item of candidate) {
143
- if (typeof item === "string") {
144
- players.add(item);
145
- }
146
- }
147
- }
148
-
149
- return [...players];
150
- }
151
-
152
- function toOutputRecord(record, lineIndex, options) {
153
- const output = {};
154
-
155
- if (options.includeIndex) {
156
- output.index = lineIndex;
157
- }
158
- output.observedAt = record.observedAt ?? null;
159
- output.sessionId = record.sessionId ?? null;
160
- output.eventId = record.eventId ?? null;
161
- output.type = record.type ?? null;
162
-
163
- if (options.fieldPath) {
164
- output.field = options.fieldPath;
165
- output.value = getByPath(record, options.fieldPath);
166
- } else {
167
- output.message = record.message ?? null;
168
- }
169
-
170
- return output;
171
- }
172
-
173
- async function main() {
174
- const options = parseCliArgs(process.argv.slice(2));
175
- await access(options.filePath);
176
-
177
- const text = await readFile(options.filePath, "utf8");
178
- const lines = text
179
- .split(/\r?\n/u)
180
- .map((line) => line.trim())
181
- .filter((line) => line.length > 0);
182
-
183
- let emitted = 0;
184
- for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
185
- const line = lines[lineIndex];
186
- let record;
187
- try {
188
- record = JSON.parse(line);
189
- } catch {
190
- continue;
191
- }
192
-
193
- if (options.types.size > 0 && !options.types.has(record.type ?? "")) {
194
- continue;
195
- }
196
-
197
- if (options.playerId) {
198
- const players = extractPlayerCandidates(record);
199
- if (!players.includes(options.playerId)) {
200
- continue;
201
- }
202
- }
203
-
204
- const output = toOutputRecord(record, lineIndex + 1, options);
205
- console.log(JSON.stringify(output));
206
- emitted += 1;
207
-
208
- if (options.limit !== undefined && emitted >= options.limit) {
209
- break;
210
- }
211
- }
212
- }
213
-
214
- main().catch((error) => {
215
- const message = error instanceof Error ? error.message : String(error);
216
- console.error(`events-extract failed: ${message}`);
217
- process.exit(1);
218
- });