Repository navigation
Expand file tree
/
Copy pathindex.html
More file actions
351 lines (334 loc) · 18 KB
/
Copy pathindex.html
File metadata and controls
351 lines (334 loc) · 18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Play chess for free, right in your browser. Challenge the computer, pass & play with a friend on one device, or invite a friend to a private online game." />
<link rel="canonical" href="https://chess.puter.com/" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Chess" />
<meta property="og:url" content="https://chess.puter.com/" />
<meta property="og:title" content="Play Chess Online — vs the Computer or a Friend" />
<meta property="og:description" content="Play chess for free, right in your browser. Challenge the computer, pass & play on one device, or invite a friend to a private online game." />
<!-- 1200x630 (1.91:1) is the ratio Facebook, LinkedIn, Slack, and X's
large card all render. Built from tools/og-image.html. -->
<meta property="og:image" content="https://chess.puter.com/og-image.png" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="Play Chess Online — free in your browser. A chess board showing a checkmate position." />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Play Chess Online — vs the Computer or a Friend" />
<meta name="twitter:description" content="Play chess for free, right in your browser. Challenge the computer, pass & play on one device, or invite a friend to a private online game." />
<meta name="twitter:image" content="https://chess.puter.com/og-image.png" />
<meta name="twitter:image:alt" content="Play Chess Online — free in your browser. A chess board showing a checkmate position." />
<link rel="icon" href="favicon.ico" sizes="48x48" />
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png" />
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png" />
<link rel="manifest" href="site.webmanifest" />
<meta name="theme-color" content="#f4f5f9" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#13151b" media="(prefers-color-scheme: dark)" />
<title>Play Chess Online — vs the Computer or a Friend</title>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": ["WebApplication", "VideoGame"],
"name": "Chess — Play Online",
"url": "https://chess.puter.com/",
"description": "Play chess for free, right in your browser. Challenge the computer, pass & play with a friend on one device, or invite a friend to a private online game.",
"applicationCategory": "GameApplication",
"operatingSystem": "Any",
"browserRequirements": "Requires JavaScript",
"genre": "Board game",
"gamePlatform": "Web browser",
"playMode": ["SinglePlayer", "MultiPlayer"],
"image": "https://chess.puter.com/icon-512.png",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
}
}
</script>
<script>
// Resolve the theme before first paint to avoid a flash. main.js keeps
// the attribute in sync afterwards; "system" follows the OS setting.
(function () {
var theme;
try {
theme = (JSON.parse(localStorage.getItem('chess-settings')) || {}).theme;
} catch (e) {
/* fall through to system */
}
if (theme !== 'light' && theme !== 'dark') {
theme = window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light';
}
document.documentElement.dataset.theme = theme;
})();
</script>
<!-- Privacy-friendly analytics by Plausible -->
<script async src="https://plausible.io/js/pa-wKhkwB5oGmJ0GlsSr-Bun.js"></script>
<script>
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
plausible.init()
</script>
</head>
<body>
<noscript>
<p class="noscript-note">
This chess game runs entirely in your browser and needs JavaScript to
work. Enable JavaScript to play against the computer, pass & play
with a friend on one device, or start a private online game.
</p>
</noscript>
<div id="app">
<header class="topbar">
<div class="brand">
<span class="brand-mark"><img src="icon-128.png" alt="" width="128" height="128" /></span>
<h1 class="brand-name">Chess<span class="visually-hidden"> — play the computer or a friend, free in your browser</span></h1>
</div>
<div class="topbar-right">
<span class="topbar-note" id="topbar-note">Player vs. Computer</span>
<div class="theme-toggle" role="group" aria-label="Theme">
<button type="button" data-theme-choice="light" title="Light theme" aria-label="Light theme">
<i data-lucide="sun"></i>
</button>
<button type="button" data-theme-choice="dark" title="Dark theme" aria-label="Dark theme">
<i data-lucide="moon"></i>
</button>
<button type="button" data-theme-choice="system" title="Follow system theme" aria-label="Follow system theme">
<i data-lucide="monitor"></i>
</button>
</div>
</div>
</header>
<main class="layout">
<section class="board-column">
<div class="board-frame">
<div id="board" class="board" role="grid" aria-label="Chess board"></div>
</div>
</section>
<aside class="sidebar">
<div class="mode-switch" role="group" aria-label="Game mode">
<button type="button" data-mode="computer" aria-pressed="true">
<i data-lucide="cpu"></i>Computer
</button>
<button type="button" data-mode="local" aria-pressed="false">
<i data-lucide="users"></i>Pass & Play
</button>
<button type="button" data-mode="online" aria-pressed="false">
<i data-lucide="globe"></i>Online
</button>
</div>
<div id="result-banner" class="result-banner hidden"></div>
<section class="card online-card hidden" id="online-card" aria-label="Online game setup">
<div class="online-section" id="online-idle">
<h2 class="card-title">Play a friend</h2>
<p class="online-note" id="online-invite-note" hidden>
You’ve been invited to a game — press Join to connect.
</p>
<button class="btn btn-primary btn-block" id="host-btn" type="button">
<i data-lucide="plus"></i><span id="host-btn-label">Create game</span>
</button>
<div class="online-divider" aria-hidden="true"><span>or join with a code</span></div>
<form class="join-row" id="join-form">
<label class="visually-hidden" for="join-input">Invite code</label>
<!-- Invite codes are served uppercase and the peer API matches
them exactly, so a phone keyboard that starts in lowercase
costs the player a failed join. Ask for capitals. -->
<input
id="join-input"
name="code"
placeholder="Invite code"
autocomplete="off"
autocapitalize="characters"
autocorrect="off"
spellcheck="false"
/>
<button class="btn btn-ghost" id="join-btn" type="submit">Join</button>
</form>
<p class="online-error" id="online-error" role="alert" hidden></p>
</div>
<div class="online-section hidden" id="online-hosting">
<h2 class="card-title">Invite your friend</h2>
<div class="invite-box">
<code class="invite-code" id="invite-code"></code>
<button class="icon-btn" id="copy-code-btn" type="button" title="Copy invite code" aria-label="Copy invite code">
<i data-lucide="copy" class="icon-copy"></i>
<i data-lucide="check" class="icon-check hidden"></i>
</button>
</div>
<button class="btn btn-primary btn-block" id="copy-link-btn" type="button">
<i data-lucide="link"></i><span id="copy-link-label">Copy invite link</span>
</button>
<p class="online-wait"><span class="spinner" aria-hidden="true"></span>Waiting for your friend to join…</p>
<button class="btn btn-ghost btn-block" id="cancel-host-btn" type="button">Cancel</button>
</div>
<div class="online-section hidden" id="online-joining">
<h2 class="card-title">Joining game</h2>
<p class="online-wait"><span class="spinner" aria-hidden="true"></span>Connecting to your friend…</p>
<button class="btn btn-ghost btn-block" id="cancel-join-btn" type="button">Cancel</button>
</div>
</section>
<section class="card player-card" id="card-top">
<span class="player-icon">
<i data-lucide="cpu" class="icon-cpu"></i>
<i data-lucide="user" class="icon-user hidden"></i>
</span>
<div class="player-info">
<p class="player-line">
<span class="player-name" id="top-name">Computer</span>
<span class="player-note" id="top-caption">Medium</span>
<span class="dots" aria-hidden="true"><span></span><span></span><span></span></span>
</p>
<p class="player-taken">
<span class="caps" id="captures-top"></span>
<span class="material" id="material-top"></span>
</p>
</div>
<!-- role="timer" is readable on demand but never announced, which
is what a value changing ten times a second wants to be. -->
<span class="clock hidden" id="clock-top" role="timer"></span>
<span class="turn-dot" aria-hidden="true"></span>
</section>
<section class="card moves-card" id="moves-card">
<div class="card-head">
<h2 class="card-title">Moves</h2>
<div class="card-actions">
<button class="icon-btn icon-btn-sm" id="pgn-copy-btn" type="button" title="Copy the game as PGN" aria-label="Copy the game as PGN" disabled>
<i data-lucide="clipboard-copy"></i>
</button>
<button class="icon-btn icon-btn-sm" id="pgn-download-btn" type="button" title="Download the game as a PGN file" aria-label="Download the game as a PGN file" disabled>
<i data-lucide="download"></i>
</button>
</div>
</div>
<ol class="move-list" id="move-list"></ol>
<p class="moves-empty" id="moves-empty">No moves yet — White begins.</p>
<div class="review-bar">
<div class="review-nav" role="group" aria-label="Review the game">
<button class="icon-btn icon-btn-sm" id="review-first-btn" type="button" title="Starting position" aria-label="Go to the starting position" disabled>
<i data-lucide="chevron-first"></i>
</button>
<button class="icon-btn icon-btn-sm" id="review-prev-btn" type="button" title="Previous move" aria-label="Go back one move" disabled>
<i data-lucide="chevron-left"></i>
</button>
<button class="icon-btn icon-btn-sm" id="review-next-btn" type="button" title="Next move" aria-label="Go forward one move" disabled>
<i data-lucide="chevron-right"></i>
</button>
<button class="icon-btn icon-btn-sm" id="review-last-btn" type="button" title="Current position" aria-label="Return to the current position" disabled>
<i data-lucide="chevron-last"></i>
</button>
</div>
<p class="review-note" id="review-note"></p>
</div>
</section>
<section class="card player-card" id="card-bottom">
<span class="player-icon"><i data-lucide="user"></i></span>
<div class="player-info">
<p class="player-line">
<span class="player-name" id="bottom-name">You</span>
<span class="player-note" id="bottom-caption">Playing White</span>
</p>
<p class="player-taken">
<span class="caps" id="captures-bottom"></span>
<span class="material" id="material-bottom"></span>
</p>
</div>
<span class="clock hidden" id="clock-bottom" role="timer"></span>
<span class="turn-dot" aria-hidden="true"></span>
</section>
<section class="controls" id="controls">
<div class="field-row" id="field-row">
<label class="field" id="level-field">
<span class="field-label">Difficulty</span>
<select id="level-select">
<option value="easy">Easy</option>
<option value="medium" selected>Medium</option>
<option value="hard">Hard</option>
</select>
</label>
<label class="field" id="time-field">
<span class="field-label">Clock</span>
<!-- Options are built from TIME_CONTROLS in src/game/clock.js,
so the ids that cross the wire and land in saved games
have exactly one definition. -->
<select id="time-select"></select>
</label>
<label class="field" id="color-field">
<span class="field-label" id="color-label">Play as</span>
<select id="color-select">
<option value="w" selected>White</option>
<option value="b">Black</option>
<option value="random">Random</option>
</select>
</label>
</div>
<div class="button-row" id="button-row">
<button class="btn btn-primary" id="new-game-btn" type="button">
<i data-lucide="plus"></i>New game
</button>
<button class="btn btn-ghost" id="undo-btn" type="button" disabled>
<i data-lucide="undo-2"></i>Undo
</button>
<button class="btn btn-primary hidden" id="rematch-btn" type="button">
<i data-lucide="rotate-ccw"></i><span id="rematch-label">Rematch</span>
</button>
<button class="btn btn-ghost btn-danger hidden" id="resign-btn" type="button">
<i data-lucide="flag"></i>Resign
</button>
<button class="btn btn-ghost hidden" id="leave-btn" type="button">
<i data-lucide="log-out"></i>Leave
</button>
</div>
<p class="controls-hint" id="controls-hint">Color takes effect when a new game starts.</p>
</section>
</aside>
</main>
</div>
<!-- Announces moves, check, and game results to assistive technology. -->
<div class="visually-hidden" role="status" id="sr-status"></div>
<!-- Transient notices (copied link, opponent events, connection errors). -->
<div class="toast" id="toast" role="status"></div>
<dialog class="dialog promo-dialog" id="promo-dialog" aria-labelledby="promo-title">
<h2 class="dialog-title" id="promo-title">Promote to</h2>
<div class="promo-choices">
<button type="button" data-promo="q" autofocus><img alt="Queen" /></button>
<button type="button" data-promo="r"><img alt="Rook" /></button>
<button type="button" data-promo="b"><img alt="Bishop" /></button>
<button type="button" data-promo="n"><img alt="Knight" /></button>
</div>
</dialog>
<dialog class="dialog gameover-dialog" id="gameover-dialog" aria-labelledby="gameover-title" aria-describedby="gameover-sub">
<span class="gameover-icon" id="gameover-icon-win"><i data-lucide="trophy"></i></span>
<span class="gameover-icon" id="gameover-icon-loss"><i data-lucide="flag"></i></span>
<span class="gameover-icon" id="gameover-icon-draw"><i data-lucide="handshake"></i></span>
<h2 class="dialog-title" id="gameover-title">Game over</h2>
<p class="dialog-sub" id="gameover-sub"></p>
<div class="dialog-buttons">
<button class="btn btn-primary" id="gameover-new" type="button" autofocus>New game</button>
<button class="btn btn-ghost" id="gameover-close" type="button">Review board</button>
</div>
</dialog>
<dialog class="dialog" id="confirm-dialog" aria-labelledby="confirm-title" aria-describedby="confirm-sub">
<h2 class="dialog-title" id="confirm-title"></h2>
<p class="dialog-sub" id="confirm-sub"></p>
<div class="dialog-buttons">
<button class="btn btn-danger-solid" id="confirm-yes" type="button"></button>
<button class="btn btn-ghost" id="confirm-no" type="button" autofocus>Cancel</button>
</div>
</dialog>
<dialog class="dialog" id="rematch-dialog" aria-labelledby="rematch-title" aria-describedby="rematch-sub">
<h2 class="dialog-title" id="rematch-title">Rematch?</h2>
<p class="dialog-sub" id="rematch-sub"></p>
<div class="dialog-buttons">
<button class="btn btn-primary" id="rematch-accept" type="button" autofocus>Accept</button>
<button class="btn btn-ghost" id="rematch-decline" type="button">Decline</button>
</div>
</dialog>
<script type="module" src="/src/main.js"></script>
</body>
</html>