board-game-engine-react 1.0.3 → 1.0.5

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.
@@ -719,7 +719,7 @@
719
719
  "expression": "(player == '0' and destinationCoordinates[1] == 0) or (player == '1' and destinationCoordinates[1] == 7)",
720
720
  "arguments": {
721
721
  "player": {
722
- "type": "RelativePath",
722
+ "type": "relativePath",
723
723
  "target": {
724
724
  "type": "contextPath",
725
725
  "path": ["originalTarget"]
@@ -727,7 +727,7 @@
727
727
  "path": ["entities", 0, "rule", "player"]
728
728
  },
729
729
  "destinationCoordinates": {
730
- "type": "Coordinates",
730
+ "type": "coordinates",
731
731
  "target": {
732
732
  "type": "contextPath",
733
733
  "path": ["target"]
@@ -107,7 +107,7 @@
107
107
  "conditions": [
108
108
  {
109
109
  "conditionType": "Is",
110
- "target": { "type": "Parent" },
110
+ "target": { "type": "parent" },
111
111
  "matcher": { "name": "mainGrid" }
112
112
  }
113
113
  ]
@@ -161,7 +161,7 @@
161
161
  "conditions": [
162
162
  {
163
163
  "conditionType": "Is",
164
- "target": { "type": "Parent" },
164
+ "target": { "type": "parent" },
165
165
  "matcher": { "name": "stock" }
166
166
  },
167
167
  {
@@ -195,7 +195,7 @@
195
195
  "conditions": [
196
196
  {
197
197
  "conditionType": "Is",
198
- "target": { "type": "Parent" },
198
+ "target": { "type": "parent" },
199
199
  "matcher": { "name": "stock" }
200
200
  },
201
201
  {
@@ -231,7 +231,7 @@
231
231
  "conditions": [
232
232
  {
233
233
  "conditionType": "Is",
234
- "target": { "type": "Parent" },
234
+ "target": { "type": "parent" },
235
235
  "matcher": { "name": "discard" }
236
236
  },
237
237
  {
@@ -298,7 +298,7 @@
298
298
  "conditions": [
299
299
  {
300
300
  "conditionType": "Is",
301
- "target": { "type": "Parent" },
301
+ "target": { "type": "parent" },
302
302
  "matcher": {
303
303
  "name": "hand",
304
304
  "player": {
@@ -319,13 +319,13 @@
319
319
  {
320
320
  "conditionType": "Is",
321
321
  "matcher": {
322
- "type": "Pick",
322
+ "type": "pick",
323
323
  "properties": ["suit"],
324
324
  "target": {
325
325
  "conditions": [
326
326
  {
327
327
  "conditionType": "Is",
328
- "target": { "type": "Parent" },
328
+ "target": { "type": "parent" },
329
329
  "matcher": { "name": "discard" }
330
330
  },
331
331
  {
@@ -339,13 +339,13 @@
339
339
  {
340
340
  "conditionType": "Is",
341
341
  "matcher": {
342
- "type": "Pick",
342
+ "type": "pick",
343
343
  "properties": ["value"],
344
344
  "target": {
345
345
  "conditions": [
346
346
  {
347
347
  "conditionType": "Is",
348
- "target": { "type": "Parent" },
348
+ "target": { "type": "parent" },
349
349
  "matcher": { "name": "discard" }
350
350
  },
351
351
  {
@@ -452,7 +452,7 @@
452
452
  "conditions": [
453
453
  {
454
454
  "conditionType": "Is",
455
- "target": { "type": "Parent" },
455
+ "target": { "type": "parent" },
456
456
  "matcher": { "name": "discard" }
457
457
  },
458
458
  {
@@ -512,7 +512,7 @@
512
512
  "matcher": {
513
513
  "name": "score",
514
514
  "player": {
515
- "type": "RelativePath",
515
+ "type": "relativePath",
516
516
  "target": {
517
517
  "conditions": [
518
518
  {
@@ -538,7 +538,7 @@
538
538
  "expression": "existingScore + sum(faceValues)",
539
539
  "arguments": {
540
540
  "existingScore": {
541
- "type": "RelativePath",
541
+ "type": "relativePath",
542
542
  "target": {
543
543
  "conditions": [
544
544
  {
@@ -546,7 +546,7 @@
546
546
  "matcher": {
547
547
  "name": "score",
548
548
  "player": {
549
- "type": "RelativePath",
549
+ "type": "relativePath",
550
550
  "target": {
551
551
  "conditions": [
552
552
  {
@@ -574,7 +574,7 @@
574
574
  "conditions": [
575
575
  {
576
576
  "conditionType": "Is",
577
- "target": { "type": "Parent" },
577
+ "target": { "type": "parent" },
578
578
  "matcher": {
579
579
  "name": "hand",
580
580
  "player": {
@@ -590,7 +590,7 @@
590
590
  "expression": "cardValue == 8 ? 50 : (cardValue >= 10 and cardValue <= 13) ? 10 : cardValue",
591
591
  "arguments": {
592
592
  "cardValue": {
593
- "conditionType": "RelativePath",
593
+ "type": "relativePath",
594
594
  "target": {
595
595
 
596
596
  "type": "contextPath",
@@ -627,7 +627,7 @@
627
627
  "expression": "score >= numPlayers * 50",
628
628
  "arguments": {
629
629
  "score": {
630
- "type": "RelativePath",
630
+ "type": "relativePath",
631
631
  "target": {
632
632
  "type": "contextPath",
633
633
  "path": ["loopTarget"]
@@ -0,0 +1,219 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>Board Game Engine Examples</title>
6
+ <style>
7
+ body {
8
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
9
+ margin: 0;
10
+ padding: 1rem 1.5rem 2rem;
11
+ background: #0f172a;
12
+ color: #e5e7eb;
13
+ }
14
+ h1 {
15
+ font-size: 1.4rem;
16
+ margin-bottom: 0.75rem;
17
+ }
18
+ .controls {
19
+ display: flex;
20
+ flex-wrap: wrap;
21
+ gap: 0.75rem;
22
+ align-items: center;
23
+ margin-bottom: 1rem;
24
+ }
25
+ select, input, button {
26
+ background: #020617;
27
+ color: #e5e7eb;
28
+ border-radius: 999px;
29
+ border: 1px solid #1f2937;
30
+ padding: 0.35rem 0.9rem;
31
+ font-size: 0.9rem;
32
+ outline: none;
33
+ }
34
+ select:focus, input:focus, button:focus {
35
+ border-color: #38bdf8;
36
+ box-shadow: 0 0 0 1px #38bdf8;
37
+ }
38
+ button {
39
+ cursor: pointer;
40
+ background: linear-gradient(135deg, #22c55e, #16a34a);
41
+ border: none;
42
+ color: #022c22;
43
+ font-weight: 600;
44
+ }
45
+ button:hover {
46
+ filter: brightness(1.08);
47
+ }
48
+ button:disabled {
49
+ opacity: 0.5;
50
+ cursor: default;
51
+ }
52
+ label {
53
+ font-size: 0.85rem;
54
+ opacity: 0.85;
55
+ }
56
+ .layout {
57
+ display: grid;
58
+ grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
59
+ gap: 1rem;
60
+ align-items: flex-start;
61
+ }
62
+ #debug {
63
+ background: #020617;
64
+ border-radius: 0.85rem;
65
+ border: 1px solid #1f2937;
66
+ min-height: 320px;
67
+ padding: 0.5rem;
68
+ overflow: auto;
69
+ }
70
+ .panel {
71
+ background: #020617;
72
+ border-radius: 0.85rem;
73
+ border: 1px solid #1f2937;
74
+ padding: 0.75rem 0.9rem;
75
+ min-height: 160px;
76
+ }
77
+ .panel h2 {
78
+ margin: 0 0 0.5rem;
79
+ font-size: 0.9rem;
80
+ letter-spacing: 0.06em;
81
+ text-transform: uppercase;
82
+ opacity: 0.7;
83
+ }
84
+ pre {
85
+ margin: 0;
86
+ font-size: 0.78rem;
87
+ line-height: 1.4;
88
+ white-space: pre-wrap;
89
+ word-break: break-word;
90
+ }
91
+ .badge {
92
+ display: inline-flex;
93
+ align-items: center;
94
+ gap: 0.25rem;
95
+ padding: 0.1rem 0.5rem;
96
+ border-radius: 999px;
97
+ background: rgba(56, 189, 248, 0.1);
98
+ border: 1px solid rgba(56, 189, 248, 0.5);
99
+ font-size: 0.7rem;
100
+ text-transform: uppercase;
101
+ letter-spacing: 0.08em;
102
+ }
103
+ </style>
104
+ </head>
105
+ <body>
106
+ <h1>Board Game Engine – Examples</h1>
107
+ <div class="controls">
108
+ <label>
109
+ Game&nbsp;
110
+ <select id="game-select">
111
+ <option value="tic-tac-toe">Tic Tac Toe</option>
112
+ <option value="connect-four">Connect Four</option>
113
+ <option value="reversi">Reversi</option>
114
+ <option value="eights">Crazy Eights</option>
115
+ <option value="checkers">Checkers</option>
116
+ </select>
117
+ </label>
118
+ <label>
119
+ Players&nbsp;
120
+ <input id="players-input" type="number" min="1" max="6" value="2" />
121
+ </label>
122
+ <button id="start-btn">Start / Reset Game</button>
123
+ <span class="badge">Debug UI attaches below</span>
124
+ </div>
125
+
126
+ <div class="layout">
127
+ <div id="debug"></div>
128
+ <div class="panel">
129
+ <h2>Client snapshot</h2>
130
+ <pre id="state-view">(no game started)</pre>
131
+ </div>
132
+ </div>
133
+
134
+ <script src="../dist/board-game-engine.js"></script>
135
+ <script>
136
+ (function () {
137
+ const gameFiles = {
138
+ 'tic-tac-toe': './tic-tac-toe.json',
139
+ 'connect-four': './connect-four.json',
140
+ 'reversi': './reversi.json',
141
+ 'eights': './eights.json',
142
+ 'checkers': './checkers.json',
143
+ };
144
+
145
+ const selectEl = document.getElementById('game-select');
146
+ const playersEl = document.getElementById('players-input');
147
+ const startBtn = document.getElementById('start-btn');
148
+ const stateView = document.getElementById('state-view');
149
+
150
+ let currentClient = null;
151
+
152
+ function toSerializableSnapshot(snapshot) {
153
+ // Avoid circular structures by swapping in originalG (plain JSON)
154
+ if (!snapshot || !snapshot.state) return snapshot;
155
+ const { state, ...rest } = snapshot;
156
+ const { originalG, G, ...stateRest } = state;
157
+ return {
158
+ ...rest,
159
+ state: {
160
+ ...stateRest,
161
+ // originalG is what came from boardgame.io before our deserialization step
162
+ G: originalG ?? G,
163
+ },
164
+ };
165
+ }
166
+
167
+ async function startGame() {
168
+ const key = selectEl.value;
169
+ const file = gameFiles[key];
170
+ if (!file || !window.BoardGameEngine || !window.BoardGameEngine.Client) {
171
+ stateView.textContent = 'Engine bundle or game config not available.';
172
+ return;
173
+ }
174
+
175
+ startBtn.disabled = true;
176
+ stateView.textContent = 'Loading ' + key + '…';
177
+
178
+ try {
179
+ const res = await fetch(file);
180
+ const rules = await res.json();
181
+
182
+ const numPlayers =
183
+ Number(playersEl.value) ||
184
+ rules.numPlayers ||
185
+ rules.maxPlayers ||
186
+ 2;
187
+
188
+ const client = new window.BoardGameEngine.Client({
189
+ gameRules: JSON.stringify(rules),
190
+ gameName: key,
191
+ numPlayers,
192
+ onClientUpdate: () => {
193
+ const snapshot = client.getState();
194
+ const safe = toSerializableSnapshot(snapshot);
195
+ stateView.textContent = JSON.stringify(safe, null, 2);
196
+ },
197
+ });
198
+
199
+ currentClient = client.connect();
200
+ if (currentClient && typeof currentClient.getState === 'function') {
201
+ // Force initial snapshot after connect
202
+ const snapshot = currentClient.getState();
203
+ const safe = toSerializableSnapshot(snapshot);
204
+ stateView.textContent = JSON.stringify(safe, null, 2);
205
+ }
206
+ } catch (err) {
207
+ console.error(err);
208
+ stateView.textContent = 'Error loading game: ' + (err && err.message ? err.message : String(err));
209
+ } finally {
210
+ startBtn.disabled = false;
211
+ }
212
+ }
213
+
214
+ startBtn.addEventListener('click', startGame);
215
+ })();
216
+ </script>
217
+ </body>
218
+ </html>
219
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "board-game-engine-react",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "React library for using board-game-engine",
5
5
  "main": "./dist/board-game-engine-react.cjs",
6
6
  "module": "./dist/board-game-engine-react.mjs",
@@ -94,7 +94,7 @@
94
94
  "vite": "^5.0.0"
95
95
  },
96
96
  "dependencies": {
97
- "board-game-engine": "^2.0.0",
97
+ "board-game-engine": "^2.0.1",
98
98
  "react": "^18.2.0",
99
99
  "react-error-boundary": "^3.1.4",
100
100
  "react-transition-group": "^4.4.5"