@johnmorrisdotca/domino 1.1.0 → 1.1.2

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/CHANGELOG.md CHANGED
@@ -6,6 +6,37 @@ All notable changes to this project are written here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.1.2] - 2026-10-06
10
+
11
+ Nothing that was exported has changed. The README is the family's one layout, in full.
12
+
13
+ ### Added
14
+
15
+ - The README has a picture of the demo on a desk and on a phone, in light and dark, taken from the demo by `pnpm screenshots:readme` (the pictures are in `docs/images/` and are not in the package), pictures of the table, the largest table, the options, the code panel and the Japanese words, an Examples section of nine examples that run, examples for React, Vue, Svelte and Angular, and an Accessibility section.
16
+ - `pnpm test:readme` type-checks and runs every TypeScript and JavaScript example in the README against the built package, as a job of its own in CI; `src/readme.test.js` holds the README to the family's standard (sections in order, languages on code fences, pictures with alt text and a caption, no marketing words, version pins) in `pnpm check`; `pnpm test:package` fails if a picture or anything under `docs/` is in the packed package.
17
+
18
+ ### Changed
19
+
20
+ - The credits for the tile sounds are `CREDITS.md` at the top of the package, not `docs/credits.md`, so that they are still in the package when nothing from `docs/` is. The words of the credits are unchanged.
21
+ - `pnpm pictures` is `pnpm screenshots:readme`, and takes WebP pictures in light and dark under `docs/images/`; `docs/desktop.jpg` and `docs/phone.jpg` are gone.
22
+ - Repository only: the package and everything it exports are unchanged. `CONTRIBUTING.md` is the family's one text with a section of its own for Domino, held to the master in johnmorrisdotca/.github by `src/family.test.js`; `ci.yml` and `pages.yml` are the family's one text (`pnpm check`, the demo, and the package on Linux, macOS and Windows), and any jobs of the package's own after them.
23
+ - The demo's page titles read `Domino · pitch`, like the rest of the family's.
24
+ - The demo's own stylesheet is `demo/domino.css`, named for the package like the family's.
25
+
26
+ ## [1.1.1] - 2026-10-05
27
+
28
+ Nothing that was exported has changed.
29
+
30
+ ### Added
31
+
32
+ - A test holds every `@johnmorrisdotca/domino@N` version pin in the README to this package's major version.
33
+
34
+ ### Changed
35
+
36
+ - The family's list, in the README and in the demo's footer, names all twenty-four packages, Karakuri and Houseki included.
37
+ - The npm description is one sentence of 250 characters or fewer, so npm and its search show it whole; it is also the repository's About text. `homepage` is the demo site and `author` is `"John Morris"`, the same in every package.
38
+ - The GitHub Actions workflows use the current versions of the actions (checkout 7, setup-node 7, pnpm/action-setup 6; configure-pages 6, upload-pages-artifact 5 and deploy-pages 5 for Pages), which clears GitHub's Node 20 deprecation warning.
39
+
9
40
  ## [1.1.0] - 2026-10-01
10
41
 
11
42
  ### Added
package/README.md CHANGED
@@ -8,14 +8,31 @@ Double-nine, double-twelve and double-fifteen sets; the full rules of Mexican Tr
8
8
  <a href="https://www.npmjs.com/package/@johnmorrisdotca/domino"><img alt="npm" src="https://img.shields.io/npm/v/@johnmorrisdotca/domino?color=2f5d4a"></a>
9
9
  <a href="./LICENSE"><img alt="MIT licence" src="https://img.shields.io/badge/licence-MIT-2f5d4a"></a>
10
10
  <img alt="No dependencies" src="https://img.shields.io/badge/dependencies-0-2f5d4a">
11
+ <img alt="TypeScript" src="https://img.shields.io/badge/types-TypeScript-3178c6">
11
12
  </p>
12
13
 
13
14
  <p align="center"><a href="https://johnmorrisdotca.github.io/domino/"><strong>Play Mexican Train →</strong></a> · <a href="https://johnmorrisdotca.github.io/domino/api.html">API reference</a></p>
14
15
 
15
- <p align="center">
16
- <img src="docs/desktop.jpg" alt="A game of Mexican Train for three in the demo, under its header with the language chooser, five cloth patches and the Help switch: the set, players and rules to choose, a train for every seat and the Mexican Train, and your hand with the tiles you may lay lifted" width="620">
17
- <img src="docs/phone.jpg" alt="The same game on a phone in dark mode, in Japanese: every train down the table and your hand of ten, four tiles lifted" width="200">
18
- </p>
16
+ <table align="center">
17
+ <tr>
18
+ <td align="center" valign="top">
19
+ <picture>
20
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/domino/main/docs/images/hero-desk-dark.webp">
21
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/domino/main/docs/images/hero-desk-light.webp" alt="The demo on a desk, in English, a few turns into a game of Mexican Train for three: the page header with the language chooser, five cloth patches and the Help switch, the choices of set, players, rounds, doubles rule and Mexican Train rule, then the green table with a train for each seat and the Mexican Train, the status line Your turn, Cover the double, and your hand of tiles with the ones that may be laid lifted" width="600">
22
+ </picture>
23
+ <br><em>The demo on a desk: a double-nine table for three, a few turns in.</em>
24
+ </td>
25
+ <td align="center" valign="top">
26
+ <picture>
27
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/domino/main/docs/images/hero-phone-dark.webp">
28
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/domino/main/docs/images/hero-phone-light.webp" alt="The demo on a phone, in Japanese: every train down the green table, the status line saying it is your turn to cover the double, and your hand of ten tiles with four lifted and gold-edged" width="190">
29
+ </picture>
30
+ <br><em>On a phone, in Japanese, in the device's light or dark.</em>
31
+ </td>
32
+ </tr>
33
+ </table>
34
+
35
+ Domino is the rules of dominoes as plain functions over plain data: the set, the tiles and what fits, a table of two to eight laying trains out from a hub double, a computer to fill any empty seat, and a game that is only its seed and its moves, so it replays exactly on any machine and is kept as a line of text. It has no screen of its own, because every site draws its own table; it gives the rules, the words and the sounds. [The demo](https://johnmorrisdotca.github.io/domino/) is a table built on it with nothing to install.
19
36
 
20
37
  ## In 30 seconds
21
38
 
@@ -49,6 +66,75 @@ npx @johnmorrisdotca/domino play --seed 2026 --players 3 --set 9 --length short
49
66
  - **People who want to look at a game**: the command line deals a seed, plays
50
67
  one out and reads a kept game back, in English or Japanese.
51
68
 
69
+ ## Features
70
+
71
+ - **The full rules of Mexican Train**, for two to eight players on a
72
+ double-nine, double-twelve or double-fifteen set, with the house rules as
73
+ options.
74
+ - **A computer player** that plans its longest run, plays doubles well and
75
+ answers in a few milliseconds.
76
+ - **Seeded deals that replay exactly.** The same seed and table deal the same
77
+ hands on every machine, and a game is only its table, its seed and its moves.
78
+ - **Saved games as text**, read back through the rules, so a changed save is
79
+ refused.
80
+ - **The words of a table** in English and Japanese: whose turn it is, what was
81
+ laid, how a round ended. See [Languages](#languages).
82
+ - **Tile sounds**, optional: tiles laid, drawn and shuffled, and a knock for a
83
+ pass. See [Sounds](#sounds).
84
+ - **A command line**: deal a seed, play a game out, read a kept game back. See
85
+ [The command line](#the-command-line).
86
+ - **No dependencies, and no drawing.** Plain functions over plain data.
87
+
88
+
89
+ ### What's in it
90
+
91
+ Each picture is the real demo, a table drawn from the package's functions and taken from [the demo](https://johnmorrisdotca.github.io/domino/) with `pnpm screenshots:readme`, in light and dark.
92
+
93
+ <table>
94
+ <tr>
95
+ <td align="center" valign="top" width="50%">
96
+ <picture>
97
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/domino/main/docs/images/table-desk-dark.webp">
98
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/domino/main/docs/images/table-desk-light.webp" alt="A double-twelve table for four on a desk, in the middle of the first round: a row for Your train and each computer's train and the Mexican Train, each with its tiles laid in a line from the hub double 12-12 and the number it needs next, the line Computer 4 laid 10-9 on Computer 4's train, and your hand of fifteen tiles with two lifted" width="400">
99
+ </picture>
100
+ <br><em><strong>The table.</strong> A train for every seat, the Mexican Train that anybody may add to, and the tiles in your hand that may be laid, lifted.</em>
101
+ </td>
102
+ <td align="center" valign="top" width="50%">
103
+ <picture>
104
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/domino/main/docs/images/big-table-desk-dark.webp">
105
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/domino/main/docs/images/big-table-desk-light.webp" alt="A double-fifteen table for eight at the start of the first round: nine rows, one for each of the eight seats and the Mexican Train, each holding only the hub double 15-15, and your hand of fifteen tiles in a row with the two that may be laid lifted" width="400">
106
+ </picture>
107
+ <br><em><strong>The largest table.</strong> A double-fifteen set (136 tiles) for eight players, a hand of fifteen each.</em>
108
+ </td>
109
+ </tr>
110
+ <tr>
111
+ <td align="center" valign="top" width="50%">
112
+ <picture>
113
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/domino/main/docs/images/set-up-desk-dark.webp">
114
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/domino/main/docs/images/set-up-desk-light.webp" alt="The demo's choices on a desk: the set (double-nine, double-twelve with double-twelve chosen, double-fifteen), the number of players (2, 3, 4 chosen, 6, 8), the rounds (Short chosen, Every double), the doubles rule (Cover one chosen, Chain), when the Mexican Train may start (Anyone, any time chosen, After your own), the Sound switch and the Deal again button" width="400">
115
+ </picture>
116
+ <br><em><strong>The options.</strong> The three sets, two to eight players, and the three house rules, all set when the game starts.</em>
117
+ </td>
118
+ <td align="center" valign="top" width="50%">
119
+ <picture>
120
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/domino/main/docs/images/using-it-desk-dark.webp">
121
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/domino/main/docs/images/using-it-desk-light.webp" alt="The demo's Using it panel on a desk: the code that makes the game on the table (startTrain, legalPlays, playTrain with computerMove), the same deal on the command line as an npx line, and the game so far as the text encodeTrain writes, each with a copy button" width="400">
122
+ </picture>
123
+ <br><em><strong>The code behind the table.</strong> The panel shows the lines that make the game on the screen, the same deal on the command line, and the game kept as text.</em>
124
+ </td>
125
+ </tr>
126
+ <tr>
127
+ <td align="center" valign="top" width="50%">
128
+ <picture>
129
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/domino/main/docs/images/japanese-phone-dark.webp">
130
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/domino/main/docs/images/japanese-phone-light.webp" alt="The table on a phone in Japanese at the first turn of a double-nine game for three: the status line あなたの番です。牌をタップして置きます。, the round and hub, four trains each holding only the 9-9 double, and a hand of ten tiles with two lifted" width="240">
131
+ </picture>
132
+ <br><em><strong>In Japanese.</strong> The words of the table come from the package, in English or Japanese.</em>
133
+ </td>
134
+ <td></td>
135
+ </tr>
136
+ </table>
137
+
52
138
  ## Use it in your project
53
139
 
54
140
  Domino has no screen of its own: it is plain functions over plain data, so
@@ -58,6 +144,16 @@ however you like, and pass each move through `playTrain`. The table in the
58
144
  [`demo/page.js`](./demo/page.js), a page of plain DOM that does exactly that,
59
145
  and the demo's *Using it* panel shows the code for the game on the table.
60
146
 
147
+ ### Install
148
+
149
+ ```sh
150
+ npm install @johnmorrisdotca/domino
151
+ # or: pnpm add @johnmorrisdotca/domino
152
+ # or: yarn add @johnmorrisdotca/domino
153
+ ```
154
+
155
+ It is ES modules only, with its types included, and needs Node 22 or later outside a browser. A page with no bundler can import it from a CDN (`@1` is the major version): see the first example under [Examples](#examples).
156
+
61
157
  ### 1. The API alone
62
158
 
63
159
  ```ts
@@ -99,29 +195,302 @@ per game and plays it again through the rules whenever it needs the state.
99
195
  ### 4. From a terminal
100
196
 
101
197
  See [The command line](#the-command-line).
102
-
103
- There is no React, Vue, Svelte or Angular component, on purpose: a table is a
198
+ See [The command line](#the-command-line). There is no React, Vue, Svelte or Angular component, on purpose: a table is a
104
199
  screen, and every site draws its own. Domino gives it the rules, the words and
105
- the sounds.
200
+ the sounds, and [In a framework](#in-a-framework) holds a game in each one's state.
201
+
202
+ ### In a framework
203
+
204
+ Domino has no component of its own, on purpose: a table is a screen, and every site draws its own. What every framework needs is the same, a game held in state and one function that applies a move, and each is a few lines. `playTrain` returns `null` for a move the rules refuse, so a handler can ignore it.
205
+
206
+ #### React
207
+
208
+ ```jsx
209
+ import { useState } from "react";
210
+ import { computerMove, legalPlays, playTrain, startTrain, tileWords, trainStatus } from "@johnmorrisdotca/domino";
211
+
212
+ export function Table() {
213
+ const [game, setGame] = useState(() => startTrain(9, ["You", "", ""], 2026, undefined, [false, true, true]));
214
+ const lay = ({ tile, train }) => setGame((now) => playTrain(now, { kind: "play", tile, train }) ?? now);
215
+ return (
216
+ <section>
217
+ <p role="status">{trainStatus(game, "en", 0)}</p>
218
+ {game.toPlay === 0 && legalPlays(game).map((play) => (
219
+ <button key={`${play.tile}-${play.train}`} onClick={() => lay(play)}>{tileWords(play.tile)} on train {play.train}</button>
220
+ ))}
221
+ {game.toPlay !== 0 && <button onClick={() => setGame((now) => playTrain(now, computerMove(now)) ?? now)}>Let the computer move</button>}
222
+ </section>
223
+ );
224
+ }
225
+ ```
106
226
 
107
- ## Features
227
+ #### Vue
108
228
 
109
- - **The full rules of Mexican Train**, for two to eight players on a
110
- double-nine, double-twelve or double-fifteen set, with the house rules as
111
- options.
112
- - **A computer player** that plans its longest run, plays doubles well and
113
- answers in a few milliseconds.
114
- - **Seeded deals that replay exactly.** The same seed and table deal the same
115
- hands on every machine, and a game is only its table, its seed and its moves.
116
- - **Saved games as text**, read back through the rules, so a changed save is
117
- refused.
118
- - **The words of a table** in English and Japanese: whose turn it is, what was
119
- laid, how a round ended. See [Languages](#languages).
120
- - **Tile sounds**, optional: tiles laid, drawn and shuffled, and a knock for a
121
- pass. See [Sounds](#sounds).
122
- - **A command line**: deal a seed, play a game out, read a kept game back. See
123
- [The command line](#the-command-line).
124
- - **No dependencies, and no drawing.** Plain functions over plain data.
229
+ ```vue
230
+ <script setup>
231
+ import { shallowRef } from "vue";
232
+ import { computerMove, legalPlays, playTrain, startTrain, tileWords, trainStatus } from "@johnmorrisdotca/domino";
233
+
234
+ const game = shallowRef(startTrain(9, ["You", "", ""], 2026, undefined, [false, true, true]));
235
+ const lay = (move) => { game.value = playTrain(game.value, move) ?? game.value; };
236
+ </script>
237
+
238
+ <template>
239
+ <p role="status">{{ trainStatus(game, "en", 0) }}</p>
240
+ <button v-for="play in game.toPlay === 0 ? legalPlays(game) : []" :key="`${play.tile}-${play.train}`" @click="lay({ kind: 'play', ...play })">
241
+ {{ tileWords(play.tile) }} on train {{ play.train }}
242
+ </button>
243
+ <button v-if="game.toPlay !== 0" @click="lay(computerMove(game))">Let the computer move</button>
244
+ </template>
245
+ ```
246
+
247
+ #### Svelte
248
+
249
+ ```svelte
250
+ <script>
251
+ import { computerMove, legalPlays, playTrain, startTrain, tileWords, trainStatus } from "@johnmorrisdotca/domino";
252
+
253
+ let game = startTrain(9, ["You", "", ""], 2026, undefined, [false, true, true]);
254
+ const lay = (move) => { game = playTrain(game, move) ?? game; };
255
+ </script>
256
+
257
+ <p role="status">{trainStatus(game, "en", 0)}</p>
258
+ {#if game.toPlay === 0}
259
+ {#each legalPlays(game) as play}
260
+ <button on:click={() => lay({ kind: "play", ...play })}>{tileWords(play.tile)} on train {play.train}</button>
261
+ {/each}
262
+ {:else}
263
+ <button on:click={() => lay(computerMove(game))}>Let the computer move</button>
264
+ {/if}
265
+ ```
266
+
267
+ #### Angular
268
+
269
+ ```ts no-check
270
+ import { Component, signal } from "@angular/core";
271
+ import { computerMove, legalPlays, playTrain, startTrain, trainStatus } from "@johnmorrisdotca/domino";
272
+
273
+ @Component({
274
+ selector: "app-table",
275
+ standalone: true,
276
+ template: `<p role="status">{{ status() }}</p><button (click)="computer()">Let the computer move</button>`,
277
+ })
278
+ export class TableComponent {
279
+ game = signal(startTrain(9, ["You", "", ""], 2026, undefined, [false, true, true])!);
280
+ status = () => trainStatus(this.game(), "en", 0);
281
+ computer() { this.game.update((now) => playTrain(now, computerMove(now)) ?? now); }
282
+ }
283
+ ```
284
+
285
+ ## Examples
286
+
287
+ Each example is a whole recipe: copy it and it works. They are run in CI against the built package (`pnpm test:readme`), so none of them is a guess, and the output shown is what they print.
288
+
289
+ ### A table in a page, with no bundler
290
+
291
+ Save this as a file, serve it, and open it: a double-nine table for three with two computers, your hand as buttons, and the computers answering after each of your moves. The module comes from a CDN, and `@1` is the major version.
292
+
293
+ ```html
294
+ <!doctype html>
295
+ <meta charset="utf-8">
296
+ <title>Mexican Train</title>
297
+ <p id="status" role="status"></p>
298
+ <div id="hand"></div>
299
+ <script type="module">
300
+ import { computerMove, legalPlays, playTrain, startTrain, tileWords, trainStatus } from "https://cdn.jsdelivr.net/npm/@johnmorrisdotca/domino@1/dist/index.js";
301
+
302
+ let game = startTrain(9, ["You", "", ""], 2026, undefined, [false, true, true]);
303
+
304
+ function show() {
305
+ document.getElementById("status").textContent = trainStatus(game, "en", 0);
306
+ document.getElementById("hand").replaceChildren(...legalPlays(game).filter(() => game.toPlay === 0).map(({ tile, train }) => {
307
+ const button = document.createElement("button");
308
+ button.textContent = `${tileWords(tile)} on train ${train}`;
309
+ button.onclick = () => { game = playTrain(game, { kind: "play", tile, train }) ?? game; answer(); };
310
+ return button;
311
+ }));
312
+ }
313
+ function answer() {
314
+ while (game.phase === "playing" && game.toPlay !== 0) game = playTrain(game, computerMove(game)) ?? game;
315
+ show();
316
+ }
317
+ answer();
318
+ </script>
319
+ ```
320
+
321
+ ### Deal a seed and read the hands
322
+
323
+ The same seed and table deal the same hands on every machine, so a seed is a deal you can name. `endsOf` gives a tile's two ends, and `tileWords` says one.
324
+
325
+ ```ts
326
+ import { startTrain, tileWords } from "@johnmorrisdotca/domino";
327
+
328
+ const game = startTrain(12, ["You", "", "", ""], 2026, undefined, [false, true, true, true])!;
329
+ console.log(game.hands[0].map(tileWords).join(" ")); // your fifteen tiles
330
+ console.log(game.engine, game.hands.map((hand) => hand.length), game.boneyard.length);
331
+ ```
332
+
333
+ ```text
334
+ 4–2 2–0 6–2 8–1 7–6 6–4 8–3 6–6 3–3 9–9 8–2 12–9 11–0 4–0 9–5
335
+ 12 [ 15, 15, 15, 15 ] 30
336
+ ```
337
+
338
+ ### Let the computers play a whole game
339
+
340
+ `computerMove` is a move for whoever is to play, in any phase, so a game with only computers at the table is a loop. This is the game the command line plays for the same seed: 277 moves, and Computer 3 wins with 57 pips.
341
+
342
+ ```ts
343
+ import { computerMove, playTrain, startTrain, trainTotals } from "@johnmorrisdotca/domino";
344
+
345
+ let game = startTrain(9, ["", "", ""], 2026, { length: "short", doubles: "one", mexican: "any" }, [true, true, true])!;
346
+ let moves = 0;
347
+ while (game.phase !== "finished") {
348
+ game = playTrain(game, computerMove(game))!;
349
+ moves += 1;
350
+ }
351
+ console.log(moves, "moves in", game.rounds, "rounds");
352
+ console.log("pips by seat:", trainTotals(game), "winner: seat", game.winners[0]);
353
+ ```
354
+
355
+ ```text
356
+ 277 moves in 5 rounds
357
+ pips by seat: [ 88, 117, 57 ] winner: seat 2
358
+ ```
359
+
360
+ ### House rules
361
+
362
+ Three options change the game, and all three are set when the game starts: how many rounds (`length`), what a double does (`doubles`) and when the Mexican Train may be started (`mexican`). A table the rules do not allow is `null`.
363
+
364
+ ```ts
365
+ import { startTrain, TRAIN_DEFAULT_OPTIONS } from "@johnmorrisdotca/domino";
366
+
367
+ console.log(TRAIN_DEFAULT_OPTIONS);
368
+ const house = startTrain(15, ["Ann", "Ben", "Cho"], 99, { length: "short", doubles: "chain", mexican: "ownFirst" });
369
+ console.log(house?.options, house?.rounds, house?.hands[0].length); // double-fifteen: 16 rounds, or 8 when short
370
+ console.log(startTrain(12, ["Only one at the table"])); // a table needs two to eight
371
+ ```
372
+
373
+ ```text
374
+ { length: 'full', doubles: 'one', mexican: 'any' }
375
+ { length: 'short', doubles: 'chain', mexican: 'ownFirst' } 8 12
376
+ null
377
+ ```
378
+
379
+ ### Keep a game and read it back
380
+
381
+ A game is its table, its seed and its moves, so the saved text is short, and what is read back is made again by playing every move through the rules. A changed save is `null`.
382
+
383
+ ```ts
384
+ import { computerMove, decodeTrain, encodeTrain, playTrain, startTrain } from "@johnmorrisdotca/domino";
385
+
386
+ let game = startTrain(12, ["You", "", "", ""], 2026, undefined, [false, true, true, true])!;
387
+ game = playTrain(game, computerMove(game))!;
388
+
389
+ const kept = encodeTrain(game);
390
+ console.log(kept);
391
+ console.log(decodeTrain(kept)?.last); // the same game, and its last move
392
+ console.log(decodeTrain(kept.replace('"seed":2026', '"seed":2027'))); // a changed seed no longer makes these moves: null
393
+ ```
394
+
395
+ ```text
396
+ {"v":1,"set":12,"options":{"length":"full","doubles":"one","mexican":"any"},"seed":2026,"players":["You","","",""],"computers":[false,true,true,true],"moves":"p156.0"}
397
+ { seat: 0, move: { kind: 'play', tile: 156, train: 0 } }
398
+ null
399
+ ```
400
+
401
+ ### A server that checks every move
402
+
403
+ The client sends a move and the server holds the saved text. `decodeTrain` trusts nothing it reads, and `playTrain` refuses a move the rules do not allow, so the server never has to believe the client.
404
+
405
+ ```ts
406
+ import { decodeTrain, encodeTrain, legalPlays, playTrain, startTrain, type TrainMove } from "@johnmorrisdotca/domino";
407
+
408
+ const saved = encodeTrain(startTrain(12, ["Ann", "Ben"], 5)!); // what the database holds
409
+
410
+ /** The new saved text, or null when the save is not a game or the move is not a legal one. */
411
+ function accept(saved: string, move: TrainMove): string | null {
412
+ const game = decodeTrain(saved);
413
+ const next = game === null ? null : playTrain(game, move);
414
+ return next === null ? null : encodeTrain(next);
415
+ }
416
+
417
+ const game = decodeTrain(saved)!;
418
+ const legal = legalPlays(game)[0]!;
419
+ console.log(accept(saved, { kind: "play", tile: legal.tile, train: legal.train })?.endsWith(`"moves":"p${legal.tile}.${legal.train}"}`));
420
+ console.log(accept(saved, { kind: "draw" })); // a draw while a tile fits: refused
421
+ console.log(accept("not a game", { kind: "pass" })); // refused
422
+ ```
423
+
424
+ ```text
425
+ true
426
+ null
427
+ null
428
+ ```
429
+
430
+ ### The words of a table, in two languages
431
+
432
+ The package says what the rules have already decided, in a sentence a page can put in an `aria-live` region: whose turn it is, what was just laid, who is who.
433
+
434
+ ```ts
435
+ import { computerMove, playTrain, startTrain, trainNews, trainSeatName, trainStatus } from "@johnmorrisdotca/domino";
436
+
437
+ let game = startTrain(9, ["You", "", ""], 7, undefined, [false, true, true])!;
438
+ console.log(trainStatus(game, "en", 0), "|", trainStatus(game, "ja", 0));
439
+ game = playTrain(game, computerMove(game))!;
440
+ console.log(trainNews(game, "en", 0));
441
+ console.log(trainSeatName(game, 1, "en", 0), "|", trainSeatName(game, 1, "ja", 0));
442
+ ```
443
+
444
+ ```text
445
+ Your turn. Tap a tile to lay it. | あなたの番です。牌をタップして置きます。
446
+ You laid 9–7 on Your train.
447
+ Computer 2 | コンピューター2
448
+ ```
449
+
450
+ ### The command line, and the same thing from code
451
+
452
+ `domino check` reads a saved game back through the rules and says where it stands, and `domino replay` says every move in words. `runCli` is the whole command line as a pure function, so the same text comes back from a test or a server.
453
+
454
+ ```sh
455
+ npx @johnmorrisdotca/domino check '{"v":1,"set":9,"options":{"length":"short","doubles":"chain","mexican":"ownFirst"},"seed":7,"players":["Ann","Ben",""],"computers":[false,false,true],"moves":""}'
456
+ ```
457
+
458
+ ```text
459
+ Double-nine, 3 players, seed 7, 5 rounds; moves made: 0
460
+ Round 1 of 5 is being played; Ann is to play.
461
+ ```
462
+
463
+ ```ts
464
+ import { runCli } from "@johnmorrisdotca/domino";
465
+
466
+ const result = runCli(["deal", "--seed", "7", "--players", "2", "--set", "9"]);
467
+ console.log(result.code, result.out.split("\n")[0]);
468
+ console.log(runCli(["check", "{}"])); // exit code 1: what was asked for could not be done
469
+ ```
470
+
471
+ ```text
472
+ 0 Double-nine, 2 players, seed 7
473
+ {
474
+ code: 1,
475
+ out: '',
476
+ err: 'domino: that is not a game these rules can play out again\n'
477
+ }
478
+ ```
479
+
480
+ ### Tile sounds that wait for a tap
481
+
482
+ A browser lets a page make sound only after somebody has touched it, and a muted table never downloads the recordings. The player is silent until asked, and nothing throws where there is no audio.
483
+
484
+ ```ts no-run
485
+ import { createTileSounds } from "@johnmorrisdotca/domino/tile-sounds";
486
+
487
+ const sounds = createTileSounds({ muted: true, volume: 0.6 }); // nothing is fetched yet
488
+ document.querySelector("#sound")!.addEventListener("click", () => {
489
+ sounds.setMuted(false);
490
+ sounds.play("shuffle"); // the first sound fetches the recordings
491
+ });
492
+ sounds.play("lay"); // a tile laid: silent while muted
493
+ ```
125
494
 
126
495
  ## Mexican Train
127
496
 
@@ -171,7 +540,7 @@ again exactly by the tests.
171
540
  npm install -g @johnmorrisdotca/domino # then `domino`, or use npx with nothing installed
172
541
  ```
173
542
 
174
- ```
543
+ ```text
175
544
  Usage: domino <command> [options]
176
545
 
177
546
  Dominoes and Mexican Train: the same deal for the same seed, on every machine.
@@ -238,34 +607,13 @@ import { runCli } from "@johnmorrisdotca/domino";
238
607
  runCli(["deal", "--seed", "2026", "--players", "3", "--set", "9"]); // { code: 0, out: "Double-nine, 3 players, …", err: "" }
239
608
  ```
240
609
 
241
- ## Languages
242
-
243
- The words of a table are English and Japanese: `DOMINO_STRINGS.en` and
244
- `DOMINO_STRINGS.ja`, one table, so the two are kept side by side. Five functions
245
- say what the rules have already decided, in either language:
246
-
247
- ```ts
248
- import { trainNews, trainSeatName, trainStatus } from "@johnmorrisdotca/domino";
249
-
250
- trainStatus(game, "ja", 0); // "あなたの番です。牌をタップして置きます。"
251
- trainNews(game, "en", 0); // "You laid 12–9 on Your train." (after the first move)
252
- trainSeatName(game, 1, "en", 0); // "Computer 2"
253
- ```
254
-
255
- `dominoSay` fills in the braces (`{who}`, `{tile}`) of any string, and
256
- `dominoLanguage` reads a tag such as `ja_JP.UTF-8`. **Japanese: included; not yet
257
- reviewed by a native reader. Corrections welcome.** Every Japanese string is
258
- listed beside its English in [docs/strings-ja.md](./docs/strings-ja.md), and there
259
- is an [issue template](https://github.com/johnmorrisdotca/domino/issues/new?template=fix-a-translation.md)
260
- for fixing one. Any other language is a table of your own with the same names.
261
-
262
610
  ## Sounds
263
611
 
264
612
  Recordings for a table to play: the tiles shuffled, one drawn, one laid, and a
265
613
  knock on the table for a pass. Nothing sounds unless a table asks, and nothing is
266
614
  fetched until the first sound.
267
615
 
268
- ```ts
616
+ ```ts no-check
269
617
  import { createTileSounds } from "@johnmorrisdotca/domino/tile-sounds";
270
618
 
271
619
  const sounds = createTileSounds(); // silent until asked: nothing is fetched yet
@@ -286,7 +634,7 @@ muteButton.onclick = () => sounds.setMuted(!sounds.muted);
286
634
  - **What they really are.** The recordings are poker chips, from Kenney's
287
635
  [Casino Audio](https://kenney.nl/assets/casino-audio) (CC0), because that is the
288
636
  nearest recorded click of a hard tile on a table that is free to use. They are
289
- not dominoes, and [docs/credits.md](./docs/credits.md) says so, names each file
637
+ not dominoes, and [CREDITS.md](./CREDITS.md) says so, names each file
290
638
  and what was done to it.
291
639
  - **What it costs.** The player is small, and the recordings are a few tens of
292
640
  kilobytes of AAC in a module of their own (`@johnmorrisdotca/domino/sounds`),
@@ -323,12 +671,32 @@ The [API reference](https://johnmorrisdotca.github.io/domino/api.html) (also kep
323
671
  | `TrainGame`, `TrainMove`, `TrainOptions`, `Domino`, `Language`, … | The types |
324
672
  | `VERSION` | This package's version |
325
673
 
674
+
675
+ ### Entry points
676
+
677
+ | Entry | What it holds |
678
+ | --- | --- |
679
+ | `@johnmorrisdotca/domino` | The dominoes, the rules of Mexican Train, the computer player, saved games, the words and the command line |
680
+ | `@johnmorrisdotca/domino/tile-sounds` | `createTileSounds`: the sounds player, silent until asked |
681
+ | `@johnmorrisdotca/domino/sounds` | `TILE_SOUND_DATA`: the recordings as base64 AAC, fetched by the first sound |
682
+
683
+ ### The calls to learn first
684
+
685
+ | Call | What it does |
686
+ | --- | --- |
687
+ | `startTrain(set, players, seed, options, computers)` | A new game |
688
+ | `legalPlays(game)` | Every tile you may lay now, and on which train |
689
+ | `playTrain(game, move)` | The game after a move, or `null` |
690
+ | `computerMove(game)` | A move for whoever is to play |
691
+ | `encodeTrain(game)` and `decodeTrain(text)` | A game as text, and back |
692
+ | `trainStatus(game, language, seat)` | One sentence on whose turn it is |
693
+
326
694
  ## Theming
327
695
 
328
696
  None, on purpose: Domino draws nothing, so there is nothing of its own to
329
697
  theme, and a table built on it looks however your page looks. The demo is the
330
698
  worked example: its dominoes and table are drawn by [`demo/page.js`](./demo/page.js)
331
- and [`demo/site.css`](./demo/site.css), over the family's shared stylesheet.
699
+ and [`demo/domino.css`](./demo/domino.css), over the family's shared stylesheet.
332
700
 
333
701
  ## Limits
334
702
 
@@ -343,6 +711,19 @@ and [`demo/site.css`](./demo/site.css), over the family's shared stylesheet.
343
711
  | A tile | `low * 16 + high`, each end 0 to 15 | `TRAIN_PIP_BASE` |
344
712
  | Moves a played game may take on the command line | 100,000 | `CLI_MOVES_MOST` |
345
713
 
714
+ ## Accessibility
715
+
716
+ Domino draws nothing, so what it can do for a table's accessibility is give a page the words and keep its own behaviour out of the way. What a table built on it does is the page's to say, and the demo's table is the worked example.
717
+
718
+ - **Sentences for a screen reader.** `trainStatus` (whose turn it is, and what is wanted of you), `trainNews` (what was just laid, drawn or passed) and `trainSeatName` (who is who) are plain sentences in English or Japanese, made for an `aria-live` region: the demo puts the status in a `role="status"` element, so a move is spoken without moving focus.
719
+ - **A tile can be said.** `tileWords` gives a tile as words that read aloud (`12–9`), and the demo labels every tile in the hand with it, as a real `button` that is disabled when it cannot be laid.
720
+ - **The keyboard.** In the demo every tile and every action is a native button, so Tab, Enter and Space play a whole game; a tile that may go on more than one train asks which, with a button for each train. Nothing in the package needs a pointer.
721
+ - **No colour carries a meaning alone.** The package returns data and words, never colours. In the demo a train's marker is also said in words (open or closed), and the tile that may be laid is also the only one that is not disabled.
722
+ - **Touch targets.** The demo's tiles in your hand are 76 by 46 pixels and its buttons at least 44 pixels high, and its table fits a phone at 390 pixels.
723
+ - **Sound is optional.** The tile sounds are silent until a page asks, never the only sign of a move (every move is also a sentence in `trainNews`), and a muted table never downloads them.
724
+ - **Reduced motion.** The package animates nothing. The demo's one transition, a tile lifting when it may be laid, is off under `prefers-reduced-motion`.
725
+ - **Not yet.** The package has no way to say a whole train as one sentence, so a screen-reader user hears a train as its tiles, one by one. The Japanese words have not been read by a native reader (see [Languages](#languages)). The colour pairs of the demo have not been measured against WCAG contrast ratios.
726
+
346
727
  ## Browser and runtime support
347
728
 
348
729
  The rules, the computer player, the words and the command line run anywhere
@@ -353,6 +734,35 @@ The sounds need the Web Audio API, which every current browser has; elsewhere
353
734
  they are silent and nothing throws. The demo is tested in Chromium and in
354
735
  WebKit, Safari's engine, at phone size with touch.
355
736
 
737
+ ## Languages
738
+
739
+ The words of a table are English and Japanese: `DOMINO_STRINGS.en` and
740
+ `DOMINO_STRINGS.ja`, one table, so the two are kept side by side. Five functions
741
+ say what the rules have already decided, in either language:
742
+
743
+ ```ts no-check
744
+ import { trainNews, trainSeatName, trainStatus } from "@johnmorrisdotca/domino";
745
+
746
+ trainStatus(game, "ja", 0); // "あなたの番です。牌をタップして置きます。"
747
+ trainNews(game, "en", 0); // "You laid 12–9 on Your train." (after the first move)
748
+ trainSeatName(game, 1, "en", 0); // "Computer 2"
749
+ ```
750
+
751
+ `dominoSay` fills in the braces (`{who}`, `{tile}`) of any string, and
752
+ `dominoLanguage` reads a tag such as `ja_JP.UTF-8`. **Japanese: included; not yet
753
+ reviewed by a native reader. Corrections welcome.** Every Japanese string is
754
+ listed beside its English in [docs/strings-ja.md](./docs/strings-ja.md), and there
755
+ is an [issue template](https://github.com/johnmorrisdotca/domino/issues/new?template=fix-a-translation.md)
756
+ for fixing one. Any other language is a table of your own with the same names.
757
+
758
+ ## Roadmap
759
+
760
+ - More domino games: Block, Draw, All Fives and Chicken Foot
761
+ - A React hook, for a table kept in component state
762
+
763
+ Left out on purpose: anything played for stakes, and play over a network, which
764
+ needs a server. A game here is plain data, so your own server can carry it.
765
+
356
766
  ## Architecture
357
767
 
358
768
  The dominoes and the rules of Mexican Train are plain functions over plain
@@ -404,53 +814,61 @@ Using it somewhere? [Tell us](https://github.com/johnmorrisdotca/domino/issues/n
404
814
 
405
815
  ### The family
406
816
 
407
- The code of every package is MIT, and all of them were written for the same site. Each is at
408
- [github.com/johnmorrisdotca](https://github.com/johnmorrisdotca):
409
-
410
- - [Korokoro](https://github.com/johnmorrisdotca/korokoro) (コロコロ): dice, with exact odds, the dice of 44 games and real sounds.
411
- - [Kyuubu](https://github.com/johnmorrisdotca/kyuubu) (キューブ): a turning cube for the browser, 2×2 to 7×7, with record solves to replay.
412
- - [Hitotsu](https://github.com/johnmorrisdotca/hitotsu) (一つ): a colour-card shedding game for two to eight, with the house rules people play.
413
- - [Toranpu](https://github.com/johnmorrisdotca/toranpu) (トランプ): a deck of playing cards, ten card games with computer players, and three solitaires.
414
- - [Tane](https://github.com/johnmorrisdotca/tane) (種): seeded random numbers and daily seeds, the same in every browser and on every server.
415
- - [Narabe](https://github.com/johnmorrisdotca/narabe) (並べ): one rules engine for abstract board games: gomoku, renju, Reversi, Hex, Go, checkers and more.
416
- - [Tenka](https://github.com/johnmorrisdotca/tenka) (天下): world conquest for two to six, on a map of the real world.
417
- - [Kumimoji](https://github.com/johnmorrisdotca/kumimoji) (組み文字): the crossword tile race, in English and Japanese kana.
418
- - [Tsunagi](https://github.com/johnmorrisdotca/tsunagi) (繋ぎ): a line-joining logic puzzle with 1,792 levels, each with exactly one answer.
419
- - [Jarajara](https://github.com/johnmorrisdotca/jarajara) (ジャラジャラ): mahjong tiles drawn as SVG, stacked layouts, and the matching solitaire Awase.
420
- - [Suido](https://github.com/johnmorrisdotca/suido) (水道): a pipe puzzle: turn the pieces until the water reaches every drain.
421
- - [Kotoba](https://github.com/johnmorrisdotca/kotoba) (言葉): word lists and word-game rules in English, French, German and Japanese.
422
- - [Sugoroku](https://github.com/johnmorrisdotca/sugoroku) (双六): backgammon and its variants, with the doubling cube and match play.
423
- - [Kazu](https://github.com/johnmorrisdotca/kazu) (数): grid number puzzles: Sudoku and its variants, Futoshiki and Skyscrapers.
424
- - [Meikyuu](https://github.com/johnmorrisdotca/meikyuu) (迷宮): a maze game of a thousand levels.
425
-
426
- ## Roadmap
427
-
428
- - More domino games: Block, Draw, All Fives and Chicken Foot
429
- - A React hook, for a table kept in component state
430
-
431
- Left out on purpose: anything played for stakes, and play over a network, which
432
- needs a server. A game here is plain data, so your own server can carry it.
433
-
434
- ## Contributing
435
-
436
- See [CONTRIBUTING.md](./CONTRIBUTING.md). In short:
817
+ <!-- family:start (made by scripts/family-readme.mjs from scripts/family-template.mjs; change those, not this) -->
818
+ Domino is one of twenty-four packages, each made for the same site, each at
819
+ [github.com/johnmorrisdotca](https://github.com/johnmorrisdotca). The code of every one is MIT.
820
+
821
+ - [Korokoro](https://github.com/johnmorrisdotca/korokoro) (コロコロ): dice, with notation, exact odds, real sounds and the dice of many games. [Demo](https://johnmorrisdotca.github.io/korokoro/).
822
+ - [Kyuubu](https://github.com/johnmorrisdotca/kyuubu) (キューブ): a turning cube for the browser, 2×2 to 7×7, with record solves to replay. [Demo](https://johnmorrisdotca.github.io/kyuubu/).
823
+ - [Hitotsu](https://github.com/johnmorrisdotca/hitotsu) (一つ): a colour-card shedding game for two to eight, with the house rules people play. [Demo](https://johnmorrisdotca.github.io/hitotsu/).
824
+ - [Toranpu](https://github.com/johnmorrisdotca/toranpu) (トランプ): a deck of playing cards, card games with computer players, and solitaires. [Demo](https://johnmorrisdotca.github.io/toranpu/).
825
+ - [Tane](https://github.com/johnmorrisdotca/tane) (種): seeded random numbers and daily seeds, the same in every browser and on every server. [Demo](https://johnmorrisdotca.github.io/tane/).
826
+ - [Narabe](https://github.com/johnmorrisdotca/narabe) (並べ): one rules engine for abstract board games, from gomoku and Reversi to Go and checkers. [Demo](https://johnmorrisdotca.github.io/narabe/).
827
+ - [Tenka](https://github.com/johnmorrisdotca/tenka) (天下): world conquest for two to six, on a map of the real world. [Demo](https://johnmorrisdotca.github.io/tenka/).
828
+ - [Kumimoji](https://github.com/johnmorrisdotca/kumimoji) (組み文字): a crossword tile race, in English and Japanese kana. [Demo](https://johnmorrisdotca.github.io/kumimoji/).
829
+ - [Tsunagi](https://github.com/johnmorrisdotca/tsunagi) (繋ぎ): a line-joining logic puzzle whose every level has exactly one answer. [Demo](https://johnmorrisdotca.github.io/tsunagi/).
830
+ - [Jarajara](https://github.com/johnmorrisdotca/jarajara) (ジャラジャラ): mahjong tiles drawn as SVG, stacked layouts, and the matching solitaire Awase. [Demo](https://johnmorrisdotca.github.io/jarajara/).
831
+ - [Suido](https://github.com/johnmorrisdotca/suido) (水道): a pipe puzzle: turn the pieces until the water reaches every drain. [Demo](https://johnmorrisdotca.github.io/suido/).
832
+ - [Domino](https://github.com/johnmorrisdotca/domino) (ドミノ): dominoes and Mexican Train. [Demo](https://johnmorrisdotca.github.io/domino/).
833
+ - [Kotoba](https://github.com/johnmorrisdotca/kotoba) (言葉): word lists and word-game rules in English, French, German and Japanese. [Demo](https://johnmorrisdotca.github.io/kotoba/).
834
+ - [Sugoroku](https://github.com/johnmorrisdotca/sugoroku) (双六): backgammon and its variants, with the doubling cube and match play. [Demo](https://johnmorrisdotca.github.io/sugoroku/).
835
+ - [Kazu](https://github.com/johnmorrisdotca/kazu) (数): grid number puzzles: Sudoku and its variants, Futoshiki and Skyscrapers. [Demo](https://johnmorrisdotca.github.io/kazu/).
836
+ - [Meikyuu](https://github.com/johnmorrisdotca/meikyuu) (迷宮): mazes on squares, hexagons, triangles and circles, made from a seed and drawn through with a finger or the mouse. [Demo](https://johnmorrisdotca.github.io/meikyuu/).
837
+ - [Hikidashi](https://github.com/johnmorrisdotca/hikidashi) (引き出し): a drawer of small Japanese text tools: era dates, kanji numerals, readings and sentence difficulty. [Demo](https://johnmorrisdotca.github.io/hikidashi/).
838
+ - [Chizu](https://github.com/johnmorrisdotca/chizu) (地図): maps of the world and of countries' regions, in English and Japanese, with a quiz and callouts. [Demo](https://johnmorrisdotca.github.io/chizu/).
839
+ - [Bushu](https://github.com/johnmorrisdotca/bushu) (部首): find a kanji by the parts it is made of. [Demo](https://johnmorrisdotca.github.io/bushu/).
840
+ - [Tobiishi](https://github.com/johnmorrisdotca/tobiishi) (飛び石): peg solitaire with nine boards and seeded solvable challenges. [Demo](https://johnmorrisdotca.github.io/tobiishi/).
841
+ - [Jirai](https://github.com/johnmorrisdotca/jirai) (地雷): minesweeper on shaped grids with verified no-guess boards. [Demo](https://johnmorrisdotca.github.io/jirai/).
842
+ - [Gunjin](https://github.com/johnmorrisdotca/gunjin) (軍人): five hidden-rank strategy games with pass-the-device play. [Demo](https://johnmorrisdotca.github.io/gunjin/).
843
+ - [Karakuri](https://github.com/johnmorrisdotca/karakuri) (からくり): eight hyper-casual puzzle games, some of them physics: draw a shield, pull pins, cut ropes, slide blocks, pour tubes. [Demo](https://johnmorrisdotca.github.io/karakuri/).
844
+ - [Houseki](https://github.com/johnmorrisdotca/houseki) (宝石): gem and stone matching puzzles: falling triplets, stone collapse, colour chains and gem swap. [Demo](https://johnmorrisdotca.github.io/houseki/).
845
+
846
+ **This package is Domino.** The demos of all twenty-four share one header and footer, so each links the rest.
847
+ <!-- family:end -->
848
+
849
+ ## Development
437
850
 
438
851
  ```sh
439
852
  pnpm install
440
- pnpm check # lint, types and tests
441
- pnpm test:cli # the command line, run as a child process
442
- pnpm test:package # pack it as npm does, install it, import every entry and run the command
443
- pnpm test:demo # the demo in real browsers, by taps
853
+ pnpm check # lint, types and tests
854
+ pnpm test:cli # the command line, run as a child process
855
+ pnpm test:package # pack it as npm does, install it, import every entry and run the command
856
+ pnpm test:demo # the demo in real browsers, by taps
857
+ pnpm test:readme # run every example in this README against the built package
858
+ pnpm site # build the demo into site/, as the Pages workflow publishes it
859
+ pnpm screenshots:readme # take the README's pictures from the built demo, in light and dark
444
860
  ```
445
861
 
446
- A change to the rules must leave every game in the fixture dealing and playing
862
+ ## Contributing
863
+
864
+ See [CONTRIBUTING.md](./CONTRIBUTING.md). A change to the rules must leave every game in the fixture dealing and playing
447
865
  exactly as it did. Please follow the [code of conduct](./CODE_OF_CONDUCT.md).
448
866
 
449
867
  ## Changes
450
868
 
451
- See [CHANGELOG.md](./CHANGELOG.md).
869
+ See [CHANGELOG.md](./CHANGELOG.md). The latest release, 1.1.2, adds no code: it is this README in full, with pictures of the table, examples that are run on every change, examples for React, Vue, Svelte and Angular, and an Accessibility section.
452
870
 
453
871
  ## Licence
454
872
 
455
873
  [MIT](./LICENSE) © John Morris. The tile sounds are Kenney's Casino Audio, CC0:
456
- see [docs/credits.md](./docs/credits.md).
874
+ see [CREDITS.md](./CREDITS.md).
package/dist/sounds.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * The tile sounds, recorded: tiles shuffled, drawn, laid and knocked on the
3
3
  * table, as base64 AAC (.m4a). From Kenney's Casino Audio
4
- * pack, CC0; see docs/credits.md. Written by scripts/sounds.mjs from the files
4
+ * pack, CC0; see CREDITS.md. Written by scripts/sounds.mjs from the files
5
5
  * in ./sounds, never by hand. `createTileSounds` loads this module only when
6
6
  * a sound is first played, so a page that stays silent never downloads it.
7
7
  */
package/dist/sounds.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * The tile sounds, recorded: tiles shuffled, drawn, laid and knocked on the
3
3
  * table, as base64 AAC (.m4a). From Kenney's Casino Audio
4
- * pack, CC0; see docs/credits.md. Written by scripts/sounds.mjs from the files
4
+ * pack, CC0; see CREDITS.md. Written by scripts/sounds.mjs from the files
5
5
  * in ./sounds, never by hand. `createTileSounds` loads this module only when
6
6
  * a sound is first played, so a page that stays silent never downloads it.
7
7
  */
@@ -2,7 +2,7 @@
2
2
  * THE SOUNDS OF A DOMINO TABLE: tiles shuffled, a tile drawn from the
3
3
  * boneyard, a tile laid, a knock on the table for a pass. The recordings are
4
4
  * poker chips set down and handled (Kenney's Casino Audio, CC0; see
5
- * docs/credits.md), the nearest recorded sound of a hard tile on a table that
5
+ * CREDITS.md), the nearest recorded sound of a hard tile on a table that
6
6
  * is free to use. They are loaded the first time a sound is played and never
7
7
  * before, so a page that stays silent never fetches them. Where they cannot be
8
8
  * loaded or decoded, a short sound made in the browser stands in. Nothing here
@@ -2,7 +2,7 @@
2
2
  * THE SOUNDS OF A DOMINO TABLE: tiles shuffled, a tile drawn from the
3
3
  * boneyard, a tile laid, a knock on the table for a pass. The recordings are
4
4
  * poker chips set down and handled (Kenney's Casino Audio, CC0; see
5
- * docs/credits.md), the nearest recorded sound of a hard tile on a table that
5
+ * CREDITS.md), the nearest recorded sound of a hard tile on a table that
6
6
  * is free to use. They are loaded the first time a sound is played and never
7
7
  * before, so a page that stays silent never fetches them. Where they cannot be
8
8
  * loaded or decoded, a short sound made in the browser stands in. Nothing here
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** The package's version. */
2
- export declare const VERSION = "1.1.0";
2
+ export declare const VERSION = "1.1.2";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /** The package's version. */
2
- export const VERSION = "1.1.0";
2
+ export const VERSION = "1.1.2";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@johnmorrisdotca/domino",
3
- "version": "1.1.0",
4
- "description": "Dominoes for JavaScript and TypeScript: double-nine, double-twelve and double-fifteen sets, and the full rules of Mexican Train for two to eight players, with a computer player, seeded deals that replay exactly, a compact saved-game format, the words of the table in English and Japanese, tile sounds and a command line. Zero dependencies.",
3
+ "version": "1.1.2",
4
+ "description": "Dominoes for JavaScript and TypeScript: double-nine to double-fifteen sets and the full rules of Mexican Train for two to eight, with a computer player, seeded deals, English and Japanese words, and a command line. Zero dependencies.",
5
5
  "keywords": [
6
6
  "dominoes",
7
7
  "domino",
@@ -51,7 +51,7 @@
51
51
  "boneyard",
52
52
  "pips"
53
53
  ],
54
- "homepage": "https://github.com/johnmorrisdotca/domino#readme",
54
+ "homepage": "https://johnmorrisdotca.github.io/domino/",
55
55
  "repository": {
56
56
  "type": "git",
57
57
  "url": "git+https://github.com/johnmorrisdotca/domino.git"
@@ -86,7 +86,7 @@
86
86
  "files": [
87
87
  "dist",
88
88
  "bin",
89
- "docs/credits.md",
89
+ "CREDITS.md",
90
90
  "README.md",
91
91
  "LICENSE",
92
92
  "CHANGELOG.md"
@@ -101,13 +101,15 @@
101
101
  "test": "vitest run",
102
102
  "test:cli": "pnpm build && node scripts/check-cli.mjs",
103
103
  "test:package": "pnpm build && node scripts/check-package.mjs",
104
+ "family:readme": "node scripts/family-readme.mjs",
104
105
  "docs:api": "node scripts/api-write.mjs",
105
106
  "docs:make": "node scripts/docs.mjs",
106
107
  "sounds": "node scripts/sounds.mjs",
107
108
  "check": "pnpm lint && pnpm typecheck && pnpm test",
108
109
  "prepublishOnly": "pnpm check && pnpm build",
109
110
  "site": "pnpm build && node scripts/site.mjs",
110
- "pictures": "pnpm site && node scripts/readme-pictures.mjs",
111
+ "screenshots:readme": "pnpm site && node scripts/readme-pictures.mjs",
112
+ "test:readme": "pnpm build && node scripts/check-readme-examples.mjs",
111
113
  "test:demo": "pnpm site && playwright test"
112
114
  },
113
115
  "devDependencies": {
File without changes