chesspal 0.0.1 → 0.2.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/README.md +99 -2
- package/dist/cli/chat-hook.d.ts +2 -0
- package/dist/cli/chat-hook.js +33 -0
- package/dist/cli/cli.d.ts +2 -0
- package/dist/cli/cli.js +28 -0
- package/dist/cli/command-line.d.ts +7 -0
- package/dist/cli/command-line.js +177 -0
- package/dist/commands/agents.d.ts +26 -0
- package/dist/commands/agents.js +72 -0
- package/dist/commands/ai-move.d.ts +28 -0
- package/dist/commands/ai-move.js +85 -0
- package/dist/commands/ai-say.d.ts +22 -0
- package/dist/commands/ai-say.js +58 -0
- package/dist/commands/analyse-game.d.ts +65 -0
- package/dist/commands/analyse-game.js +265 -0
- package/dist/commands/annotate-game.d.ts +39 -0
- package/dist/commands/annotate-game.js +131 -0
- package/dist/commands/answer-lines.d.ts +28 -0
- package/dist/commands/answer-lines.js +144 -0
- package/dist/commands/clock.d.ts +15 -0
- package/dist/commands/clock.js +45 -0
- package/dist/commands/coach.d.ts +45 -0
- package/dist/commands/coach.js +344 -0
- package/dist/commands/context.d.ts +67 -0
- package/dist/commands/context.js +37 -0
- package/dist/commands/delete-game.d.ts +7 -0
- package/dist/commands/delete-game.js +30 -0
- package/dist/commands/delete-review.d.ts +8 -0
- package/dist/commands/delete-review.js +34 -0
- package/dist/commands/draw-offer.d.ts +10 -0
- package/dist/commands/draw-offer.js +43 -0
- package/dist/commands/drawings.d.ts +13 -0
- package/dist/commands/drawings.js +25 -0
- package/dist/commands/end-game.d.ts +23 -0
- package/dist/commands/end-game.js +67 -0
- package/dist/commands/export-game.d.ts +14 -0
- package/dist/commands/export-game.js +27 -0
- package/dist/commands/game-summary.d.ts +78 -0
- package/dist/commands/game-summary.js +102 -0
- package/dist/commands/index.d.ts +18 -0
- package/dist/commands/index.js +64 -0
- package/dist/commands/init.d.ts +15 -0
- package/dist/commands/init.js +73 -0
- package/dist/commands/lead-input.d.ts +8 -0
- package/dist/commands/lead-input.js +21 -0
- package/dist/commands/levels.d.ts +9 -0
- package/dist/commands/levels.js +25 -0
- package/dist/commands/look.d.ts +31 -0
- package/dist/commands/look.js +64 -0
- package/dist/commands/new-game.d.ts +68 -0
- package/dist/commands/new-game.js +218 -0
- package/dist/commands/opening-book.d.ts +13 -0
- package/dist/commands/opening-book.js +84 -0
- package/dist/commands/page-link.d.ts +11 -0
- package/dist/commands/page-link.js +28 -0
- package/dist/commands/past-games.d.ts +11 -0
- package/dist/commands/past-games.js +47 -0
- package/dist/commands/play-move.d.ts +37 -0
- package/dist/commands/play-move.js +94 -0
- package/dist/commands/player-move.d.ts +13 -0
- package/dist/commands/player-move.js +51 -0
- package/dist/commands/player-say.d.ts +5 -0
- package/dist/commands/player-say.js +16 -0
- package/dist/commands/ponder.d.ts +52 -0
- package/dist/commands/ponder.js +179 -0
- package/dist/commands/position.d.ts +14 -0
- package/dist/commands/position.js +130 -0
- package/dist/commands/profiles.d.ts +69 -0
- package/dist/commands/profiles.js +163 -0
- package/dist/commands/registry.d.ts +59 -0
- package/dist/commands/registry.js +62 -0
- package/dist/commands/say.d.ts +16 -0
- package/dist/commands/say.js +84 -0
- package/dist/commands/speech.d.ts +8 -0
- package/dist/commands/speech.js +20 -0
- package/dist/commands/status.d.ts +35 -0
- package/dist/commands/status.js +128 -0
- package/dist/commands/study-games.d.ts +5 -0
- package/dist/commands/study-games.js +40 -0
- package/dist/commands/study.d.ts +38 -0
- package/dist/commands/study.js +106 -0
- package/dist/commands/view.d.ts +14 -0
- package/dist/commands/view.js +125 -0
- package/dist/core/board-text.d.ts +7 -0
- package/dist/core/board-text.js +18 -0
- package/dist/core/book.json +1 -0
- package/dist/core/clock.d.ts +45 -0
- package/dist/core/clock.js +109 -0
- package/dist/core/facts.d.ts +55 -0
- package/dist/core/facts.js +175 -0
- package/dist/core/game.d.ts +95 -0
- package/dist/core/game.js +352 -0
- package/dist/core/illegal.d.ts +19 -0
- package/dist/core/illegal.js +141 -0
- package/dist/core/index.d.ts +20 -0
- package/dist/core/index.js +12 -0
- package/dist/core/lead.d.ts +15 -0
- package/dist/core/lead.js +40 -0
- package/dist/core/levels.d.ts +20 -0
- package/dist/core/levels.js +33 -0
- package/dist/core/material.d.ts +9 -0
- package/dist/core/material.js +12 -0
- package/dist/core/moods.d.ts +21 -0
- package/dist/core/moods.js +45 -0
- package/dist/core/openings.d.ts +35 -0
- package/dist/core/openings.js +98 -0
- package/dist/core/openings.json +1 -0
- package/dist/core/pgn.d.ts +10 -0
- package/dist/core/pgn.js +213 -0
- package/dist/core/profile.d.ts +117 -0
- package/dist/core/profile.js +232 -0
- package/dist/core/record.d.ts +21 -0
- package/dist/core/record.js +25 -0
- package/dist/core/review.d.ts +80 -0
- package/dist/core/review.js +146 -0
- package/dist/games/ai-model.d.ts +5 -0
- package/dist/games/ai-model.js +15 -0
- package/dist/games/analysis.d.ts +12 -0
- package/dist/games/analysis.js +26 -0
- package/dist/games/archive.d.ts +63 -0
- package/dist/games/archive.js +242 -0
- package/dist/games/chat-start.d.ts +16 -0
- package/dist/games/chat-start.js +26 -0
- package/dist/games/coach.d.ts +57 -0
- package/dist/games/coach.js +144 -0
- package/dist/games/current-game.d.ts +56 -0
- package/dist/games/current-game.js +134 -0
- package/dist/games/files.d.ts +9 -0
- package/dist/games/files.js +53 -0
- package/dist/games/index.d.ts +11 -0
- package/dist/games/index.js +12 -0
- package/dist/games/plans.d.ts +9 -0
- package/dist/games/plans.js +23 -0
- package/dist/games/table-talk.d.ts +12 -0
- package/dist/games/table-talk.js +25 -0
- package/dist/games/talk.d.ts +36 -0
- package/dist/games/talk.js +131 -0
- package/dist/games/thoughts.d.ts +15 -0
- package/dist/games/thoughts.js +60 -0
- package/dist/home/data-folder.d.ts +12 -0
- package/dist/home/data-folder.js +55 -0
- package/dist/home/index.d.ts +2 -0
- package/dist/home/index.js +3 -0
- package/dist/home/open-folder.d.ts +2 -0
- package/dist/home/open-folder.js +14 -0
- package/dist/host-files/agents.d.ts +20 -0
- package/dist/host-files/agents.js +53 -0
- package/dist/host-files/host-files.d.ts +15 -0
- package/dist/host-files/host-files.js +182 -0
- package/dist/host-files/index.d.ts +2 -0
- package/dist/host-files/index.js +3 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/page/app/anchor.js +88 -0
- package/dist/page/app/app.js +458 -0
- package/dist/page/app/keys.js +94 -0
- package/dist/page/app/phase.js +30 -0
- package/dist/page/app/served.js +73 -0
- package/dist/page/avatars/avatars.js +19 -0
- package/dist/page/avatars/beanie.webp +0 -0
- package/dist/page/avatars/beard.webp +0 -0
- package/dist/page/avatars/bun.webp +0 -0
- package/dist/page/avatars/cat.webp +0 -0
- package/dist/page/avatars/curls.webp +0 -0
- package/dist/page/avatars/glasses.webp +0 -0
- package/dist/page/avatars/moustache.webp +0 -0
- package/dist/page/avatars/owl.webp +0 -0
- package/dist/page/avatars/short-hair.webp +0 -0
- package/dist/page/avatars/silver-bob.webp +0 -0
- package/dist/page/avatars/thought.js +10 -0
- package/dist/page/avatars/torretta.js +38 -0
- package/dist/page/base.css +160 -0
- package/dist/page/board/board.css +959 -0
- package/dist/page/board/board.js +125 -0
- package/dist/page/board/explain.js +58 -0
- package/dist/page/board/marks.js +160 -0
- package/dist/page/board/motion.js +71 -0
- package/dist/page/board/pointer.js +239 -0
- package/dist/page/board/squares.js +26 -0
- package/dist/page/dialogs/analyses.js +195 -0
- package/dist/page/dialogs/dialog.js +26 -0
- package/dist/page/dialogs/dialogs.css +1228 -0
- package/dist/page/dialogs/new-game.js +42 -0
- package/dist/page/dialogs/profiles.js +152 -0
- package/dist/page/dialogs/search.js +31 -0
- package/dist/page/dialogs/settings.js +42 -0
- package/dist/page/dialogs/studied.js +39 -0
- package/dist/page/dialogs/study.js +51 -0
- package/dist/page/game/badges.js +50 -0
- package/dist/page/game/browse.js +17 -0
- package/dist/page/game/card-fold.js +40 -0
- package/dist/page/game/column.js +51 -0
- package/dist/page/game/ending.js +73 -0
- package/dist/page/game/game.css +577 -0
- package/dist/page/game/move-list.js +72 -0
- package/dist/page/game/opening-book.js +14 -0
- package/dist/page/game/plies.js +82 -0
- package/dist/page/game/result-tile.js +14 -0
- package/dist/page/helps/helps.css +689 -0
- package/dist/page/helps/helps.js +220 -0
- package/dist/page/helps/view.js +127 -0
- package/dist/page/layout/fold-tab.js +11 -0
- package/dist/page/layout/folds.js +43 -0
- package/dist/page/layout/header.js +28 -0
- package/dist/page/layout/layout.css +834 -0
- package/dist/page/lead/lead.js +82 -0
- package/dist/page/lead/view.js +38 -0
- package/dist/page/main.js +8 -0
- package/dist/page/pieces/CREDITS.md +19 -0
- package/dist/page/pieces/capablanca-small.svg +20 -0
- package/dist/page/pieces/capablanca.svg +22 -0
- package/dist/page/pieces/nitida-small.svg +20 -0
- package/dist/page/pieces/nitida.svg +21 -0
- package/dist/page/pieces/pieces.js +28 -0
- package/dist/page/pieces/torretta-small.svg +20 -0
- package/dist/page/pieces/torretta.svg +21 -0
- package/dist/page/players/card.js +56 -0
- package/dist/page/players/clock-time.js +12 -0
- package/dist/page/players/model-name.js +20 -0
- package/dist/page/profile/profile.js +99 -0
- package/dist/page/profile/settings.js +77 -0
- package/dist/page/sounds/capture.ogg +0 -0
- package/dist/page/sounds/check.ogg +0 -0
- package/dist/page/sounds/draw.ogg +0 -0
- package/dist/page/sounds/flag.ogg +0 -0
- package/dist/page/sounds/mate.ogg +0 -0
- package/dist/page/sounds/move.ogg +0 -0
- package/dist/page/sounds/offer.ogg +0 -0
- package/dist/page/sounds/resign.ogg +0 -0
- package/dist/page/sounds/sounds.js +105 -0
- package/dist/page/style.css +9 -0
- package/dist/page/talk/talk.css +958 -0
- package/dist/page/talk/talk.js +165 -0
- package/dist/page/talk/voice.js +38 -0
- package/dist/page/text.js +711 -0
- package/dist/page/theme.css +292 -0
- package/dist/profiles/avatar.d.ts +23 -0
- package/dist/profiles/avatar.js +84 -0
- package/dist/profiles/front-matter.d.ts +9 -0
- package/dist/profiles/front-matter.js +33 -0
- package/dist/profiles/index.d.ts +3 -0
- package/dist/profiles/index.js +5 -0
- package/dist/profiles/profiles.d.ts +69 -0
- package/dist/profiles/profiles.js +254 -0
- package/dist/profiles/settings.d.ts +12 -0
- package/dist/profiles/settings.js +46 -0
- package/dist/server/bell.d.ts +68 -0
- package/dist/server/bell.js +225 -0
- package/dist/server/caller.d.ts +21 -0
- package/dist/server/caller.js +132 -0
- package/dist/server/mcp.d.ts +13 -0
- package/dist/server/mcp.js +207 -0
- package/dist/server/page/analyses.d.ts +23 -0
- package/dist/server/page/analyses.js +65 -0
- package/dist/server/page/files.d.ts +5 -0
- package/dist/server/page/files.js +92 -0
- package/dist/server/page/game.d.ts +6 -0
- package/dist/server/page/game.js +381 -0
- package/dist/server/page/http.d.ts +29 -0
- package/dist/server/page/http.js +68 -0
- package/dist/server/page/page.d.ts +41 -0
- package/dist/server/page/page.js +229 -0
- package/dist/server/page/profiles.d.ts +19 -0
- package/dist/server/page/profiles.js +215 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +3 -0
- package/instructions/analysis.md +4 -0
- package/instructions/analyst-agent.md +8 -0
- package/instructions/analyst.md +4 -0
- package/instructions/coach.md +11 -0
- package/instructions/opponent.md +15 -0
- package/instructions/ponder.md +9 -0
- package/package.json +66 -5
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/* The page's colours, light and dark, and the skins the settings choose for the board, the pieces and the marks (D-56) */
|
|
2
|
+
|
|
3
|
+
/* The page in Zoe's Salotto azzurro (D-46), light and dark. Its ground mixes the board's dark square, which the settings set before the page draws: without
|
|
4
|
+
them, as without scripts, the page has no ground of its own */
|
|
5
|
+
:root {
|
|
6
|
+
--page: color-mix(in oklab, var(--dark-square) 12%, #fbfbfa);
|
|
7
|
+
--card: color-mix(in oklab, var(--dark-square) 3%, #ffffff);
|
|
8
|
+
--ink: #1d2733;
|
|
9
|
+
--soft: #626d7b;
|
|
10
|
+
--line: color-mix(in oklab, var(--dark-square) 24%, #f1f1ef);
|
|
11
|
+
--accent: #2d6aa8;
|
|
12
|
+
--on-accent: #ffffff;
|
|
13
|
+
--quote: color-mix(in oklab, var(--dark-square) 9%, #fafafa);
|
|
14
|
+
--say: color-mix(in oklab, var(--dark-square) 38%, #fafafa);
|
|
15
|
+
--say-ink: #1d2733;
|
|
16
|
+
--warn-back: #fff4d6;
|
|
17
|
+
/* The squares, their highlights, the marks and the pieces take their colours from the skins the settings choose, further on */
|
|
18
|
+
--mated: rgba(214, 40, 40, 0.8);
|
|
19
|
+
--low-time: #c62828;
|
|
20
|
+
--hint: rgba(0, 0, 0, 0.14);
|
|
21
|
+
--explain-ink: #1d2733;
|
|
22
|
+
--lift-shadow: rgba(16, 28, 44, 0.32);
|
|
23
|
+
--ghost: 0.35;
|
|
24
|
+
/* The four colours of PGN's %cal and %csl, for what the AI draws (D-69) */
|
|
25
|
+
--drawn-green: #15a34a;
|
|
26
|
+
--drawn-red: #dc2626;
|
|
27
|
+
--drawn-yellow: #eab308;
|
|
28
|
+
--drawn-blue: #2563eb;
|
|
29
|
+
/* Ink that stays dark in both themes: on the light squares and on White's chips */
|
|
30
|
+
--fixed-ink: #1d2733;
|
|
31
|
+
/* The helps (D-78, Zoe's sketch B): one ink for all they draw, never one of the AI's colours, a fill or a ring. The board says where, the card says what */
|
|
32
|
+
--help-ink: #11161d;
|
|
33
|
+
--help-on: #fff;
|
|
34
|
+
--help-line: rgba(17, 22, 29, 0.78);
|
|
35
|
+
--help-halo: rgba(255, 255, 255, 0.85);
|
|
36
|
+
--torretta-body: #6d9fd1;
|
|
37
|
+
--torretta-shade: #4b7cb0;
|
|
38
|
+
--torretta-screen: #16263a;
|
|
39
|
+
--torretta-face: #f2f7fc;
|
|
40
|
+
--torretta-light: #f4c84c;
|
|
41
|
+
--torretta-alarm: #ef6a4c;
|
|
42
|
+
--torretta-ponder: #8f9a8a;
|
|
43
|
+
/* The badges of the moves (D-69): white signs, dark on the yellow one; each disc at least 3:1 with its sign */
|
|
44
|
+
--badge-ink: #fff;
|
|
45
|
+
/* How a game went for the player, in the Analysis window's list: the colours of the move badges (D-69) */
|
|
46
|
+
--result-win: var(--badge-best);
|
|
47
|
+
--result-loss: var(--badge-blunder);
|
|
48
|
+
--result-draw: var(--badge-note);
|
|
49
|
+
--badge-note: #7b8794;
|
|
50
|
+
--badge-brilliant: #0f9a9e;
|
|
51
|
+
--badge-great: #2f74c8;
|
|
52
|
+
--badge-best: #3c9a3a;
|
|
53
|
+
--badge-excellent: #6b9c2c;
|
|
54
|
+
--badge-good: #7d9a62;
|
|
55
|
+
--badge-book: #94704c;
|
|
56
|
+
--badge-inaccuracy: #e6b422;
|
|
57
|
+
--badge-inaccuracy-ink: #3b2c00;
|
|
58
|
+
--badge-mistake: #d4650f;
|
|
59
|
+
--badge-miss: #c2407d;
|
|
60
|
+
--badge-blunder: #d22c2c;
|
|
61
|
+
--shadow: 0 1px 2px rgba(29, 39, 51, 0.06), 0 6px 18px rgba(29, 39, 51, 0.06);
|
|
62
|
+
/* On a light page the board keeps a thin edge in its dark squares colour, and a deeper shadow, so its light squares do not melt into the page */
|
|
63
|
+
--board-shadow: 0 0 0 1px color-mix(in oklab, var(--dark-square) 55%, transparent), 0 2px 4px rgba(29, 39, 51, 0.1), 0 10px 28px rgba(29, 39, 51, 0.12);
|
|
64
|
+
--gap: 20px;
|
|
65
|
+
--left: 300px;
|
|
66
|
+
--right: 300px;
|
|
67
|
+
/* The board's least size beside the talk: room for the AI's words, the box and both cards; a lower window scrolls */
|
|
68
|
+
--least: 440px;
|
|
69
|
+
--tab: 16px;
|
|
70
|
+
--rail: 56px;
|
|
71
|
+
--coin: 40px;
|
|
72
|
+
/* How far from the board's top and bottom edges the faces sit, in the cards and folded, and the tabs */
|
|
73
|
+
--ear: 36px;
|
|
74
|
+
--tuck: 10px;
|
|
75
|
+
--bar: 36px;
|
|
76
|
+
/* The cards' corners, as the board's; the room between the cards, and between them and the board */
|
|
77
|
+
--radius: 6px;
|
|
78
|
+
--between: 10px;
|
|
79
|
+
--bubble: 14px;
|
|
80
|
+
color-scheme: light;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
:root[data-theme="dark"] {
|
|
84
|
+
--page: color-mix(in oklab, var(--dark-square) 13%, #0b0d10);
|
|
85
|
+
--card: color-mix(in oklab, var(--dark-square) 16%, #14171b);
|
|
86
|
+
--ink: #e6ebf1;
|
|
87
|
+
--soft: #8d98a7;
|
|
88
|
+
--line: color-mix(in oklab, var(--dark-square) 24%, #1b1f24);
|
|
89
|
+
--accent: #7cb0e4;
|
|
90
|
+
--on-accent: #0f1a28;
|
|
91
|
+
--low-time: #ff6b6b;
|
|
92
|
+
--quote: color-mix(in oklab, var(--dark-square) 20%, #1a1d22);
|
|
93
|
+
--say: color-mix(in oklab, var(--dark-square) 34%, #15181c);
|
|
94
|
+
--say-ink: #e6ebf1;
|
|
95
|
+
--warn-back: #2a2616;
|
|
96
|
+
--hint: rgba(0, 0, 0, 0.17);
|
|
97
|
+
--lift-shadow: rgba(0, 0, 0, 0.5);
|
|
98
|
+
--torretta-screen: #0f1a28;
|
|
99
|
+
--badge-great: #3577c9;
|
|
100
|
+
--badge-book: #9c7650;
|
|
101
|
+
--badge-miss: #c9478a;
|
|
102
|
+
--badge-blunder: #d93434;
|
|
103
|
+
--shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 22px rgba(0, 0, 0, 0.25);
|
|
104
|
+
--board-shadow: var(--shadow);
|
|
105
|
+
color-scheme: dark;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Zoe's palettes: on the page's root and on each swatch of the settings. Board skins, each with its own highlights */
|
|
109
|
+
:root[data-board="azzurro"],
|
|
110
|
+
[data-board="azzurro"] {
|
|
111
|
+
--light-square: #eaf1f8;
|
|
112
|
+
--dark-square: #86abd0;
|
|
113
|
+
--last-move: rgba(255, 206, 70, 0.65);
|
|
114
|
+
--selected: rgba(255, 190, 50, 0.85);
|
|
115
|
+
--hover-edge: #f4c84c;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
:root[data-theme="dark"][data-board="azzurro"],
|
|
119
|
+
:root[data-theme="dark"] [data-board="azzurro"] {
|
|
120
|
+
--light-square: #a9bccd;
|
|
121
|
+
--dark-square: #61809e;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
:root[data-board="verde"],
|
|
125
|
+
[data-board="verde"] {
|
|
126
|
+
--light-square: #eeeed2;
|
|
127
|
+
--dark-square: #769656;
|
|
128
|
+
--last-move: rgba(255, 255, 51, 0.5);
|
|
129
|
+
--selected: rgba(255, 236, 40, 0.75);
|
|
130
|
+
--hover-edge: #f6f669;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
:root[data-theme="dark"][data-board="verde"],
|
|
134
|
+
:root[data-theme="dark"] [data-board="verde"] {
|
|
135
|
+
--light-square: #c3c7a8;
|
|
136
|
+
--dark-square: #5f7c45;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
:root[data-board="noce"],
|
|
140
|
+
[data-board="noce"] {
|
|
141
|
+
--light-square: #e9d8bd;
|
|
142
|
+
--dark-square: #a6866a;
|
|
143
|
+
--last-move: rgba(200, 212, 40, 0.55);
|
|
144
|
+
--selected: rgba(185, 205, 20, 0.75);
|
|
145
|
+
--hover-edge: #cdd26a;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
:root[data-theme="dark"][data-board="noce"],
|
|
149
|
+
:root[data-theme="dark"] [data-board="noce"] {
|
|
150
|
+
--light-square: #c4b096;
|
|
151
|
+
--dark-square: #80654d;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
:root[data-board="ardesia"],
|
|
155
|
+
[data-board="ardesia"] {
|
|
156
|
+
--light-square: #dfe3e8;
|
|
157
|
+
--dark-square: #8b97a4;
|
|
158
|
+
--last-move: rgba(255, 206, 70, 0.6);
|
|
159
|
+
--selected: rgba(255, 190, 50, 0.8);
|
|
160
|
+
--hover-edge: #f4c84c;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
:root[data-theme="dark"][data-board="ardesia"],
|
|
164
|
+
:root[data-theme="dark"] [data-board="ardesia"] {
|
|
165
|
+
--light-square: #a7b0ba;
|
|
166
|
+
--dark-square: #65707c;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
:root[data-board="grigio"],
|
|
170
|
+
[data-board="grigio"] {
|
|
171
|
+
--light-square: #ededed;
|
|
172
|
+
--dark-square: #9a9a9a;
|
|
173
|
+
--last-move: rgba(255, 206, 70, 0.6);
|
|
174
|
+
--selected: rgba(255, 190, 50, 0.8);
|
|
175
|
+
--hover-edge: #f4c84c;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
:root[data-theme="dark"][data-board="grigio"],
|
|
179
|
+
:root[data-theme="dark"] [data-board="grigio"] {
|
|
180
|
+
--light-square: #b9b9b9;
|
|
181
|
+
--dark-square: #707070;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
:root[data-board="lavanda"],
|
|
185
|
+
[data-board="lavanda"] {
|
|
186
|
+
--light-square: #ece6f2;
|
|
187
|
+
--dark-square: #9a86b8;
|
|
188
|
+
--last-move: rgba(255, 214, 90, 0.6);
|
|
189
|
+
--selected: rgba(255, 200, 60, 0.8);
|
|
190
|
+
--hover-edge: #f4c84c;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
:root[data-theme="dark"][data-board="lavanda"],
|
|
194
|
+
:root[data-theme="dark"] [data-board="lavanda"] {
|
|
195
|
+
--light-square: #b8adc6;
|
|
196
|
+
--dark-square: #6f5e8c;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
:root[data-board="ciliegio"],
|
|
200
|
+
[data-board="ciliegio"] {
|
|
201
|
+
--light-square: #ecd3b6;
|
|
202
|
+
--dark-square: #9a5a3e;
|
|
203
|
+
--last-move: rgba(230, 220, 70, 0.55);
|
|
204
|
+
--selected: rgba(220, 210, 40, 0.75);
|
|
205
|
+
--hover-edge: #e6dc46;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
:root[data-theme="dark"][data-board="ciliegio"],
|
|
209
|
+
:root[data-theme="dark"] [data-board="ciliegio"] {
|
|
210
|
+
--light-square: #c6ab8f;
|
|
211
|
+
--dark-square: #73412c;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
:root[data-board="menta"],
|
|
215
|
+
[data-board="menta"] {
|
|
216
|
+
--light-square: #e9f3ec;
|
|
217
|
+
--dark-square: #7cb396;
|
|
218
|
+
--last-move: rgba(255, 218, 80, 0.6);
|
|
219
|
+
--selected: rgba(255, 204, 50, 0.8);
|
|
220
|
+
--hover-edge: #f4c84c;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
:root[data-theme="dark"][data-board="menta"],
|
|
224
|
+
:root[data-theme="dark"] [data-board="menta"] {
|
|
225
|
+
--light-square: #b3c6b9;
|
|
226
|
+
--dark-square: #58876d;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
:root[data-board="carta"],
|
|
230
|
+
[data-board="carta"] {
|
|
231
|
+
--light-square: #f3f1ea;
|
|
232
|
+
--dark-square: #b8b2a2;
|
|
233
|
+
--last-move: rgba(110, 165, 225, 0.5);
|
|
234
|
+
--selected: rgba(80, 145, 215, 0.7);
|
|
235
|
+
--hover-edge: #4a8ad0;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
:root[data-theme="dark"][data-board="carta"],
|
|
239
|
+
:root[data-theme="dark"] [data-board="carta"] {
|
|
240
|
+
--light-square: #c9c5b9;
|
|
241
|
+
--dark-square: #8a8577;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* Piece colours for Nitida and Torretta */
|
|
245
|
+
:root[data-pieces="classico"],
|
|
246
|
+
[data-pieces="classico"] {
|
|
247
|
+
--white-piece: #fff;
|
|
248
|
+
--black-piece: #000;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
:root[data-pieces="avorio"],
|
|
252
|
+
[data-pieces="avorio"] {
|
|
253
|
+
--white-piece: #f4ead3;
|
|
254
|
+
--black-piece: #2a1c12;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
:root[data-pieces="notte"],
|
|
258
|
+
[data-pieces="notte"] {
|
|
259
|
+
--white-piece: #fff;
|
|
260
|
+
--black-piece: #1a3050;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
:root[data-pieces="bordeaux"],
|
|
264
|
+
[data-pieces="bordeaux"] {
|
|
265
|
+
--white-piece: #fff;
|
|
266
|
+
--black-piece: #5e161c;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/* Marks with the right button */
|
|
270
|
+
:root[data-marks="arancione"],
|
|
271
|
+
[data-marks="arancione"] {
|
|
272
|
+
--mark: #f07c1e;
|
|
273
|
+
--mark-square: rgba(240, 124, 30, 0.65);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
:root[data-marks="rosso"],
|
|
277
|
+
[data-marks="rosso"] {
|
|
278
|
+
--mark: #d6342c;
|
|
279
|
+
--mark-square: rgba(214, 52, 44, 0.6);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
:root[data-marks="blu"],
|
|
283
|
+
[data-marks="blu"] {
|
|
284
|
+
--mark: #2335a8;
|
|
285
|
+
--mark-square: rgba(35, 53, 168, 0.62);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
:root[data-marks="verde"],
|
|
289
|
+
[data-marks="verde"] {
|
|
290
|
+
--mark: #0f6b30;
|
|
291
|
+
--mark-square: rgba(15, 107, 48, 0.7);
|
|
292
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** The types of image a profile takes, by the file names they have there. */
|
|
2
|
+
export declare const imageTypes: {
|
|
3
|
+
readonly png: "image/png";
|
|
4
|
+
readonly jpg: "image/jpeg";
|
|
5
|
+
readonly webp: "image/webp";
|
|
6
|
+
};
|
|
7
|
+
export type ImageType = keyof typeof imageTypes;
|
|
8
|
+
/** The largest image the page may send: it sends a small one, made from the player's photo. */
|
|
9
|
+
export declare const sentImageLimit: number;
|
|
10
|
+
/** The player's own image: its bytes, its type as its first bytes tell it, and a stamp that changes with it; undefined when there is none, or it is no image. */
|
|
11
|
+
export declare function ownImage(root: string, id: string): {
|
|
12
|
+
bytes: Buffer;
|
|
13
|
+
type: ImageType;
|
|
14
|
+
stamp: string;
|
|
15
|
+
} | undefined;
|
|
16
|
+
/** The stamp of the player's own image, which the page adds to its address; undefined when there is none. Only its first bytes are read. */
|
|
17
|
+
export declare function ownImageStamp(root: string, id: string): string | undefined;
|
|
18
|
+
/** Saves an image the page sent as the player's own, in place of any other: a PNG, JPEG or WebP, as its first bytes tell, within the limit. */
|
|
19
|
+
export declare function saveOwnImage(root: string, id: string, bytes: Uint8Array): void;
|
|
20
|
+
/** Removes the player's own images, but the one kept: a drawn avatar chosen on the page shows in their place. */
|
|
21
|
+
export declare function removeOwnImage(root: string, id: string, kept?: string): void;
|
|
22
|
+
/** An image's type by its first bytes: never by its name, which anything may have. */
|
|
23
|
+
export declare function imageTypeOf(bytes: Uint8Array): ImageType | undefined;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// The player's own picture (D-45): an image in the profile's folder, put there by hand or sent from the page, which shows instead of a drawn avatar.
|
|
2
|
+
import { closeSync, openSync, readFileSync, readSync, rmSync, statSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { writeAtomically } from "../games/index.js";
|
|
5
|
+
import { profileFolder } from "./profiles.js";
|
|
6
|
+
/** The types of image a profile takes, by the file names they have there. */
|
|
7
|
+
export const imageTypes = { png: "image/png", jpg: "image/jpeg", webp: "image/webp" };
|
|
8
|
+
/** The largest image the page may send: it sends a small one, made from the player's photo. */
|
|
9
|
+
export const sentImageLimit = 1024 * 1024;
|
|
10
|
+
/** The player's own image: its bytes, its type as its first bytes tell it, and a stamp that changes with it; undefined when there is none, or it is no image. */
|
|
11
|
+
export function ownImage(root, id) {
|
|
12
|
+
const found = ownImageFile(root, id);
|
|
13
|
+
try {
|
|
14
|
+
return found === undefined ? undefined : { bytes: readFileSync(found.path), type: found.type, stamp: found.stamp };
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** The stamp of the player's own image, which the page adds to its address; undefined when there is none. Only its first bytes are read. */
|
|
21
|
+
export function ownImageStamp(root, id) {
|
|
22
|
+
return ownImageFile(root, id)?.stamp;
|
|
23
|
+
}
|
|
24
|
+
/** Saves an image the page sent as the player's own, in place of any other: a PNG, JPEG or WebP, as its first bytes tell, within the limit. */
|
|
25
|
+
export function saveOwnImage(root, id, bytes) {
|
|
26
|
+
const type = imageTypeOf(bytes);
|
|
27
|
+
if (type === undefined) {
|
|
28
|
+
throw new Error("The picture must be a PNG, JPEG or WebP image.");
|
|
29
|
+
}
|
|
30
|
+
if (bytes.length > sentImageLimit) {
|
|
31
|
+
throw new Error(`The picture is ${Math.ceil(bytes.length / 1024)} KB: send one of ${sentImageLimit / 1024} KB at most.`);
|
|
32
|
+
}
|
|
33
|
+
const name = `avatar.${type}`;
|
|
34
|
+
writeAtomically(join(profileFolder(root, id), name), bytes);
|
|
35
|
+
removeOwnImage(root, id, name);
|
|
36
|
+
}
|
|
37
|
+
/** Removes the player's own images, but the one kept: a drawn avatar chosen on the page shows in their place. */
|
|
38
|
+
export function removeOwnImage(root, id, kept) {
|
|
39
|
+
for (const name of fileNames.filter((one) => one !== kept)) {
|
|
40
|
+
rmSync(join(profileFolder(root, id), name), { force: true });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** An image's type by its first bytes: never by its name, which anything may have. */
|
|
44
|
+
export function imageTypeOf(bytes) {
|
|
45
|
+
const starts = (signature, at = 0) => signature.every((byte, index) => bytes[at + index] === byte);
|
|
46
|
+
if (starts([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])) {
|
|
47
|
+
return "png";
|
|
48
|
+
}
|
|
49
|
+
if (starts([0xff, 0xd8, 0xff])) {
|
|
50
|
+
return "jpg";
|
|
51
|
+
}
|
|
52
|
+
return starts([0x52, 0x49, 0x46, 0x46]) && starts([0x57, 0x45, 0x42, 0x50], 8) ? "webp" : undefined;
|
|
53
|
+
}
|
|
54
|
+
function ownImageFile(root, id) {
|
|
55
|
+
for (const name of fileNames) {
|
|
56
|
+
const path = join(profileFolder(root, id), name);
|
|
57
|
+
try {
|
|
58
|
+
const { size, mtimeMs } = statSync(path);
|
|
59
|
+
const type = size > keptImageLimit ? undefined : imageTypeOf(firstBytes(path));
|
|
60
|
+
if (type !== undefined) {
|
|
61
|
+
return { path, type, stamp: `${Math.trunc(mtimeMs)}-${size}` };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// No such file, or one that cannot be read: the next name.
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
function firstBytes(path) {
|
|
71
|
+
const bytes = new Uint8Array(12);
|
|
72
|
+
const file = openSync(path, "r");
|
|
73
|
+
try {
|
|
74
|
+
readSync(file, bytes, 0, bytes.length, 0);
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
closeSync(file);
|
|
78
|
+
}
|
|
79
|
+
return bytes;
|
|
80
|
+
}
|
|
81
|
+
// The names the player's image may have in the profile's folder, the first found winning.
|
|
82
|
+
const fileNames = ["avatar.png", "avatar.jpg", "avatar.jpeg", "avatar.webp"];
|
|
83
|
+
// An image the player put in the folder by hand may be a photo as the camera took it, but not a huge file.
|
|
84
|
+
const keptImageLimit = 10 * 1024 * 1024;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** The fields of a markdown file's front matter, as text, and the text below it. */
|
|
2
|
+
export interface FrontMatter {
|
|
3
|
+
readonly fields: Readonly<Record<string, string>>;
|
|
4
|
+
readonly body: string;
|
|
5
|
+
}
|
|
6
|
+
/** Reads a flat front matter: a value in double quotes as JSON writes it, any other as it stands; lines that are not key: value are left out. */
|
|
7
|
+
export declare function readFrontMatter(text: string): FrontMatter;
|
|
8
|
+
/** Writes a flat front matter, its text values in double quotes so that any name reads back as it was, and the text below it. */
|
|
9
|
+
export declare function writeFrontMatter(fields: Readonly<Record<string, string | number | undefined>>, body?: string): string;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// A flat YAML front matter (D-9): one field a line, key: value, between two lines of ---, then the text below it, which stays as it was.
|
|
2
|
+
/** Reads a flat front matter: a value in double quotes as JSON writes it, any other as it stands; lines that are not key: value are left out. */
|
|
3
|
+
export function readFrontMatter(text) {
|
|
4
|
+
// An editor may begin the file with a byte-order mark.
|
|
5
|
+
const match = /^?---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(text);
|
|
6
|
+
if (match === null) {
|
|
7
|
+
return { fields: {}, body: text };
|
|
8
|
+
}
|
|
9
|
+
const fields = {};
|
|
10
|
+
for (const line of match[1].split(/\r?\n/)) {
|
|
11
|
+
const field = /^([A-Za-z][\w-]*):\s*(.*?)\s*$/.exec(line);
|
|
12
|
+
if (field !== null && field[2] !== "") {
|
|
13
|
+
fields[field[1]] = valueOf(field[2]);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return { fields, body: text.slice(match[0].length) };
|
|
17
|
+
}
|
|
18
|
+
/** Writes a flat front matter, its text values in double quotes so that any name reads back as it was, and the text below it. */
|
|
19
|
+
export function writeFrontMatter(fields, body = "") {
|
|
20
|
+
const lines = Object.entries(fields).flatMap(([key, value]) => (value === undefined ? [] : [`${key}: ${typeof value === "number" ? value : JSON.stringify(value)}`]));
|
|
21
|
+
return `---\n${lines.join("\n")}\n---\n${body}`;
|
|
22
|
+
}
|
|
23
|
+
function valueOf(written) {
|
|
24
|
+
if (written.startsWith('"')) {
|
|
25
|
+
try {
|
|
26
|
+
return String(JSON.parse(written));
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return written;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return written.startsWith("'") && written.endsWith("'") && written.length > 1 ? written.slice(1, -1).replaceAll("''", "'") : written;
|
|
33
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { type ImageType, imageTypeOf, imageTypes, ownImage, ownImageStamp, removeOwnImage, saveOwnImage, sentImageLimit } from "./avatar.ts";
|
|
2
|
+
export { type Accounts, activateProfile, activeProfile, createProfile, type DrawnAvatar, drawnAvatars, ensureProfile, gameFolder, gameFolders, type Level, levels, listProfiles, nameLimit, type PlayerProfile, type ProfileFields, profileFolder, type Rating, ratingLimits, type RatingSite, ratingSites, updateProfile, } from "./profiles.ts";
|
|
3
|
+
export { helpsIn, languageIn, type PageSettings, profileSettings, saveProfileSettings, settingsOf } from "./settings.ts";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// The player's profiles (D-23): who plays, their games, their picture and their page settings, each in profiles/<id>/ of the data folder (D-71). Below the
|
|
2
|
+
// commands, beside the games.
|
|
3
|
+
export { imageTypeOf, imageTypes, ownImage, ownImageStamp, removeOwnImage, saveOwnImage, sentImageLimit } from "./avatar.js";
|
|
4
|
+
export { activateProfile, activeProfile, createProfile, drawnAvatars, ensureProfile, gameFolder, gameFolders, levels, listProfiles, nameLimit, profileFolder, ratingLimits, ratingSites, updateProfile, } from "./profiles.js";
|
|
5
|
+
export { helpsIn, languageIn, profileSettings, saveProfileSettings, settingsOf } from "./settings.js";
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** How the player says they play, from who has just learned to who plays tournaments. */
|
|
2
|
+
export declare const levels: readonly ["learning", "casual", "regular", "tournament"];
|
|
3
|
+
export type Level = (typeof levels)[number];
|
|
4
|
+
/** Where a rating comes from. */
|
|
5
|
+
export declare const ratingSites: readonly ["lichess", "chess.com", "fide"];
|
|
6
|
+
export type RatingSite = (typeof ratingSites)[number];
|
|
7
|
+
/** The lowest and highest rating a profile takes. */
|
|
8
|
+
export declare const ratingLimits: {
|
|
9
|
+
readonly lowest: 100;
|
|
10
|
+
readonly highest: 3500;
|
|
11
|
+
};
|
|
12
|
+
/** The longest name a profile keeps. */
|
|
13
|
+
export declare const nameLimit = 40;
|
|
14
|
+
/** The avatars Zoe drew, for a player without an image of their own (D-45). */
|
|
15
|
+
export declare const drawnAvatars: readonly ["short-hair", "bun", "glasses", "beanie", "beard", "curls", "moustache", "silver-bob", "cat", "owl"];
|
|
16
|
+
export type DrawnAvatar = (typeof drawnAvatars)[number];
|
|
17
|
+
/** A rating and where it comes from. */
|
|
18
|
+
export interface Rating {
|
|
19
|
+
readonly value: number;
|
|
20
|
+
readonly site: RatingSite;
|
|
21
|
+
}
|
|
22
|
+
/** What the player tells of themselves: their name, how they play, their rating, the avatar they chose. */
|
|
23
|
+
export interface ProfileFields {
|
|
24
|
+
readonly name: string;
|
|
25
|
+
readonly level?: Level;
|
|
26
|
+
readonly rating?: Rating;
|
|
27
|
+
readonly avatar?: DrawnAvatar;
|
|
28
|
+
}
|
|
29
|
+
/** The player's names on the sites they play on. */
|
|
30
|
+
export interface Accounts {
|
|
31
|
+
readonly lichess?: string;
|
|
32
|
+
readonly chesscom?: string;
|
|
33
|
+
}
|
|
34
|
+
/** A profile: its folder's name, and what profile.md says; a folder without one is named by the folder. */
|
|
35
|
+
export interface PlayerProfile extends ProfileFields {
|
|
36
|
+
readonly id: string;
|
|
37
|
+
/** Made by Chesspal at the first start, until the player completes it: the board page's wizard does (D-71). */
|
|
38
|
+
readonly new?: true;
|
|
39
|
+
/** The player's names on Lichess and chess.com, written in profile.md by hand or from the page, by which the games they load are theirs (D-93). */
|
|
40
|
+
readonly accounts?: Accounts;
|
|
41
|
+
}
|
|
42
|
+
/** What may change in a profile: what the player tells of themselves, and their names on the sites, each one written whole. */
|
|
43
|
+
export type ProfileChanges = Partial<ProfileFields> & {
|
|
44
|
+
readonly accounts?: Accounts;
|
|
45
|
+
};
|
|
46
|
+
/** The profiles in the data folder, by their folders' names. */
|
|
47
|
+
export declare function listProfiles(root: string): PlayerProfile[];
|
|
48
|
+
/**
|
|
49
|
+
* Makes the first profile when there is none, named after the system's account and new until the player completes it (D-71). Two processes starting
|
|
50
|
+
* together make one: the second finds its folder taken.
|
|
51
|
+
*/
|
|
52
|
+
export declare function ensureProfile(root: string, account: string): void;
|
|
53
|
+
/** The profile in use: the one active.json names, else the first. */
|
|
54
|
+
export declare function activeProfile(root: string): PlayerProfile;
|
|
55
|
+
/** Where the games are: the folder of the profile in use. */
|
|
56
|
+
export declare function gameFolder(root: string): string;
|
|
57
|
+
/** A profile's folder. */
|
|
58
|
+
export declare function profileFolder(root: string, id: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Makes a profile, its folder named from the player's name, and puts it in use unless told not to; the one Chesspal made, while new, becomes it instead,
|
|
61
|
+
* with its games, and its folder takes the player's name too (D-71).
|
|
62
|
+
*/
|
|
63
|
+
export declare function createProfile(root: string, fields: ProfileFields, use?: boolean): PlayerProfile;
|
|
64
|
+
/** Every profile's folder, where games may be. */
|
|
65
|
+
export declare function gameFolders(root: string): string[];
|
|
66
|
+
/** Puts a profile in use. */
|
|
67
|
+
export declare function activateProfile(root: string, id: string): PlayerProfile;
|
|
68
|
+
/** Changes what a profile says of the player, keeping the rest of profile.md as it was written: its other fields and the text below them. */
|
|
69
|
+
export declare function updateProfile(root: string, id: string, changes: ProfileChanges): PlayerProfile;
|