chesspal 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/cli.js +6 -6
  3. package/dist/commands/{analyse-game.d.ts → analysis/analyse.d.ts} +2 -2
  4. package/dist/commands/{analyse-game.js → analysis/analyse.js} +7 -11
  5. package/dist/commands/{annotate-game.d.ts → analysis/annotate.d.ts} +1 -1
  6. package/dist/commands/{annotate-game.js → analysis/annotate.js} +6 -9
  7. package/dist/commands/{delete-review.d.ts → analysis/delete-review.d.ts} +1 -1
  8. package/dist/commands/{delete-review.js → analysis/delete-review.js} +5 -5
  9. package/dist/commands/analysis/index.d.ts +4 -0
  10. package/dist/commands/analysis/index.js +5 -0
  11. package/dist/commands/{study-games.d.ts → analysis/study-games.d.ts} +1 -1
  12. package/dist/commands/{study-games.js → analysis/study-games.js} +4 -5
  13. package/dist/commands/{agents.d.ts → answers/agents.d.ts} +4 -4
  14. package/dist/commands/{agents.js → answers/agents.js} +13 -9
  15. package/dist/commands/{clock.d.ts → answers/clock.d.ts} +2 -2
  16. package/dist/commands/{clock.js → answers/clock.js} +2 -2
  17. package/dist/commands/{drawings.d.ts → answers/drawings.d.ts} +1 -1
  18. package/dist/commands/{drawings.js → answers/drawings.js} +1 -1
  19. package/dist/commands/answers/index.d.ts +12 -0
  20. package/dist/commands/answers/index.js +14 -0
  21. package/dist/commands/{lead-input.d.ts → answers/lead-input.d.ts} +1 -1
  22. package/dist/commands/{lead-input.js → answers/lead-input.js} +1 -1
  23. package/dist/commands/{answer-lines.d.ts → answers/lines.d.ts} +2 -2
  24. package/dist/commands/{answer-lines.js → answers/lines.js} +4 -4
  25. package/dist/commands/{opening-book.d.ts → answers/opening-book.d.ts} +1 -1
  26. package/dist/commands/{opening-book.js → answers/opening-book.js} +3 -3
  27. package/dist/commands/{play-move.d.ts → answers/play-move.d.ts} +2 -2
  28. package/dist/commands/{play-move.js → answers/play-move.js} +3 -3
  29. package/dist/commands/{say.d.ts → answers/say.d.ts} +3 -3
  30. package/dist/commands/{say.js → answers/say.js} +4 -4
  31. package/dist/commands/{speech.js → answers/speech.js} +1 -1
  32. package/dist/commands/{study.d.ts → answers/study.d.ts} +3 -3
  33. package/dist/commands/{study.js → answers/study.js} +3 -3
  34. package/dist/commands/{game-summary.d.ts → answers/summary.d.ts} +2 -2
  35. package/dist/commands/{game-summary.js → answers/summary.js} +4 -4
  36. package/dist/commands/{view.d.ts → answers/view.d.ts} +1 -1
  37. package/dist/commands/{ai-move.d.ts → game/ai-move.d.ts} +2 -2
  38. package/dist/commands/{ai-move.js → game/ai-move.js} +6 -11
  39. package/dist/commands/{coach.d.ts → game/coach.d.ts} +1 -1
  40. package/dist/commands/{coach.js → game/coach.js} +7 -13
  41. package/dist/commands/{draw-offer.d.ts → game/draw-offer.d.ts} +1 -1
  42. package/dist/commands/{draw-offer.js → game/draw-offer.js} +4 -4
  43. package/dist/commands/{end-game.d.ts → game/end.d.ts} +2 -2
  44. package/dist/commands/{end-game.js → game/end.js} +5 -9
  45. package/dist/commands/{export-game.d.ts → game/export.d.ts} +1 -1
  46. package/dist/commands/{export-game.js → game/export.js} +4 -4
  47. package/dist/commands/game/index.d.ts +11 -0
  48. package/dist/commands/game/index.js +13 -0
  49. package/dist/commands/{levels.d.ts → game/levels.d.ts} +3 -3
  50. package/dist/commands/{levels.js → game/levels.js} +3 -3
  51. package/dist/commands/{look.d.ts → game/look.d.ts} +3 -4
  52. package/dist/commands/{look.js → game/look.js} +5 -10
  53. package/dist/commands/{new-game.d.ts → game/new.d.ts} +3 -4
  54. package/dist/commands/{new-game.js → game/new.js} +17 -13
  55. package/dist/commands/{page-link.d.ts → game/page-link.d.ts} +1 -1
  56. package/dist/commands/{player-move.d.ts → game/player-move.d.ts} +2 -2
  57. package/dist/commands/{player-move.js → game/player-move.js} +4 -8
  58. package/dist/commands/{ponder.d.ts → game/ponder.d.ts} +3 -3
  59. package/dist/commands/{ponder.js → game/ponder.js} +6 -9
  60. package/dist/commands/{position.d.ts → game/position.d.ts} +2 -2
  61. package/dist/commands/{position.js → game/position.js} +5 -7
  62. package/dist/commands/{status.d.ts → game/status.d.ts} +2 -4
  63. package/dist/commands/{status.js → game/status.js} +12 -17
  64. package/dist/commands/index.d.ts +6 -17
  65. package/dist/commands/index.js +11 -38
  66. package/dist/commands/{delete-game.d.ts → profiles/delete-game.d.ts} +1 -1
  67. package/dist/commands/{delete-game.js → profiles/delete-game.js} +3 -3
  68. package/dist/commands/profiles/index.d.ts +4 -0
  69. package/dist/commands/profiles/index.js +5 -0
  70. package/dist/commands/{past-games.d.ts → profiles/past-games.d.ts} +1 -1
  71. package/dist/commands/{past-games.js → profiles/past-games.js} +5 -5
  72. package/dist/commands/{profiles.d.ts → profiles/profiles.d.ts} +7 -7
  73. package/dist/commands/{profiles.js → profiles/profiles.js} +4 -4
  74. package/dist/commands/{ratings.d.ts → profiles/ratings.d.ts} +1 -1
  75. package/dist/commands/{ratings.js → profiles/ratings.js} +2 -2
  76. package/dist/commands/{context.js → registry/context.js} +2 -2
  77. package/dist/commands/registry/index.d.ts +2 -0
  78. package/dist/commands/registry/index.js +3 -0
  79. package/dist/commands/setup/index.d.ts +2 -0
  80. package/dist/commands/setup/index.js +3 -0
  81. package/dist/commands/{init.d.ts → setup/init.d.ts} +1 -1
  82. package/dist/commands/{init.js → setup/init.js} +2 -3
  83. package/dist/commands/{instructions.d.ts → setup/instructions.d.ts} +2 -2
  84. package/dist/commands/{instructions.js → setup/instructions.js} +3 -3
  85. package/dist/commands/{ai-say.d.ts → talk/ai-say.d.ts} +2 -3
  86. package/dist/commands/{ai-say.js → talk/ai-say.js} +5 -9
  87. package/dist/commands/talk/index.d.ts +2 -0
  88. package/dist/commands/talk/index.js +3 -0
  89. package/dist/commands/{player-say.d.ts → talk/player-say.d.ts} +1 -1
  90. package/dist/commands/{player-say.js → talk/player-say.js} +4 -4
  91. package/dist/page/app/app.js +53 -21
  92. package/dist/page/app/served.js +15 -3
  93. package/dist/page/avatars/torretta.js +10 -3
  94. package/dist/page/dialogs/dialogs.css +10 -0
  95. package/dist/page/dialogs/profiles.js +1 -5
  96. package/dist/page/dialogs/settings.js +18 -4
  97. package/dist/page/game/column.js +1 -1
  98. package/dist/page/game/game.css +26 -3
  99. package/dist/page/guide/blocks.js +13 -2
  100. package/dist/page/guide/credits.js +6 -0
  101. package/dist/page/guide/drawings/analysis.js +13 -0
  102. package/dist/page/guide/drawings/drawings.css +329 -0
  103. package/dist/page/guide/drawings/drawings.js +15 -0
  104. package/dist/page/guide/drawings/game.js +15 -0
  105. package/dist/page/guide/drawings/helps.js +13 -0
  106. package/dist/page/guide/drawings/how-it-works.js +13 -0
  107. package/dist/page/guide/drawings/parts.js +103 -0
  108. package/dist/page/guide/drawings/players.js +19 -0
  109. package/dist/page/guide/drawings/talk.js +9 -0
  110. package/dist/page/guide/en.md +39 -25
  111. package/dist/page/guide/guide.css +123 -91
  112. package/dist/page/guide/guide.js +47 -25
  113. package/dist/page/guide/it.md +39 -25
  114. package/dist/page/guide/markdown.js +5 -0
  115. package/dist/page/helps/helps.css +201 -88
  116. package/dist/page/helps/helps.js +50 -31
  117. package/dist/page/helps/view.js +13 -3
  118. package/dist/page/{guide/foot.js → layout/footer.js} +7 -8
  119. package/dist/page/layout/header.js +5 -3
  120. package/dist/page/layout/layout.css +114 -10
  121. package/dist/page/layout/window.js +6 -26
  122. package/dist/page/main.js +1 -1
  123. package/dist/page/pieces/pieces.js +5 -2
  124. package/dist/page/style.css +1 -0
  125. package/dist/page/table/table.css +69 -0
  126. package/dist/page/table/update.js +82 -0
  127. package/dist/page/table/window.js +6 -5
  128. package/dist/page/talk/chat.css +6 -6
  129. package/dist/page/talk/talk.css +17 -67
  130. package/dist/page/talk/talk.js +6 -6
  131. package/dist/page/talk/voice.js +12 -0
  132. package/dist/page/text.js +78 -20
  133. package/dist/page/theme.css +2 -0
  134. package/dist/server/{bell.js → bell/bell.js} +17 -4
  135. package/dist/server/bell/index.d.ts +1 -0
  136. package/dist/server/bell/index.js +2 -0
  137. package/dist/server/{caller.d.ts → mcp/caller.d.ts} +1 -1
  138. package/dist/server/{caller.js → mcp/caller.js} +1 -1
  139. package/dist/server/mcp/index.d.ts +1 -0
  140. package/dist/server/mcp/index.js +2 -0
  141. package/dist/server/{mcp.d.ts → mcp/mcp.d.ts} +1 -1
  142. package/dist/server/{mcp.js → mcp/mcp.js} +9 -9
  143. package/dist/server/page/attach.js +8 -3
  144. package/dist/server/page/game.js +19 -3
  145. package/dist/server/page/http.d.ts +1 -1
  146. package/dist/server/page/index.d.ts +3 -0
  147. package/dist/server/page/index.js +3 -0
  148. package/dist/server/page/page.d.ts +12 -3
  149. package/dist/server/page/page.js +26 -5
  150. package/dist/server/page/table.d.ts +7 -1
  151. package/dist/server/page/table.js +79 -3
  152. package/dist/server/page/update.d.ts +18 -0
  153. package/dist/server/page/update.js +40 -0
  154. package/dist/server/table/browser.d.ts +1 -1
  155. package/dist/server/table/browser.js +1 -1
  156. package/dist/server/table/hosts/chats.d.ts +1 -1
  157. package/dist/server/table/hosts/chats.js +2 -2
  158. package/dist/server/table/hosts/index.d.ts +1 -1
  159. package/dist/server/table/hosts/index.js +1 -1
  160. package/dist/server/table/hosts/play.d.ts +8 -1
  161. package/dist/server/table/hosts/play.js +40 -4
  162. package/dist/server/table/hosts/seat.d.ts +5 -1
  163. package/dist/server/table/hosts/seat.js +1 -1
  164. package/dist/server/table/index.d.ts +3 -2
  165. package/dist/server/table/index.js +3 -2
  166. package/dist/server/table/launch.d.ts +5 -2
  167. package/dist/server/table/launch.js +6 -3
  168. package/dist/server/table/link.d.ts +1 -1
  169. package/dist/server/table/link.js +3 -3
  170. package/dist/server/table/table.d.ts +4 -5
  171. package/dist/server/table/table.js +15 -12
  172. package/dist/server/table/update.d.ts +17 -0
  173. package/dist/server/table/update.js +77 -0
  174. package/dist/sites/index.d.ts +1 -1
  175. package/dist/sites/index.js +2 -2
  176. package/dist/version.d.ts +4 -0
  177. package/dist/version.js +12 -1
  178. package/package.json +1 -1
  179. /package/dist/commands/{speech.d.ts → answers/speech.d.ts} +0 -0
  180. /package/dist/commands/{view.js → answers/view.js} +0 -0
  181. /package/dist/commands/{page-link.js → game/page-link.js} +0 -0
  182. /package/dist/commands/{context.d.ts → registry/context.d.ts} +0 -0
  183. /package/dist/commands/{registry.d.ts → registry/registry.d.ts} +0 -0
  184. /package/dist/commands/{registry.js → registry/registry.js} +0 -0
  185. /package/dist/server/{bell.d.ts → bell/bell.d.ts} +0 -0
@@ -0,0 +1,103 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
2
+ import { useContext, useId } from "preact/hooks";
3
+ import { ChosenSet, pieceSymbol } from "../../pieces/pieces.js";
4
+ /** The top-left corner of a square: `file` 0 to 7 from a, `rank` 1 to 8, White at the bottom. */
5
+ export function corner(grid, file, rank) {
6
+ return { x: grid.x + file * grid.cell, y: grid.y + (8 - rank) * grid.cell };
7
+ }
8
+ /** The centre of a square. */
9
+ export function centre(grid, file, rank) {
10
+ const { x, y } = corner(grid, file, rank);
11
+ return { x: x + grid.cell / 2, y: y + grid.cell / 2 };
12
+ }
13
+ /** A card of the page, its corners as the page's. */
14
+ export function Card({ x, y, width, height, class: name = "paper" }) {
15
+ return _jsx("rect", { class: name, x: x, y: y, width: width, height: height, rx: "6" });
16
+ }
17
+ /** A line of text, as a rounded bar: `strong` for a title or a name. */
18
+ export function Bar({ x, y, width, strong = false, class: name }) {
19
+ return _jsx("rect", { class: name ?? (strong ? "bar strong" : "bar"), x: x, y: y, width: width, height: "5", rx: "2.5" });
20
+ }
21
+ /** The board's squares, light and dark. */
22
+ export function Board({ grid, children }) {
23
+ return (_jsxs("g", { children: [_jsx("rect", { class: "light", x: grid.x, y: grid.y, width: grid.cell * 8, height: grid.cell * 8 }), _jsx("path", { class: "dark", d: darkSquares(grid) }), children] }));
24
+ }
25
+ /** A square filled with one of the board's colours: the last move, a hint. */
26
+ export function Square({ grid, file, rank, class: name }) {
27
+ const { x, y } = corner(grid, file, rank);
28
+ return _jsx("rect", { class: name, x: x, y: y, width: grid.cell, height: grid.cell });
29
+ }
30
+ /** A piece of the chosen set by its FEN letter, on a square of the board. */
31
+ export function PieceOn({ grid, file, rank, letter, class: name }) {
32
+ const { x, y } = corner(grid, file, rank);
33
+ return _jsx(PieceAt, { x: x, y: y, size: grid.cell, letter: letter, class: name });
34
+ }
35
+ /** A piece of the chosen set anywhere in the drawing, `size` wide, coloured by the settings as the board's. */
36
+ export function PieceAt({ x, y, size, letter, class: name = "" }) {
37
+ const set = useContext(ChosenSet);
38
+ const side = letter === letter.toUpperCase() ? "white" : "black";
39
+ return _jsx("use", { href: pieceSymbol(letter, set), x: x, y: y, width: size, height: size, class: `piece ${side} ${name}` });
40
+ }
41
+ /** The pieces of a position, one string a rank from the 8th down, "." for an empty square: "....k..." */
42
+ export function Pieces({ grid, ranks }) {
43
+ return (_jsx("g", { children: ranks.flatMap((row, index) => [...row].map((letter, file) => letter === "." ? null : _jsx(PieceOn, { grid: grid, file: file, rank: 8 - index, letter: letter }, `${file}${index}`))) }));
44
+ }
45
+ /** An arrow from one point to another, its shaft `width` wide, as the AI draws them on the board. */
46
+ export function Arrow({ from, to, width, class: name }) {
47
+ return _jsx("polygon", { class: name, points: arrowPoints(from, to, width) });
48
+ }
49
+ /** The Torretta with its neutral face, `size` wide, its top-left corner at x, y; as a `bust`, as on a player's card, in a disc `size` wide, clipped to it. */
50
+ export function Torretta({ x, y, size, bust = false }) {
51
+ const clip = useId();
52
+ if (bust) {
53
+ return (_jsxs("g", { transform: `translate(${x} ${y}) scale(${size / 96}) translate(-16 -8)`, children: [_jsx("clipPath", { id: clip, children: _jsx("circle", { cx: "64", cy: "56", r: "48" }) }), _jsx("circle", { class: "words", cx: "64", cy: "56", r: "48" }), _jsx("g", { "clip-path": `url(#${clip})`, children: _jsx(Figure, {}) })] }));
54
+ }
55
+ return (_jsx("g", { transform: `translate(${x} ${y}) scale(${size / 128})`, children: _jsx(Figure, {}) }));
56
+ }
57
+ /** A person's head and shoulders in a disc of `tone`, a class of drawings.css; `ring` draws the accent around it. */
58
+ export function Face({ x, y, r, tone, ring = false }) {
59
+ const side = r * 0.7;
60
+ const low = y + r * 0.71;
61
+ return (_jsxs("g", { children: [ring && _jsx("circle", { class: "chosen", cx: x, cy: y, r: r + 3.5 }), _jsx("circle", { class: tone, cx: x, cy: y, r: r }), _jsx("circle", { class: "person", cx: x, cy: y - r * 0.2, r: r * 0.34 }), _jsx("path", { class: "person", d: `M${x - side} ${low}Q${x - side} ${y + r * 0.22} ${x} ${y + r * 0.22}Q${x + side} ${y + r * 0.22} ${x + side} ${low}A${r} ${r} 0 0 1 ${x - side} ${low}Z` })] }));
62
+ }
63
+ /** A move's badge, a disc and its sign: best (a tick), mistake (?) or blunder (??). */
64
+ export function Badge({ x, y, r, kind }) {
65
+ return (_jsxs("g", { children: [_jsx("circle", { class: `judgement ${kind}`, cx: x, cy: y, r: r }), kind === "best" && _jsx("path", { class: "sign", style: { strokeWidth: r * 0.28 }, d: `M${x - r * 0.45} ${y + r * 0.02}L${x - r * 0.12} ${y + r * 0.36}L${x + r * 0.45} ${y - r * 0.32}` }), kind === "mistake" && _jsx(Question, { x: x, y: y, size: r }), kind === "blunder" && (_jsxs(_Fragment, { children: [_jsx(Question, { x: x - r * 0.36, y: y, size: r * 0.8 }), _jsx(Question, { x: x + r * 0.36, y: y, size: r * 0.8 })] }))] }));
66
+ }
67
+ /** A small clock face with its two hands. */
68
+ export function Clock({ x, y, r, class: name = "clock" }) {
69
+ return (_jsxs("g", { class: name, children: [_jsx("circle", { cx: x, cy: y, r: r }), _jsx("path", { d: `M${x} ${y - r * 0.6}V${y}L${x + r * 0.45} ${y + r * 0.3}` })] }));
70
+ }
71
+ /** A chevron pointing left or right, centred on x, y. */
72
+ export function Chevron({ x, y, size, left = false }) {
73
+ const reach = left ? -size / 2 : size / 2;
74
+ return _jsx("path", { d: `M${x - reach / 2} ${y - size / 2}L${x + reach / 2} ${y}L${x - reach / 2} ${y + size / 2}` });
75
+ }
76
+ /** The Torretta's figure on its own grid of 128, its disc's frame 16 8 96 96 as the page's bust. */
77
+ function Figure() {
78
+ return (_jsxs("g", { class: "tower", children: [_jsx("path", { class: "antenna", d: "M64 31V19" }), _jsx("circle", { class: "light-bulb", cx: "64", cy: "16", r: "5" }), _jsx("rect", { class: "shade", x: "29", y: "64", width: "12", height: "26", rx: "2" }), _jsx("rect", { class: "shade", x: "87", y: "64", width: "12", height: "26", rx: "2" }), _jsx("path", { class: "body", d: "M34 30H47V40H57V30H71V40H81V30H94V54L89 58L92 106H36L39 58L34 54Z" }), _jsx("rect", { class: "shade", x: "30", y: "104", width: "68", height: "12", rx: "4" }), _jsx("rect", { class: "screen", x: "44", y: "63", width: "40", height: "32", rx: "7" }), _jsx("circle", { class: "features", cx: "55", cy: "76", r: "4.6" }), _jsx("circle", { class: "features", cx: "73", cy: "76", r: "4.6" }), _jsx("rect", { class: "features", x: "58", y: "85.4", width: "12", height: "3.2", rx: "1.6" })] }));
79
+ }
80
+ /** A question mark on a grid of one, `size` wide, centred on x, y. */
81
+ function Question({ x, y, size }) {
82
+ return (_jsxs("g", { class: "sign", transform: `translate(${x} ${y}) scale(${size})`, children: [_jsx("path", { style: { strokeWidth: 0.24 }, d: "M-0.3 -0.22Q-0.3 -0.55 0 -0.55Q0.3 -0.55 0.3 -0.25Q0.3 -0.02 0 0.08V0.2" }), _jsx("circle", { class: "dot", cy: "0.48", r: "0.14" })] }));
83
+ }
84
+ function darkSquares(grid) {
85
+ const steps = [];
86
+ for (let row = 0; row < 8; row++) {
87
+ for (let column = 0; column < 8; column++) {
88
+ if ((row + column) % 2 === 1) {
89
+ steps.push(`M${grid.x + column * grid.cell} ${grid.y + row * grid.cell}h${grid.cell}v${grid.cell}h${-grid.cell}z`);
90
+ }
91
+ }
92
+ }
93
+ return steps.join("");
94
+ }
95
+ function arrowPoints(from, to, width) {
96
+ const length = Math.hypot(to.x - from.x, to.y - from.y);
97
+ const along = { x: (to.x - from.x) / length, y: (to.y - from.y) / length };
98
+ const across = { x: -along.y, y: along.x };
99
+ const head = width * 2.2;
100
+ const neck = { x: to.x - along.x * head, y: to.y - along.y * head };
101
+ const at = (base, side) => `${(base.x + across.x * side).toFixed(1)},${(base.y + across.y * side).toFixed(1)}`;
102
+ return [at(from, width / 2), at(neck, width / 2), at(neck, width * 1.15), `${to.x},${to.y}`, at(neck, -width * 1.15), at(neck, -width / 2), at(from, -width / 2)].join(" ");
103
+ }
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
2
+ // The players: the player's face in the header, ringed, and under it the window of the players, the one in use ticked, with the pencil to their profile
3
+ import { Bar, Card, Face, Torretta } from "./parts.js";
4
+ /** The players in the window, from the top: the player's own is the second. */
5
+ const players = [{ tone: "tone-2", name: 58 }, { tone: "tone-player", name: 46 }, { tone: "tone-6", name: 66 }];
6
+ const own = 1;
7
+ const row = { x: 136, y: 102, width: 298, height: 28, step: 34 };
8
+ /** A strip of the header with the player's face at its end, and the window «Chi gioca?» it opens. */
9
+ export function Players() {
10
+ return (_jsxs("svg", { class: "guide-art", viewBox: "0 0 480 220", "aria-hidden": "true", children: [_jsx(Card, { x: 16, y: 10, width: 448, height: 36 }), _jsx(Torretta, { x: 22, y: 11, size: 34 }), _jsx("rect", { class: "quote", x: "64", y: "19", width: "60", height: "18", rx: "9" }), [350, 376, 402].map((x) => _jsx("rect", { class: "field", x: x, y: "18", width: "20", height: "20", rx: "5" }, x)), _jsx(Face, { x: 442, y: 28, r: 11, tone: "tone-player", ring: true }), _jsx("rect", { class: "lift-shadow", x: "121", y: "63", width: "330", height: "150", rx: "6" }), _jsx(Card, { x: 120, y: 60, width: 330, height: 150 }), _jsx(Bar, { x: 136, y: 73, width: 62, strong: true }), _jsx("path", { class: "soft-line", d: "M426 70L434 78M434 70L426 78" }), _jsx(Bar, { x: 136, y: 88, width: 120 }), players.map((player, index) => _jsx(PlayerRow, { index: index, tone: player.tone, name: player.name }, player.tone))] }));
11
+ }
12
+ /** A line of the window: a face and a name; the player's own is ticked and has the pencil beside it. */
13
+ function PlayerRow({ index, tone, name }) {
14
+ const y = row.y + index * row.step;
15
+ const middle = y + row.height / 2;
16
+ const mine = index === own;
17
+ const width = mine ? row.width - row.height - 6 : row.width;
18
+ return (_jsxs("g", { children: [_jsx(Card, { x: row.x, y: y, width: width, height: row.height }), _jsx(Face, { x: row.x + 16, y: middle, r: 9, tone: tone }), _jsx(Bar, { x: row.x + 32, y: middle - 2.5, width: name, strong: true }), mine && (_jsxs(_Fragment, { children: [_jsx("path", { class: "tick", d: `M${row.x + width - 26} ${middle}l4 4l7 -8` }), _jsx(Card, { x: row.x + row.width - row.height, y: y, width: row.height, height: row.height }), _jsxs("g", { class: "pencil", transform: `translate(${row.x + row.width - row.height + 6} ${y + 6}) scale(0.667)`, children: [_jsx("path", { d: "M4 20L5 15L15.5 4.5L19.5 8.5L9 19Z" }), _jsx("path", { d: "M13.5 6.5L17.5 10.5" })] })] }))] }));
19
+ }
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
+ // Talking to the AI: under its name, the player's question, its answer, and the box where the player writes, beside the board
3
+ import { Bar, Board, Card, Chevron, Pieces, Torretta } from "./parts.js";
4
+ const grid = { x: 256, y: 10, cell: 30 };
5
+ const position = [".....rk.", ".....ppp", "..n.....", "....p...", "..B.P...", ".....N..", ".....PPP", "......K."];
6
+ /** The AI's card, the talk under it and the box with its send button, the board cut by the drawing's edge. */
7
+ export function Talk() {
8
+ return (_jsxs("svg", { class: "guide-art", viewBox: "0 0 480 220", "aria-hidden": "true", children: [_jsx(Board, { grid: grid, children: _jsx(Pieces, { grid: grid, ranks: position }) }), _jsx(Card, { x: 16, y: 10, width: 220, height: 46 }), _jsx(Torretta, { x: 18, y: 13, size: 36, bust: true }), _jsx(Bar, { x: 58, y: 24, width: 56, strong: true }), _jsx(Bar, { x: 58, y: 35, width: 34 }), _jsx(Card, { x: 86, y: 66, width: 150, height: 24 }), _jsx(Bar, { x: 96, y: 75.5, width: 110, strong: true }), _jsx(Card, { x: 16, y: 100, width: 200, height: 42, class: "words" }), _jsx(Bar, { x: 26, y: 111, width: 170, class: "bar on-words" }), _jsx(Bar, { x: 26, y: 123, width: 120, class: "bar on-words" }), _jsx(Card, { x: 16, y: 154, width: 220, height: 56, class: "paper focused" }), _jsx(Bar, { x: 28, y: 168, width: 104 }), _jsx("rect", { class: "caret", x: "136", y: "163", width: "2", height: "15", rx: "1" }), _jsx("rect", { class: "accent", x: "176", y: "187", width: "50", height: "16", rx: "8" }), _jsx(Bar, { x: 186, y: 192.5, width: 18, class: "bar on-accent" }), _jsx("g", { class: "on-accent-line", children: _jsx(Chevron, { x: 213, y: 195, size: 7 }) })] }));
9
+ }
@@ -1,9 +1,11 @@
1
1
  # Chesspal: the guide
2
2
 
3
- With **Chesspal** you play chess against an **AI**, on a real board in your browser, and learn with it. This guide is for players: you do not need to know how to program.
3
+ With **Chesspal** you play chess against an **AI**, on a real board, and learn with it. This guide is for players: you do not need to know how to program.
4
4
 
5
5
  ## How it works
6
6
 
7
+ ![The page with the board and the AI's chat window, joined by a thread](how-it-works)
8
+
7
9
  | Who | What they do |
8
10
  |---|---|
9
11
  | **You** | You move on the board and talk with the AI. |
@@ -14,53 +16,65 @@ There are two windows: this **page**, with the board, and the AI's **chat**, in
14
16
 
15
17
  No chess engine plays for the AI: every move and every judgment is its own. Chesspal checks that each move is legal and tells the AI what is on the board: the pieces attacked and defended, the pins, the opening's name.
16
18
 
17
- ## Quick start
18
-
19
- 1. Install **Node.js** from [nodejs.org](https://nodejs.org), the recommended (LTS) version, and an AI with your own subscription: **Claude Code** or **Codex**.
20
- 2. Open a terminal, the window where you type commands (on Windows, Command Prompt: press Start, type `cmd`, press Enter; on macOS, Terminal), and type `npm install -g chesspal`, then `chesspal`: this page opens. The first time it offers an icon on your desktop, to open it with a double click.
21
- 3. Press **Claude Code** or **Codex**: the AI's chat opens in a window of its own. Keep it open while you play.
22
- 4. Press **New game**, choose your colour, the clock and the AI's level, and press **Start**.
23
-
24
- ## If you are lost
25
-
26
- - **The AI does not answer**: look at its window. If it is asking you something, answer there; if you closed it, press **Claude Code** or **Codex** again.
27
- - **The page does not open**: double-click Chesspal's icon, or open it as in the [Quick start](#quick-start).
28
- - **Your games** are in a folder on your computer: **Who's playing?**, from your picture at the top right, shows where, and **Open the folder** opens it.
19
+ ### Getting started
29
20
 
30
- ## The AI's chat
31
-
32
- - The page opens the AI's **chat** with its buttons, in a window of its own: there the AI thinks and writes. Beside the buttons you choose its model (the version of the AI) and how much it reasons: the more it reasons, the slower it plays.
33
- - You talk with the AI in the box under its name, a few words with each move: it reads them with your move. You can also write to it in its window.
34
- - A **move written** in the chat counts too: `e4`, `Nf3`, with the English letters of the pieces (K Q R B N), or in words.
35
- - At each **new game**, the chat the page opened starts again clean by itself, once the AI has stopped thinking: a long chat makes the AI slower.
21
+ 1. Click the **AI's name**, at the top left, and choose its chat among those on your computer: **Claude Code** or **Codex**. It opens in a window of its own: keep it open while you play.
22
+ 2. Press **New game**, choose your colour, the clock and the AI's level, and press **Start**.
23
+ 3. Move: the AI answers on the board, and with a few words under its name.
36
24
 
37
25
  ## The game
38
26
 
27
+ ![The board with the dots of the legal moves and a piece moving](game)
28
+
39
29
  - **Move** by dragging a piece, or by clicking the piece and then its square. The dots show the legal moves; when a move is not allowed, the page says why.
40
30
  - **The clock**, if you chose one, starts with **Start**. The AI has its own and knows how much time it has left.
41
31
  - **Offer a draw** on your turn, once each side has moved; **Resign** ends the game.
42
- - **The helps**: with "The AI teaches as you play", in the settings, the **Helps** card shows the pieces in danger, the pins and the pawns, and the AI, as your coach, gives you an idea. The AI draws coloured arrows on the board: the **?** beside the moves explains every mark.
43
32
  - **Flip** turns the board round; **PGN** saves the moves in the file every chess site reads, to open on Lichess or Chess.com.
44
33
 
34
+ ## Talking with the AI
35
+
36
+ ![The box to write in under the AI's name, and its answer](talk)
37
+
38
+ - You talk with the AI in the **box under its name**, a few words with each move: it reads them with your move. You can also write to it in its window.
39
+ - A **move written** in the chat counts too: `e4`, `Nf3`, with the English letters of the pieces (K Q R B N), or in words.
40
+ - **The AI's name** opens the choice of its chat: Claude Code or Codex, the model (which AI: some are faster, others stronger) and how much it reasons. The more it reasons, the slower it plays. If you change them, the chat starts afresh in the same window: the AI forgets what you talked about, and the game stays as it is.
41
+ - At each **new game**, the chat the page opened starts afresh by itself, once the AI has stopped thinking: a long chat makes the AI slower.
42
+
43
+ ## Helps and marks
44
+
45
+ ![Coloured arrows and badges on the board, beside the helps' card](helps)
46
+
47
+ - With **"The AI teaches as you play"**, in the settings, the **Helps** card shows the pieces in danger, the pins and the pawns, and the AI, as your coach, gives you an idea.
48
+ - The AI draws **coloured arrows** on the board: the **?** beside the moves explains every mark.
49
+ - In the review, a **badge** on a move gives the AI's judgment: a great move, an inaccuracy, a blunder.
50
+
45
51
  ## Review and analysis
46
52
 
47
- - When the game is over, press **Analyse the game**: the AI goes over it and puts its judgments and notes on the moves. Read them by stepping through the moves with the arrows.
53
+ ![The bar that steps through the moves, and the judgments on the moves](analysis)
54
+
55
+ - When the game is over, press **Analyse the game**: the AI goes over it and puts its judgments and notes on the moves. Read them by stepping through the moves with the arrows at the foot of the column, or by clicking a move.
48
56
  - **Analyses**, in the header, opens your analyses, and loads a game played elsewhere: paste its PGN, or choose a .pgn file.
49
57
  - Ask the AI about the game in the box under its name.
50
58
  - **Annotated PGN** saves the game with its comments.
51
59
 
52
60
  ## Players and profile
53
61
 
54
- - **Who's playing?**: your picture at the top right chooses a player or adds one. Each has their own games and settings.
55
- - **Your profile**: a click on your picture beside the board, or the pencil in **Who's playing?**, changes your picture, your name, how you play, your names on Lichess and Chess.com and your FIDE rating.
62
+ ![Your picture at the top right and the Who's playing? window](players)
63
+
64
+ - **Who's playing?**: your picture at the top right, or your name beside the board, opens the list of the players: there you choose one or add one. Each has their own games and settings.
65
+ - **Your profile**: in **Who's playing?**, the pencil beside your name changes your picture, your name, how you play, your names on Lichess and Chess.com and your FIDE rating.
56
66
  - **Your rating**: from your names there, Chesspal reads your public rating, the one of your rapid games if you play them, and tells the AI. No passwords: anyone can see that rating on the site. Without a name there, the AI knows how you play from **How do you play?**
57
67
  - **Your FIDE rating**, if you play tournaments, you type yourself: no site gives it to Chesspal. The AI reads it beside the site's, each on its own.
58
68
  - If you load a game played on Lichess or Chess.com, Chesspal knows which colour you played.
59
69
 
60
70
  ## Questions and problems
61
71
 
62
- - **The AI is slow**: it really thinks over each move. Choose a faster model, or less reasoning, beside the chat's buttons.
72
+ - **The AI does not answer, and its clock runs**: look at its window, which may have gone behind the others: find it in the bar at the bottom. If it is asking you something, answer there; if you closed it, click the AI's name and open another.
73
+ - **The AI is slow**: it really thinks over each move. From its name, choose a faster model, or less reasoning.
74
+ - **A piece does not move**: it is not your turn, or the move is not allowed; the page says why.
75
+ - **Closed the page?** Open it again from Chesspal's icon, on the desktop or in the menu: the game you left halfway is still there.
76
+ - **Your games** are in a folder on your computer: **Who's playing?**, from your picture at the top right, shows where, and **Open the folder** opens it. For a backup copy it, with the chat and the page closed.
77
+ - **A new version of Chesspal**: an arrow at the top tells you, and installs it between games.
63
78
  - **What it costs**: Chesspal is free; the AI uses your own subscription, and you pay nothing more.
64
79
  - **Can the AI play an illegal move?** No: Chesspal checks every move. Its judgments are its own, though, and an AI can be wrong, like a person.
65
- - **A backup**: copy the folder of your games, with the chat and the page closed.
66
80
  - **Something does not work?** Tell us on [GitHub](https://github.com/stefanocaronia/chesspal/issues): what you did, what you expected, what happened. GitHub is the site where Chesspal is made: you write there with a free account, and anyone can read it.
@@ -1,11 +1,19 @@
1
- /* The guide: a tall dialog, an index of chips, each part folding under its title, and the foot with who made Chesspal and the credits (Zoe) */
1
+ /* The guide: a wide dialog, the index of its pages beside the page shown, and at the dialog's foot, on every page, the arrows to the one before and after
2
+ (Zoe) */
2
3
 
3
4
  .dialog:has(> .guide) {
5
+ width: min(900px, calc(100vw - 32px));
4
6
  height: calc(100vh - 48px);
5
7
  max-height: 90vh;
6
8
  }
7
9
 
10
+ /* As tall as the dialog under its title, so that a short page keeps its arrows at the foot */
8
11
  .guide {
12
+ display: grid;
13
+ grid-template-columns: 200px minmax(0, 1fr);
14
+ gap: 28px;
15
+ align-items: start;
16
+ min-height: calc(100% - 60px);
9
17
  font-size: 14px;
10
18
  line-height: 1.55;
11
19
  }
@@ -36,76 +44,69 @@
36
44
  font-size: 13px;
37
45
  }
38
46
 
39
- /* A heading a chip or a link brings into sight stays under the dialog's own title */
47
+ /* A heading a link brings into sight stays under the dialog's own title */
40
48
  .guide [id] {
41
49
  scroll-margin-top: 64px;
42
50
  }
43
51
 
52
+ /* The index: the pages' titles, the one shown marked by a bar at its start; it stays in sight while the page scrolls */
44
53
  .guide-index {
54
+ position: sticky;
55
+ top: 60px;
45
56
  display: flex;
46
- flex-wrap: wrap;
47
- gap: 8px;
48
- margin: 4px 0 14px;
57
+ flex-direction: column;
58
+ gap: 2px;
59
+ margin-top: 4px;
49
60
  }
50
61
 
51
62
  .guide-chip {
52
63
  min-height: 32px;
53
- padding: 5px 12px;
54
- border: 1px solid var(--line);
55
- border-radius: 999px;
56
- background: var(--card);
57
- color: var(--ink);
64
+ padding: 6px 12px;
65
+ border: 0;
66
+ border-radius: 0 8px 8px 0;
67
+ background: none;
68
+ color: var(--soft);
58
69
  font: inherit;
59
- font-size: 13px;
70
+ font-size: 13.5px;
71
+ text-align: start;
72
+ cursor: pointer;
60
73
  }
61
74
 
62
75
  .guide-chip:hover {
63
- border-color: var(--accent);
64
- color: var(--accent);
76
+ color: var(--ink);
65
77
  }
66
78
 
67
- /* A part: its title, a chevron that turns when it opens */
68
- .guide-part {
69
- border-top: 1px solid var(--line);
79
+ .guide-chip[aria-current="page"] {
80
+ background: var(--quote);
81
+ box-shadow: inset 3px 0 0 var(--accent);
82
+ color: var(--ink);
83
+ font-weight: 600;
70
84
  }
71
85
 
72
- .guide-part summary {
86
+ .guide-page {
73
87
  display: flex;
74
- align-items: center;
75
- gap: 8px;
76
- padding: 10px 0;
77
- cursor: pointer;
78
- list-style: none;
79
- }
80
-
81
- .guide-part summary::-webkit-details-marker {
82
- display: none;
88
+ flex-direction: column;
89
+ align-self: stretch;
83
90
  }
84
91
 
85
- .guide-part summary::before,
86
- .credits summary::before {
87
- content: "";
88
- width: 7px;
89
- height: 7px;
90
- border-right: 1.7px solid var(--soft);
91
- border-bottom: 1.7px solid var(--soft);
92
- transform: rotate(-45deg);
93
- transition: transform 0.15s;
92
+ /* The page's text grows to push the arrows to the foot */
93
+ .guide-text {
94
+ flex: 1 0 auto;
95
+ margin-bottom: 22px;
94
96
  }
95
97
 
96
- .guide-part[open] summary::before,
97
- .credits[open] summary::before {
98
- transform: rotate(45deg);
99
- }
100
-
101
- .guide-part h3 {
102
- margin: 0;
103
- font-size: 16px;
98
+ /* The page's title takes the focus when the page turns, for a screen reader: no ring, since no key brought it there */
99
+ .guide-page h3 {
100
+ margin: 4px 0 12px;
101
+ font-size: 19px;
104
102
  font-weight: 600;
103
+ outline: none;
105
104
  }
106
105
 
107
- .guide-part[open] {
108
- padding-bottom: 6px;
106
+ .guide-page h4 {
107
+ margin: 16px 0 6px;
108
+ font-size: 15px;
109
+ font-weight: 600;
109
110
  }
110
111
 
111
112
  .guide-table {
@@ -125,68 +126,99 @@
125
126
  vertical-align: top;
126
127
  }
127
128
 
128
- /* The foot: who made Chesspal, where it lives, the heart that supports it; the credits folded under it */
129
- .guide-foot {
130
- display: grid;
131
- gap: 6px;
132
- margin-top: 18px;
133
- padding-top: 14px;
129
+ /* The arrows to the page before and after, each with its title: at the foot of a short page, and at the dialog's foot over a long one */
130
+ .guide-turn {
131
+ position: sticky;
132
+ bottom: 0;
133
+ display: flex;
134
+ gap: 12px;
135
+ padding: 14px 0 4px;
134
136
  border-top: 1px solid var(--line);
135
- color: var(--soft);
136
- font-size: 12.5px;
137
- text-align: center;
138
- }
139
-
140
- .guide-foot p {
141
- margin: 0;
137
+ background: var(--card);
142
138
  }
143
139
 
144
- .foot-own {
145
- display: flex;
146
- flex-wrap: wrap;
140
+ .guide-turn button {
141
+ display: inline-flex;
147
142
  align-items: center;
148
- justify-content: center;
149
- gap: 6px 14px;
143
+ gap: 6px;
144
+ min-height: 36px;
145
+ padding: 6px 12px;
146
+ border: 1px solid var(--line);
147
+ border-radius: 8px;
148
+ background: var(--card);
149
+ color: var(--ink);
150
+ font: inherit;
151
+ font-size: 13.5px;
152
+ cursor: pointer;
150
153
  }
151
154
 
152
- .guide .foot-own a {
153
- display: inline-flex;
154
- align-items: center;
155
- gap: 5px;
156
- color: inherit;
157
- text-decoration: none;
155
+ .guide-turn button:hover {
156
+ border-color: var(--accent);
157
+ color: var(--accent);
158
158
  }
159
159
 
160
- .guide .foot-own a:hover,
161
- .guide .foot-own a:focus-visible {
162
- color: var(--ink);
160
+ .guide-turn .next {
161
+ margin-inline-start: auto;
163
162
  }
164
163
 
165
- .foot-own .icon {
164
+ .guide-turn .icon {
166
165
  width: 16px;
167
166
  height: 16px;
168
- }
167
+ fill: none;
168
+ stroke: currentColor;
169
+ stroke-width: 2;
170
+ stroke-linecap: round;
171
+ stroke-linejoin: round;
172
+ }
173
+
174
+ /* On a narrow screen the index is one row of chips over the page, scrolled sideways, its end fading where more follow; the arrows share the page's
175
+ width at its foot, each title by its arrow */
176
+ @media (max-width: 640px) {
177
+ .guide {
178
+ grid-template-columns: minmax(0, 1fr);
179
+ grid-template-rows: auto 1fr;
180
+ gap: 14px;
181
+ }
169
182
 
170
- .foot-support .icon {
171
- color: var(--low-time);
172
- }
183
+ .guide-index {
184
+ position: static;
185
+ flex-direction: row;
186
+ gap: 6px;
187
+ overflow-x: auto;
188
+ scrollbar-width: none;
189
+ mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
190
+ }
173
191
 
174
- .credits summary {
175
- display: inline-flex;
176
- align-items: center;
177
- gap: 6px;
178
- cursor: pointer;
179
- list-style: none;
180
- }
192
+ .guide-index::-webkit-scrollbar {
193
+ display: none;
194
+ }
181
195
 
182
- .credits summary::-webkit-details-marker {
183
- display: none;
184
- }
196
+ .guide-chip {
197
+ flex: none;
198
+ border: 1px solid var(--line);
199
+ border-radius: 999px;
200
+ font-size: 13px;
201
+ white-space: nowrap;
202
+ }
185
203
 
186
- .credits ul {
187
- margin: 8px auto 0;
188
- max-width: 60ch;
189
- text-align: start;
204
+ .guide-chip[aria-current="page"] {
205
+ box-shadow: none;
206
+ border-color: var(--accent);
207
+ }
208
+
209
+ .guide-turn {
210
+ position: static;
211
+ }
212
+
213
+ .guide-turn button {
214
+ flex: 1 1 0;
215
+ min-width: 0;
216
+ }
217
+
218
+ .guide-turn .next {
219
+ justify-content: flex-end;
220
+ text-align: end;
221
+ }
190
222
  }
191
223
 
192
224
  @media (max-width: 600px) {