@bendyline/gilde 0.1.7 → 0.1.8

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