@datamoc/mw_games 0.25.0 → 0.27.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.
Files changed (112) hide show
  1. package/CHANGELOG.md +192 -0
  2. package/README.md +15 -0
  3. package/api-surface.json +14942 -0
  4. package/dist/actors/StatBlock.d.ts +2 -4
  5. package/dist/actors/StatBlock.d.ts.map +1 -1
  6. package/dist/actors/StatBlock.js +2 -4
  7. package/dist/actors/StatBlock.js.map +1 -1
  8. package/dist/ai/Heuristics.d.ts +1 -1
  9. package/dist/ai/Heuristics.js +1 -1
  10. package/dist/ai/Suggest.d.ts +54 -0
  11. package/dist/ai/Suggest.d.ts.map +1 -0
  12. package/dist/ai/Suggest.js +48 -0
  13. package/dist/ai/Suggest.js.map +1 -0
  14. package/dist/ai/index.d.ts +2 -0
  15. package/dist/ai/index.d.ts.map +1 -1
  16. package/dist/ai/index.js +1 -0
  17. package/dist/ai/index.js.map +1 -1
  18. package/dist/assets/index.d.ts +1 -0
  19. package/dist/assets/index.d.ts.map +1 -1
  20. package/dist/assets/index.js.map +1 -1
  21. package/dist/core/Blob.d.ts.map +1 -1
  22. package/dist/core/Blob.js +2 -8
  23. package/dist/core/Blob.js.map +1 -1
  24. package/dist/core/Grid.d.ts +115 -0
  25. package/dist/core/Grid.d.ts.map +1 -1
  26. package/dist/core/Grid.js +125 -0
  27. package/dist/core/Grid.js.map +1 -1
  28. package/dist/core/HttpTransport.d.ts +14 -0
  29. package/dist/core/HttpTransport.d.ts.map +1 -1
  30. package/dist/core/HttpTransport.js +14 -0
  31. package/dist/core/HttpTransport.js.map +1 -1
  32. package/dist/core/Random.d.ts +63 -13
  33. package/dist/core/Random.d.ts.map +1 -1
  34. package/dist/core/Random.js +28 -25
  35. package/dist/core/Random.js.map +1 -1
  36. package/dist/core/Replay.d.ts +28 -4
  37. package/dist/core/Replay.d.ts.map +1 -1
  38. package/dist/core/Replay.js +38 -9
  39. package/dist/core/Replay.js.map +1 -1
  40. package/dist/core/ReplayFile.d.ts +197 -0
  41. package/dist/core/ReplayFile.d.ts.map +1 -0
  42. package/dist/core/ReplayFile.js +257 -0
  43. package/dist/core/ReplayFile.js.map +1 -0
  44. package/dist/core/index.d.ts +9 -5
  45. package/dist/core/index.d.ts.map +1 -1
  46. package/dist/core/index.js +4 -2
  47. package/dist/core/index.js.map +1 -1
  48. package/dist/headless/index.d.ts +87 -0
  49. package/dist/headless/index.d.ts.map +1 -0
  50. package/dist/headless/index.js +87 -0
  51. package/dist/headless/index.js.map +1 -0
  52. package/dist/mw_games.global.js +113 -113
  53. package/dist/mwl/index.d.ts +1 -1
  54. package/dist/mwl/index.d.ts.map +1 -1
  55. package/dist/mwl/index.js.map +1 -1
  56. package/dist/roguelike/Level.d.ts +1 -1
  57. package/dist/roguelike/Level.d.ts.map +1 -1
  58. package/dist/roguelike/Level.js +3 -21
  59. package/dist/roguelike/Level.js.map +1 -1
  60. package/dist/roguelike/Targeting.d.ts.map +1 -1
  61. package/dist/roguelike/Targeting.js +2 -1
  62. package/dist/roguelike/Targeting.js.map +1 -1
  63. package/dist/rpg/index.d.ts +1 -1
  64. package/dist/rpg/index.d.ts.map +1 -1
  65. package/dist/simulation/Training.d.ts +77 -0
  66. package/dist/simulation/Training.d.ts.map +1 -1
  67. package/dist/simulation/Training.js +87 -0
  68. package/dist/simulation/Training.js.map +1 -1
  69. package/dist/simulation/index.d.ts +2 -2
  70. package/dist/simulation/index.d.ts.map +1 -1
  71. package/dist/simulation/index.js +1 -1
  72. package/dist/simulation/index.js.map +1 -1
  73. package/dist/two-d/pixi-interop.d.ts +24 -1
  74. package/dist/two-d/pixi-interop.d.ts.map +1 -1
  75. package/dist/two-d/pixi-interop.js +23 -1
  76. package/dist/two-d/pixi-interop.js.map +1 -1
  77. package/dist/two-d/render/Beam.d.ts +93 -0
  78. package/dist/two-d/render/Beam.d.ts.map +1 -0
  79. package/dist/two-d/render/Beam.js +154 -0
  80. package/dist/two-d/render/Beam.js.map +1 -0
  81. package/dist/two-d/render/Flights.d.ts +79 -0
  82. package/dist/two-d/render/Flights.d.ts.map +1 -0
  83. package/dist/two-d/render/Flights.js +120 -0
  84. package/dist/two-d/render/Flights.js.map +1 -0
  85. package/dist/two-d/render/Particles.d.ts +48 -0
  86. package/dist/two-d/render/Particles.d.ts.map +1 -1
  87. package/dist/two-d/render/Particles.js +59 -1
  88. package/dist/two-d/render/Particles.js.map +1 -1
  89. package/dist/two-d/render/index.d.ts +6 -2
  90. package/dist/two-d/render/index.d.ts.map +1 -1
  91. package/dist/two-d/render/index.js +2 -0
  92. package/dist/two-d/render/index.js.map +1 -1
  93. package/dist/two-d/ui/MessageLog.d.ts +28 -0
  94. package/dist/two-d/ui/MessageLog.d.ts.map +1 -1
  95. package/dist/two-d/ui/MessageLog.js +23 -6
  96. package/dist/two-d/ui/MessageLog.js.map +1 -1
  97. package/dist/two-d/ui/TextPrompt.d.ts +115 -0
  98. package/dist/two-d/ui/TextPrompt.d.ts.map +1 -0
  99. package/dist/two-d/ui/TextPrompt.js +227 -0
  100. package/dist/two-d/ui/TextPrompt.js.map +1 -0
  101. package/dist/two-d/ui/index.d.ts +4 -2
  102. package/dist/two-d/ui/index.d.ts.map +1 -1
  103. package/dist/two-d/ui/index.js +2 -1
  104. package/dist/two-d/ui/index.js.map +1 -1
  105. package/dist/version.d.ts +1 -1
  106. package/dist/version.js +1 -1
  107. package/package.json +16 -3
  108. package/sbom.cdx.json +6 -6
  109. package/tools/audit-adoptions.d.mts +65 -0
  110. package/tools/audit-adoptions.mjs +252 -0
  111. package/tools/browser-driver.d.mts +78 -0
  112. package/tools/browser-driver.mjs +642 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,198 @@ the public API may still change between minor versions.
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.27.0] - 2026-10-07
11
+
12
+ Two strands in one release. A run is durable and drives the AI (roadmap 396-397): the
13
+ versioned replay envelope refuses another game or framework build by name, `LastRun` keeps
14
+ the newest recording, `runCheckpoint`/`resumeRunPlayer` restore a run mid-run, and the
15
+ `file://` plumbing (download, picker, Blob read) ships with it; `imitationFromReplay` turns
16
+ a recorded run into training samples against its own seeded environment, `runSeededEpisode`
17
+ plays a whole run from a named seed behind any deterministic chooser, and `ai.Suggester`
18
+ is the throttled, non-mutating hint source. The render and UI strand: `Flights` owns live
19
+ projectile flights, `Beam`/`Beams` draw one-shot beams, `TextPrompt` asks for one line with
20
+ IME and screen-reader support, `MessageLog.lastEntries` reads retained entries back, and
21
+ `ParticleEmitter.attach` follows a target; `core.FloatSource` narrows the injectable random
22
+ stream for float-only helpers.
23
+
24
+ ### Added
25
+
26
+ - `core.FloatSource` splits `core.RandomSource`: helpers that draw floats only
27
+ (`float`, `chance`, `weighted`, `weightedKey`) accept the narrower
28
+ `{ float(): number }`, so a float-only stream needs no dead `int`. The
29
+ integer helpers (`int`, `range`, `normalRange`, `element`, `shuffle`) keep
30
+ requiring the full source; `element` stays wide deliberately, because it
31
+ draws through `int()` and re-spelling that draw would change its stream.
32
+
33
+ - `MessageLog.lastEntries(n)` reads the newest retained entries back as plain
34
+ `{ text, level }` records, oldest first, without scraping rendered children:
35
+ entries the wrapped-line budget already dropped are gone, over-count reads
36
+ everything retained, and zero or negative reads nothing. The slice lives in
37
+ the pure `takeLastEntries` beside the existing `linesToDrop` budget, so the
38
+ readback contract is testable without a renderer.
39
+
40
+ - `ParticleEmitter.attach(target)` follows a display object or position thunk on
41
+ every update tick and every `burst()`, with `offsetX`/`offsetY`, an `enabled`
42
+ callback gating tick emission, and auto-detach for destroyed targets;
43
+ `detach()` keeps the last position. The follow math is tested headless through
44
+ textureless emitters.
45
+
46
+ - `Flights` owns a scene's live projectile flights over the existing `Projectile`:
47
+ `add(sprite | texture, from, to, { speed, tint?, spin?, fadeIn?, onArrive? })`
48
+ returns a handle, `update(dt)` drives positions with per-flight spin and fade,
49
+ each arrival dispatches once after leaving the list, and `cancel()`/`clear()`
50
+ forget without dispatching. Caller sprites stay caller-owned; texture-built
51
+ sprites are parented here and destroyed with their flight.
52
+
53
+ - `Beam`/`Beams` draw one-shot beams between two screen points: a fading line by
54
+ default, a fading repeating texture strip with `texture`, additive blend unless
55
+ opted out, `retarget` for tracking endpoints, and `update` reporting expiry
56
+ exactly once so the `Beams` group can remove finished beams itself.
57
+
58
+ - `TextPrompt` asks for one line of text over a `TextModel`: typing through
59
+ `onText` (the newest open prompt wins), caret and edits through
60
+ `left`/`right`/`backspace`/`delete` actions, `confirm` gated by `validate` and
61
+ `cancel` giving up. IME compositions preview until they commit, and the
62
+ message plus validation errors announce through `screenReader` (assertive for
63
+ the errors), with an injectable announcer for tests.
64
+
65
+ - A run is durable now (roadmap 396): `exportReplayFile`/`importReplayFile` wrap a
66
+ recording in a versioned, self-describing envelope that refuses another game or
67
+ framework build by name, `LastRun` keeps the newest recording (one deep, bounded,
68
+ over the same storage a save slot uses), and `runCheckpoint`/`resumeRunPlayer`
69
+ pair the partial recording with the saved state so a restored run resumes mid-run
70
+ instead of restarting - `Recorder` and `Player` both take `fromFrame`, and
71
+ `parseReplayEvents` factors out the half of `deserializeReplay`'s check that
72
+ validates an already-parsed array. The `file://` plumbing rides along:
73
+ `downloadReplayFile` (a Blob download, never `fetch()`), `pickReplayFile`
74
+ (the file picker, null on cancel) and `readReplayFile` (any `Blob`, headless
75
+ Node included).
76
+
77
+ - Replays train and drive the AI (roadmap 397): `imitationFromReplay` walks a
78
+ recorded run against the same seeded `TrainingEnvironment` it was played on and
79
+ returns the `(observation, action)` samples a game's own trainer fits;
80
+ `runSeededEpisode` plays a whole run with any deterministic chooser (a heuristic,
81
+ a `NeuralPolicy`'s argmax, not just a `NeuralModel` like `runRollouts`) from a
82
+ named seed, recording every chosen action so runs compare across builds and
83
+ policies; and `ai.Suggester` is the in-game suggestion mode, the same decision
84
+ call pointed at a hint UI instead of the world, throttled by a frame-count budget
85
+ and never mutating state to compute a hint.
86
+
87
+ ## [0.26.1] - 2026-10-07
88
+
89
+ The 0.26.0 follow-up: its Chrome end-to-end test failed on every CI run, so the
90
+ `tools/browser-driver` Chrome engine never actually worked on a CI machine (a cold
91
+ Windows runner never reached the debugging endpoint in the old budget; an Ubuntu
92
+ runner crashed in Chrome's sandbox). Chrome now launches against its own profile,
93
+ the endpoint is watched on both output streams with a cold-start budget and a
94
+ diagnostic that names what the browser printed, `close` releases the profile and
95
+ the stdio pipes only after the child exits, and the CI workflows pass
96
+ `--no-sandbox` on Linux through the driver's own `MWG_DRIVER_CHROME_ARGS` channel.
97
+ 0.26.0 was tagged before this was known and its npm publish never ran.
98
+
99
+ ### Fixed
100
+
101
+ - `tools/browser-driver`'s Chrome engine launches against its own profile
102
+ (`options.profileDir`, or a temp dir the driver creates and removes on `close`)
103
+ instead of the machine's default one, watches both stdout and stderr for the
104
+ debugging endpoint (which stream a build prints it on is not something to bet
105
+ on), waits up to 30 s instead of 15 (a cold CI machine's first Chrome start can
106
+ outrun the old budget), and names what the browser printed when the endpoint
107
+ never arrives. This is the fix for the Chrome end-to-end test failing on every
108
+ CI run since the driver landed: the default profile on a fresh runner never
109
+ reached the endpoint in time. `close` now also destroys the child's stdio
110
+ pipes (surviving browser helper processes could hold a suite open past the
111
+ browser's own death) and releases the profile only after the child exits.
112
+ The failing configuration is now diagnosed, not just reported: the timeout
113
+ names what the browser printed. CI's Linux jobs pass `--no-sandbox` through
114
+ the driver's `MWG_DRIVER_CHROME_ARGS` channel, since an Ubuntu 23.10+ runner
115
+ that disables unprivileged user namespaces is a property of that machine,
116
+ not of the tool.
117
+
118
+ ## [0.26.0] - 2026-10-07
119
+
120
+ The machine-readable surface and the audit tooling around it: `api-surface.json` ships as the
121
+ `./api-manifest` subpath (one `{ name, kind, subpath, declaringModule }` row per export), the
122
+ blessed `mwg/headless` entry imports every renderer-free module in one line, `tools/audit-adoptions`
123
+ checks a consumer's imports and local definitions against that manifest, and the dependency-free
124
+ `tools/browser-driver` harness drives real Chrome and Firefox. `core` gained injectable `RandomSource`
125
+ streams for every derived helper and the shared square-grid rulers (`chebyshev`, `manhattan`,
126
+ `euclidean`, `distance` by `DistanceMetric`), the coverage gate now enforces `two-d/ui` instead of
127
+ excluding the whole tree, and the bundle-size baseline is refreshed for the growth those brought.
128
+
129
+ ### Added
130
+
131
+ - Exported the types a public signature already names: `mwl` move/evolution/matchup
132
+ definitions, `core` achievement criteria and hex shape types, particle curve and spawn
133
+ area types, screen effect steps, `rpg` route targets, asset loader options, and the
134
+ `core.HttpTransport` base class its four clients already extend.
135
+
136
+ - `core.NEIGHBOURS4`/`NEIGHBOURS8`/`CIRCLE8` share one frozen square-grid offset table
137
+ instead of each module keeping its own: axial, row-major eight, and the clockwise ring
138
+ (`roguelike`'s `neighbourOffsets` returns these now); `core.euclidean` is the
139
+ straight-line ruler beside `roguelike`'s `chebyshevDistance`.
140
+
141
+ - `core.chebyshev` is the king-move ruler beside `euclidean` (a diagonal costs one
142
+ step) and `core.manhattan` the orthogonal-step count; `core.distance` measures with
143
+ the ruler a `DistanceMetric` names, so a data-authored rule picks its geometry by
144
+ name. `roguelike`'s `chebyshevDistance` delegates to `chebyshev` instead of spelling
145
+ the arithmetic out again.
146
+
147
+ - `api-surface.json` is the machine-readable API surface: one
148
+ `{ name, kind, subpath, declaringModule }` entry per export per subpath,
149
+ generated by the same `tools/api-report.mjs` pass that maintains
150
+ `API_REPORT.md`, shipped in the package behind the `./api-manifest` subpath,
151
+ and pinned by `tests/api-manifest.test.ts` (shape and coverage) plus the
152
+ existing `--check` (agreement with the declarations). `node
153
+ tools/api-report.mjs --diff OLD NEW` diffs two releases' surfaces, and the
154
+ report parser no longer drops `export type { ... }` re-export lists.
155
+
156
+ - `core.RandomSource` lets every derived helper (`chance`, `element`,
157
+ `weighted`, `weightedKey`, `shuffle`, `int`, `range`, `normalRange`) draw
158
+ from an injected stream: pass a rule-local `Generator` (or any
159
+ `float`/`int` pair) as the trailing `source` and the ambient stream is left
160
+ untouched, with identical draws and the same `null` reporting.
161
+
162
+ - `node tools/api-report.mjs --diff OLD NEW` lists added, removed and
163
+ kind-changed exports between two `api-surface.json` manifests, so a version
164
+ bump yields a one-command surface diff.
165
+
166
+ - `mwg/headless` is the blessed renderer-free entry: `core`, `simulation`,
167
+ `mwl`, `i18n`, `actors`, `world`, `battle`, `roguelike`, `board`, `audio`,
168
+ `rpg`, `ai`, `testing` and the two renderer-free asset halves, in one import
169
+ with no DOM or WebGL globals. `tests/headless-smoke.test.ts` imports it in
170
+ plain Node, walks the reachable graph for a renderer leak, and replays a
171
+ seeded scenario through it.
172
+
173
+ - `tools/audit-adoptions` (also `mwg-audit-adoptions`) is the shipped consumer
174
+ adoption auditor: manifest plus reasons file plus config (type-only
175
+ directories, subpath deny-lists, per-pattern import budgets), reporting
176
+ unadopted exports, stale reasons, shadowing collisions and config violations
177
+ with `file:line` and a non-zero exit.
178
+
179
+ - `two-d/pixi-interop` now states the interop-only rationale on each
180
+ re-exported primitive's own declaration: every histogram symbol
181
+ (`Rectangle`, `Texture`, `Container`, `Sprite`, `Graphics`, `FillGradient`,
182
+ `TilingSprite`) already has a facade family, so the note names the
183
+ Pixi-typed seam that keeps the raw export, and `tests/pixi-interop-coverage`
184
+ pins both halves.
185
+
186
+ - `tools/browser-driver` is the dependency-free browser harness: a self-served
187
+ static directory on an OS-chosen free port, Chrome over CDP and Firefox over
188
+ WebDriver BiDi behind one surface (`goto`/`waitReady`/`tap` at canvas
189
+ fractions/`evaluate`/`script`/`screenshot`/`consoleErrors`/`close`), reusing
190
+ the `browser-smoke` readiness contract. Verified live on both engines.
191
+
192
+ ### Changed
193
+
194
+ - The coverage gate now enforces `two-d/ui` instead of excluding the whole tree:
195
+ the widget tests the suite already ran carry it (97.3/92.6/94.3 against the
196
+ 88/89/82 floors), so the exclusion was stale, and a wildcard also left every
197
+ new UI file silently ungated. `EventDialogue` stays excluded as intended, under
198
+ its real path (`two-d/ui`, where the old flag pointed at a nonexistent
199
+ `two-d/stage` copy), and `SelectionModel` gained a direct contract test that
200
+ covers it fully, where before only its embedding widgets exercised it.
201
+
10
202
  ## [0.25.0] - 2026-10-05
11
203
 
12
204
  Framework support for the Pixel Dungeon port's simulation and content proposals: numeric
package/README.md CHANGED
@@ -336,6 +336,21 @@ edited in a proper editor, without any of those options requiring changes to the
336
336
  It also keeps the content out of the bundle: `tools/compile-resources` treats a map file
337
337
  exactly like a sprite sheet, so adding a hundred maps does not touch the build at all.
338
338
 
339
+ ### Objects for behavior, data for content
340
+
341
+ Content is data (above), but a game's *behavior* belongs in classes. A monster kept as
342
+ loose scene fields works for one tutorial room and collapses for a dungeon: give it a
343
+ class holding its state and the methods that change it, built on the framework's own
344
+ bricks (`core.Scene` scenes, `actors.StatBlock` stats, `battle.Creature` opponents,
345
+ `roguelike.Level` maps, `rpg.GridMover` movement, `core.EntityRegistry` identity).
346
+ Subclass the brick that already owns the concern instead of reimplementing it beside an
347
+ interface; no new base class is needed for ordinary actors.
348
+
349
+ The boundary is where serialization starts. `simulation` commands survive
350
+ `structuredClone`, `core.SaveSystem` stores JSON-serialisable state, and MWL rows are
351
+ records by design, so classes stop where those begin: flatten at the boundary the way
352
+ `rpg.GameState` does, and rebuild objects on load rather than storing them.
353
+
339
354
  ### On writing direction
340
355
 
341
356
  Supporting more than one language is mostly bookkeeping. Supporting more than one writing