@johnmorrisdotca/domino 1.1.1 → 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 +17 -0
- package/README.md +472 -67
- package/dist/sounds.d.ts +1 -1
- package/dist/sounds.js +1 -1
- package/dist/tile-sounds.d.ts +1 -1
- package/dist/tile-sounds.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -3
- /package/{docs/credits.md → CREDITS.md} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,23 @@ 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
|
+
|
|
9
26
|
## [1.1.1] - 2026-10-05
|
|
10
27
|
|
|
11
28
|
Nothing that was exported has changed.
|
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
|
-
<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
227
|
+
#### Vue
|
|
108
228
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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 [
|
|
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/
|
|
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
|
|
@@ -436,34 +846,29 @@ Domino is one of twenty-four packages, each made for the same site, each at
|
|
|
436
846
|
**This package is Domino.** The demos of all twenty-four share one header and footer, so each links the rest.
|
|
437
847
|
<!-- family:end -->
|
|
438
848
|
|
|
439
|
-
##
|
|
440
|
-
|
|
441
|
-
- More domino games: Block, Draw, All Fives and Chicken Foot
|
|
442
|
-
- A React hook, for a table kept in component state
|
|
443
|
-
|
|
444
|
-
Left out on purpose: anything played for stakes, and play over a network, which
|
|
445
|
-
needs a server. A game here is plain data, so your own server can carry it.
|
|
446
|
-
|
|
447
|
-
## Contributing
|
|
448
|
-
|
|
449
|
-
See [CONTRIBUTING.md](./CONTRIBUTING.md). In short:
|
|
849
|
+
## Development
|
|
450
850
|
|
|
451
851
|
```sh
|
|
452
852
|
pnpm install
|
|
453
|
-
pnpm check
|
|
454
|
-
pnpm test:cli
|
|
455
|
-
pnpm test:package
|
|
456
|
-
pnpm test:demo
|
|
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
|
|
457
860
|
```
|
|
458
861
|
|
|
459
|
-
|
|
862
|
+
## Contributing
|
|
863
|
+
|
|
864
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md). A change to the rules must leave every game in the fixture dealing and playing
|
|
460
865
|
exactly as it did. Please follow the [code of conduct](./CODE_OF_CONDUCT.md).
|
|
461
866
|
|
|
462
867
|
## Changes
|
|
463
868
|
|
|
464
|
-
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.
|
|
465
870
|
|
|
466
871
|
## Licence
|
|
467
872
|
|
|
468
873
|
[MIT](./LICENSE) © John Morris. The tile sounds are Kenney's Casino Audio, CC0:
|
|
469
|
-
see [
|
|
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
|
|
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
|
|
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/tile-sounds.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
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/tile-sounds.js
CHANGED
|
@@ -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
|
-
*
|
|
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.
|
|
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.
|
|
2
|
+
export const VERSION = "1.1.2";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnmorrisdotca/domino",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
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",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"files": [
|
|
87
87
|
"dist",
|
|
88
88
|
"bin",
|
|
89
|
-
"
|
|
89
|
+
"CREDITS.md",
|
|
90
90
|
"README.md",
|
|
91
91
|
"LICENSE",
|
|
92
92
|
"CHANGELOG.md"
|
|
@@ -108,7 +108,8 @@
|
|
|
108
108
|
"check": "pnpm lint && pnpm typecheck && pnpm test",
|
|
109
109
|
"prepublishOnly": "pnpm check && pnpm build",
|
|
110
110
|
"site": "pnpm build && node scripts/site.mjs",
|
|
111
|
-
"
|
|
111
|
+
"screenshots:readme": "pnpm site && node scripts/readme-pictures.mjs",
|
|
112
|
+
"test:readme": "pnpm build && node scripts/check-readme-examples.mjs",
|
|
112
113
|
"test:demo": "pnpm site && playwright test"
|
|
113
114
|
},
|
|
114
115
|
"devDependencies": {
|
|
File without changes
|