@bendyline/gilde 0.1.86 → 0.1.87

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 (104) hide show
  1. package/data/craftbook-templates/index.json +1 -1
  2. package/data/craftbook-templates/raw-index.json +1 -1
  3. package/data/craftbook-templates/ta/tailor-resume/versions/1.0.5/craftbook.json +226 -0
  4. package/data/craftbook-templates/ta/tailor-resume/versions/1.0.5/test.json +79 -0
  5. package/data/knowledge-catalogs/ca/caselaw-alaska-part-0001/manifest.json +24 -0
  6. package/data/knowledge-catalogs/ca/caselaw-alaska-part-0001/versions/2026.10.1/manifest.json +658 -0
  7. package/data/knowledge-catalogs/index.json +1 -1
  8. package/data/knowledge-catalogs/raw-index.json +1 -1
  9. package/data/project-types/ch/checkers/versions/1.2.1/about.md +9 -0
  10. package/data/project-types/ch/checkers/versions/1.2.1/game.json +77 -0
  11. package/data/project-types/ch/checkers/versions/1.2.1/manifest.json +168 -0
  12. package/data/project-types/ch/checkers/versions/1.2.1/mission.md +9 -0
  13. package/data/project-types/ch/checkers/versions/1.2.1/pages/board/index.html +1158 -0
  14. package/data/project-types/ch/chess/versions/1.0.4/about.md +9 -0
  15. package/data/project-types/ch/chess/versions/1.0.4/game.json +127 -0
  16. package/data/project-types/ch/chess/versions/1.0.4/manifest.json +182 -0
  17. package/data/project-types/ch/chess/versions/1.0.4/mission.md +8 -0
  18. package/data/project-types/ch/chess/versions/1.0.4/pages/board/index.html +851 -0
  19. package/data/project-types/de/design-scheme/versions/1.0.2/about.md +6 -0
  20. package/data/project-types/de/design-scheme/versions/1.0.2/manifest.json +70 -0
  21. package/data/project-types/de/design-scheme/versions/1.0.2/mission.md +3 -0
  22. package/data/project-types/de/design-scheme/versions/1.0.2/pages/gallery/index.html +212 -0
  23. package/data/project-types/de/design-scheme/versions/1.0.2/schemes/index.json +9 -0
  24. package/data/project-types/de/design-scheme/versions/1.0.2/schemes/warm-dusk.json +4 -0
  25. package/data/project-types/ev/event-planner/versions/1.0.2/about.md +7 -0
  26. package/data/project-types/ev/event-planner/versions/1.0.2/budget.json +5 -0
  27. package/data/project-types/ev/event-planner/versions/1.0.2/guests.json +10 -0
  28. package/data/project-types/ev/event-planner/versions/1.0.2/manifest.json +171 -0
  29. package/data/project-types/ev/event-planner/versions/1.0.2/mission.md +6 -0
  30. package/data/project-types/ev/event-planner/versions/1.0.2/pages/dashboard/index.html +283 -0
  31. package/data/project-types/fi/fitness-coach/versions/1.0.2/about.md +7 -0
  32. package/data/project-types/fi/fitness-coach/versions/1.0.2/manifest.json +126 -0
  33. package/data/project-types/fi/fitness-coach/versions/1.0.2/mission.md +7 -0
  34. package/data/project-types/fi/fitness-coach/versions/1.0.2/pages/dashboard/index.html +273 -0
  35. package/data/project-types/fi/fitness-coach/versions/1.0.2/training.json +6 -0
  36. package/data/project-types/fl/flashcards/versions/1.1.1/about.md +8 -0
  37. package/data/project-types/fl/flashcards/versions/1.1.1/deck.json +7 -0
  38. package/data/project-types/fl/flashcards/versions/1.1.1/manifest.json +168 -0
  39. package/data/project-types/fl/flashcards/versions/1.1.1/mission.md +6 -0
  40. package/data/project-types/fl/flashcards/versions/1.1.1/pages/review/index.html +477 -0
  41. package/data/project-types/fr/freelance-office/versions/1.0.2/about.md +6 -0
  42. package/data/project-types/fr/freelance-office/versions/1.0.2/invoices.json +9 -0
  43. package/data/project-types/fr/freelance-office/versions/1.0.2/manifest.json +143 -0
  44. package/data/project-types/fr/freelance-office/versions/1.0.2/mission.md +6 -0
  45. package/data/project-types/fr/freelance-office/versions/1.0.2/pages/dashboard/index.html +258 -0
  46. package/data/project-types/fu/fundraiser-hq/versions/1.0.2/about.md +7 -0
  47. package/data/project-types/fu/fundraiser-hq/versions/1.0.2/donations.json +7 -0
  48. package/data/project-types/fu/fundraiser-hq/versions/1.0.2/manifest.json +127 -0
  49. package/data/project-types/fu/fundraiser-hq/versions/1.0.2/mission.md +6 -0
  50. package/data/project-types/fu/fundraiser-hq/versions/1.0.2/pages/dashboard/index.html +261 -0
  51. package/data/project-types/go/go/versions/1.0.2/about.md +9 -0
  52. package/data/project-types/go/go/versions/1.0.2/game.json +103 -0
  53. package/data/project-types/go/go/versions/1.0.2/manifest.json +168 -0
  54. package/data/project-types/go/go/versions/1.0.2/mission.md +8 -0
  55. package/data/project-types/go/go/versions/1.0.2/pages/board/index.html +855 -0
  56. package/data/project-types/ho/household-budget/versions/1.0.3/about.md +6 -0
  57. package/data/project-types/ho/household-budget/versions/1.0.3/ledger.json +5 -0
  58. package/data/project-types/ho/household-budget/versions/1.0.3/manifest.json +164 -0
  59. package/data/project-types/ho/household-budget/versions/1.0.3/mission.md +5 -0
  60. package/data/project-types/ho/household-budget/versions/1.0.3/pages/dashboard/index.html +340 -0
  61. package/data/project-types/ho/household-manual/versions/1.0.2/about.md +7 -0
  62. package/data/project-types/ho/household-manual/versions/1.0.2/manifest.json +153 -0
  63. package/data/project-types/ho/household-manual/versions/1.0.2/mission.md +8 -0
  64. package/data/project-types/ho/household-manual/versions/1.0.2/pages/dashboard/index.html +258 -0
  65. package/data/project-types/ho/household-manual/versions/1.0.2/systems.json +8 -0
  66. package/data/project-types/index.json +1 -1
  67. package/data/project-types/jo/job-hunt/versions/1.0.2/about.md +10 -0
  68. package/data/project-types/jo/job-hunt/versions/1.0.2/activity.json +4 -0
  69. package/data/project-types/jo/job-hunt/versions/1.0.2/manifest.json +213 -0
  70. package/data/project-types/jo/job-hunt/versions/1.0.2/mission.md +9 -0
  71. package/data/project-types/jo/job-hunt/versions/1.0.2/pages/dashboard/index.html +430 -0
  72. package/data/project-types/jo/job-hunt/versions/1.0.2/pipeline.json +6 -0
  73. package/data/project-types/la/language-trainer/versions/1.0.2/about.md +6 -0
  74. package/data/project-types/la/language-trainer/versions/1.0.2/manifest.json +80 -0
  75. package/data/project-types/la/language-trainer/versions/1.0.2/mission.md +4 -0
  76. package/data/project-types/la/language-trainer/versions/1.0.2/pages/dashboard/index.html +268 -0
  77. package/data/project-types/la/language-trainer/versions/1.0.2/progress.json +7 -0
  78. package/data/project-types/li/life-binder/versions/1.0.3/about.md +7 -0
  79. package/data/project-types/li/life-binder/versions/1.0.3/documents.json +145 -0
  80. package/data/project-types/li/life-binder/versions/1.0.3/manifest.json +138 -0
  81. package/data/project-types/li/life-binder/versions/1.0.3/mission.md +6 -0
  82. package/data/project-types/li/life-binder/versions/1.0.3/pages/dashboard/index.html +248 -0
  83. package/data/project-types/me/meal-planner/versions/1.0.2/about.md +6 -0
  84. package/data/project-types/me/meal-planner/versions/1.0.2/manifest.json +160 -0
  85. package/data/project-types/me/meal-planner/versions/1.0.2/menu.json +5 -0
  86. package/data/project-types/me/meal-planner/versions/1.0.2/mission.md +5 -0
  87. package/data/project-types/me/meal-planner/versions/1.0.2/pages/dashboard/index.html +248 -0
  88. package/data/project-types/me/meal-planner/versions/1.0.2/pantry.json +9 -0
  89. package/data/project-types/no/novel-writing-room/versions/1.0.2/about.md +7 -0
  90. package/data/project-types/no/novel-writing-room/versions/1.0.2/chapters.json +10 -0
  91. package/data/project-types/no/novel-writing-room/versions/1.0.2/manifest.json +158 -0
  92. package/data/project-types/no/novel-writing-room/versions/1.0.2/mission.md +7 -0
  93. package/data/project-types/no/novel-writing-room/versions/1.0.2/pages/dashboard/index.html +264 -0
  94. package/data/project-types/no/novel-writing-room/versions/1.0.2/sessions.json +6 -0
  95. package/data/project-types/raw-index.json +1 -1
  96. package/data/project-types/tr/trip-planner/versions/1.0.2/about.md +7 -0
  97. package/data/project-types/tr/trip-planner/versions/1.0.2/journal.json +4 -0
  98. package/data/project-types/tr/trip-planner/versions/1.0.2/manifest.json +194 -0
  99. package/data/project-types/tr/trip-planner/versions/1.0.2/mission.md +4 -0
  100. package/data/project-types/tr/trip-planner/versions/1.0.2/packing.json +8 -0
  101. package/data/project-types/tr/trip-planner/versions/1.0.2/pages/dashboard/index.html +308 -0
  102. package/data/project-types/tr/trip-planner/versions/1.0.2/trip.json +7 -0
  103. package/package.json +1 -1
  104. package/schemas/project-type-version.schema.json +13 -0
@@ -0,0 +1,851 @@
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>Chess</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
+ --sq-light: #efe4d1;
18
+ --sq-dark: #9a7455;
19
+ --sq-hint: #557a5b;
20
+ --frame-a: #8d694d;
21
+ --frame-b: #4d3424;
22
+ --frame-edge: #342116;
23
+ --white-piece-face: #fff8e8;
24
+ --white-piece-side: #a8987e;
25
+ --white-piece-edge: #594b3c;
26
+ --white-piece-highlight: rgba(255, 255, 255, 0.9);
27
+ --black-piece-face: #302a24;
28
+ --black-piece-side: #100d0a;
29
+ --black-piece-edge: #090705;
30
+ --black-piece-highlight: rgba(255, 255, 255, 0.2);
31
+ --last-move: rgba(241, 184, 84, 0.42);
32
+ }
33
+ :root[data-theme='dark'] {
34
+ --bg: #1c1a17;
35
+ --card: #262320;
36
+ --ink: #efe9e0;
37
+ --muted: #a59a8c;
38
+ --accent: #e0894a;
39
+ --track: #3a352f;
40
+ --sq-light: #b8a58b;
41
+ --sq-dark: #674a35;
42
+ --sq-hint: #6f9b70;
43
+ --frame-a: #74543d;
44
+ --frame-b: #34241a;
45
+ --frame-edge: #1b120d;
46
+ --white-piece-face: #fff5dc;
47
+ --white-piece-side: #9d8b70;
48
+ --white-piece-edge: #4b3d30;
49
+ --white-piece-highlight: rgba(255, 255, 255, 0.88);
50
+ --black-piece-face: #29221c;
51
+ --black-piece-side: #0b0907;
52
+ --black-piece-edge: #050403;
53
+ --black-piece-highlight: rgba(255, 255, 255, 0.18);
54
+ --last-move: rgba(236, 159, 85, 0.38);
55
+ }
56
+ @media (prefers-color-scheme: dark) {
57
+ :root:not([data-theme='light']) {
58
+ --bg: #1c1a17;
59
+ --card: #262320;
60
+ --ink: #efe9e0;
61
+ --muted: #a59a8c;
62
+ --accent: #e0894a;
63
+ --track: #3a352f;
64
+ --sq-light: #b8a58b;
65
+ --sq-dark: #674a35;
66
+ --sq-hint: #6f9b70;
67
+ --frame-a: #74543d;
68
+ --frame-b: #34241a;
69
+ --frame-edge: #1b120d;
70
+ --white-piece-face: #fff5dc;
71
+ --white-piece-side: #9d8b70;
72
+ --white-piece-edge: #4b3d30;
73
+ --white-piece-highlight: rgba(255, 255, 255, 0.88);
74
+ --black-piece-face: #29221c;
75
+ --black-piece-side: #0b0907;
76
+ --black-piece-edge: #050403;
77
+ --black-piece-highlight: rgba(255, 255, 255, 0.18);
78
+ --last-move: rgba(236, 159, 85, 0.38);
79
+ }
80
+ }
81
+ * { box-sizing: border-box; }
82
+ body {
83
+ margin: 0;
84
+ padding: 1.25rem;
85
+ background: var(--bg);
86
+ color: var(--ink);
87
+ font: 15px/1.5 system-ui, -apple-system, 'Segoe UI', sans-serif;
88
+ }
89
+ main { max-width: 760px; margin: 0 auto; }
90
+ header {
91
+ display: flex;
92
+ align-items: baseline;
93
+ justify-content: space-between;
94
+ gap: 0.75rem;
95
+ flex-wrap: wrap;
96
+ }
97
+ h1 {
98
+ margin: 0;
99
+ font-family: Georgia, 'PT Serif', 'Times New Roman', serif;
100
+ font-size: 1.35rem;
101
+ }
102
+ button { font: inherit; }
103
+ .newgame,
104
+ .passive-button {
105
+ min-height: 44px;
106
+ border: 1px solid var(--track);
107
+ border-radius: 6px;
108
+ padding: 0.32rem 0.7rem;
109
+ background: var(--card);
110
+ color: var(--ink);
111
+ cursor: pointer;
112
+ }
113
+ .newgame:hover,
114
+ .passive-button:hover { border-color: var(--accent); }
115
+ .status { min-height: 1.5em; margin: 0.15rem 0 0.9rem; color: var(--muted); }
116
+ .status.thinking { color: var(--accent); }
117
+ .banner {
118
+ display: none;
119
+ margin-bottom: 0.75rem;
120
+ padding: 0.45rem 0.7rem;
121
+ border: 1px solid var(--accent);
122
+ border-radius: 6px;
123
+ font-size: 0.85rem;
124
+ }
125
+ .banner.show { display: block; }
126
+ .note {
127
+ margin: 0 0 0.85rem;
128
+ padding: 0.5rem 0.65rem;
129
+ border: 1px solid var(--track);
130
+ border-radius: 6px;
131
+ background: var(--card);
132
+ color: var(--muted);
133
+ font-size: 0.8rem;
134
+ }
135
+ .table { display: grid; grid-template-columns: minmax(0, 1fr) 220px; gap: 0.9rem; }
136
+ .boardwrap {
137
+ padding: 0.85rem;
138
+ border: 1px solid var(--frame-edge);
139
+ border-radius: 14px;
140
+ background: linear-gradient(145deg, var(--frame-a), var(--frame-b));
141
+ box-shadow:
142
+ inset 0 1px 0 rgba(255, 255, 255, 0.2),
143
+ inset 0 -4px 8px rgba(0, 0, 0, 0.25),
144
+ 0 10px 24px rgba(31, 21, 15, 0.22);
145
+ }
146
+ .board {
147
+ display: grid;
148
+ grid-template-columns: repeat(8, minmax(0, 1fr));
149
+ width: 100%;
150
+ aspect-ratio: 1;
151
+ overflow: hidden;
152
+ border: 1px solid var(--frame-edge);
153
+ border-radius: 8px;
154
+ box-shadow: 0 5px 12px rgba(0, 0, 0, 0.3);
155
+ user-select: none;
156
+ }
157
+ .cell {
158
+ position: relative;
159
+ display: grid;
160
+ min-width: 0;
161
+ min-height: 0;
162
+ aspect-ratio: 1;
163
+ place-items: center;
164
+ padding: 0;
165
+ border: 0;
166
+ color: inherit;
167
+ }
168
+ .cell.light { background: var(--sq-light); }
169
+ .cell.dark { background: var(--sq-dark); }
170
+ .cell.selectable { cursor: pointer; }
171
+ .cell.selected {
172
+ outline: 3px solid var(--accent);
173
+ outline-offset: -3px;
174
+ z-index: 2;
175
+ }
176
+ .cell.hint { cursor: pointer; }
177
+ .cell.hint::after {
178
+ position: absolute;
179
+ z-index: 2;
180
+ width: 24%;
181
+ height: 24%;
182
+ border-radius: 50%;
183
+ background: var(--sq-hint);
184
+ box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.18);
185
+ content: '';
186
+ }
187
+ .cell.hint.capture::after {
188
+ width: 72%;
189
+ height: 72%;
190
+ border: 5px solid var(--sq-hint);
191
+ background: transparent;
192
+ box-shadow: none;
193
+ }
194
+ .cell.last-from { box-shadow: inset 0 0 0 3px var(--last-move); }
195
+ .cell.last-to { box-shadow: inset 0 0 0 999px var(--last-move); }
196
+ .piece {
197
+ position: relative;
198
+ z-index: 1;
199
+ display: grid;
200
+ width: 100%;
201
+ height: 100%;
202
+ place-items: center;
203
+ font-family: Georgia, 'Times New Roman', serif;
204
+ font-size: clamp(1.5rem, 7vw, 3.25rem);
205
+ line-height: 1;
206
+ isolation: isolate;
207
+ transform: translate(-2px, -3px);
208
+ transition: transform 140ms ease-out;
209
+ }
210
+ .piece.white {
211
+ --piece-face: var(--white-piece-face);
212
+ --piece-side: var(--white-piece-side);
213
+ --piece-edge: var(--white-piece-edge);
214
+ --piece-highlight: var(--white-piece-highlight);
215
+ }
216
+ .piece.black {
217
+ --piece-face: var(--black-piece-face);
218
+ --piece-side: var(--black-piece-side);
219
+ --piece-edge: var(--black-piece-edge);
220
+ --piece-highlight: var(--black-piece-highlight);
221
+ }
222
+ .piece::before,
223
+ .piece::after {
224
+ position: absolute;
225
+ inset: 0;
226
+ display: grid;
227
+ place-items: center;
228
+ content: attr(data-glyph);
229
+ }
230
+ .piece::before {
231
+ z-index: -1;
232
+ color: var(--piece-side);
233
+ -webkit-text-stroke: 1px var(--piece-edge);
234
+ text-shadow:
235
+ 1px 1px 0 var(--piece-edge),
236
+ 2px 2px 0 var(--piece-edge),
237
+ 3px 3px 0 var(--piece-edge),
238
+ 4px 5px 4px rgba(0, 0, 0, 0.34);
239
+ transform: translate(3px, 4px);
240
+ }
241
+ .piece::after {
242
+ color: var(--piece-face);
243
+ -webkit-text-stroke: 1px var(--piece-edge);
244
+ text-shadow:
245
+ -1px -1px 0 var(--piece-highlight),
246
+ 1px 1px 0 color-mix(in srgb, var(--piece-side) 68%, transparent);
247
+ }
248
+ .cell.selectable:hover .piece,
249
+ .cell.selected .piece { transform: translate(-3px, -5px) scale(1.04); }
250
+ .coord {
251
+ position: absolute;
252
+ z-index: 3;
253
+ color: rgba(43, 38, 32, 0.55);
254
+ font-size: clamp(0.45rem, 1.3vw, 0.65rem);
255
+ font-weight: 700;
256
+ line-height: 1;
257
+ pointer-events: none;
258
+ }
259
+ .coord.rank { top: 5%; left: 6%; }
260
+ .coord.file { right: 6%; bottom: 5%; }
261
+ .dark .coord { color: rgba(255, 250, 242, 0.58); }
262
+ .aside { display: flex; flex-direction: column; gap: 0.6rem; min-width: 0; }
263
+ .panel {
264
+ padding: 0.7rem 0.85rem;
265
+ border: 1px solid var(--track);
266
+ border-radius: 10px;
267
+ background: var(--card);
268
+ font-size: 0.85rem;
269
+ }
270
+ .panel h2 {
271
+ margin: 0 0 0.35rem;
272
+ color: var(--muted);
273
+ font-size: 0.72rem;
274
+ letter-spacing: 0.05em;
275
+ text-transform: uppercase;
276
+ }
277
+ .move-thought { font-style: italic; }
278
+ .move-thought .who {
279
+ display: block;
280
+ margin-bottom: 0.15rem;
281
+ color: var(--muted);
282
+ font-size: 0.78rem;
283
+ font-style: normal;
284
+ }
285
+ .log { max-height: 230px; margin: 0; padding-left: 1.2rem; overflow-y: auto; }
286
+ .log li { margin: 0.12rem 0; color: var(--muted); }
287
+ .log li.latest { color: var(--ink); }
288
+ dialog {
289
+ width: min(410px, calc(100vw - 2rem));
290
+ padding: 0;
291
+ border: 1px solid var(--track);
292
+ border-radius: 10px;
293
+ background: var(--card);
294
+ color: var(--ink);
295
+ box-shadow: 0 18px 55px rgba(0, 0, 0, 0.35);
296
+ }
297
+ dialog::backdrop { background: rgba(20, 17, 14, 0.62); }
298
+ .dialog-content { padding: 1rem; }
299
+ .dialog-content h2 {
300
+ margin: 0 0 0.2rem;
301
+ font-family: Georgia, 'PT Serif', serif;
302
+ font-size: 1.1rem;
303
+ }
304
+ .dialog-content p { margin: 0 0 0.85rem; color: var(--muted); font-size: 0.85rem; }
305
+ .piece-tray {
306
+ display: grid;
307
+ grid-template-columns: repeat(4, 1fr);
308
+ gap: 0.35rem;
309
+ padding: 0.35rem;
310
+ border: 1px solid var(--track);
311
+ border-radius: 10px;
312
+ background: var(--track);
313
+ }
314
+ .promotion-key {
315
+ min-height: 3.2rem;
316
+ border: 1px solid transparent;
317
+ border-radius: 6px;
318
+ background: var(--card);
319
+ color: var(--ink);
320
+ cursor: pointer;
321
+ font-family: Georgia, 'Times New Roman', serif;
322
+ font-size: 1.8rem;
323
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.14);
324
+ }
325
+ .promotion-key:hover { border-color: var(--accent); }
326
+ .dialog-actions { display: flex; justify-content: flex-end; margin-top: 0.8rem; }
327
+ @media (max-width: 640px) {
328
+ .table { grid-template-columns: 1fr; }
329
+ .aside { display: grid; grid-template-columns: 1fr 1fr; }
330
+ }
331
+ @media (prefers-reduced-motion: reduce) {
332
+ .piece { transition: none; }
333
+ }
334
+ .demo-banner {
335
+ display: flex;
336
+ align-items: center;
337
+ justify-content: space-between;
338
+ gap: 0.75rem;
339
+ margin: 0 0 0.85rem;
340
+ padding: 0.5rem 0.65rem;
341
+ border: 1px solid var(--accent);
342
+ border-radius: 6px;
343
+ background: color-mix(in srgb, var(--card) 88%, var(--accent));
344
+ color: var(--ink);
345
+ font-size: 0.8rem;
346
+ }
347
+ .demo-banner[hidden] { display: none; }
348
+ .demo-banner strong { font-weight: 700; }
349
+ .demo-reset {
350
+ flex: none;
351
+ padding: 0.25rem 0.5rem;
352
+ border: 1px solid var(--accent);
353
+ border-radius: 6px;
354
+ background: var(--card);
355
+ color: var(--ink);
356
+ cursor: pointer;
357
+ font: inherit;
358
+ }
359
+ .demo-reset:hover { border-color: var(--ink); }
360
+ </style>
361
+ </head>
362
+ <body>
363
+ <main>
364
+ <div class="demo-banner" data-gezel-demo-banner hidden>
365
+ <span><strong>Demo mode</strong> — sample data stays in this page.</span>
366
+ <button type="button" class="demo-reset" onclick="location.reload()">Reset demo</button>
367
+ </div>
368
+ <p class="note" id="browser-note" hidden>
369
+ Viewing from a browser tab — the board stays live, but moves happen in the app's Output pane.
370
+ </p>
371
+ <div class="banner" id="banner"></div>
372
+ <header>
373
+ <h1>Chess</h1>
374
+ <button type="button" class="newgame" id="newgame">New game</button>
375
+ </header>
376
+ <p class="status" id="status">Setting up the board…</p>
377
+ <div class="table">
378
+ <div class="boardwrap"><div class="board" id="board" aria-label="Chess board"></div></div>
379
+ <div class="aside">
380
+ <div class="panel move-thought" id="move-thought-panel" hidden>
381
+ <span class="who">Schaakspeler says</span>
382
+ <span id="move-thought"></span>
383
+ </div>
384
+ <div class="panel">
385
+ <h2>Moves</h2>
386
+ <ol class="log" id="log"><li>No moves yet — white opens.</li></ol>
387
+ </div>
388
+ </div>
389
+ </div>
390
+ <dialog id="promotion-dialog" aria-labelledby="promotion-title">
391
+ <div class="dialog-content">
392
+ <h2 id="promotion-title">Promote your pawn</h2>
393
+ <p>Choose the piece that arrives on the back rank.</p>
394
+ <div class="piece-tray" id="promotion-choices"></div>
395
+ <div class="dialog-actions">
396
+ <button type="button" class="passive-button" id="cancel-promotion">Cancel</button>
397
+ </div>
398
+ </div>
399
+ </dialog>
400
+ </main>
401
+ <script>
402
+ /* gezel-page-demo-stub v1 */
403
+ /*
404
+ * The canonical demo stub for Gezel type pages. MIT License.
405
+ *
406
+ * Paste this file's bytes verbatim into a <script> block ahead of the
407
+ * page's own code, then call makeDemoGezel({ page, tools, data }) with the
408
+ * page's demo handlers. Served by Gezel, the real window.gezel is already
409
+ * injected and the stub steps aside; opened as a raw file (the live demos
410
+ * on gezelgilde.com), it installs a window.gezel whose tools and data are
411
+ * the page-supplied handler maps — one code path in every mode. `tools`
412
+ * and `data` map a tool name / declared read path to a function; data
413
+ * handlers back read() and list(), and url() returns the handler's value
414
+ * or passes a data: URI through. See docs/page-authoring.md.
415
+ */
416
+ (function () {
417
+ 'use strict';
418
+ window.makeDemoGezel = function (opts) {
419
+ if (window.gezel) return window.gezel;
420
+ var page = (opts && opts.page) || {};
421
+ var tools = (opts && opts.tools) || {};
422
+ var data = (opts && opts.data) || {};
423
+ var themeListeners = [];
424
+ var media = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
425
+ var ui = {
426
+ theme: { mode: media && media.matches ? 'dark' : 'light' },
427
+ onTheme: function (cb) {
428
+ themeListeners.push(cb);
429
+ return function () {
430
+ var at = themeListeners.indexOf(cb);
431
+ if (at >= 0) themeListeners.splice(at, 1);
432
+ };
433
+ },
434
+ };
435
+ if (media && media.addEventListener) {
436
+ media.addEventListener('change', function (ev) {
437
+ ui.theme = { mode: ev.matches ? 'dark' : 'light' };
438
+ themeListeners.slice().forEach(function (cb) { cb(ui.theme); });
439
+ });
440
+ }
441
+ function fail(code, message) {
442
+ var err = new Error(message);
443
+ err.code = code;
444
+ return Promise.reject(err);
445
+ }
446
+ function run(map, key, arg) {
447
+ if (!Object.prototype.hasOwnProperty.call(map, key)) return null;
448
+ return Promise.resolve().then(function () { return map[key](arg); });
449
+ }
450
+ window.gezel = {
451
+ page: {
452
+ api: 1,
453
+ projectId: 'demo',
454
+ source: 'type',
455
+ entry: page.entry || 'index.html',
456
+ typeName: page.typeName || 'demo',
457
+ params: page.params || {},
458
+ mode: 'demo',
459
+ },
460
+ tools: {
461
+ list: function () { return Promise.resolve(Object.keys(tools)); },
462
+ invoke: function (name, input) {
463
+ var call = run(tools, name, input || {});
464
+ if (!call) return fail('not-allowed', "The demo does not handle the tool '" + name + "'.");
465
+ return call.then(function (output) { return { output: output }; });
466
+ },
467
+ },
468
+ data: {
469
+ read: function (path, o) {
470
+ return run(data, path, o || {}) || fail('not-allowed', "The demo has no data for '" + path + "'.");
471
+ },
472
+ list: function (path, o) {
473
+ return run(data, path, o || {}) || Promise.resolve([]);
474
+ },
475
+ watch: function () { return function () {}; },
476
+ url: function (path) {
477
+ if (Object.prototype.hasOwnProperty.call(data, path)) return String(data[path]({}));
478
+ return typeof path === 'string' && path.indexOf('data:') === 0 ? path : '';
479
+ },
480
+ },
481
+ ui: ui,
482
+ refresh: function () {},
483
+ };
484
+ return window.gezel;
485
+ };
486
+ })();
487
+ </script>
488
+ <script>
489
+ (function () {
490
+ 'use strict';
491
+
492
+ var FILES = 'abcdefgh';
493
+ var PIECES = {
494
+ K: '♚', Q: '♛', R: '♜', B: '♝', N: '♞', P: '♟',
495
+ k: '♚', q: '♛', r: '♜', b: '♝', n: '♞', p: '♟',
496
+ };
497
+ var PROMOTION_PIECES = { q: '♛', r: '♜', b: '♝', n: '♞' };
498
+ var state = null;
499
+ var selected = null;
500
+ var busy = false;
501
+ var promotionMoves = [];
502
+ var demoGame = null;
503
+
504
+ function squareName(x, y) { return FILES[x] + String(8 - y); }
505
+ function sideOf(piece) {
506
+ if (!piece || piece === '.') return null;
507
+ return piece === piece.toUpperCase() ? 'user' : 'ai';
508
+ }
509
+ function demoCoords(name) { return { x: FILES.indexOf(name[0]), y: 8 - Number(name[1]) }; }
510
+ function demoAt(squares, x, y) { return x < 0 || x > 7 || y < 0 || y > 7 ? null : squares[y * 8 + x]; }
511
+ function demoSet(squares, x, y, piece) {
512
+ var i = y * 8 + x;
513
+ return squares.slice(0, i) + piece + squares.slice(i + 1);
514
+ }
515
+ function demoMoves(game) {
516
+ var out = [];
517
+ var squares = game.squares;
518
+ var side = game.turn;
519
+ function add(fromX, fromY, toX, toY, extra) {
520
+ var target = demoAt(squares, toX, toY);
521
+ if (target === null || sideOf(target) === side) return;
522
+ var base = { from: squareName(fromX, fromY), to: squareName(toX, toY), capture: target !== '.' };
523
+ out.push(Object.assign(base, extra || {}));
524
+ }
525
+ function ray(x, y, dx, dy) {
526
+ var tx = x + dx; var ty = y + dy;
527
+ while (demoAt(squares, tx, ty) !== null) {
528
+ var target = demoAt(squares, tx, ty);
529
+ if (sideOf(target) === side) break;
530
+ add(x, y, tx, ty);
531
+ if (target !== '.') break;
532
+ tx += dx; ty += dy;
533
+ }
534
+ }
535
+ for (var y = 0; y < 8; y += 1) {
536
+ for (var x = 0; x < 8; x += 1) {
537
+ var piece = demoAt(squares, x, y);
538
+ if (sideOf(piece) !== side) continue;
539
+ var kind = piece.toLowerCase();
540
+ if (kind === 'p') {
541
+ var dir = side === 'user' ? -1 : 1;
542
+ var start = side === 'user' ? 6 : 1;
543
+ var last = side === 'user' ? 0 : 7;
544
+ if (demoAt(squares, x, y + dir) === '.') {
545
+ if (y + dir === last) {
546
+ ['q', 'r', 'b', 'n'].forEach(function (promotion) { add(x, y, x, y + dir, { promotion: promotion }); });
547
+ } else {
548
+ add(x, y, x, y + dir);
549
+ if (y === start && demoAt(squares, x, y + dir * 2) === '.') add(x, y, x, y + dir * 2);
550
+ }
551
+ }
552
+ [-1, 1].forEach(function (dx) {
553
+ var target = demoAt(squares, x + dx, y + dir);
554
+ if (target && target !== '.' && sideOf(target) !== side) {
555
+ if (y + dir === last) ['q', 'r', 'b', 'n'].forEach(function (promotion) { add(x, y, x + dx, y + dir, { promotion: promotion }); });
556
+ else add(x, y, x + dx, y + dir);
557
+ }
558
+ });
559
+ } else if (kind === 'n') {
560
+ [[-2,-1],[-2,1],[-1,-2],[-1,2],[1,-2],[1,2],[2,-1],[2,1]].forEach(function (d) { add(x, y, x + d[0], y + d[1]); });
561
+ } else if (kind === 'k') {
562
+ for (var ky = -1; ky <= 1; ky += 1) for (var kx = -1; kx <= 1; kx += 1) if (kx || ky) add(x, y, x + kx, y + ky);
563
+ } else {
564
+ if (kind === 'b' || kind === 'q') [[-1,-1],[-1,1],[1,-1],[1,1]].forEach(function (d) { ray(x, y, d[0], d[1]); });
565
+ if (kind === 'r' || kind === 'q') [[-1,0],[1,0],[0,-1],[0,1]].forEach(function (d) { ray(x, y, d[0], d[1]); });
566
+ }
567
+ }
568
+ }
569
+ return out;
570
+ }
571
+ function demoNewGame() {
572
+ var game = {
573
+ version: 1,
574
+ squares: 'rnbqkbnrpppppppp................................PPPPPPPPRNBQKBNR',
575
+ turn: 'user', status: 'playing', legalMoves: [], lastMove: null,
576
+ lastMoveThought: '', moveLog: [], fullmoveNumber: 1,
577
+ };
578
+ demoGame = game;
579
+ game.legalMoves = demoMoves(game);
580
+ return game;
581
+ }
582
+ function demoUserMove(input) {
583
+ var move = demoGame.legalMoves.find(function (m) {
584
+ return m.from === input.from && m.to === input.to && (!m.promotion || m.promotion === (input.promotion || 'q'));
585
+ });
586
+ if (!move) throw new Error('That move is not available in the hot-seat demo.');
587
+ var from = demoCoords(move.from); var to = demoCoords(move.to);
588
+ var piece = demoAt(demoGame.squares, from.x, from.y);
589
+ var captured = demoAt(demoGame.squares, to.x, to.y);
590
+ demoGame.squares = demoSet(demoSet(demoGame.squares, from.x, from.y, '.'), to.x, to.y,
591
+ move.promotion ? (demoGame.turn === 'user' ? move.promotion.toUpperCase() : move.promotion) : piece);
592
+ demoGame.lastMove = { from: move.from, to: move.to };
593
+ demoGame.moveLog.push({ by: demoGame.turn, notation: move.from + '–' + move.to + (move.promotion ? '=' + move.promotion.toUpperCase() : '') });
594
+ if (captured && captured.toLowerCase() === 'k') {
595
+ demoGame.status = demoGame.turn === 'user' ? 'user_won' : 'ai_won';
596
+ demoGame.legalMoves = [];
597
+ } else {
598
+ demoGame.turn = demoGame.turn === 'user' ? 'ai' : 'user';
599
+ if (demoGame.turn === 'user') demoGame.fullmoveNumber += 1;
600
+ demoGame.legalMoves = demoMoves(demoGame);
601
+ if (demoGame.legalMoves.length === 0) demoGame.status = 'draw';
602
+ }
603
+ return { status: demoGame.status, turn: demoGame.turn, summary: 'Move played.' };
604
+ }
605
+
606
+ demoNewGame();
607
+ makeDemoGezel({
608
+ page: { entry: 'board/index.html', typeName: 'Chess', params: { personality: 'peppy', playStyle: 'Opponent' } },
609
+ tools: {
610
+ user_move: demoUserMove,
611
+ new_game: function () {
612
+ demoNewGame();
613
+ return { status: demoGame.status, turn: demoGame.turn, summary: 'New game.' };
614
+ },
615
+ },
616
+ data: {
617
+ 'game.json': function () { return demoGame; },
618
+ },
619
+ });
620
+
621
+ // ── one code path from here: window.gezel exists in every mode ──
622
+ var demoMode = gezel.page.mode === 'demo';
623
+ var browserMode = gezel.page.mode === 'browser';
624
+
625
+ function applyTheme(mode) {
626
+ document.documentElement.setAttribute('data-theme', mode === 'dark' ? 'dark' : 'light');
627
+ }
628
+ applyTheme(gezel.ui.theme.mode);
629
+ gezel.ui.onTheme(function (theme) { applyTheme(theme.mode); });
630
+
631
+ if (demoMode) document.querySelector('[data-gezel-demo-banner]').hidden = false;
632
+ if (browserMode) document.getElementById('browser-note').hidden = false;
633
+
634
+ function setBanner(text) {
635
+ var banner = document.getElementById('banner');
636
+ banner.textContent = text || '';
637
+ banner.className = text ? 'banner show' : 'banner';
638
+ }
639
+ function invokeErrorText(error) {
640
+ if (error && error.code === 'unavailable') {
641
+ return "Moves happen in the app's Output pane — this browser tab stays view-only.";
642
+ }
643
+ return String(error && error.message ? error.message : error);
644
+ }
645
+ function statusLine() {
646
+ if (!state) return 'Setting up the board…';
647
+ if (demoMode && state.status === 'playing') return 'Hot seat — ' + (state.turn === 'user' ? 'white' : 'black') + ' to move.';
648
+ if (demoMode && state.status === 'user_won') return 'White wins the hot-seat demo.';
649
+ if (demoMode && state.status === 'ai_won') return 'Black wins the hot-seat demo.';
650
+ if (demoMode && state.status === 'draw') return 'Hot-seat draw — reset for another game.';
651
+ if (state.status === 'user_won') return 'Checkmate — you won. The Schaakspeler is ready for a rematch.';
652
+ if (state.status === 'ai_won') return 'Checkmate — the Schaakspeler takes this one.';
653
+ if (state.status === 'draw') return 'Draw — a balanced board, and a rematch whenever you like.';
654
+ if (busy) return 'Sending your move…';
655
+ if (state.turn === 'ai') return 'Schaakspeler is thinking…';
656
+ return selected ? 'Choose a highlighted destination.' : 'Your move — you have white.';
657
+ }
658
+ function movesFrom(name) {
659
+ if (!state) return [];
660
+ return state.legalMoves.filter(function (move) { return move.from === name; });
661
+ }
662
+ function movesTo(name) {
663
+ return selected
664
+ ? movesFrom(selected).filter(function (move) { return move.to === name; })
665
+ : [];
666
+ }
667
+ function render() {
668
+ var status = document.getElementById('status');
669
+ status.textContent = statusLine();
670
+ status.className =
671
+ state && !demoMode && state.turn === 'ai' && state.status === 'playing'
672
+ ? 'status thinking'
673
+ : 'status';
674
+
675
+ var thoughtPanel = document.getElementById('move-thought-panel');
676
+ if (state && state.lastMoveThought) {
677
+ thoughtPanel.hidden = false;
678
+ document.getElementById('move-thought').textContent = state.lastMoveThought;
679
+ } else {
680
+ thoughtPanel.hidden = true;
681
+ }
682
+
683
+ var log = document.getElementById('log');
684
+ if (state && state.moveLog.length) {
685
+ log.innerHTML = '';
686
+ state.moveLog.forEach(function (entry, index) {
687
+ var item = document.createElement('li');
688
+ item.textContent = (entry.by === 'user' ? 'White ' : 'Black ') + entry.notation;
689
+ if (index === state.moveLog.length - 1) item.className = 'latest';
690
+ log.appendChild(item);
691
+ });
692
+ log.scrollTop = log.scrollHeight;
693
+ } else {
694
+ log.innerHTML = '<li>No moves yet — white opens.</li>';
695
+ }
696
+
697
+ var board = document.getElementById('board');
698
+ board.innerHTML = '';
699
+ var myTurn = state && (demoMode || state.turn === 'user') && state.status === 'playing' && !busy;
700
+ for (var y = 0; y < 8; y += 1) {
701
+ for (var x = 0; x < 8; x += 1) {
702
+ var name = squareName(x, y);
703
+ var piece = state ? state.squares[y * 8 + x] : '.';
704
+ var choices = movesTo(name);
705
+ var cell = document.createElement('button');
706
+ cell.type = 'button';
707
+ cell.className = 'cell ' + ((x + y) % 2 ? 'dark' : 'light');
708
+ cell.setAttribute('aria-label', name + (piece === '.' ? ', empty' : ', ' + piece));
709
+ cell.dataset.square = name;
710
+ if (state && state.lastMove) {
711
+ if (state.lastMove.from === name) cell.className += ' last-from';
712
+ if (state.lastMove.to === name) cell.className += ' last-to';
713
+ }
714
+ if (selected === name) cell.className += ' selected';
715
+ if (choices.length) {
716
+ cell.className += ' hint';
717
+ if (piece !== '.') cell.className += ' capture';
718
+ }
719
+ if (myTurn && (movesFrom(name).length || choices.length)) cell.className += ' selectable';
720
+
721
+ if (x === 0) {
722
+ var rank = document.createElement('span');
723
+ rank.className = 'coord rank';
724
+ rank.textContent = String(8 - y);
725
+ cell.appendChild(rank);
726
+ }
727
+ if (y === 7) {
728
+ var file = document.createElement('span');
729
+ file.className = 'coord file';
730
+ file.textContent = FILES[x];
731
+ cell.appendChild(file);
732
+ }
733
+ if (piece !== '.') {
734
+ var figure = document.createElement('span');
735
+ figure.className = 'piece ' + (sideOf(piece) === 'user' ? 'white' : 'black');
736
+ figure.dataset.glyph = PIECES[piece];
737
+ figure.setAttribute('aria-hidden', 'true');
738
+ cell.appendChild(figure);
739
+ }
740
+ cell.addEventListener('click', onSquareClick);
741
+ board.appendChild(cell);
742
+ }
743
+ }
744
+ }
745
+
746
+ function onSquareClick(event) {
747
+ if (!state || (!demoMode && state.turn !== 'user') || state.status !== 'playing' || busy) return;
748
+ var name = event.currentTarget.dataset.square;
749
+ var destinations = movesTo(name);
750
+ if (selected && destinations.length) {
751
+ if (destinations.some(function (move) { return move.promotion; })) {
752
+ openPromotion(destinations);
753
+ } else {
754
+ submitMove(destinations[0]);
755
+ }
756
+ return;
757
+ }
758
+ if (movesFrom(name).length) selected = name;
759
+ else selected = null;
760
+ render();
761
+ }
762
+
763
+ function openPromotion(moves) {
764
+ promotionMoves = moves;
765
+ var tray = document.getElementById('promotion-choices');
766
+ tray.innerHTML = '';
767
+ moves.forEach(function (move) {
768
+ var button = document.createElement('button');
769
+ button.type = 'button';
770
+ button.className = 'promotion-key';
771
+ button.textContent = PROMOTION_PIECES[move.promotion];
772
+ button.setAttribute('aria-label', 'Promote to ' + move.promotion);
773
+ button.addEventListener('click', function () {
774
+ document.getElementById('promotion-dialog').close();
775
+ submitMove(move);
776
+ });
777
+ tray.appendChild(button);
778
+ });
779
+ document.getElementById('promotion-dialog').showModal();
780
+ }
781
+
782
+ function submitMove(move) {
783
+ selected = null;
784
+ busy = true;
785
+ render();
786
+ gezel.tools
787
+ .invoke('user_move', {
788
+ from: move.from,
789
+ to: move.to,
790
+ ...(move.promotion ? { promotion: move.promotion } : {}),
791
+ })
792
+ .then(function (result) {
793
+ busy = false;
794
+ if (
795
+ result.reaction &&
796
+ result.reaction.delivered === false &&
797
+ result.reaction.reason === 'engagement-off'
798
+ ) {
799
+ setBanner('Move played — but AI engagement is off, so the Schaakspeler cannot reply.');
800
+ }
801
+ return loadGame();
802
+ })
803
+ .catch(function (error) {
804
+ busy = false;
805
+ setBanner(invokeErrorText(error));
806
+ render();
807
+ });
808
+ }
809
+
810
+ function newGame() {
811
+ if (busy) return;
812
+ selected = null;
813
+ busy = true;
814
+ render();
815
+ gezel.tools
816
+ .invoke('new_game', {})
817
+ .then(function () {
818
+ busy = false;
819
+ setBanner('');
820
+ return loadGame();
821
+ })
822
+ .catch(function (error) {
823
+ busy = false;
824
+ setBanner(invokeErrorText(error));
825
+ render();
826
+ });
827
+ }
828
+
829
+ function transitionState(next) {
830
+ state = next;
831
+ if (selected && !movesFrom(selected).length) selected = null;
832
+ render();
833
+ }
834
+ function loadGame() {
835
+ return gezel.data.read('game.json').then(
836
+ function (next) { if (next) transitionState(next); },
837
+ function () {},
838
+ );
839
+ }
840
+
841
+ document.getElementById('newgame').addEventListener('click', newGame);
842
+ document.getElementById('cancel-promotion').addEventListener('click', function () {
843
+ promotionMoves = [];
844
+ document.getElementById('promotion-dialog').close();
845
+ });
846
+ loadGame();
847
+ gezel.data.watch('game.json', function () { loadGame(); });
848
+ })();
849
+ </script>
850
+ </body>
851
+ </html>