@pech/chess-board 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +100 -0
- package/dist/index.cjs +982 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +107 -0
- package/dist/index.d.ts +107 -0
- package/dist/index.js +975 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,975 @@
|
|
|
1
|
+
// src/coords.ts
|
|
2
|
+
var FILES = "abcdefgh";
|
|
3
|
+
function squareToCoords(sq, orientation) {
|
|
4
|
+
const fileIdx = FILES.indexOf(sq.charAt(0));
|
|
5
|
+
const rank = Number(sq.charAt(1));
|
|
6
|
+
if (orientation === "white") {
|
|
7
|
+
return [fileIdx, 8 - rank];
|
|
8
|
+
}
|
|
9
|
+
return [7 - fileIdx, rank - 1];
|
|
10
|
+
}
|
|
11
|
+
function coordsToSquare(col, row, orientation) {
|
|
12
|
+
if (col < 0 || col > 7 || row < 0 || row > 7) return null;
|
|
13
|
+
let fileIdx;
|
|
14
|
+
let rank;
|
|
15
|
+
if (orientation === "white") {
|
|
16
|
+
fileIdx = col;
|
|
17
|
+
rank = 8 - row;
|
|
18
|
+
} else {
|
|
19
|
+
fileIdx = 7 - col;
|
|
20
|
+
rank = row + 1;
|
|
21
|
+
}
|
|
22
|
+
const file = FILES.charAt(fileIdx);
|
|
23
|
+
if (!file) return null;
|
|
24
|
+
return `${file}${rank}`;
|
|
25
|
+
}
|
|
26
|
+
function isLightSquare(sq) {
|
|
27
|
+
const fileIdx = FILES.indexOf(sq.charAt(0));
|
|
28
|
+
const rankIdx = Number(sq.charAt(1)) - 1;
|
|
29
|
+
return (fileIdx + rankIdx) % 2 !== 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/fen.ts
|
|
33
|
+
var STARTING_FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
|
34
|
+
var FEN_PIECES = {
|
|
35
|
+
K: { color: "white", type: "king" },
|
|
36
|
+
Q: { color: "white", type: "queen" },
|
|
37
|
+
R: { color: "white", type: "rook" },
|
|
38
|
+
B: { color: "white", type: "bishop" },
|
|
39
|
+
N: { color: "white", type: "knight" },
|
|
40
|
+
P: { color: "white", type: "pawn" },
|
|
41
|
+
k: { color: "black", type: "king" },
|
|
42
|
+
q: { color: "black", type: "queen" },
|
|
43
|
+
r: { color: "black", type: "rook" },
|
|
44
|
+
b: { color: "black", type: "bishop" },
|
|
45
|
+
n: { color: "black", type: "knight" },
|
|
46
|
+
p: { color: "black", type: "pawn" }
|
|
47
|
+
};
|
|
48
|
+
var PIECE_TO_CHAR = {
|
|
49
|
+
king: "k",
|
|
50
|
+
queen: "q",
|
|
51
|
+
rook: "r",
|
|
52
|
+
bishop: "b",
|
|
53
|
+
knight: "n",
|
|
54
|
+
pawn: "p"
|
|
55
|
+
};
|
|
56
|
+
function parseFen(fen) {
|
|
57
|
+
const pieces = /* @__PURE__ */ new Map();
|
|
58
|
+
const placement = fen.split(" ")[0] ?? "";
|
|
59
|
+
const rows = placement.split("/");
|
|
60
|
+
for (let r = 0; r < rows.length; r++) {
|
|
61
|
+
const row = rows[r];
|
|
62
|
+
if (!row) continue;
|
|
63
|
+
const rank = 8 - r;
|
|
64
|
+
let fileIdx = 0;
|
|
65
|
+
for (const ch of row) {
|
|
66
|
+
if (ch >= "1" && ch <= "8") {
|
|
67
|
+
fileIdx += Number(ch);
|
|
68
|
+
} else {
|
|
69
|
+
const piece = FEN_PIECES[ch];
|
|
70
|
+
if (piece && fileIdx < 8) {
|
|
71
|
+
const file = FILES.charAt(fileIdx);
|
|
72
|
+
pieces.set(`${file}${rank}`, piece);
|
|
73
|
+
}
|
|
74
|
+
fileIdx++;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return pieces;
|
|
79
|
+
}
|
|
80
|
+
function positionToFen(pieces) {
|
|
81
|
+
const rows = [];
|
|
82
|
+
for (let rank = 8; rank >= 1; rank--) {
|
|
83
|
+
let row = "";
|
|
84
|
+
let empty = 0;
|
|
85
|
+
for (let f = 0; f < 8; f++) {
|
|
86
|
+
const file = FILES.charAt(f);
|
|
87
|
+
const key = `${file}${rank}`;
|
|
88
|
+
const piece = pieces.get(key);
|
|
89
|
+
if (piece) {
|
|
90
|
+
if (empty > 0) {
|
|
91
|
+
row += String(empty);
|
|
92
|
+
empty = 0;
|
|
93
|
+
}
|
|
94
|
+
const ch = PIECE_TO_CHAR[piece.type];
|
|
95
|
+
row += piece.color === "white" ? ch.toUpperCase() : ch;
|
|
96
|
+
} else {
|
|
97
|
+
empty++;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (empty > 0) row += String(empty);
|
|
101
|
+
rows.push(row);
|
|
102
|
+
}
|
|
103
|
+
return rows.join("/");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/pieces-svg.ts
|
|
107
|
+
var PIECE_SVGS = {
|
|
108
|
+
"white-king": '<svg version="1.1" viewBox="0 0 4096 4096" xmlns="http://www.w3.org/2000/svg">\n <path d="m2125.3 872.45h-156.01v-287.84h-182.37q-74.707 0-74.707-72.51v-2.1973q0-72.51 74.707-72.51h182.37v-186.77q0-76.904 79.102-76.904 76.904 0 76.904 76.904v186.77h188.96q72.51 0 72.51 72.51v2.1973q0 72.51-72.51 72.51l-186.77 2.1973z"/>\n <path d="m815.81 3151-72.51-410.89q-2.1973 0-6.5918-8.789-10.986-15.381-63.721-39.551-50.537-26.367-118.65-87.891-96.68-81.299-151.61-131.84-52.734-50.537-96.68-109.86-134.03-184.57-149.41-446.04-21.973-252.69 204.35-503.17 228.52-250.49 617.43-235.11 145.02 8.789 340.58 70.312 63.721 26.367 129.64 52.734 68.115 24.17 134.03 50.537 35.156 17.578 61.523 35.156-10.986-46.143-10.986-92.285 0-171.39 120.85-292.24 123.05-120.85 294.43-123.05 171.39 0 292.24 123.05 120.85 120.85 120.85 290.04 0 35.156-8.789 92.285 30.762-19.775 59.326-32.959 101.07-43.945 265.87-103.27 188.96-63.721 340.58-72.51 388.92-17.578 615.23 235.11 221.92 250.49 206.54 503.17-17.578 261.47-151.61 446.04-43.945 59.326-98.877 112.06-54.932 50.537-147.22 129.64-72.51 61.523-123.05 87.891-50.537 24.17-59.326 39.551-2.1973 4.3945-4.3946 6.5918-2.1972 2.1973-2.1972 4.3945l-70.312 413.09 145.02 542.72q-109.86 98.877-492.19 162.6t-883.3 63.721q-509.77 0-896.48-68.115-386.72-65.918-485.6-166.99z"/>\n <path d="m2123.2 2423.8q377.93 4.3945 692.14 46.143 314.21 39.551 492.19 101.07 83.496-65.918 182.37-145.02 98.877-81.299 164.79-164.8 105.47-134.03 105.47-353.76 0-197.75-94.482-329.59-169.19-246.09-514.16-246.09-206.54 0-424.07 85.693-191.16 76.904-290.04 171.39-184.57 184.57-272.46 474.61-30.762 103.27-37.354 188.96-4.3946 83.496-4.3946 171.39z" fill="#fff"/>\n <path d="m2048.4 2015.1q15.381-61.524 26.367-85.693 21.973-85.693 50.537-145.02 13.184-37.354 37.354-85.693 26.367-50.537 54.932-114.26 17.578-37.354 37.354-90.088 19.775-54.932 39.551-107.67 17.578-43.945 17.578-94.482 0-107.67-76.904-182.37-76.904-76.904-186.77-76.904-261.47 0-261.47 261.47 0 50.537 17.578 94.482 48.34 142.82 74.707 197.75 28.564 63.721 52.734 114.26 24.17 48.34 41.748 85.693 28.564 72.51 48.34 145.02 4.3945 13.184 26.367 83.496z" fill="#fff"/>\n <path d="m1971.5 2423.8q-2.1973-85.693-6.5918-169.19-4.3945-85.693-32.959-188.96-90.088-294.43-272.46-474.61-94.482-92.285-290.04-171.39-224.12-87.891-424.07-87.891-347.17 0-514.16 248.29-94.482 131.84-94.482 329.59 0 215.33 105.47 353.76 63.721 81.299 162.6 162.6 98.877 81.299 184.57 147.22 384.52-138.43 1182.1-149.41z" fill="#fff"/>\n <path d="m3248.1 3614.6q-424.07-171.39-1190.9-171.39-795.41 0-1204.1 175.78 386.72 153.81 1197.5 153.81 386.72 0 705.32-43.945 318.6-41.748 492.19-114.26z" fill="#fff"/>\n <path d="m3191 3408.1-65.918-252.69q-435.06-96.68-1076.7-96.68-639.4 0-1074.5 96.68l-70.312 254.88q419.68-123.05 1147-123.05 722.9 0 1140.4 120.85z" fill="#fff"/>\n <path d="m949.84 3017q417.48-105.47 1107.4-105.47 676.76 0 1092 101.07l54.932-323q-441.65-116.46-1155.8-116.46-718.51 0-1153.6 118.65z" fill="#fff"/>\n</svg>',
|
|
109
|
+
"white-queen": '<svg version="1.1" viewBox="0 0 4096 4096" xmlns="http://www.w3.org/2000/svg">\n <path d="m3781.6 1118.5q-125.24 0-213.13-85.693-87.891-87.891-87.891-213.13 0-123.05 87.891-210.94 87.891-90.088 213.13-90.088 123.05 0 210.94 90.088 87.891 87.891 87.891 210.94 0 125.24-87.891 213.13-87.891 85.693-210.94 85.693z"/>\n <path d="m314.25 1118.5q-125.24 0-213.13-85.693-85.693-87.891-85.693-213.13 0-123.05 85.693-210.94 87.891-90.088 213.13-90.088t213.13 90.088q87.891 87.891 87.891 210.94 0 125.24-87.891 213.13-87.891 85.693-213.13 85.693z"/>\n <path d="m2968.6 876.76q-125.24 0-213.13-85.693-85.693-87.891-85.693-213.13 0-123.05 85.693-210.94 87.891-87.891 213.13-87.891 125.24 0 213.13 87.891 87.891 87.891 87.891 210.94 0 125.24-87.891 213.13-87.891 85.693-213.13 85.693z"/>\n <path d="m1122.9 876.76q-125.24 0-213.13-85.693-87.891-87.891-87.891-213.13 0-123.05 87.891-210.94 87.891-87.891 213.13-87.891 123.05 0 210.94 87.891 87.891 87.891 87.891 210.94 0 125.24-87.891 213.13-87.891 85.693-210.94 85.693z"/>\n <path d="m3399.2 3706.9q-107.67 94.482-483.4 158.2t-865.72 63.721q-498.78 0-876.71-65.918t-476.81-164.8l138.43-527.34-61.523-344.97-193.36-336.18-186.77-1366.7 107.67-41.748 602.05 1015.1 13.184-1208.5 149.41-26.367 459.23 1215.1 246.09-1307.4h151.61l246.09 1303 454.83-1210.7 151.61 26.367 13.184 1208.5 604.25-1017.3 103.27 48.34-182.37 1360.1-195.56 336.18-61.523 349.37z"/>\n <path d="m2045.8 766.99q-125.24 0-213.13-87.891-85.693-87.891-85.693-213.13 0-123.05 85.693-210.94 87.891-87.891 213.13-87.891 123.05 0 210.94 87.891 90.088 87.891 90.088 210.94 0 125.24-90.088 213.13-87.891 87.891-210.94 87.891z"/>\n <path d="m3781.6 964.65q145.02 0 145.02-145.02 0-147.22-145.02-147.22-147.22 0-147.22 147.22 0 145.02 147.22 145.02z" fill="#fff"/>\n <path d="m314.25 964.65q147.22 0 147.22-145.02 0-147.22-147.22-147.22-145.02 0-145.02 147.22 0 145.02 145.02 145.02z" fill="#fff"/>\n <path d="m2968.6 722.95q147.22 0 147.22-145.02t-147.22-145.02q-145.02 0-145.02 145.02t145.02 145.02z" fill="#fff"/>\n <path d="m1122.9 722.95q145.02 0 145.02-145.02t-145.02-145.02q-147.22 0-147.22 145.02t147.22 145.02z" fill="#fff"/>\n <path d="m3221.3 3627.8q-402.1-166.99-1166.7-166.99-780.03 0-1179.9 171.39 384.52 151.61 1173.3 151.61 377.93 0 689.94-41.748 314.21-41.748 483.4-114.26z" fill="#fff"/>\n <path d="m3166.3 3425.6-65.918-248.29q-430.66-94.482-1054.7-94.482-617.43 0-1052.5 94.482l-68.115 250.49q408.69-123.05 1122.8-123.05 696.53 0 1118.4 120.85z" fill="#fff"/>\n <path d="m3034.5 2313.8q50.537 15.381 112.06 15.381 134.03 0 250.49-83.496l120.85-760.25z" fill="#fff"/>\n <path d="m1050.4 2302.8-472.41-815.19 120.85 742.68q125.24 87.891 243.9 87.891 46.143 0 107.67-15.381z" fill="#fff"/>\n <path d="m1608.5 2179.8-360.35-986.57v1004.2q6.5918-8.789 19.775-21.973 43.945-92.285 145.02-92.285 83.496 0 136.23 70.312z" fill="#fff"/>\n <path d="m2843.4 2210.5v-1017.3l-362.55 997.56q41.748-15.381 70.312-39.551 43.945-54.932 118.65-54.932 87.891 0 140.62 76.904 6.5918 8.7891 15.381 19.775 8.7891 8.789 17.578 17.578z" fill="#fff"/>\n <path d="m2234.8 2168.8-186.77-1074.5-186.77 1061.3q6.5918-4.3946 30.762-21.973 50.537-98.877 153.81-98.877 112.06 0 145.02 98.877 13.184 13.184 43.945 35.156z" fill="#fff"/>\n <path d="m3219.1 2693.9 142.82-252.69q-105.47 41.748-215.33 41.748-294.43 0-470.21-239.5-131.84 109.86-294.43 109.86-210.94 0-336.18-164.79-140.62 153.81-336.18 153.81-158.2 0-290.04-107.67-184.57 235.11-476.81 235.11-112.06 0-221.92-41.748l153.81 263.67q426.27-123.05 1171.1-123.05 758.06 0 1173.3 125.24z" fill="#fff"/>\n <path d="m3164.2 2825.8q-424.07-107.67-1109.6-107.67-703.12 0-1122.8 109.86l32.959 210.94q428.47-101.07 1089.8-101.07 656.98 0 1072.3 98.877z" fill="#fff"/>\n <path d="m2045.8 613.18q147.22 0 147.22-147.22 0-145.02-147.22-145.02-145.02 0-145.02 145.02 0 147.22 145.02 147.22z" fill="#fff"/>\n</svg>',
|
|
110
|
+
"white-rook": '<svg version="1.1" viewBox="0 0 4096 4096" xmlns="http://www.w3.org/2000/svg">\n <path d="m2350.1 549.46h373.54v-301.03h602.05v823.97l-487.79 375.73v1050.3l373.54 373.54v450.44h336.18v525.15h-2999.3v-525.15h336.18v-450.44l375.73-373.54v-1050.3l-487.79-375.73v-823.97h599.85v301.03h375.73v-301.03h602.05z"/>\n <path d="m2763.2 1298.9 279.05-226.32h-1986.3l281.25 226.32z" fill="#fff"/>\n <path d="m3004.9 2872.1-226.32-224.12h-1456.8l-230.71 224.12z" fill="#fff"/>\n <path d="m3174.1 923.07v-525.15h-301.03v301.03h-676.76v-301.03h-296.63v301.03h-674.56v-301.03h-301.03v525.15z" fill="#fff"/>\n <path d="m2686.3 1448.2h-1274.4v1050.3h1274.4z" fill="#fff"/>\n <path d="m3059.8 3023.6h-2021.5v298.83h2021.5z" fill="#fff"/>\n <path d="m3400.4 3471.9h-2702.6v226.32h2702.6z" fill="#fff"/>\n</svg>',
|
|
111
|
+
"white-bishop": '<svg version="1.1" viewBox="0 0 4096 4096" xmlns="http://www.w3.org/2000/svg">\n <path d="m2048 3456.4q-30.762 125.24-74.707 173.58t-116.46 101.07q-79.102 54.932-186.77 92.285-107.67 39.551-239.5 19.775l-617.43-85.693q-37.354-4.3945-68.115 0-28.564 4.3946-54.932 4.3946-46.143 0-118.65 19.775-70.312 21.973-109.86 61.523l-213.13-349.37q39.551-43.945 70.312-61.524t72.51-37.354q127.44-59.326 272.46-72.51 61.523-4.3945 120.85-2.1972 59.326 2.1972 123.05-4.3946 118.65 19.775 237.3 37.354 120.85 15.381 241.7 32.959 131.84 0 177.98-26.367 24.17-13.184 76.904-48.34t105.47-103.27q-116.46-13.184-237.3-43.945-120.85-32.959-213.13-68.115l228.52-566.89q-171.39-98.877-239.5-158.2-68.115-61.523-107.67-140.62-57.129-101.07-74.707-195.56-15.381-94.482-13.184-169.19 2.1973-131.84 61.523-290.04 61.524-160.4 228.52-285.64 138.43-105.47 270.26-217.53 131.84-112.06 261.47-261.47-162.6-83.496-162.6-265.87 0-123.05 85.693-210.94 87.891-87.891 213.13-87.891 123.05 0 210.94 87.891 87.891 87.891 87.891 210.94 0 180.18-162.6 265.87 127.44 149.41 257.08 261.47 131.84 112.06 274.66 217.53 164.79 125.24 224.12 285.64 59.326 158.2 63.721 290.04 0 74.707-15.381 169.19-15.381 94.482-70.312 195.56-43.945 79.102-112.06 140.62-65.918 59.326-235.11 158.2l228.52 566.89q-96.68 35.156-217.53 68.115-120.85 30.762-232.91 43.945 50.537 68.115 103.27 103.27 52.734 35.156 79.102 48.34 46.143 26.367 177.98 26.367 118.65-17.578 237.3-32.959 120.85-17.578 241.7-37.354 59.326 6.5918 118.65 4.3946 61.523-2.1973 125.24 2.1972 140.62 13.184 272.46 72.51 39.551 19.775 70.312 37.354 32.959 17.578 72.51 61.524l-215.33 349.37q-39.551-39.551-112.06-61.523-70.312-19.775-114.26-19.775-28.564 0-59.326-4.3946-28.564-4.3945-65.918 0l-615.23 85.693q-131.84 19.775-246.09-17.578-112.06-37.354-184.57-98.877-72.51-59.326-116.46-103.27-41.748-41.748-70.312-166.99z"/>\n <path d="m1968.9 3208.1h-70.312q-123.05 197.75-235.11 248.29-52.734 26.367-116.46 48.34-63.721 21.973-147.22 21.973-15.381 0-235.11-35.156-105.47-15.381-166.99-32.959t-96.68-21.973q-125.24-15.381-292.24 13.184-101.07 17.578-188.96 63.721l105.47 171.39q26.367-26.367 68.115-35.156 43.945-6.5918 79.102-15.381 92.285-15.381 175.78-4.3946 28.564 6.5918 112.06 15.381 83.496 10.986 221.92 32.959 164.8 24.17 224.12 24.17 230.71 0 353.76-87.891 74.707-57.129 140.62-160.4 68.115-101.07 68.115-246.09z" fill="#fff"/>\n <path d="m2048 2379.7q213.13 0 408.69 32.959 215.33-76.904 312.01-239.5 83.496-140.62 83.496-309.81 0-101.07-50.537-221.92-50.537-123.05-164.79-221.92-129.64-107.67-283.45-235.11-153.81-129.64-305.42-301.03-153.81 171.39-307.62 301.03-153.81 127.44-281.25 235.11-116.46 98.877-166.99 221.92-48.34 120.85-48.34 221.92 0 169.19 81.299 309.81 94.482 162.6 314.21 239.5 193.36-32.959 408.69-32.959z" fill="#fff"/>\n <path d="m2048 2779.6q257.08 0 494.38 50.537l-105.47-270.26q-193.36-30.762-388.92-30.762-199.95 0-391.11 30.762l-105.47 270.26q235.11-50.537 496.58-50.537z" fill="#fff"/>\n <path d="m2048 694.4q149.41 0 149.41-149.41t-149.41-149.41-149.41 149.41 149.41 149.41z" fill="#fff"/>\n <path d="m2048 3087.2q149.41 0 290.04-24.17 142.82-26.367 274.66-61.523-257.08-68.115-564.7-68.115-312.01 0-564.7 68.115 127.44 35.156 270.26 61.523 142.82 24.17 294.43 24.17z" fill="#fff"/>\n <path d="m1968.9 1817.2-182.37-2.1973q-74.707 0-74.707-74.707t74.707-74.707h182.37v-188.96q0-76.904 79.102-76.904 76.904 0 76.904 76.904v188.96h188.96q72.51 0 72.51 74.707t-72.51 74.707h-188.96v180.18q0 79.102-76.904 79.102-79.102 0-79.102-79.102z"/>\n <path d="m2124.9 3208.1q0 145.02 65.918 246.09 68.115 103.27 145.02 160.4 120.85 87.891 353.76 87.891 57.129 0 224.12-24.17 136.23-21.973 219.73-32.959 83.496-8.7891 112.06-15.381 83.496-10.986 175.78 4.3946 35.156 8.789 76.904 15.381 43.945 8.7891 72.51 35.156l105.47-171.39q-90.088-46.143-191.16-63.721-166.99-28.564-292.24-13.184-37.354 4.3945-98.877 21.973-59.326 17.578-162.6 32.959-221.92 35.156-235.11 35.156-85.693 0-149.41-21.973-63.721-21.973-114.26-48.34-116.46-52.734-237.3-248.29z" fill="#fff"/>\n</svg>',
|
|
112
|
+
"white-knight": '<svg version="1.1" viewBox="0 0 4096 4096" xmlns="http://www.w3.org/2000/svg">\n <path d="m2166.6 613.2q344.97 21.973 639.4 177.98 294.43 156.01 500.98 399.9 145.02 171.39 272.46 413.09 129.64 241.7 206.54 511.96 87.891 314.21 109.86 661.38 24.17 344.97 24.17 639.4v479t-342.77 0q-340.58 0-885.5 0h-1474.4q-19.775 0-19.775-107.67 2.1972-107.67 15.381-173.58 8.7891-52.734 41.748-149.41t109.86-235.11q35.156-70.312 166.99-204.35 131.84-136.23 303.22-314.21 98.877-101.07 153.81-254.88 57.129-153.81 48.34-279.05-81.299 65.918-177.98 107.67-465.82 166.99-674.56 483.4-15.381 19.775-98.877 177.98-43.945 83.496-74.707 114.26-41.748 41.748-120.85 46.143-123.05 6.5918-191.16-118.65-92.285 26.367-164.79 21.973-123.05-46.143-177.98-98.877-112.06-112.06-147.22-224.12-32.959-112.06-32.959-241.7 0-184.57 228.52-487.79 268.07-349.37 285.64-531.74 0-79.102 15.381-177.98 13.184-68.115 54.932-131.84 28.564-43.945 37.354-59.326 10.986-17.578 37.354-50.537 19.775-26.367 32.959-39.551 13.184-15.381 32.959-39.551 24.17-28.564 61.523-65.918-116.46-320.8-94.482-661.38 437.26 156.01 733.89 489.99 72.51-248.29 285.64-402.1 175.78 123.05 279.05 325.2z"/>\n <path d="m3654.1 3739.9q-2.1972 0 4.3946-120.85 6.5918-118.65 6.5918-257.08 2.1972-274.66 0-566.89-2.1973-294.43-79.102-586.67-74.707-281.25-164.79-479-90.088-199.95-195.56-344.97-158.2-237.3-430.66-402.1-272.46-164.79-569.09-215.33 19.775 107.67 17.578 210.94-4.3945 79.102-74.707 79.102-81.299 0-72.51-79.102 6.5918-290.04-206.54-496.58-166.99 175.78-180.18 408.69-4.3946 76.904-79.102 68.115-70.312-2.1973-70.312-81.299 0 0 4.3945-17.578-90.088 28.564-188.96 81.299-63.721 43.945-103.27-21.973-39.551-65.918 35.156-103.27 94.482-48.34 142.82-72.51-188.96-193.36-430.66-312.01 26.367 305.42 166.99 577.88 37.354 57.129-17.578 101.07-61.523 48.34-103.27-15.381-15.381-21.973-43.945-79.102-46.143 46.143-61.523 68.115-15.381 19.775-54.932 87.891-37.354 68.115-54.932 112.06-19.775 54.932-17.578 90.088 4.3945 32.959 6.5918 74.707-19.775 129.64-90.088 243.9-68.115 114.26-175.78 279.05-103.27 158.2-158.2 237.3-54.932 79.102-83.496 202.15-19.775 74.707 0 182.37 19.775 105.47 85.693 164.8 101.07 103.27 195.56 94.482 30.762 0 81.299-24.17 52.734-24.17 81.299-92.285 57.129-125.24 94.482-125.24 54.932 0 59.326 61.523 0 13.184-35.156 109.86-19.775 43.945-52.734 92.285-41.748 57.129-37.354 48.34 35.156 125.24 116.46 43.945 24.17-24.17 54.932-90.088t96.68-177.98q76.904-129.64 164.8-210.94 87.891-81.299 156.01-131.84 39.551-28.564 96.68-65.918t153.81-76.904q76.904-30.762 169.19-74.707 94.482-46.142 166.99-116.46 101.07-98.877 156.01-243.9 28.564-81.299 21.973-199.95-19.775-74.707 74.707-74.707 70.312 0 79.102 72.51 0 248.29-140.62 452.64 46.143 140.62 24.17 307.62-19.775 134.03-94.482 287.84-72.51 151.61-296.63 338.38-454.83 377.93-430.66 777.83 0 0 373.54 0 375.73 0 705.32 0z" fill="#fff"/>\n <path d="m674.71 2404q-63.721 39.551-76.904 105.47 2.1973 72.51-68.115 79.102-76.904 8.7891-79.102-65.918 8.7891-145.02 129.64-230.71 57.129-46.142 105.47 8.7891 48.34 59.326-10.986 103.27z"/>\n <path d="m1327.3 1355.9q28.564 43.945 21.973 92.285-21.973 140.62-156.01 118.65-39.551-6.5918-63.721-26.367-8.789 10.986-26.367 48.34-24.17 70.312-92.285 48.34-68.115-26.367-52.734-98.877 98.877-252.69 358.15-347.17 74.707-21.973 98.877 43.945 26.367 70.312-39.551 96.68-13.184 6.5918-24.17 13.184-10.986 4.3945-24.17 10.986z"/>\n</svg>',
|
|
113
|
+
"white-pawn": '<svg version="1.1" viewBox="0 0 4096 4096" xmlns="http://www.w3.org/2000/svg">\n <path d="m2049.1 3846.4h-1186.5q-87.891-219.73-87.891-459.23 0-406.49 230.71-729.49t593.26-461.43q-156.01-72.51-254.88-217.53-96.68-147.22-96.68-331.79 0-230.71 153.81-399.9t377.93-195.56q-177.98-134.03-177.98-353.76 0-184.57 129.64-316.41 131.84-131.84 318.6-131.84 184.57 0 316.41 131.84t131.84 316.41q0 219.73-177.98 353.76 224.12 26.367 377.93 195.56 153.81 169.19 153.81 399.9 0 184.57-101.07 331.79-98.877 145.02-252.69 217.53 362.55 138.43 593.26 461.43t230.71 729.49q0 237.3-85.693 459.23z"/>\n <path d="m2049.1 3697h1078.9q46.143-158.2 46.143-309.81 0-342.77-191.16-621.83-188.96-279.05-487.79-410.89-145.02-10.986-145.02-158.2 0-116.46 147.22-171.39 204.35-142.82 204.35-377.93 0-169.19-114.26-296.63t-276.86-147.22q-131.84-10.986-131.84-149.41 0-61.523 48.34-114.26 118.65-92.285 118.65-241.7 0-123.05-87.891-210.94-87.891-87.891-208.74-87.891-125.24 0-213.13 87.891-85.693 87.891-85.693 210.94 0 147.22 118.65 241.7 48.34 48.34 48.34 114.26 0 138.43-129.64 149.41-164.79 19.775-279.05 147.22-112.06 127.44-112.06 296.63 0 235.11 204.35 377.93 147.22 57.129 147.22 171.39 0 147.22-147.22 158.2-298.83 131.84-487.79 410.89t-188.96 621.83q0 162.6 46.143 309.81z" fill="#fff"/>\n</svg>',
|
|
114
|
+
"black-king": '<svg version="1.1" viewBox="0 0 4096 4096" xmlns="http://www.w3.org/2000/svg">\n <path d="m815.83 3151.1-72.51-410.89q-2.1973 0-6.5918-8.789-10.986-15.381-63.721-39.551-50.537-26.367-118.65-87.891-96.68-81.299-151.61-131.84-52.734-50.537-96.68-109.86-134.03-184.57-149.41-446.04-21.973-252.69 204.35-503.17 228.52-250.49 617.43-235.11 145.02 8.789 340.58 70.312 63.721 26.367 129.64 52.734 68.115 24.17 134.03 50.537 35.156 17.578 61.523 35.156-10.986-46.143-10.986-92.285 0-171.39 120.85-292.24 123.05-120.85 294.43-123.05 171.39 0 292.24 123.05 120.85 120.85 120.85 290.04 0 35.156-8.789 92.285 30.762-19.775 59.326-32.959 101.07-43.945 265.87-103.27 188.96-63.721 340.58-72.51 388.92-17.578 615.23 235.11 221.92 250.49 206.54 503.17-17.578 261.47-151.61 446.04-43.945 59.326-98.877 112.06-54.932 50.537-147.22 129.64-72.51 61.523-123.05 87.891-50.537 24.17-59.326 39.551-2.1973 4.3945-4.3946 6.5918-2.1972 2.1973-2.1972 4.3945l-70.312 413.09 145.02 542.72q-109.86 98.877-492.19 162.6t-883.3 63.721q-509.77 0-896.48-68.115-386.72-65.918-485.6-166.99z"/>\n <path d="m2048.5 2015.1q15.381-61.524 26.367-85.693 21.973-85.693 50.537-145.02 13.184-37.354 37.354-85.693 26.367-50.537 54.932-114.26 17.578-37.354 37.354-90.088 19.775-54.932 39.551-107.67 17.578-43.945 17.578-94.482 0-107.67-76.904-182.37-76.904-76.904-186.77-76.904-261.47 0-261.47 261.47 0 50.537 17.578 94.482 48.34 142.82 74.707 197.75 28.564 63.721 52.734 114.26 24.17 48.34 41.748 85.693 28.564 72.51 48.34 145.02 4.3945 13.184 26.367 83.496z" fill="#fff"/>\n <path d="m2048.5 1639.3q-4.3945-21.973-10.986-37.354-13.184-43.945-21.973-63.721-6.5918-15.381-17.578-37.354-10.986-24.17-21.973-50.537-6.5918-15.381-17.578-39.551-8.7891-26.367-15.381-48.34-6.5918-19.775-6.5918-41.748 0-116.46 112.06-116.46 116.46 0 116.46 114.26 0 28.564-8.7891 41.748-30.762 83.496-32.959 90.088-32.959 65.918-41.748 85.693-15.381 35.156-19.775 63.721-6.5918 13.184-8.7891 24.17-2.1972 8.7891-4.3945 15.381z"/>\n <path d="m1969.4 2566.6q0-87.891-4.3945-241.7-4.3945-156.01-32.959-259.28-90.088-294.43-272.46-474.61-94.482-92.285-290.04-171.39-224.12-87.891-424.07-87.891-347.17 0-514.16 248.29-94.482 131.84-94.482 329.59 0 215.33 105.47 353.76 54.932 79.102 210.94 195.56 156.01 116.46 263.67 215.33 191.16-41.748 430.66-72.51 241.7-30.762 621.83-35.156z" fill="#fff"/>\n <path d="m1802.4 2397.4q-274.66 4.3945-503.17 28.564-226.32 24.17-351.56 68.115-65.918-81.299-153.81-162.6-85.693-83.496-151.61-156.01-109.86-112.06-109.86-246.09 0-164.79 54.932-241.7 59.326-87.891 182.37-129.64 123.05-43.945 248.29-43.945 158.2 0 303.22 70.312 142.82 74.707 188.96 118.65 149.41 151.61 232.91 329.59 28.564 65.918 41.748 184.57 15.381 116.46 17.578 180.18z"/>\n <path d="m2125.4 872.49h-156.01v-287.84h-182.37q-74.707 0-74.707-72.51v-2.1973q0-72.51 74.707-72.51h182.37v-186.77q0-76.904 79.102-76.904 76.904 0 76.904 76.904v186.77h188.96q72.51 0 72.51 72.51v2.1973q0 72.51-72.51 72.51l-186.77 2.1973z"/>\n <path d="m3191 3605.9-65.918-259.28q-428.47-98.877-1076.7-98.877-641.6 0-1072.3 98.877l-70.312 261.47q417.48-127.44 1144.8-127.44 349.37 0 648.19 35.156 298.83 35.156 492.19 90.088z" fill="#fff"/>\n <path d="m3133.9 2948.9q-404.3-112.06-1076.7-112.06-676.76 0-1089.8 114.26l32.959 221.92q415.28-107.67 1056.9-107.67 639.4 0 1041.5 105.47z" fill="#fff"/>\n <path d="m2127.6 2568.8q377.93 6.5918 619.63 37.354 241.7 30.762 435.06 72.51 120.85-118.65 268.07-226.32t206.54-184.57q105.47-142.82 105.47-355.96 0-195.56-94.482-327.39-169.19-248.29-516.36-248.29-202.15 0-421.88 87.891-199.95 79.102-290.04 171.39-186.77 180.18-272.46 474.61-32.959 101.07-37.354 257.08-2.1972 156.01-2.1972 241.7z" fill="#fff"/>\n <path d="m2288 2397.4q0-63.721 13.184-180.18 15.381-118.65 46.143-184.57 81.299-177.98 232.91-329.59 43.945-43.945 188.96-118.65 142.82-70.312 305.42-70.312 123.05 0 243.9 43.945 123.05 41.748 184.57 129.64 54.932 74.707 54.932 241.7 0 131.84-107.67 246.09-70.312 72.51-151.61 147.22-81.299 72.51-156.01 171.39-127.44-43.945-355.96-68.115-226.32-24.17-498.78-28.564z"/>\n</svg>',
|
|
115
|
+
"black-queen": '<svg version="1.1" viewBox="0 0 4096 4096" xmlns="http://www.w3.org/2000/svg">\n <path d="m2045.9 767.01q-125.24 0-213.13-87.891-85.693-87.891-85.693-213.13 0-123.05 85.693-210.94 87.891-87.891 213.13-87.891 123.05 0 210.94 87.891 90.088 87.891 90.088 210.94 0 125.24-90.088 213.13-87.891 87.891-210.94 87.891z"/>\n <path d="m3399.4 3706.9q-107.67 94.482-483.4 158.2t-865.72 63.721q-498.78 0-876.71-65.918t-476.81-164.8l138.43-527.34-61.523-344.97-193.36-336.18-186.77-1366.7 107.67-41.748 602.05 1015.1 13.184-1208.5 149.41-26.367 459.23 1215.1 246.09-1307.4h151.61l246.09 1303 454.83-1210.7 151.61 26.367 13.184 1208.5 604.25-1017.3 103.27 48.34-182.37 1360.1-195.56 336.18-61.523 349.37z"/>\n <path d="m1123 876.8q-125.24 0-213.13-85.693-87.891-87.891-87.891-213.13 0-123.05 87.891-210.94 87.891-87.891 213.13-87.891 123.05 0 210.94 87.891 87.891 87.891 87.891 210.94 0 125.24-87.891 213.13-87.891 85.693-210.94 85.693z"/>\n <path d="m2968.7 876.8q-125.24 0-213.13-85.693-85.693-87.891-85.693-213.13 0-123.05 85.693-210.94 87.891-87.891 213.13-87.891 125.24 0 213.13 87.891 87.891 87.891 87.891 210.94 0 125.24-87.891 213.13-87.891 85.693-213.13 85.693z"/>\n <path d="m314.38 1118.5q-125.24 0-213.13-85.693-85.693-87.891-85.693-213.13 0-123.05 85.693-210.94 87.891-90.088 213.13-90.088t213.13 90.088q87.891 87.891 87.891 210.94 0 125.24-87.891 213.13-87.891 85.693-213.13 85.693z"/>\n <path d="m3781.7 1118.5q-125.24 0-213.13-85.693-87.891-87.891-87.891-213.13 0-123.05 87.891-210.94 87.891-90.088 213.13-90.088 123.05 0 210.94 90.088 87.891 87.891 87.891 210.94 0 125.24-87.891 213.13-87.891 85.693-210.94 85.693z"/>\n <path d="m3131.3 2979.6q-404.3-112.06-1076.7-112.06-676.76 0-1089.8 114.26l32.959 221.92q415.28-107.67 1056.9-107.67 639.4 0 1041.5 105.47z" fill="#fff"/>\n <path d="m3188.4 3636.6-65.918-259.28q-428.47-98.877-1076.7-98.877-641.6 0-1072.3 98.877l-70.312 261.47q417.48-127.44 1144.8-127.44 349.37 0 648.19 35.156 298.83 35.156 492.19 90.088z" fill="#fff"/>\n <path d="m3285.1 2586.3q-182.37-65.918-514.16-107.67-329.59-43.945-729.49-43.945-391.11 0-716.31 41.748-325.2 39.551-511.96 105.47l109.86 199.95q184.57-54.932 479-79.102t643.8-24.17 646 24.17 481.2 81.299z" fill="#fff"/>\n</svg>',
|
|
116
|
+
"black-rook": '<svg version="1.1" viewBox="0 0 4096 4096" xmlns="http://www.w3.org/2000/svg">\n <path d="m2350.1 549.46h373.54v-301.03h602.05v823.97l-487.79 375.73v1050.3l373.54 373.54v450.44h336.18v525.15h-2999.3v-525.15h336.18v-450.44l375.73-373.54v-1050.3l-487.79-375.73v-823.97h599.85v301.03h375.73v-301.03h602.05z"/>\n <path d="m2049 2836.8h-909.67l-101.07 94.482v127.44h2021.5v-127.44l-101.07-94.482z" fill="#fff"/>\n <path d="m2049 2458.9h-637.21v101.07l-131.84 127.44h1538.1l-131.84-127.44v-101.07z" fill="#fff"/>\n <path d="m2049 1259.2h-769.04l131.84 103.27v125.24h1274.4v-125.24l131.84-103.27z" fill="#fff"/>\n <path d="m2049 887.86h-1125v101.07l160.4 120.85h1931.4l156.01-120.85v-101.07z" fill="#fff"/>\n <path d="m1038.3 3287.3v224.12h2021.5v-224.12z" fill="#fff"/>\n</svg>',
|
|
117
|
+
"black-bishop": '<svg version="1.1" viewBox="0 0 4096 4096" xmlns="http://www.w3.org/2000/svg">\n <path d="m2048 3456.3q-30.762 125.24-74.707 173.58t-116.46 101.07q-79.102 54.932-186.77 92.285-107.67 39.551-239.5 19.775l-617.43-85.693q-37.354-4.3945-68.115 0-28.564 4.3946-54.932 4.3946-46.143 0-118.65 19.775-70.312 21.973-109.86 61.523l-213.13-349.37q39.551-43.945 70.312-61.524t72.51-37.354q127.44-59.326 272.46-72.51 61.523-4.3945 120.85-2.1972 59.326 2.1972 123.05-4.3946 118.65 19.775 237.3 37.354 120.85 15.381 241.7 32.959 131.84 0 177.98-26.367 24.17-13.184 76.904-48.34t105.47-103.27q-116.46-13.184-237.3-43.945-120.85-32.959-213.13-68.115l228.52-566.89q-171.39-98.877-239.5-158.2-68.115-61.523-107.67-140.62-57.129-101.07-74.707-195.56-15.381-94.482-13.184-169.19 2.1973-131.84 61.523-290.04 61.524-160.4 228.52-285.64 138.43-105.47 270.26-217.53 131.84-112.06 261.47-261.47-162.6-83.496-162.6-265.87 0-123.05 85.693-210.94 87.891-87.891 213.13-87.891 123.05 0 210.94 87.891 87.891 87.891 87.891 210.94 0 180.18-162.6 265.87 127.44 149.41 257.08 261.47 131.84 112.06 274.66 217.53 164.79 125.24 224.12 285.64 59.326 158.2 63.721 290.04 0 74.707-15.381 169.19-15.381 94.482-70.312 195.56-43.945 79.102-112.06 140.62-65.918 59.326-235.11 158.2l228.52 566.89q-96.68 35.156-217.53 68.115-120.85 30.762-232.91 43.945 50.537 68.115 103.27 103.27 52.734 35.156 79.102 48.34 46.143 26.367 177.98 26.367 118.65-17.578 237.3-32.959 120.85-17.578 241.7-37.354 59.326 6.5918 118.65 4.3946 61.523-2.1973 125.24 2.1972 140.62 13.184 272.46 72.51 39.551 19.775 70.312 37.354 32.959 17.578 72.51 61.524l-215.33 349.37q-39.551-39.551-112.06-61.523-70.312-19.775-114.26-19.775-28.564 0-59.326-4.3946-28.564-4.3945-65.918 0l-615.23 85.693q-131.84 19.775-246.09-17.578-112.06-37.354-184.57-98.877-72.51-59.326-116.46-103.27-41.748-41.748-70.312-166.99z"/>\n <path d="m1966.7 1821.5v186.77q0 81.299 81.299 81.299t81.299-81.299v-188.96h197.75q76.904 0 76.904-79.102t-76.904-79.102h-197.75v-197.75q0-81.299-81.299-81.299t-81.299 81.299v197.75h-193.36q-76.904 0-76.904 79.102t76.904 79.102z" fill="#fff"/>\n <path d="m1918.4 3416.7q50.537-107.67 50.537-208.74h-70.312q-85.693 140.62-177.98 208.74z" fill="#fff"/>\n <path d="m2371 3416.7q-87.891-65.918-175.78-208.74h-70.312q0 107.67 50.537 208.74z" fill="#fff"/>\n <path d="m2447.9 2586.2-63.721-153.81v-59.326q-166.99-24.17-336.18-24.17-164.79 0-333.98 24.17l-2.1972 59.326-59.326 153.81q186.77-32.959 395.51-32.959 210.94 0 399.9 32.959z" fill="#fff"/>\n <path d="m2632.5 3038.8-92.285-224.12q-224.12-48.34-492.19-48.34-265.87 0-487.79 48.34l-92.285 221.92q272.46-68.115 580.08-68.115 303.22 0 584.47 70.312z" fill="#fff"/>\n</svg>',
|
|
118
|
+
"black-knight": '<svg version="1.1" viewBox="0 0 4096 4096" xmlns="http://www.w3.org/2000/svg">\n <path d="m2166.7 613.11q344.97 21.973 639.4 177.98 294.43 156.01 500.98 399.9 145.02 171.39 272.46 413.09 129.64 241.7 206.54 511.96 87.891 314.21 109.86 661.38 24.17 344.97 24.17 639.4v479t-342.77 0q-340.58 0-885.5 0h-1474.4q-19.775 0-19.775-107.67 2.1972-107.67 15.381-173.58 8.7891-52.734 41.748-149.41t109.86-235.11q35.156-70.312 166.99-204.35 131.84-136.23 303.22-314.21 98.877-101.07 153.81-254.88 57.129-153.81 48.34-279.05-81.299 65.918-177.98 107.67-465.82 166.99-674.56 483.4-15.381 19.775-98.877 177.98-43.945 83.496-74.707 114.26-41.748 41.748-120.85 46.143-123.05 6.5918-191.16-118.65-92.285 26.367-164.79 21.973-123.05-46.143-177.98-98.877-112.06-112.06-147.22-224.12-32.959-112.06-32.959-241.7 0-184.57 228.52-487.79 268.07-349.37 285.64-531.74 0-79.102 15.381-177.98 13.184-68.115 54.932-131.84 28.564-43.945 37.354-59.326 10.986-17.578 37.354-50.537 19.775-26.367 32.959-39.551 13.184-15.381 32.959-39.551 24.17-28.564 61.523-65.918-116.46-320.8-94.482-661.38 437.26 156.01 733.89 489.99 72.51-248.29 285.64-402.1 175.78 123.05 279.05 325.2z"/>\n <path d="m1237.2 1355.8q48.34-24.17 48.34-24.17 65.918-26.367 41.748-96.68-26.367-65.918-101.07-43.945-259.28 94.482-358.15 347.17-15.381 72.51 52.734 98.877 68.115 21.973 92.285-48.34 17.578-37.354 26.367-48.34 24.17 19.775 63.721 26.367 134.03 21.973 156.01-118.65 6.5918-48.34-21.973-92.285z" fill="#fff"/>\n <path d="m683.47 2450q63.721-43.945 13.184-105.47-52.734-50.537-116.46-8.789-134.03 87.891-142.82 230.71 2.1973 72.51 85.693 68.115 79.102-6.5918 76.904-81.299 17.578-70.312 83.496-103.27z" fill="#fff"/>\n <path d="m3654.2 3739.8q-2.1972 0 4.3946-120.85 6.5918-118.65 6.5918-257.08 2.1972-274.66 0-566.89-2.1973-294.43-79.102-586.67-74.707-281.25-164.79-479-90.088-199.95-195.56-344.97-158.2-237.3-430.66-402.1-272.46-164.79-569.09-215.33 8.789 50.537 4.3945 103.27-2.1973 52.734 2.1973 101.07 213.13 72.51 402.1 180.18 188.96 107.67 276.86 232.91 105.47 145.02 195.56 344.97 90.088 197.75 164.79 479 74.707 292.24 76.904 586.67 2.1973 292.24 2.1973 566.89 0 138.43-6.5918 257.08-6.5918 120.85 0 120.85z" fill="#fff"/>\n <path d="m1595.4 953.71q-10.986-79.102 4.3946-171.39-131.84 26.367-248.29 123.05-70.312 37.353-32.959 103.27 37.354 68.115 103.27 21.973 46.142-24.17 83.496-43.945 39.551-21.973 90.088-32.959z" fill="#fff"/>\n <path d="m2168.9 2026q153.81-202.15 151.61-450.44-8.7891-72.51-83.496-72.51-101.07 0-79.102 74.707 6.5918 120.85-24.17 199.95-50.537 125.24-112.06 186.77-32.959 65.918 39.551 96.68 70.312 32.959 107.67-35.156z" fill="#fff"/>\n <path d="m872.46 2841.2q8.789-19.775 28.564-59.326 37.354-92.285 37.354-109.86-4.3945-61.523-63.721-61.523-43.945 0-103.27 125.24-8.7891 17.578-26.367 30.762-59.326 61.524 17.578 103.27 70.312 41.748 109.86-28.564z" fill="#fff"/>\n</svg>',
|
|
119
|
+
"black-pawn": '<svg version="1.1" viewBox="0 0 4096 4096" xmlns="http://www.w3.org/2000/svg">\n <path d="m2049.1 3846.5h-1186.5q-87.891-219.73-87.891-459.23 0-406.49 230.71-729.49 230.71-323 593.26-461.43-156.01-72.51-254.88-217.53-96.68-147.22-96.68-331.79 0-230.71 153.81-399.9 153.81-169.19 377.93-195.56-177.98-134.03-177.98-353.76 0-184.57 129.64-316.41 131.84-131.84 318.6-131.84 184.57 0 316.41 131.84 131.84 131.84 131.84 316.41 0 219.73-177.98 353.76 224.12 26.367 377.93 195.56 153.81 169.19 153.81 399.9 0 184.57-101.07 331.79-98.877 145.02-252.69 217.53 362.55 138.43 593.26 461.43 230.71 323 230.71 729.49 0 237.3-85.693 459.23z" dominant-baseline="central" aria-label="\u265F"/>\n</svg>'
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// src/assets.ts
|
|
123
|
+
var defaultPieceTheme = (piece) => {
|
|
124
|
+
return PIECE_SVGS[`${piece.color}-${piece.type}`] ?? "";
|
|
125
|
+
};
|
|
126
|
+
var defaultBoardTheme = {
|
|
127
|
+
lightSquare: "#f0d9b5",
|
|
128
|
+
darkSquare: "#b58863"
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// src/styles.ts
|
|
132
|
+
function injectStyles() {
|
|
133
|
+
if (typeof document === "undefined") return;
|
|
134
|
+
if (document.getElementById("cb-styles")) return;
|
|
135
|
+
const el = document.createElement("style");
|
|
136
|
+
el.id = "cb-styles";
|
|
137
|
+
el.textContent = STYLES;
|
|
138
|
+
document.head.appendChild(el);
|
|
139
|
+
}
|
|
140
|
+
var STYLES = (
|
|
141
|
+
/* css */
|
|
142
|
+
`
|
|
143
|
+
.cb-board {
|
|
144
|
+
position: relative;
|
|
145
|
+
display: grid;
|
|
146
|
+
grid-template-columns: repeat(8, 1fr);
|
|
147
|
+
grid-template-rows: repeat(8, 1fr);
|
|
148
|
+
aspect-ratio: 1 / 1;
|
|
149
|
+
width: 100%;
|
|
150
|
+
contain: layout style paint;
|
|
151
|
+
user-select: none;
|
|
152
|
+
-webkit-user-select: none;
|
|
153
|
+
touch-action: none;
|
|
154
|
+
-webkit-touch-callout: none;
|
|
155
|
+
box-sizing: border-box;
|
|
156
|
+
overflow: hidden;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* Squares */
|
|
160
|
+
.cb-square {
|
|
161
|
+
position: relative;
|
|
162
|
+
width: 100%;
|
|
163
|
+
height: 100%;
|
|
164
|
+
box-sizing: border-box;
|
|
165
|
+
}
|
|
166
|
+
.cb-square.cb-light { background: var(--cb-light-sq); }
|
|
167
|
+
.cb-square.cb-dark { background: var(--cb-dark-sq); }
|
|
168
|
+
|
|
169
|
+
/* Highlight: last move */
|
|
170
|
+
.cb-square.cb-hl-lastmove.cb-light { background: var(--cb-hl-lm-light, #cdd16a); }
|
|
171
|
+
.cb-square.cb-hl-lastmove.cb-dark { background: var(--cb-hl-lm-dark, #aaaa23); }
|
|
172
|
+
|
|
173
|
+
/* Highlight: selected */
|
|
174
|
+
.cb-square.cb-hl-selected.cb-light { background: var(--cb-hl-sel-light, #7fc97f); }
|
|
175
|
+
.cb-square.cb-hl-selected.cb-dark { background: var(--cb-hl-sel-dark, #5aad5a); }
|
|
176
|
+
|
|
177
|
+
/* Highlight: check */
|
|
178
|
+
.cb-square.cb-hl-check {
|
|
179
|
+
background: radial-gradient(
|
|
180
|
+
ellipse at center,
|
|
181
|
+
rgba(255,0,0,0.6) 0%,
|
|
182
|
+
rgba(255,0,0,0.3) 40%,
|
|
183
|
+
rgba(255,0,0,0) 70%
|
|
184
|
+
) !important;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/* Legal move indicators: dot on empty squares */
|
|
188
|
+
.cb-square.cb-legal::after {
|
|
189
|
+
content: '';
|
|
190
|
+
position: absolute;
|
|
191
|
+
top: 50%;
|
|
192
|
+
left: 50%;
|
|
193
|
+
transform: translate(-50%, -50%);
|
|
194
|
+
width: 28%;
|
|
195
|
+
height: 28%;
|
|
196
|
+
border-radius: 50%;
|
|
197
|
+
background: rgba(0, 0, 0, 0.14);
|
|
198
|
+
pointer-events: none;
|
|
199
|
+
z-index: 1;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* Legal move indicators: ring on capture squares */
|
|
203
|
+
.cb-square.cb-legal.cb-has-piece::after {
|
|
204
|
+
width: 100%;
|
|
205
|
+
height: 100%;
|
|
206
|
+
border-radius: 0;
|
|
207
|
+
background: radial-gradient(transparent 48%, rgba(0,0,0,0.12) 52%);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/* Pieces \u2014 smaller than cell so they don't touch edges (padding via size) */
|
|
211
|
+
.cb-piece {
|
|
212
|
+
position: absolute;
|
|
213
|
+
width: 12.5%;
|
|
214
|
+
height: 12.5%;
|
|
215
|
+
top: 0;
|
|
216
|
+
left: 0;
|
|
217
|
+
z-index: 2;
|
|
218
|
+
pointer-events: none;
|
|
219
|
+
will-change: transform;
|
|
220
|
+
display: flex;
|
|
221
|
+
align-items: center;
|
|
222
|
+
justify-content: center;
|
|
223
|
+
}
|
|
224
|
+
.cb-piece.cb-animating {
|
|
225
|
+
transition: transform var(--cb-anim-duration, 150ms) ease-out;
|
|
226
|
+
}
|
|
227
|
+
.cb-piece.cb-dragging {
|
|
228
|
+
z-index: 10;
|
|
229
|
+
cursor: grabbing;
|
|
230
|
+
transition: none !important;
|
|
231
|
+
}
|
|
232
|
+
.cb-piece img,
|
|
233
|
+
.cb-piece svg {
|
|
234
|
+
width: var(--cb-piece-size, 85%);
|
|
235
|
+
height: var(--cb-piece-size, 85%);
|
|
236
|
+
object-fit: contain;
|
|
237
|
+
display: block;
|
|
238
|
+
pointer-events: none;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* Coordinates */
|
|
242
|
+
.cb-coord {
|
|
243
|
+
position: absolute;
|
|
244
|
+
font-size: 0.7em;
|
|
245
|
+
font-family: system-ui, sans-serif;
|
|
246
|
+
font-weight: 700;
|
|
247
|
+
pointer-events: none;
|
|
248
|
+
z-index: 1;
|
|
249
|
+
line-height: 1;
|
|
250
|
+
}
|
|
251
|
+
.cb-coord-file { right: 2px; bottom: 1px; }
|
|
252
|
+
.cb-coord-rank { left: 2px; top: 1px; }
|
|
253
|
+
.cb-coord.cb-on-light { color: var(--cb-dark-sq); }
|
|
254
|
+
.cb-coord.cb-on-dark { color: var(--cb-light-sq); }
|
|
255
|
+
|
|
256
|
+
/* SVG overlay for arrows */
|
|
257
|
+
.cb-svg {
|
|
258
|
+
position: absolute;
|
|
259
|
+
inset: 0;
|
|
260
|
+
width: 100%;
|
|
261
|
+
height: 100%;
|
|
262
|
+
z-index: 3;
|
|
263
|
+
pointer-events: none;
|
|
264
|
+
overflow: visible;
|
|
265
|
+
}
|
|
266
|
+
`
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
// src/dom.ts
|
|
270
|
+
function createBoardDOM(orientation, theme, showCoords) {
|
|
271
|
+
const boardEl = document.createElement("div");
|
|
272
|
+
boardEl.className = "cb-board";
|
|
273
|
+
boardEl.style.setProperty("--cb-light-sq", theme.lightSquare);
|
|
274
|
+
boardEl.style.setProperty("--cb-dark-sq", theme.darkSquare);
|
|
275
|
+
const squareEls = /* @__PURE__ */ new Map();
|
|
276
|
+
for (let row = 0; row < 8; row++) {
|
|
277
|
+
for (let col = 0; col < 8; col++) {
|
|
278
|
+
const sq = coordsToSquare(col, row, orientation);
|
|
279
|
+
const light = isLightSquare(sq);
|
|
280
|
+
const div = document.createElement("div");
|
|
281
|
+
div.className = `cb-square ${light ? "cb-light" : "cb-dark"}`;
|
|
282
|
+
div.setAttribute("data-square", sq);
|
|
283
|
+
if (showCoords) {
|
|
284
|
+
appendCoords(div, sq, row, col, light);
|
|
285
|
+
}
|
|
286
|
+
boardEl.appendChild(div);
|
|
287
|
+
squareEls.set(sq, div);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
const svgEl = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
291
|
+
svgEl.setAttribute("class", "cb-svg");
|
|
292
|
+
svgEl.setAttribute("viewBox", "0 0 100 100");
|
|
293
|
+
boardEl.appendChild(svgEl);
|
|
294
|
+
return { boardEl, squareEls, svgEl };
|
|
295
|
+
}
|
|
296
|
+
function rebuildSquares(boardEl, squareEls, orientation, theme, showCoords) {
|
|
297
|
+
for (const el of squareEls.values()) {
|
|
298
|
+
el.remove();
|
|
299
|
+
}
|
|
300
|
+
squareEls.clear();
|
|
301
|
+
boardEl.style.setProperty("--cb-light-sq", theme.lightSquare);
|
|
302
|
+
boardEl.style.setProperty("--cb-dark-sq", theme.darkSquare);
|
|
303
|
+
const svgEl = boardEl.querySelector(".cb-svg");
|
|
304
|
+
for (let row = 0; row < 8; row++) {
|
|
305
|
+
for (let col = 0; col < 8; col++) {
|
|
306
|
+
const sq = coordsToSquare(col, row, orientation);
|
|
307
|
+
const light = isLightSquare(sq);
|
|
308
|
+
const div = document.createElement("div");
|
|
309
|
+
div.className = `cb-square ${light ? "cb-light" : "cb-dark"}`;
|
|
310
|
+
div.setAttribute("data-square", sq);
|
|
311
|
+
if (showCoords) {
|
|
312
|
+
appendCoords(div, sq, row, col, light);
|
|
313
|
+
}
|
|
314
|
+
if (svgEl) {
|
|
315
|
+
boardEl.insertBefore(div, svgEl);
|
|
316
|
+
} else {
|
|
317
|
+
boardEl.appendChild(div);
|
|
318
|
+
}
|
|
319
|
+
squareEls.set(sq, div);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function createPieceEl(sq, piece, orientation, pieceTheme) {
|
|
324
|
+
const [col, row] = squareToCoords(sq, orientation);
|
|
325
|
+
const el = document.createElement("div");
|
|
326
|
+
el.className = "cb-piece";
|
|
327
|
+
el.setAttribute("data-square", sq);
|
|
328
|
+
el.setAttribute("aria-label", `${piece.color} ${piece.type}`);
|
|
329
|
+
el.style.transform = `translate(${col * 100}%, ${row * 100}%)`;
|
|
330
|
+
const content = pieceTheme(piece);
|
|
331
|
+
if (content.trimStart().startsWith("<")) {
|
|
332
|
+
el.innerHTML = content;
|
|
333
|
+
} else {
|
|
334
|
+
const img = document.createElement("img");
|
|
335
|
+
img.src = content;
|
|
336
|
+
img.alt = `${piece.color} ${piece.type}`;
|
|
337
|
+
img.draggable = false;
|
|
338
|
+
el.appendChild(img);
|
|
339
|
+
}
|
|
340
|
+
return el;
|
|
341
|
+
}
|
|
342
|
+
function appendCoords(div, sq, row, col, light) {
|
|
343
|
+
const colorCls = light ? "cb-on-light" : "cb-on-dark";
|
|
344
|
+
if (row === 7) {
|
|
345
|
+
const span = document.createElement("span");
|
|
346
|
+
span.className = `cb-coord cb-coord-file ${colorCls}`;
|
|
347
|
+
span.textContent = sq.charAt(0);
|
|
348
|
+
div.appendChild(span);
|
|
349
|
+
}
|
|
350
|
+
if (col === 0) {
|
|
351
|
+
const span = document.createElement("span");
|
|
352
|
+
span.className = `cb-coord cb-coord-rank ${colorCls}`;
|
|
353
|
+
span.textContent = sq.charAt(1);
|
|
354
|
+
div.appendChild(span);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/diff.ts
|
|
359
|
+
function samePiece(a, b) {
|
|
360
|
+
return a.color === b.color && a.type === b.type;
|
|
361
|
+
}
|
|
362
|
+
function diffPieces(oldPieces, newPieces) {
|
|
363
|
+
const disappeared = [];
|
|
364
|
+
const appeared = [];
|
|
365
|
+
for (const [sq, piece] of oldPieces) {
|
|
366
|
+
const np = newPieces.get(sq);
|
|
367
|
+
if (!np || !samePiece(piece, np)) {
|
|
368
|
+
disappeared.push({ square: sq, piece });
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
for (const [sq, piece] of newPieces) {
|
|
372
|
+
const op = oldPieces.get(sq);
|
|
373
|
+
if (!op || !samePiece(op, piece)) {
|
|
374
|
+
appeared.push({ square: sq, piece });
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
const moved = [];
|
|
378
|
+
const usedD = /* @__PURE__ */ new Set();
|
|
379
|
+
const usedA = /* @__PURE__ */ new Set();
|
|
380
|
+
for (let a = 0; a < appeared.length; a++) {
|
|
381
|
+
if (usedA.has(a)) continue;
|
|
382
|
+
const ap = appeared[a];
|
|
383
|
+
for (let d = 0; d < disappeared.length; d++) {
|
|
384
|
+
if (usedD.has(d)) continue;
|
|
385
|
+
const dp = disappeared[d];
|
|
386
|
+
if (samePiece(dp.piece, ap.piece)) {
|
|
387
|
+
moved.push({ from: dp.square, to: ap.square, piece: ap.piece });
|
|
388
|
+
usedD.add(d);
|
|
389
|
+
usedA.add(a);
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
const removed = disappeared.filter((_, i) => !usedD.has(i)).map((d) => d.square);
|
|
395
|
+
const added = appeared.filter((_, i) => !usedA.has(i));
|
|
396
|
+
return { moved, added, removed };
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// src/arrows.ts
|
|
400
|
+
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
401
|
+
var DEFAULT_COLOR = "rgba(0, 180, 50, 0.8)";
|
|
402
|
+
function squareCenter(sq, orientation) {
|
|
403
|
+
const [col, row] = squareToCoords(sq, orientation);
|
|
404
|
+
return [(col + 0.5) * 12.5, (row + 0.5) * 12.5];
|
|
405
|
+
}
|
|
406
|
+
function createArrowEl(arrow, orientation) {
|
|
407
|
+
const color = arrow.color ?? DEFAULT_COLOR;
|
|
408
|
+
const [x1, y1] = squareCenter(arrow.from, orientation);
|
|
409
|
+
const [x2, y2] = squareCenter(arrow.to, orientation);
|
|
410
|
+
const dx = x2 - x1;
|
|
411
|
+
const dy = y2 - y1;
|
|
412
|
+
const len = Math.sqrt(dx * dx + dy * dy);
|
|
413
|
+
const nx = dx / len;
|
|
414
|
+
const ny = dy / len;
|
|
415
|
+
const headLen = 3.5;
|
|
416
|
+
const headW = 2.8;
|
|
417
|
+
const endX = x2 - nx * headLen;
|
|
418
|
+
const endY = y2 - ny * headLen;
|
|
419
|
+
const g = document.createElementNS(SVG_NS, "g");
|
|
420
|
+
g.setAttribute("data-arrow", `${arrow.from}-${arrow.to}`);
|
|
421
|
+
const line = document.createElementNS(SVG_NS, "line");
|
|
422
|
+
line.setAttribute("x1", String(x1));
|
|
423
|
+
line.setAttribute("y1", String(y1));
|
|
424
|
+
line.setAttribute("x2", String(endX));
|
|
425
|
+
line.setAttribute("y2", String(endY));
|
|
426
|
+
line.setAttribute("stroke", color);
|
|
427
|
+
line.setAttribute("stroke-width", "2.4");
|
|
428
|
+
line.setAttribute("stroke-linecap", "round");
|
|
429
|
+
line.setAttribute("opacity", "0.85");
|
|
430
|
+
const head = document.createElementNS(SVG_NS, "polygon");
|
|
431
|
+
head.setAttribute(
|
|
432
|
+
"points",
|
|
433
|
+
`${x2},${y2} ${endX - ny * headW},${endY + nx * headW} ${endX + ny * headW},${endY - nx * headW}`
|
|
434
|
+
);
|
|
435
|
+
head.setAttribute("fill", color);
|
|
436
|
+
head.setAttribute("opacity", "0.85");
|
|
437
|
+
g.appendChild(line);
|
|
438
|
+
g.appendChild(head);
|
|
439
|
+
return g;
|
|
440
|
+
}
|
|
441
|
+
function renderArrows(svgEl, arrows, orientation) {
|
|
442
|
+
svgEl.replaceChildren();
|
|
443
|
+
for (const arrow of arrows) {
|
|
444
|
+
svgEl.appendChild(createArrowEl(arrow, orientation));
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// src/board.ts
|
|
449
|
+
var ChessBoard = class {
|
|
450
|
+
// ────────────────────────────────────────────────────────────────────
|
|
451
|
+
// Constructor
|
|
452
|
+
// ────────────────────────────────────────────────────────────────────
|
|
453
|
+
constructor(container, options) {
|
|
454
|
+
this.pieceEls = /* @__PURE__ */ new Map();
|
|
455
|
+
this.selected = null;
|
|
456
|
+
this.lastMoveSquares = null;
|
|
457
|
+
this.checkSq = null;
|
|
458
|
+
this.legalSqs = /* @__PURE__ */ new Set();
|
|
459
|
+
this.arrowList = [];
|
|
460
|
+
// ── Interaction ──────────────────────────────────────────────────────
|
|
461
|
+
this.dragState = null;
|
|
462
|
+
this.arrowDragOrigin = null;
|
|
463
|
+
this.pendingClick = null;
|
|
464
|
+
this.destroyed = false;
|
|
465
|
+
// ────────────────────────────────────────────────────────────────────
|
|
466
|
+
// Event handlers (arrow-function fields for stable `this`)
|
|
467
|
+
// ────────────────────────────────────────────────────────────────────
|
|
468
|
+
this.handlePointerDown = (e) => {
|
|
469
|
+
if (this.destroyed) return;
|
|
470
|
+
if (e.button === 2) {
|
|
471
|
+
e.preventDefault();
|
|
472
|
+
const sq2 = this.squareFromPointer(e);
|
|
473
|
+
if (sq2) {
|
|
474
|
+
this.arrowDragOrigin = sq2;
|
|
475
|
+
this.boardEl.setPointerCapture(e.pointerId);
|
|
476
|
+
}
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (e.button !== 0 || this.viewOnly) return;
|
|
480
|
+
const sq = this.squareFromPointer(e);
|
|
481
|
+
if (!sq) return;
|
|
482
|
+
if (this.arrowList.length > 0) {
|
|
483
|
+
this.clearArrows();
|
|
484
|
+
}
|
|
485
|
+
if (this.selected && sq !== this.selected && this.legalSqs.has(sq)) {
|
|
486
|
+
const result = this.onMoveCallback?.(this.selected, sq);
|
|
487
|
+
if (result === false) {
|
|
488
|
+
this.doDeselect();
|
|
489
|
+
} else {
|
|
490
|
+
this.applyMove(this.selected, sq);
|
|
491
|
+
this.doDeselect();
|
|
492
|
+
}
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
if (this.pieces.has(sq)) {
|
|
496
|
+
if (this.draggable) {
|
|
497
|
+
this.startDrag(sq, e);
|
|
498
|
+
} else {
|
|
499
|
+
this.pendingClick = { sq, x: e.clientX, y: e.clientY };
|
|
500
|
+
this.boardEl.setPointerCapture(e.pointerId);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
this.handlePointerMove = (e) => {
|
|
505
|
+
if (this.destroyed) return;
|
|
506
|
+
if (this.arrowDragOrigin) return;
|
|
507
|
+
if (this.dragState) {
|
|
508
|
+
this.updateDrag(e);
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
this.handlePointerUp = (e) => {
|
|
512
|
+
if (this.destroyed) return;
|
|
513
|
+
if (e.button === 2 && this.arrowDragOrigin) {
|
|
514
|
+
const sq = this.squareFromPointer(e);
|
|
515
|
+
if (sq && sq !== this.arrowDragOrigin) {
|
|
516
|
+
this.addArrow(this.arrowDragOrigin, sq);
|
|
517
|
+
this.onArrowCallback?.(this.arrowDragOrigin, sq);
|
|
518
|
+
}
|
|
519
|
+
try {
|
|
520
|
+
this.boardEl.releasePointerCapture(e.pointerId);
|
|
521
|
+
} catch {
|
|
522
|
+
}
|
|
523
|
+
this.arrowDragOrigin = null;
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
if (this.dragState) {
|
|
527
|
+
this.endDrag(e);
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
if (this.pendingClick) {
|
|
531
|
+
const clickedSq = this.pendingClick.sq;
|
|
532
|
+
if (this.selected && clickedSq !== this.selected) {
|
|
533
|
+
const result = this.onMoveCallback?.(this.selected, clickedSq);
|
|
534
|
+
if (result === false) {
|
|
535
|
+
if (this.pieces.has(clickedSq) && this.clickable && !this.legalSqs.has(clickedSq)) {
|
|
536
|
+
this.doSelect(clickedSq);
|
|
537
|
+
} else {
|
|
538
|
+
this.doDeselect();
|
|
539
|
+
}
|
|
540
|
+
} else {
|
|
541
|
+
this.applyMove(this.selected, clickedSq);
|
|
542
|
+
this.doDeselect();
|
|
543
|
+
}
|
|
544
|
+
} else if (this.clickable) {
|
|
545
|
+
if (clickedSq === this.selected) {
|
|
546
|
+
this.doDeselect();
|
|
547
|
+
} else {
|
|
548
|
+
this.doSelect(clickedSq);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
try {
|
|
552
|
+
this.boardEl.releasePointerCapture(e.pointerId);
|
|
553
|
+
} catch {
|
|
554
|
+
}
|
|
555
|
+
this.pendingClick = null;
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
this.handlePointerCancel = (e) => {
|
|
560
|
+
if (this.destroyed) return;
|
|
561
|
+
if (this.dragState) {
|
|
562
|
+
const { pieceEl, originSq, pointerId } = this.dragState;
|
|
563
|
+
pieceEl.classList.remove("cb-dragging");
|
|
564
|
+
try {
|
|
565
|
+
this.boardEl.releasePointerCapture(pointerId);
|
|
566
|
+
} catch {
|
|
567
|
+
}
|
|
568
|
+
this.translatePiece(pieceEl, originSq, true);
|
|
569
|
+
this.dragState = null;
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
if (this.pendingClick) {
|
|
573
|
+
try {
|
|
574
|
+
this.boardEl.releasePointerCapture(e.pointerId);
|
|
575
|
+
} catch {
|
|
576
|
+
}
|
|
577
|
+
this.pendingClick = null;
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
if (this.arrowDragOrigin) {
|
|
581
|
+
try {
|
|
582
|
+
this.boardEl.releasePointerCapture(e.pointerId);
|
|
583
|
+
} catch {
|
|
584
|
+
}
|
|
585
|
+
this.arrowDragOrigin = null;
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
this.handleContextMenu = (e) => {
|
|
589
|
+
e.preventDefault();
|
|
590
|
+
};
|
|
591
|
+
injectStyles();
|
|
592
|
+
this.orientation = options?.orientation ?? "white";
|
|
593
|
+
this.pieceTheme = options?.pieceTheme ?? defaultPieceTheme;
|
|
594
|
+
this.boardTheme = options?.boardTheme ?? defaultBoardTheme;
|
|
595
|
+
this.animDuration = options?.animationDuration ?? 150;
|
|
596
|
+
this.draggable = options?.draggable ?? true;
|
|
597
|
+
this.clickable = options?.clickable ?? true;
|
|
598
|
+
this.viewOnly = options?.viewOnly ?? false;
|
|
599
|
+
this.showCoords = options?.coordinates ?? true;
|
|
600
|
+
this.onMoveCallback = options?.onMove ?? null;
|
|
601
|
+
this.onSelectCallback = options?.onSelect ?? null;
|
|
602
|
+
this.onArrowCallback = options?.onArrowDrawn ?? null;
|
|
603
|
+
const { boardEl, squareEls, svgEl } = createBoardDOM(
|
|
604
|
+
this.orientation,
|
|
605
|
+
this.boardTheme,
|
|
606
|
+
this.showCoords
|
|
607
|
+
);
|
|
608
|
+
this.boardEl = boardEl;
|
|
609
|
+
this.squareEls = squareEls;
|
|
610
|
+
this.svgEl = svgEl;
|
|
611
|
+
this.boardEl.style.setProperty(
|
|
612
|
+
"--cb-anim-duration",
|
|
613
|
+
`${this.animDuration}ms`
|
|
614
|
+
);
|
|
615
|
+
container.appendChild(this.boardEl);
|
|
616
|
+
const fen = options?.position ?? STARTING_FEN;
|
|
617
|
+
this.pieces = parseFen(fen);
|
|
618
|
+
this.renderAllPieces();
|
|
619
|
+
this.boardEl.addEventListener("pointerdown", this.handlePointerDown);
|
|
620
|
+
this.boardEl.addEventListener("pointermove", this.handlePointerMove);
|
|
621
|
+
this.boardEl.addEventListener("pointerup", this.handlePointerUp);
|
|
622
|
+
this.boardEl.addEventListener("pointercancel", this.handlePointerCancel);
|
|
623
|
+
this.boardEl.addEventListener("contextmenu", this.handleContextMenu);
|
|
624
|
+
}
|
|
625
|
+
// ────────────────────────────────────────────────────────────────────
|
|
626
|
+
// Public API — position
|
|
627
|
+
// ────────────────────────────────────────────────────────────────────
|
|
628
|
+
setPosition(fen) {
|
|
629
|
+
const newPieces = parseFen(fen);
|
|
630
|
+
this.syncPieces(newPieces, true);
|
|
631
|
+
}
|
|
632
|
+
getPosition() {
|
|
633
|
+
return positionToFen(this.pieces);
|
|
634
|
+
}
|
|
635
|
+
// ────────────────────────────────────────────────────────────────────
|
|
636
|
+
// Public API — orientation
|
|
637
|
+
// ────────────────────────────────────────────────────────────────────
|
|
638
|
+
setOrientation(orientation) {
|
|
639
|
+
if (orientation === this.orientation) return;
|
|
640
|
+
this.orientation = orientation;
|
|
641
|
+
rebuildSquares(
|
|
642
|
+
this.boardEl,
|
|
643
|
+
this.squareEls,
|
|
644
|
+
orientation,
|
|
645
|
+
this.boardTheme,
|
|
646
|
+
this.showCoords
|
|
647
|
+
);
|
|
648
|
+
this.repositionAllPieces();
|
|
649
|
+
this.refreshHighlights();
|
|
650
|
+
this.renderArrowsInternal();
|
|
651
|
+
}
|
|
652
|
+
getOrientation() {
|
|
653
|
+
return this.orientation;
|
|
654
|
+
}
|
|
655
|
+
flip() {
|
|
656
|
+
this.setOrientation(
|
|
657
|
+
this.orientation === "white" ? "black" : "white"
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
// ────────────────────────────────────────────────────────────────────
|
|
661
|
+
// Public API — selection & highlights
|
|
662
|
+
// ────────────────────────────────────────────────────────────────────
|
|
663
|
+
select(sq) {
|
|
664
|
+
if (sq) {
|
|
665
|
+
this.doSelect(sq);
|
|
666
|
+
} else {
|
|
667
|
+
this.doDeselect();
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
setLastMove(from, to) {
|
|
671
|
+
this.clearHighlightType("cb-hl-lastmove");
|
|
672
|
+
this.lastMoveSquares = [from, to];
|
|
673
|
+
this.squareEls.get(from)?.classList.add("cb-hl-lastmove");
|
|
674
|
+
this.squareEls.get(to)?.classList.add("cb-hl-lastmove");
|
|
675
|
+
}
|
|
676
|
+
clearLastMove() {
|
|
677
|
+
this.clearHighlightType("cb-hl-lastmove");
|
|
678
|
+
this.lastMoveSquares = null;
|
|
679
|
+
}
|
|
680
|
+
setCheck(sq) {
|
|
681
|
+
this.clearHighlightType("cb-hl-check");
|
|
682
|
+
this.checkSq = sq;
|
|
683
|
+
if (sq) {
|
|
684
|
+
this.squareEls.get(sq)?.classList.add("cb-hl-check");
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
setLegalMoves(squares) {
|
|
688
|
+
this.clearHighlightType("cb-legal");
|
|
689
|
+
this.legalSqs = new Set(squares);
|
|
690
|
+
for (const sq of squares) {
|
|
691
|
+
this.squareEls.get(sq)?.classList.add("cb-legal");
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
clearLegalMoves() {
|
|
695
|
+
this.clearHighlightType("cb-legal");
|
|
696
|
+
this.legalSqs.clear();
|
|
697
|
+
}
|
|
698
|
+
// ────────────────────────────────────────────────────────────────────
|
|
699
|
+
// Public API — arrows
|
|
700
|
+
// ────────────────────────────────────────────────────────────────────
|
|
701
|
+
setArrows(arrows) {
|
|
702
|
+
this.arrowList = [...arrows];
|
|
703
|
+
this.renderArrowsInternal();
|
|
704
|
+
}
|
|
705
|
+
addArrow(from, to, color) {
|
|
706
|
+
const exists = this.arrowList.some(
|
|
707
|
+
(a) => a.from === from && a.to === to
|
|
708
|
+
);
|
|
709
|
+
if (exists) return;
|
|
710
|
+
this.arrowList.push({ from, to, color });
|
|
711
|
+
this.renderArrowsInternal();
|
|
712
|
+
}
|
|
713
|
+
removeArrow(from, to) {
|
|
714
|
+
this.arrowList = this.arrowList.filter(
|
|
715
|
+
(a) => !(a.from === from && a.to === to)
|
|
716
|
+
);
|
|
717
|
+
this.renderArrowsInternal();
|
|
718
|
+
}
|
|
719
|
+
clearArrows() {
|
|
720
|
+
this.arrowList = [];
|
|
721
|
+
this.renderArrowsInternal();
|
|
722
|
+
}
|
|
723
|
+
// ────────────────────────────────────────────────────────────────────
|
|
724
|
+
// Public API — lifecycle
|
|
725
|
+
// ────────────────────────────────────────────────────────────────────
|
|
726
|
+
destroy() {
|
|
727
|
+
if (this.destroyed) return;
|
|
728
|
+
this.destroyed = true;
|
|
729
|
+
this.boardEl.removeEventListener(
|
|
730
|
+
"pointerdown",
|
|
731
|
+
this.handlePointerDown
|
|
732
|
+
);
|
|
733
|
+
this.boardEl.removeEventListener(
|
|
734
|
+
"pointermove",
|
|
735
|
+
this.handlePointerMove
|
|
736
|
+
);
|
|
737
|
+
this.boardEl.removeEventListener("pointerup", this.handlePointerUp);
|
|
738
|
+
this.boardEl.removeEventListener(
|
|
739
|
+
"pointercancel",
|
|
740
|
+
this.handlePointerCancel
|
|
741
|
+
);
|
|
742
|
+
this.boardEl.removeEventListener(
|
|
743
|
+
"contextmenu",
|
|
744
|
+
this.handleContextMenu
|
|
745
|
+
);
|
|
746
|
+
this.boardEl.remove();
|
|
747
|
+
this.pieceEls.clear();
|
|
748
|
+
this.squareEls.clear();
|
|
749
|
+
this.pieces.clear();
|
|
750
|
+
this.arrowList.length = 0;
|
|
751
|
+
this.legalSqs.clear();
|
|
752
|
+
}
|
|
753
|
+
// ────────────────────────────────────────────────────────────────────
|
|
754
|
+
// Rendering internals
|
|
755
|
+
// ────────────────────────────────────────────────────────────────────
|
|
756
|
+
renderAllPieces() {
|
|
757
|
+
for (const el of this.pieceEls.values()) el.remove();
|
|
758
|
+
this.pieceEls.clear();
|
|
759
|
+
for (const [sq, piece] of this.pieces) {
|
|
760
|
+
const el = createPieceEl(
|
|
761
|
+
sq,
|
|
762
|
+
piece,
|
|
763
|
+
this.orientation,
|
|
764
|
+
this.pieceTheme
|
|
765
|
+
);
|
|
766
|
+
this.boardEl.insertBefore(el, this.svgEl);
|
|
767
|
+
this.pieceEls.set(sq, el);
|
|
768
|
+
}
|
|
769
|
+
this.updateOccupied();
|
|
770
|
+
}
|
|
771
|
+
syncPieces(newPieces, animate) {
|
|
772
|
+
const diff = diffPieces(this.pieces, newPieces);
|
|
773
|
+
for (const sq of diff.removed) {
|
|
774
|
+
const el = this.pieceEls.get(sq);
|
|
775
|
+
if (el) {
|
|
776
|
+
el.remove();
|
|
777
|
+
this.pieceEls.delete(sq);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
for (const { from, to } of diff.moved) {
|
|
781
|
+
const el = this.pieceEls.get(from);
|
|
782
|
+
if (!el) continue;
|
|
783
|
+
this.pieceEls.delete(from);
|
|
784
|
+
this.pieceEls.set(to, el);
|
|
785
|
+
el.setAttribute("data-square", to);
|
|
786
|
+
this.translatePiece(el, to, animate);
|
|
787
|
+
}
|
|
788
|
+
for (const { square, piece } of diff.added) {
|
|
789
|
+
const el = createPieceEl(
|
|
790
|
+
square,
|
|
791
|
+
piece,
|
|
792
|
+
this.orientation,
|
|
793
|
+
this.pieceTheme
|
|
794
|
+
);
|
|
795
|
+
this.boardEl.insertBefore(el, this.svgEl);
|
|
796
|
+
this.pieceEls.set(square, el);
|
|
797
|
+
}
|
|
798
|
+
this.pieces = newPieces;
|
|
799
|
+
this.updateOccupied();
|
|
800
|
+
}
|
|
801
|
+
repositionAllPieces() {
|
|
802
|
+
for (const [sq, el] of this.pieceEls) {
|
|
803
|
+
const [col, row] = squareToCoords(sq, this.orientation);
|
|
804
|
+
el.style.transform = `translate(${col * 100}%, ${row * 100}%)`;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
translatePiece(el, sq, animate) {
|
|
808
|
+
const [col, row] = squareToCoords(sq, this.orientation);
|
|
809
|
+
if (animate && this.animDuration > 0) {
|
|
810
|
+
el.classList.add("cb-animating");
|
|
811
|
+
el.style.transform = `translate(${col * 100}%, ${row * 100}%)`;
|
|
812
|
+
el.addEventListener(
|
|
813
|
+
"transitionend",
|
|
814
|
+
() => el.classList.remove("cb-animating"),
|
|
815
|
+
{ once: true }
|
|
816
|
+
);
|
|
817
|
+
} else {
|
|
818
|
+
el.style.transform = `translate(${col * 100}%, ${row * 100}%)`;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
updateOccupied() {
|
|
822
|
+
for (const [sq, el] of this.squareEls) {
|
|
823
|
+
el.classList.toggle("cb-has-piece", this.pieces.has(sq));
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
// ────────────────────────────────────────────────────────────────────
|
|
827
|
+
// Highlight internals
|
|
828
|
+
// ────────────────────────────────────────────────────────────────────
|
|
829
|
+
refreshHighlights() {
|
|
830
|
+
this.clearHighlightType("cb-hl-lastmove");
|
|
831
|
+
this.clearHighlightType("cb-hl-selected");
|
|
832
|
+
this.clearHighlightType("cb-hl-check");
|
|
833
|
+
this.clearHighlightType("cb-legal");
|
|
834
|
+
if (this.lastMoveSquares) {
|
|
835
|
+
this.squareEls.get(this.lastMoveSquares[0])?.classList.add("cb-hl-lastmove");
|
|
836
|
+
this.squareEls.get(this.lastMoveSquares[1])?.classList.add("cb-hl-lastmove");
|
|
837
|
+
}
|
|
838
|
+
if (this.selected) {
|
|
839
|
+
this.squareEls.get(this.selected)?.classList.add("cb-hl-selected");
|
|
840
|
+
}
|
|
841
|
+
if (this.checkSq) {
|
|
842
|
+
this.squareEls.get(this.checkSq)?.classList.add("cb-hl-check");
|
|
843
|
+
}
|
|
844
|
+
for (const sq of this.legalSqs) {
|
|
845
|
+
this.squareEls.get(sq)?.classList.add("cb-legal");
|
|
846
|
+
}
|
|
847
|
+
this.updateOccupied();
|
|
848
|
+
}
|
|
849
|
+
clearHighlightType(cls) {
|
|
850
|
+
for (const el of this.squareEls.values()) {
|
|
851
|
+
el.classList.remove(cls);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
renderArrowsInternal() {
|
|
855
|
+
renderArrows(this.svgEl, this.arrowList, this.orientation);
|
|
856
|
+
}
|
|
857
|
+
// ────────────────────────────────────────────────────────────────────
|
|
858
|
+
// Selection internals
|
|
859
|
+
// ────────────────────────────────────────────────────────────────────
|
|
860
|
+
doSelect(sq) {
|
|
861
|
+
if (this.selected) {
|
|
862
|
+
this.squareEls.get(this.selected)?.classList.remove("cb-hl-selected");
|
|
863
|
+
}
|
|
864
|
+
this.selected = sq;
|
|
865
|
+
this.squareEls.get(sq)?.classList.add("cb-hl-selected");
|
|
866
|
+
this.onSelectCallback?.(sq);
|
|
867
|
+
}
|
|
868
|
+
doDeselect() {
|
|
869
|
+
if (this.selected) {
|
|
870
|
+
this.squareEls.get(this.selected)?.classList.remove("cb-hl-selected");
|
|
871
|
+
}
|
|
872
|
+
this.selected = null;
|
|
873
|
+
this.clearLegalMoves();
|
|
874
|
+
this.onSelectCallback?.(null);
|
|
875
|
+
}
|
|
876
|
+
// ────────────────────────────────────────────────────────────────────
|
|
877
|
+
// Move internals (after accepted drag or click-to-move)
|
|
878
|
+
// ────────────────────────────────────────────────────────────────────
|
|
879
|
+
applyMove(from, to) {
|
|
880
|
+
const piece = this.pieces.get(from);
|
|
881
|
+
if (!piece) return;
|
|
882
|
+
const capturedEl = this.pieceEls.get(to);
|
|
883
|
+
if (capturedEl) {
|
|
884
|
+
capturedEl.remove();
|
|
885
|
+
this.pieceEls.delete(to);
|
|
886
|
+
}
|
|
887
|
+
this.pieces.delete(from);
|
|
888
|
+
this.pieces.set(to, piece);
|
|
889
|
+
const el = this.pieceEls.get(from);
|
|
890
|
+
if (el) {
|
|
891
|
+
this.pieceEls.delete(from);
|
|
892
|
+
this.pieceEls.set(to, el);
|
|
893
|
+
el.setAttribute("data-square", to);
|
|
894
|
+
const [col, row] = squareToCoords(to, this.orientation);
|
|
895
|
+
el.style.transform = `translate(${col * 100}%, ${row * 100}%)`;
|
|
896
|
+
}
|
|
897
|
+
this.setLastMove(from, to);
|
|
898
|
+
this.updateOccupied();
|
|
899
|
+
}
|
|
900
|
+
// ────────────────────────────────────────────────────────────────────
|
|
901
|
+
// Coordinate helpers
|
|
902
|
+
// ────────────────────────────────────────────────────────────────────
|
|
903
|
+
squareFromPointer(e) {
|
|
904
|
+
const rect = this.boardEl.getBoundingClientRect();
|
|
905
|
+
const size = rect.width / 8;
|
|
906
|
+
const col = Math.max(
|
|
907
|
+
0,
|
|
908
|
+
Math.min(7, Math.floor((e.clientX - rect.left) / size))
|
|
909
|
+
);
|
|
910
|
+
const row = Math.max(
|
|
911
|
+
0,
|
|
912
|
+
Math.min(7, Math.floor((e.clientY - rect.top) / size))
|
|
913
|
+
);
|
|
914
|
+
return coordsToSquare(col, row, this.orientation);
|
|
915
|
+
}
|
|
916
|
+
// ────────────────────────────────────────────────────────────────────
|
|
917
|
+
// Drag internals
|
|
918
|
+
// ────────────────────────────────────────────────────────────────────
|
|
919
|
+
startDrag(sq, e) {
|
|
920
|
+
const el = this.pieceEls.get(sq);
|
|
921
|
+
if (!el) return;
|
|
922
|
+
this.boardEl.setPointerCapture(e.pointerId);
|
|
923
|
+
if (this.clickable) {
|
|
924
|
+
this.doSelect(sq);
|
|
925
|
+
}
|
|
926
|
+
const rect = this.boardEl.getBoundingClientRect();
|
|
927
|
+
el.classList.add("cb-dragging");
|
|
928
|
+
el.classList.remove("cb-animating");
|
|
929
|
+
this.dragState = {
|
|
930
|
+
pieceEl: el,
|
|
931
|
+
originSq: sq,
|
|
932
|
+
pointerId: e.pointerId,
|
|
933
|
+
boardRect: rect
|
|
934
|
+
};
|
|
935
|
+
this.updateDrag(e);
|
|
936
|
+
}
|
|
937
|
+
updateDrag(e) {
|
|
938
|
+
if (!this.dragState) return;
|
|
939
|
+
const { pieceEl, boardRect } = this.dragState;
|
|
940
|
+
const pieceSize = boardRect.width / 8;
|
|
941
|
+
const relX = e.clientX - boardRect.left;
|
|
942
|
+
const relY = e.clientY - boardRect.top;
|
|
943
|
+
const tx = (relX - pieceSize / 2) / pieceSize * 100;
|
|
944
|
+
const ty = (relY - pieceSize / 2) / pieceSize * 100;
|
|
945
|
+
pieceEl.style.transform = `translate(${tx}%, ${ty}%)`;
|
|
946
|
+
}
|
|
947
|
+
endDrag(e) {
|
|
948
|
+
if (!this.dragState) return;
|
|
949
|
+
const { pieceEl, originSq, pointerId } = this.dragState;
|
|
950
|
+
pieceEl.classList.remove("cb-dragging");
|
|
951
|
+
try {
|
|
952
|
+
this.boardEl.releasePointerCapture(pointerId);
|
|
953
|
+
} catch {
|
|
954
|
+
}
|
|
955
|
+
const sq = this.squareFromPointer(e);
|
|
956
|
+
if (sq && sq !== originSq) {
|
|
957
|
+
const result = this.onMoveCallback?.(originSq, sq);
|
|
958
|
+
if (result === false) {
|
|
959
|
+
this.translatePiece(pieceEl, originSq, true);
|
|
960
|
+
if (this.clickable) this.doSelect(originSq);
|
|
961
|
+
} else {
|
|
962
|
+
this.applyMove(originSq, sq);
|
|
963
|
+
this.doDeselect();
|
|
964
|
+
}
|
|
965
|
+
} else {
|
|
966
|
+
this.translatePiece(pieceEl, originSq, true);
|
|
967
|
+
if (this.clickable) this.doSelect(originSq);
|
|
968
|
+
}
|
|
969
|
+
this.dragState = null;
|
|
970
|
+
}
|
|
971
|
+
};
|
|
972
|
+
|
|
973
|
+
export { ChessBoard, STARTING_FEN, defaultBoardTheme, defaultPieceTheme, parseFen, positionToFen };
|
|
974
|
+
//# sourceMappingURL=index.js.map
|
|
975
|
+
//# sourceMappingURL=index.js.map
|