Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
53f593b
simplify assignments
schlawg Nov 11, 2024
acb0a69
use speech synthesis for move confirmation when both are enabled
schlawg Nov 11, 2024
020b9ce
allow hashing of assets in managed directories (compiled) that were c…
schlawg Nov 11, 2024
d21cf8d
remove occasional pause after pronouncing A file
schlawg Nov 11, 2024
76e9f30
use node to run makeGrammar typescript directly. update readme
schlawg Nov 11, 2024
dba78ce
add pieces commands to lexicon and remove unused "opponent"
schlawg Nov 11, 2024
c91ad95
move ui/package.json stuff to main package.json
schlawg Nov 11, 2024
cdc0325
add pieces, move confirm, and shift key explanation
schlawg Nov 11, 2024
eabf7a9
dont let mic pause counter get out of whack
schlawg Nov 11, 2024
aa5345c
cancel speech synthesis when shift key is pressed
schlawg Nov 11, 2024
8ee55e8
add commands to readout pieces
schlawg Nov 11, 2024
8d7ddef
hash voice grammars so they update properly when changed
schlawg Nov 11, 2024
0c942df
remove chessops bundling from chess barrel
schlawg Nov 11, 2024
838faa9
remove unnecessary dot folder
schlawg Nov 11, 2024
c4be3e1
fix paths in readme
schlawg Nov 11, 2024
ff15c77
vitest scripts are now at root
fitztrev Nov 11, 2024
f24f1a7
use package script rather than shell script to build and add generate…
schlawg Nov 11, 2024
83c175d
Merge remote-tracking branch 'origin/ui-speech-confirm' into ui-speec…
schlawg Nov 11, 2024
1a3c49c
fix error in readme that noone will ever read
schlawg Nov 11, 2024
8f16204
simplify ui/README.md, ui/voice/README.md for future archaeologists
schlawg Nov 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/assets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ jobs:
run: ./ui/build --no-install -p
- name: Tests
run: pnpm test
working-directory: ui
- name: Prepare asset dir
run: mkdir assets && mv public assets/ && cp -p bin/download-lifat LICENSE COPYING.md README.md assets/ && git log -n 1 --pretty=oneline > assets/commit.txt
- name: Tar assets
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ dist/
node_modules/
ui/common/css/theme/gen/*.scss
ui/.build/build
ui/voice/.build/crowdv
ui/voice/crowdv
ui/*/npm-debug.log
ui/*/tsconfig.tsbuildinfo
hs_*.log
Expand Down
2 changes: 1 addition & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@
dist/
readme
pnpm-lock.yaml
/ui/voice/@build/crowdv/*.json
/ui/voice/crowdv/
15 changes: 14 additions & 1 deletion modules/web/src/main/ui/help.scala
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,17 @@ object help:
),
li(instructions2()),
li(instructions3(voice("yes"), voice("no"))),
li(instructions4(strong("Push to Talk"))),
li(
instructions4(strong("Push to Talk")),
strong(" Shift"),
" also cancels any ongoing speech."
),
li(
"Enable ",
a(href := "/account/preferences/game-behavior#moveConfirmation")("Move Confirmation"),
" in Settings, set timer off, and set clarity to clear if you are playing blindfolded",
" with speech synthesis. This enables spoken move confirmation."
),
li(instructions5(), phonetics),
li(
instructions6(
Expand Down Expand Up @@ -233,6 +243,9 @@ object help:
row(voice("yes"), playPreferredMoveOrConfirmSomething()),
row(voice("vocabulary"), "List all available commands"),
row(voice("blindfold"), "Toggle blindfold mode"),
row(voice("clock"), "Read out clocks"),
row(voice("pieces"), "Read out pieces"),
row(voice("white pieces"), "Read out white pieces"),
row(voice("next"), trans.puzzle.nextPuzzle()),
row(voice("upvote"), trans.puzzle.upVote()),
row(voice("solve"), showPuzzleSolution()),
Expand Down
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@
"chessground": "^9.1.1",
"chessops": "^0.14.2",
"eslint": "^9.14.0",
"jsdom": "^25.0.1",
"lint-staged": "^15.2.10",
"onchange": "^7.1.0",
"prettier": "^3.3.3",
"snabbdom": "3.5.1",
"typescript": "^5.6.3"
"typescript": "^5.6.3",
"vitest": "^2.1.4"
},
"_comments": [
"//": [
"snabbdom pinned to 3.5.1 until https://github.com/snabbdom/snabbdom/issues/1114 is resolved",
"typescript above just to allow manual tsc. ui/.build/package.json's typesript version is the truth"
],
Expand All @@ -55,7 +57,8 @@
"serverlog": "pnpm journal & pnpm metals",
"piece-css": "pnpx tsx bin/gen/piece-css.ts",
"trans-dump": "pnpx tsx bin/trans-dump.ts",
"test": "cd ui/ && pnpm test",
"test": "vitest run -c ui/vitest.config.mts",
"test:watch": "vitest -c ui/vitest.config.mts",
"multilog": "pnpm serverlog & ui/build -w"
}
}
15 changes: 6 additions & 9 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
packages:
- 'bin'
- 'ui'
- 'ui/*'
- 'ui/@types/*'
4 changes: 2 additions & 2 deletions ui/.build/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ export async function main(): Promise<void> {
env.sync = argv.includes('--sync');
}
if (argv.includes('--no-color')) env.color = undefined;
if (argv.includes('--no-time')) env.logTime = false;
if (argv.includes('--no-context')) env.logContext = false;

env.logTime = !argv.includes('--no-time');
env.logContext = !argv.includes('--no-context');
env.watch = argv.includes('--watch') || oneDashArgs.includes('w');
env.prod = argv.includes('--prod') || oneDashArgs.includes('p');
env.debug = argv.includes('--debug') || oneDashArgs.includes('d');
Expand Down
11 changes: 4 additions & 7 deletions ui/.build/src/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import crypto from 'node:crypto';
import es from 'esbuild';
import { env, colors as c, warnMark } from './main.ts';
import { globArray, globArrays } from './parse.ts';
import { isUnmanagedAsset } from './sync.ts';
import { allSources } from './sass.ts';
import { jsLogger } from './console.ts';

Expand Down Expand Up @@ -64,12 +63,10 @@ export async function cssManifest(): Promise<void> {
export async function hashedManifest(): Promise<void> {
const newHashLinks = new Map<string, number>();
const alreadyHashed = new Map<string, string>();
const sources: string[] = (
await globArrays(
env.building.flatMap(x => x.hashGlobs ?? []),
{ cwd: env.outDir },
)
).filter(isUnmanagedAsset);
const sources: string[] = await globArrays(
env.building.flatMap(x => x.hashGlobs ?? []),
{ cwd: env.outDir },
);
const sourceStats = await Promise.all(sources.map(file => fs.promises.stat(file)));

for (const [i, stat] of sourceStats.entries()) {
Expand Down
18 changes: 2 additions & 16 deletions ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,17 @@

## Building

Client builds are performed by the ui/build script. Stick to `ui/build -w` and leave it running when you can. This automatically rebuilds any client source files when changed and lets you quickly see the results in your browser. NOTE - always use hard refresh (google it) or disable caching in the network tab of your browser inspector to pick up fresh changes.

Usage examples:
Client builds are performed by the [ui/build](./.build/readme) script. Stick to `ui/build -wc` and leave it running. This does a clean build then rebuilds any client source files when changed. A browser reload will show the results.

```bash
ui/build # builds all client assets in dev mode
ui/build -w # builds all client assets and watches for changes
ui/build -p # builds minified client assets (prod builds)
ui/build --no-install # no pnpm install (to preserve local links you have set up)
ui/build analyse site msg # specify modules (don't build everything)
ui/build -w dasher chart # watch mode but only for given modules
ui/build --tsc -w # watch mode but type checking only
ui/build --sass msg notify # build css only for msg and notify modules
ui/build --no-color # don't use color in logs
ui/build --no-time # don't log the time
ui/build --no-context # don't log the context ([sass], [esbuild], etc)
ui/build --help
```

## Testing

The frontend uses the [Vitest](https://vitest.dev/) testing framework.

```bash
cd ui

pnpm test
## or
pnpm test:watch
Expand Down
9 changes: 8 additions & 1 deletion ui/bits/src/bits.polyglot.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as co from 'chessops';
import { deepFreeze } from 'common/algo';
import { normalMove } from 'chess';
import { type NormalMove, type Chess, parseUci, makeUci } from 'chessops';
import { normalizeMove } from 'chessops/chess';

export type OpeningMove = { uci: string; weight: number };

Expand Down Expand Up @@ -268,6 +269,12 @@ function uciToShort(uci: Uci): number {
return (promotion << 12) | (from << 6) | to;
}

function normalMove(chess: Chess, unsafeUci: Uci): { uci: Uci; move: NormalMove } | undefined {
const unsafe = parseUci(unsafeUci);
const move = unsafe && 'from' in unsafe ? { ...unsafe, ...normalizeMove(chess, unsafe) } : undefined;
return move && chess.isLegal(move) ? { uci: makeUci(move), move } : undefined;
}

const promotes = ['', 'n', 'b', 'r', 'q', '?', '?', '?'];

const rolodex = {
Expand Down
8 changes: 0 additions & 8 deletions ui/chess/src/chess.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { uciChar } from './uciChar';
import { type NormalMove, type Chess, parseUci, makeUci } from 'chessops';
import { normalizeMove } from 'chessops/chess';

export * from './sanWriter';
export const initialFen: FEN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
Expand Down Expand Up @@ -39,9 +37,3 @@ export function readDrops(line?: string | null): Key[] | null {
if (typeof line === 'undefined' || line === null) return null;
return (line.match(/.{2}/g) as Key[]) || [];
}

export function normalMove(chess: Chess, unsafeUci: Uci): { uci: Uci; move: NormalMove } | undefined {
const unsafe = parseUci(unsafeUci);
const move = unsafe && 'from' in unsafe ? { ...unsafe, ...normalizeMove(chess, unsafe) } : undefined;
return move && chess.isLegal(move) ? { uci: makeUci(move), move } : undefined;
}
46 changes: 46 additions & 0 deletions ui/chess/src/sanWriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,49 @@ export function sanWriter(fen: string, ucis: string[]): SanToUci {
});
return sans;
}

export function speakable(san?: San): string {
const text = !san
? 'Game start'
: san.includes('O-O-O#')
? 'long castle checkmate'
: san.includes('O-O-O+')
? 'long castle check'
: san.includes('O-O-O')
? 'long castle'
: san.includes('O-O#')
? 'short castle checkmate'
: san.includes('O-O+')
? 'short castle check'
: san.includes('O-O')
? 'short castle'
: san
.split('')
.map(c => {
if (c == 'x') return 'takes';
if (c == '+') return 'check';
if (c == '#') return 'checkmate';
if (c == '=') return 'promotes to';
if (c == '@') return 'at';
const code = c.charCodeAt(0);
if (code > 48 && code < 58) return c; // 1-8
if (code > 96 && code < 105) return c.toUpperCase();
return (
{
P: 'pawn',
N: 'knight',
B: 'bishop',
R: 'rook',
Q: 'queen',
K: 'king',
}[c.toUpperCase()] ?? c
);
})
.join(' ')
.replace(/^A /, '"A"') // "A takes" & "A 3" are mispronounced
.replace(/(\d) E (\d)/, '$1,E $2') // Strings such as 1E5 are treated as scientific notation
.replace(/C /, 'c ') // Capital C is pronounced as "degrees celsius" when it comes after a number (e.g. R8c3)
.replace(/F /, 'f ') // Capital F is pronounced as "degrees fahrenheit" when it comes after a number (e.g. R8f3)
.replace(/(\d) H (\d)/, '$1H$2'); // "H" is pronounced as "hour" when it comes after a number with a space (e.g. Rook 5 H 3)
return text;
}
20 changes: 0 additions & 20 deletions ui/package.json

This file was deleted.

23 changes: 12 additions & 11 deletions ui/round/src/ctrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import type {
import { defined, type Toggle, toggle, requestIdleCallback } from 'common';
import { storage, once, type LichessBooleanStorage } from 'common/storage';
import { pubsub } from 'common/pubsub';
import { readFen, sanOf, speakable } from 'chess/sanWriter';

interface GoneBerserk {
white?: boolean;
Expand All @@ -71,7 +72,7 @@ export default class RoundController implements MoveRootCtrl {
firstSeconds = true;
flip = false;
menu: Toggle;
confirmMoveEnabled: Toggle = toggle(true);
confirmMoveToggle: Toggle = toggle(true);
loading = false;
loadingTimeout: number;
redirecting = false;
Expand Down Expand Up @@ -335,28 +336,28 @@ export default class RoundController implements MoveRootCtrl {
};

sendMove = (orig: Key, dest: Key, prom: Role | undefined, meta: CgMoveMetadata): void => {
const move: SocketMove = {
u: orig + dest,
};
const move: SocketMove = { u: orig + dest };
if (prom) move.u += prom === 'knight' ? 'n' : prom[0];
if (blur.get()) move.b = 1;
this.resign(false);
if (this.data.pref.submitMove && this.confirmMoveEnabled() && !meta.premove) {

if (this.data.pref.submitMove && this.confirmMoveToggle() && !meta.premove) {
if (site.sound.speech()) {
const spoken = `${speakable(sanOf(readFen(this.stepAt(this.ply).fen), move.u))}. confirm?`;
site.sound.say(spoken, false, true);
}
this.toSubmit = move;
this.redraw();
} else {
this.actualSendMove('move', move, {
justCaptured: meta.captured,
premove: meta.premove,
});
return;
}
this.actualSendMove('move', move, { justCaptured: meta.captured, premove: meta.premove });
};

sendNewPiece = (role: Role, key: Key, isPredrop: boolean): void => {
const drop: SocketDrop = { role, pos: key };
if (blur.get()) drop.b = 1;
this.resign(false);
if (this.data.pref.submitMove && this.confirmMoveEnabled() && !isPredrop) {
if (this.data.pref.submitMove && this.confirmMoveToggle() && !isPredrop) {
this.toSubmit = drop;
this.redraw();
} else {
Expand Down
2 changes: 1 addition & 1 deletion ui/round/src/view/boardMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default function (ctrl: RoundController): LooseVNode {
),
menu.voiceInput(boolPrefXhrToggle('voice', !!ctrl.voiceMove), !spectator),
menu.keyboardInput(boolPrefXhrToggle('keyboardMove', !!ctrl.keyboardMove), !spectator),
!spectator && d.pref.submitMove ? menu.confirmMove(ctrl.confirmMoveEnabled) : undefined,
!spectator && d.pref.submitMove ? menu.confirmMove(ctrl.confirmMoveToggle) : undefined,
]),
h('section.board-menu__links', [
h(
Expand Down
Loading