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
@@ -1,10 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
2
- import { useEffect, useRef } from "preact/hooks";
2
+ import { useEffect, useRef, useState } from "preact/hooks";
3
3
  import { Piece } from "../pieces/pieces.js";
4
4
  import { looks, pieceSets } from "../profile/settings.js";
5
+ import { hasVoice, onVoices } from "../talk/voice.js";
5
6
  /** The panel of the settings, open while `open` is true: every change goes to `onChange` at once. */
6
7
  export function SettingsPanel({ open, settings, onChange, onClose, text }) {
7
8
  const dialog = useRef(null);
9
+ const voiced = useVoiced(text.language);
8
10
  useEffect(() => {
9
11
  const element = dialog.current;
10
12
  if (open && !element.open) {
@@ -15,7 +17,7 @@ export function SettingsPanel({ open, settings, onChange, onClose, text }) {
15
17
  }
16
18
  }, [open]);
17
19
  const set = (key, value) => onChange({ ...settings, [key]: value });
18
- return (_jsxs("dialog", { ref: dialog, class: "dialog", "aria-label": text.settings, onClose: onClose, onClick: (event) => event.target === dialog.current && onClose(), children: [_jsxs("header", { children: [_jsx("h2", { children: text.settings }), _jsx("button", { class: "icon-button", type: "button", title: text.close, "aria-label": text.close, onClick: onClose, children: _jsx("svg", { class: "icon", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M6 6L18 18M18 6L6 18" }) }) })] }), _jsxs("div", { class: "setting-columns", children: [_jsxs(Section, { title: text.look, icon: lookIcon, children: [_jsxs("div", { class: "setting-group", children: [_jsx("p", { class: "setting-label", children: text.themeChoice }), _jsx(Segments, { label: text.themeChoice, children: ["system", "light", "dark"].map((theme) => _jsx(Choice, { on: settings.theme === theme, onPick: () => set("theme", theme), children: text.themes[theme] }, theme)) })] }), _jsxs("div", { class: "setting-group", children: [_jsxs("p", { class: "setting-label", children: [text.boardSkin, " ", _jsx("b", { children: nameOf(settings.board, text) })] }), _jsx(Swatches, { look: "board", label: text.boardSkin, settings: settings, onPick: (id) => set("board", id), text: text })] }), _jsxs("div", { class: "setting-group", children: [_jsx("p", { class: "setting-label", children: text.pieceSet }), _jsx("div", { class: "piece-sets", role: "radiogroup", "aria-label": text.pieceSet, children: pieceSets.map((pieceSet) => (_jsxs(Choice, { on: settings.set === pieceSet, onPick: () => set("set", pieceSet), children: [_jsxs("span", { class: "sample", children: [_jsx(Piece, { letter: "N", set: pieceSet }), _jsx(Piece, { letter: "n", set: pieceSet })] }), nameOf(pieceSet, text)] }, pieceSet))) })] }), _jsxs("div", { class: "setting-group setting-pair", children: [_jsxs("div", { children: [_jsx("p", { class: "setting-label", children: text.pieceColours }), _jsx(Swatches, { look: "pieces", label: text.pieceColours, settings: settings, onPick: (id) => set("pieces", id), text: text })] }), _jsxs("div", { children: [_jsx("p", { class: "setting-label", children: text.marksColour }), _jsx(Swatches, { look: "marks", label: text.marksColour, settings: settings, onPick: (id) => set("marks", id), text: text })] })] })] }), _jsxs("div", { class: "setting-column", children: [_jsxs(Section, { title: text.play, icon: playIcon, children: [_jsx(Switch, { on: settings.dots, onSwitch: (on) => set("dots", on), children: text.dots }), _jsx(Switch, { on: settings.squareNames, onSwitch: (on) => set("squareNames", on), children: text.squareNames }), _jsx(Switch, { on: settings.explain, onSwitch: (on) => set("explain", on), children: text.explain }), _jsx(Switch, { on: settings.book, onSwitch: (on) => set("book", on), children: text.bookBadges }), _jsx(Switch, { on: settings.helps, onSwitch: (on) => set("helps", on), children: text.helps }), _jsx(Switch, { on: settings.sound, onSwitch: (on) => set("sound", on), children: text.sounds }), _jsx(Switch, { on: settings.voice, onSwitch: (on) => set("voice", on), children: text.voice })] }), _jsx(Section, { title: text.languageChoice, icon: languageIcon, children: _jsx(Segments, { label: text.languageChoice, children: ["auto", "it", "en"].map((language) => _jsx(Choice, { on: settings.language === language, onPick: () => set("language", language), children: text.languages[language] }, language)) }) })] })] })] }));
20
+ return (_jsxs("dialog", { ref: dialog, class: "dialog", "aria-label": text.settings, onClose: onClose, onClick: (event) => event.target === dialog.current && onClose(), children: [_jsxs("header", { children: [_jsx("h2", { children: text.settings }), _jsx("button", { class: "icon-button", type: "button", title: text.close, "aria-label": text.close, onClick: onClose, children: _jsx("svg", { class: "icon", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M6 6L18 18M18 6L6 18" }) }) })] }), _jsxs("div", { class: "setting-columns", children: [_jsxs(Section, { title: text.look, icon: lookIcon, children: [_jsxs("div", { class: "setting-group", children: [_jsx("p", { class: "setting-label", children: text.themeChoice }), _jsx(Segments, { label: text.themeChoice, children: ["system", "light", "dark"].map((theme) => _jsx(Choice, { on: settings.theme === theme, onPick: () => set("theme", theme), children: text.themes[theme] }, theme)) })] }), _jsxs("div", { class: "setting-group", children: [_jsxs("p", { class: "setting-label", children: [text.boardSkin, " ", _jsx("b", { children: nameOf(settings.board, text) })] }), _jsx(Swatches, { look: "board", label: text.boardSkin, settings: settings, onPick: (id) => set("board", id), text: text })] }), _jsxs("div", { class: "setting-group", children: [_jsx("p", { class: "setting-label", children: text.pieceSet }), _jsx("div", { class: "piece-sets", role: "radiogroup", "aria-label": text.pieceSet, children: pieceSets.map((pieceSet) => (_jsxs(Choice, { on: settings.set === pieceSet, onPick: () => set("set", pieceSet), children: [_jsxs("span", { class: "sample", children: [_jsx(Piece, { letter: "N", set: pieceSet }), _jsx(Piece, { letter: "n", set: pieceSet })] }), nameOf(pieceSet, text)] }, pieceSet))) })] }), _jsxs("div", { class: "setting-group setting-pair", children: [_jsxs("div", { children: [_jsx("p", { class: "setting-label", children: text.pieceColours }), _jsx(Swatches, { look: "pieces", label: text.pieceColours, settings: settings, onPick: (id) => set("pieces", id), text: text })] }), _jsxs("div", { children: [_jsx("p", { class: "setting-label", children: text.marksColour }), _jsx(Swatches, { look: "marks", label: text.marksColour, settings: settings, onPick: (id) => set("marks", id), text: text })] })] })] }), _jsxs("div", { class: "setting-column", children: [_jsxs(Section, { title: text.play, icon: playIcon, children: [_jsx(Switch, { on: settings.dots, onSwitch: (on) => set("dots", on), children: text.dots }), _jsx(Switch, { on: settings.squareNames, onSwitch: (on) => set("squareNames", on), children: text.squareNames }), _jsx(Switch, { on: settings.explain, onSwitch: (on) => set("explain", on), children: text.explain }), _jsx(Switch, { on: settings.book, onSwitch: (on) => set("book", on), children: text.bookBadges }), _jsx(Switch, { on: settings.helps, onSwitch: (on) => set("helps", on), children: text.helps }), _jsx(Switch, { on: settings.sound, onSwitch: (on) => set("sound", on), children: text.sounds }), _jsx(Switch, { on: settings.voice, onSwitch: (on) => set("voice", on), ...(voiced ? {} : { unavailable: text.noVoice }), children: text.voice })] }), _jsx(Section, { title: text.languageChoice, icon: languageIcon, children: _jsx(Segments, { label: text.languageChoice, children: ["auto", "it", "en"].map((language) => _jsx(Choice, { on: settings.language === language, onPick: () => set("language", language), children: text.languages[language] }, language)) }) })] })] })] }));
19
21
  }
20
22
  // The sections' line icons: a palette, a pawn, a globe.
21
23
  const lookIcon = (_jsxs(_Fragment, { children: [_jsx("path", { d: "M12 3a9 9 0 1 0 0 18c1.2 0 1.8-.8 1.8-1.7 0-1.2-1-1.6-1-2.6 0-1 .8-1.7 1.8-1.7H17a4 4 0 0 0 4-4C21 6.5 17 3 12 3Z" }), _jsx("circle", { cx: "7.5", cy: "11", r: "1.2" }), _jsx("circle", { cx: "10", cy: "7", r: "1.2" }), _jsx("circle", { cx: "14.5", cy: "7", r: "1.2" })] }));
@@ -34,8 +36,20 @@ function Segments({ label, children }) {
34
36
  function Choice({ on, onPick, children }) {
35
37
  return (_jsx("button", { type: "button", role: "radio", "aria-checked": on, onClick: onPick, children: children }));
36
38
  }
37
- function Switch({ on, onSwitch, children }) {
38
- return (_jsxs("label", { class: "switch", children: [_jsx("span", { children: children }), _jsx("input", { type: "checkbox", role: "switch", checked: on, onChange: (event) => onSwitch(event.currentTarget.checked) })] }));
39
+ /** A switch; one that cannot be used here is off and disabled, and its tooltip says why. */
40
+ function Switch({ on, onSwitch, unavailable, children }) {
41
+ const usable = unavailable === undefined;
42
+ return (_jsxs("label", { class: "switch", title: unavailable, children: [_jsx("span", { children: children }), _jsx("input", { type: "checkbox", role: "switch", checked: on && usable, disabled: !usable, title: unavailable, onChange: (event) => onSwitch(event.currentTarget.checked) })] }));
43
+ }
44
+ /** Whether the browser has a voice for the language, looked at again whenever its voices change. */
45
+ function useVoiced(language) {
46
+ const [voiced, setVoiced] = useState(() => hasVoice(language));
47
+ useEffect(() => {
48
+ const look = () => setVoiced(hasVoice(language));
49
+ look();
50
+ return onVoices(look);
51
+ }, [language]);
52
+ return voiced;
39
53
  }
40
54
  function nameOf(id, text) {
41
55
  return text.names[id] ?? id;
@@ -14,7 +14,7 @@ export function GameColumn({ plies, result, how, lit, started, move, toMove, ope
14
14
  const bar = standings === undefined ? undefined : _jsx(LeadBar, { standing: standingAt(standings, shownPlies), shown: shownPlies, text: text });
15
15
  return (_jsx("aside", { class: "side", id: "game", "aria-label": text.game, children: started === undefined && analysis === undefined
16
16
  ? (_jsxs(_Fragment, { children: [_jsx("p", { class: "card empty", children: text.noGame }), onAnalyse === undefined ? null : _jsx(AnalyseButton, { label: text.study.analyseLast, onAnalyse: onAnalyse })] }))
17
- : (_jsxs(_Fragment, { children: [_jsx(GameCard, { plies: plies, result: result, how: how, lit: lit, started: started, move: move, toMove: toMove, bar: bar, text: text }), analysis === undefined || standings === undefined ? null : _jsx(LeadChart, { plies: plies, standings: standings, shown: shownPlies, onShow: onShow, text: text }), opening === undefined ? null : _jsx(OpeningCard, { opening: opening, text: text }), helps, analysis === undefined || analysis.summary !== undefined ? null : (_jsxs("p", { class: "card review waiting", role: "status", children: [_jsx("span", { class: "spinner", "aria-hidden": "true" }), text.reviewing(analysis.by)] })), result !== undefined && plies.length === 0 ? null : _jsx(MoveList, { plies: plies, result: result, shown: shownPlies, onShow: onShow, tools: legend, text: text }), onDownload === undefined && onSaveMoves === undefined ? null : (_jsxs("div", { class: "card analysis-actions", children: [onDownload === undefined ? null : _jsx(SaveButton, { label: text.study.download, hint: text.study.downloadHint, onSave: onDownload }), onSaveMoves === undefined ? null : _jsx(SaveButton, { label: text.saveMoves, hint: text.saveMovesHint, onSave: onSaveMoves })] })), onAnalyse === undefined ? null : _jsx(AnalyseButton, { label: text.study.analyseIt, onAnalyse: onAnalyse }), _jsx(Steps, { shown: shownPlies, total: plies.length, onStep: onStep, text: text })] })) }));
17
+ : (_jsxs(_Fragment, { children: [_jsxs("div", { class: "side-cards", children: [_jsx(GameCard, { plies: plies, result: result, how: how, lit: lit, started: started, move: move, toMove: toMove, bar: bar, text: text }), analysis?.reviewing !== true ? null : (_jsxs("p", { class: "card review waiting", role: "status", children: [_jsx("span", { class: "spinner", "aria-hidden": "true" }), text.reviewing(analysis.by)] })), analysis?.onComplete === undefined ? null : (_jsxs("div", { class: "card review incomplete", children: [_jsx("p", { role: "status", children: text.incomplete }), _jsx("button", { type: "button", title: text.completeHint, "aria-label": text.completeHint, onClick: analysis.onComplete, children: text.complete })] })), analysis === undefined || standings === undefined ? null : _jsx(LeadChart, { plies: plies, standings: standings, shown: shownPlies, onShow: onShow, text: text }), opening === undefined ? null : _jsx(OpeningCard, { opening: opening, text: text }), helps] }), _jsxs("div", { class: "side-foot", children: [result !== undefined && plies.length === 0 ? null : _jsx(MoveList, { plies: plies, result: result, shown: shownPlies, onShow: onShow, tools: legend, text: text }), onDownload === undefined && onSaveMoves === undefined ? null : (_jsxs("div", { class: "card analysis-actions", children: [onDownload === undefined ? null : _jsx(SaveButton, { label: text.study.download, hint: text.study.downloadHint, onSave: onDownload }), onSaveMoves === undefined ? null : _jsx(SaveButton, { label: text.saveMoves, hint: text.saveMovesHint, onSave: onSaveMoves })] })), onAnalyse === undefined ? null : _jsx(AnalyseButton, { label: text.study.analyseIt, onAnalyse: onAnalyse }), _jsx(Steps, { shown: shownPlies, total: plies.length, onStep: onStep, text: text })] })] })) }));
18
18
  }
19
19
  /** A button that saves the game as a file in the player's downloads, its tooltip saying what the file holds. */
20
20
  function SaveButton({ label, hint, onSave }) {
@@ -320,6 +320,27 @@
320
320
  color: var(--soft);
321
321
  }
322
322
 
323
+ /* A review nobody is finishing: the note, and beside it the button that brings the game back to the AI (D-109); neutral, as no error (Zoe) */
324
+ .review.incomplete,
325
+ .say.incomplete {
326
+ display: flex;
327
+ align-items: center;
328
+ justify-content: space-between;
329
+ gap: 8px;
330
+ margin: 0;
331
+ color: var(--soft);
332
+ }
333
+
334
+ .review.incomplete button,
335
+ .say.incomplete button {
336
+ flex: none;
337
+ }
338
+
339
+ /* On the bubble's tint the button keeps the card's ground, to read as one */
340
+ .say.incomplete button {
341
+ background: var(--card);
342
+ }
343
+
323
344
  .review ul {
324
345
  margin: 0;
325
346
  padding-left: 18px;
@@ -497,7 +518,8 @@
497
518
  padding: 8px;
498
519
  }
499
520
 
500
- .analysis-actions button {
521
+ .analysis-actions button,
522
+ .incomplete button {
501
523
  flex: 1;
502
524
  display: inline-flex;
503
525
  align-items: center;
@@ -513,7 +535,8 @@
513
535
  cursor: pointer;
514
536
  }
515
537
 
516
- .analysis-actions button:hover {
538
+ .analysis-actions button:hover,
539
+ .incomplete button:hover {
517
540
  border-color: var(--accent);
518
541
  }
519
542
 
@@ -584,6 +607,6 @@
584
607
  }
585
608
 
586
609
  /* The saves and the steps stay at the foot of the column, with the moves folded too (Stefano) */
587
- .side > .moves-card + * {
610
+ .side-foot > .moves-card + * {
588
611
  margin-top: auto;
589
612
  }
@@ -1,4 +1,5 @@
1
- // The markdown the guide is written in, read into blocks: headings, paragraphs, lists, tables, quotes, code; its comments left out. markdown.tsx draws them.
1
+ // The markdown the guide is written in, read into blocks: headings, paragraphs, lists, tables, quotes, code and drawings; its comments left out. markdown.tsx
2
+ // draws them.
2
3
  // Copied from rpg-engine's guide (src/dashboard/help/blocks.ts), without the headings' icons and the cards' previews.
3
4
  /** The blocks of a markdown text. */
4
5
  export function markdownBlocks(text) {
@@ -16,9 +17,14 @@ export function markdownBlocks(text) {
16
17
  };
17
18
  for (let line = lines[index]; line !== undefined; line = lines[index]) {
18
19
  const heading = /^(#{1,6})\s+(.*?)\s*$/.exec(line);
20
+ const drawing = drawingOf(line);
19
21
  if (line.trim() === "") {
20
22
  index += 1;
21
23
  }
24
+ else if (drawing !== undefined) {
25
+ blocks.push(drawing);
26
+ index += 1;
27
+ }
22
28
  else if (heading !== null) {
23
29
  blocks.push({ kind: "heading", level: heading[1]?.length ?? 1, text: heading[2] ?? "" });
24
30
  index += 1;
@@ -46,7 +52,7 @@ export function markdownBlocks(text) {
46
52
  blocks.push({ kind: "list", ordered, items: items.reduce((all, one) => (listItem(one) === undefined ? [...all.slice(0, -1), `${all.at(-1) ?? ""} ${one.trim()}`] : [...all, listItem(one)?.text ?? ""]), []) });
47
53
  }
48
54
  else {
49
- const paragraph = run((one) => one.trim() !== "" && !/^(#{1,6}\s|```|>|\|)/.test(one) && listItem(one) === undefined);
55
+ const paragraph = run((one) => one.trim() !== "" && !/^(#{1,6}\s|```|>|\|)/.test(one) && listItem(one) === undefined && drawingOf(one) === undefined);
50
56
  blocks.push({ kind: "paragraph", text: paragraph.map((one) => one.trim()).join(" ") });
51
57
  }
52
58
  }
@@ -56,6 +62,11 @@ export function markdownBlocks(text) {
56
62
  export function anchorOf(heading) {
57
63
  return heading.trim().toLowerCase().replace(/[^\p{L}\p{N}\s_-]/gu, "").replace(/\s/g, "-");
58
64
  }
65
+ /** A drawing on a line of its own: ![what it shows](its name); undefined for another line. */
66
+ function drawingOf(line) {
67
+ const drawing = /^!\[([^\]]*)\]\(([\w-]+)\)$/.exec(line.trim());
68
+ return drawing === null ? undefined : { kind: "drawing", name: drawing[2] ?? "", alt: drawing[1] ?? "" };
69
+ }
59
70
  /** A list item's mark and text: - text, or 1. text; undefined for another line. */
60
71
  function listItem(line) {
61
72
  const item = /^([-*]|\d+\.)\s+(.*)$/.exec(line);
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "preact/jsx-runtime";
2
+ import { Inline } from "./markdown.js";
3
+ /** The credits' page of the guide, under the title the guide gives every page. */
4
+ export function GuideCredits({ text }) {
5
+ return (_jsx("ul", { children: text.guide.creditLines.map((line) => (_jsx("li", { children: _jsx(Inline, { text: line, go: () => undefined }) }, line))) }));
6
+ }
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
+ // Looking back at a game: the moves with their judgements, the one shown on the board in gold, and the bar of steps to the start, back, on and to the end
3
+ import { Badge, Bar, Board, Card, Chevron, Pieces, Square } from "./parts.js";
4
+ const grid = { x: 16, y: 10, cell: 25 };
5
+ const position = ["r...r.k.", "pp...ppp", "..n.....", "...p....", "...P.B..", "..N..Q..", "PP...PPP", "R....RK."];
6
+ /** The board at a move judged a mistake, the Moves card and the steps under it. */
7
+ export function Analysis() {
8
+ return (_jsxs("svg", { class: "guide-art", viewBox: "0 0 480 220", "aria-hidden": "true", children: [_jsxs(Board, { grid: grid, children: [_jsx(Square, { grid: grid, file: 3, rank: 1, class: "last" }), _jsx(Square, { grid: grid, file: 5, rank: 3, class: "last" }), _jsx(Pieces, { grid: grid, ranks: position })] }), _jsx(Badge, { x: 163, y: 138, r: 6.5, kind: "mistake" }), _jsx(Card, { x: 236, y: 10, width: 228, height: 134 }), _jsx(Bar, { x: 248, y: 20.5, width: 48, strong: true }), _jsx("rect", { class: "quote", x: "242", y: "34", width: "216", height: "20", rx: "4" }), _jsx(Move, { y: 34, white: "best" }), _jsx(Move, { y: 58, black: "mistake" }), _jsx("rect", { class: "quote", x: "242", y: "82", width: "216", height: "20", rx: "4" }), _jsx(Move, { y: 82, white: "blunder", black: "best" }), _jsx("rect", { class: "last", x: "258", y: "108", width: "66", height: "16", rx: "4" }), _jsx(Move, { y: 106, white: "mistake", shown: true }), _jsx(Card, { x: 236, y: 156, width: 228, height: 54 }), _jsxs("g", { class: "accent-line", children: [_jsx("path", { d: "M259 177V189" }), _jsx(Chevron, { x: 268, y: 183, size: 12, left: true }), _jsx(Chevron, { x: 321.5, y: 183, size: 12, left: true }), _jsx(Chevron, { x: 378.5, y: 183, size: 12 }), _jsx(Chevron, { x: 432, y: 183, size: 12 }), _jsx("path", { d: "M441 177V189" })] })] }));
9
+ }
10
+ /** A row of the moves: its number, White's move and Black's, each with its badge if it has one; `shown` when White's is the one on the board. */
11
+ function Move({ y, white, black, shown = false }) {
12
+ return (_jsxs("g", { children: [_jsx(Bar, { x: 246, y: y + 7.5, width: 8 }), _jsx(Bar, { x: 264, y: y + 7.5, width: 36, strong: true, class: shown ? "bar on-last" : undefined }), white !== undefined && _jsx(Badge, { x: 312, y: y + 10, r: 6, kind: white }), _jsx(Bar, { x: 350, y: y + 7.5, width: 36, strong: true }), black !== undefined && _jsx(Badge, { x: 398, y: y + 10, r: 6, kind: black })] }));
13
+ }
@@ -0,0 +1,329 @@
1
+ /* The guide's drawings (Zoe): sketches of the page on its own ground, every colour from the theme, so one drawing serves light and dark */
2
+
3
+ .guide-drawing {
4
+ max-width: 520px;
5
+ margin: 6px auto 16px;
6
+ overflow: hidden;
7
+ border: 1px solid var(--line);
8
+ border-radius: var(--radius);
9
+ background: var(--page);
10
+ }
11
+
12
+ .guide-art {
13
+ display: block;
14
+ width: 100%;
15
+ height: auto;
16
+ aspect-ratio: 480 / 220;
17
+ }
18
+
19
+ /* The page's cards and what is written on them, as bars */
20
+ .guide-art .paper {
21
+ fill: var(--card);
22
+ stroke: var(--line);
23
+ stroke-width: 1.5;
24
+ }
25
+
26
+ .guide-art .quote {
27
+ fill: var(--quote);
28
+ }
29
+
30
+ .guide-art .words {
31
+ fill: var(--say);
32
+ }
33
+
34
+ .guide-art .field {
35
+ fill: var(--page);
36
+ stroke: var(--line);
37
+ stroke-width: 1.5;
38
+ }
39
+
40
+ .guide-art .bar {
41
+ fill: color-mix(in oklab, var(--soft) 45%, var(--card));
42
+ }
43
+
44
+ .guide-art .bar.strong {
45
+ fill: color-mix(in oklab, var(--ink) 70%, var(--card));
46
+ }
47
+
48
+ .guide-art .bar.on-words {
49
+ fill: color-mix(in oklab, var(--say-ink) 55%, var(--say));
50
+ }
51
+
52
+ .guide-art .rule {
53
+ stroke: var(--line);
54
+ stroke-width: 1.5;
55
+ }
56
+
57
+ .guide-art .bullet {
58
+ fill: color-mix(in oklab, var(--soft) 60%, var(--card));
59
+ }
60
+
61
+ .guide-art .button,
62
+ .guide-art .soft-line {
63
+ fill: none;
64
+ stroke: var(--soft);
65
+ stroke-width: 1.5;
66
+ stroke-linecap: round;
67
+ }
68
+
69
+ /* What the page speaks of, in the accent */
70
+ .guide-art .accent {
71
+ fill: var(--accent);
72
+ }
73
+
74
+ .guide-art .bar.on-last {
75
+ fill: color-mix(in oklab, var(--fixed-ink) 70%, transparent);
76
+ }
77
+
78
+ .guide-art .bar.on-accent {
79
+ fill: var(--on-accent);
80
+ }
81
+
82
+ .guide-art .accent-line,
83
+ .guide-art .on-accent-line,
84
+ .guide-art .thread {
85
+ fill: none;
86
+ stroke: var(--accent);
87
+ stroke-width: 2.5;
88
+ stroke-linecap: round;
89
+ stroke-linejoin: round;
90
+ }
91
+
92
+ .guide-art .on-accent-line {
93
+ stroke: var(--on-accent);
94
+ stroke-width: 2;
95
+ }
96
+
97
+ /* The tick of the player in use and the pencil to their profile, as the window of the players draws them */
98
+ .guide-art .tick,
99
+ .guide-art .pencil {
100
+ fill: none;
101
+ stroke: var(--accent);
102
+ stroke-linecap: round;
103
+ stroke-linejoin: round;
104
+ }
105
+
106
+ .guide-art .tick {
107
+ stroke-width: 2;
108
+ }
109
+
110
+ .guide-art .pencil {
111
+ stroke-width: 2.4;
112
+ }
113
+
114
+
115
+ .guide-art .knot,
116
+ .guide-art .caret {
117
+ fill: var(--accent);
118
+ }
119
+
120
+ .guide-art .focused,
121
+ .guide-art .call {
122
+ fill: var(--card);
123
+ stroke: var(--accent);
124
+ stroke-width: 2;
125
+ }
126
+
127
+ .guide-art .call-square,
128
+ .guide-art .chosen {
129
+ fill: none;
130
+ stroke: var(--accent);
131
+ stroke-width: 1.5;
132
+ }
133
+
134
+ .guide-art .chosen {
135
+ stroke-width: 2.5;
136
+ }
137
+
138
+ /* The board and what the page draws on it */
139
+ .guide-art .light {
140
+ fill: var(--light-square);
141
+ }
142
+
143
+ .guide-art .dark {
144
+ fill: var(--dark-square);
145
+ }
146
+
147
+ .guide-art .last {
148
+ fill: var(--last-move);
149
+ }
150
+
151
+ .guide-art .hint {
152
+ fill: var(--hint);
153
+ }
154
+
155
+ .guide-art .over {
156
+ fill: none;
157
+ stroke: var(--hover-edge);
158
+ stroke-width: 2.5;
159
+ }
160
+
161
+ .guide-art .ghost {
162
+ opacity: var(--ghost);
163
+ }
164
+
165
+ .guide-art .lift-shadow {
166
+ fill: var(--lift-shadow);
167
+ opacity: 0.6;
168
+ }
169
+
170
+ .guide-art .pointer {
171
+ fill: var(--ink);
172
+ stroke: var(--card);
173
+ stroke-width: 1.2;
174
+ stroke-linejoin: round;
175
+ }
176
+
177
+ .guide-art .drawn {
178
+ stroke: var(--help-halo);
179
+ stroke-width: 1.2;
180
+ stroke-linejoin: round;
181
+ opacity: 0.85;
182
+ }
183
+
184
+ .guide-art .drawn.green {
185
+ fill: var(--drawn-green);
186
+ }
187
+
188
+ .guide-art .help-halo,
189
+ .guide-art .help-line {
190
+ fill: none;
191
+ stroke-linecap: round;
192
+ }
193
+
194
+ .guide-art .help-halo {
195
+ stroke: var(--help-halo);
196
+ stroke-width: 4.5;
197
+ }
198
+
199
+ .guide-art .help-line {
200
+ stroke: var(--help-line);
201
+ stroke-width: 2.2;
202
+ stroke-dasharray: 5 4;
203
+ }
204
+
205
+ .guide-art .danger {
206
+ fill: var(--drawn-red);
207
+ }
208
+
209
+ .guide-art .danger-line {
210
+ stroke: var(--drawn-red);
211
+ stroke-width: 2;
212
+ stroke-linecap: round;
213
+ }
214
+
215
+ .guide-art .danger-dot {
216
+ fill: var(--help-on);
217
+ }
218
+
219
+ .guide-art .danger-row {
220
+ fill: color-mix(in oklab, var(--drawn-red) 12%, var(--card));
221
+ }
222
+
223
+ /* The move badges: a disc in the colour of the judgement, a white sign */
224
+ .guide-art .judgement.best {
225
+ fill: var(--badge-best);
226
+ }
227
+
228
+ .guide-art .judgement.mistake {
229
+ fill: var(--badge-mistake);
230
+ }
231
+
232
+ .guide-art .judgement.blunder {
233
+ fill: var(--badge-blunder);
234
+ }
235
+
236
+ .guide-art .sign {
237
+ fill: none;
238
+ stroke: var(--badge-ink);
239
+ stroke-linecap: round;
240
+ stroke-linejoin: round;
241
+ }
242
+
243
+ .guide-art .sign .dot {
244
+ fill: var(--badge-ink);
245
+ stroke: none;
246
+ }
247
+
248
+ .guide-art .clock {
249
+ fill: none;
250
+ stroke: var(--soft);
251
+ stroke-width: 1.3;
252
+ stroke-linecap: round;
253
+ }
254
+
255
+ .guide-art .clock.on-accent {
256
+ stroke: var(--on-accent);
257
+ }
258
+
259
+ /* The Torretta, and the players' faces on their discs */
260
+ .guide-art .tower .antenna {
261
+ fill: none;
262
+ stroke: var(--torretta-shade);
263
+ stroke-width: 4;
264
+ stroke-linecap: round;
265
+ }
266
+
267
+ .guide-art .tower .light-bulb {
268
+ fill: var(--torretta-light);
269
+ }
270
+
271
+ .guide-art .tower .shade {
272
+ fill: var(--torretta-shade);
273
+ }
274
+
275
+ .guide-art .tower .body {
276
+ fill: var(--torretta-body);
277
+ }
278
+
279
+ .guide-art .tower .screen {
280
+ fill: var(--torretta-screen);
281
+ }
282
+
283
+ .guide-art .tower .features {
284
+ fill: var(--torretta-face);
285
+ }
286
+
287
+ .guide-art .person {
288
+ fill: var(--card);
289
+ }
290
+
291
+ .guide-art .tone-player {
292
+ fill: var(--badge-brilliant);
293
+ }
294
+
295
+ .guide-art .tone-1 {
296
+ fill: var(--badge-great);
297
+ }
298
+
299
+ .guide-art .tone-2 {
300
+ fill: var(--badge-book);
301
+ }
302
+
303
+ .guide-art .tone-3 {
304
+ fill: var(--badge-excellent);
305
+ }
306
+
307
+ .guide-art .tone-4 {
308
+ fill: var(--badge-miss);
309
+ }
310
+
311
+ .guide-art .tone-5 {
312
+ fill: var(--badge-note);
313
+ }
314
+
315
+ .guide-art .tone-6 {
316
+ fill: var(--badge-mistake);
317
+ }
318
+
319
+ .guide-art .tone-7 {
320
+ fill: var(--badge-good);
321
+ }
322
+
323
+ .guide-art .tone-8 {
324
+ fill: var(--badge-inaccuracy);
325
+ }
326
+
327
+ .guide-art .tone-9 {
328
+ fill: var(--torretta-body);
329
+ }
@@ -0,0 +1,15 @@
1
+ import { Analysis } from "./analysis.js";
2
+ import { Game } from "./game.js";
3
+ import { Helps } from "./helps.js";
4
+ import { HowItWorks } from "./how-it-works.js";
5
+ import { Players } from "./players.js";
6
+ import { Talk } from "./talk.js";
7
+ /** The guide's drawings, by the name its markdown gives them: ![what it shows](name). */
8
+ export const drawings = {
9
+ "how-it-works": HowItWorks,
10
+ game: Game,
11
+ talk: Talk,
12
+ helps: Helps,
13
+ analysis: Analysis,
14
+ players: Players,
15
+ };
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
+ // Playing a move: a knight lifted from its square under the pointer, the dots of where it may go, the gold edge where it would land, and the player's clock running
3
+ import { Bar, Board, Card, centre, Clock, corner, Face, PieceAt, PieceOn, Pieces, Square, Torretta } from "./parts.js";
4
+ const grid = { x: 140, y: 10, cell: 25 };
5
+ const position = ["rnbqkbnr", "pppp.ppp", "........", "....p...", "....P...", "........", "PPPP.PPP", "RNBQKB.R"];
6
+ /** The board after 1.e4 e5 with White's knight in the air, the two players' cards on the left and the moves on the right. */
7
+ export function Game() {
8
+ const over = corner(grid, 5, 3);
9
+ return (_jsxs("svg", { class: "guide-art", viewBox: "0 0 480 220", "aria-hidden": "true", children: [_jsxs(Board, { grid: grid, children: [_jsx(Square, { grid: grid, file: 4, rank: 7, class: "last" }), _jsx(Square, { grid: grid, file: 4, rank: 5, class: "last" }), _jsx(Pieces, { grid: grid, ranks: position }), _jsx(PieceOn, { grid: grid, file: 6, rank: 1, letter: "N", class: "ghost" }), _jsx(Dot, { file: 4, rank: 2 }), _jsx(Dot, { file: 7, rank: 3 }), _jsx("rect", { class: "over", x: over.x + 1.25, y: over.y + 1.25, width: grid.cell - 2.5, height: grid.cell - 2.5 })] }), _jsx("ellipse", { class: "lift-shadow", cx: over.x + 13, cy: over.y + 20, rx: "11", ry: "3.5" }), _jsx(PieceAt, { x: over.x - 3.5, y: over.y - 15, size: 32, letter: "N" }), _jsx("path", { class: "pointer", transform: `translate(${over.x + 17} ${over.y + 8})`, d: "M0 0V13L3.5 10L6 15.5L8.2 14.5L5.8 9.3H10Z" }), _jsx(Card, { x: 16, y: 10, width: 112, height: 48 }), _jsx(Torretta, { x: 18, y: 14, size: 32, bust: true }), _jsx(Bar, { x: 54, y: 20, width: 46, strong: true }), _jsx(Bar, { x: 54, y: 30, width: 30 }), _jsx("rect", { class: "quote", x: "54", y: "40", width: "44", height: "12", rx: "6" }), _jsx(Clock, { x: 61, y: 46, r: 3.4 }), _jsx(Bar, { x: 68, y: 43.5, width: 24 }), _jsx(Card, { x: 16, y: 162, width: 112, height: 48 }), _jsx(Face, { x: 34, y: 180, r: 12, tone: "tone-player" }), _jsx(Bar, { x: 54, y: 170, width: 46, strong: true }), _jsx(Bar, { x: 54, y: 180, width: 30 }), _jsx("rect", { class: "accent", x: "54", y: "192", width: "44", height: "12", rx: "6" }), _jsx(Clock, { x: 61, y: 198, r: 3.4, class: "clock on-accent" }), _jsx(Bar, { x: 68, y: 195.5, width: 24, class: "bar on-accent" }), _jsx(Card, { x: 352, y: 10, width: 112, height: 44 }), _jsx(Bar, { x: 362, y: 22, width: 70, strong: true }), _jsx(Bar, { x: 362, y: 34, width: 52 }), _jsx(Card, { x: 352, y: 150, width: 112, height: 60 }), _jsx(Bar, { x: 362, y: 162, width: 40, strong: true }), _jsx(Bar, { x: 362, y: 184, width: 8 }), _jsx(Bar, { x: 378, y: 184, width: 28 }), _jsx("rect", { class: "last", x: "414", y: "179", width: "40", height: "15", rx: "4" }), _jsx(Bar, { x: 420, y: 184, width: 28, class: "bar on-last" })] }));
10
+ }
11
+ /** The dot of a square the lifted piece may go to. */
12
+ function Dot({ file, rank }) {
13
+ const { x, y } = centre(grid, file, rank);
14
+ return _jsx("circle", { class: "hint", cx: x, cy: y, r: grid.cell * 0.165 });
15
+ }
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
+ import { Arrow, Badge, Bar, Board, Card, centre, Pieces, Square } from "./parts.js";
3
+ const grid = { x: 16, y: 10, cell: 25 };
4
+ const position = ["...qk...", ".....ppp", "p.n.....", ".B..p...", "....P...", "..N..N..", ".....PPP", ".....RK."];
5
+ /** The board with its marks, and the Helps card open on its first tab. */
6
+ export function Helps() {
7
+ const bishop = centre(grid, 1, 5);
8
+ return (_jsxs("svg", { class: "guide-art", viewBox: "0 0 480 220", "aria-hidden": "true", children: [_jsxs(Board, { grid: grid, children: [_jsx(Square, { grid: grid, file: 0, rank: 7, class: "last" }), _jsx(Square, { grid: grid, file: 0, rank: 6, class: "last" }), _jsx(Pieces, { grid: grid, ranks: position })] }), _jsx("path", { class: "help-halo", d: `M${bishop.x} ${bishop.y}L116 35` }), _jsx("path", { class: "help-line", d: `M${bishop.x} ${bishop.y}L116 35` }), _jsx("path", { class: "danger", d: "M41 110V97L54 110Z" }), _jsx("circle", { class: "danger-dot", cx: "44.5", cy: "106", r: "1.7" }), _jsx(Arrow, { from: centre(grid, 5, 3), to: centre(grid, 4, 5), width: 5, class: "drawn green" }), _jsx(Badge, { x: 38, y: 63, r: 6.5, kind: "best" }), _jsx(Card, { x: 236, y: 36, width: 228, height: 148 }), _jsx("circle", { class: "accent-line", cx: "252", cy: "55", r: "5.5" }), _jsx("circle", { class: "accent", cx: "252", cy: "55", r: "2" }), _jsx(Bar, { x: 264, y: 52.5, width: 44, class: "bar accent" }), _jsx("rect", { class: "button", x: "420", y: "48", width: "14", height: "14", rx: "3" }), _jsx("rect", { class: "button", x: "440", y: "48", width: "14", height: "14", rx: "3" }), _jsx(Bar, { x: 250, y: 70, width: 34, strong: true }), _jsx(Bar, { x: 298, y: 70, width: 40 }), _jsx("path", { class: "rule", d: "M246 85.5H454" }), _jsx("rect", { class: "accent", x: "246", y: "82", width: "42", height: "2.5", rx: "1" }), _jsx(Row, { y: 96, width: 96, children: _jsx("path", { class: "danger", d: "M252 112V100L264 112Z" }) }), _jsxs(Row, { y: 124, width: 88, children: [_jsx("path", { class: "danger-line", d: "M253 141L259 135" }), _jsx("circle", { class: "danger", cx: "260.5", cy: "133.5", r: "3.5" })] }), _jsx("rect", { class: "quote", x: "246", y: "152", width: "208", height: "22", rx: "4" }), _jsx("circle", { class: "soft-line", cx: "257", cy: "163", r: "4.5" }), _jsx(Bar, { x: 272, y: 160.5, width: 112 }), _jsx(Bar, { x: 418, y: 160.5, width: 8, strong: true }), _jsx(Bar, { x: 434, y: 160.5, width: 8, strong: true })] }));
9
+ }
10
+ /** A row of the card about the player's pieces in trouble: a red tint and edge, its sign, a line and a count. */
11
+ function Row({ y, width, children }) {
12
+ return (_jsxs("g", { children: [_jsx("rect", { class: "danger-row", x: "246", y: y, width: "208", height: "22", rx: "4" }), _jsx("rect", { class: "danger", x: "246", y: y, width: "3", height: "22" }), children, _jsx(Bar, { x: 272, y: y + 8.5, width: width, strong: true }), _jsx(Bar, { x: 434, y: y + 8.5, width: 8, strong: true })] }));
13
+ }
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
+ // How Chesspal works: the board's page and the AI's chat, two windows tied by a thread, the call through which the AI plays
3
+ import { Bar, Board, Card, Chevron, Face, Pieces, Square, Torretta } from "./parts.js";
4
+ const grid = { x: 26, y: 42, cell: 19 };
5
+ const position = [".....rk.", ".....ppp", "..n.....", "....p...", "....P...", ".....N..", ".....PPP", ".....RK."];
6
+ /** The page with its board and the Torretta, the chat beside it, and the thread between them. */
7
+ export function HowItWorks() {
8
+ return (_jsxs("svg", { class: "guide-art", viewBox: "0 0 480 220", "aria-hidden": "true", children: [_jsx(Window, { x: 16, width: 212 }), _jsxs(Board, { grid: grid, children: [_jsx(Square, { grid: grid, file: 1, rank: 8, class: "last" }), _jsx(Square, { grid: grid, file: 2, rank: 6, class: "last" }), _jsx(Pieces, { grid: grid, ranks: position })] }), _jsx(Torretta, { x: 186, y: 40, size: 32 }), _jsx(Bar, { x: 190, y: 78, width: 26, strong: true }), _jsx(Bar, { x: 190, y: 88, width: 18 }), _jsx(Face, { x: 203, y: 182, r: 11, tone: "tone-player" }), _jsx(Window, { x: 278, width: 186 }), _jsx(Card, { x: 288, y: 40, width: 166, height: 24, class: "quote" }), _jsx(Bar, { x: 296, y: 49, width: 100, strong: true }), _jsx("circle", { class: "bullet", cx: "293", cy: "78", r: "2.5" }), _jsx(Bar, { x: 300, y: 75, width: 130 }), _jsx(Bar, { x: 300, y: 86, width: 96 }), _jsx(Card, { x: 288, y: 102, width: 166, height: 26, class: "call" }), _jsx("rect", { class: "light", x: "296", y: "109", width: "12", height: "12" }), _jsx("rect", { class: "dark", x: "296", y: "109", width: "6", height: "6" }), _jsx("rect", { class: "dark", x: "302", y: "115", width: "6", height: "6" }), _jsx("rect", { class: "call-square", x: "296", y: "109", width: "12", height: "12" }), _jsx(Bar, { x: 316, y: 112, width: 74, strong: true }), _jsx("circle", { class: "bullet", cx: "293", cy: "146", r: "2.5" }), _jsx(Bar, { x: 300, y: 143, width: 120 }), _jsx(Bar, { x: 300, y: 154, width: 80 }), _jsx("rect", { class: "field", x: "288", y: "170", width: "166", height: "24", rx: "5" }), _jsx("g", { class: "accent-line", children: _jsx(Chevron, { x: 299, y: 182, size: 8 }) }), _jsx("rect", { class: "caret", x: "309", y: "176", width: "2", height: "12", rx: "1" }), _jsx("path", { class: "thread", d: "M228 108C258 108 258 115 288 115" }), _jsx("circle", { class: "knot", cx: "228", cy: "108", r: "4" }), _jsx("circle", { class: "knot", cx: "288", cy: "115", r: "4" })] }));
9
+ }
10
+ /** A window with its title bar and three dots, as tall as the drawing leaves. */
11
+ function Window({ x, width }) {
12
+ return (_jsxs("g", { children: [_jsx(Card, { x: x, y: 16, width: width, height: 188 }), _jsx("path", { class: "rule", d: `M${x} 32H${x + width}` }), _jsx("circle", { class: "bullet", cx: x + 11, cy: "24", r: "2.5" }), _jsx("circle", { class: "bullet", cx: x + 20, cy: "24", r: "2.5" }), _jsx("circle", { class: "bullet", cx: x + 29, cy: "24", r: "2.5" })] }));
13
+ }