@datamoc/mw_games 0.42.0 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +59 -0
- package/README.md +62 -1
- package/REFERENCE.md +57 -5
- package/api-surface.json +672 -0
- package/data/microgm-essential.PROVENANCE.md +13 -0
- package/data/microgm-essential.sf2 +0 -0
- package/data/soundfont-catalog.json +8 -0
- package/dist/audio/AudioLoader.d.ts +28 -0
- package/dist/audio/AudioLoader.d.ts.map +1 -0
- package/dist/audio/AudioLoader.js +53 -0
- package/dist/audio/AudioLoader.js.map +1 -0
- package/dist/audio/Channels.d.ts +1 -0
- package/dist/audio/Channels.d.ts.map +1 -1
- package/dist/audio/Channels.js +2 -1
- package/dist/audio/Channels.js.map +1 -1
- package/dist/audio/MidiRender.d.ts +16 -0
- package/dist/audio/MidiRender.d.ts.map +1 -1
- package/dist/audio/MidiRender.js +21 -0
- package/dist/audio/MidiRender.js.map +1 -1
- package/dist/audio/MusicPlayer.d.ts +80 -0
- package/dist/audio/MusicPlayer.d.ts.map +1 -0
- package/dist/audio/MusicPlayer.js +147 -0
- package/dist/audio/MusicPlayer.js.map +1 -0
- package/dist/audio/SampleDecoder.d.ts +16 -2
- package/dist/audio/SampleDecoder.d.ts.map +1 -1
- package/dist/audio/SampleDecoder.js +10 -6
- package/dist/audio/SampleDecoder.js.map +1 -1
- package/dist/audio/Sound.d.ts +2 -0
- package/dist/audio/Sound.d.ts.map +1 -1
- package/dist/audio/Sound.js +3 -0
- package/dist/audio/Sound.js.map +1 -1
- package/dist/audio/SoundFont.d.ts +5 -3
- package/dist/audio/SoundFont.d.ts.map +1 -1
- package/dist/audio/SoundFont.js +10 -8
- package/dist/audio/SoundFont.js.map +1 -1
- package/dist/audio/Synth.d.ts +1 -1
- package/dist/audio/Synth.d.ts.map +1 -1
- package/dist/audio/Synth.js +4 -0
- package/dist/audio/Synth.js.map +1 -1
- package/dist/audio/index.d.ts +6 -2
- package/dist/audio/index.d.ts.map +1 -1
- package/dist/audio/index.js +3 -1
- package/dist/audio/index.js.map +1 -1
- package/dist/mw_games.global.js +22 -22
- package/dist/mwl/index.d.ts +2 -0
- package/dist/mwl/index.d.ts.map +1 -1
- package/dist/mwl/index.js +1 -0
- package/dist/mwl/index.js.map +1 -1
- package/dist/mwl/objects.d.ts +31 -0
- package/dist/mwl/objects.d.ts.map +1 -0
- package/dist/mwl/objects.js +83 -0
- package/dist/mwl/objects.js.map +1 -0
- package/dist/mwl/schema.d.ts +1 -1
- package/dist/mwl/schema.d.ts.map +1 -1
- package/dist/mwl/tables.d.ts +2 -0
- package/dist/mwl/tables.d.ts.map +1 -1
- package/dist/mwl/tables.js +13 -0
- package/dist/mwl/tables.js.map +1 -1
- package/dist/physics/XpbdWorld.d.ts +23 -5
- package/dist/physics/XpbdWorld.d.ts.map +1 -1
- package/dist/physics/XpbdWorld.js +90 -6
- package/dist/physics/XpbdWorld.js.map +1 -1
- package/dist/testing/index.d.ts +16 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +21 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/three-d/Collision3D.d.ts +46 -2
- package/dist/three-d/Collision3D.d.ts.map +1 -1
- package/dist/three-d/Collision3D.js +46 -2
- package/dist/three-d/Collision3D.js.map +1 -1
- package/dist/three-d/Grid.d.ts +12 -1
- package/dist/three-d/Grid.d.ts.map +1 -1
- package/dist/three-d/Grid.js +12 -1
- package/dist/three-d/Grid.js.map +1 -1
- package/dist/three-d/Vox.d.ts +13 -1
- package/dist/three-d/Vox.d.ts.map +1 -1
- package/dist/three-d/Vox.js +13 -1
- package/dist/three-d/Vox.js.map +1 -1
- package/dist/two-d/Game.d.ts +21 -1
- package/dist/two-d/Game.d.ts.map +1 -1
- package/dist/two-d/Game.js +73 -6
- package/dist/two-d/Game.js.map +1 -1
- package/dist/two-d/Scene2D.d.ts +24 -0
- package/dist/two-d/Scene2D.d.ts.map +1 -1
- package/dist/two-d/Scene2D.js +30 -0
- package/dist/two-d/Scene2D.js.map +1 -1
- package/dist/two-d/render/SceneTransition.d.ts +272 -0
- package/dist/two-d/render/SceneTransition.d.ts.map +1 -0
- package/dist/two-d/render/SceneTransition.js +431 -0
- package/dist/two-d/render/SceneTransition.js.map +1 -0
- package/dist/two-d/render/index.d.ts +2 -0
- package/dist/two-d/render/index.d.ts.map +1 -1
- package/dist/two-d/render/index.js +1 -0
- package/dist/two-d/render/index.js.map +1 -1
- package/dist/two-d/ui/Button.d.ts +23 -0
- package/dist/two-d/ui/Button.d.ts.map +1 -1
- package/dist/two-d/ui/Button.js +37 -0
- package/dist/two-d/ui/Button.js.map +1 -1
- package/dist/two-d/ui/DropdownView.d.ts +49 -3
- package/dist/two-d/ui/DropdownView.d.ts.map +1 -1
- package/dist/two-d/ui/DropdownView.js +150 -9
- package/dist/two-d/ui/DropdownView.js.map +1 -1
- package/dist/two-d/ui/ScrollBox.d.ts +90 -0
- package/dist/two-d/ui/ScrollBox.d.ts.map +1 -1
- package/dist/two-d/ui/ScrollBox.js +206 -4
- package/dist/two-d/ui/ScrollBox.js.map +1 -1
- package/dist/two-d/ui/ScrollText.d.ts +122 -0
- package/dist/two-d/ui/ScrollText.d.ts.map +1 -0
- package/dist/two-d/ui/ScrollText.js +202 -0
- package/dist/two-d/ui/ScrollText.js.map +1 -0
- package/dist/two-d/ui/Tooltip.d.ts +70 -1
- package/dist/two-d/ui/Tooltip.d.ts.map +1 -1
- package/dist/two-d/ui/Tooltip.js +115 -3
- package/dist/two-d/ui/Tooltip.js.map +1 -1
- package/dist/two-d/ui/Window.d.ts +35 -2
- package/dist/two-d/ui/Window.d.ts.map +1 -1
- package/dist/two-d/ui/Window.js +58 -3
- package/dist/two-d/ui/Window.js.map +1 -1
- package/dist/two-d/ui/index.d.ts +7 -5
- package/dist/two-d/ui/index.d.ts.map +1 -1
- package/dist/two-d/ui/index.js +3 -2
- package/dist/two-d/ui/index.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +7 -3
- package/sbom.cdx.json +19 -260
- package/tools/browser-driver.mjs +3 -3
- package/tools/browser-smoke.mjs +19 -2
- package/tools/build-tablebases.mjs +7 -3
- package/tools/compile-openings.mjs +7 -3
- package/tools/compile-resources.d.mts +2 -0
- package/tools/compile-resources.mjs +13 -1
- package/tools/emit-page.d.mts +6 -0
- package/tools/emit-page.mjs +43 -3
- package/tools/find-chrome.mjs +4 -2
- package/tools/init.mjs +11 -3
- package/tools/play-uci.mjs +9 -5
- package/tools/vite.mjs +9 -1
- package/tools.md +1 -0
package/tools/emit-page.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { readFile, writeFile, rm, stat } from 'node:fs/promises';
|
|
2
|
+
import { readFile, readdir, writeFile, rm, stat } from 'node:fs/promises';
|
|
3
3
|
import { realpathSync } from 'node:fs';
|
|
4
4
|
import { join, resolve as resolvePath } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
@@ -81,6 +81,7 @@ export async function emitPage({
|
|
|
81
81
|
soundFont = true,
|
|
82
82
|
soundFontUsage,
|
|
83
83
|
csp = true,
|
|
84
|
+
maxPageBytes,
|
|
84
85
|
}) {
|
|
85
86
|
if (!dist) throw new Error('emitPage needs the dist folder of a vite build');
|
|
86
87
|
if (!assets && assetFiles?.length) throw new Error(`unknown asset file ${assetFiles[0]}: no assets folder`);
|
|
@@ -97,7 +98,7 @@ export async function emitPage({
|
|
|
97
98
|
soundFont,
|
|
98
99
|
soundFontUsage,
|
|
99
100
|
})
|
|
100
|
-
: { groups: [], rawBytes: 0, embeddedBytes: 0, webpConverted: 0, svgOptimised: 0, soundFonts: [] };
|
|
101
|
+
: { groups: [], keys: [], rawBytes: 0, embeddedBytes: 0, webpConverted: 0, svgOptimised: 0, soundFonts: [] };
|
|
101
102
|
|
|
102
103
|
const html = await readFile(join(dist, 'index.html'), 'utf8');
|
|
103
104
|
const classic = toClassicScript(html);
|
|
@@ -124,7 +125,38 @@ export async function emitPage({
|
|
|
124
125
|
const standalone = await readFile(single.path, 'utf8');
|
|
125
126
|
await writeFile(single.path, withContentSecurityPolicy(standalone, { ...cspOptions, scripts }), 'utf8');
|
|
126
127
|
}
|
|
127
|
-
|
|
128
|
+
const unusedAssets = await unreferencedAssets(dist, classic.src, compiled.keys);
|
|
129
|
+
const pageBytes = await pageWeight(dist, single, compiled.groups);
|
|
130
|
+
if (maxPageBytes !== undefined && pageBytes > maxPageBytes) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`the page weighs ${kb(pageBytes)}, over the ${kb(maxPageBytes)} budget (maxPageBytes)` +
|
|
133
|
+
(unusedAssets.length
|
|
134
|
+
? `; ${unusedAssets.length} embedded asset(s) are never named in the game code: ${unusedAssets.slice(0, 5).join(', ')}`
|
|
135
|
+
: ''),
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
return { dist, entry: classic.src, ...compiled, compressed, single, unusedAssets, pageBytes };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** the embedded assets whose path appears nowhere in the game's script: a hint (a path built at run time is not seen), never an error */
|
|
142
|
+
async function unreferencedAssets(dist, entry, keys) {
|
|
143
|
+
if (keys.length === 0) return [];
|
|
144
|
+
const code = await readFile(join(dist, entry), 'utf8').catch(() => '');
|
|
145
|
+
return keys.filter((key) => !code.includes(key)).sort();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** the bytes a player downloads to open the page: the single file when there is one, else the page, the game script and the asset scripts */
|
|
149
|
+
async function pageWeight(dist, single, groups) {
|
|
150
|
+
const files = single
|
|
151
|
+
? [single.path]
|
|
152
|
+
: [
|
|
153
|
+
join(dist, 'index.html'),
|
|
154
|
+
...(await readdir(dist)).filter((name) => name.endsWith('.js')).map((name) => join(dist, name)),
|
|
155
|
+
...groups.map((g) => join(dist, 'assets', `${g.name}.js`)),
|
|
156
|
+
];
|
|
157
|
+
let total = 0;
|
|
158
|
+
for (const file of files) total += (await stat(file)).size;
|
|
159
|
+
return total;
|
|
128
160
|
}
|
|
129
161
|
|
|
130
162
|
const kb = (n) => (n / 1024).toFixed(1) + ' KB';
|
|
@@ -170,6 +202,7 @@ async function main(argv) {
|
|
|
170
202
|
svgo: argv.includes('--svgo'),
|
|
171
203
|
soundFont: !argv.includes('--no-soundfont-subset'),
|
|
172
204
|
soundFontUsage,
|
|
205
|
+
maxPageBytes: value('max-page-bytes') ? Number(value('max-page-bytes')) : undefined,
|
|
173
206
|
csp: argv.includes('--no-csp')
|
|
174
207
|
? false
|
|
175
208
|
: { connect: argv.filter((a) => a.startsWith('--connect=')).map((a) => a.slice('--connect='.length)) },
|
|
@@ -186,6 +219,13 @@ async function main(argv) {
|
|
|
186
219
|
);
|
|
187
220
|
}
|
|
188
221
|
if (argv.includes('--svgo')) console.log(` ${result.svgOptimised} SVG(s) optimised`);
|
|
222
|
+
console.log(` page weight ${kb(result.pageBytes)}`);
|
|
223
|
+
if (result.unusedAssets.length > 0) {
|
|
224
|
+
console.log(
|
|
225
|
+
` warning: ${result.unusedAssets.length} embedded asset(s) are never named in the game code, ` +
|
|
226
|
+
`so they only add weight (a path built at run time is not seen): ${result.unusedAssets.join(', ')}`,
|
|
227
|
+
);
|
|
228
|
+
}
|
|
189
229
|
for (const font of result.soundFonts ?? []) {
|
|
190
230
|
console.log(
|
|
191
231
|
font.programs === null
|
package/tools/find-chrome.mjs
CHANGED
|
@@ -17,9 +17,11 @@ async function playwright() {
|
|
|
17
17
|
/**
|
|
18
18
|
* The browser to drive: the platform's usual Chrome (or, on Windows, Edge), then a Chromium that
|
|
19
19
|
* Playwright itself installed (`PLAYWRIGHT_BROWSERS_PATH`, common in CI images and containers),
|
|
20
|
-
* then whatever is on PATH. `CHROME_PATH` overrides all of them
|
|
20
|
+
* then whatever is on PATH. `CHROME_PATH` or `CHROME` overrides all of them.
|
|
21
21
|
*/
|
|
22
22
|
export async function findChrome() {
|
|
23
|
+
const override = process.env.CHROME_PATH || process.env.CHROME;
|
|
24
|
+
if (override) return override;
|
|
23
25
|
const candidates =
|
|
24
26
|
process.platform === 'win32'
|
|
25
27
|
? [
|
|
@@ -93,7 +95,7 @@ async function playwrightChromium() {
|
|
|
93
95
|
* page setup and assertions; this is the launch they all had in common.
|
|
94
96
|
*/
|
|
95
97
|
export async function launchChrome({ argsEnv = 'MWG_BENCHMARK_CHROME_ARGS' } = {}) {
|
|
96
|
-
const executablePath =
|
|
98
|
+
const executablePath = await findChrome();
|
|
97
99
|
const extraArgs = (process.env[argsEnv] ?? '').split(' ').filter(Boolean);
|
|
98
100
|
const { chromium } = await playwright();
|
|
99
101
|
return chromium.launch({
|
package/tools/init.mjs
CHANGED
|
@@ -26,7 +26,13 @@ export function initFiles(name) {
|
|
|
26
26
|
private: true,
|
|
27
27
|
version: '0.0.0',
|
|
28
28
|
type: 'module',
|
|
29
|
-
scripts: {
|
|
29
|
+
scripts: {
|
|
30
|
+
dev: 'vite',
|
|
31
|
+
build: 'vite build',
|
|
32
|
+
check: 'tsc --noEmit',
|
|
33
|
+
test: 'node --test',
|
|
34
|
+
'hooks:install': 'git config core.hooksPath .githooks',
|
|
35
|
+
},
|
|
30
36
|
dependencies: { '@datamoc/mw_games': `^${PACKAGE_VERSION}`, 'pixi.js': '^8.20.1' },
|
|
31
37
|
devDependencies: { typescript: '^7.0.2', vite: '^8.2.2' },
|
|
32
38
|
},
|
|
@@ -101,7 +107,9 @@ export function initFiles(name) {
|
|
|
101
107
|
'',
|
|
102
108
|
].join('\n'),
|
|
103
109
|
'assets/.gitkeep': '',
|
|
104
|
-
'
|
|
110
|
+
'.gitignore': 'node_modules/\ndist/\n.opencode/\n.coord-session\n',
|
|
111
|
+
'.githooks/pre-commit': '#!/bin/sh\nset -e\nnpm run check\nnpm test\n',
|
|
112
|
+
'README.md': `# ${name}\n\n\`npm install\`, then \`npm run dev\` to play it while you edit, \`npm run build\` to write \`dist/\`.\nOpen \`dist/index.html\` (or \`dist/standalone.html\`) by double-clicking it: no server needed.\n\nPut images and sounds under \`assets/\`; the build compiles them into the page. An \`assets/credits.json\`\n(\`[{ "name": "...", "license": "...", "author": "...", "url": "..." }]\`) becomes \`dist/CREDITS.txt\`.\n\nAfter \`git init\`, run \`npm run hooks:install\` to enable the included pre-commit hook.\nIt runs \`npm run check\` and \`npm test\`; add your tests under \`tests/\`.\n`,
|
|
105
113
|
};
|
|
106
114
|
}
|
|
107
115
|
|
|
@@ -121,7 +129,7 @@ export function initProject(folder) {
|
|
|
121
129
|
)) {
|
|
122
130
|
const file = join(target, path);
|
|
123
131
|
mkdirSync(dirname(file), { recursive: true });
|
|
124
|
-
writeFileSync(file, content, 'utf8');
|
|
132
|
+
writeFileSync(file, content, { encoding: 'utf8', mode: path === '.githooks/pre-commit' ? 0o755 : 0o644 });
|
|
125
133
|
written.push(path);
|
|
126
134
|
}
|
|
127
135
|
return { folder: target, files: written };
|
package/tools/play-uci.mjs
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
|
-
import { readFileSync, readdirSync, realpathSync } from 'node:fs';
|
|
3
|
+
import { existsSync, readFileSync, readdirSync, realpathSync } from 'node:fs';
|
|
4
4
|
import { join, extname } from 'node:path';
|
|
5
5
|
import { createInterface } from 'node:readline';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
//the framework's own modules: the TypeScript sources inside this repository, the built `dist` inside an
|
|
7
|
+
//installed package, which ships no `src`
|
|
8
|
+
const fromSource = existsSync(new URL('../src/board/chess.ts', import.meta.url));
|
|
9
|
+
const load = (path) => import(fromSource ? `../src/${path}.ts` : `../dist/${path}.js`);
|
|
10
|
+
const { applyMove, cloneChess, legalMoves, parseFen, squareName, startingChess } = await load('board/chess');
|
|
11
|
+
const { parseUciMove, probeBook } = await load('board/openings');
|
|
12
|
+
const { searchTourney } = await load('board/tourney');
|
|
13
|
+
const { loadTablebaseEnding, probeTablebase } = await load('board/tablebase');
|
|
10
14
|
|
|
11
15
|
/**
|
|
12
16
|
* A UCI adapter over the tournament engine: `position`/`go` on stdin, `bestmove`
|
package/tools/vite.mjs
CHANGED
|
@@ -80,7 +80,15 @@ export function mwgPage(options = {}) {
|
|
|
80
80
|
const { assets: _assets, sbom = true, ...emitOptions } = options;
|
|
81
81
|
const source = assets ? resolve(root, assets) : undefined;
|
|
82
82
|
const dist = resolve(root, outDir);
|
|
83
|
-
await emitPage({
|
|
83
|
+
const page = await emitPage({
|
|
84
|
+
...emitOptions,
|
|
85
|
+
dist,
|
|
86
|
+
assets: source && existsSync(source) ? source : undefined,
|
|
87
|
+
});
|
|
88
|
+
if (page.unusedAssets.length > 0)
|
|
89
|
+
console.warn(
|
|
90
|
+
`mwg-page: ${page.unusedAssets.length} embedded asset(s) are never named in the game code: ${page.unusedAssets.join(', ')}`,
|
|
91
|
+
);
|
|
84
92
|
if (sbom) {
|
|
85
93
|
const manifest = join(root, 'package.json');
|
|
86
94
|
const packageJson = existsSync(manifest)
|
package/tools.md
CHANGED
|
@@ -201,6 +201,7 @@ same build.
|
|
|
201
201
|
| --- | --- | --- |
|
|
202
202
|
| `roadmap-progress` | Reports CLOSED.md + ROADMAP.md completion: numbered items in batches of 25, plus the 1.0 exit checklist on its own row (checks to run, not capabilities, so they stay out of the numbered totals), optionally in a browser | `npm run roadmap:progress` |
|
|
203
203
|
| `build-webpage-examples` / `build-webpage-docs` | Generate the live examples and Documentation page under `webpage/` (`REFERENCE.md` guide + TypeDoc under `documentation/api/` + the examples index) | `npm run webpage:examples`, `npm run webpage:docs` |
|
|
204
|
+
| `build-bridge-tutorial` / `bins-smoke` | `build-bridge-tutorial` writes `webpage/tutorials/bridge/index.html` from `tools/templates/bridge-tutorial.html`, quoting the code blocks of `examples/bridge` so a test can check them. `bins-smoke` packs the project, installs the tarball in an empty folder and runs every `mwg-*` bin with `--help` on the Node that runs it; CI runs it on Node 20.19.0. Repository tools, not shipped | `npm run build:bridge-tutorial`, `npm run bins:smoke` |
|
|
204
205
|
| `build-example-index` | Writes `documentation/examples.html`, read from source text (no typedoc, no renderer): for each public module the symbols that carry an `@example`, each linked to its typedoc page when one exists, with the runnable `examples/` that import the module. Part of `webpage:docs`; a repository tool, not shipped (item 430) | `npm run webpage:docs`, or `node tools/build-example-index.mjs [outFile]` |
|
|
205
206
|
| `make-example-diagrams` / `make-architecture-diagrams` | Rebuild the generated diagrams under `webpage/assets` (never hand-drawn) | `npm run webpage:diagrams` |
|
|
206
207
|
| `api-report` | Regenerates `API_REPORT.md` from the built declarations; `--check` compares instead. A CI gate | `npm run api:report`, `npm run api:check` |
|