chesspal 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/commands/analysis/analyse.js +7 -2
- package/dist/commands/analysis/annotate.js +6 -2
- package/dist/commands/answers/agents.d.ts +2 -0
- package/dist/commands/answers/agents.js +5 -0
- package/dist/commands/answers/index.d.ts +2 -2
- package/dist/commands/answers/index.js +2 -2
- package/dist/commands/answers/lines.js +3 -1
- package/dist/commands/answers/say.d.ts +7 -1
- package/dist/commands/answers/say.js +25 -7
- package/dist/commands/answers/study.d.ts +27 -5
- package/dist/commands/answers/study.js +121 -10
- package/dist/commands/game/look.d.ts +1 -0
- package/dist/commands/game/look.js +8 -8
- package/dist/commands/game/position.d.ts +1 -0
- package/dist/commands/game/position.js +5 -5
- package/dist/commands/index.d.ts +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/moods.d.ts +2 -0
- package/dist/core/moods.js +11 -2
- package/dist/games/analysis.d.ts +11 -0
- package/dist/games/analysis.js +23 -0
- package/dist/games/archive.d.ts +9 -1
- package/dist/games/archive.js +18 -1
- package/dist/games/current-game.d.ts +23 -1
- package/dist/games/current-game.js +6 -1
- package/dist/games/index.d.ts +3 -3
- package/dist/games/index.js +2 -2
- package/dist/page/app/app.js +148 -29
- package/dist/page/app/keys.js +16 -1
- package/dist/page/app/title.js +6 -3
- package/dist/page/board/board.css +6 -0
- package/dist/page/game/column.js +5 -4
- package/dist/page/game/game.css +150 -1
- package/dist/page/game/move-list.js +48 -10
- package/dist/page/game/variation.js +65 -0
- package/dist/page/guide/en.md +1 -0
- package/dist/page/guide/it.md +1 -0
- package/dist/page/table/window.js +8 -5
- package/dist/page/talk/chat.css +8 -0
- package/dist/page/talk/talk.js +20 -2
- package/dist/page/text.js +20 -0
- package/dist/server/bell/bell.d.ts +5 -2
- package/dist/server/bell/bell.js +36 -12
- package/dist/server/page/game.js +38 -7
- package/dist/server/page/page.js +1 -1
- package/dist/server/page/table.d.ts +12 -2
- package/dist/server/page/table.js +18 -6
- package/dist/server/table/hosts/chats.js +1 -1
- package/dist/server/table/hosts/play.d.ts +3 -1
- package/dist/server/table/hosts/play.js +6 -5
- package/dist/server/table/hosts/seat.d.ts +5 -1
- package/dist/server/table/hosts/seat.js +1 -1
- package/instructions/analysis.md +2 -2
- package/instructions/opponent.md +1 -1
- package/package.json +1 -1
package/dist/page/game/column.js
CHANGED
|
@@ -4,18 +4,19 @@ import { LeadBar, LeadChart } from "../lead/lead.js";
|
|
|
4
4
|
import { standingAt } from "../lead/view.js";
|
|
5
5
|
import { Piece } from "../pieces/pieces.js";
|
|
6
6
|
import { FoldButton, useCardFold } from "./card-fold.js";
|
|
7
|
-
import { MoveList, Steps } from "./move-list.js";
|
|
7
|
+
import { MoveList, Steps, stepsLine } from "./move-list.js";
|
|
8
8
|
import { ResultTile } from "./result-tile.js";
|
|
9
9
|
import { ReviewProgress } from "./review-progress.js";
|
|
10
10
|
/**
|
|
11
11
|
* The column, which the player folds with its tab; under the board, where three columns would leave the board small, always open. A game in analysis
|
|
12
12
|
* (D-69) says above the moves that the AI is going over it, until its word on the whole game comes, which the talk shows.
|
|
13
13
|
*/
|
|
14
|
-
export function GameColumn({ plies, result, how, lit, started, move, toMove, opening, outOfBook, helps, legend, standings, analysis, shownPlies, onShow, onStep, onDownload, onSaveMoves, onAnalyse, text }) {
|
|
15
|
-
|
|
14
|
+
export function GameColumn({ plies, result, how, lit, started, move, toMove, opening, outOfBook, helps, legend, standings, analysis, shownPlies, line, onShow, onStep, onDownload, onSaveMoves, onAnalyse, text }) {
|
|
15
|
+
// In a game the bar waits for the coach's first estimate: a host that runs no coach gives none (Stefano).
|
|
16
|
+
const bar = standings === undefined || (analysis === undefined && standings.length === 0) ? undefined : _jsx(LeadBar, { standing: standingAt(standings, shownPlies), shown: shownPlies, text: text });
|
|
16
17
|
return (_jsx("aside", { class: "side", id: "game", "aria-label": text.game, children: started === undefined && analysis === undefined
|
|
17
18
|
? (_jsxs(_Fragment, { children: [_jsx("p", { class: "card empty", children: text.noGame }), onAnalyse === undefined ? null : _jsx(AnalyseButton, { label: text.study.analyseLast, onAnalyse: onAnalyse })] }))
|
|
18
|
-
: (_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("div", { class: "card review waiting", children: [
|
|
19
|
+
: (_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("div", { class: "card review waiting", children: [_jsxs("p", { children: [_jsx("span", { role: "status", children: text.reviewing(analysis.by) }), analysis.onStop === undefined ? null : (_jsx("button", { type: "button", class: "stop-review", title: text.stopReview, "aria-label": text.stopReview, onClick: analysis.onStop, children: _jsx("svg", { class: "icon", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M7 7L17 17M17 7L7 17" }) }) }))] }), analysis.count === undefined ? null : _jsx(ReviewProgress, { count: analysis.count, label: text.reviewing(analysis.by) })] })), analysis?.onComplete === undefined ? null : (_jsxs("div", { class: "card review incomplete", children: [_jsxs("p", { children: [_jsx("span", { role: "status", children: text.incomplete }), _jsx("button", { type: "button", title: text.completeHint, "aria-label": text.completeHint, onClick: analysis.onComplete, children: text.complete })] }), analysis.count === undefined || analysis.count.done === 0 ? null : _jsx(ReviewProgress, { count: analysis.count, label: text.incomplete, stopped: true })] })), analysis === undefined || standings === undefined ? null : _jsx(LeadChart, { plies: plies, standings: standings, shown: shownPlies, onShow: onShow, text: text }), opening === undefined ? null : _jsx(OpeningCard, { opening: opening, ...(outOfBook === undefined ? {} : { outOfBook }), text: text }), helps] }), _jsxs("div", { class: "side-foot", children: [result !== undefined && plies.length === 0 ? null : _jsx(MoveList, { plies: plies, result: result, shown: shownPlies, ...(line === undefined ? {} : { line }), 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, ...stepsLine(line, plies), onStep: onStep, text: text })] })] })) }));
|
|
19
20
|
}
|
|
20
21
|
/** A button that saves the game as a file in the player's downloads, its tooltip saying what the file holds. */
|
|
21
22
|
function SaveButton({ label, hint, onSave }) {
|
package/dist/page/game/game.css
CHANGED
|
@@ -338,6 +338,7 @@
|
|
|
338
338
|
color: var(--soft);
|
|
339
339
|
}
|
|
340
340
|
|
|
341
|
+
.review.waiting > p,
|
|
341
342
|
.review.incomplete > p,
|
|
342
343
|
.say.incomplete > p {
|
|
343
344
|
display: flex;
|
|
@@ -504,7 +505,7 @@
|
|
|
504
505
|
font-weight: 600;
|
|
505
506
|
}
|
|
506
507
|
|
|
507
|
-
.moves li:nth-child(even) {
|
|
508
|
+
.moves li:nth-child(even of :not(.line)) {
|
|
508
509
|
background: var(--page);
|
|
509
510
|
}
|
|
510
511
|
|
|
@@ -555,6 +556,125 @@
|
|
|
555
556
|
box-shadow: 0 0 0 1.5px var(--card);
|
|
556
557
|
}
|
|
557
558
|
|
|
559
|
+
/* A variation in analysis (D-116): one row under the move it leaves from, indented, an accent edge on its left, its moves wrapping; the move it leaves
|
|
560
|
+
from underlined in the accent while the board shows the line */
|
|
561
|
+
.moves li.line {
|
|
562
|
+
display: flex;
|
|
563
|
+
align-items: flex-start;
|
|
564
|
+
gap: 2px;
|
|
565
|
+
margin: 2px 0 2px 24px;
|
|
566
|
+
padding: 2px 2px 2px 8px;
|
|
567
|
+
border-left: 3px solid var(--accent);
|
|
568
|
+
border-radius: 0 6px 6px 0;
|
|
569
|
+
background: color-mix(in oklab, var(--accent) 8%, var(--card));
|
|
570
|
+
font-size: 13px;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.line-moves {
|
|
574
|
+
flex: 1;
|
|
575
|
+
display: flex;
|
|
576
|
+
flex-wrap: wrap;
|
|
577
|
+
gap: 1px 2px;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
.moves .line .ply {
|
|
581
|
+
margin-left: 0;
|
|
582
|
+
padding: 1px 4px;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
.line-number {
|
|
586
|
+
color: var(--soft);
|
|
587
|
+
margin-right: 1px;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.moves .line .current .line-number {
|
|
591
|
+
color: #4d5866;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
.moves .ply.fork {
|
|
595
|
+
box-shadow: inset 0 -2px 0 var(--accent);
|
|
596
|
+
border-radius: 5px 5px 0 0;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/* Back on the game the line fades, its moves still a click away */
|
|
600
|
+
.moves li.line.faded {
|
|
601
|
+
opacity: 0.55;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
.moves li.line.faded:hover,
|
|
605
|
+
.moves li.line.faded:focus-within {
|
|
606
|
+
opacity: 0.85;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/* The button that asks the AI to analyse it, small in the accent beside the cross; off while no chat hears the player */
|
|
610
|
+
.analyse-line {
|
|
611
|
+
flex: none;
|
|
612
|
+
min-height: 24px;
|
|
613
|
+
padding: 1px 8px;
|
|
614
|
+
border: 1px solid var(--accent);
|
|
615
|
+
border-radius: 6px;
|
|
616
|
+
background: none;
|
|
617
|
+
color: var(--accent);
|
|
618
|
+
font: inherit;
|
|
619
|
+
font-size: 12px;
|
|
620
|
+
font-weight: 600;
|
|
621
|
+
cursor: pointer;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
.analyse-line:hover:not(:disabled) {
|
|
625
|
+
background: color-mix(in oklab, var(--accent) 14%, transparent);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
.analyse-line:disabled {
|
|
629
|
+
opacity: 0.45;
|
|
630
|
+
cursor: default;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/* The cross that closes it, at the row's end, as the one that stops the analysis asked; a finger's 32 pixels on a touch screen */
|
|
634
|
+
.close-line,
|
|
635
|
+
.stop-review {
|
|
636
|
+
display: grid;
|
|
637
|
+
place-items: center;
|
|
638
|
+
width: 24px;
|
|
639
|
+
height: 24px;
|
|
640
|
+
flex: none;
|
|
641
|
+
padding: 0;
|
|
642
|
+
border: 0;
|
|
643
|
+
border-radius: 50%;
|
|
644
|
+
background: none;
|
|
645
|
+
color: var(--soft);
|
|
646
|
+
cursor: pointer;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
.close-line:hover,
|
|
650
|
+
.stop-review:hover {
|
|
651
|
+
background: color-mix(in oklab, var(--ink) 9%, transparent);
|
|
652
|
+
color: var(--ink);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.close-line .icon,
|
|
656
|
+
.stop-review .icon {
|
|
657
|
+
width: 14px;
|
|
658
|
+
height: 14px;
|
|
659
|
+
stroke-width: 2.2;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
@media (pointer: coarse) {
|
|
663
|
+
.close-line,
|
|
664
|
+
.stop-review {
|
|
665
|
+
width: 32px;
|
|
666
|
+
height: 32px;
|
|
667
|
+
margin-block: -4px;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
@media (max-width: 479px) {
|
|
672
|
+
.moves li.line {
|
|
673
|
+
margin-left: 12px;
|
|
674
|
+
padding-left: 6px;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
558
678
|
/* The buttons that step through the moves, under them as on Lichess and chess.com */
|
|
559
679
|
.steps {
|
|
560
680
|
display: flex;
|
|
@@ -591,6 +711,35 @@
|
|
|
591
711
|
stroke-width: 2;
|
|
592
712
|
}
|
|
593
713
|
|
|
714
|
+
/* On a variation, the fork with the move it leaves from, in the accent: it takes the board back to the game */
|
|
715
|
+
.steps .fork-back {
|
|
716
|
+
flex: 1.6;
|
|
717
|
+
display: inline-flex;
|
|
718
|
+
align-items: center;
|
|
719
|
+
justify-content: center;
|
|
720
|
+
gap: 3px;
|
|
721
|
+
padding: 4px 6px;
|
|
722
|
+
border-color: var(--accent);
|
|
723
|
+
color: var(--accent);
|
|
724
|
+
font: inherit;
|
|
725
|
+
font-size: 13px;
|
|
726
|
+
white-space: nowrap;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
.steps .fork-back:hover {
|
|
730
|
+
border-color: var(--accent);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
.steps .fork-back span {
|
|
734
|
+
color: var(--ink);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
.steps .fork-icon {
|
|
738
|
+
width: 16px;
|
|
739
|
+
height: 16px;
|
|
740
|
+
flex: none;
|
|
741
|
+
}
|
|
742
|
+
|
|
594
743
|
/* A piece in a move: the set's small one, White's white and Black's black, edged so either shows on either theme */
|
|
595
744
|
.figurine {
|
|
596
745
|
display: inline-block;
|
|
@@ -1,22 +1,30 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
|
|
2
|
+
// The moves of the game beside the board, in pairs, with the pieces drawn as figures, the same in every language (D-50); the player looks back through them
|
|
3
|
+
// with a click on one or with the buttons under them. In analysis a variation the player plays is one row under the move it leaves from (D-116).
|
|
4
|
+
import { Fragment } from "preact";
|
|
2
5
|
import { useEffect, useRef } from "preact/hooks";
|
|
3
6
|
import { Figurine } from "../pieces/pieces.js";
|
|
4
7
|
import { BadgeIcon, NoteIcon } from "./badges.js";
|
|
5
8
|
import { FoldButton, useCardFold } from "./card-fold.js";
|
|
9
|
+
import { lineText, moveNumberOf } from "./variation.js";
|
|
6
10
|
/**
|
|
7
11
|
* The moves numbered in pairs, the one the board shows marked (`shown`, how many moves it shows), and the result once the game is over; a click on a move
|
|
8
12
|
* shows it. The list keeps its last move in sight, and the one shown while the player looks back.
|
|
9
13
|
*/
|
|
10
|
-
export function MoveList({ plies, result, shown, onShow, tools, text }) {
|
|
14
|
+
export function MoveList({ plies, result, shown, line, onShow, tools, text }) {
|
|
11
15
|
const list = useRef(null);
|
|
12
16
|
const [folded, toggleFold] = useCardFold("moves");
|
|
13
17
|
const rows = rowsOf(plies);
|
|
14
|
-
const
|
|
18
|
+
const onTheLine = line !== undefined && line.cursor > 0;
|
|
19
|
+
const current = onTheLine ? undefined : plies[shown - 1];
|
|
20
|
+
const fork = onTheLine ? plies[line.at - 1] : undefined;
|
|
21
|
+
// The line goes under the row of the move it leaves from, before the first row when it leaves from the start.
|
|
22
|
+
const lineAfter = line === undefined ? undefined : line.at === 0 ? -1 : rows.findIndex((row) => row.white === plies[line.at - 1] || row.black === plies[line.at - 1]);
|
|
15
23
|
useEffect(() => {
|
|
16
24
|
list.current?.scrollTo({ top: list.current.scrollHeight });
|
|
17
25
|
}, [plies.length]);
|
|
18
26
|
// Only the list scrolls to the move shown: the page under the board stays where the player has it.
|
|
19
|
-
useEffect(() => keepInSight(list.current), [shown]);
|
|
27
|
+
useEffect(() => keepInSight(list.current), [shown, line?.cursor, line?.plies.length]);
|
|
20
28
|
// The cards above it change height with the position, the helps' card above all: the list follows, its move still in sight.
|
|
21
29
|
useEffect(() => {
|
|
22
30
|
const element = list.current;
|
|
@@ -27,26 +35,56 @@ export function MoveList({ plies, result, shown, onShow, tools, text }) {
|
|
|
27
35
|
observer.observe(element);
|
|
28
36
|
return () => observer.disconnect();
|
|
29
37
|
}, []);
|
|
30
|
-
const move = (ply) => _jsx(Move, { ply: ply, current: ply !== undefined && ply === current, onShow: () => onShow(plies.indexOf(ply) + 1), text: text });
|
|
38
|
+
const move = (ply) => _jsx(Move, { ply: ply, current: ply !== undefined && ply === current, fork: ply !== undefined && ply === fork, onShow: () => onShow(plies.indexOf(ply) + 1), text: text });
|
|
39
|
+
const lineRow = line === undefined ? null : _jsx(LineRow, { line: line, text: text });
|
|
31
40
|
// The card's title with its icon, a score sheet, as the other cards of the column, which folds the card to it (Stefano); only the list under it
|
|
32
41
|
// scrolls, and it stays in the page while folded, so that it keeps its move in sight.
|
|
33
|
-
return (_jsxs("section", { class: `card moves-card${folded ? " folded" : ""}`, "aria-label": text.moves, children: [_jsxs("div", { class: "moves-head", children: [_jsx("h3", { class: "card-title", children: _jsxs(FoldButton, { folded: folded, onFold: toggleFold, text: text, children: [_jsx("svg", { class: "icon", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M6 3H15L19 7V21H6ZM15 3V7H19M9 11H16M9 14.5H16M9 18H13" }) }), text.moves] }) }), tools] }), _jsxs("div", { ref: list, class: "moves", hidden: folded, children: [
|
|
42
|
+
return (_jsxs("section", { class: `card moves-card${folded ? " folded" : ""}`, "aria-label": text.moves, children: [_jsxs("div", { class: "moves-head", children: [_jsx("h3", { class: "card-title", children: _jsxs(FoldButton, { folded: folded, onFold: toggleFold, text: text, children: [_jsx("svg", { class: "icon", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M6 3H15L19 7V21H6ZM15 3V7H19M9 11H16M9 14.5H16M9 18H13" }) }), text.moves] }) }), tools] }), _jsxs("div", { ref: list, class: "moves", hidden: folded, children: [_jsxs("ol", { children: [lineAfter === -1 ? lineRow : null, rows.map(({ number, white, black }, index) => (_jsxs(Fragment, { children: [_jsxs("li", { children: [_jsxs("span", { class: "number", children: [number, "."] }), move(white), move(black)] }), index === lineAfter ? lineRow : null] }, number)))] }), result === undefined ? null : _jsx("p", { class: "result", children: result })] })] }));
|
|
34
43
|
}
|
|
35
|
-
/**
|
|
36
|
-
|
|
44
|
+
/**
|
|
45
|
+
* The buttons that step through the moves: to the start, back, forward, and to the game as it is; each one off where it could not go. On a variation,
|
|
46
|
+
* back and forward step through it, and the fork with the move it leaves from takes the board back to the game.
|
|
47
|
+
*/
|
|
48
|
+
export function Steps({ shown, total, line, fork, onStep, text }) {
|
|
49
|
+
const onTheLine = line !== undefined && line.cursor > 0;
|
|
37
50
|
const button = (step, path, off) => (_jsx("button", { type: "button", title: text.steps[step], "aria-label": text.steps[step], disabled: off, onClick: () => onStep(step), children: _jsx("svg", { class: "icon", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: path }) }) }));
|
|
38
|
-
return (_jsxs("nav", { class: "steps card", "aria-label": text.moves, children: [button("first", "M7 6V18M17 6L11 12L17 18", shown === 0), button("back", "M14.5 6L8.5 12L14.5 18", shown === 0), button("forward", "M9.5 6L15.5 12L9.5 18", shown === total), button("last", "M17 6V18M7 6L13 12L7 18", shown === total)] }));
|
|
51
|
+
return (_jsxs("nav", { class: "steps card", "aria-label": text.moves, children: [button("first", "M7 6V18M17 6L11 12L17 18", !onTheLine && shown === 0), button("back", "M14.5 6L8.5 12L14.5 18", !onTheLine && shown === 0), button("forward", "M9.5 6L15.5 12L9.5 18", onTheLine ? line.cursor === line.plies.length : shown === total), button("last", "M17 6V18M7 6L13 12L7 18", !onTheLine && shown === total), onTheLine ? _jsx(ForkButton, { fork: fork, onBack: line.onBack, text: text }) : null] }));
|
|
52
|
+
}
|
|
53
|
+
/** The variation for the steps, with the game's move it leaves from. */
|
|
54
|
+
export function stepsLine(line, plies) {
|
|
55
|
+
const fork = line === undefined ? undefined : plies[line.at - 1];
|
|
56
|
+
return line === undefined ? {} : fork === undefined ? { line } : { line, fork };
|
|
39
57
|
}
|
|
40
58
|
/** A move in SAN with each piece's letter drawn as its figure, the same in every language (D-50), and a capture's x in grey, so the squares stand out. */
|
|
41
59
|
export function Figurines({ san, side }) {
|
|
42
60
|
return (_jsx(_Fragment, { children: san.split(/([KQRBNx])/).map((part, index) => index % 2 === 0 ? part : part === "x" ? _jsx("span", { class: "takes", children: "x" }, index) : _jsx(Figurine, { letter: part, side: side }, index)) }));
|
|
43
61
|
}
|
|
44
|
-
function Move({ ply, current, onShow, text }) {
|
|
62
|
+
function Move({ ply, current, fork, onShow, text }) {
|
|
45
63
|
if (ply === undefined) {
|
|
46
64
|
return _jsx("span", { children: "\u2026" });
|
|
47
65
|
}
|
|
48
66
|
// A screen reader reads the move in SAN and the AI's badge by its name; the eye sees each piece's letter as its figure, and the badge's disc (D-69).
|
|
49
|
-
return (_jsxs("button", { type: "button", class: current ? "ply current" : "ply", "aria-current": current ? "step" : undefined, onClick: onShow, children: [_jsx("span", { class: "visually-hidden", children: ply.review?.badge === undefined ? ply.san : `${ply.san}, ${text.badges[ply.review.badge]}` }), _jsx("span", { "aria-hidden": "true", children: _jsx(Figurines, { san: ply.san, side: ply.side }) }), ply.review?.badge !== undefined ? _jsx(BadgeIcon, { badge: ply.review.badge }) : ply.review?.note !== undefined ? _jsx(NoteIcon, {}) : null] }));
|
|
67
|
+
return (_jsxs("button", { type: "button", class: current ? "ply current" : fork ? "ply fork" : "ply", "aria-current": current ? "step" : undefined, onClick: onShow, children: [_jsx("span", { class: "visually-hidden", children: ply.review?.badge === undefined ? ply.san : `${ply.san}, ${text.badges[ply.review.badge]}` }), _jsx("span", { "aria-hidden": "true", children: _jsx(Figurines, { san: ply.san, side: ply.side }) }), ply.review?.badge !== undefined ? _jsx(BadgeIcon, { badge: ply.review.badge }) : ply.review?.note !== undefined ? _jsx(NoteIcon, {}) : null] }));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The variation's row: its moves numbered as a PGN writes them, the one shown in the gold of the moves, the button that asks the AI to analyse it, and a
|
|
71
|
+
* cross that closes it; faded while the board shows the game, its moves still a click away.
|
|
72
|
+
*/
|
|
73
|
+
function LineRow({ line, text }) {
|
|
74
|
+
return (_jsxs("li", { class: line.cursor > 0 ? "line" : "line faded", "aria-label": `${text.variation.line}: ${lineText(line.plies)}`, children: [_jsx("span", { class: "line-moves", children: line.plies.map((ply, index) => {
|
|
75
|
+
const current = index + 1 === line.cursor;
|
|
76
|
+
const number = moveNumberOf(ply, index === 0);
|
|
77
|
+
return (_jsxs("button", { type: "button", class: current ? "ply current" : "ply", "aria-current": current ? "step" : undefined, onClick: () => line.onShow(index + 1), children: [_jsxs("span", { class: "visually-hidden", children: [number, ply.san] }), _jsxs("span", { "aria-hidden": "true", children: [number === "" ? null : _jsx("span", { class: "line-number", children: number.replace("...", "…") }), _jsx(Figurines, { san: ply.san, side: ply.side })] })] }, index));
|
|
78
|
+
}) }), _jsx("button", { type: "button", class: "analyse-line", title: line.canAnalyse ? text.variation.analyseHint(line.analyst) : text.asleepInAnalysis(line.analyst), disabled: !line.canAnalyse, onClick: line.onAnalyse, children: text.variation.analyse }), _jsx("button", { type: "button", class: "close-line", title: text.variation.close, "aria-label": text.variation.close, onClick: line.onClose, children: _jsx("svg", { class: "icon", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M7 7L17 17M17 7L7 17" }) }) })] }));
|
|
79
|
+
}
|
|
80
|
+
/** The fork with the game's move the variation leaves from: it takes the board back to the game there. */
|
|
81
|
+
function ForkButton({ fork, onBack, text }) {
|
|
82
|
+
const move = fork === undefined ? undefined : `${fork.number}${fork.side === "white" ? "." : "..."}${fork.san}`;
|
|
83
|
+
return (_jsxs("button", { type: "button", class: "fork-back", title: text.variation.back(move), "aria-label": text.variation.back(move), onClick: onBack, children: [_jsx(ForkIcon, {}), fork === undefined ? null : (_jsxs("span", { "aria-hidden": "true", children: [fork.number, fork.side === "white" ? "." : "…", _jsx(Figurines, { san: fork.san, side: fork.side })] }))] }));
|
|
84
|
+
}
|
|
85
|
+
/** The sign of a variation: a line that forks from the game's. */
|
|
86
|
+
export function ForkIcon() {
|
|
87
|
+
return (_jsx("svg", { class: "icon fork-icon", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M7 4V20M7 12C7 8 17 9 17 4M17 4L14 6.5M17 4L19.5 7" }) }));
|
|
50
88
|
}
|
|
51
89
|
/** Scrolls the list, and only the list, as little as it takes to show the whole row of its current move, and the result under the last one. */
|
|
52
90
|
function keepInSight(list) {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { stepped } from "./browse.js";
|
|
2
|
+
/** Whether the board shows a move of the line, not the game. */
|
|
3
|
+
export function onLine(line) {
|
|
4
|
+
return line !== undefined && line.cursor > 0;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The line after the player moves `san` where the board stands, and how many of the game's moves the board shows by then: on the game, its own next move
|
|
8
|
+
* steps forward and the line's first move goes back into the line; any other starts a new line. On the line, its own next move steps forward and any other
|
|
9
|
+
* cuts the line there and goes on with it.
|
|
10
|
+
*/
|
|
11
|
+
export function afterMove(line, game, shown, san) {
|
|
12
|
+
if (line !== undefined && line.cursor > 0) {
|
|
13
|
+
const moves = line.moves[line.cursor] === san ? line.moves : [...line.moves.slice(0, line.cursor), san];
|
|
14
|
+
return { line: { at: line.at, moves, cursor: line.cursor + 1 }, shown: line.at };
|
|
15
|
+
}
|
|
16
|
+
if (game[shown] === san) {
|
|
17
|
+
return { line: line === undefined ? undefined : { ...line, cursor: 0 }, shown: shown + 1 };
|
|
18
|
+
}
|
|
19
|
+
if (line?.at === shown && line.moves[0] === san) {
|
|
20
|
+
return { line: { ...line, cursor: 1 }, shown };
|
|
21
|
+
}
|
|
22
|
+
return { line: { at: shown, moves: [san], cursor: 1 }, shown };
|
|
23
|
+
}
|
|
24
|
+
/** The line after a step back or forward through it: back from its first move the board is on the game again, where the line leaves it. */
|
|
25
|
+
export function stepLine(line, step) {
|
|
26
|
+
return { ...line, cursor: stepped(step, line.cursor, line.moves.length) };
|
|
27
|
+
}
|
|
28
|
+
/** The line with the board back on the game, the line kept faded. */
|
|
29
|
+
export function leaveLine(line) {
|
|
30
|
+
return line === undefined ? undefined : { ...line, cursor: 0 };
|
|
31
|
+
}
|
|
32
|
+
/** The record of the position the board shows: the game's moves up to the line, then the line's up to its cursor. */
|
|
33
|
+
export function lineRecord(record, line) {
|
|
34
|
+
const moves = [...record.moves.slice(0, line.at).map(({ san }) => san), ...line.moves.slice(0, line.cursor)];
|
|
35
|
+
return { tags: record.tags, moves: moves.map((san) => ({ san })) };
|
|
36
|
+
}
|
|
37
|
+
/** The line's moves numbered from the position it leaves the game at, given by its move number and the side to move. */
|
|
38
|
+
export function linePlies(line, start) {
|
|
39
|
+
let { moveNumber: number, turn: side } = start;
|
|
40
|
+
return line.moves.map((san) => {
|
|
41
|
+
const ply = { san, number, side };
|
|
42
|
+
number += side === "black" ? 1 : 0;
|
|
43
|
+
side = side === "white" ? "black" : "white";
|
|
44
|
+
return ply;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/** The moves written as a PGN writes them, 12...Kf8 13.Nxe5 Bxe2: the number before White's moves, and before the first when it is Black's. */
|
|
48
|
+
export function lineText(plies) {
|
|
49
|
+
return plies.map((ply, index) => `${moveNumberOf(ply, index === 0)}${ply.san}`).join(" ");
|
|
50
|
+
}
|
|
51
|
+
/** The number written before a move of a line, 13. or 12..., none before Black's but the first. */
|
|
52
|
+
export function moveNumberOf(ply, first) {
|
|
53
|
+
return ply.side === "white" ? `${ply.number}.` : first ? `${ply.number}...` : "";
|
|
54
|
+
}
|
|
55
|
+
/** Whether the board goes from one place to another by more than one move, which shows the position at once instead of sliding a move. */
|
|
56
|
+
export function isJump(from, to) {
|
|
57
|
+
if (from.cursor === 0 && to.cursor === 0) {
|
|
58
|
+
return Math.abs(from.at - to.at) > 1;
|
|
59
|
+
}
|
|
60
|
+
if (from.cursor > 0 && to.cursor > 0) {
|
|
61
|
+
return from.at !== to.at || Math.abs(from.cursor - to.cursor) > 1;
|
|
62
|
+
}
|
|
63
|
+
const [game, line] = from.cursor === 0 ? [from, to] : [to, from];
|
|
64
|
+
return !(game.at === line.at && line.cursor === 1);
|
|
65
|
+
}
|
package/dist/page/guide/en.md
CHANGED
|
@@ -53,6 +53,7 @@ No chess engine plays for the AI: every move and every judgment is its own. Ches
|
|
|
53
53
|

|
|
54
54
|
|
|
55
55
|
- When the game is over, press **Analyse the game**: the AI goes over it and puts its judgments and notes on the moves. Read them by stepping through the moves with the arrows at the foot of the column, or by clicking a move.
|
|
56
|
+
- In analysis, **move the pieces**, White's and Black's, from any move: a variation starts, with a coloured edge round the board. Click a move of the game to go back to it; the ✕, or Esc, closes the variation.
|
|
56
57
|
- **Analyses**, in the header, opens your analyses, and loads a game played elsewhere: paste its PGN, or choose a .pgn file.
|
|
57
58
|
- With your names on Lichess and Chess.com in your profile, **Load a game** lists your latest games there: click one to analyse it.
|
|
58
59
|
- Ask the AI about the game in the box under its name.
|
package/dist/page/guide/it.md
CHANGED
|
@@ -53,6 +53,7 @@ Nessun motore di scacchi gioca al posto dell'AI: ogni mossa e ogni giudizio sono
|
|
|
53
53
|

|
|
54
54
|
|
|
55
55
|
- A partita finita premi **Analizza la partita**: l'AI la ripassa e mette sulle mosse i suoi giudizi e le sue note. Le leggi scorrendo le mosse con le frecce in fondo alla colonna, o cliccando una mossa.
|
|
56
|
+
- Nell'analisi **muovi i pezzi**, bianchi e neri, da qualunque mossa: nasce una variante, con un bordo colorato attorno alla scacchiera. Clicca una mossa della partita per tornarci; la ✕, o Esc, chiude la variante.
|
|
56
57
|
- **Analisi**, nell'intestazione, apre le tue analisi e carica una partita giocata altrove: incolla il suo PGN, o scegli un file .pgn.
|
|
57
58
|
- Con i tuoi nomi su Lichess e Chess.com nel profilo, **Carica una partita** elenca le tue ultime partite là: clicca su una per analizzarla.
|
|
58
59
|
- Chiedi all'AI della partita nella casella sotto il suo nome.
|
|
@@ -3,9 +3,12 @@ import { useEffect, useState } from "preact/hooks";
|
|
|
3
3
|
import { Dialog } from "../dialogs/dialog.js";
|
|
4
4
|
import { checkIcon } from "../dialogs/profiles.js";
|
|
5
5
|
import { canAct, chatAction, choiceKeys, chosen, effortsOf, firstHost, offeredHosts, startedWith } from "./action.js";
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
/**
|
|
7
|
+
* The chat's window: `onStarted` once a chat opens or starts again, the page then saying where it stands; `onClose` when the player closes it without;
|
|
8
|
+
* `review` when it opened to have a game analysed.
|
|
9
|
+
*/
|
|
10
|
+
export function ChatDialog({ open, review = false, table, settings, onChange, name, onStarted, onClose, text }) {
|
|
11
|
+
return (_jsx(Dialog, { open: open, title: review ? text.table.reviewTitle : text.table.title, onClose: onClose, text: text, children: _jsx(ChatForm, { review: review, table: table, settings: settings, onChange: onChange, name: name, onStarted: onStarted, text: text }) }));
|
|
9
12
|
}
|
|
10
13
|
/** The AI's name on its card, which opens the chat's window: with no chat at the table, a hollow ring before it says so. */
|
|
11
14
|
export function AiNameButton({ name, table, onOpen, text }) {
|
|
@@ -45,7 +48,7 @@ const hostTitles = { claude: "Claude Code", codex: "Codex", antigravity: "Antigr
|
|
|
45
48
|
/** The ↻ of a chat that starts again. */
|
|
46
49
|
const restartIcon = (_jsx("svg", { class: "icon in-use", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M19.5 12a7.5 7.5 0 1 1-2.2-5.3M19.5 4.5v4h-4" }) }));
|
|
47
50
|
/** The window's form, made again at each opening with the host at the table selected, else the last the button used, else the first. */
|
|
48
|
-
function ChatForm({ review, table, settings, onChange, name,
|
|
51
|
+
function ChatForm({ review, table, settings, onChange, name, onStarted, text }) {
|
|
49
52
|
const words = text.table;
|
|
50
53
|
const installed = offeredHosts(table);
|
|
51
54
|
const [selected, setSelected] = useState(() => firstHost(table, settings));
|
|
@@ -73,7 +76,7 @@ function ChatForm({ review, table, settings, onChange, name, onClose, text }) {
|
|
|
73
76
|
setSending(false);
|
|
74
77
|
if (done) {
|
|
75
78
|
onChange({ ...settings, chatHost: host.name });
|
|
76
|
-
|
|
79
|
+
onStarted();
|
|
77
80
|
}
|
|
78
81
|
else {
|
|
79
82
|
setFailed(true);
|
package/dist/page/talk/chat.css
CHANGED
|
@@ -106,3 +106,11 @@
|
|
|
106
106
|
opacity: 1;
|
|
107
107
|
background: color-mix(in oklab, currentColor 15%, transparent);
|
|
108
108
|
}
|
|
109
|
+
|
|
110
|
+
/* On a variation, the fork's sign under the moves before the move the board showed, in the bubble's colour (D-116) */
|
|
111
|
+
.shown-line .fork-icon {
|
|
112
|
+
width: 14px;
|
|
113
|
+
height: 14px;
|
|
114
|
+
margin-right: 3px;
|
|
115
|
+
stroke-width: 2.2;
|
|
116
|
+
}
|
package/dist/page/talk/talk.js
CHANGED
|
@@ -4,7 +4,7 @@ import { createContext } from "preact";
|
|
|
4
4
|
import { useContext, useEffect, useLayoutEffect, useRef, useState } from "preact/hooks";
|
|
5
5
|
import { Torretta } from "../avatars/torretta.js";
|
|
6
6
|
import { BadgeIcon, NoteIcon } from "../game/badges.js";
|
|
7
|
-
import { Figurines } from "../game/move-list.js";
|
|
7
|
+
import { Figurines, ForkIcon } from "../game/move-list.js";
|
|
8
8
|
import { talkLimits } from "../game/plies.js";
|
|
9
9
|
import { ReviewProgress } from "../game/review-progress.js";
|
|
10
10
|
import { signature } from "../players/model-name.js";
|
|
@@ -87,7 +87,7 @@ export function Compose({ lines, newestFirst, spent, draft, onDraft, onSend, can
|
|
|
87
87
|
};
|
|
88
88
|
return (_jsxs(_Fragment, { children: [_jsx("ol", { ref: list, class: "sent", "aria-live": "polite", children: inOrder(lines.map((line, index) => (_jsxs("li", { class: line.who === "ai" ? "from-ai" : undefined, style: about === undefined ? aged(lines.length - 1 - index) : reread(index, lastAnswer), children: [line.who === "ai"
|
|
89
89
|
? (_jsxs(_Fragment, { children: [_jsx(Torretta, { size: 24 }), _jsx("p", { class: "say", children: _jsx(Marked, { text: line.text }) })] }))
|
|
90
|
-
: (_jsxs("p", { class: "said", children: [about === undefined
|
|
90
|
+
: (_jsxs("p", { class: "said", children: [about === undefined ? null : _jsx(ShownPlace, { shown: line.shown, about: about, text: text }), line.text] })), index === lastWritten ? _jsx(Status, { heard: line.heard, name: name, text: text }) : null] }, index))), newestFirst) }), to, left <= 0 ? null : (_jsxs("form", { class: about === undefined ? "compose" : "compose asking", onSubmit: (event) => {
|
|
91
91
|
event.preventDefault();
|
|
92
92
|
submit();
|
|
93
93
|
}, children: [_jsx("p", { class: "limit", role: "status", children: problem ?? "" }), _jsx("textarea", { rows: 2, maxLength: left, placeholder: prompt, "aria-label": prompt, value: draft, onInput: (event) => onDraft(event.currentTarget.value), onKeyDown: (event) => {
|
|
@@ -106,6 +106,24 @@ export function Compose({ lines, newestFirst, spent, draft, onDraft, onSend, can
|
|
|
106
106
|
export function TalkFaces({ name, aiPicture, you, picture, ai, player, aiMoves, playerMoves, unread, text }) {
|
|
107
107
|
return (_jsxs("div", { class: "faces", children: [_jsx(RailPlayer, { place: "ai", picture: aiPicture ?? _jsx(Torretta, { size: 40, bust: true }), 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 })] }));
|
|
108
108
|
}
|
|
109
|
+
/** Where a line of the player's was written: on a variation the board showed, its mark; else the game's move, none at the start. */
|
|
110
|
+
function ShownPlace({ shown, about, text }) {
|
|
111
|
+
const variation = shown?.variation;
|
|
112
|
+
if (variation?.move !== undefined) {
|
|
113
|
+
return _jsx(ShownLine, { variation: variation, onShow: () => about.onLine(variation), text: text });
|
|
114
|
+
}
|
|
115
|
+
return (_jsxs(_Fragment, { children: [shown?.move === undefined ? null : _jsx(ShownMove, { move: shown.move, onShow: () => about.onShow(shown.at), text: text }), variation === undefined ? null : _jsx(ShownLine, { variation: variation, onShow: () => about.onLine(variation), text: text })] }));
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The variation a line of the player's was written on, small at the line's head: the fork's sign in the accent and the move the board showed, none when
|
|
119
|
+
* it was set aside; a press puts the variation back on the board (D-116).
|
|
120
|
+
*/
|
|
121
|
+
function ShownLine({ variation, onShow, text }) {
|
|
122
|
+
const { move } = variation;
|
|
123
|
+
const label = text.variation.show(variation.text);
|
|
124
|
+
const [, number = "", san = ""] = /^(\d+\.+)(.+)$/.exec(move ?? "") ?? [];
|
|
125
|
+
return (_jsxs("button", { type: "button", class: "shown-move shown-line", title: label, "aria-label": label, onClick: onShow, children: [_jsx(ForkIcon, {}), move === undefined ? null : (_jsxs(_Fragment, { children: [_jsx("span", { class: "move-number", children: number }), _jsx(Figurines, { san: san, side: number.endsWith("...") ? "black" : "white" })] }))] }));
|
|
126
|
+
}
|
|
109
127
|
/** The move a line of the player's was written on, 14.♘f3, small at the line's head: a press shows it on the board again (Zoe). */
|
|
110
128
|
function ShownMove({ move, onShow, text }) {
|
|
111
129
|
const [, number = "", san = move] = /^(\d+\.+)(.+)$/.exec(move) ?? [];
|
package/dist/page/text.js
CHANGED
|
@@ -84,6 +84,15 @@ const english = {
|
|
|
84
84
|
game: "The game",
|
|
85
85
|
moves: "Moves",
|
|
86
86
|
steps: { first: "Start", back: "Previous move", forward: "Next move", last: "Back to the game" },
|
|
87
|
+
variation: {
|
|
88
|
+
line: "Variation",
|
|
89
|
+
close: "Close the variation (Esc)",
|
|
90
|
+
back: (move) => move === undefined ? "Back to the start of the game" : `Back to the game, at ${move}`,
|
|
91
|
+
analyse: "Analyse",
|
|
92
|
+
analyseHint: (name) => `Ask ${name} to analyse this variation`,
|
|
93
|
+
analyseWords: "Analyse this variation",
|
|
94
|
+
show: (line) => `Show the variation ${line} on the board`,
|
|
95
|
+
},
|
|
87
96
|
noGame: "No game yet: press + to start one, or ask for one in the chat.",
|
|
88
97
|
foldCard: "Fold the card",
|
|
89
98
|
openCard: "Open the card",
|
|
@@ -118,6 +127,7 @@ const english = {
|
|
|
118
127
|
mated: (side) => `${side === "white" ? "White" : "Black"} is mated`,
|
|
119
128
|
},
|
|
120
129
|
reviewing: (name) => `${name} is going over the game…`,
|
|
130
|
+
stopReview: "Cancel the analysis",
|
|
121
131
|
incomplete: "Analysis not complete",
|
|
122
132
|
complete: "Complete it",
|
|
123
133
|
completeHint: "Complete the analysis",
|
|
@@ -523,6 +533,15 @@ const italian = {
|
|
|
523
533
|
game: "La partita",
|
|
524
534
|
moves: "Mosse",
|
|
525
535
|
steps: { first: "Inizio", back: "Mossa precedente", forward: "Mossa successiva", last: "Torna alla partita" },
|
|
536
|
+
variation: {
|
|
537
|
+
line: "Variante",
|
|
538
|
+
close: "Chiudi la variante (Esc)",
|
|
539
|
+
back: (move) => move === undefined ? "Torna all'inizio della partita" : `Torna alla partita, a ${move}`,
|
|
540
|
+
analyse: "Analizza",
|
|
541
|
+
analyseHint: (name) => `Chiedi a ${name} di analizzare questa variante`,
|
|
542
|
+
analyseWords: "Analizza questa variante",
|
|
543
|
+
show: (line) => `Rimetti sulla scacchiera la variante ${line}`,
|
|
544
|
+
},
|
|
526
545
|
noGame: "Nessuna partita: premi + per iniziarne una, o chiedila nella chat.",
|
|
527
546
|
foldCard: "Chiudi la scheda",
|
|
528
547
|
openCard: "Apri la scheda",
|
|
@@ -557,6 +576,7 @@ const italian = {
|
|
|
557
576
|
mated: (side) => `Matto al ${side === "white" ? "Bianco" : "Nero"}`,
|
|
558
577
|
},
|
|
559
578
|
reviewing: (name) => `${name} sta analizzando la partita…`,
|
|
579
|
+
stopReview: "Annulla l'analisi",
|
|
560
580
|
incomplete: "Analisi non completa",
|
|
561
581
|
complete: "Completa",
|
|
562
582
|
completeHint: "Completa l'analisi",
|
|
@@ -11,6 +11,7 @@ export declare class Bell {
|
|
|
11
11
|
private busy;
|
|
12
12
|
private woken;
|
|
13
13
|
private hooked;
|
|
14
|
+
private unheard;
|
|
14
15
|
private stopWatch;
|
|
15
16
|
private readonly news;
|
|
16
17
|
private readonly changed;
|
|
@@ -25,6 +26,8 @@ export declare class Bell {
|
|
|
25
26
|
get inTurn(): boolean;
|
|
26
27
|
/** Whether the doorbell woke the chat in the turn it is in. */
|
|
27
28
|
get woke(): boolean;
|
|
29
|
+
/** Whether the chat is out of its turn and hears nobody: its hook went without the bell, or it was stopped; until it calls a tool or a hook waits again. */
|
|
30
|
+
get deaf(): boolean;
|
|
28
31
|
/** Whether the chat hears the player: in a turn, or waiting for the bell with a hook. */
|
|
29
32
|
get listening(): boolean;
|
|
30
33
|
/** The chat calls a tool, so it is in a turn: true when nobody was listening before. */
|
|
@@ -97,5 +100,5 @@ export type BellHeard = {
|
|
|
97
100
|
* of its folder that serves its own page: the table is one more page to choose from, unless the ports to try are given (Priya).
|
|
98
101
|
*/
|
|
99
102
|
export declare function bellHeard(input: string, ports?: number[]): Promise<BellHeard>;
|
|
100
|
-
/** Adds a line to the log of the hooks
|
|
101
|
-
export declare function
|
|
103
|
+
/** Adds a line to the log of the doorbell's hooks, keeping its last lines; a log that cannot be written never stops the hook. */
|
|
104
|
+
export declare function noteHook(folder: string, why: string, now?: Date): void;
|