chesspal 0.1.0 → 0.2.1

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 (211) hide show
  1. package/README.md +45 -82
  2. package/dist/cli/chat-hook.js +1 -1
  3. package/dist/cli/command-line.d.ts +1 -2
  4. package/dist/cli/command-line.js +2 -3
  5. package/dist/commands/agents.d.ts +26 -0
  6. package/dist/commands/agents.js +72 -0
  7. package/dist/commands/ai-move.d.ts +5 -14
  8. package/dist/commands/ai-move.js +28 -35
  9. package/dist/commands/ai-say.d.ts +3 -1
  10. package/dist/commands/ai-say.js +24 -6
  11. package/dist/commands/analyse-game.d.ts +4 -0
  12. package/dist/commands/analyse-game.js +43 -16
  13. package/dist/commands/annotate-game.d.ts +4 -0
  14. package/dist/commands/annotate-game.js +65 -12
  15. package/dist/commands/answer-lines.d.ts +28 -0
  16. package/dist/commands/answer-lines.js +144 -0
  17. package/dist/commands/coach.d.ts +45 -0
  18. package/dist/commands/coach.js +344 -0
  19. package/dist/commands/context.d.ts +16 -5
  20. package/dist/commands/context.js +1 -0
  21. package/dist/commands/delete-game.d.ts +7 -0
  22. package/dist/commands/delete-game.js +30 -0
  23. package/dist/commands/delete-review.d.ts +8 -0
  24. package/dist/commands/delete-review.js +34 -0
  25. package/dist/commands/drawings.d.ts +0 -2
  26. package/dist/commands/drawings.js +5 -3
  27. package/dist/commands/end-game.js +5 -2
  28. package/dist/commands/export-game.d.ts +1 -1
  29. package/dist/commands/export-game.js +4 -3
  30. package/dist/commands/game-summary.d.ts +21 -38
  31. package/dist/commands/game-summary.js +30 -167
  32. package/dist/commands/index.d.ts +15 -0
  33. package/dist/commands/index.js +47 -2
  34. package/dist/commands/init.d.ts +3 -3
  35. package/dist/commands/init.js +4 -4
  36. package/dist/commands/lead-input.d.ts +8 -0
  37. package/dist/commands/lead-input.js +21 -0
  38. package/dist/commands/look.js +4 -1
  39. package/dist/commands/new-game.d.ts +2 -3
  40. package/dist/commands/new-game.js +7 -4
  41. package/dist/commands/play-move.d.ts +8 -15
  42. package/dist/commands/play-move.js +5 -13
  43. package/dist/commands/player-move.d.ts +2 -6
  44. package/dist/commands/player-move.js +13 -6
  45. package/dist/commands/player-say.d.ts +1 -1
  46. package/dist/commands/player-say.js +1 -1
  47. package/dist/commands/ponder.d.ts +10 -0
  48. package/dist/commands/ponder.js +33 -21
  49. package/dist/commands/position.d.ts +1 -1
  50. package/dist/commands/position.js +3 -1
  51. package/dist/commands/profiles.d.ts +13 -4
  52. package/dist/commands/profiles.js +49 -15
  53. package/dist/commands/registry.d.ts +8 -3
  54. package/dist/commands/registry.js +12 -11
  55. package/dist/commands/say.d.ts +1 -1
  56. package/dist/commands/say.js +16 -16
  57. package/dist/commands/speech.d.ts +8 -0
  58. package/dist/commands/speech.js +20 -0
  59. package/dist/commands/status.d.ts +9 -3
  60. package/dist/commands/status.js +40 -15
  61. package/dist/commands/study-games.js +1 -1
  62. package/dist/commands/study.js +3 -19
  63. package/dist/core/facts.js +15 -15
  64. package/dist/core/game.d.ts +3 -1
  65. package/dist/core/game.js +8 -4
  66. package/dist/core/illegal.js +1 -1
  67. package/dist/core/index.d.ts +5 -4
  68. package/dist/core/index.js +5 -4
  69. package/dist/core/lead.d.ts +15 -0
  70. package/dist/core/lead.js +40 -0
  71. package/dist/core/levels.d.ts +1 -1
  72. package/dist/core/levels.js +1 -1
  73. package/dist/core/moods.d.ts +0 -2
  74. package/dist/core/moods.js +2 -2
  75. package/dist/core/openings.d.ts +0 -2
  76. package/dist/core/openings.js +1 -1
  77. package/dist/core/profile.js +1 -1
  78. package/dist/core/record.d.ts +1 -1
  79. package/dist/core/record.js +1 -1
  80. package/dist/core/review.d.ts +18 -3
  81. package/dist/core/review.js +52 -9
  82. package/dist/games/ai-model.d.ts +4 -0
  83. package/dist/games/ai-model.js +9 -0
  84. package/dist/games/analysis.d.ts +1 -1
  85. package/dist/games/archive.d.ts +25 -4
  86. package/dist/games/archive.js +99 -25
  87. package/dist/games/coach.d.ts +57 -0
  88. package/dist/games/coach.js +144 -0
  89. package/dist/games/current-game.d.ts +2 -0
  90. package/dist/games/current-game.js +7 -1
  91. package/dist/games/files.js +1 -0
  92. package/dist/games/index.d.ts +5 -4
  93. package/dist/games/index.js +5 -4
  94. package/dist/games/talk.d.ts +1 -5
  95. package/dist/games/talk.js +14 -14
  96. package/dist/home/open-folder.js +1 -1
  97. package/dist/host-files/{ponder-agents.d.ts → agents.d.ts} +10 -2
  98. package/dist/host-files/agents.js +53 -0
  99. package/dist/host-files/host-files.d.ts +7 -2
  100. package/dist/host-files/host-files.js +27 -12
  101. package/dist/host-files/index.d.ts +2 -2
  102. package/dist/host-files/index.js +3 -3
  103. package/dist/index.d.ts +1 -3
  104. package/dist/index.js +1 -0
  105. package/dist/page/app/anchor.js +88 -0
  106. package/dist/page/{app.js → app/app.js} +116 -231
  107. package/dist/page/app/keys.js +94 -0
  108. package/dist/page/app/phase.js +30 -0
  109. package/dist/page/app/served.js +73 -0
  110. package/dist/page/avatars/avatars.js +19 -0
  111. package/dist/page/avatars/thought.js +10 -0
  112. package/dist/page/base.css +160 -0
  113. package/dist/page/board/board.css +959 -0
  114. package/dist/page/board/board.js +125 -0
  115. package/dist/page/{explain.js → board/explain.js} +1 -1
  116. package/dist/page/board/marks.js +160 -0
  117. package/dist/page/board/motion.js +71 -0
  118. package/dist/page/board/pointer.js +239 -0
  119. package/dist/page/board/squares.js +26 -0
  120. package/dist/page/dialogs/analyses.js +195 -0
  121. package/dist/page/{dialog.js → dialogs/dialog.js} +1 -1
  122. package/dist/page/dialogs/dialogs.css +1228 -0
  123. package/dist/page/{new-game-dialog.js → dialogs/new-game.js} +3 -3
  124. package/dist/page/{profile-dialogs.js → dialogs/profiles.js} +40 -11
  125. package/dist/page/dialogs/search.js +31 -0
  126. package/dist/page/dialogs/settings.js +42 -0
  127. package/dist/page/dialogs/studied.js +39 -0
  128. package/dist/page/dialogs/study.js +51 -0
  129. package/dist/page/{badges.js → game/badges.js} +1 -1
  130. package/dist/page/{browse.js → game/browse.js} +1 -1
  131. package/dist/page/game/card-fold.js +40 -0
  132. package/dist/page/game/column.js +55 -0
  133. package/dist/page/{ending.js → game/ending.js} +2 -2
  134. package/dist/page/game/game.css +577 -0
  135. package/dist/page/{move-list.js → game/move-list.js} +10 -6
  136. package/dist/page/{plies.js → game/plies.js} +30 -10
  137. package/dist/page/game/result-tile.js +14 -0
  138. package/dist/page/helps/helps.css +689 -0
  139. package/dist/page/helps/helps.js +220 -0
  140. package/dist/page/helps/view.js +127 -0
  141. package/dist/page/layout/fold-tab.js +11 -0
  142. package/dist/page/{folds.js → layout/folds.js} +1 -1
  143. package/dist/page/{header.js → layout/header.js} +5 -4
  144. package/dist/page/layout/layout.css +834 -0
  145. package/dist/page/lead/lead.js +82 -0
  146. package/dist/page/lead/view.js +38 -0
  147. package/dist/page/main.js +2 -2
  148. package/dist/page/pieces/CREDITS.md +12 -29
  149. package/dist/page/pieces/capablanca-small.svg +20 -0
  150. package/dist/page/pieces/capablanca.svg +22 -0
  151. package/dist/page/pieces/nitida-small.svg +3 -2
  152. package/dist/page/pieces/nitida.svg +3 -2
  153. package/dist/page/{pieces.js → pieces/pieces.js} +2 -2
  154. package/dist/page/pieces/torretta-small.svg +15 -14
  155. package/dist/page/pieces/torretta.svg +17 -15
  156. package/dist/page/{player-card.js → players/card.js} +2 -6
  157. package/dist/page/{clock-time.js → players/clock-time.js} +2 -2
  158. package/dist/page/{profile.js → profile/profile.js} +9 -5
  159. package/dist/page/{settings.js → profile/settings.js} +5 -4
  160. package/dist/page/style.css +9 -4398
  161. package/dist/page/talk/talk.css +958 -0
  162. package/dist/page/{talk.js → talk/talk.js} +39 -46
  163. package/dist/page/text.js +137 -19
  164. package/dist/page/theme.css +292 -0
  165. package/dist/profiles/index.d.ts +1 -1
  166. package/dist/profiles/profiles.d.ts +15 -4
  167. package/dist/profiles/profiles.js +24 -7
  168. package/dist/server/bell.d.ts +10 -2
  169. package/dist/server/bell.js +28 -12
  170. package/dist/server/caller.d.ts +14 -3
  171. package/dist/server/caller.js +44 -11
  172. package/dist/server/mcp.d.ts +2 -3
  173. package/dist/server/mcp.js +53 -19
  174. package/dist/server/page/analyses.d.ts +23 -0
  175. package/dist/server/page/analyses.js +65 -0
  176. package/dist/server/page/files.d.ts +5 -0
  177. package/dist/server/page/files.js +92 -0
  178. package/dist/server/page/game.d.ts +6 -0
  179. package/dist/server/page/game.js +381 -0
  180. package/dist/server/{http.d.ts → page/http.d.ts} +13 -0
  181. package/dist/server/{http.js → page/http.js} +11 -0
  182. package/dist/server/{page.d.ts → page/page.d.ts} +8 -13
  183. package/dist/server/page/page.js +229 -0
  184. package/dist/server/{profile-routes.d.ts → page/profiles.d.ts} +2 -2
  185. package/dist/server/{profile-routes.js → page/profiles.js} +47 -18
  186. package/instructions/analysis.md +4 -0
  187. package/instructions/analyst-agent.md +8 -0
  188. package/instructions/analyst.md +3 -7
  189. package/instructions/coach.md +11 -0
  190. package/instructions/opponent.md +4 -4
  191. package/package.json +1 -1
  192. package/dist/host-files/ponder-agents.js +0 -40
  193. package/dist/page/avatars.js +0 -16
  194. package/dist/page/board.js +0 -566
  195. package/dist/page/fold-tab.js +0 -9
  196. package/dist/page/game-column.js +0 -44
  197. package/dist/page/helps-view.js +0 -51
  198. package/dist/page/helps.js +0 -90
  199. package/dist/page/pieces/cburnett-small.svg +0 -20
  200. package/dist/page/pieces/cburnett.svg +0 -20
  201. package/dist/page/settings-panel.js +0 -32
  202. package/dist/page/studied.js +0 -14
  203. package/dist/page/study-dialog.js +0 -58
  204. package/dist/server/analyses.d.ts +0 -17
  205. package/dist/server/analyses.js +0 -46
  206. package/dist/server/page.js +0 -657
  207. /package/dist/page/{torretta.js → avatars/torretta.js} +0 -0
  208. /package/dist/page/{opening-book.js → game/opening-book.js} +0 -0
  209. /package/dist/page/{model-name.js → players/model-name.js} +0 -0
  210. /package/dist/page/{sounds.js → sounds/sounds.js} +0 -0
  211. /package/dist/page/{voice.js → talk/voice.js} +0 -0
@@ -1,34 +1,25 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "preact/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
2
2
  // The talk on the board page (D-51, D-53): the AI's words in bubbles that point at the Torretta, the player's above the box they write in.
3
3
  import { createContext } from "preact";
4
4
  import { useContext, useEffect, useLayoutEffect, useRef } from "preact/hooks";
5
- import { BadgeIcon, NoteIcon } from "./badges.js";
6
- import { signature } from "./model-name.js";
7
- import { Figurines } from "./move-list.js";
8
- import { talkLimits } from "./plies.js";
9
- import { Torretta } from "./torretta.js";
5
+ import { Torretta } from "../avatars/torretta.js";
6
+ import { BadgeIcon, NoteIcon } from "../game/badges.js";
7
+ import { Figurines } from "../game/move-list.js";
8
+ import { talkLimits } from "../game/plies.js";
9
+ import { signature } from "../players/model-name.js";
10
10
  import { hush, speak } from "./voice.js";
11
- /**
12
- * The AI's words of the game, a bubble each, the newest by the Torretta: below it, or above it on a board turned round; the first points at it. With the helps
13
- * on, its judgment of the player's last move comes newest, in a line that opens on its note (D-78).
14
- */
15
- export function AiWords({ words, newestFirst, voice, judged, text }) {
11
+ /** The AI's words of the game, a bubble each, the newest by the Torretta: below it, or above it on a board turned round; the first points at it. */
12
+ export function AiWords({ words, newestFirst, voice }) {
16
13
  const list = useRef(null);
17
14
  useOnlyWhole(list, words, newestFirst);
18
15
  useSpokenNews(words, voice);
19
- const says = (_jsx("ol", { ref: list, class: "says", "aria-live": "polite", children: inOrder(words.map((word, index) => (_jsx("li", { class: "say", style: aged(words.length - 1 - index), children: _jsx(Marked, { text: word }) }, index))), newestFirst) }));
20
- // The judgment sits by the Torretta, out of the bubbles' order: it never pushes the AI's words away.
21
- if (judged === undefined) {
22
- return says;
23
- }
24
- const line = _jsx(Judged, { ply: judged, text: text });
25
- return newestFirst ? _jsxs(_Fragment, { children: [line, says] }) : _jsxs(_Fragment, { children: [says, line] });
16
+ return (_jsx("ol", { ref: list, class: "says", "aria-live": "polite", children: inOrder(words.map((word, index) => (_jsx("li", { class: "say", style: aged(words.length - 1 - index), children: _jsx(Marked, { text: word }) }, index))), newestFirst) }));
26
17
  }
27
18
  /**
28
19
  * The AI's word on the move shown of a game in analysis (D-69), in a bubble that points down at the Torretta beside the AI's name: the move, its badge by name,
29
20
  * and its note when it wrote one; read out as the player steps through the game. The Torretta and the name stay when the move has no word.
30
21
  */
31
- export function AiNote({ ply, opening, closing, summary, name, by, mood, voice, text }) {
22
+ export function AiNote({ ply, opening, closing, summary, reviewing, name, by, mood, voice, text }) {
32
23
  // On a move of the book without the AI's note, the AI reports what the book says: the opening in the title, the variation under it.
33
24
  const book = ply?.review?.note === undefined ? opening : undefined;
34
25
  const shown = ply?.review ?? (book === undefined ? undefined : { badge: "book" });
@@ -42,13 +33,9 @@ export function AiNote({ ply, opening, closing, summary, name, by, mood, voice,
42
33
  return hush;
43
34
  }, [spoken, voice]);
44
35
  // The Torretta stays in sight through the whole analysis, under its bubbles, which show only where it wrote something.
45
- return (_jsxs("div", { class: "ai-note", "aria-live": "polite", children: [ply === undefined || shown === undefined ? null : (_jsxs("p", { class: `say move-note ${shown.badge ?? ""}`, children: [_jsxs("span", { class: "head", children: [shown.badge === undefined ? _jsx(NoteIcon, {}) : _jsx(BadgeIcon, { badge: shown.badge }), _jsxs("b", { children: [_jsxs("span", { class: "visually-hidden", children: [ply.number, ply.side === "white" ? "." : "...", ply.san] }), _jsxs("span", { "aria-hidden": "true", children: [_jsxs("span", { class: "move-number", children: [ply.number, ply.side === "white" ? "." : "..."] }), _jsx(Figurines, { san: ply.san, side: ply.side })] })] }), " ", title] }), note === undefined ? null : (_jsx("span", { class: "note", children: _jsx(Marked, { text: note }) })), shown.arrows === undefined && shown.squares === undefined ? null : _jsx(Legend, { review: shown, text: text })] })), summary === undefined ? null : _jsx(GameReview, { by: name, summary: summary, text: text }), closing === undefined ? null : (_jsx("p", { class: "say closing", children: _jsx(Marked, { text: closing }) })), _jsxs("p", { class: "who", children: [_jsx(Torretta, { size: 36, mood: mood }), _jsxs("span", { class: "signed", children: [name, by === undefined ? null : _jsx("small", { children: signature(by.annotator, by.effort) })] })] })] }));
46
- }
47
- /** The AI's judgment of the player's move, with the helps on: its badge and the move in a line, which opens on its note (D-78). */
48
- function Judged({ ply, text }) {
49
- const { badge, note } = ply.review ?? {};
50
- const head = (_jsxs(_Fragment, { children: [badge === undefined ? _jsx(NoteIcon, {}) : _jsx(BadgeIcon, { badge: badge }), _jsxs("b", { children: [_jsxs("span", { class: "move-number", children: [ply.number, ply.side === "white" ? "." : "..."] }), _jsx(Figurines, { san: ply.san, side: ply.side })] }), " ", badge === undefined ? null : text.badges[badge]] }));
51
- return (_jsx("div", { class: `say move-note judged ${badge ?? ""}`, children: note === undefined ? _jsx("span", { class: "head", children: head }) : (_jsxs("details", { children: [_jsx("summary", { class: "head", children: head }), _jsx("span", { class: "note", children: _jsx(Marked, { text: note }) })] })) }));
36
+ return (_jsxs("div", { class: "ai-note", "aria-live": "polite", children: [ply === undefined || shown === undefined ? null : (_jsxs("p", { class: `say move-note ${shown.badge ?? ""}`, children: [_jsxs("span", { class: "head", children: [shown.badge === undefined ? _jsx(NoteIcon, {}) : _jsx(BadgeIcon, { badge: shown.badge }), _jsxs("b", { children: [_jsxs("span", { class: "visually-hidden", children: [ply.number, ply.side === "white" ? "." : "...", ply.san] }), _jsxs("span", { "aria-hidden": "true", children: [_jsxs("span", { class: "move-number", children: [ply.number, ply.side === "white" ? "." : "..."] }), _jsx(Figurines, { san: ply.san, side: ply.side })] })] }), " ", title] }), note === undefined ? null : (_jsx("span", { class: "note", children: _jsx(Marked, { text: note }) })), shown.arrows === undefined && shown.squares === undefined ? null : _jsx(Legend, { review: shown, words: text.drawn })] })), summary === undefined ? null : _jsx(GameReview, { by: name, summary: summary, text: text }), closing === undefined ? null : (_jsx("p", { class: "say closing", children: _jsx(Marked, { text: closing }) })), reviewing === true
37
+ ? (_jsxs("p", { class: "say reviewing", children: [_jsx("span", { class: "spinner", "aria-hidden": "true" }), text.reviewing(name)] }))
38
+ : null, _jsxs("p", { class: "who", children: [_jsx(Torretta, { size: 36, mood: mood }), _jsxs("span", { class: "signed", children: [name, by === undefined ? null : _jsx("small", { children: signature(by.annotator, by.effort) })] })] })] }));
52
39
  }
53
40
  /** The squares and moves in the AI's words, such as e3, Cxe4, 7.Nd4 or O-O: in bold, as the player looks for them on the board. */
54
41
  export function Marked({ text }) {
@@ -57,31 +44,18 @@ export function Marked({ text }) {
57
44
  ? (_jsx("b", { children: _jsx(OnBoard, { text: part }) }, index))
58
45
  : _jsx(OnBoard, { text: part }, index)) }));
59
46
  }
60
- /** Where the pointer is among the squares and moves in the AI's words (T-111): the board lights that square up. */
47
+ /** Where the pointer is among the squares and moves in the AI's words: the board lights that square up. */
61
48
  export const PointSquare = createContext(() => undefined);
62
- function OnBoard({ text }) {
63
- const point = useContext(PointSquare);
64
- return (_jsx(_Fragment, { children: text.split(boardWords).map((part, index) => index % 2 === 1
65
- ? _jsx("b", { class: "on-board", onPointerEnter: () => point(squareIn(part)), onPointerLeave: (event) => event.pointerType === "mouse" && point(undefined), children: part }, index)
66
- : part) }));
67
- }
68
- /** The square a word names: a square, or where a move goes, the last square in it; none for a castling. */
69
- function squareIn(word) {
70
- return /[a-h][1-8](?!.*[a-h][1-8])/.exec(word)?.[0];
71
- }
72
49
  // **a few words** the AI put in bold, as Markdown writes them.
73
50
  const boldWords = /\*\*(.+?)\*\*/;
74
51
  // A square or a move in SAN or with the pieces' figurines (D-86, D-87), with its number if it has one; the capture group keeps it in split's parts.
75
52
  const boardWords = /(?<![\p{L}\d])((?:\d+\.(?:\.\.)?\s?)?(?:O-O(?:-O)?|[KQRBN♔-♟]?[a-h]?[1-8]?x?[a-h][1-8](?:=[QRBN♔-♟])?)[+#]?[!?]{0,2})(?![\p{L}\d])/u;
76
- /** The AI's word on the whole game (D-69), in the Torretta's bubble at the start of the game: a paragraph, and its points as a list. */
77
- function GameReview({ by, summary, text }) {
78
- const [lead = "", ...points] = summary.split(/\s*•\s+/);
79
- return (_jsxs("section", { class: "say review", "aria-label": text.reviewBy(by), children: [_jsxs("p", { class: "head", children: [_jsx("svg", { class: "icon", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M12 4V20M8 20H16M5 7H19M5 7L2.5 13A2.5 2 0 0 0 7.5 13ZM19 7L16.5 13A2.5 2 0 0 0 21.5 13Z" }) }), text.reviewBy(by)] }), lead === "" ? null : (_jsx("p", { children: _jsx(Marked, { text: lead }) })), points.length === 0 ? null : (_jsx("ul", { children: points.map((point, index) => (_jsx("li", { children: _jsx(Marked, { text: point }) }, index))) }))] }));
80
- }
81
- /** What the colours drawn with a note mean, the ones it uses: the AI's legend, for the player (D-69). */
82
- function Legend({ review, text }) {
53
+ /**
54
+ * What the colours drawn with a note or the coach's hint mean, the ones it uses, in the words of who drew them: the legend, for the player (D-69, Zoe).
55
+ */
56
+ export function Legend({ review, words }) {
83
57
  const used = [...new Set([...(review.arrows ?? []), ...(review.squares ?? [])].map((drawn) => drawn.colour))];
84
- return (_jsx("span", { class: "legend", children: used.map((colour) => (_jsxs("span", { class: colour, children: [_jsx("i", { "aria-hidden": "true" }), text.drawn[colour]] }, colour))) }));
58
+ return (_jsx("span", { class: "legend", children: used.map((colour) => (_jsxs("span", { class: colour, children: [_jsx("i", { "aria-hidden": "true" }), words[colour]] }, colour))) }));
85
59
  }
86
60
  /**
87
61
  * The player's words of the game, the newest by the box they write in with how far it got, and the box: Enter or the button sends the words alone, the next
@@ -110,12 +84,31 @@ export function Compose({ lines, newestFirst, spent, draft, onDraft, onSend, can
110
84
  : _jsx("span", { class: "hint", children: !blank && canMove ? text.withMove : "" }), _jsxs("button", { class: "send", type: "submit", disabled: blank, children: [text.send, _jsx("svg", { class: "icon", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M5 12H18M13 7L18 12L13 17" }) })] })] })] }))] }));
111
85
  }
112
86
  /**
113
- * The talk narrowed to a card beside the board (T-84): the Torretta above, the player below, each with their name and side written down the card, a ring on
87
+ * The talk narrowed to a card beside the board: the Torretta above, the player below, each with their name and side written down the card, a ring on
114
88
  * whoever moves and a dot on the Torretta when the AI spoke meanwhile.
115
89
  */
116
90
  export function TalkFaces({ name, aiPicture, you, picture, ai, player, aiMoves, playerMoves, unread, text }) {
117
91
  return (_jsxs("div", { class: "faces", children: [_jsx(RailPlayer, { place: "ai", picture: aiPicture ?? _jsx(Torretta, { size: 40 }), name: name, ...(ai === undefined ? {} : { side: text.sides[ai] }), moves: aiMoves, unread: unread }), _jsx(RailPlayer, { place: "you", picture: picture, name: you, ...(player === undefined ? {} : { side: text.sides[player] }), moves: playerMoves })] }));
118
92
  }
93
+ function OnBoard({ text }) {
94
+ const point = useContext(PointSquare);
95
+ return (_jsx(_Fragment, { children: text.split(boardWords).map((part, index) => index % 2 === 1
96
+ ? (_jsx("b", { class: "on-board", onPointerEnter: () => point(squareIn(part)), onPointerLeave: (event) => event.pointerType === "mouse" && point(undefined), children: _jsx(Takes, { move: part }) }, index))
97
+ : part) }));
98
+ }
99
+ /** A move with its capture's x light, as the move list writes it: the piece and the squares stand out (Stefano, for readers with ADHD). */
100
+ function Takes({ move }) {
101
+ return _jsx(_Fragment, { children: move.split("x").map((part, index) => index === 0 ? part : [_jsx("span", { class: "takes", children: "x" }, index), part]) });
102
+ }
103
+ /** The square a word names: a square, or where a move goes, the last square in it; none for a castling. */
104
+ function squareIn(word) {
105
+ return /[a-h][1-8](?!.*[a-h][1-8])/.exec(word)?.[0];
106
+ }
107
+ /** The AI's word on the whole game (D-69), in the Torretta's bubble at the start of the game: a paragraph, and its points as a list. */
108
+ function GameReview({ by, summary, text }) {
109
+ const [lead = "", ...points] = summary.split(/\s*•\s+/);
110
+ return (_jsxs("section", { class: "say review", "aria-label": text.reviewBy(by), children: [_jsxs("p", { class: "head", children: [_jsx("svg", { class: "icon", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M12 4V20M8 20H16M5 7H19M5 7L2.5 13A2.5 2 0 0 0 7.5 13ZM19 7L16.5 13A2.5 2 0 0 0 21.5 13Z" }) }), text.reviewBy(by)] }), lead === "" ? null : (_jsx("p", { children: _jsx(Marked, { text: lead }) })), points.length === 0 ? null : (_jsx("ul", { children: points.map((point, index) => (_jsx("li", { children: _jsx(Marked, { text: point }) }, index))) }))] }));
111
+ }
119
112
  function RailPlayer({ place, picture, name, side, moves, unread = false }) {
120
113
  return (_jsxs("div", { class: `rail-player ${place}${moves ? " moving" : ""}`, children: [_jsx("span", { class: `face${unread ? " unread" : ""}`, children: picture }), _jsxs("span", { class: "rail-name", children: [name, " ", side === undefined ? null : _jsxs("span", { class: "note", children: ["\u00B7 ", side] })] })] }));
121
114
  }
package/dist/page/text.js CHANGED
@@ -31,6 +31,7 @@ const english = {
31
31
  marksColour: "Arrows and marked squares",
32
32
  play: "Play",
33
33
  dots: "Dots on the legal moves",
34
+ squareNames: "The square's name under the pointer",
34
35
  explain: "Explain the moves refused",
35
36
  bookBadges: "Mark the book moves",
36
37
  helps: "The AI teaches as you play",
@@ -39,7 +40,7 @@ const english = {
39
40
  names: {
40
41
  nitida: "Nitida",
41
42
  torretta: "Torretta",
42
- cburnett: "cburnett",
43
+ capablanca: "Capablanca",
43
44
  azzurro: "Blue",
44
45
  verde: "Green",
45
46
  noce: "Walnut",
@@ -61,7 +62,10 @@ const english = {
61
62
  moves: "Moves",
62
63
  steps: { first: "Start", back: "Previous move", forward: "Next move", last: "Back to the game" },
63
64
  noGame: "No game yet: press + to start one, or ask for one in the chat.",
64
- saveMoves: "Save the moves (PGN)",
65
+ foldCard: "Fold the card",
66
+ openCard: "Open the card",
67
+ saveMoves: "Moves-only PGN",
68
+ saveMovesHint: "The moves alone, to open on Lichess or chess.com",
65
69
  noGameNow: "No game in progress",
66
70
  analysing: "Analysis in progress",
67
71
  badges: {
@@ -78,6 +82,18 @@ const english = {
78
82
  },
79
83
  reviewBy: (name) => `${name}'s review`,
80
84
  drawn: { green: "better", red: "threat", yellow: "another way", blue: "plan" },
85
+ lead: {
86
+ hint: "Who is ahead, in pawns, as the AI estimates it: Chesspal does not compute it",
87
+ chart: "How the game went",
88
+ chartHint: "Who was ahead move by move, as the AI estimated it: click to go to that move",
89
+ even: "Even",
90
+ none: "No estimate yet",
91
+ earlier: "Estimated before the last move",
92
+ drawn: "Drawn on the board",
93
+ ahead: (side, pawns) => `${side === "white" ? "White" : "Black"} ahead by ${pawns} pawns`,
94
+ mate: (side, moves) => `${side === "white" ? "White" : "Black"} mates in ${moves}`,
95
+ mated: (side) => `${side === "white" ? "White" : "Black"} is mated`,
96
+ },
81
97
  reviewing: (name) => `${name} is going over the game…`,
82
98
  you: "You",
83
99
  ai: "AI",
@@ -108,8 +124,10 @@ const english = {
108
124
  canGo: "a legal move",
109
125
  boardLabel: (turn, lastMove) => `Chessboard, ${english.toMove(turn)}${lastMove === undefined ? "" : `, last move ${lastMove}`}`,
110
126
  clearChat: (name) => `Before a new game, clear your chat with ${name}: in the window where you opened ${name}, not here, write /clear, then a message such as "new game". A clean chat plays faster.`,
127
+ outdated: (name) => `Chesspal has been updated, but this folder still has its old files: close the chat with ${name}, run chesspal init in this folder, and open a new chat.`,
111
128
  offline: (name) => `${name} is not connected. Write it a message in the window where you opened ${name}, not in this page's chat: the page connects again by itself.`,
112
129
  startClocks: "Start",
130
+ thinking: { move: "Thinking about its move", ponder: "Thinking while you play" },
113
131
  asleep: (name) => `${name} is not listening: write a message, such as "hi", in the window where you opened ${name}, not here. Its clock waits until it answers.`,
114
132
  commandHere: (name) => `/clear and the other commands go in the window where you opened ${name}, not here.`,
115
133
  refused: {
@@ -183,6 +201,8 @@ const english = {
183
201
  yourPicture: "Your picture: change it",
184
202
  avatars: { "short-hair": "Short hair", bun: "Bun", glasses: "Glasses", beanie: "Beanie", beard: "Beard", curls: "Curls", moustache: "Moustache", "silver-bob": "Silver bob", cat: "Cat", owl: "Owl" },
185
203
  whilePlaying: "Finish the game, or resign, before changing player.",
204
+ username: "your username",
205
+ accountTitle: "With your name there, a game you load from there knows which side is yours.",
186
206
  badImage: "That picture won't open: try another photo (the ones from a phone usually work).",
187
207
  },
188
208
  start: {
@@ -208,21 +228,45 @@ const english = {
208
228
  note: "The game is kept to study; the AI goes over it with you in the chat.",
209
229
  start: "Analyse",
210
230
  yours: "Your analyses",
211
- bring: "Bring a game",
231
+ bring: "Load a game",
232
+ bringNote: "a PGN played elsewhere, pasted or from a file",
233
+ search: "Names, models, openings…",
234
+ noMatch: "No game found",
212
235
  reviewed: "reviewed",
213
236
  unreviewed: "to review",
214
237
  moves: (count) => `${count} ${count === 1 ? "move" : "moves"}`,
215
- download: "Save PGN",
238
+ outcome: { won: "won", lost: "lost", drawn: "drawn" },
239
+ more: "More",
240
+ redo: "Analyse again",
241
+ redoNote: "with your chat's model and effort",
242
+ unreview: "Delete the analysis",
243
+ unreviewNote: "the game stays, to review",
244
+ remove: "Delete the game",
245
+ askRedo: (game, by) => ({
246
+ question: `Analyse ${game} again?`,
247
+ note: `${by === undefined ? "The review" : `The review by ${by}`} is deleted; your chat's analyst writes it again, with the model and effort it has now.`,
248
+ yes: "Analyse again",
249
+ }),
250
+ askUnreview: (game) => ({ question: `Delete the analysis of ${game}?`, note: "Its badges, notes and the coach's judgments go; the game stays.", yes: "Delete" }),
251
+ askRemove: (game, when) => ({ question: `Delete the game ${game}${when === undefined ? "" : ` of ${when}`}?`, note: "With its analysis. It cannot be undone.", yes: "Delete" }),
252
+ cancel: "Cancel",
253
+ download: "Annotated PGN",
254
+ downloadHint: "The game with the review's comments and judgments",
216
255
  analyseIt: "Analyse the game",
217
256
  analyseLast: "Analyse the last game",
218
257
  },
219
258
  helpsCard: {
220
259
  title: "Helps",
260
+ coach: "The coach",
261
+ showHint: "Show hint",
262
+ hideHint: "Hide hint",
263
+ drawn: { green: "idea", red: "threat", yellow: "line", blue: "target" },
221
264
  tactics: "Tactics",
222
265
  strategy: "Strategy",
223
266
  map: "Map",
224
267
  mapHint: "Hold it, or the M key, to see who controls each square; on a phone, a touch turns it on and off",
225
- hold: "hold",
268
+ bare: "Hide the drawings",
269
+ bareHint: "Hold it to see the board without the arrows, the marked squares and the helps' signs; on a phone, a touch hides them and shows them again",
226
270
  attackers: "attackers",
227
271
  defenders: "defenders",
228
272
  undefended: "no defender",
@@ -231,8 +275,20 @@ const english = {
231
275
  pinnedTo: (letter) => `pinned to the ${englishNames[letter]}`,
232
276
  pinnedBy: (letter) => `by the ${englishNames[letter]}`,
233
277
  nothingAtRisk: "No piece at risk, no pins.",
234
- checks: (side, toMove) => `${side === "white" ? "White" : "Black"}'s checks${toMove ? "" : `, if it were ${side === "white" ? "White" : "Black"}'s move`}`,
278
+ line: (kind, side, you, toMove) => {
279
+ const name = side === "white" ? "White" : "Black";
280
+ if (you === undefined) {
281
+ return kind === "risk" ? `${name}'s pieces at risk` : kind === "pin" ? `${name}'s pinned pieces` : `${name}'s checks${toMove ? "" : `, if it were ${name}'s move`}`;
282
+ }
283
+ if (kind === "check") {
284
+ return side === you ? `Checks you ${toMove ? "can" : "could"} give` : `Checks the opponent ${toMove ? "can" : "could"} give you`;
285
+ }
286
+ return `${side === you ? "Your" : "The opponent's"} ${kind === "risk" ? "pieces at risk" : "pinned pieces"}`;
287
+ },
235
288
  loose: "Pieces neither attacked nor defended",
289
+ yours: "yours",
290
+ theirs: "the opponent's",
291
+ you: "(you)",
236
292
  white: "White",
237
293
  black: "Black",
238
294
  rows: {
@@ -248,14 +304,17 @@ const english = {
248
304
  bishopPair: ["Bishop pair", "Both bishops still on the board."],
249
305
  space: ["Space (squares in the enemy's half)", "How many squares of the enemy's half one's pieces attack."],
250
306
  undeveloped: ["Minor pieces not developed", "Knights and bishops still on their first squares."],
251
- castled: ["Castling", "How it castled; not yet while it still can, no more once the king or the rooks have moved."],
307
+ castled: ["Castling", "How it castled; a dash while it still can, a cross once the king or the rooks have moved."],
252
308
  kingAttacks: ["Enemy attacks around the king", "How many enemy attacks fall on the squares next to the king."],
253
309
  },
310
+ groups: { pawns: "Pawns", pieces: "Pieces", king: "King" },
254
311
  yes: "yes",
255
312
  notYet: "not yet",
256
313
  noMore: "no more",
257
- phases: { opening: "opening", middlegame: "middlegame", endgame: "endgame" },
258
- openFiles: (files) => `Open files: ${files}`,
314
+ phases: { opening: "Opening", middlegame: "Middlegame", endgame: "Endgame" },
315
+ openFiles: "Open files",
316
+ control: "Squares controlled",
317
+ both: "both",
259
318
  controlled: (white, black, both) => `Squares only White's ${white}, only Black's ${black}, both ${both}`,
260
319
  oppositeBishops: "Bishops of opposite colours",
261
320
  repetitions: (times) => `This position has stood ${times} times`,
@@ -291,6 +350,7 @@ const italian = {
291
350
  marksColour: "Frecce e case segnate",
292
351
  play: "Gioco",
293
352
  dots: "Pallini sulle mosse legali",
353
+ squareNames: "Il nome della casa sotto il puntatore",
294
354
  explain: "Spiega le mosse vietate",
295
355
  bookBadges: "Segna le mosse da libro",
296
356
  helps: "L'AI ti insegna mentre giochi",
@@ -299,7 +359,7 @@ const italian = {
299
359
  names: {
300
360
  nitida: "Nitida",
301
361
  torretta: "Torretta",
302
- cburnett: "cburnett",
362
+ capablanca: "Capablanca",
303
363
  azzurro: "Azzurro",
304
364
  verde: "Verde",
305
365
  noce: "Noce",
@@ -321,7 +381,10 @@ const italian = {
321
381
  moves: "Mosse",
322
382
  steps: { first: "Inizio", back: "Mossa precedente", forward: "Mossa successiva", last: "Torna alla partita" },
323
383
  noGame: "Nessuna partita: premi + per iniziarne una, o chiedila nella chat.",
324
- saveMoves: "Scarica le mosse (PGN)",
384
+ foldCard: "Chiudi la scheda",
385
+ openCard: "Apri la scheda",
386
+ saveMoves: "PGN solo mosse",
387
+ saveMovesHint: "Solo le mosse, da aprire su Lichess o chess.com",
325
388
  noGameNow: "Nessuna partita in corso",
326
389
  analysing: "Analisi in corso",
327
390
  badges: {
@@ -338,6 +401,18 @@ const italian = {
338
401
  },
339
402
  reviewBy: (name) => `Il giudizio di ${name}`,
340
403
  drawn: { green: "meglio", red: "minaccia", yellow: "altra via", blue: "piano" },
404
+ lead: {
405
+ hint: "Chi è avanti, in pedoni, secondo la stima dell'AI: Chesspal non lo calcola",
406
+ chart: "Andamento della partita",
407
+ chartHint: "Chi era avanti mossa per mossa, secondo la stima dell'AI: clicca per andare a quella mossa",
408
+ even: "Pari",
409
+ none: "Ancora nessuna stima",
410
+ earlier: "Stimata prima dell'ultima mossa",
411
+ drawn: "Patta sulla scacchiera",
412
+ ahead: (side, pawns) => `Il ${side === "white" ? "Bianco" : "Nero"} è avanti di ${pawns} pedoni`,
413
+ mate: (side, moves) => `Il ${side === "white" ? "Bianco" : "Nero"} dà matto in ${moves}`,
414
+ mated: (side) => `Matto al ${side === "white" ? "Bianco" : "Nero"}`,
415
+ },
341
416
  reviewing: (name) => `${name} sta analizzando la partita…`,
342
417
  you: "Tu",
343
418
  ai: "AI",
@@ -368,8 +443,10 @@ const italian = {
368
443
  canGo: "mossa possibile",
369
444
  boardLabel: (turn, lastMove) => `Scacchiera, ${italian.toMove(turn)}${lastMove === undefined ? "" : `, ultima mossa ${lastMove}`}`,
370
445
  clearChat: (name) => `Prima di una nuova partita azzera la conversazione con ${name}: nella finestra dove hai aperto ${name}, non qui, scrivi /clear e poi un messaggio, per esempio "nuova partita". Con la chat pulita l'AI gioca più veloce.`,
446
+ outdated: (name) => `Chesspal è stato aggiornato, ma questa cartella ha ancora i file di prima: chiudi la chat con ${name}, esegui chesspal init in questa cartella e apri una chat nuova.`,
371
447
  offline: (name) => `${name} è scollegato. Scrivigli un messaggio nella finestra dove hai aperto ${name}, non nella chat di questa pagina: la pagina si ricollega da sola.`,
372
448
  startClocks: "Inizia",
449
+ thinking: { move: "Sta pensando alla sua mossa", ponder: "Pensa mentre giochi tu" },
373
450
  asleep: (name) => `${name} non ti sta ascoltando: scrivi un messaggio, per esempio "ciao", nella finestra dove hai aperto ${name}, non qui. Il suo orologio aspetta che risponda.`,
374
451
  commandHere: (name) => `/clear e gli altri comandi vanno scritti nella finestra dove hai aperto ${name}, non qui.`,
375
452
  refused: {
@@ -444,6 +521,8 @@ const italian = {
444
521
  yourPicture: "La tua immagine: cambiala",
445
522
  avatars: { "short-hair": "Capelli corti", bun: "Chignon", glasses: "Occhiali", beanie: "Berretto", beard: "Barba", curls: "Ricci", moustache: "Baffi", "silver-bob": "Caschetto grigio", cat: "Gatto", owl: "Gufo" },
446
523
  whilePlaying: "Finisci la partita, o abbandona, prima di cambiare giocatore.",
524
+ username: "il tuo nome utente",
525
+ accountTitle: "Col tuo nome lì, una partita che carichi da lì sa qual è la tua parte.",
447
526
  badImage: "Questa immagine non si apre: prova con un'altra foto (quelle del telefono di solito vanno bene).",
448
527
  },
449
528
  start: {
@@ -469,31 +548,67 @@ const italian = {
469
548
  note: "La partita resta tra quelle da studiare; l'AI la commenta con te nella chat.",
470
549
  start: "Analizza",
471
550
  yours: "Le tue analisi",
472
- bring: "Porta una partita",
551
+ bring: "Carica una partita",
552
+ bringNote: "un PGN giocato altrove, incollato o da file",
553
+ search: "Nomi, modelli, aperture…",
554
+ noMatch: "Nessuna partita trovata",
473
555
  reviewed: "commentata",
474
556
  unreviewed: "da commentare",
475
557
  moves: (count) => `${count} ${count === 1 ? "mossa" : "mosse"}`,
476
- download: "Scarica PGN",
558
+ outcome: { won: "vinta", lost: "persa", drawn: "patta" },
559
+ more: "Altro",
560
+ redo: "Rifai l'analisi",
561
+ redoNote: "con il modello e l'effort della tua chat",
562
+ unreview: "Elimina l'analisi",
563
+ unreviewNote: "la partita resta, da commentare",
564
+ remove: "Elimina la partita",
565
+ askRedo: (game, by) => ({
566
+ question: `Rifare l'analisi di ${game}?`,
567
+ note: `${by === undefined ? "L'analisi" : `L'analisi di ${by}`} si cancella; la rifà l'analista della tua chat, col modello e l'effort che ha ora.`,
568
+ yes: "Rifai",
569
+ }),
570
+ askUnreview: (game) => ({ question: `Eliminare l'analisi di ${game}?`, note: "Bollini, note e giudizi dell'allenatore si cancellano; la partita resta.", yes: "Elimina" }),
571
+ askRemove: (game, when) => ({ question: `Eliminare la partita ${game}${when === undefined ? "" : ` del ${when}`}?`, note: "Con la sua analisi. Non si può annullare.", yes: "Elimina" }),
572
+ cancel: "Annulla",
573
+ download: "PGN annotato",
574
+ downloadHint: "La partita con i commenti e i giudizi della revisione",
477
575
  analyseIt: "Analizza la partita",
478
576
  analyseLast: "Analizza l'ultima partita",
479
577
  },
480
578
  helpsCard: {
481
579
  title: "Aiuti",
580
+ coach: "L'allenatore",
581
+ showHint: "Mostra il suggerimento",
582
+ hideHint: "Nascondi il suggerimento",
583
+ drawn: { green: "idea", red: "minaccia", yellow: "linea", blue: "obiettivo" },
482
584
  tactics: "Tattica",
483
585
  strategy: "Strategia",
484
586
  map: "Mappa",
485
587
  mapHint: "Tienilo premuto, o tieni premuto il tasto M, per vedere chi controlla ogni casa; sul telefono un tocco la accende e la spegne",
486
- hold: "tieni premuto",
588
+ bare: "Nascondi i disegni",
589
+ bareHint: "Tienilo premuto per vedere la scacchiera senza frecce, case segnate e segni degli aiuti; sul telefono un tocco li nasconde e li rimostra",
487
590
  attackers: "attaccanti",
488
591
  defenders: "difensori",
489
592
  undefended: "nessun difensore",
490
- cheaper: "un attaccante vale meno",
593
+ cheaper: "un attaccante vale meno di lui",
491
594
  outnumbered: "più attaccanti che difensori",
492
595
  pinnedTo: (letter) => `davanti ${italianWith("a", letter)}`,
493
596
  pinnedBy: (letter) => italianWith("da", letter),
494
597
  nothingAtRisk: "Nessun pezzo in pericolo, nessuna inchiodatura.",
495
- checks: (side, toMove) => `Scacchi del ${side === "white" ? "Bianco" : "Nero"}${toMove ? "" : ", se toccasse a lui"}`,
598
+ line: (kind, side, you, toMove) => {
599
+ const name = side === "white" ? "Bianco" : "Nero";
600
+ if (you === undefined) {
601
+ return kind === "risk" ? `Pezzi del ${name} in pericolo` : kind === "pin" ? `Pezzi del ${name} inchiodati` : `Scacchi del ${name}${toMove ? "" : ", se toccasse a lui"}`;
602
+ }
603
+ if (kind === "check") {
604
+ return side === you ? `Scacchi che ${toMove ? "puoi" : "potresti"} dare` : `Scacchi che l'avversario ${toMove ? "può" : "potrebbe"} darti`;
605
+ }
606
+ return `${side === you ? "I tuoi pezzi" : "I pezzi avversari"} ${kind === "risk" ? "in pericolo" : "inchiodati"}`;
607
+ },
496
608
  loose: "Pezzi né attaccati né difesi",
609
+ yours: "tuoi",
610
+ theirs: "avversari",
611
+ you: "(tu)",
497
612
  white: "Bianco",
498
613
  black: "Nero",
499
614
  rows: {
@@ -509,14 +624,17 @@ const italian = {
509
624
  bishopPair: ["Coppia degli alfieri", "Tutti e due gli alfieri ancora sulla scacchiera."],
510
625
  space: ["Spazio (case nella metà avversaria)", "Quante case della metà avversaria attaccano i propri pezzi."],
511
626
  undeveloped: ["Pezzi minori non sviluppati", "Cavalli e alfieri ancora sulle case di partenza."],
512
- castled: ["Arrocco", "Come ha arroccato; non ancora finché può farlo, non più quando il re o le torri si sono già mossi."],
627
+ castled: ["Arrocco", "Come ha arroccato; un trattino finché può ancora farlo, una croce quando il re o le torri si sono già mossi."],
513
628
  kingAttacks: ["Attacchi nemici attorno al re", "Quanti attacchi nemici cadono sulle case accanto al re."],
514
629
  },
630
+ groups: { pawns: "Pedoni", pieces: "Pezzi", king: "Re" },
515
631
  yes: "sì",
516
632
  notYet: "non ancora",
517
633
  noMore: "non più",
518
- phases: { opening: "apertura", middlegame: "mediogioco", endgame: "finale" },
519
- openFiles: (files) => `Colonne aperte: ${files}`,
634
+ phases: { opening: "Apertura", middlegame: "Mediogioco", endgame: "Finale" },
635
+ openFiles: "Colonne aperte",
636
+ control: "Case controllate",
637
+ both: "tutti e due",
520
638
  controlled: (white, black, both) => `Case solo del Bianco ${white}, solo del Nero ${black}, di tutti e due ${both}`,
521
639
  oppositeBishops: "Alfieri di colore contrario",
522
640
  repetitions: (times) => `Questa posizione si è vista ${times} volte`,