@bendyline/gilde 0.1.92 → 0.1.94

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 (137) hide show
  1. package/README.md +6 -4
  2. package/authoring/chat-models/underdog-saluki-27b-iq2-mix.json +159 -0
  3. package/data/chat-models/index.json +1 -1
  4. package/data/chat-models/raw-index.json +1 -1
  5. package/data/chat-models/un/underdog-saluki-27b-iq2-mix/manifest.json +164 -0
  6. package/data/chat-models/un/underdog-saluki-27b-iq2-mix/versions/1.0.0/manifest.json +14 -0
  7. package/data/craftbook-templates/br/branding-website/manifest.json +2 -1
  8. package/data/craftbook-templates/br/branding-website/versions/1.1.4/craftbook.json +346 -0
  9. package/data/craftbook-templates/br/branding-website/versions/1.1.4/test.json +164 -0
  10. package/data/craftbook-templates/fr/freeze-scope/versions/1.4.0/craftbook.json +94 -0
  11. package/data/craftbook-templates/fr/freeze-scope/versions/1.4.0/test.json +131 -0
  12. package/data/craftbook-templates/index.json +1 -1
  13. package/data/craftbook-templates/na/narrated-slideshow/manifest.json +2 -1
  14. package/data/craftbook-templates/na/narrated-slideshow/versions/1.1.7/craftbook.json +315 -0
  15. package/data/craftbook-templates/na/narrated-slideshow/versions/1.1.7/test.json +89 -0
  16. package/data/craftbook-templates/na/narrated-slideshow/versions/1.1.8/craftbook.json +323 -0
  17. package/data/craftbook-templates/na/narrated-slideshow/versions/1.1.8/test.json +217 -0
  18. package/data/craftbook-templates/ph/photo-library-nightly/manifest.json +22 -0
  19. package/data/craftbook-templates/ph/photo-library-nightly/versions/1.0.0/craftbook.json +186 -0
  20. package/data/craftbook-templates/ph/photo-library-nightly/versions/1.0.0/test.json +69 -0
  21. package/data/craftbook-templates/po/powerpoint-deck/manifest.json +2 -1
  22. package/data/craftbook-templates/po/powerpoint-deck/versions/1.7.17/craftbook.json +486 -0
  23. package/data/craftbook-templates/po/powerpoint-deck/versions/1.7.17/test.json +265 -0
  24. package/data/craftbook-templates/po/powerpoint-deck/versions/1.7.18/craftbook.json +501 -0
  25. package/data/craftbook-templates/po/powerpoint-deck/versions/1.7.18/test.json +266 -0
  26. package/data/craftbook-templates/raw-index.json +1 -1
  27. package/data/craftbook-templates/re/report-pdf/manifest.json +2 -1
  28. package/data/craftbook-templates/re/report-pdf/versions/1.1.7/craftbook.json +316 -0
  29. package/data/craftbook-templates/re/report-pdf/versions/1.1.7/test.json +101 -0
  30. package/data/craftbook-templates/re/report-pdf/versions/1.1.8/craftbook.json +324 -0
  31. package/data/craftbook-templates/re/report-pdf/versions/1.1.8/test.json +258 -0
  32. package/data/craftbook-templates/re/research-report/manifest.json +2 -1
  33. package/data/craftbook-templates/re/research-report/versions/1.0.4/craftbook.json +286 -0
  34. package/data/craftbook-templates/re/research-report/versions/1.0.4/test.json +183 -0
  35. package/data/craftbook-templates/re/research-to-document/manifest.json +2 -1
  36. package/data/craftbook-templates/re/research-to-document/versions/1.2.7/craftbook.json +387 -0
  37. package/data/craftbook-templates/re/research-to-document/versions/1.2.7/test.json +242 -0
  38. package/data/craftbook-templates/re/research-to-document/versions/1.2.8/craftbook.json +395 -0
  39. package/data/craftbook-templates/re/research-to-document/versions/1.2.8/test.json +254 -0
  40. package/data/gezel-templates/cu/curator/manifest.json +20 -0
  41. package/data/gezel-templates/cu/curator/versions/1.0.0/about.md +22 -0
  42. package/data/gezel-templates/cu/curator/versions/1.0.0/manifest.json +23 -0
  43. package/data/gezel-templates/index.json +1 -1
  44. package/data/gezel-templates/pu/puzzelaar/manifest.json +19 -0
  45. package/data/gezel-templates/pu/puzzelaar/versions/1.0.0/about.md +18 -0
  46. package/data/gezel-templates/pu/puzzelaar/versions/1.0.0/manifest.json +16 -0
  47. package/data/gezel-templates/raw-index.json +1 -1
  48. package/data/gezel-templates/wo/woordsmid/manifest.json +19 -0
  49. package/data/gezel-templates/wo/woordsmid/versions/1.0.0/about.md +18 -0
  50. package/data/gezel-templates/wo/woordsmid/versions/1.0.0/manifest.json +16 -0
  51. package/data/image-models/index.json +1 -1
  52. package/data/image-models/mi/ming-image-0.1-design-bf16/manifest.json +39 -0
  53. package/data/image-models/mi/ming-image-0.1-design-bf16/versions/1.0.0/manifest.json +31 -0
  54. package/data/image-models/raw-index.json +1 -1
  55. package/data/knowledge-catalogs/be/bendyline-how-to-books/manifest.json +26 -0
  56. package/data/knowledge-catalogs/be/bendyline-how-to-books/versions/2026.10.8/manifest.json +8950 -0
  57. package/data/knowledge-catalogs/index.json +1 -1
  58. package/data/knowledge-catalogs/mi/microsoftdocs-aspnet-core-en/manifest.json +22 -0
  59. package/data/knowledge-catalogs/mi/microsoftdocs-aspnet-core-en/versions/2026.10.16/manifest.json +18270 -0
  60. package/data/knowledge-catalogs/mi/microsoftdocs-azure-ai-platform-en/manifest.json +23 -0
  61. package/data/knowledge-catalogs/mi/microsoftdocs-azure-ai-platform-en/versions/2026.10.16/manifest.json +1098 -0
  62. package/data/knowledge-catalogs/mi/microsoftdocs-azure-apps-compute-en/manifest.json +23 -0
  63. package/data/knowledge-catalogs/mi/microsoftdocs-azure-apps-compute-en/versions/2026.10.16/manifest.json +722 -0
  64. package/data/knowledge-catalogs/mi/microsoftdocs-azure-data-aiot-en/manifest.json +23 -0
  65. package/data/knowledge-catalogs/mi/microsoftdocs-azure-data-aiot-en/versions/2026.10.16/manifest.json +530 -0
  66. package/data/knowledge-catalogs/mi/microsoftdocs-azure-management-hybrid-en/manifest.json +23 -0
  67. package/data/knowledge-catalogs/mi/microsoftdocs-azure-management-hybrid-en/versions/2026.10.16/manifest.json +602 -0
  68. package/data/knowledge-catalogs/mi/microsoftdocs-azure-network-security-en/manifest.json +23 -0
  69. package/data/knowledge-catalogs/mi/microsoftdocs-azure-network-security-en/versions/2026.10.16/manifest.json +250 -0
  70. package/data/knowledge-catalogs/mi/microsoftdocs-dotnet-en/manifest.json +22 -0
  71. package/data/knowledge-catalogs/mi/microsoftdocs-dotnet-en/versions/2026.10.16/manifest.json +16794 -0
  72. package/data/knowledge-catalogs/mi/microsoftdocs-entity-framework-en/manifest.json +22 -0
  73. package/data/knowledge-catalogs/mi/microsoftdocs-entity-framework-en/versions/2026.10.16/manifest.json +1106 -0
  74. package/data/knowledge-catalogs/mi/microsoftdocs-microsoft-365-en/manifest.json +22 -0
  75. package/data/knowledge-catalogs/mi/microsoftdocs-microsoft-365-en/versions/2026.10.16/manifest.json +234 -0
  76. package/data/knowledge-catalogs/mi/microsoftdocs-powershell-en/manifest.json +22 -0
  77. package/data/knowledge-catalogs/mi/microsoftdocs-powershell-en/versions/2026.10.16/manifest.json +522 -0
  78. package/data/knowledge-catalogs/mi/microsoftdocs-sql-server-en/manifest.json +22 -0
  79. package/data/knowledge-catalogs/mi/microsoftdocs-sql-server-en/versions/2026.10.16/manifest.json +1850 -0
  80. package/data/knowledge-catalogs/mi/microsoftdocs-windows-apps-en/manifest.json +22 -0
  81. package/data/knowledge-catalogs/mi/microsoftdocs-windows-apps-en/versions/2026.10.16/manifest.json +1734 -0
  82. package/data/knowledge-catalogs/mi/microsoftdocs-windows-server-en/manifest.json +22 -0
  83. package/data/knowledge-catalogs/mi/microsoftdocs-windows-server-en/versions/2026.10.16/manifest.json +774 -0
  84. package/data/knowledge-catalogs/raw-index.json +1 -1
  85. package/data/project-types/ch/checkers/versions/1.2.3/about.md +9 -0
  86. package/data/project-types/ch/checkers/versions/1.2.3/game.json +77 -0
  87. package/data/project-types/ch/checkers/versions/1.2.3/manifest.json +182 -0
  88. package/data/project-types/ch/checkers/versions/1.2.3/mission.md +9 -0
  89. package/data/project-types/ch/checkers/versions/1.2.3/pages/board/index.html +1158 -0
  90. package/data/project-types/ch/chess/versions/1.0.6/about.md +9 -0
  91. package/data/project-types/ch/chess/versions/1.0.6/game.json +127 -0
  92. package/data/project-types/ch/chess/versions/1.0.6/manifest.json +196 -0
  93. package/data/project-types/ch/chess/versions/1.0.6/mission.md +8 -0
  94. package/data/project-types/ch/chess/versions/1.0.6/pages/board/index.html +851 -0
  95. package/data/project-types/fi/fitness-coach/versions/1.1.0/about.md +8 -0
  96. package/data/project-types/fi/fitness-coach/versions/1.1.0/craftbooks/training-recap.json +34 -0
  97. package/data/project-types/fi/fitness-coach/versions/1.1.0/manifest.json +229 -0
  98. package/data/project-types/fi/fitness-coach/versions/1.1.0/mission.md +7 -0
  99. package/data/project-types/fi/fitness-coach/versions/1.1.0/pages/dashboard/index.html +383 -0
  100. package/data/project-types/fi/fitness-coach/versions/1.1.0/training.json +6 -0
  101. package/data/project-types/fl/flashcards/versions/1.1.2/about.md +8 -0
  102. package/data/project-types/fl/flashcards/versions/1.1.2/deck.json +7 -0
  103. package/data/project-types/fl/flashcards/versions/1.1.2/manifest.json +169 -0
  104. package/data/project-types/fl/flashcards/versions/1.1.2/mission.md +6 -0
  105. package/data/project-types/fl/flashcards/versions/1.1.2/pages/review/index.html +477 -0
  106. package/data/project-types/fl/flashcards/versions/1.2.0/about.md +8 -0
  107. package/data/project-types/fl/flashcards/versions/1.2.0/deck.json +7 -0
  108. package/data/project-types/fl/flashcards/versions/1.2.0/manifest.json +207 -0
  109. package/data/project-types/fl/flashcards/versions/1.2.0/mission.md +6 -0
  110. package/data/project-types/fl/flashcards/versions/1.2.0/pages/review/index.html +549 -0
  111. package/data/project-types/go/go/versions/1.0.4/about.md +9 -0
  112. package/data/project-types/go/go/versions/1.0.4/game.json +103 -0
  113. package/data/project-types/go/go/versions/1.0.4/manifest.json +182 -0
  114. package/data/project-types/go/go/versions/1.0.4/mission.md +8 -0
  115. package/data/project-types/go/go/versions/1.0.4/pages/board/index.html +855 -0
  116. package/data/project-types/index.json +1 -1
  117. package/data/project-types/la/language-trainer/versions/1.1.0/about.md +8 -0
  118. package/data/project-types/la/language-trainer/versions/1.1.0/manifest.json +245 -0
  119. package/data/project-types/la/language-trainer/versions/1.1.0/mission.md +4 -0
  120. package/data/project-types/la/language-trainer/versions/1.1.0/pages/dashboard/index.html +468 -0
  121. package/data/project-types/la/language-trainer/versions/1.1.0/progress.json +10 -0
  122. package/data/project-types/la/language-trainer/versions/1.1.0/reviews.json +3 -0
  123. package/data/project-types/la/language-trainer/versions/1.1.0/scenarios.json +84 -0
  124. package/data/project-types/raw-index.json +1 -1
  125. package/data/project-types/wo/word-clues/manifest.json +20 -0
  126. package/data/project-types/wo/word-clues/versions/1.0.0/about.md +7 -0
  127. package/data/project-types/wo/word-clues/versions/1.0.0/game.json +14 -0
  128. package/data/project-types/wo/word-clues/versions/1.0.0/manifest.json +205 -0
  129. package/data/project-types/wo/word-clues/versions/1.0.0/mission.md +3 -0
  130. package/data/project-types/wo/word-clues/versions/1.0.0/pages/board/index.html +399 -0
  131. package/data/project-types/wo/word-clues/versions/1.0.0/words.json +216 -0
  132. package/package.json +5 -3
  133. package/schemas/craftbook-doc.schema.json +14 -0
  134. package/schemas/craftbook-template-version.schema.json +14 -0
  135. package/schemas/craftbook-test.schema.json +4 -1
  136. package/schemas/image-model-version.schema.json +2 -1
  137. package/schemas/project-type-version.schema.json +131 -0
@@ -0,0 +1,855 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <meta name="gezel-demo" content="standalone" />
7
+ <title>Go</title>
8
+ <style>
9
+ :root {
10
+ color-scheme: light dark;
11
+ --bg: #faf7f2;
12
+ --card: #fff;
13
+ --ink: #2b2620;
14
+ --muted: #7a7166;
15
+ --accent: #9a5928;
16
+ --track: #e8dfd2;
17
+ --wood-a: #d4a45f;
18
+ --wood-b: #b97d3f;
19
+ --wood-edge: #694322;
20
+ --line: rgba(49, 30, 18, 0.78);
21
+ --black-stone-a: #4a4540;
22
+ --black-stone-b: #171411;
23
+ --white-stone-a: #fffdf6;
24
+ --white-stone-b: #d8d0c3;
25
+ --last-move: #c55e32;
26
+ --legal: #52745a;
27
+ }
28
+ :root[data-theme='dark'] {
29
+ --bg: #1c1a17;
30
+ --card: #262320;
31
+ --ink: #efe9e0;
32
+ --muted: #a59a8c;
33
+ --accent: #e0894a;
34
+ --track: #3a352f;
35
+ --wood-a: #a7733c;
36
+ --wood-b: #744a29;
37
+ --wood-edge: #2b1a10;
38
+ --line: rgba(28, 18, 12, 0.88);
39
+ --last-move: #f19a5f;
40
+ --legal: #7da486;
41
+ }
42
+ @media (prefers-color-scheme: dark) {
43
+ :root:not([data-theme='light']) {
44
+ --bg: #1c1a17;
45
+ --card: #262320;
46
+ --ink: #efe9e0;
47
+ --muted: #a59a8c;
48
+ --accent: #e0894a;
49
+ --track: #3a352f;
50
+ --wood-a: #a7733c;
51
+ --wood-b: #744a29;
52
+ --wood-edge: #2b1a10;
53
+ --line: rgba(28, 18, 12, 0.88);
54
+ --last-move: #f19a5f;
55
+ --legal: #7da486;
56
+ }
57
+ }
58
+ * { box-sizing: border-box; }
59
+ body {
60
+ margin: 0;
61
+ padding: 1.25rem;
62
+ background: var(--bg);
63
+ color: var(--ink);
64
+ font: 15px/1.5 system-ui, -apple-system, 'Segoe UI', sans-serif;
65
+ }
66
+ main { max-width: 820px; margin: 0 auto; }
67
+ header {
68
+ display: flex;
69
+ align-items: baseline;
70
+ justify-content: space-between;
71
+ gap: 0.75rem;
72
+ flex-wrap: wrap;
73
+ }
74
+ h1 {
75
+ margin: 0;
76
+ font-family: Georgia, 'PT Serif', 'Times New Roman', serif;
77
+ font-size: 1.35rem;
78
+ }
79
+ button { font: inherit; }
80
+ .newgame,
81
+ .pass-button {
82
+ min-height: 44px;
83
+ border: 1px solid var(--track);
84
+ border-radius: 6px;
85
+ padding: 0.32rem 0.7rem;
86
+ background: var(--card);
87
+ color: var(--ink);
88
+ cursor: pointer;
89
+ }
90
+ .newgame:hover,
91
+ .pass-button:hover { border-color: var(--accent); }
92
+ .pass-button:disabled { cursor: default; opacity: 0.55; }
93
+ .status { min-height: 1.5em; margin: 0.15rem 0 0.9rem; color: var(--muted); }
94
+ .status.thinking { color: var(--accent); }
95
+ .banner {
96
+ display: none;
97
+ margin-bottom: 0.75rem;
98
+ padding: 0.45rem 0.7rem;
99
+ border: 1px solid var(--accent);
100
+ border-radius: 6px;
101
+ font-size: 0.85rem;
102
+ }
103
+ .banner.show { display: block; }
104
+ .note {
105
+ margin: 0 0 0.85rem;
106
+ padding: 0.5rem 0.65rem;
107
+ border: 1px solid var(--track);
108
+ border-radius: 6px;
109
+ background: var(--card);
110
+ color: var(--muted);
111
+ font-size: 0.8rem;
112
+ }
113
+ .table { display: grid; grid-template-columns: minmax(0, 1fr) 220px; gap: 0.9rem; }
114
+ .boardwrap {
115
+ min-width: 0;
116
+ padding: clamp(0.8rem, 3vw, 1.35rem);
117
+ border: 1px solid var(--wood-edge);
118
+ border-radius: 14px;
119
+ background:
120
+ linear-gradient(95deg, rgba(255,255,255,0.08), transparent 35%, rgba(74,37,16,0.08)),
121
+ linear-gradient(145deg, var(--wood-a), var(--wood-b));
122
+ box-shadow:
123
+ inset 0 1px 0 rgba(255, 255, 255, 0.22),
124
+ inset 0 -5px 9px rgba(74, 37, 16, 0.24),
125
+ 0 10px 24px rgba(31, 21, 15, 0.22);
126
+ }
127
+ .board {
128
+ display: grid;
129
+ grid-template-columns: repeat(var(--board-size), 1fr);
130
+ aspect-ratio: 1;
131
+ user-select: none;
132
+ }
133
+ .point {
134
+ position: relative;
135
+ display: grid;
136
+ min-width: 0;
137
+ min-height: 0;
138
+ place-items: center;
139
+ padding: 0;
140
+ border: 0;
141
+ background: transparent;
142
+ color: inherit;
143
+ }
144
+ .point::before,
145
+ .point::after {
146
+ position: absolute;
147
+ z-index: 0;
148
+ background: var(--line);
149
+ content: '';
150
+ pointer-events: none;
151
+ }
152
+ .point::before {
153
+ top: calc(50% - 0.5px);
154
+ right: var(--right-edge, 0);
155
+ left: var(--left-edge, 0);
156
+ height: 1px;
157
+ }
158
+ .point::after {
159
+ top: var(--top-edge, 0);
160
+ bottom: var(--bottom-edge, 0);
161
+ left: calc(50% - 0.5px);
162
+ width: 1px;
163
+ }
164
+ .point.star:not(.occupied) .star-dot {
165
+ position: relative;
166
+ z-index: 1;
167
+ width: clamp(3px, 14%, 7px);
168
+ aspect-ratio: 1;
169
+ border-radius: 50%;
170
+ background: var(--line);
171
+ }
172
+ .point.legal { cursor: pointer; }
173
+ .point.legal:not(.occupied):hover .star-dot {
174
+ position: relative;
175
+ z-index: 2;
176
+ width: 30%;
177
+ aspect-ratio: 1;
178
+ border-radius: 50%;
179
+ background: var(--legal);
180
+ box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.16);
181
+ }
182
+ .stone {
183
+ position: relative;
184
+ z-index: 2;
185
+ width: 88%;
186
+ aspect-ratio: 1;
187
+ border: 1px solid rgba(32, 22, 16, 0.45);
188
+ border-radius: 50%;
189
+ box-shadow:
190
+ inset 0 4px 5px rgba(255, 255, 255, 0.2),
191
+ inset 0 -5px 7px rgba(0, 0, 0, 0.28),
192
+ 0 3px 5px rgba(45, 27, 15, 0.35);
193
+ transition: transform 140ms ease-out;
194
+ }
195
+ .stone.black { background: radial-gradient(circle at 34% 27%, var(--black-stone-a), var(--black-stone-b) 72%); }
196
+ .stone.white { background: radial-gradient(circle at 34% 27%, var(--white-stone-a), var(--white-stone-b) 72%); }
197
+ .point.last .stone::after {
198
+ position: absolute;
199
+ inset: 34%;
200
+ border-radius: 50%;
201
+ background: var(--last-move);
202
+ content: '';
203
+ }
204
+ .coord {
205
+ position: absolute;
206
+ z-index: 3;
207
+ color: rgba(44, 27, 16, 0.72);
208
+ font-size: clamp(0.38rem, 1vw, 0.62rem);
209
+ font-weight: 700;
210
+ line-height: 1;
211
+ pointer-events: none;
212
+ }
213
+ .coord.rank { top: 4%; left: 4%; }
214
+ .coord.file { right: 4%; bottom: 4%; }
215
+ .aside { display: flex; flex-direction: column; gap: 0.6rem; min-width: 0; }
216
+ .panel {
217
+ padding: 0.7rem 0.85rem;
218
+ border: 1px solid var(--track);
219
+ border-radius: 10px;
220
+ background: var(--card);
221
+ font-size: 0.85rem;
222
+ }
223
+ .panel h2 {
224
+ margin: 0 0 0.35rem;
225
+ color: var(--muted);
226
+ font-size: 0.72rem;
227
+ letter-spacing: 0.05em;
228
+ text-transform: uppercase;
229
+ }
230
+ .move-thought { font-style: italic; }
231
+ .move-thought .who {
232
+ display: block;
233
+ margin-bottom: 0.15rem;
234
+ color: var(--muted);
235
+ font-size: 0.78rem;
236
+ font-style: normal;
237
+ }
238
+ .game-actions { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
239
+ .capture-count { color: var(--muted); font-size: 0.78rem; }
240
+ .log { max-height: 210px; margin: 0; padding-left: 1.2rem; overflow-y: auto; }
241
+ .log li { margin: 0.12rem 0; color: var(--muted); }
242
+ .log li.latest { color: var(--ink); }
243
+ dialog {
244
+ width: min(430px, calc(100vw - 2rem));
245
+ padding: 0;
246
+ border: 1px solid var(--track);
247
+ border-radius: 10px;
248
+ background: var(--card);
249
+ color: var(--ink);
250
+ box-shadow: 0 18px 55px rgba(0, 0, 0, 0.35);
251
+ }
252
+ dialog::backdrop { background: rgba(20, 17, 14, 0.62); }
253
+ .dialog-content { padding: 1rem; }
254
+ .dialog-content h2 {
255
+ margin: 0;
256
+ font-family: Georgia, 'PT Serif', serif;
257
+ font-size: 1.1rem;
258
+ }
259
+ .dialog-intro { margin: 0.2rem 0 0.85rem; color: var(--muted); font-size: 0.85rem; }
260
+ fieldset { margin: 0 0 0.75rem; padding: 0; border: 0; }
261
+ legend {
262
+ margin-bottom: 0.35rem;
263
+ color: var(--muted);
264
+ font-size: 0.72rem;
265
+ font-weight: 700;
266
+ letter-spacing: 0.05em;
267
+ text-transform: uppercase;
268
+ }
269
+ .key-tray {
270
+ display: grid;
271
+ grid-template-columns: repeat(3, 1fr);
272
+ gap: 0.35rem;
273
+ padding: 0.35rem;
274
+ border: 1px solid var(--track);
275
+ border-radius: 10px;
276
+ background: var(--track);
277
+ }
278
+ .key-tray.two { grid-template-columns: repeat(2, 1fr); }
279
+ .rule-key {
280
+ padding: 0.45rem;
281
+ border: 1px solid transparent;
282
+ border-radius: 6px;
283
+ background: var(--card);
284
+ color: var(--ink);
285
+ cursor: pointer;
286
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.14);
287
+ }
288
+ .rule-key:hover { border-color: var(--accent); }
289
+ .rule-key[aria-checked='true'] {
290
+ border-color: var(--accent);
291
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2);
292
+ transform: translateY(1px);
293
+ }
294
+ .rule-key strong { display: block; font-size: 0.88rem; }
295
+ .rule-key span { display: block; color: var(--muted); font-size: 0.72rem; }
296
+ .dialog-actions { display: flex; justify-content: flex-end; gap: 0.45rem; margin-top: 0.9rem; }
297
+ .dialog-button {
298
+ min-height: 44px;
299
+ padding: 0.4rem 0.75rem;
300
+ border: 1px solid var(--accent);
301
+ border-radius: 6px;
302
+ background: var(--accent);
303
+ color: var(--bg);
304
+ cursor: pointer;
305
+ }
306
+ .dialog-button.secondary { border-color: var(--track); background: var(--card); color: var(--ink); }
307
+ @media (max-width: 660px) {
308
+ .table { grid-template-columns: 1fr; }
309
+ .aside { display: grid; grid-template-columns: 1fr 1fr; }
310
+ }
311
+ @media (prefers-reduced-motion: reduce) {
312
+ .stone { transition: none; }
313
+ }
314
+ .demo-banner {
315
+ display: flex;
316
+ align-items: center;
317
+ justify-content: space-between;
318
+ gap: 0.75rem;
319
+ margin: 0 0 0.85rem;
320
+ padding: 0.5rem 0.65rem;
321
+ border: 1px solid var(--accent);
322
+ border-radius: 6px;
323
+ background: color-mix(in srgb, var(--card) 88%, var(--accent));
324
+ color: var(--ink);
325
+ font-size: 0.8rem;
326
+ }
327
+ .demo-banner[hidden] { display: none; }
328
+ .demo-banner strong { font-weight: 700; }
329
+ .demo-reset {
330
+ flex: none;
331
+ padding: 0.25rem 0.5rem;
332
+ border: 1px solid var(--accent);
333
+ border-radius: 6px;
334
+ background: var(--card);
335
+ color: var(--ink);
336
+ cursor: pointer;
337
+ font: inherit;
338
+ }
339
+ .demo-reset:hover { border-color: var(--ink); }
340
+ </style>
341
+ </head>
342
+ <body>
343
+ <main>
344
+ <div class="demo-banner" data-gezel-demo-banner hidden>
345
+ <span><strong>Demo mode</strong> — sample data stays in this page.</span>
346
+ <button type="button" class="demo-reset" onclick="location.reload()">Reset demo</button>
347
+ </div>
348
+ <p class="note" id="browser-note" hidden>
349
+ Viewing from a browser tab — the board stays live, but moves happen in the app's Output pane.
350
+ </p>
351
+ <div class="banner" id="banner"></div>
352
+ <header>
353
+ <h1>Go</h1>
354
+ <button type="button" class="newgame" id="newgame">New game</button>
355
+ </header>
356
+ <p class="status" id="status">Setting up the board…</p>
357
+ <div class="table">
358
+ <div class="boardwrap"><div class="board" id="board" aria-label="Go board"></div></div>
359
+ <div class="aside">
360
+ <div class="panel move-thought" id="move-thought-panel" hidden>
361
+ <span class="who">Go-speler says</span>
362
+ <span id="move-thought"></span>
363
+ </div>
364
+ <div class="panel game-actions">
365
+ <button type="button" class="pass-button" id="pass">Pass</button>
366
+ <span class="capture-count" id="captures">Captures — 0 / 0</span>
367
+ </div>
368
+ <div class="panel">
369
+ <h2>Moves</h2>
370
+ <ol class="log" id="log"><li>No moves yet — black opens.</li></ol>
371
+ </div>
372
+ </div>
373
+ </div>
374
+ <dialog id="new-game-dialog" aria-labelledby="new-game-title">
375
+ <div class="dialog-content">
376
+ <h2 id="new-game-title">New game</h2>
377
+ <p class="dialog-intro">Choose a board and scoring balance.</p>
378
+ <fieldset>
379
+ <legend>Board size</legend>
380
+ <div class="key-tray" role="radiogroup" aria-label="Board size">
381
+ <button type="button" class="rule-key size-key" role="radio" aria-checked="true" data-size="9">
382
+ <strong>9 × 9</strong><span>Quick</span>
383
+ </button>
384
+ <button type="button" class="rule-key size-key" role="radio" aria-checked="false" data-size="13">
385
+ <strong>13 × 13</strong><span>Medium</span>
386
+ </button>
387
+ <button type="button" class="rule-key size-key" role="radio" aria-checked="false" data-size="19">
388
+ <strong>19 × 19</strong><span>Full</span>
389
+ </button>
390
+ </div>
391
+ </fieldset>
392
+ <fieldset>
393
+ <legend>Komi</legend>
394
+ <div class="key-tray two" role="radiogroup" aria-label="Komi">
395
+ <button type="button" class="rule-key komi-key" role="radio" aria-checked="true" data-komi="6.5">
396
+ <strong>6.5 points</strong><span>Standard balance</span>
397
+ </button>
398
+ <button type="button" class="rule-key komi-key" role="radio" aria-checked="false" data-komi="0">
399
+ <strong>No komi</strong><span>Even score</span>
400
+ </button>
401
+ </div>
402
+ </fieldset>
403
+ <div class="dialog-actions">
404
+ <button type="button" class="dialog-button secondary" id="cancel-new-game">Cancel</button>
405
+ <button type="button" class="dialog-button" id="start-new-game">Start game</button>
406
+ </div>
407
+ </div>
408
+ </dialog>
409
+ </main>
410
+ <script>
411
+ /* gezel-page-demo-stub v1 */
412
+ /*
413
+ * The canonical demo stub for Gezel type pages. MIT License.
414
+ *
415
+ * Paste this file's bytes verbatim into a <script> block ahead of the
416
+ * page's own code, then call makeDemoGezel({ page, tools, data }) with the
417
+ * page's demo handlers. Served by Gezel, the real window.gezel is already
418
+ * injected and the stub steps aside; opened as a raw file (the live demos
419
+ * on gezelgilde.com), it installs a window.gezel whose tools and data are
420
+ * the page-supplied handler maps — one code path in every mode. `tools`
421
+ * and `data` map a tool name / declared read path to a function; data
422
+ * handlers back read() and list(), and url() returns the handler's value
423
+ * or passes a data: URI through. See docs/page-authoring.md.
424
+ */
425
+ (function () {
426
+ 'use strict';
427
+ window.makeDemoGezel = function (opts) {
428
+ if (window.gezel) return window.gezel;
429
+ var page = (opts && opts.page) || {};
430
+ var tools = (opts && opts.tools) || {};
431
+ var data = (opts && opts.data) || {};
432
+ var themeListeners = [];
433
+ var media = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
434
+ var ui = {
435
+ theme: { mode: media && media.matches ? 'dark' : 'light' },
436
+ onTheme: function (cb) {
437
+ themeListeners.push(cb);
438
+ return function () {
439
+ var at = themeListeners.indexOf(cb);
440
+ if (at >= 0) themeListeners.splice(at, 1);
441
+ };
442
+ },
443
+ };
444
+ if (media && media.addEventListener) {
445
+ media.addEventListener('change', function (ev) {
446
+ ui.theme = { mode: ev.matches ? 'dark' : 'light' };
447
+ themeListeners.slice().forEach(function (cb) { cb(ui.theme); });
448
+ });
449
+ }
450
+ function fail(code, message) {
451
+ var err = new Error(message);
452
+ err.code = code;
453
+ return Promise.reject(err);
454
+ }
455
+ function run(map, key, arg) {
456
+ if (!Object.prototype.hasOwnProperty.call(map, key)) return null;
457
+ return Promise.resolve().then(function () { return map[key](arg); });
458
+ }
459
+ window.gezel = {
460
+ page: {
461
+ api: 1,
462
+ projectId: 'demo',
463
+ source: 'type',
464
+ entry: page.entry || 'index.html',
465
+ typeName: page.typeName || 'demo',
466
+ params: page.params || {},
467
+ mode: 'demo',
468
+ },
469
+ tools: {
470
+ list: function () { return Promise.resolve(Object.keys(tools)); },
471
+ invoke: function (name, input) {
472
+ var call = run(tools, name, input || {});
473
+ if (!call) return fail('not-allowed', "The demo does not handle the tool '" + name + "'.");
474
+ return call.then(function (output) { return { output: output }; });
475
+ },
476
+ },
477
+ data: {
478
+ read: function (path, o) {
479
+ return run(data, path, o || {}) || fail('not-allowed', "The demo has no data for '" + path + "'.");
480
+ },
481
+ list: function (path, o) {
482
+ return run(data, path, o || {}) || Promise.resolve([]);
483
+ },
484
+ watch: function () { return function () {}; },
485
+ url: function (path) {
486
+ if (Object.prototype.hasOwnProperty.call(data, path)) return String(data[path]({}));
487
+ return typeof path === 'string' && path.indexOf('data:') === 0 ? path : '';
488
+ },
489
+ },
490
+ ui: ui,
491
+ refresh: function () {},
492
+ };
493
+ return window.gezel;
494
+ };
495
+ })();
496
+ </script>
497
+ <script>
498
+ (function () {
499
+ 'use strict';
500
+
501
+ var GO_FILES = 'ABCDEFGHJKLMNOPQRST';
502
+ var state = null;
503
+ var busy = false;
504
+ var newBoardSize = 9;
505
+ var newKomi = 6.5;
506
+ var demoGame = null;
507
+
508
+ function pointName(x, y, size) { return GO_FILES[x] + String(size - y); }
509
+ function demoCoords(name, size) { return { x: GO_FILES.indexOf(name[0]), y: size - Number(name.slice(1)) }; }
510
+ function demoNeighbors(x, y, size) {
511
+ return [[x - 1, y], [x + 1, y], [x, y - 1], [x, y + 1]].filter(function (p) {
512
+ return p[0] >= 0 && p[0] < size && p[1] >= 0 && p[1] < size;
513
+ });
514
+ }
515
+ function demoGroup(board, x, y, size) {
516
+ var color = board[y * size + x];
517
+ var seen = {}; var stones = []; var liberties = {};
518
+ var queue = [[x, y]];
519
+ while (queue.length) {
520
+ var p = queue.pop(); var key = p[0] + ',' + p[1];
521
+ if (seen[key]) continue;
522
+ seen[key] = true; stones.push(p);
523
+ demoNeighbors(p[0], p[1], size).forEach(function (n) {
524
+ var ch = board[n[1] * size + n[0]];
525
+ if (ch === '.') liberties[n[0] + ',' + n[1]] = true;
526
+ else if (ch === color && !seen[n[0] + ',' + n[1]]) queue.push(n);
527
+ });
528
+ }
529
+ return { stones: stones, liberties: Object.keys(liberties).length };
530
+ }
531
+ function demoTryMove(game, move) {
532
+ if (move === 'pass') return { squares: game.squares, captures: [] };
533
+ var size = game.boardSize; var at = demoCoords(move, size);
534
+ if (at.x < 0 || at.y < 0 || at.x >= size || at.y >= size) return null;
535
+ var board = game.squares.split('');
536
+ var index = at.y * size + at.x;
537
+ if (board[index] !== '.') return null;
538
+ var color = game.turn === 'user' ? 'X' : 'O';
539
+ var other = color === 'X' ? 'O' : 'X';
540
+ board[index] = color;
541
+ var captures = [];
542
+ demoNeighbors(at.x, at.y, size).forEach(function (n) {
543
+ if (board[n[1] * size + n[0]] !== other) return;
544
+ var group = demoGroup(board, n[0], n[1], size);
545
+ if (group.liberties === 0) group.stones.forEach(function (p) {
546
+ board[p[1] * size + p[0]] = '.';
547
+ captures.push(pointName(p[0], p[1], size));
548
+ });
549
+ });
550
+ if (demoGroup(board, at.x, at.y, size).liberties === 0) return null;
551
+ var squares = board.join('');
552
+ if (game.previousPosition && squares === game.previousPosition) return null;
553
+ return { squares: squares, captures: captures };
554
+ }
555
+ function demoLegalMoves(game) {
556
+ var out = [];
557
+ for (var y = 0; y < game.boardSize; y += 1) for (var x = 0; x < game.boardSize; x += 1) {
558
+ if (game.squares[y * game.boardSize + x] !== '.') continue;
559
+ var name = pointName(x, y, game.boardSize);
560
+ if (demoTryMove(game, name)) out.push(name);
561
+ }
562
+ return out;
563
+ }
564
+ function demoScore(game) {
565
+ var black = game.captures.user; var white = game.captures.ai + game.komi;
566
+ for (var i = 0; i < game.squares.length; i += 1) {
567
+ if (game.squares[i] === 'X') black += 1;
568
+ if (game.squares[i] === 'O') white += 1;
569
+ }
570
+ if (black === white) return { winner: 'draw', margin: 0 };
571
+ return { winner: black > white ? 'user' : 'ai', margin: Math.abs(black - white) };
572
+ }
573
+ function demoNewGame(boardSize, komi) {
574
+ var game = {
575
+ version: 1, boardSize: boardSize, squares: '.'.repeat(boardSize * boardSize),
576
+ turn: 'user', status: 'playing', komi: komi, consecutivePasses: 0,
577
+ previousPosition: null, legalMoves: [], captures: { user: 0, ai: 0 },
578
+ lastMove: null, lastMoveThought: '', moveLog: [], score: null,
579
+ };
580
+ demoGame = game;
581
+ game.legalMoves = demoLegalMoves(game);
582
+ return game;
583
+ }
584
+ function demoUserMove(input) {
585
+ var move = input.move;
586
+ if (move !== 'pass' && !demoGame.legalMoves.includes(move)) throw new Error('That point is not legal in the hot-seat demo.');
587
+ var result = demoTryMove(demoGame, move);
588
+ if (!result) throw new Error('That point is not legal in the hot-seat demo.');
589
+ var by = demoGame.turn;
590
+ var before = demoGame.squares;
591
+ demoGame.squares = result.squares;
592
+ demoGame.previousPosition = before;
593
+ demoGame.captures[by] += result.captures.length;
594
+ demoGame.consecutivePasses = move === 'pass' ? demoGame.consecutivePasses + 1 : 0;
595
+ demoGame.lastMove = { by: by, move: move };
596
+ demoGame.moveLog.push({ by: by, move: move, captures: result.captures });
597
+ demoGame.turn = by === 'user' ? 'ai' : 'user';
598
+ if (demoGame.consecutivePasses >= 2) {
599
+ demoGame.status = 'finished';
600
+ demoGame.score = demoScore(demoGame);
601
+ demoGame.legalMoves = [];
602
+ } else {
603
+ demoGame.legalMoves = demoLegalMoves(demoGame);
604
+ }
605
+ return { status: demoGame.status, turn: demoGame.turn, summary: 'Move played.' };
606
+ }
607
+
608
+ demoNewGame(9, 6.5);
609
+ makeDemoGezel({
610
+ page: { entry: 'board/index.html', typeName: 'Go', params: { personality: 'peppy', playStyle: 'Opponent' } },
611
+ tools: {
612
+ user_move: demoUserMove,
613
+ new_game: function (input) {
614
+ demoNewGame(Number(input.boardSize) || 9, input.komi === undefined ? 6.5 : Number(input.komi));
615
+ return { status: demoGame.status, turn: demoGame.turn, summary: 'New game.' };
616
+ },
617
+ },
618
+ data: {
619
+ 'game.json': function () { return demoGame; },
620
+ },
621
+ });
622
+
623
+ // ── one code path from here: window.gezel exists in every mode ──
624
+ var demoMode = gezel.page.mode === 'demo';
625
+ var browserMode = gezel.page.mode === 'browser';
626
+
627
+ function applyTheme(mode) {
628
+ document.documentElement.setAttribute('data-theme', mode === 'dark' ? 'dark' : 'light');
629
+ }
630
+ applyTheme(gezel.ui.theme.mode);
631
+ gezel.ui.onTheme(function (theme) { applyTheme(theme.mode); });
632
+
633
+ if (demoMode) document.querySelector('[data-gezel-demo-banner]').hidden = false;
634
+ if (browserMode) document.getElementById('browser-note').hidden = false;
635
+
636
+ function isStar(x, y, size) {
637
+ var points =
638
+ size === 9 ? [2, 4, 6] :
639
+ size === 13 ? [3, 6, 9] :
640
+ [3, 9, 15];
641
+ if (size === 9) return (x === 4 && y === 4) || (x !== 4 && y !== 4 && points.includes(x) && points.includes(y));
642
+ return points.includes(x) && points.includes(y);
643
+ }
644
+ function setBanner(text) {
645
+ var banner = document.getElementById('banner');
646
+ banner.textContent = text || '';
647
+ banner.className = text ? 'banner show' : 'banner';
648
+ }
649
+ function invokeErrorText(error) {
650
+ if (error && error.code === 'unavailable') {
651
+ return "Moves happen in the app's Output pane — this browser tab stays view-only.";
652
+ }
653
+ return String(error && error.message ? error.message : error);
654
+ }
655
+ function scoreText() {
656
+ if (!state || !state.score) return '';
657
+ if (state.score.winner === 'draw') return 'The final score is even.';
658
+ var color = state.score.winner === 'user' ? 'Black' : 'White';
659
+ return color + ' wins by ' + state.score.margin + ' points.';
660
+ }
661
+ function statusLine() {
662
+ if (!state) return 'Setting up the board…';
663
+ if (state.status !== 'playing') return scoreText() + ' Ready for another game?';
664
+ if (demoMode) return 'Hot seat — ' + (state.turn === 'user' ? 'black' : 'white') + ' to move, or pass.';
665
+ if (busy) return 'Sending your move…';
666
+ if (state.turn === 'ai') return 'Go-speler is thinking…';
667
+ return 'Your move — place black, or pass.';
668
+ }
669
+ function render() {
670
+ var status = document.getElementById('status');
671
+ status.textContent = statusLine();
672
+ status.className =
673
+ state && !demoMode && state.turn === 'ai' && state.status === 'playing'
674
+ ? 'status thinking'
675
+ : 'status';
676
+
677
+ var thoughtPanel = document.getElementById('move-thought-panel');
678
+ if (state && state.lastMoveThought) {
679
+ thoughtPanel.hidden = false;
680
+ document.getElementById('move-thought').textContent = state.lastMoveThought;
681
+ } else {
682
+ thoughtPanel.hidden = true;
683
+ }
684
+ document.getElementById('captures').textContent = state
685
+ ? 'Captures — black ' + state.captures.user + ' / white ' + state.captures.ai
686
+ : 'Captures — 0 / 0';
687
+ document.getElementById('pass').disabled =
688
+ !state || (!demoMode && state.turn !== 'user') || state.status !== 'playing' || busy;
689
+
690
+ var log = document.getElementById('log');
691
+ if (state && state.moveLog.length) {
692
+ log.innerHTML = '';
693
+ state.moveLog.forEach(function (entry, index) {
694
+ var item = document.createElement('li');
695
+ var captures = entry.captures && entry.captures.length
696
+ ? ' (captures ' + entry.captures.length + ')'
697
+ : '';
698
+ item.textContent = (entry.by === 'user' ? 'Black ' : 'White ') + entry.move + captures;
699
+ if (index === state.moveLog.length - 1) item.className = 'latest';
700
+ log.appendChild(item);
701
+ });
702
+ log.scrollTop = log.scrollHeight;
703
+ } else {
704
+ log.innerHTML = '<li>No moves yet — black opens.</li>';
705
+ }
706
+
707
+ var board = document.getElementById('board');
708
+ board.innerHTML = '';
709
+ var size = state ? state.boardSize : 9;
710
+ board.style.setProperty('--board-size', size);
711
+ var legal = {};
712
+ if (state) state.legalMoves.forEach(function (move) { legal[move] = true; });
713
+ var myTurn = state && (demoMode || state.turn === 'user') && state.status === 'playing' && !busy;
714
+ for (var y = 0; y < size; y += 1) {
715
+ for (var x = 0; x < size; x += 1) {
716
+ var name = pointName(x, y, size);
717
+ var stone = state ? state.squares[y * size + x] : '.';
718
+ var point = document.createElement('button');
719
+ point.type = 'button';
720
+ point.className = 'point';
721
+ point.dataset.point = name;
722
+ point.setAttribute('aria-label', name + (stone === '.' ? ', empty' : stone === 'X' ? ', black' : ', white'));
723
+ if (x === 0) point.style.setProperty('--left-edge', '50%');
724
+ if (x === size - 1) point.style.setProperty('--right-edge', '50%');
725
+ if (y === 0) point.style.setProperty('--top-edge', '50%');
726
+ if (y === size - 1) point.style.setProperty('--bottom-edge', '50%');
727
+ if (isStar(x, y, size)) point.className += ' star';
728
+ if (stone !== '.') point.className += ' occupied';
729
+ if (myTurn && legal[name]) point.className += ' legal';
730
+ if (state && state.lastMove && state.lastMove.move === name) point.className += ' last';
731
+
732
+ if (x === 0) {
733
+ var rank = document.createElement('span');
734
+ rank.className = 'coord rank';
735
+ rank.textContent = String(size - y);
736
+ point.appendChild(rank);
737
+ }
738
+ if (y === size - 1) {
739
+ var file = document.createElement('span');
740
+ file.className = 'coord file';
741
+ file.textContent = GO_FILES[x];
742
+ point.appendChild(file);
743
+ }
744
+ if (stone === '.') {
745
+ var dot = document.createElement('span');
746
+ dot.className = 'star-dot';
747
+ point.appendChild(dot);
748
+ } else {
749
+ var piece = document.createElement('span');
750
+ piece.className = 'stone ' + (stone === 'X' ? 'black' : 'white');
751
+ point.appendChild(piece);
752
+ }
753
+ point.addEventListener('click', onPointClick);
754
+ board.appendChild(point);
755
+ }
756
+ }
757
+ }
758
+
759
+ function onPointClick(event) {
760
+ if (!state || (!demoMode && state.turn !== 'user') || state.status !== 'playing' || busy) return;
761
+ var move = event.currentTarget.dataset.point;
762
+ if (!state.legalMoves.includes(move)) return;
763
+ submitMove(move);
764
+ }
765
+ function submitMove(move) {
766
+ busy = true;
767
+ render();
768
+ gezel.tools
769
+ .invoke('user_move', { move: move })
770
+ .then(function (result) {
771
+ busy = false;
772
+ if (
773
+ result.reaction &&
774
+ result.reaction.delivered === false &&
775
+ result.reaction.reason === 'engagement-off'
776
+ ) {
777
+ setBanner('Move played — but AI engagement is off, so the Go-speler cannot reply.');
778
+ }
779
+ return loadGame();
780
+ })
781
+ .catch(function (error) {
782
+ busy = false;
783
+ setBanner(invokeErrorText(error));
784
+ render();
785
+ });
786
+ }
787
+ function syncDialog() {
788
+ document.querySelectorAll('.size-key').forEach(function (button) {
789
+ button.setAttribute('aria-checked', String(Number(button.dataset.size) === newBoardSize));
790
+ });
791
+ document.querySelectorAll('.komi-key').forEach(function (button) {
792
+ button.setAttribute('aria-checked', String(Number(button.dataset.komi) === newKomi));
793
+ });
794
+ }
795
+ function openNewGame() {
796
+ if (busy) return;
797
+ newBoardSize = state ? state.boardSize : 9;
798
+ newKomi = state ? state.komi : 6.5;
799
+ syncDialog();
800
+ document.getElementById('new-game-dialog').showModal();
801
+ }
802
+ function newGame() {
803
+ busy = true;
804
+ render();
805
+ gezel.tools
806
+ .invoke('new_game', { boardSize: newBoardSize, komi: newKomi })
807
+ .then(function () {
808
+ busy = false;
809
+ setBanner('');
810
+ return loadGame();
811
+ })
812
+ .catch(function (error) {
813
+ busy = false;
814
+ setBanner(invokeErrorText(error));
815
+ render();
816
+ });
817
+ }
818
+ function loadGame() {
819
+ return gezel.data.read('game.json').then(
820
+ function (next) {
821
+ if (!next) return;
822
+ state = next;
823
+ render();
824
+ },
825
+ function () {},
826
+ );
827
+ }
828
+
829
+ document.getElementById('pass').addEventListener('click', function () { submitMove('pass'); });
830
+ document.getElementById('newgame').addEventListener('click', openNewGame);
831
+ document.getElementById('cancel-new-game').addEventListener('click', function () {
832
+ document.getElementById('new-game-dialog').close();
833
+ });
834
+ document.getElementById('start-new-game').addEventListener('click', function () {
835
+ document.getElementById('new-game-dialog').close();
836
+ newGame();
837
+ });
838
+ document.querySelectorAll('.size-key').forEach(function (button) {
839
+ button.addEventListener('click', function () {
840
+ newBoardSize = Number(button.dataset.size);
841
+ syncDialog();
842
+ });
843
+ });
844
+ document.querySelectorAll('.komi-key').forEach(function (button) {
845
+ button.addEventListener('click', function () {
846
+ newKomi = Number(button.dataset.komi);
847
+ syncDialog();
848
+ });
849
+ });
850
+ loadGame();
851
+ gezel.data.watch('game.json', function () { loadGame(); });
852
+ })();
853
+ </script>
854
+ </body>
855
+ </html>