@datamoc/mw_games 0.44.2 → 0.46.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 (1695) hide show
  1. package/3d/models.d.ts +1 -0
  2. package/3d/models.js +1 -0
  3. package/3d.d.ts +1 -0
  4. package/3d.js +1 -0
  5. package/README.md +5 -732
  6. package/actors.d.ts +1 -0
  7. package/actors.js +1 -0
  8. package/ai/lua.d.ts +1 -0
  9. package/ai/lua.js +1 -0
  10. package/ai.d.ts +1 -0
  11. package/ai.js +1 -0
  12. package/assets/binary.d.ts +1 -0
  13. package/assets/binary.js +1 -0
  14. package/assets/paths.d.ts +1 -0
  15. package/assets/paths.js +1 -0
  16. package/assets.d.ts +1 -0
  17. package/assets.js +1 -0
  18. package/audio.d.ts +1 -0
  19. package/audio.js +1 -0
  20. package/battle.d.ts +1 -0
  21. package/battle.js +1 -0
  22. package/board.d.ts +1 -0
  23. package/board.js +1 -0
  24. package/core.d.ts +1 -0
  25. package/core.js +1 -0
  26. package/headless.d.ts +1 -0
  27. package/headless.js +1 -0
  28. package/i18n.d.ts +1 -0
  29. package/i18n.js +1 -0
  30. package/index.d.ts +1 -0
  31. package/index.js +1 -0
  32. package/mwl/presentation.d.ts +1 -0
  33. package/mwl/presentation.js +1 -0
  34. package/mwl/pyroeis.d.ts +1 -0
  35. package/mwl/pyroeis.js +1 -0
  36. package/mwl.d.ts +1 -0
  37. package/mwl.js +1 -0
  38. package/package.json +212 -394
  39. package/physics/xpbd.d.ts +1 -0
  40. package/physics/xpbd.js +1 -0
  41. package/physics.d.ts +1 -0
  42. package/physics.js +1 -0
  43. package/roguelike.d.ts +1 -0
  44. package/roguelike.js +1 -0
  45. package/rpg.d.ts +1 -0
  46. package/rpg.js +1 -0
  47. package/simulation.d.ts +1 -0
  48. package/simulation.js +1 -0
  49. package/skeleton.d.ts +1 -0
  50. package/skeleton.js +1 -0
  51. package/testing.d.ts +1 -0
  52. package/testing.js +1 -0
  53. package/threads.d.ts +1 -0
  54. package/threads.js +1 -0
  55. package/tools/asset-report.d.mts +1 -37
  56. package/tools/asset-report.mjs +1 -157
  57. package/tools/audio.d.mts +1 -75
  58. package/tools/audio.mjs +1 -437
  59. package/tools/audit-adoptions.d.mts +1 -65
  60. package/tools/audit-adoptions.mjs +1 -252
  61. package/tools/benchmark-browser.d.mts +1 -33
  62. package/tools/benchmark-browser.mjs +1 -169
  63. package/tools/benchmark-history.d.mts +1 -8
  64. package/tools/benchmark-history.mjs +1 -31
  65. package/tools/browser-driver.d.mts +1 -122
  66. package/tools/browser-driver.mjs +1 -861
  67. package/tools/browser-smoke.d.mts +1 -30
  68. package/tools/browser-smoke.mjs +1 -184
  69. package/tools/build-tablebases.d.mts +1 -22
  70. package/tools/build-tablebases.mjs +1 -557
  71. package/tools/bundle-size.d.mts +1 -11
  72. package/tools/bundle-size.mjs +1 -142
  73. package/tools/classic-html.d.mts +1 -6
  74. package/tools/classic-html.mjs +1 -69
  75. package/tools/compile-openings.d.mts +1 -20
  76. package/tools/compile-openings.mjs +1 -138
  77. package/tools/compile-resources.d.mts +1 -66
  78. package/tools/compile-resources.mjs +1 -406
  79. package/tools/compress-dist.d.mts +1 -42
  80. package/tools/compress-dist.mjs +1 -193
  81. package/tools/csp.d.mts +1 -7
  82. package/tools/csp.mjs +1 -65
  83. package/tools/emit-page.d.mts +1 -61
  84. package/tools/emit-page.mjs +1 -273
  85. package/tools/extract-html.d.mts +1 -18
  86. package/tools/extract-html.mjs +1 -235
  87. package/tools/extract-rgssad.d.mts +1 -5
  88. package/tools/extract-rgssad.mjs +1 -64
  89. package/tools/find-chrome.d.mts +1 -7
  90. package/tools/find-chrome.mjs +1 -106
  91. package/tools/i18n-edit.d.mts +1 -29
  92. package/tools/i18n-edit.mjs +1 -748
  93. package/tools/init.d.mts +1 -5
  94. package/tools/init.mjs +1 -155
  95. package/tools/make-example-assets.d.mts +1 -2
  96. package/tools/make-example-assets.mjs +1 -731
  97. package/tools/multiplayer-server.d.mts +1 -27
  98. package/tools/multiplayer-server.mjs +1 -199
  99. package/tools/play-uci.d.mts +1 -26
  100. package/tools/play-uci.mjs +1 -205
  101. package/tools/sbom.d.mts +1 -83
  102. package/tools/sbom.mjs +1 -340
  103. package/tools/single-file.d.mts +1 -33
  104. package/tools/single-file.mjs +1 -239
  105. package/tools/soundfonts.d.mts +1 -79
  106. package/tools/soundfonts.mjs +1 -301
  107. package/tools/svg-optimise.d.mts +1 -8
  108. package/tools/svg-optimise.mjs +1 -45
  109. package/tools/verify-scenarios.d.mts +1 -15
  110. package/tools/verify-scenarios.mjs +1 -133
  111. package/tools/vite.d.mts +1 -17
  112. package/tools/vite.mjs +1 -102
  113. package/tools/webp-convert.d.mts +1 -8
  114. package/tools/webp-convert.mjs +1 -98
  115. package/two-d/pixi-interop.d.ts +1 -0
  116. package/two-d/pixi-interop.js +1 -0
  117. package/two-d/presentation.d.ts +1 -0
  118. package/two-d/presentation.js +1 -0
  119. package/two-d/render.d.ts +1 -0
  120. package/two-d/render.js +1 -0
  121. package/two-d/stage.d.ts +1 -0
  122. package/two-d/stage.js +1 -0
  123. package/two-d/ui.d.ts +1 -0
  124. package/two-d/ui.js +1 -0
  125. package/two-d.d.ts +1 -0
  126. package/two-d.js +1 -0
  127. package/world.d.ts +1 -0
  128. package/world.js +1 -0
  129. package/CHANGELOG.md +0 -3196
  130. package/LICENSE +0 -373
  131. package/MWG - Best Practices.md +0 -97
  132. package/MWG - Deep Code and Architecture Review.md +0 -238
  133. package/REFERENCE.md +0 -2256
  134. package/api-surface.json +0 -18128
  135. package/data/microgm-essential.PROVENANCE.md +0 -13
  136. package/data/microgm-essential.sf2 +0 -0
  137. package/data/microgm-opt.PROVENANCE.md +0 -23
  138. package/data/microgm-opt.sf2 +0 -0
  139. package/data/soundfont-catalog.json +0 -191
  140. package/dist/actors/Advancement.d.ts +0 -90
  141. package/dist/actors/Advancement.d.ts.map +0 -1
  142. package/dist/actors/Advancement.js +0 -115
  143. package/dist/actors/Advancement.js.map +0 -1
  144. package/dist/actors/Affix.d.ts +0 -96
  145. package/dist/actors/Affix.d.ts.map +0 -1
  146. package/dist/actors/Affix.js +0 -68
  147. package/dist/actors/Affix.js.map +0 -1
  148. package/dist/actors/Appearances.d.ts +0 -48
  149. package/dist/actors/Appearances.d.ts.map +0 -1
  150. package/dist/actors/Appearances.js +0 -62
  151. package/dist/actors/Appearances.js.map +0 -1
  152. package/dist/actors/Aura.d.ts +0 -45
  153. package/dist/actors/Aura.d.ts.map +0 -1
  154. package/dist/actors/Aura.js +0 -85
  155. package/dist/actors/Aura.js.map +0 -1
  156. package/dist/actors/Barrier.d.ts +0 -60
  157. package/dist/actors/Barrier.d.ts.map +0 -1
  158. package/dist/actors/Barrier.js +0 -70
  159. package/dist/actors/Barrier.js.map +0 -1
  160. package/dist/actors/Charges.d.ts +0 -66
  161. package/dist/actors/Charges.d.ts.map +0 -1
  162. package/dist/actors/Charges.js +0 -61
  163. package/dist/actors/Charges.js.map +0 -1
  164. package/dist/actors/EntityTemplate.d.ts +0 -127
  165. package/dist/actors/EntityTemplate.d.ts.map +0 -1
  166. package/dist/actors/EntityTemplate.js +0 -117
  167. package/dist/actors/EntityTemplate.js.map +0 -1
  168. package/dist/actors/Equipment.d.ts +0 -88
  169. package/dist/actors/Equipment.d.ts.map +0 -1
  170. package/dist/actors/Equipment.js +0 -107
  171. package/dist/actors/Equipment.js.map +0 -1
  172. package/dist/actors/Inventory.d.ts +0 -123
  173. package/dist/actors/Inventory.d.ts.map +0 -1
  174. package/dist/actors/Inventory.js +0 -165
  175. package/dist/actors/Inventory.js.map +0 -1
  176. package/dist/actors/ItemState.d.ts +0 -43
  177. package/dist/actors/ItemState.d.ts.map +0 -1
  178. package/dist/actors/ItemState.js +0 -63
  179. package/dist/actors/ItemState.js.map +0 -1
  180. package/dist/actors/ItemStatusEffect.d.ts +0 -40
  181. package/dist/actors/ItemStatusEffect.d.ts.map +0 -1
  182. package/dist/actors/ItemStatusEffect.js +0 -39
  183. package/dist/actors/ItemStatusEffect.js.map +0 -1
  184. package/dist/actors/Loot.d.ts +0 -38
  185. package/dist/actors/Loot.d.ts.map +0 -1
  186. package/dist/actors/Loot.js +0 -28
  187. package/dist/actors/Loot.js.map +0 -1
  188. package/dist/actors/Progression.d.ts +0 -52
  189. package/dist/actors/Progression.d.ts.map +0 -1
  190. package/dist/actors/Progression.js +0 -59
  191. package/dist/actors/Progression.js.map +0 -1
  192. package/dist/actors/Resource.d.ts +0 -53
  193. package/dist/actors/Resource.d.ts.map +0 -1
  194. package/dist/actors/Resource.js +0 -57
  195. package/dist/actors/Resource.js.map +0 -1
  196. package/dist/actors/Scaling.d.ts +0 -30
  197. package/dist/actors/Scaling.d.ts.map +0 -1
  198. package/dist/actors/Scaling.js +0 -9
  199. package/dist/actors/Scaling.js.map +0 -1
  200. package/dist/actors/Shop.d.ts +0 -40
  201. package/dist/actors/Shop.d.ts.map +0 -1
  202. package/dist/actors/Shop.js +0 -36
  203. package/dist/actors/Shop.js.map +0 -1
  204. package/dist/actors/SkillPoints.d.ts +0 -72
  205. package/dist/actors/SkillPoints.d.ts.map +0 -1
  206. package/dist/actors/SkillPoints.js +0 -87
  207. package/dist/actors/SkillPoints.js.map +0 -1
  208. package/dist/actors/StatBlock.d.ts +0 -86
  209. package/dist/actors/StatBlock.d.ts.map +0 -1
  210. package/dist/actors/StatBlock.js +0 -110
  211. package/dist/actors/StatBlock.js.map +0 -1
  212. package/dist/actors/StatusEffect.d.ts +0 -67
  213. package/dist/actors/StatusEffect.d.ts.map +0 -1
  214. package/dist/actors/StatusEffect.js +0 -59
  215. package/dist/actors/StatusEffect.js.map +0 -1
  216. package/dist/actors/Support.d.ts +0 -43
  217. package/dist/actors/Support.d.ts.map +0 -1
  218. package/dist/actors/Support.js +0 -71
  219. package/dist/actors/Support.js.map +0 -1
  220. package/dist/actors/Traits.d.ts +0 -43
  221. package/dist/actors/Traits.d.ts.map +0 -1
  222. package/dist/actors/Traits.js +0 -35
  223. package/dist/actors/Traits.js.map +0 -1
  224. package/dist/actors/craft.d.ts +0 -63
  225. package/dist/actors/craft.d.ts.map +0 -1
  226. package/dist/actors/craft.js +0 -86
  227. package/dist/actors/craft.js.map +0 -1
  228. package/dist/actors/index.d.ts +0 -46
  229. package/dist/actors/index.d.ts.map +0 -1
  230. package/dist/actors/index.js +0 -24
  231. package/dist/actors/index.js.map +0 -1
  232. package/dist/actors/skillCheck.d.ts +0 -21
  233. package/dist/actors/skillCheck.d.ts.map +0 -1
  234. package/dist/actors/skillCheck.js +0 -24
  235. package/dist/actors/skillCheck.js.map +0 -1
  236. package/dist/ai/Heuristics.d.ts +0 -240
  237. package/dist/ai/Heuristics.d.ts.map +0 -1
  238. package/dist/ai/Heuristics.js +0 -298
  239. package/dist/ai/Heuristics.js.map +0 -1
  240. package/dist/ai/Neural.d.ts +0 -65
  241. package/dist/ai/Neural.d.ts.map +0 -1
  242. package/dist/ai/Neural.js +0 -169
  243. package/dist/ai/Neural.js.map +0 -1
  244. package/dist/ai/Suggest.d.ts +0 -54
  245. package/dist/ai/Suggest.d.ts.map +0 -1
  246. package/dist/ai/Suggest.js +0 -48
  247. package/dist/ai/Suggest.js.map +0 -1
  248. package/dist/ai/index.d.ts +0 -136
  249. package/dist/ai/index.d.ts.map +0 -1
  250. package/dist/ai/index.js +0 -207
  251. package/dist/ai/index.js.map +0 -1
  252. package/dist/ai/lua.d.ts +0 -74
  253. package/dist/ai/lua.d.ts.map +0 -1
  254. package/dist/ai/lua.js +0 -217
  255. package/dist/ai/lua.js.map +0 -1
  256. package/dist/ai/score.d.ts +0 -162
  257. package/dist/ai/score.d.ts.map +0 -1
  258. package/dist/ai/score.js +0 -147
  259. package/dist/ai/score.js.map +0 -1
  260. package/dist/ai/search.d.ts +0 -108
  261. package/dist/ai/search.d.ts.map +0 -1
  262. package/dist/ai/search.js +0 -148
  263. package/dist/ai/search.js.map +0 -1
  264. package/dist/assets/ByteProgress.d.ts +0 -37
  265. package/dist/assets/ByteProgress.d.ts.map +0 -1
  266. package/dist/assets/ByteProgress.js +0 -54
  267. package/dist/assets/ByteProgress.js.map +0 -1
  268. package/dist/assets/Streaming.d.ts +0 -56
  269. package/dist/assets/Streaming.d.ts.map +0 -1
  270. package/dist/assets/Streaming.js +0 -100
  271. package/dist/assets/Streaming.js.map +0 -1
  272. package/dist/assets/SvgParts.d.ts +0 -31
  273. package/dist/assets/SvgParts.d.ts.map +0 -1
  274. package/dist/assets/SvgParts.js +0 -54
  275. package/dist/assets/SvgParts.js.map +0 -1
  276. package/dist/assets/SvgSource.d.ts +0 -3
  277. package/dist/assets/SvgSource.d.ts.map +0 -1
  278. package/dist/assets/SvgSource.js +0 -22
  279. package/dist/assets/SvgSource.js.map +0 -1
  280. package/dist/assets/binary.d.ts +0 -52
  281. package/dist/assets/binary.d.ts.map +0 -1
  282. package/dist/assets/binary.js +0 -57
  283. package/dist/assets/binary.js.map +0 -1
  284. package/dist/assets/index.d.ts +0 -27
  285. package/dist/assets/index.d.ts.map +0 -1
  286. package/dist/assets/index.js +0 -20
  287. package/dist/assets/index.js.map +0 -1
  288. package/dist/assets/loader.d.ts +0 -70
  289. package/dist/assets/loader.d.ts.map +0 -1
  290. package/dist/assets/loader.js +0 -115
  291. package/dist/assets/loader.js.map +0 -1
  292. package/dist/assets/paths.d.ts +0 -73
  293. package/dist/assets/paths.d.ts.map +0 -1
  294. package/dist/assets/paths.js +0 -91
  295. package/dist/assets/paths.js.map +0 -1
  296. package/dist/assets/svg.d.ts +0 -87
  297. package/dist/assets/svg.d.ts.map +0 -1
  298. package/dist/assets/svg.js +0 -166
  299. package/dist/assets/svg.js.map +0 -1
  300. package/dist/audio/AdaptiveMusic.d.ts +0 -85
  301. package/dist/audio/AdaptiveMusic.d.ts.map +0 -1
  302. package/dist/audio/AdaptiveMusic.js +0 -230
  303. package/dist/audio/AdaptiveMusic.js.map +0 -1
  304. package/dist/audio/AudioLoader.d.ts +0 -33
  305. package/dist/audio/AudioLoader.d.ts.map +0 -1
  306. package/dist/audio/AudioLoader.js +0 -58
  307. package/dist/audio/AudioLoader.js.map +0 -1
  308. package/dist/audio/AudioViews.d.ts +0 -70
  309. package/dist/audio/AudioViews.d.ts.map +0 -1
  310. package/dist/audio/AudioViews.js +0 -119
  311. package/dist/audio/AudioViews.js.map +0 -1
  312. package/dist/audio/BusBudget.d.ts +0 -89
  313. package/dist/audio/BusBudget.d.ts.map +0 -1
  314. package/dist/audio/BusBudget.js +0 -120
  315. package/dist/audio/BusBudget.js.map +0 -1
  316. package/dist/audio/Captions.d.ts +0 -27
  317. package/dist/audio/Captions.d.ts.map +0 -1
  318. package/dist/audio/Captions.js +0 -16
  319. package/dist/audio/Captions.js.map +0 -1
  320. package/dist/audio/Channels.d.ts +0 -282
  321. package/dist/audio/Channels.d.ts.map +0 -1
  322. package/dist/audio/Channels.js +0 -573
  323. package/dist/audio/Channels.js.map +0 -1
  324. package/dist/audio/CoreHost.d.ts +0 -114
  325. package/dist/audio/CoreHost.d.ts.map +0 -1
  326. package/dist/audio/CoreHost.js +0 -335
  327. package/dist/audio/CoreHost.js.map +0 -1
  328. package/dist/audio/DecoderGuard.d.ts +0 -139
  329. package/dist/audio/DecoderGuard.d.ts.map +0 -1
  330. package/dist/audio/DecoderGuard.js +0 -208
  331. package/dist/audio/DecoderGuard.js.map +0 -1
  332. package/dist/audio/Fft.d.ts +0 -3
  333. package/dist/audio/Fft.d.ts.map +0 -1
  334. package/dist/audio/Fft.js +0 -45
  335. package/dist/audio/Fft.js.map +0 -1
  336. package/dist/audio/LoopTags.d.ts +0 -55
  337. package/dist/audio/LoopTags.d.ts.map +0 -1
  338. package/dist/audio/LoopTags.js +0 -136
  339. package/dist/audio/LoopTags.js.map +0 -1
  340. package/dist/audio/Midi.d.ts +0 -219
  341. package/dist/audio/Midi.d.ts.map +0 -1
  342. package/dist/audio/Midi.js +0 -409
  343. package/dist/audio/Midi.js.map +0 -1
  344. package/dist/audio/MidiRender.d.ts +0 -144
  345. package/dist/audio/MidiRender.d.ts.map +0 -1
  346. package/dist/audio/MidiRender.js +0 -448
  347. package/dist/audio/MidiRender.js.map +0 -1
  348. package/dist/audio/MidiSynth.d.ts +0 -147
  349. package/dist/audio/MidiSynth.d.ts.map +0 -1
  350. package/dist/audio/MidiSynth.js +0 -205
  351. package/dist/audio/MidiSynth.js.map +0 -1
  352. package/dist/audio/Music.d.ts +0 -70
  353. package/dist/audio/Music.d.ts.map +0 -1
  354. package/dist/audio/Music.js +0 -191
  355. package/dist/audio/Music.js.map +0 -1
  356. package/dist/audio/MusicPlayer.d.ts +0 -80
  357. package/dist/audio/MusicPlayer.d.ts.map +0 -1
  358. package/dist/audio/MusicPlayer.js +0 -147
  359. package/dist/audio/MusicPlayer.js.map +0 -1
  360. package/dist/audio/Orchestrator.d.ts +0 -58
  361. package/dist/audio/Orchestrator.d.ts.map +0 -1
  362. package/dist/audio/Orchestrator.js +0 -74
  363. package/dist/audio/Orchestrator.js.map +0 -1
  364. package/dist/audio/Playable.d.ts +0 -38
  365. package/dist/audio/Playable.d.ts.map +0 -1
  366. package/dist/audio/Playable.js +0 -29
  367. package/dist/audio/Playable.js.map +0 -1
  368. package/dist/audio/Positional.d.ts +0 -133
  369. package/dist/audio/Positional.d.ts.map +0 -1
  370. package/dist/audio/Positional.js +0 -138
  371. package/dist/audio/Positional.js.map +0 -1
  372. package/dist/audio/Resample.d.ts +0 -61
  373. package/dist/audio/Resample.d.ts.map +0 -1
  374. package/dist/audio/Resample.js +0 -97
  375. package/dist/audio/Resample.js.map +0 -1
  376. package/dist/audio/SampleDecoder.d.ts +0 -55
  377. package/dist/audio/SampleDecoder.d.ts.map +0 -1
  378. package/dist/audio/SampleDecoder.js +0 -74
  379. package/dist/audio/SampleDecoder.js.map +0 -1
  380. package/dist/audio/Settings.d.ts +0 -99
  381. package/dist/audio/Settings.d.ts.map +0 -1
  382. package/dist/audio/Settings.js +0 -134
  383. package/dist/audio/Settings.js.map +0 -1
  384. package/dist/audio/Sfx.d.ts +0 -148
  385. package/dist/audio/Sfx.d.ts.map +0 -1
  386. package/dist/audio/Sfx.js +0 -213
  387. package/dist/audio/Sfx.js.map +0 -1
  388. package/dist/audio/Sound.d.ts +0 -57
  389. package/dist/audio/Sound.d.ts.map +0 -1
  390. package/dist/audio/Sound.js +0 -79
  391. package/dist/audio/Sound.js.map +0 -1
  392. package/dist/audio/SoundFont.d.ts +0 -192
  393. package/dist/audio/SoundFont.d.ts.map +0 -1
  394. package/dist/audio/SoundFont.js +0 -862
  395. package/dist/audio/SoundFont.js.map +0 -1
  396. package/dist/audio/SpectralDistance.d.ts +0 -34
  397. package/dist/audio/SpectralDistance.d.ts.map +0 -1
  398. package/dist/audio/SpectralDistance.js +0 -64
  399. package/dist/audio/SpectralDistance.js.map +0 -1
  400. package/dist/audio/StreamChannel.d.ts +0 -150
  401. package/dist/audio/StreamChannel.d.ts.map +0 -1
  402. package/dist/audio/StreamChannel.js +0 -390
  403. package/dist/audio/StreamChannel.js.map +0 -1
  404. package/dist/audio/StreamPlayable.d.ts +0 -73
  405. package/dist/audio/StreamPlayable.d.ts.map +0 -1
  406. package/dist/audio/StreamPlayable.js +0 -130
  407. package/dist/audio/StreamPlayable.js.map +0 -1
  408. package/dist/audio/Synth.d.ts +0 -64
  409. package/dist/audio/Synth.d.ts.map +0 -1
  410. package/dist/audio/Synth.js +0 -133
  411. package/dist/audio/Synth.js.map +0 -1
  412. package/dist/audio/SyxBank.d.ts +0 -73
  413. package/dist/audio/SyxBank.d.ts.map +0 -1
  414. package/dist/audio/SyxBank.js +0 -130
  415. package/dist/audio/SyxBank.js.map +0 -1
  416. package/dist/audio/Underrun.d.ts +0 -25
  417. package/dist/audio/Underrun.d.ts.map +0 -1
  418. package/dist/audio/Underrun.js +0 -18
  419. package/dist/audio/Underrun.js.map +0 -1
  420. package/dist/audio/Wav.d.ts +0 -56
  421. package/dist/audio/Wav.d.ts.map +0 -1
  422. package/dist/audio/Wav.js +0 -164
  423. package/dist/audio/Wav.js.map +0 -1
  424. package/dist/audio/WebMidi.d.ts +0 -58
  425. package/dist/audio/WebMidi.d.ts.map +0 -1
  426. package/dist/audio/WebMidi.js +0 -79
  427. package/dist/audio/WebMidi.js.map +0 -1
  428. package/dist/audio/humanize/Groove.d.ts +0 -80
  429. package/dist/audio/humanize/Groove.d.ts.map +0 -1
  430. package/dist/audio/humanize/Groove.js +0 -102
  431. package/dist/audio/humanize/Groove.js.map +0 -1
  432. package/dist/audio/humanize/GrooveConverter.d.ts +0 -49
  433. package/dist/audio/humanize/GrooveConverter.d.ts.map +0 -1
  434. package/dist/audio/humanize/GrooveConverter.js +0 -344
  435. package/dist/audio/humanize/GrooveConverter.js.map +0 -1
  436. package/dist/audio/humanize/GrooveExtractor.d.ts +0 -49
  437. package/dist/audio/humanize/GrooveExtractor.d.ts.map +0 -1
  438. package/dist/audio/humanize/GrooveExtractor.js +0 -179
  439. package/dist/audio/humanize/GrooveExtractor.js.map +0 -1
  440. package/dist/audio/humanize/GrooveHumanizer.d.ts +0 -34
  441. package/dist/audio/humanize/GrooveHumanizer.d.ts.map +0 -1
  442. package/dist/audio/humanize/GrooveHumanizer.js +0 -37
  443. package/dist/audio/humanize/GrooveHumanizer.js.map +0 -1
  444. package/dist/audio/humanize/Humanize.d.ts +0 -54
  445. package/dist/audio/humanize/Humanize.d.ts.map +0 -1
  446. package/dist/audio/humanize/Humanize.js +0 -239
  447. package/dist/audio/humanize/Humanize.js.map +0 -1
  448. package/dist/audio/humanize/HumanizerFactory.d.ts +0 -68
  449. package/dist/audio/humanize/HumanizerFactory.d.ts.map +0 -1
  450. package/dist/audio/humanize/HumanizerFactory.js +0 -84
  451. package/dist/audio/humanize/HumanizerFactory.js.map +0 -1
  452. package/dist/audio/humanize/LiteHumanizer.d.ts +0 -30
  453. package/dist/audio/humanize/LiteHumanizer.d.ts.map +0 -1
  454. package/dist/audio/humanize/LiteHumanizer.js +0 -35
  455. package/dist/audio/humanize/LiteHumanizer.js.map +0 -1
  456. package/dist/audio/humanize/Onsets.d.ts +0 -26
  457. package/dist/audio/humanize/Onsets.d.ts.map +0 -1
  458. package/dist/audio/humanize/Onsets.js +0 -121
  459. package/dist/audio/humanize/Onsets.js.map +0 -1
  460. package/dist/audio/index.d.ts +0 -75
  461. package/dist/audio/index.d.ts.map +0 -1
  462. package/dist/audio/index.js +0 -38
  463. package/dist/audio/index.js.map +0 -1
  464. package/dist/battle/AttackDialog.d.ts +0 -75
  465. package/dist/battle/AttackDialog.d.ts.map +0 -1
  466. package/dist/battle/AttackDialog.js +0 -115
  467. package/dist/battle/AttackDialog.js.map +0 -1
  468. package/dist/battle/AttackPreview.d.ts +0 -70
  469. package/dist/battle/AttackPreview.d.ts.map +0 -1
  470. package/dist/battle/AttackPreview.js +0 -78
  471. package/dist/battle/AttackPreview.js.map +0 -1
  472. package/dist/battle/BattleAI.d.ts +0 -40
  473. package/dist/battle/BattleAI.d.ts.map +0 -1
  474. package/dist/battle/BattleAI.js +0 -63
  475. package/dist/battle/BattleAI.js.map +0 -1
  476. package/dist/battle/BattleStats.d.ts +0 -45
  477. package/dist/battle/BattleStats.d.ts.map +0 -1
  478. package/dist/battle/BattleStats.js +0 -63
  479. package/dist/battle/BattleStats.js.map +0 -1
  480. package/dist/battle/Evolution.d.ts +0 -34
  481. package/dist/battle/Evolution.d.ts.map +0 -1
  482. package/dist/battle/Evolution.js +0 -37
  483. package/dist/battle/Evolution.js.map +0 -1
  484. package/dist/battle/Field.d.ts +0 -36
  485. package/dist/battle/Field.d.ts.map +0 -1
  486. package/dist/battle/Field.js +0 -31
  487. package/dist/battle/Field.js.map +0 -1
  488. package/dist/battle/Hooks.d.ts +0 -39
  489. package/dist/battle/Hooks.d.ts.map +0 -1
  490. package/dist/battle/Hooks.js +0 -38
  491. package/dist/battle/Hooks.js.map +0 -1
  492. package/dist/battle/Move.d.ts +0 -45
  493. package/dist/battle/Move.d.ts.map +0 -1
  494. package/dist/battle/Move.js +0 -23
  495. package/dist/battle/Move.js.map +0 -1
  496. package/dist/battle/Party.d.ts +0 -32
  497. package/dist/battle/Party.d.ts.map +0 -1
  498. package/dist/battle/Party.js +0 -62
  499. package/dist/battle/Party.js.map +0 -1
  500. package/dist/battle/Species.d.ts +0 -50
  501. package/dist/battle/Species.d.ts.map +0 -1
  502. package/dist/battle/Species.js +0 -41
  503. package/dist/battle/Species.js.map +0 -1
  504. package/dist/battle/StatStages.d.ts +0 -52
  505. package/dist/battle/StatStages.d.ts.map +0 -1
  506. package/dist/battle/StatStages.js +0 -51
  507. package/dist/battle/StatStages.js.map +0 -1
  508. package/dist/battle/TypeMatrix.d.ts +0 -25
  509. package/dist/battle/TypeMatrix.d.ts.map +0 -1
  510. package/dist/battle/TypeMatrix.js +0 -35
  511. package/dist/battle/TypeMatrix.js.map +0 -1
  512. package/dist/battle/UnitSelector.d.ts +0 -72
  513. package/dist/battle/UnitSelector.d.ts.map +0 -1
  514. package/dist/battle/UnitSelector.js +0 -117
  515. package/dist/battle/UnitSelector.js.map +0 -1
  516. package/dist/battle/Whiteboard.d.ts +0 -50
  517. package/dist/battle/Whiteboard.d.ts.map +0 -1
  518. package/dist/battle/Whiteboard.js +0 -94
  519. package/dist/battle/Whiteboard.js.map +0 -1
  520. package/dist/battle/index.d.ts +0 -26
  521. package/dist/battle/index.d.ts.map +0 -1
  522. package/dist/battle/index.js +0 -15
  523. package/dist/battle/index.js.map +0 -1
  524. package/dist/board/Army.d.ts +0 -92
  525. package/dist/board/Army.d.ts.map +0 -1
  526. package/dist/board/Army.js +0 -123
  527. package/dist/board/Army.js.map +0 -1
  528. package/dist/board/Classics.d.ts +0 -419
  529. package/dist/board/Classics.d.ts.map +0 -1
  530. package/dist/board/Classics.js +0 -754
  531. package/dist/board/Classics.js.map +0 -1
  532. package/dist/board/Engine.d.ts +0 -95
  533. package/dist/board/Engine.d.ts.map +0 -1
  534. package/dist/board/Engine.js +0 -545
  535. package/dist/board/Engine.js.map +0 -1
  536. package/dist/board/FogOfWar.d.ts +0 -79
  537. package/dist/board/FogOfWar.d.ts.map +0 -1
  538. package/dist/board/FogOfWar.js +0 -150
  539. package/dist/board/FogOfWar.js.map +0 -1
  540. package/dist/board/HexSkirmish.d.ts +0 -213
  541. package/dist/board/HexSkirmish.d.ts.map +0 -1
  542. package/dist/board/HexSkirmish.js +0 -268
  543. package/dist/board/HexSkirmish.js.map +0 -1
  544. package/dist/board/Tactics.d.ts +0 -212
  545. package/dist/board/Tactics.d.ts.map +0 -1
  546. package/dist/board/Tactics.js +0 -303
  547. package/dist/board/Tactics.js.map +0 -1
  548. package/dist/board/bitboard.d.ts +0 -132
  549. package/dist/board/bitboard.d.ts.map +0 -1
  550. package/dist/board/bitboard.js +0 -495
  551. package/dist/board/bitboard.js.map +0 -1
  552. package/dist/board/chess.d.ts +0 -167
  553. package/dist/board/chess.d.ts.map +0 -1
  554. package/dist/board/chess.js +0 -578
  555. package/dist/board/chess.js.map +0 -1
  556. package/dist/board/index.d.ts +0 -23
  557. package/dist/board/index.d.ts.map +0 -1
  558. package/dist/board/index.js +0 -12
  559. package/dist/board/index.js.map +0 -1
  560. package/dist/board/openings.d.ts +0 -58
  561. package/dist/board/openings.d.ts.map +0 -1
  562. package/dist/board/openings.js +0 -45
  563. package/dist/board/openings.js.map +0 -1
  564. package/dist/board/tablebase.d.ts +0 -118
  565. package/dist/board/tablebase.d.ts.map +0 -1
  566. package/dist/board/tablebase.js +0 -414
  567. package/dist/board/tablebase.js.map +0 -1
  568. package/dist/board/tourney.d.ts +0 -97
  569. package/dist/board/tourney.d.ts.map +0 -1
  570. package/dist/board/tourney.js +0 -1002
  571. package/dist/board/tourney.js.map +0 -1
  572. package/dist/core/Achievements.d.ts +0 -101
  573. package/dist/core/Achievements.d.ts.map +0 -1
  574. package/dist/core/Achievements.js +0 -141
  575. package/dist/core/Achievements.js.map +0 -1
  576. package/dist/core/ActionJournal.d.ts +0 -43
  577. package/dist/core/ActionJournal.d.ts.map +0 -1
  578. package/dist/core/ActionJournal.js +0 -77
  579. package/dist/core/ActionJournal.js.map +0 -1
  580. package/dist/core/Blob.d.ts +0 -79
  581. package/dist/core/Blob.d.ts.map +0 -1
  582. package/dist/core/Blob.js +0 -140
  583. package/dist/core/Blob.js.map +0 -1
  584. package/dist/core/Clone.d.ts +0 -31
  585. package/dist/core/Clone.d.ts.map +0 -1
  586. package/dist/core/Clone.js +0 -84
  587. package/dist/core/Clone.js.map +0 -1
  588. package/dist/core/Collection.d.ts +0 -59
  589. package/dist/core/Collection.d.ts.map +0 -1
  590. package/dist/core/Collection.js +0 -77
  591. package/dist/core/Collection.js.map +0 -1
  592. package/dist/core/Csv.d.ts +0 -74
  593. package/dist/core/Csv.d.ts.map +0 -1
  594. package/dist/core/Csv.js +0 -201
  595. package/dist/core/Csv.js.map +0 -1
  596. package/dist/core/DialogueText.d.ts +0 -72
  597. package/dist/core/DialogueText.d.ts.map +0 -1
  598. package/dist/core/DialogueText.js +0 -68
  599. package/dist/core/DialogueText.js.map +0 -1
  600. package/dist/core/Entity.d.ts +0 -42
  601. package/dist/core/Entity.d.ts.map +0 -1
  602. package/dist/core/Entity.js +0 -61
  603. package/dist/core/Entity.js.map +0 -1
  604. package/dist/core/Feedback.d.ts +0 -27
  605. package/dist/core/Feedback.d.ts.map +0 -1
  606. package/dist/core/Feedback.js +0 -33
  607. package/dist/core/Feedback.js.map +0 -1
  608. package/dist/core/FixedStepper.d.ts +0 -38
  609. package/dist/core/FixedStepper.d.ts.map +0 -1
  610. package/dist/core/FixedStepper.js +0 -56
  611. package/dist/core/FixedStepper.js.map +0 -1
  612. package/dist/core/Grid.d.ts +0 -179
  613. package/dist/core/Grid.d.ts.map +0 -1
  614. package/dist/core/Grid.js +0 -201
  615. package/dist/core/Grid.js.map +0 -1
  616. package/dist/core/Handles.d.ts +0 -42
  617. package/dist/core/Handles.d.ts.map +0 -1
  618. package/dist/core/Handles.js +0 -38
  619. package/dist/core/Handles.js.map +0 -1
  620. package/dist/core/Hex.d.ts +0 -79
  621. package/dist/core/Hex.d.ts.map +0 -1
  622. package/dist/core/Hex.js +0 -161
  623. package/dist/core/Hex.js.map +0 -1
  624. package/dist/core/Hooks.d.ts +0 -48
  625. package/dist/core/Hooks.d.ts.map +0 -1
  626. package/dist/core/Hooks.js +0 -33
  627. package/dist/core/Hooks.js.map +0 -1
  628. package/dist/core/HttpTransport.d.ts +0 -53
  629. package/dist/core/HttpTransport.d.ts.map +0 -1
  630. package/dist/core/HttpTransport.js +0 -108
  631. package/dist/core/HttpTransport.js.map +0 -1
  632. package/dist/core/Input.d.ts +0 -256
  633. package/dist/core/Input.d.ts.map +0 -1
  634. package/dist/core/Input.js +0 -557
  635. package/dist/core/Input.js.map +0 -1
  636. package/dist/core/JavaRandom.d.ts +0 -55
  637. package/dist/core/JavaRandom.d.ts.map +0 -1
  638. package/dist/core/JavaRandom.js +0 -81
  639. package/dist/core/JavaRandom.js.map +0 -1
  640. package/dist/core/Loading.d.ts +0 -65
  641. package/dist/core/Loading.d.ts.map +0 -1
  642. package/dist/core/Loading.js +0 -119
  643. package/dist/core/Loading.js.map +0 -1
  644. package/dist/core/Log.d.ts +0 -48
  645. package/dist/core/Log.d.ts.map +0 -1
  646. package/dist/core/Log.js +0 -59
  647. package/dist/core/Log.js.map +0 -1
  648. package/dist/core/Math.d.ts +0 -14
  649. package/dist/core/Math.d.ts.map +0 -1
  650. package/dist/core/Math.js +0 -16
  651. package/dist/core/Math.js.map +0 -1
  652. package/dist/core/Motion.d.ts +0 -47
  653. package/dist/core/Motion.d.ts.map +0 -1
  654. package/dist/core/Motion.js +0 -122
  655. package/dist/core/Motion.js.map +0 -1
  656. package/dist/core/Multiplayer.d.ts +0 -101
  657. package/dist/core/Multiplayer.d.ts.map +0 -1
  658. package/dist/core/Multiplayer.js +0 -156
  659. package/dist/core/Multiplayer.js.map +0 -1
  660. package/dist/core/News.d.ts +0 -51
  661. package/dist/core/News.d.ts.map +0 -1
  662. package/dist/core/News.js +0 -65
  663. package/dist/core/News.js.map +0 -1
  664. package/dist/core/Pathfinding.d.ts +0 -41
  665. package/dist/core/Pathfinding.d.ts.map +0 -1
  666. package/dist/core/Pathfinding.js +0 -86
  667. package/dist/core/Pathfinding.js.map +0 -1
  668. package/dist/core/PlayerInput.d.ts +0 -57
  669. package/dist/core/PlayerInput.d.ts.map +0 -1
  670. package/dist/core/PlayerInput.js +0 -82
  671. package/dist/core/PlayerInput.js.map +0 -1
  672. package/dist/core/Presentation.d.ts +0 -56
  673. package/dist/core/Presentation.d.ts.map +0 -1
  674. package/dist/core/Presentation.js +0 -78
  675. package/dist/core/Presentation.js.map +0 -1
  676. package/dist/core/Random.d.ts +0 -259
  677. package/dist/core/Random.d.ts.map +0 -1
  678. package/dist/core/Random.js +0 -408
  679. package/dist/core/Random.js.map +0 -1
  680. package/dist/core/Reactions.d.ts +0 -67
  681. package/dist/core/Reactions.d.ts.map +0 -1
  682. package/dist/core/Reactions.js +0 -92
  683. package/dist/core/Reactions.js.map +0 -1
  684. package/dist/core/Registry.d.ts +0 -31
  685. package/dist/core/Registry.d.ts.map +0 -1
  686. package/dist/core/Registry.js +0 -46
  687. package/dist/core/Registry.js.map +0 -1
  688. package/dist/core/Replay.d.ts +0 -126
  689. package/dist/core/Replay.d.ts.map +0 -1
  690. package/dist/core/Replay.js +0 -162
  691. package/dist/core/Replay.js.map +0 -1
  692. package/dist/core/ReplayFile.d.ts +0 -197
  693. package/dist/core/ReplayFile.d.ts.map +0 -1
  694. package/dist/core/ReplayFile.js +0 -257
  695. package/dist/core/ReplayFile.js.map +0 -1
  696. package/dist/core/RunHistory.d.ts +0 -54
  697. package/dist/core/RunHistory.d.ts.map +0 -1
  698. package/dist/core/RunHistory.js +0 -40
  699. package/dist/core/RunHistory.js.map +0 -1
  700. package/dist/core/Sanitize.d.ts +0 -101
  701. package/dist/core/Sanitize.d.ts.map +0 -1
  702. package/dist/core/Sanitize.js +0 -162
  703. package/dist/core/Sanitize.js.map +0 -1
  704. package/dist/core/Save.d.ts +0 -123
  705. package/dist/core/Save.d.ts.map +0 -1
  706. package/dist/core/Save.js +0 -216
  707. package/dist/core/Save.js.map +0 -1
  708. package/dist/core/SaveSync.d.ts +0 -43
  709. package/dist/core/SaveSync.d.ts.map +0 -1
  710. package/dist/core/SaveSync.js +0 -56
  711. package/dist/core/SaveSync.js.map +0 -1
  712. package/dist/core/Scene.d.ts +0 -63
  713. package/dist/core/Scene.d.ts.map +0 -1
  714. package/dist/core/Scene.js +0 -81
  715. package/dist/core/Scene.js.map +0 -1
  716. package/dist/core/SceneComponents.d.ts +0 -67
  717. package/dist/core/SceneComponents.d.ts.map +0 -1
  718. package/dist/core/SceneComponents.js +0 -76
  719. package/dist/core/SceneComponents.js.map +0 -1
  720. package/dist/core/SceneStack.d.ts +0 -61
  721. package/dist/core/SceneStack.d.ts.map +0 -1
  722. package/dist/core/SceneStack.js +0 -91
  723. package/dist/core/SceneStack.js.map +0 -1
  724. package/dist/core/Scramble.d.ts +0 -21
  725. package/dist/core/Scramble.d.ts.map +0 -1
  726. package/dist/core/Scramble.js +0 -52
  727. package/dist/core/Scramble.js.map +0 -1
  728. package/dist/core/Session.d.ts +0 -31
  729. package/dist/core/Session.d.ts.map +0 -1
  730. package/dist/core/Session.js +0 -11
  731. package/dist/core/Session.js.map +0 -1
  732. package/dist/core/Settings.d.ts +0 -96
  733. package/dist/core/Settings.d.ts.map +0 -1
  734. package/dist/core/Settings.js +0 -190
  735. package/dist/core/Settings.js.map +0 -1
  736. package/dist/core/Signal.d.ts +0 -35
  737. package/dist/core/Signal.d.ts.map +0 -1
  738. package/dist/core/Signal.js +0 -41
  739. package/dist/core/Signal.js.map +0 -1
  740. package/dist/core/Spawner.d.ts +0 -65
  741. package/dist/core/Spawner.d.ts.map +0 -1
  742. package/dist/core/Spawner.js +0 -82
  743. package/dist/core/Spawner.js.map +0 -1
  744. package/dist/core/State.d.ts +0 -97
  745. package/dist/core/State.d.ts.map +0 -1
  746. package/dist/core/State.js +0 -177
  747. package/dist/core/State.js.map +0 -1
  748. package/dist/core/Stats.d.ts +0 -46
  749. package/dist/core/Stats.d.ts.map +0 -1
  750. package/dist/core/Stats.js +0 -47
  751. package/dist/core/Stats.js.map +0 -1
  752. package/dist/core/StoredValue.d.ts +0 -30
  753. package/dist/core/StoredValue.d.ts.map +0 -1
  754. package/dist/core/StoredValue.js +0 -38
  755. package/dist/core/StoredValue.js.map +0 -1
  756. package/dist/core/SyncGuard.d.ts +0 -57
  757. package/dist/core/SyncGuard.d.ts.map +0 -1
  758. package/dist/core/SyncGuard.js +0 -116
  759. package/dist/core/SyncGuard.js.map +0 -1
  760. package/dist/core/Telemetry.d.ts +0 -63
  761. package/dist/core/Telemetry.d.ts.map +0 -1
  762. package/dist/core/Telemetry.js +0 -83
  763. package/dist/core/Telemetry.js.map +0 -1
  764. package/dist/core/Twee.d.ts +0 -101
  765. package/dist/core/Twee.d.ts.map +0 -1
  766. package/dist/core/Twee.js +0 -174
  767. package/dist/core/Twee.js.map +0 -1
  768. package/dist/core/Tween.d.ts +0 -60
  769. package/dist/core/Tween.d.ts.map +0 -1
  770. package/dist/core/Tween.js +0 -98
  771. package/dist/core/Tween.js.map +0 -1
  772. package/dist/core/UndoHistory.d.ts +0 -52
  773. package/dist/core/UndoHistory.d.ts.map +0 -1
  774. package/dist/core/UndoHistory.js +0 -49
  775. package/dist/core/UndoHistory.js.map +0 -1
  776. package/dist/core/index.d.ts +0 -94
  777. package/dist/core/index.d.ts.map +0 -1
  778. package/dist/core/index.js +0 -53
  779. package/dist/core/index.js.map +0 -1
  780. package/dist/headless/index.d.ts +0 -87
  781. package/dist/headless/index.d.ts.map +0 -1
  782. package/dist/headless/index.js +0 -87
  783. package/dist/headless/index.js.map +0 -1
  784. package/dist/i18n/Content.d.ts +0 -151
  785. package/dist/i18n/Content.d.ts.map +0 -1
  786. package/dist/i18n/Content.js +0 -218
  787. package/dist/i18n/Content.js.map +0 -1
  788. package/dist/i18n/EditSession.d.ts +0 -101
  789. package/dist/i18n/EditSession.d.ts.map +0 -1
  790. package/dist/i18n/EditSession.js +0 -150
  791. package/dist/i18n/EditSession.js.map +0 -1
  792. package/dist/i18n/Fluent.d.ts +0 -7
  793. package/dist/i18n/Fluent.d.ts.map +0 -1
  794. package/dist/i18n/Fluent.js +0 -98
  795. package/dist/i18n/Fluent.js.map +0 -1
  796. package/dist/i18n/Format.d.ts +0 -25
  797. package/dist/i18n/Format.d.ts.map +0 -1
  798. package/dist/i18n/Format.js +0 -32
  799. package/dist/i18n/Format.js.map +0 -1
  800. package/dist/i18n/FormatSpec.d.ts +0 -76
  801. package/dist/i18n/FormatSpec.d.ts.map +0 -1
  802. package/dist/i18n/FormatSpec.js +0 -306
  803. package/dist/i18n/FormatSpec.js.map +0 -1
  804. package/dist/i18n/Po.d.ts +0 -54
  805. package/dist/i18n/Po.d.ts.map +0 -1
  806. package/dist/i18n/Po.js +0 -192
  807. package/dist/i18n/Po.js.map +0 -1
  808. package/dist/i18n/SemanticMessage.d.ts +0 -84
  809. package/dist/i18n/SemanticMessage.d.ts.map +0 -1
  810. package/dist/i18n/SemanticMessage.js +0 -54
  811. package/dist/i18n/SemanticMessage.js.map +0 -1
  812. package/dist/i18n/SoundMarkers.d.ts +0 -38
  813. package/dist/i18n/SoundMarkers.d.ts.map +0 -1
  814. package/dist/i18n/SoundMarkers.js +0 -48
  815. package/dist/i18n/SoundMarkers.js.map +0 -1
  816. package/dist/i18n/Validate.d.ts +0 -82
  817. package/dist/i18n/Validate.d.ts.map +0 -1
  818. package/dist/i18n/Validate.js +0 -106
  819. package/dist/i18n/Validate.js.map +0 -1
  820. package/dist/i18n/index.d.ts +0 -177
  821. package/dist/i18n/index.d.ts.map +0 -1
  822. package/dist/i18n/index.js +0 -331
  823. package/dist/i18n/index.js.map +0 -1
  824. package/dist/index.d.ts +0 -26
  825. package/dist/index.d.ts.map +0 -1
  826. package/dist/index.js +0 -26
  827. package/dist/index.js.map +0 -1
  828. package/dist/mw_games.global.js +0 -1410
  829. package/dist/mwl/MapFile.d.ts +0 -41
  830. package/dist/mwl/MapFile.d.ts.map +0 -1
  831. package/dist/mwl/MapFile.js +0 -53
  832. package/dist/mwl/MapFile.js.map +0 -1
  833. package/dist/mwl/actors.d.ts +0 -62
  834. package/dist/mwl/actors.d.ts.map +0 -1
  835. package/dist/mwl/actors.js +0 -82
  836. package/dist/mwl/actors.js.map +0 -1
  837. package/dist/mwl/campaign.d.ts +0 -51
  838. package/dist/mwl/campaign.d.ts.map +0 -1
  839. package/dist/mwl/campaign.js +0 -58
  840. package/dist/mwl/campaign.js.map +0 -1
  841. package/dist/mwl/carryover.d.ts +0 -86
  842. package/dist/mwl/carryover.d.ts.map +0 -1
  843. package/dist/mwl/carryover.js +0 -70
  844. package/dist/mwl/carryover.js.map +0 -1
  845. package/dist/mwl/catalog.d.ts +0 -98
  846. package/dist/mwl/catalog.d.ts.map +0 -1
  847. package/dist/mwl/catalog.js +0 -259
  848. package/dist/mwl/catalog.js.map +0 -1
  849. package/dist/mwl/compiler.d.ts +0 -135
  850. package/dist/mwl/compiler.d.ts.map +0 -1
  851. package/dist/mwl/compiler.js +0 -216
  852. package/dist/mwl/compiler.js.map +0 -1
  853. package/dist/mwl/conditions.d.ts +0 -30
  854. package/dist/mwl/conditions.d.ts.map +0 -1
  855. package/dist/mwl/conditions.js +0 -212
  856. package/dist/mwl/conditions.js.map +0 -1
  857. package/dist/mwl/content.d.ts +0 -140
  858. package/dist/mwl/content.d.ts.map +0 -1
  859. package/dist/mwl/content.js +0 -179
  860. package/dist/mwl/content.js.map +0 -1
  861. package/dist/mwl/expression.d.ts +0 -42
  862. package/dist/mwl/expression.d.ts.map +0 -1
  863. package/dist/mwl/expression.js +0 -164
  864. package/dist/mwl/expression.js.map +0 -1
  865. package/dist/mwl/grammar.d.ts +0 -100
  866. package/dist/mwl/grammar.d.ts.map +0 -1
  867. package/dist/mwl/grammar.js +0 -588
  868. package/dist/mwl/grammar.js.map +0 -1
  869. package/dist/mwl/hooks.d.ts +0 -201
  870. package/dist/mwl/hooks.d.ts.map +0 -1
  871. package/dist/mwl/hooks.js +0 -165
  872. package/dist/mwl/hooks.js.map +0 -1
  873. package/dist/mwl/index.d.ts +0 -51
  874. package/dist/mwl/index.d.ts.map +0 -1
  875. package/dist/mwl/index.js +0 -26
  876. package/dist/mwl/index.js.map +0 -1
  877. package/dist/mwl/objects.d.ts +0 -31
  878. package/dist/mwl/objects.d.ts.map +0 -1
  879. package/dist/mwl/objects.js +0 -83
  880. package/dist/mwl/objects.js.map +0 -1
  881. package/dist/mwl/package-container.d.ts +0 -185
  882. package/dist/mwl/package-container.d.ts.map +0 -1
  883. package/dist/mwl/package-container.js +0 -446
  884. package/dist/mwl/package-container.js.map +0 -1
  885. package/dist/mwl/package-document.d.ts +0 -217
  886. package/dist/mwl/package-document.d.ts.map +0 -1
  887. package/dist/mwl/package-document.js +0 -639
  888. package/dist/mwl/package-document.js.map +0 -1
  889. package/dist/mwl/package-rom.d.ts +0 -37
  890. package/dist/mwl/package-rom.d.ts.map +0 -1
  891. package/dist/mwl/package-rom.js +0 -96
  892. package/dist/mwl/package-rom.js.map +0 -1
  893. package/dist/mwl/package-verify.d.ts +0 -34
  894. package/dist/mwl/package-verify.d.ts.map +0 -1
  895. package/dist/mwl/package-verify.js +0 -111
  896. package/dist/mwl/package-verify.js.map +0 -1
  897. package/dist/mwl/package.d.ts +0 -184
  898. package/dist/mwl/package.d.ts.map +0 -1
  899. package/dist/mwl/package.js +0 -382
  900. package/dist/mwl/package.js.map +0 -1
  901. package/dist/mwl/persistence.d.ts +0 -67
  902. package/dist/mwl/persistence.d.ts.map +0 -1
  903. package/dist/mwl/persistence.js +0 -135
  904. package/dist/mwl/persistence.js.map +0 -1
  905. package/dist/mwl/presentation.d.ts +0 -86
  906. package/dist/mwl/presentation.d.ts.map +0 -1
  907. package/dist/mwl/presentation.js +0 -419
  908. package/dist/mwl/presentation.js.map +0 -1
  909. package/dist/mwl/pyroeis-runtime.d.ts +0 -82
  910. package/dist/mwl/pyroeis-runtime.d.ts.map +0 -1
  911. package/dist/mwl/pyroeis-runtime.js +0 -535
  912. package/dist/mwl/pyroeis-runtime.js.map +0 -1
  913. package/dist/mwl/pyroeis.d.ts +0 -54
  914. package/dist/mwl/pyroeis.d.ts.map +0 -1
  915. package/dist/mwl/pyroeis.js +0 -189
  916. package/dist/mwl/pyroeis.js.map +0 -1
  917. package/dist/mwl/readers.d.ts +0 -77
  918. package/dist/mwl/readers.d.ts.map +0 -1
  919. package/dist/mwl/readers.js +0 -150
  920. package/dist/mwl/readers.js.map +0 -1
  921. package/dist/mwl/report.d.ts +0 -44
  922. package/dist/mwl/report.d.ts.map +0 -1
  923. package/dist/mwl/report.js +0 -88
  924. package/dist/mwl/report.js.map +0 -1
  925. package/dist/mwl/runtime.d.ts +0 -577
  926. package/dist/mwl/runtime.d.ts.map +0 -1
  927. package/dist/mwl/runtime.js +0 -1741
  928. package/dist/mwl/runtime.js.map +0 -1
  929. package/dist/mwl/schema.d.ts +0 -151
  930. package/dist/mwl/schema.d.ts.map +0 -1
  931. package/dist/mwl/schema.js +0 -979
  932. package/dist/mwl/schema.js.map +0 -1
  933. package/dist/mwl/scripts.d.ts +0 -26
  934. package/dist/mwl/scripts.d.ts.map +0 -1
  935. package/dist/mwl/scripts.js +0 -34
  936. package/dist/mwl/scripts.js.map +0 -1
  937. package/dist/mwl/tables.d.ts +0 -95
  938. package/dist/mwl/tables.d.ts.map +0 -1
  939. package/dist/mwl/tables.js +0 -100
  940. package/dist/mwl/tables.js.map +0 -1
  941. package/dist/mwl/utils.d.ts +0 -10
  942. package/dist/mwl/utils.d.ts.map +0 -1
  943. package/dist/mwl/utils.js +0 -40
  944. package/dist/mwl/utils.js.map +0 -1
  945. package/dist/physics/PhysicsWorld.d.ts +0 -158
  946. package/dist/physics/PhysicsWorld.d.ts.map +0 -1
  947. package/dist/physics/PhysicsWorld.js +0 -376
  948. package/dist/physics/PhysicsWorld.js.map +0 -1
  949. package/dist/physics/XpbdWorld.d.ts +0 -213
  950. package/dist/physics/XpbdWorld.d.ts.map +0 -1
  951. package/dist/physics/XpbdWorld.js +0 -337
  952. package/dist/physics/XpbdWorld.js.map +0 -1
  953. package/dist/physics/cloth/index.d.ts +0 -99
  954. package/dist/physics/cloth/index.d.ts.map +0 -1
  955. package/dist/physics/cloth/index.js +0 -226
  956. package/dist/physics/cloth/index.js.map +0 -1
  957. package/dist/physics/index.d.ts +0 -7
  958. package/dist/physics/index.d.ts.map +0 -1
  959. package/dist/physics/index.js +0 -4
  960. package/dist/physics/index.js.map +0 -1
  961. package/dist/physics/spring/index.d.ts +0 -91
  962. package/dist/physics/spring/index.d.ts.map +0 -1
  963. package/dist/physics/spring/index.js +0 -120
  964. package/dist/physics/spring/index.js.map +0 -1
  965. package/dist/physics/xpbd.d.ts +0 -3
  966. package/dist/physics/xpbd.d.ts.map +0 -1
  967. package/dist/physics/xpbd.js +0 -2
  968. package/dist/physics/xpbd.js.map +0 -1
  969. package/dist/roguelike/Boss.d.ts +0 -79
  970. package/dist/roguelike/Boss.d.ts.map +0 -1
  971. package/dist/roguelike/Boss.js +0 -126
  972. package/dist/roguelike/Boss.js.map +0 -1
  973. package/dist/roguelike/Cave.d.ts +0 -124
  974. package/dist/roguelike/Cave.d.ts.map +0 -1
  975. package/dist/roguelike/Cave.js +0 -216
  976. package/dist/roguelike/Cave.js.map +0 -1
  977. package/dist/roguelike/Combat.d.ts +0 -35
  978. package/dist/roguelike/Combat.d.ts.map +0 -1
  979. package/dist/roguelike/Combat.js +0 -33
  980. package/dist/roguelike/Combat.js.map +0 -1
  981. package/dist/roguelike/ContentRoll.d.ts +0 -53
  982. package/dist/roguelike/ContentRoll.d.ts.map +0 -1
  983. package/dist/roguelike/ContentRoll.js +0 -48
  984. package/dist/roguelike/ContentRoll.js.map +0 -1
  985. package/dist/roguelike/Doors.d.ts +0 -73
  986. package/dist/roguelike/Doors.d.ts.map +0 -1
  987. package/dist/roguelike/Doors.js +0 -115
  988. package/dist/roguelike/Doors.js.map +0 -1
  989. package/dist/roguelike/DungeonParity.d.ts +0 -57
  990. package/dist/roguelike/DungeonParity.d.ts.map +0 -1
  991. package/dist/roguelike/DungeonParity.js +0 -87
  992. package/dist/roguelike/DungeonParity.js.map +0 -1
  993. package/dist/roguelike/Elevation.d.ts +0 -41
  994. package/dist/roguelike/Elevation.d.ts.map +0 -1
  995. package/dist/roguelike/Elevation.js +0 -52
  996. package/dist/roguelike/Elevation.js.map +0 -1
  997. package/dist/roguelike/Features.d.ts +0 -59
  998. package/dist/roguelike/Features.d.ts.map +0 -1
  999. package/dist/roguelike/Features.js +0 -76
  1000. package/dist/roguelike/Features.js.map +0 -1
  1001. package/dist/roguelike/FieldOfView.d.ts +0 -86
  1002. package/dist/roguelike/FieldOfView.d.ts.map +0 -1
  1003. package/dist/roguelike/FieldOfView.js +0 -148
  1004. package/dist/roguelike/FieldOfView.js.map +0 -1
  1005. package/dist/roguelike/Level.d.ts +0 -139
  1006. package/dist/roguelike/Level.d.ts.map +0 -1
  1007. package/dist/roguelike/Level.js +0 -189
  1008. package/dist/roguelike/Level.js.map +0 -1
  1009. package/dist/roguelike/MonsterAI.d.ts +0 -54
  1010. package/dist/roguelike/MonsterAI.d.ts.map +0 -1
  1011. package/dist/roguelike/MonsterAI.js +0 -83
  1012. package/dist/roguelike/MonsterAI.js.map +0 -1
  1013. package/dist/roguelike/MultiStageAbility.d.ts +0 -59
  1014. package/dist/roguelike/MultiStageAbility.d.ts.map +0 -1
  1015. package/dist/roguelike/MultiStageAbility.js +0 -76
  1016. package/dist/roguelike/MultiStageAbility.js.map +0 -1
  1017. package/dist/roguelike/MultiTurnBeam.d.ts +0 -108
  1018. package/dist/roguelike/MultiTurnBeam.d.ts.map +0 -1
  1019. package/dist/roguelike/MultiTurnBeam.js +0 -164
  1020. package/dist/roguelike/MultiTurnBeam.js.map +0 -1
  1021. package/dist/roguelike/Overworld.d.ts +0 -89
  1022. package/dist/roguelike/Overworld.d.ts.map +0 -1
  1023. package/dist/roguelike/Overworld.js +0 -325
  1024. package/dist/roguelike/Overworld.js.map +0 -1
  1025. package/dist/roguelike/Pathfinder.d.ts +0 -103
  1026. package/dist/roguelike/Pathfinder.d.ts.map +0 -1
  1027. package/dist/roguelike/Pathfinder.js +0 -213
  1028. package/dist/roguelike/Pathfinder.js.map +0 -1
  1029. package/dist/roguelike/Placement.d.ts +0 -62
  1030. package/dist/roguelike/Placement.d.ts.map +0 -1
  1031. package/dist/roguelike/Placement.js +0 -79
  1032. package/dist/roguelike/Placement.js.map +0 -1
  1033. package/dist/roguelike/RoomBuilders.d.ts +0 -60
  1034. package/dist/roguelike/RoomBuilders.d.ts.map +0 -1
  1035. package/dist/roguelike/RoomBuilders.js +0 -57
  1036. package/dist/roguelike/RoomBuilders.js.map +0 -1
  1037. package/dist/roguelike/Scheduler.d.ts +0 -96
  1038. package/dist/roguelike/Scheduler.d.ts.map +0 -1
  1039. package/dist/roguelike/Scheduler.js +0 -154
  1040. package/dist/roguelike/Scheduler.js.map +0 -1
  1041. package/dist/roguelike/Secrets.d.ts +0 -57
  1042. package/dist/roguelike/Secrets.d.ts.map +0 -1
  1043. package/dist/roguelike/Secrets.js +0 -77
  1044. package/dist/roguelike/Secrets.js.map +0 -1
  1045. package/dist/roguelike/Stealth.d.ts +0 -47
  1046. package/dist/roguelike/Stealth.d.ts.map +0 -1
  1047. package/dist/roguelike/Stealth.js +0 -48
  1048. package/dist/roguelike/Stealth.js.map +0 -1
  1049. package/dist/roguelike/Targeting.d.ts +0 -312
  1050. package/dist/roguelike/Targeting.d.ts.map +0 -1
  1051. package/dist/roguelike/Targeting.js +0 -483
  1052. package/dist/roguelike/Targeting.js.map +0 -1
  1053. package/dist/roguelike/TriggerTracker.d.ts +0 -46
  1054. package/dist/roguelike/TriggerTracker.d.ts.map +0 -1
  1055. package/dist/roguelike/TriggerTracker.js +0 -59
  1056. package/dist/roguelike/TriggerTracker.js.map +0 -1
  1057. package/dist/roguelike/generate.d.ts +0 -139
  1058. package/dist/roguelike/generate.d.ts.map +0 -1
  1059. package/dist/roguelike/generate.js +0 -166
  1060. package/dist/roguelike/generate.js.map +0 -1
  1061. package/dist/roguelike/index.d.ts +0 -48
  1062. package/dist/roguelike/index.d.ts.map +0 -1
  1063. package/dist/roguelike/index.js +0 -27
  1064. package/dist/roguelike/index.js.map +0 -1
  1065. package/dist/rpg/Collision.d.ts +0 -61
  1066. package/dist/rpg/Collision.d.ts.map +0 -1
  1067. package/dist/rpg/Collision.js +0 -94
  1068. package/dist/rpg/Collision.js.map +0 -1
  1069. package/dist/rpg/Event.d.ts +0 -50
  1070. package/dist/rpg/Event.d.ts.map +0 -1
  1071. package/dist/rpg/Event.js +0 -36
  1072. package/dist/rpg/Event.js.map +0 -1
  1073. package/dist/rpg/EventRunner.d.ts +0 -139
  1074. package/dist/rpg/EventRunner.d.ts.map +0 -1
  1075. package/dist/rpg/EventRunner.js +0 -125
  1076. package/dist/rpg/EventRunner.js.map +0 -1
  1077. package/dist/rpg/FreeMover.d.ts +0 -59
  1078. package/dist/rpg/FreeMover.d.ts.map +0 -1
  1079. package/dist/rpg/FreeMover.js +0 -79
  1080. package/dist/rpg/FreeMover.js.map +0 -1
  1081. package/dist/rpg/GameState.d.ts +0 -36
  1082. package/dist/rpg/GameState.d.ts.map +0 -1
  1083. package/dist/rpg/GameState.js +0 -49
  1084. package/dist/rpg/GameState.js.map +0 -1
  1085. package/dist/rpg/GridMover.d.ts +0 -71
  1086. package/dist/rpg/GridMover.d.ts.map +0 -1
  1087. package/dist/rpg/GridMover.js +0 -119
  1088. package/dist/rpg/GridMover.js.map +0 -1
  1089. package/dist/rpg/Marshal.d.ts +0 -81
  1090. package/dist/rpg/Marshal.d.ts.map +0 -1
  1091. package/dist/rpg/Marshal.js +0 -422
  1092. package/dist/rpg/Marshal.js.map +0 -1
  1093. package/dist/rpg/MovableSprite.d.ts +0 -31
  1094. package/dist/rpg/MovableSprite.d.ts.map +0 -1
  1095. package/dist/rpg/MovableSprite.js +0 -10
  1096. package/dist/rpg/MovableSprite.js.map +0 -1
  1097. package/dist/rpg/MoveRoute.d.ts +0 -118
  1098. package/dist/rpg/MoveRoute.d.ts.map +0 -1
  1099. package/dist/rpg/MoveRoute.js +0 -139
  1100. package/dist/rpg/MoveRoute.js.map +0 -1
  1101. package/dist/rpg/Quest.d.ts +0 -173
  1102. package/dist/rpg/Quest.d.ts.map +0 -1
  1103. package/dist/rpg/Quest.js +0 -221
  1104. package/dist/rpg/Quest.js.map +0 -1
  1105. package/dist/rpg/automap.d.ts +0 -81
  1106. package/dist/rpg/automap.d.ts.map +0 -1
  1107. package/dist/rpg/automap.js +0 -107
  1108. package/dist/rpg/automap.js.map +0 -1
  1109. package/dist/rpg/dialogue-text.d.ts +0 -81
  1110. package/dist/rpg/dialogue-text.d.ts.map +0 -1
  1111. package/dist/rpg/dialogue-text.js +0 -88
  1112. package/dist/rpg/dialogue-text.js.map +0 -1
  1113. package/dist/rpg/index.d.ts +0 -25
  1114. package/dist/rpg/index.d.ts.map +0 -1
  1115. package/dist/rpg/index.js +0 -14
  1116. package/dist/rpg/index.js.map +0 -1
  1117. package/dist/rpg/twee-events.d.ts +0 -48
  1118. package/dist/rpg/twee-events.d.ts.map +0 -1
  1119. package/dist/rpg/twee-events.js +0 -35
  1120. package/dist/rpg/twee-events.js.map +0 -1
  1121. package/dist/simulation/Campaign.d.ts +0 -60
  1122. package/dist/simulation/Campaign.d.ts.map +0 -1
  1123. package/dist/simulation/Campaign.js +0 -89
  1124. package/dist/simulation/Campaign.js.map +0 -1
  1125. package/dist/simulation/CampaignSave.d.ts +0 -68
  1126. package/dist/simulation/CampaignSave.d.ts.map +0 -1
  1127. package/dist/simulation/CampaignSave.js +0 -54
  1128. package/dist/simulation/CampaignSave.js.map +0 -1
  1129. package/dist/simulation/EventPresentation.d.ts +0 -111
  1130. package/dist/simulation/EventPresentation.d.ts.map +0 -1
  1131. package/dist/simulation/EventPresentation.js +0 -120
  1132. package/dist/simulation/EventPresentation.js.map +0 -1
  1133. package/dist/simulation/Harness.d.ts +0 -26
  1134. package/dist/simulation/Harness.d.ts.map +0 -1
  1135. package/dist/simulation/Harness.js +0 -26
  1136. package/dist/simulation/Harness.js.map +0 -1
  1137. package/dist/simulation/Runtime.d.ts +0 -189
  1138. package/dist/simulation/Runtime.d.ts.map +0 -1
  1139. package/dist/simulation/Runtime.js +0 -244
  1140. package/dist/simulation/Runtime.js.map +0 -1
  1141. package/dist/simulation/Scenario.d.ts +0 -44
  1142. package/dist/simulation/Scenario.d.ts.map +0 -1
  1143. package/dist/simulation/Scenario.js +0 -40
  1144. package/dist/simulation/Scenario.js.map +0 -1
  1145. package/dist/simulation/Training.d.ts +0 -220
  1146. package/dist/simulation/Training.d.ts.map +0 -1
  1147. package/dist/simulation/Training.js +0 -366
  1148. package/dist/simulation/Training.js.map +0 -1
  1149. package/dist/simulation/Turns.d.ts +0 -40
  1150. package/dist/simulation/Turns.d.ts.map +0 -1
  1151. package/dist/simulation/Turns.js +0 -41
  1152. package/dist/simulation/Turns.js.map +0 -1
  1153. package/dist/simulation/index.d.ts +0 -25
  1154. package/dist/simulation/index.d.ts.map +0 -1
  1155. package/dist/simulation/index.js +0 -16
  1156. package/dist/simulation/index.js.map +0 -1
  1157. package/dist/skeleton/index.d.ts +0 -212
  1158. package/dist/skeleton/index.d.ts.map +0 -1
  1159. package/dist/skeleton/index.js +0 -325
  1160. package/dist/skeleton/index.js.map +0 -1
  1161. package/dist/testing/FakeAudio.d.ts +0 -149
  1162. package/dist/testing/FakeAudio.d.ts.map +0 -1
  1163. package/dist/testing/FakeAudio.js +0 -219
  1164. package/dist/testing/FakeAudio.js.map +0 -1
  1165. package/dist/testing/SceneControls.d.ts +0 -35
  1166. package/dist/testing/SceneControls.d.ts.map +0 -1
  1167. package/dist/testing/SceneControls.js +0 -49
  1168. package/dist/testing/SceneControls.js.map +0 -1
  1169. package/dist/testing/index.d.ts +0 -125
  1170. package/dist/testing/index.d.ts.map +0 -1
  1171. package/dist/testing/index.js +0 -157
  1172. package/dist/testing/index.js.map +0 -1
  1173. package/dist/threads/index.d.ts +0 -3
  1174. package/dist/threads/index.d.ts.map +0 -1
  1175. package/dist/threads/index.js +0 -2
  1176. package/dist/threads/index.js.map +0 -1
  1177. package/dist/threads/spawn.d.ts +0 -73
  1178. package/dist/threads/spawn.d.ts.map +0 -1
  1179. package/dist/threads/spawn.js +0 -167
  1180. package/dist/threads/spawn.js.map +0 -1
  1181. package/dist/threads/worker.d.ts +0 -51
  1182. package/dist/threads/worker.d.ts.map +0 -1
  1183. package/dist/threads/worker.js +0 -84
  1184. package/dist/threads/worker.js.map +0 -1
  1185. package/dist/three-d/Character3D.d.ts +0 -74
  1186. package/dist/three-d/Character3D.d.ts.map +0 -1
  1187. package/dist/three-d/Character3D.js +0 -122
  1188. package/dist/three-d/Character3D.js.map +0 -1
  1189. package/dist/three-d/Collision3D.d.ts +0 -111
  1190. package/dist/three-d/Collision3D.d.ts.map +0 -1
  1191. package/dist/three-d/Collision3D.js +0 -119
  1192. package/dist/three-d/Collision3D.js.map +0 -1
  1193. package/dist/three-d/Engine3D.d.ts +0 -25
  1194. package/dist/three-d/Engine3D.d.ts.map +0 -1
  1195. package/dist/three-d/Engine3D.js +0 -45
  1196. package/dist/three-d/Engine3D.js.map +0 -1
  1197. package/dist/three-d/Grid.d.ts +0 -30
  1198. package/dist/three-d/Grid.d.ts.map +0 -1
  1199. package/dist/three-d/Grid.js +0 -24
  1200. package/dist/three-d/Grid.js.map +0 -1
  1201. package/dist/three-d/Heightmap.d.ts +0 -38
  1202. package/dist/three-d/Heightmap.d.ts.map +0 -1
  1203. package/dist/three-d/Heightmap.js +0 -29
  1204. package/dist/three-d/Heightmap.js.map +0 -1
  1205. package/dist/three-d/Models.d.ts +0 -49
  1206. package/dist/three-d/Models.d.ts.map +0 -1
  1207. package/dist/three-d/Models.js +0 -77
  1208. package/dist/three-d/Models.js.map +0 -1
  1209. package/dist/three-d/TileGrid3D.d.ts +0 -27
  1210. package/dist/three-d/TileGrid3D.d.ts.map +0 -1
  1211. package/dist/three-d/TileGrid3D.js +0 -66
  1212. package/dist/three-d/TileGrid3D.js.map +0 -1
  1213. package/dist/three-d/Vox.d.ts +0 -43
  1214. package/dist/three-d/Vox.d.ts.map +0 -1
  1215. package/dist/three-d/Vox.js +0 -108
  1216. package/dist/three-d/Vox.js.map +0 -1
  1217. package/dist/three-d/index.d.ts +0 -15
  1218. package/dist/three-d/index.d.ts.map +0 -1
  1219. package/dist/three-d/index.js +0 -8
  1220. package/dist/three-d/index.js.map +0 -1
  1221. package/dist/two-d/Game.d.ts +0 -240
  1222. package/dist/two-d/Game.d.ts.map +0 -1
  1223. package/dist/two-d/Game.js +0 -487
  1224. package/dist/two-d/Game.js.map +0 -1
  1225. package/dist/two-d/QualityScaler.d.ts +0 -63
  1226. package/dist/two-d/QualityScaler.d.ts.map +0 -1
  1227. package/dist/two-d/QualityScaler.js +0 -92
  1228. package/dist/two-d/QualityScaler.js.map +0 -1
  1229. package/dist/two-d/ResolutionFit.d.ts +0 -28
  1230. package/dist/two-d/ResolutionFit.d.ts.map +0 -1
  1231. package/dist/two-d/ResolutionFit.js +0 -39
  1232. package/dist/two-d/ResolutionFit.js.map +0 -1
  1233. package/dist/two-d/Scene2D.d.ts +0 -43
  1234. package/dist/two-d/Scene2D.d.ts.map +0 -1
  1235. package/dist/two-d/Scene2D.js +0 -53
  1236. package/dist/two-d/Scene2D.js.map +0 -1
  1237. package/dist/two-d/index.d.ts +0 -22
  1238. package/dist/two-d/index.d.ts.map +0 -1
  1239. package/dist/two-d/index.js +0 -19
  1240. package/dist/two-d/index.js.map +0 -1
  1241. package/dist/two-d/pixi-interop.d.ts +0 -66
  1242. package/dist/two-d/pixi-interop.d.ts.map +0 -1
  1243. package/dist/two-d/pixi-interop.js +0 -72
  1244. package/dist/two-d/pixi-interop.js.map +0 -1
  1245. package/dist/two-d/presentation/MwlPresentation.d.ts +0 -117
  1246. package/dist/two-d/presentation/MwlPresentation.d.ts.map +0 -1
  1247. package/dist/two-d/presentation/MwlPresentation.js +0 -755
  1248. package/dist/two-d/presentation/MwlPresentation.js.map +0 -1
  1249. package/dist/two-d/presentation/index.d.ts +0 -3
  1250. package/dist/two-d/presentation/index.d.ts.map +0 -1
  1251. package/dist/two-d/presentation/index.js +0 -2
  1252. package/dist/two-d/presentation/index.js.map +0 -1
  1253. package/dist/two-d/render/ActorAnimator.d.ts +0 -92
  1254. package/dist/two-d/render/ActorAnimator.d.ts.map +0 -1
  1255. package/dist/two-d/render/ActorAnimator.js +0 -97
  1256. package/dist/two-d/render/ActorAnimator.js.map +0 -1
  1257. package/dist/two-d/render/AnimatedSprite.d.ts +0 -154
  1258. package/dist/two-d/render/AnimatedSprite.d.ts.map +0 -1
  1259. package/dist/two-d/render/AnimatedSprite.js +0 -197
  1260. package/dist/two-d/render/AnimatedSprite.js.map +0 -1
  1261. package/dist/two-d/render/Autotile.d.ts +0 -74
  1262. package/dist/two-d/render/Autotile.d.ts.map +0 -1
  1263. package/dist/two-d/render/Autotile.js +0 -149
  1264. package/dist/two-d/render/Autotile.js.map +0 -1
  1265. package/dist/two-d/render/Beam.d.ts +0 -136
  1266. package/dist/two-d/render/Beam.d.ts.map +0 -1
  1267. package/dist/two-d/render/Beam.js +0 -203
  1268. package/dist/two-d/render/Beam.js.map +0 -1
  1269. package/dist/two-d/render/Camera.d.ts +0 -255
  1270. package/dist/two-d/render/Camera.d.ts.map +0 -1
  1271. package/dist/two-d/render/Camera.js +0 -376
  1272. package/dist/two-d/render/Camera.js.map +0 -1
  1273. package/dist/two-d/render/Capabilities.d.ts +0 -84
  1274. package/dist/two-d/render/Capabilities.d.ts.map +0 -1
  1275. package/dist/two-d/render/Capabilities.js +0 -129
  1276. package/dist/two-d/render/Capabilities.js.map +0 -1
  1277. package/dist/two-d/render/ClothSprite.d.ts +0 -83
  1278. package/dist/two-d/render/ClothSprite.d.ts.map +0 -1
  1279. package/dist/two-d/render/ClothSprite.js +0 -105
  1280. package/dist/two-d/render/ClothSprite.js.map +0 -1
  1281. package/dist/two-d/render/ColorBlindness.d.ts +0 -39
  1282. package/dist/two-d/render/ColorBlindness.d.ts.map +0 -1
  1283. package/dist/two-d/render/ColorBlindness.js +0 -45
  1284. package/dist/two-d/render/ColorBlindness.js.map +0 -1
  1285. package/dist/two-d/render/ColorTransformBatcher.d.ts +0 -143
  1286. package/dist/two-d/render/ColorTransformBatcher.d.ts.map +0 -1
  1287. package/dist/two-d/render/ColorTransformBatcher.js +0 -395
  1288. package/dist/two-d/render/ColorTransformBatcher.js.map +0 -1
  1289. package/dist/two-d/render/Flights.d.ts +0 -90
  1290. package/dist/two-d/render/Flights.d.ts.map +0 -1
  1291. package/dist/two-d/render/Flights.js +0 -135
  1292. package/dist/two-d/render/Flights.js.map +0 -1
  1293. package/dist/two-d/render/FogLayer.d.ts +0 -68
  1294. package/dist/two-d/render/FogLayer.d.ts.map +0 -1
  1295. package/dist/two-d/render/FogLayer.js +0 -83
  1296. package/dist/two-d/render/FogLayer.js.map +0 -1
  1297. package/dist/two-d/render/Halo.d.ts +0 -58
  1298. package/dist/two-d/render/Halo.d.ts.map +0 -1
  1299. package/dist/two-d/render/Halo.js +0 -48
  1300. package/dist/two-d/render/Halo.js.map +0 -1
  1301. package/dist/two-d/render/HazeLayer.d.ts +0 -112
  1302. package/dist/two-d/render/HazeLayer.d.ts.map +0 -1
  1303. package/dist/two-d/render/HazeLayer.js +0 -186
  1304. package/dist/two-d/render/HazeLayer.js.map +0 -1
  1305. package/dist/two-d/render/ImageModifiers.d.ts +0 -312
  1306. package/dist/two-d/render/ImageModifiers.d.ts.map +0 -1
  1307. package/dist/two-d/render/ImageModifiers.js +0 -728
  1308. package/dist/two-d/render/ImageModifiers.js.map +0 -1
  1309. package/dist/two-d/render/LayeredSprite.d.ts +0 -54
  1310. package/dist/two-d/render/LayeredSprite.d.ts.map +0 -1
  1311. package/dist/two-d/render/LayeredSprite.js +0 -80
  1312. package/dist/two-d/render/LayeredSprite.js.map +0 -1
  1313. package/dist/two-d/render/LightningArc.d.ts +0 -57
  1314. package/dist/two-d/render/LightningArc.d.ts.map +0 -1
  1315. package/dist/two-d/render/LightningArc.js +0 -91
  1316. package/dist/two-d/render/LightningArc.js.map +0 -1
  1317. package/dist/two-d/render/LiquidLayer.d.ts +0 -62
  1318. package/dist/two-d/render/LiquidLayer.d.ts.map +0 -1
  1319. package/dist/two-d/render/LiquidLayer.js +0 -102
  1320. package/dist/two-d/render/LiquidLayer.js.map +0 -1
  1321. package/dist/two-d/render/Minimap.d.ts +0 -100
  1322. package/dist/two-d/render/Minimap.d.ts.map +0 -1
  1323. package/dist/two-d/render/Minimap.js +0 -157
  1324. package/dist/two-d/render/Minimap.js.map +0 -1
  1325. package/dist/two-d/render/NeonGlow.d.ts +0 -100
  1326. package/dist/two-d/render/NeonGlow.d.ts.map +0 -1
  1327. package/dist/two-d/render/NeonGlow.js +0 -184
  1328. package/dist/two-d/render/NeonGlow.js.map +0 -1
  1329. package/dist/two-d/render/PaletteRemap.d.ts +0 -154
  1330. package/dist/two-d/render/PaletteRemap.d.ts.map +0 -1
  1331. package/dist/two-d/render/PaletteRemap.js +0 -217
  1332. package/dist/two-d/render/PaletteRemap.js.map +0 -1
  1333. package/dist/two-d/render/Particles.d.ts +0 -262
  1334. package/dist/two-d/render/Particles.d.ts.map +0 -1
  1335. package/dist/two-d/render/Particles.js +0 -371
  1336. package/dist/two-d/render/Particles.js.map +0 -1
  1337. package/dist/two-d/render/Projectile.d.ts +0 -67
  1338. package/dist/two-d/render/Projectile.d.ts.map +0 -1
  1339. package/dist/two-d/render/Projectile.js +0 -78
  1340. package/dist/two-d/render/Projectile.js.map +0 -1
  1341. package/dist/two-d/render/RpgmAutotile.d.ts +0 -324
  1342. package/dist/two-d/render/RpgmAutotile.d.ts.map +0 -1
  1343. package/dist/two-d/render/RpgmAutotile.js +0 -933
  1344. package/dist/two-d/render/RpgmAutotile.js.map +0 -1
  1345. package/dist/two-d/render/SceneTransition.d.ts +0 -301
  1346. package/dist/two-d/render/SceneTransition.d.ts.map +0 -1
  1347. package/dist/two-d/render/SceneTransition.js +0 -458
  1348. package/dist/two-d/render/SceneTransition.js.map +0 -1
  1349. package/dist/two-d/render/ScreenEffects.d.ts +0 -124
  1350. package/dist/two-d/render/ScreenEffects.d.ts.map +0 -1
  1351. package/dist/two-d/render/ScreenEffects.js +0 -215
  1352. package/dist/two-d/render/ScreenEffects.js.map +0 -1
  1353. package/dist/two-d/render/Shape2D.d.ts +0 -146
  1354. package/dist/two-d/render/Shape2D.d.ts.map +0 -1
  1355. package/dist/two-d/render/Shape2D.js +0 -166
  1356. package/dist/two-d/render/Shape2D.js.map +0 -1
  1357. package/dist/two-d/render/SkeletalSprite.d.ts +0 -121
  1358. package/dist/two-d/render/SkeletalSprite.d.ts.map +0 -1
  1359. package/dist/two-d/render/SkeletalSprite.js +0 -214
  1360. package/dist/two-d/render/SkeletalSprite.js.map +0 -1
  1361. package/dist/two-d/render/SpringSprite.d.ts +0 -40
  1362. package/dist/two-d/render/SpringSprite.d.ts.map +0 -1
  1363. package/dist/two-d/render/SpringSprite.js +0 -39
  1364. package/dist/two-d/render/SpringSprite.js.map +0 -1
  1365. package/dist/two-d/render/SpriteAttachment.d.ts +0 -55
  1366. package/dist/two-d/render/SpriteAttachment.d.ts.map +0 -1
  1367. package/dist/two-d/render/SpriteAttachment.js +0 -60
  1368. package/dist/two-d/render/SpriteAttachment.js.map +0 -1
  1369. package/dist/two-d/render/SpriteDeform.d.ts +0 -156
  1370. package/dist/two-d/render/SpriteDeform.d.ts.map +0 -1
  1371. package/dist/two-d/render/SpriteDeform.js +0 -278
  1372. package/dist/two-d/render/SpriteDeform.js.map +0 -1
  1373. package/dist/two-d/render/SpriteGroup.d.ts +0 -83
  1374. package/dist/two-d/render/SpriteGroup.d.ts.map +0 -1
  1375. package/dist/two-d/render/SpriteGroup.js +0 -107
  1376. package/dist/two-d/render/SpriteGroup.js.map +0 -1
  1377. package/dist/two-d/render/SpriteMotion.d.ts +0 -121
  1378. package/dist/two-d/render/SpriteMotion.d.ts.map +0 -1
  1379. package/dist/two-d/render/SpriteMotion.js +0 -193
  1380. package/dist/two-d/render/SpriteMotion.js.map +0 -1
  1381. package/dist/two-d/render/SpriteSheet.d.ts +0 -62
  1382. package/dist/two-d/render/SpriteSheet.d.ts.map +0 -1
  1383. package/dist/two-d/render/SpriteSheet.js +0 -122
  1384. package/dist/two-d/render/SpriteSheet.js.map +0 -1
  1385. package/dist/two-d/render/StatusVisuals.d.ts +0 -86
  1386. package/dist/two-d/render/StatusVisuals.d.ts.map +0 -1
  1387. package/dist/two-d/render/StatusVisuals.js +0 -111
  1388. package/dist/two-d/render/StatusVisuals.js.map +0 -1
  1389. package/dist/two-d/render/SvgSkeleton.d.ts +0 -54
  1390. package/dist/two-d/render/SvgSkeleton.d.ts.map +0 -1
  1391. package/dist/two-d/render/SvgSkeleton.js +0 -112
  1392. package/dist/two-d/render/SvgSkeleton.js.map +0 -1
  1393. package/dist/two-d/render/TerrainGraphics.d.ts +0 -142
  1394. package/dist/two-d/render/TerrainGraphics.d.ts.map +0 -1
  1395. package/dist/two-d/render/TerrainGraphics.js +0 -161
  1396. package/dist/two-d/render/TerrainGraphics.js.map +0 -1
  1397. package/dist/two-d/render/TerrainGraphicsLayer.d.ts +0 -55
  1398. package/dist/two-d/render/TerrainGraphicsLayer.d.ts.map +0 -1
  1399. package/dist/two-d/render/TerrainGraphicsLayer.js +0 -54
  1400. package/dist/two-d/render/TerrainGraphicsLayer.js.map +0 -1
  1401. package/dist/two-d/render/TileMap.d.ts +0 -395
  1402. package/dist/two-d/render/TileMap.d.ts.map +0 -1
  1403. package/dist/two-d/render/TileMap.js +0 -967
  1404. package/dist/two-d/render/TileMap.js.map +0 -1
  1405. package/dist/two-d/render/TiledMap.d.ts +0 -113
  1406. package/dist/two-d/render/TiledMap.d.ts.map +0 -1
  1407. package/dist/two-d/render/TiledMap.js +0 -129
  1408. package/dist/two-d/render/TiledMap.js.map +0 -1
  1409. package/dist/two-d/render/TintedSprite.d.ts +0 -60
  1410. package/dist/two-d/render/TintedSprite.d.ts.map +0 -1
  1411. package/dist/two-d/render/TintedSprite.js +0 -88
  1412. package/dist/two-d/render/TintedSprite.js.map +0 -1
  1413. package/dist/two-d/render/Types2D.d.ts +0 -56
  1414. package/dist/two-d/render/Types2D.d.ts.map +0 -1
  1415. package/dist/two-d/render/Types2D.js +0 -45
  1416. package/dist/two-d/render/Types2D.js.map +0 -1
  1417. package/dist/two-d/render/Viewport.d.ts +0 -68
  1418. package/dist/two-d/render/Viewport.d.ts.map +0 -1
  1419. package/dist/two-d/render/Viewport.js +0 -74
  1420. package/dist/two-d/render/Viewport.js.map +0 -1
  1421. package/dist/two-d/render/index.d.ts +0 -81
  1422. package/dist/two-d/render/index.d.ts.map +0 -1
  1423. package/dist/two-d/render/index.js +0 -43
  1424. package/dist/two-d/render/index.js.map +0 -1
  1425. package/dist/two-d/stage/DialogueStage.d.ts +0 -90
  1426. package/dist/two-d/stage/DialogueStage.d.ts.map +0 -1
  1427. package/dist/two-d/stage/DialogueStage.js +0 -218
  1428. package/dist/two-d/stage/DialogueStage.js.map +0 -1
  1429. package/dist/two-d/stage/StoryScreen.d.ts +0 -110
  1430. package/dist/two-d/stage/StoryScreen.d.ts.map +0 -1
  1431. package/dist/two-d/stage/StoryScreen.js +0 -178
  1432. package/dist/two-d/stage/StoryScreen.js.map +0 -1
  1433. package/dist/two-d/stage/dialogue-text.d.ts +0 -81
  1434. package/dist/two-d/stage/dialogue-text.d.ts.map +0 -1
  1435. package/dist/two-d/stage/dialogue-text.js +0 -95
  1436. package/dist/two-d/stage/dialogue-text.js.map +0 -1
  1437. package/dist/two-d/stage/index.d.ts +0 -10
  1438. package/dist/two-d/stage/index.d.ts.map +0 -1
  1439. package/dist/two-d/stage/index.js +0 -6
  1440. package/dist/two-d/stage/index.js.map +0 -1
  1441. package/dist/two-d/stage/script.d.ts +0 -160
  1442. package/dist/two-d/stage/script.d.ts.map +0 -1
  1443. package/dist/two-d/stage/script.js +0 -207
  1444. package/dist/two-d/stage/script.js.map +0 -1
  1445. package/dist/two-d/stage/twee.d.ts +0 -35
  1446. package/dist/two-d/stage/twee.d.ts.map +0 -1
  1447. package/dist/two-d/stage/twee.js +0 -28
  1448. package/dist/two-d/stage/twee.js.map +0 -1
  1449. package/dist/two-d/ui/Bar.d.ts +0 -83
  1450. package/dist/two-d/ui/Bar.d.ts.map +0 -1
  1451. package/dist/two-d/ui/Bar.js +0 -110
  1452. package/dist/two-d/ui/Bar.js.map +0 -1
  1453. package/dist/two-d/ui/BitmapLabel.d.ts +0 -58
  1454. package/dist/two-d/ui/BitmapLabel.d.ts.map +0 -1
  1455. package/dist/two-d/ui/BitmapLabel.js +0 -82
  1456. package/dist/two-d/ui/BitmapLabel.js.map +0 -1
  1457. package/dist/two-d/ui/Button.d.ts +0 -133
  1458. package/dist/two-d/ui/Button.d.ts.map +0 -1
  1459. package/dist/two-d/ui/Button.js +0 -254
  1460. package/dist/two-d/ui/Button.js.map +0 -1
  1461. package/dist/two-d/ui/Checkbox.d.ts +0 -44
  1462. package/dist/two-d/ui/Checkbox.d.ts.map +0 -1
  1463. package/dist/two-d/ui/Checkbox.js +0 -89
  1464. package/dist/two-d/ui/Checkbox.js.map +0 -1
  1465. package/dist/two-d/ui/DataTable.d.ts +0 -79
  1466. package/dist/two-d/ui/DataTable.d.ts.map +0 -1
  1467. package/dist/two-d/ui/DataTable.js +0 -164
  1468. package/dist/two-d/ui/DataTable.js.map +0 -1
  1469. package/dist/two-d/ui/Dropdown.d.ts +0 -79
  1470. package/dist/two-d/ui/Dropdown.d.ts.map +0 -1
  1471. package/dist/two-d/ui/Dropdown.js +0 -136
  1472. package/dist/two-d/ui/Dropdown.js.map +0 -1
  1473. package/dist/two-d/ui/DropdownView.d.ts +0 -100
  1474. package/dist/two-d/ui/DropdownView.d.ts.map +0 -1
  1475. package/dist/two-d/ui/DropdownView.js +0 -234
  1476. package/dist/two-d/ui/DropdownView.js.map +0 -1
  1477. package/dist/two-d/ui/EventDialogue.d.ts +0 -23
  1478. package/dist/two-d/ui/EventDialogue.d.ts.map +0 -1
  1479. package/dist/two-d/ui/EventDialogue.js +0 -33
  1480. package/dist/two-d/ui/EventDialogue.js.map +0 -1
  1481. package/dist/two-d/ui/FloatingText.d.ts +0 -123
  1482. package/dist/two-d/ui/FloatingText.d.ts.map +0 -1
  1483. package/dist/two-d/ui/FloatingText.js +0 -153
  1484. package/dist/two-d/ui/FloatingText.js.map +0 -1
  1485. package/dist/two-d/ui/FloatingTextStack.d.ts +0 -150
  1486. package/dist/two-d/ui/FloatingTextStack.d.ts.map +0 -1
  1487. package/dist/two-d/ui/FloatingTextStack.js +0 -170
  1488. package/dist/two-d/ui/FloatingTextStack.js.map +0 -1
  1489. package/dist/two-d/ui/HelpScreen.d.ts +0 -45
  1490. package/dist/two-d/ui/HelpScreen.d.ts.map +0 -1
  1491. package/dist/two-d/ui/HelpScreen.js +0 -59
  1492. package/dist/two-d/ui/HelpScreen.js.map +0 -1
  1493. package/dist/two-d/ui/IconGrid.d.ts +0 -143
  1494. package/dist/two-d/ui/IconGrid.d.ts.map +0 -1
  1495. package/dist/two-d/ui/IconGrid.js +0 -327
  1496. package/dist/two-d/ui/IconGrid.js.map +0 -1
  1497. package/dist/two-d/ui/Label.d.ts +0 -63
  1498. package/dist/two-d/ui/Label.d.ts.map +0 -1
  1499. package/dist/two-d/ui/Label.js +0 -134
  1500. package/dist/two-d/ui/Label.js.map +0 -1
  1501. package/dist/two-d/ui/Layout.d.ts +0 -139
  1502. package/dist/two-d/ui/Layout.d.ts.map +0 -1
  1503. package/dist/two-d/ui/Layout.js +0 -221
  1504. package/dist/two-d/ui/Layout.js.map +0 -1
  1505. package/dist/two-d/ui/ListView.d.ts +0 -130
  1506. package/dist/two-d/ui/ListView.d.ts.map +0 -1
  1507. package/dist/two-d/ui/ListView.js +0 -326
  1508. package/dist/two-d/ui/ListView.js.map +0 -1
  1509. package/dist/two-d/ui/LoadingScreen.d.ts +0 -54
  1510. package/dist/two-d/ui/LoadingScreen.d.ts.map +0 -1
  1511. package/dist/two-d/ui/LoadingScreen.js +0 -87
  1512. package/dist/two-d/ui/LoadingScreen.js.map +0 -1
  1513. package/dist/two-d/ui/MarkupText.d.ts +0 -66
  1514. package/dist/two-d/ui/MarkupText.d.ts.map +0 -1
  1515. package/dist/two-d/ui/MarkupText.js +0 -156
  1516. package/dist/two-d/ui/MarkupText.js.map +0 -1
  1517. package/dist/two-d/ui/MessageBox.d.ts +0 -134
  1518. package/dist/two-d/ui/MessageBox.d.ts.map +0 -1
  1519. package/dist/two-d/ui/MessageBox.js +0 -263
  1520. package/dist/two-d/ui/MessageBox.js.map +0 -1
  1521. package/dist/two-d/ui/MessageLog.d.ts +0 -90
  1522. package/dist/two-d/ui/MessageLog.d.ts.map +0 -1
  1523. package/dist/two-d/ui/MessageLog.js +0 -131
  1524. package/dist/two-d/ui/MessageLog.js.map +0 -1
  1525. package/dist/two-d/ui/Meter.d.ts +0 -76
  1526. package/dist/two-d/ui/Meter.d.ts.map +0 -1
  1527. package/dist/two-d/ui/Meter.js +0 -134
  1528. package/dist/two-d/ui/Meter.js.map +0 -1
  1529. package/dist/two-d/ui/NinePatch.d.ts +0 -49
  1530. package/dist/two-d/ui/NinePatch.d.ts.map +0 -1
  1531. package/dist/two-d/ui/NinePatch.js +0 -59
  1532. package/dist/two-d/ui/NinePatch.js.map +0 -1
  1533. package/dist/two-d/ui/OnScreenKeyboard.d.ts +0 -91
  1534. package/dist/two-d/ui/OnScreenKeyboard.d.ts.map +0 -1
  1535. package/dist/two-d/ui/OnScreenKeyboard.js +0 -109
  1536. package/dist/two-d/ui/OnScreenKeyboard.js.map +0 -1
  1537. package/dist/two-d/ui/RadioGroup.d.ts +0 -68
  1538. package/dist/two-d/ui/RadioGroup.d.ts.map +0 -1
  1539. package/dist/two-d/ui/RadioGroup.js +0 -177
  1540. package/dist/two-d/ui/RadioGroup.js.map +0 -1
  1541. package/dist/two-d/ui/RebindScreen.d.ts +0 -70
  1542. package/dist/two-d/ui/RebindScreen.d.ts.map +0 -1
  1543. package/dist/two-d/ui/RebindScreen.js +0 -129
  1544. package/dist/two-d/ui/RebindScreen.js.map +0 -1
  1545. package/dist/two-d/ui/RichLabel.d.ts +0 -62
  1546. package/dist/two-d/ui/RichLabel.d.ts.map +0 -1
  1547. package/dist/two-d/ui/RichLabel.js +0 -146
  1548. package/dist/two-d/ui/RichLabel.js.map +0 -1
  1549. package/dist/two-d/ui/ScrollBox.d.ts +0 -163
  1550. package/dist/two-d/ui/ScrollBox.d.ts.map +0 -1
  1551. package/dist/two-d/ui/ScrollBox.js +0 -340
  1552. package/dist/two-d/ui/ScrollBox.js.map +0 -1
  1553. package/dist/two-d/ui/ScrollText.d.ts +0 -131
  1554. package/dist/two-d/ui/ScrollText.d.ts.map +0 -1
  1555. package/dist/two-d/ui/ScrollText.js +0 -218
  1556. package/dist/two-d/ui/ScrollText.js.map +0 -1
  1557. package/dist/two-d/ui/SelectionModel.d.ts +0 -50
  1558. package/dist/two-d/ui/SelectionModel.d.ts.map +0 -1
  1559. package/dist/two-d/ui/SelectionModel.js +0 -73
  1560. package/dist/two-d/ui/SelectionModel.js.map +0 -1
  1561. package/dist/two-d/ui/SettingsScreen.d.ts +0 -112
  1562. package/dist/two-d/ui/SettingsScreen.d.ts.map +0 -1
  1563. package/dist/two-d/ui/SettingsScreen.js +0 -338
  1564. package/dist/two-d/ui/SettingsScreen.js.map +0 -1
  1565. package/dist/two-d/ui/Skins.d.ts +0 -59
  1566. package/dist/two-d/ui/Skins.d.ts.map +0 -1
  1567. package/dist/two-d/ui/Skins.js +0 -77
  1568. package/dist/two-d/ui/Skins.js.map +0 -1
  1569. package/dist/two-d/ui/Slider.d.ts +0 -91
  1570. package/dist/two-d/ui/Slider.d.ts.map +0 -1
  1571. package/dist/two-d/ui/Slider.js +0 -170
  1572. package/dist/two-d/ui/Slider.js.map +0 -1
  1573. package/dist/two-d/ui/Spinner.d.ts +0 -67
  1574. package/dist/two-d/ui/Spinner.d.ts.map +0 -1
  1575. package/dist/two-d/ui/Spinner.js +0 -137
  1576. package/dist/two-d/ui/Spinner.js.map +0 -1
  1577. package/dist/two-d/ui/StatsScreen.d.ts +0 -40
  1578. package/dist/two-d/ui/StatsScreen.d.ts.map +0 -1
  1579. package/dist/two-d/ui/StatsScreen.js +0 -42
  1580. package/dist/two-d/ui/StatsScreen.js.map +0 -1
  1581. package/dist/two-d/ui/TabbedList.d.ts +0 -118
  1582. package/dist/two-d/ui/TabbedList.d.ts.map +0 -1
  1583. package/dist/two-d/ui/TabbedList.js +0 -221
  1584. package/dist/two-d/ui/TabbedList.js.map +0 -1
  1585. package/dist/two-d/ui/TextModel.d.ts +0 -90
  1586. package/dist/two-d/ui/TextModel.d.ts.map +0 -1
  1587. package/dist/two-d/ui/TextModel.js +0 -175
  1588. package/dist/two-d/ui/TextModel.js.map +0 -1
  1589. package/dist/two-d/ui/TextPrompt.d.ts +0 -122
  1590. package/dist/two-d/ui/TextPrompt.d.ts.map +0 -1
  1591. package/dist/two-d/ui/TextPrompt.js +0 -236
  1592. package/dist/two-d/ui/TextPrompt.js.map +0 -1
  1593. package/dist/two-d/ui/TextSharpness.d.ts +0 -33
  1594. package/dist/two-d/ui/TextSharpness.d.ts.map +0 -1
  1595. package/dist/two-d/ui/TextSharpness.js +0 -56
  1596. package/dist/two-d/ui/TextSharpness.js.map +0 -1
  1597. package/dist/two-d/ui/Toast.d.ts +0 -57
  1598. package/dist/two-d/ui/Toast.d.ts.map +0 -1
  1599. package/dist/two-d/ui/Toast.js +0 -101
  1600. package/dist/two-d/ui/Toast.js.map +0 -1
  1601. package/dist/two-d/ui/Tooltip.d.ts +0 -177
  1602. package/dist/two-d/ui/Tooltip.d.ts.map +0 -1
  1603. package/dist/two-d/ui/Tooltip.js +0 -275
  1604. package/dist/two-d/ui/Tooltip.js.map +0 -1
  1605. package/dist/two-d/ui/TreeView.d.ts +0 -68
  1606. package/dist/two-d/ui/TreeView.d.ts.map +0 -1
  1607. package/dist/two-d/ui/TreeView.js +0 -133
  1608. package/dist/two-d/ui/TreeView.js.map +0 -1
  1609. package/dist/two-d/ui/VerticalLabel.d.ts +0 -69
  1610. package/dist/two-d/ui/VerticalLabel.d.ts.map +0 -1
  1611. package/dist/two-d/ui/VerticalLabel.js +0 -110
  1612. package/dist/two-d/ui/VerticalLabel.js.map +0 -1
  1613. package/dist/two-d/ui/Window.d.ts +0 -188
  1614. package/dist/two-d/ui/Window.d.ts.map +0 -1
  1615. package/dist/two-d/ui/Window.js +0 -311
  1616. package/dist/two-d/ui/Window.js.map +0 -1
  1617. package/dist/two-d/ui/WindowStack.d.ts +0 -63
  1618. package/dist/two-d/ui/WindowStack.d.ts.map +0 -1
  1619. package/dist/two-d/ui/WindowStack.js +0 -132
  1620. package/dist/two-d/ui/WindowStack.js.map +0 -1
  1621. package/dist/two-d/ui/a11y.d.ts +0 -43
  1622. package/dist/two-d/ui/a11y.d.ts.map +0 -1
  1623. package/dist/two-d/ui/a11y.js +0 -79
  1624. package/dist/two-d/ui/a11y.js.map +0 -1
  1625. package/dist/two-d/ui/contrast.d.ts +0 -30
  1626. package/dist/two-d/ui/contrast.d.ts.map +0 -1
  1627. package/dist/two-d/ui/contrast.js +0 -42
  1628. package/dist/two-d/ui/contrast.js.map +0 -1
  1629. package/dist/two-d/ui/index.d.ts +0 -96
  1630. package/dist/two-d/ui/index.d.ts.map +0 -1
  1631. package/dist/two-d/ui/index.js +0 -49
  1632. package/dist/two-d/ui/index.js.map +0 -1
  1633. package/dist/two-d/ui/markdown.d.ts +0 -55
  1634. package/dist/two-d/ui/markdown.d.ts.map +0 -1
  1635. package/dist/two-d/ui/markdown.js +0 -147
  1636. package/dist/two-d/ui/markdown.js.map +0 -1
  1637. package/dist/two-d/ui/markup.d.ts +0 -189
  1638. package/dist/two-d/ui/markup.d.ts.map +0 -1
  1639. package/dist/two-d/ui/markup.js +0 -387
  1640. package/dist/two-d/ui/markup.js.map +0 -1
  1641. package/dist/two-d/ui/reveal.d.ts +0 -41
  1642. package/dist/two-d/ui/reveal.d.ts.map +0 -1
  1643. package/dist/two-d/ui/reveal.js +0 -22
  1644. package/dist/two-d/ui/reveal.js.map +0 -1
  1645. package/dist/two-d/ui/theme.d.ts +0 -133
  1646. package/dist/two-d/ui/theme.d.ts.map +0 -1
  1647. package/dist/two-d/ui/theme.js +0 -122
  1648. package/dist/two-d/ui/theme.js.map +0 -1
  1649. package/dist/two-d/ui/themedText.d.ts +0 -20
  1650. package/dist/two-d/ui/themedText.d.ts.map +0 -1
  1651. package/dist/two-d/ui/themedText.js +0 -9
  1652. package/dist/two-d/ui/themedText.js.map +0 -1
  1653. package/dist/version.d.ts +0 -13
  1654. package/dist/version.d.ts.map +0 -1
  1655. package/dist/version.js +0 -13
  1656. package/dist/version.js.map +0 -1
  1657. package/dist/world/Encounters.d.ts +0 -32
  1658. package/dist/world/Encounters.d.ts.map +0 -1
  1659. package/dist/world/Encounters.js +0 -9
  1660. package/dist/world/Encounters.js.map +0 -1
  1661. package/dist/world/Environment.d.ts +0 -58
  1662. package/dist/world/Environment.d.ts.map +0 -1
  1663. package/dist/world/Environment.js +0 -89
  1664. package/dist/world/Environment.js.map +0 -1
  1665. package/dist/world/Overworld.d.ts +0 -39
  1666. package/dist/world/Overworld.d.ts.map +0 -1
  1667. package/dist/world/Overworld.js +0 -40
  1668. package/dist/world/Overworld.js.map +0 -1
  1669. package/dist/world/SideTurns.d.ts +0 -115
  1670. package/dist/world/SideTurns.d.ts.map +0 -1
  1671. package/dist/world/SideTurns.js +0 -138
  1672. package/dist/world/SideTurns.js.map +0 -1
  1673. package/dist/world/TurnClock.d.ts +0 -41
  1674. package/dist/world/TurnClock.d.ts.map +0 -1
  1675. package/dist/world/TurnClock.js +0 -49
  1676. package/dist/world/TurnClock.js.map +0 -1
  1677. package/dist/world/World.d.ts +0 -64
  1678. package/dist/world/World.d.ts.map +0 -1
  1679. package/dist/world/World.js +0 -91
  1680. package/dist/world/World.js.map +0 -1
  1681. package/dist/world/index.d.ts +0 -12
  1682. package/dist/world/index.d.ts.map +0 -1
  1683. package/dist/world/index.js +0 -7
  1684. package/dist/world/index.js.map +0 -1
  1685. package/sbom.cdx.json +0 -5996
  1686. package/tools/mwl.mjs +0 -466
  1687. package/tools/vendored/rgssad-wasm/LICENSE-MIT +0 -21
  1688. package/tools/vendored/rgssad-wasm/README.md +0 -15
  1689. package/tools/vendored/rgssad-wasm/package.json +0 -17
  1690. package/tools/vendored/rgssad-wasm/rgssad_wasm.d.ts +0 -41
  1691. package/tools/vendored/rgssad-wasm/rgssad_wasm.js +0 -6
  1692. package/tools/vendored/rgssad-wasm/rgssad_wasm_bg.js +0 -399
  1693. package/tools/vendored/rgssad-wasm/rgssad_wasm_bg.wasm +0 -0
  1694. package/tools/vendored/rgssad-wasm/rgssad_wasm_bg.wasm.d.ts +0 -17
  1695. package/tools.md +0 -219
package/CHANGELOG.md DELETED
@@ -1,3196 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to `mwg` are documented here. Format follows
4
- [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versioning follows
5
- [Semantic Versioning](https://semver.org/) as of this first release - a 0.y.z version means
6
- the public API may still change between minor versions.
7
-
8
- ## [Unreleased]
9
-
10
- ## [0.44.2] - 2026-10-17
11
-
12
- Hardening of `.mwp` content package loading, found by security reviews of 0.44.0 and 0.44.1.
13
- Versions 0.44.0 and 0.44.1 were tagged and released on GitHub but their npm stages were rejected and
14
- they were never published, so 0.44.2 is the first public release of everything in their entries below.
15
-
16
- ### Fixed
17
-
18
- - A WAV header with a zero sample rate or block align fell back to its declared `byteRate`, so
19
- a lying header could still shorten the measured duration. The rate is now the lowest of the
20
- declared one, `sampleRate * blockAlign` and `sampleRate * channels * ceil(bits / 8)`, and a zero in
21
- any of them refuses the file as unreadable.
22
-
23
- ## [0.44.1] - 2026-10-17
24
-
25
- > Superseded by 0.44.2 and never published to npm.
26
-
27
- Hardening of `.mwp` content package loading, found by a security review of 0.44.0.
28
-
29
- ### Fixed
30
-
31
- - A package could multiply its work through repeated file imports: depth was bounded at 4 but
32
- the total was not. Imports now share a budget of 64 reads per package document.
33
- - An import or a `main` document named like an `Object.prototype` member (`constructor`) crashed
34
- the loader with a `TypeError`; lookups are now own-property only and report a
35
- `PackageFormatError`.
36
- - A WAV header declaring a large `byteRate` could shorten the duration measured against
37
- `maxAudioSeconds`; the lower of the declared rate and `sampleRate * blockAlign` is used.
38
-
39
- ## [0.44.0] - 2026-10-17
40
-
41
- > Superseded by 0.44.2 and never published to npm.
42
-
43
- Retro-audio integration contracts (a MIDI engine registry, streaming playback, budgets, content packages and a command line tool), player-facing audio settings, and the interface follow-ups of the last Pontifex round. The parked items 393, 394, Syzygy and NNUE are closed rather than waiting on files or weights that will not arrive, and a simplification pass over the whole tree removes duplicated code.
44
-
45
- ### Added
46
-
47
- - Pontifex follow-up points 51-54 (roadmap 443-446): `ScrollBox` now owns its `hitArea`
48
- (its viewport, kept current by `resize`/`setContentHeight`, with a `viewportWidth`
49
- getter); `DropdownView` and `ScrollText` gain `resize(width)`, and `DropdownViewOptions`
50
- gains `maxWidth` capping `autoWidth`; a transition requested while one is playing is
51
- ignored by default, with `queue: true` / `interrupt: true` in `TransitionOptions` and the
52
- `transitionDisposition` rule exported, `Game.transitioning` also reporting a queued
53
- transition; and `Dropdown.setHighlight` now opens the list as documented, so
54
- `setHighlight(i); confirm()` picks a row and the next opening shows it.
55
- - Retro-audio integration (roadmap 431-442): a named `MidiSynth` engine
56
- registry with fallback diagnostics, the streaming `Playable` contract, bus render budgets
57
- and decoder guards, `.mwp` content packages with capability policy and ROM refusal, data
58
- sound effects, an off-main-thread audio host, adaptive music, the `mwg-audio` tool, and
59
- the `testing` doubles (`FakeRetroPlayer`, fake WebAudio graph) - documented in the
60
- README's "Retro audio" section, REFERENCE and `docs/listening-protocol.md`. Player-facing
61
- settings (`AudioSettings` with PAL/NTSC, dynamics and softening rules), live Web MIDI
62
- (`connectWebMidi`), dropped `.syx` banks with DX7 patch names and audition (`SyxBank`),
63
- and the oscilloscope/tracker data cores (`waveformEnvelope`, `trackerPattern`) complete
64
- item 441.
65
-
66
- ### Changed
67
-
68
- - Simplification pass over the tree, with no change to the public API: one shared radix-2 FFT
69
- in `audio`, `HexSkirmish.reachableCosts` built on `core`'s `weightedFlood` (a negative
70
- terrain move cost is now ignored instead of accepted), `tourney` and `Tactics` using the
71
- `Engine` job default and `core`'s `cellInside`, a single byte-joining helper in the
72
- `mwl` package container, and hand-written clamps replaced by `core`'s `clamp` across
73
- `ui`, `render`, `battle`, `physics` and `audio`.
74
- - Roadmap: items 393 (Ableton and Reaper groove formats), 394 (the Magenta humanizer tier),
75
- Syzygy and NNUE are closed; 401 is the only numbered item left, waiting on a port session.
76
-
77
- ## [0.43.0] - 2026-10-17
78
-
79
- Scrolling, tooltips and screen transitions for interface-heavy games, a MIDI music player and
80
- SoundFont tooling, and the shipped command line tools made to work from an installed package on
81
- Node 20.19. `@datamoc/pyroeis` moves to 0.9.1, which ends the last moderate audit advisory.
82
-
83
- ### Added
84
-
85
- - Scrolling and transitions asked for by a bridge game (Pontifex feedback 45-50):
86
- - `ScrollBox`: `touch` (drag to scroll, coasting on release, `ScrollDrag`), `handleKey` for line, page and
87
- ends, a draggable scrollbar thumb and a clickable track, and `autoHeight`. A drag no longer clicks the row
88
- it ends on.
89
- - `DropdownView`: `maxVisibleRows` (the list scrolls), an opaque backdrop, `autoWidth`, opening with the chosen
90
- row in view, `handleKey`, `handleOutsideClick` and `fitBelow`.
91
- - `ScrollText` (a wrapped label that sizes itself and scrolls), `MarqueeLabel` (a long line sliding inside
92
- its width, still under reduced motion), `ellipsize` and `truncateLines`.
93
- - `TooltipHost`: tooltips on a touch long-press and on disabled buttons, from rectangles instead of pointer
94
- events. `Button` gains `tooltip`, `setIcon` and a second icon for the selected state (`iconSelected`).
95
- - `Game.switchScene(Next, { transition, duration, easing, pause })`, `Game.transition(swap, options)` and
96
- `Scene2D.transitionTo`: `tileShrink`, `shrink`, `pop`, `grow`, `slide`, `iris` and `dissolve` over a snapshot of
97
- the outgoing scene, skipped under reduced motion, with `Game.transitioning` and `Game.active`. `Window.open`
98
- and `Window.close` take an animation (`pop`, `grow`, `slide`, `fade`). The bridge example switches level
99
- with `tileShrink`.
100
- - The dist grew 3.8% with them; the size baseline is moved to match.
101
- - `limits` (`SoundFontLimits`: `sampleFrames`, `totalFrames`) on `decodeSoundFont`, `loadSoundFont` and
102
- `webAudioSampleDecoder` raises or lowers what a SoundFont 3 may decode to, instead of the fixed 16 M
103
- frames per sample and 128 M per font. The sample-rate bounds stay: the format itself stops at 50 kHz.
104
- - `@example`s for the `3d` functions that need no renderer (`gridPoint3D`, `cellAt`, `heightAt`,
105
- `buildHeightIndex`, `resolveCapsuleAgainstGrid`, `parseVox`). The generated API reference now covers
106
- the subpaths the root barrel does not re-export (`3d`, `physics`, `ai/lua`, `mwl/pyroeis`, `testing`,
107
- `threads`, `headless`, `assets/binary`), so the examples index links 803 of 813 symbols to a page.
108
- - `npm run build:bridge-tutorial` regenerates the bridge tutorial from `tools/templates` and the example's
109
- own source. `npm run bins:smoke` packs the project, installs it in an empty folder and runs every `mwg-*`
110
- bin with `--help`; CI runs it, with the library build, on Node 20.19.0, the floor `engines` claims.
111
- - `.gitattributes` (`* text=auto eol=lf`) ends the CRLF warnings on Windows checkouts.
112
- - An optional, reproducible 314 KB SoundFont subset covering six essential presets,
113
- with provenance and synthetic fallback for the instruments outside it.
114
- - `AudioBus` loads embedded audio and MIDI by default through `createAudioLoader`, with
115
- shared decoding, worker MIDI rendering and optional SoundFont settings across lifetimes.
116
- - `MusicPlayer` controls rendered MIDI or decoded buffers with pause, resume, seek,
117
- volume and a track-completion signal; `toAudioBuffer` copies rendered stereo samples
118
- into a Web Audio buffer. The README shows the supplied SoundFont and worker playback path.
119
- - Page byte budgets and potentially unused asset reports in the standalone build pipeline.
120
- - XPBD link payloads, explicit rupture, geometric queries and state comparison helpers.
121
- - Schema-directed `nodesToObjects` conversion and optional literal unions generated from
122
- MWL table columns. Optional attributes are documented alongside the schema.
123
- - Generated starter projects include a pre-commit hook for typecheck and tests, an activation
124
- command and ignores for local agent state.
125
- - Sawtooth sound synthesis, playback attempt counts and a shared browser test exposure hook.
126
-
127
- ### Fixed
128
-
129
- - `mwg-uci`, `mwg-openings` and `mwg-tablebases` imported `../src/...`, which the package does not ship, so
130
- they failed in every installed copy; they load `dist` there, as the other tools already did.
131
- - The bridge example keeps a saved best only when the new crossing costs less, or costs the same and sags
132
- less, instead of replacing it by any cheaper one.
133
- - Fixed waits that failed on a loaded machine: the browser smoke waits for drawn frames instead of 250 ms,
134
- the driver test polls for its tap instead of sleeping 300 ms, and the WebP noise test is seeded.
135
-
136
- ## [0.42.0] - 2026-10-16
137
-
138
- The documentation and asset follow-ups to 0.41.0: SVG minification, a policy for the instruments a
139
- SoundFont lacks, a playable bridge game with its tutorial, an examples index, and function-level
140
- examples. One behaviour changes: a drum kit a font lacks now falls back to the standard kit instead of
141
- a melodic preset.
142
-
143
- ### Added
144
-
145
- - Function-level `@example`s where the examples used to sit on a file or an interface, so an
146
- editor's hover shows them: `SaveSystem` (with a migration), `parseDialogueLines`,
147
- `parseTwee` (walking a story), `motionDuration` (reduced motion on a slide and on a
148
- meaningful bar) and `Theme` (a custom theme, `themeChanged`, the high-contrast swap).
149
- - `XpbdWorld` documents a bridge: a Warren truss with beams, a `tensionOnly` cable note and a
150
- breaking load, tested to hold a light cart, break under a heavy one and repeat exactly.
151
- - `REFERENCE.md` records what subsetting the bundled bank costs (piano and drums 264 KB,
152
- eight essential programs 421 KB, sixteen 585 KB) and what plays for a program the font lacks.
153
- - `svgo: true` on `compileResources`, `emitPage` and `mwgPage` (and `--svgo` on `mwg-emit`) minifies
154
- embedded `.svg` assets through the optional `svgo` package, version 4 or newer, imported only when
155
- used. Ids and the `viewBox` are left alone, a file is embedded optimised only when that is smaller,
156
- and one svgo cannot parse fails the build by name. On the repository's own 30 SVGs: 13.6%
157
- smaller, worst rendered pixel difference 1 in 255. `@datamoc/mw_games/tools/svg-optimise` is the
158
- standalone half.
159
- - `missingProgram: 'piano' | 'synth'` on `parseSoundFont`, `loadSoundFont` and
160
- `renderMidiToBufferAsync`: what plays for a program the font lacks, the font's own piano as
161
- before or the built-in synthesizer, so a game with a trimmed bank hears the synthesizer's timbre
162
- for an instrument it did not ship instead of a piano line.
163
- - `missingSoundFontPrograms` (`audio`) lists the programs a MIDI usage asks for that a SoundFont 2 or
164
- 3 does not carry. The asset compiler runs it: each embedded font's result has a `missing` list and
165
- `mwg-emit` and `compile-resources` warn about them.
166
- - `examples/bridge` and the "Build a bridge game" tutorial (`webpage/tutorials/bridge`): a playable
167
- truss builder on `XpbdWorld` (three levels, a budget, cables, beams coloured by load, breaking),
168
- a deterministic replay of the player's build through `Recorder`/`Player`, best results through
169
- `SaveSystem`, reduced motion and the high-contrast theme. The simulation is renderer-free and
170
- tested, every tutorial snippet is checked to appear verbatim in the example, and the interface
171
- step points at `examples/mwl-presentation` for HUD and windows described as MWL content.
172
- - An examples index (`tools/build-example-index.mjs`, written by `npm run webpage:docs` to
173
- `documentation/examples.html`): for each public module every exported symbol with an `@example`,
174
- its first lines and a link to its API page, plus the runnable examples that import the module.
175
-
176
- ### Fixed
177
-
178
- - A request for a drum kit the font lacks falls back to the standard kit, never to a melodic
179
- preset: it used to take the same program number from bank 0, so a font with a piano and no drums
180
- played the piano where the kick should be.
181
-
182
- ## [0.41.0] - 2026-10-16
183
-
184
- `microgm-opt` stays the default SoundFont, and a game that wants another one can now pick it:
185
- a licence-classified catalogue of a per-instrument collection, a tool that fetches only the
186
- instruments the game plays, and SoundFont 3 support from the build to the browser, so the
187
- font reaches the page compressed and is decoded at load.
188
-
189
- ### Added
190
-
191
- - `mwg-soundfonts` (`list`, `fetch`, `convert`, and `@datamoc/mw_games/tools/soundfonts`):
192
- `data/soundfont-catalog.json` lists the bundled bank and 18 fonts of the marmooo
193
- free-soundfonts collection with each licence classified (public domain, permissive and
194
- attribution fetch freely; share-alike, copyleft and unclear ones need `--accept-licence`;
195
- TimGM6mb is listed as GPL-2.0 where the collection says public domain). `fetch` takes the
196
- instruments named by `--midi` files or `--programs` and merges them into one SoundFont 3 with
197
- a `.credits.txt` beside it: nothing is decoded, so no `ffmpeg`. `--sf2` and `convert` decode
198
- to a plain SoundFont 2 instead (Ogg Vorbis through `ffmpeg`, a developer-machine tool), about
199
- eight times larger.
200
- - `loadSoundFont`, `decodeSoundFont` and `webAudioSampleDecoder` (`audio`): a game reads the
201
- SoundFont 2 or 3 it ships with `loadSoundFont`, a SoundFont 3 decoded once at load through
202
- `decodeAudioData` (each sample in a context at its own rate, so no resampling), or through a
203
- decoder the caller passes. Checked in Chrome against `ffmpeg`: the same frames, rates and
204
- loop points, and the same render. `decodeSoundFont` returns the SoundFont 2 bytes for
205
- anything that takes them.
206
- - `compileResources`, `emitPage` and `mwgPage` embed `.sf3` assets and subset them to the
207
- programs the game's MIDI files use, the Ogg bytes copied untouched.
208
- - `mergeSoundFonts` (`audio`): joins SoundFont 2 files, or SoundFont 3 files with their Ogg
209
- bytes untouched, into one, the first font winning a shared (bank, program).
210
-
211
- ### Fixed
212
-
213
- - `parseSoundFont` refuses a SoundFont 3 by name (pointing at `loadSoundFont`) instead of
214
- reading its Ogg bytes as PCM and playing noise.
215
- - A SoundFont whose sample offsets point outside its sample data is refused when read, rather
216
- than read beyond it.
217
- - Decoding a SoundFont 3 bounds what the file can make it allocate: a sample rate outside 400 to
218
- 200000 Hz is refused, a decoded sample is capped at sixteen million frames and a whole font at
219
- 134 million (256 MB of audio), in both `decodeSoundFont` and the WebAudio decoder.
220
- - `mwg-soundfonts` treats the font as untrusted input: a sample whose offsets point outside the
221
- sample data is refused instead of copied from beyond it, and `ffmpeg` only ever receives bytes
222
- that start with the Ogg magic, with the demuxer forced to Ogg and only the `pipe` protocol
223
- allowed, so a crafted "sample" cannot be probed as a playlist that names local files.
224
-
225
- ## [0.40.1] - 2026-10-15
226
-
227
- The published package now carries its documentation the way npm expects to find it: a
228
- homepage that opens the documentation site, the reference and the tools guide inside the
229
- tarball, declared Node support, and a `--help` on every command line tool.
230
-
231
- ### Added
232
-
233
- - `package.json` declares `homepage` (the documentation site, so `npm docs` opens it
234
- instead of the GitHub README), `bugs` and `engines` (`node >=20.19.0`), and exports
235
- `./package.json` so a tool can read an installed module's metadata. `@datamoc/mwg`
236
- inherits all of them, plus the keywords it lacked.
237
- - `REFERENCE.md` and `tools.md` ship in the tarball, so the README's relative links
238
- resolve offline from `node_modules`.
239
- - `REFERENCE.md` sections for `skeleton`, `physics` and `mwl/pyroeis`.
240
- - JSDoc on the exported symbols of the least documented entry points
241
- (`mwl/presentation`, `ai/lua`, `physics/xpbd`, `two-d/presentation`, `3d`, `mwl/pyroeis`,
242
- `physics`).
243
-
244
- ### Fixed
245
-
246
- - `mwg-bench`, `mwg-size`, `mwg-sbom`, `mwg-lockstep-server`, `mwg-mwl`, `mwg-uci` now print
247
- their usage for `--help` instead of running. `mwg-init --help` no longer creates a folder
248
- named `--help`, `mwg-scenarios --help` no longer hangs, and `mwg-placeholder-assets --help`
249
- no longer rewrites the assets.
250
-
251
- ## [0.40.0] - 2026-10-15
252
-
253
- A game that plays sampled MIDI no longer ships a whole SoundFont: the asset
254
- compiler subsets the bank to the instruments its tracks actually use, and the
255
- package now carries a small WTFPL General MIDI bank to subset from.
256
-
257
- ### Added
258
-
259
- - Build-time SoundFont subsetting: `compileResources`, `emitPage` and `mwgPage` now
260
- embed `.mid`/`.midi` and `.sf2` assets, and every embedded SoundFont is subset to
261
- the programs the embedded MIDI files actually use (`collectSoundFontUsage` over
262
- the shipped tracks, drums as bank 128). `soundFont: false` embeds a font whole,
263
- `soundFontUsage` (or `--soundfont-usage=bank:program,...`) names the programs
264
- explicitly, and a font with no shipped MIDI embeds whole. An unreadable MIDI or
265
- SoundFont fails the build by name instead of shipping silently. The result and
266
- both CLIs report each font's kept programs and byte saving: the reference bank
267
- `data/microgm-opt.sf2` (2.6 MB, 137 presets, WTFPL, shipped in the npm package
268
- for a game to copy into its assets) embeds as 25 KB for a piano-only track.
269
-
270
-
271
- ## [0.39.1] - 2026-10-15
272
-
273
- Fixes the 0.39.0 publish gate on Linux: the WebP skip-shrink test asserted one
274
- platform's encoder answer instead of the real guarantee, and failed where sharp
275
- genuinely shrinks the noise fixture.
276
-
277
- ### Fixed
278
-
279
- - The WebP test embeds whichever encoding is smaller and asserts byte-exact output
280
- with a lossless round-trip either way, instead of assuming the conversion always
281
- loses on tiny noise.
282
-
283
- ## [0.39.0] - 2026-10-15
284
-
285
- The skeleton cluster (two-bone IK, joint limits, full clip channels, diagnostics, SVG
286
- parts loading), the asset and deformation cluster (pinned deformation, SVG skeletons,
287
- asset filtering and the embedded assets report), and the effects cluster (cloth, spring,
288
- haze and neon glow, each with a stated frame budget and reduced-motion handling).
289
- `PhysicsWorld` leaves `matter-js` behind for an in-repo solver, so the dependency is gone.
290
-
291
- ### Added
292
-
293
- - Pinned sprite deformation with atomic vertex batches and one GPU upload per batch, checked
294
- against a local Pontifex bird with fixed attachments and unchanged UVs.
295
- - `loadSvgSkeleton`: SVG limb extraction, authored/manifest pivots, rest-angle normalization
296
- and automatic `SkeletalSprite` binding, including nested parts without duplicate drawing.
297
- - `assetFiles` on `mwgPage`, `emitPage` and `compileResources`: exact embedding lists with
298
- named failures for unknown entries and unchanged defaults when omitted.
299
- - `mwg-assets` (`assetReport`): per-file raw/gzip/brotli weights with each share of
300
- the compressed page, plus the embedded source inventory with byte-identical
301
- duplicates grouped by hash.
302
-
303
- - Two-bone skeleton IK with named unreachable-target failures, absolute local joint limits,
304
- and translation/scale clip channels through `sampleTransformPose` and `advancePose`.
305
- - Explicit `SkeletalSprite.setDiagnostics` overlay for bones, pivots, joints and tips.
306
- - `loadSvgParts` / `releaseSvgParts`: named SVG group textures with resolution-aware caching,
307
- compiled local-file asset support and a browser check against a local Pontifex vehicle.
308
-
309
- - Pinned-point cloth (`Cloth` Verlet mesh plus textured `ClothSprite` on the 414 mesh
310
- path) with gravity, wind, damping and a browser drape check; a damped 2D chase
311
- `Spring` for secondary motion with a stated O(1) frame budget, plus a `SpringSprite`
312
- debug line.
313
- - `HazeLayer` (with `hazeField` / `paintHazePixels`): drifting atmospheric sheets on
314
- stacked depth planes, checked in the browser over a painted harbour; `NeonGlow`
315
- (with `glowFalloff` / `paintGlowPixels`): additive neon light with colour, radius,
316
- intensity and flicker, checked in the browser over a dark lane of signs.
317
-
318
- ### Removed
319
-
320
- - The `matter-js` (and `@types/matter-js`) dependency: `PhysicsWorld` is recoded in TypeScript in this repo (semi-implicit Euler, impulse contacts, projected distance joints) with the same options, methods and signals. Bodies no longer spin: `angle` stays a display offset. The dropped `engine` field exposed the whole matter engine; nothing in this repo used it.
321
- ### Fixed
322
-
323
- - SVG group splitting retains group transforms, shared definitions and styles, and handles
324
- nested self-closing groups. Skeleton creation reports cycles instead of overflowing the stack.
325
-
326
- ## [0.38.0] - 2026-10-14
327
-
328
- Optional MWL scene and UI composition with its bridge-editor example, the
329
- all-scenarios browser verifier, instance palette setters, and a powered-by badge
330
- games can carry on their login screen. Roadmap 393 and 394 move to parked: no
331
- fixture files for the proprietary groove formats, and the neural humanizer costs
332
- more than the game use case justifies.
333
-
334
- ### Added
335
-
336
- - Optional MWL presentation compiler (`mwl/presentation`) and Pixi runtime
337
- (`two-d/presentation`): scene layers, camera, reusable UI, responsive layouts, keyed
338
- collections, typed bindings and biome-selected palette/scenery overrides. The local-file
339
- bridge-editor example checks keyboard/pointer focus, modal input, cleanup and update cost.
340
- - `Button.setColors`, `Window.setColors` and `Bar.setBackground` update instance palettes
341
- without rebuilding widgets.
342
-
343
- - `mwg-scenarios`: verifies every scenario in one local-file browser page through game-owned
344
- `SceneControls` steps for entry, bot turns, assertions and cleanup, with bounded execution
345
- and per-scenario failures.
346
- - `webpage/assets/powered-by-mwg.svg`: a badge games can copy onto their login screen,
347
- linked to the framework site, with the snippet in the README's new "Powered by mwg"
348
- section and the badge itself in the website footer.
349
-
350
- ## [0.37.0] - 2026-10-14
351
-
352
- Fixes and additions from the first outside game built on mwg (Pontifex, on 0.36.0): sounds compose with synthesized tones, two physics modules (matter-js rigid bodies and a deterministic XPBD structure solver), pointer and dropdown widgets, a project scaffold, and the `@datamoc/mwg` short-name package.
353
-
354
- ### Added
355
-
356
- - `audio.synthesizeSound(tone, options)`: a pooled `Sound` over a synthesized tone.
357
- - `core.FixedStepper`: turns the variable frame `dt` into fixed simulation steps with a substep cap.
358
- - `core.StoredValue` and `core.defaultStorage` are public, so a game can keep structured JSON progress under one key.
359
- - `Button.setSelected`, `Label.setWrapWidth`, `Window({ closeButton: true })` (a visible ✕), and `ui.flowLayout` (wrapping rows with alignment).
360
- - `ParticleEmitter.burst(count, { x, y, tint })`, `Shape2D.dashedLine`, `Camera.fit(worldWidth, worldHeight)` and `SpriteSheet.strip(path, frames)`.
361
- - `BrowserDriver.drag(fromX, fromY, toX, toY, steps)` on Chrome (CDP) and Firefox (in-page pointer events).
362
- - `Input.attachPointer`: down, move, drag and up signals with target-relative and world positions.
363
- - `physics.PhysicsWorld` (`@datamoc/mw_games/physics`, optional peer `matter-js`): rigid bodies, constraints, contact events and breakable joints (`maxStretch`, `onBreak`, `stretchOf`) on a fixed clock.
364
- - `physics.XpbdWorld` (`@datamoc/mw_games/physics/xpbd`, no `matter-js`): a deterministic XPBD structure solver with per-link loads, breaking at a real strength and ground collision, extracted from Pontifex.
365
- - `ui.DropdownView`, the widget over the `Dropdown` model.
366
- - `mwg-init <folder>`: writes a starter project that builds to a double-clickable page.
367
- - `assets/credits.json` becomes `CREDITS.txt` in the compiled output (`compileResources`, `creditsText`).
368
- - `@datamoc/mwg`, the short name for the package, generated into `packages/mwg` by `npm run alias:write` (publishing it is a separate step).
369
- - Roadmap 412 is the owner-only step left: publishing `@datamoc/mwg`.
370
-
371
- ### Changed
372
-
373
- - `assets.resolve` returns a `data:` or `blob:` URL unchanged, so a synthesized tone or a runtime blob composes with `Sound`, `Music` and textures.
374
- - `SpriteSheet.grid` warns when the frame size does not divide the sheet instead of cutting distorted frames silently.
375
- - The README status line names the current version and the core row no longer calls the loop fixed-step.
376
-
377
- ### Fixed
378
-
379
- - `compile-resources`, `compress-dist`, `play-uci`, `build-tablebases` and `compile-openings` took any importer whose file name was a suffix of theirs (`t.mjs` for `compress-dist.mjs`) for their own command line and ran it on import; they now compare real paths.
380
- - A sound that is missing from the build plays as silence with a warning instead of rejecting inside `Game.start` and leaving a black screen.
381
- - `tools/vite.mjs` and the build tools it imports no longer use top-level await, so a `vite.config.ts` in a project without `"type": "module"` loads.
382
- - `mwgPage()` and the examples stop printing the `EMPTY_IMPORT_META` warning on every build.
383
-
384
- ## [0.36.1] - 2026-10-13
385
-
386
- A maintenance release: the optional Lua dependency catches up with Pyroeis 0.9.0, and the CI no longer hangs on a stuck browser.
387
-
388
- ### Changed
389
-
390
- - The optional `@datamoc/pyroeis` dependency moves from `^0.6.0` to `^0.9.0`. No API change on the mwg side.
391
- - The Actions group is bumped (`actions/setup-node` 7.1.0 and `actions/upload-artifact`).
392
- - The scheduled browser benchmark uses floors fit for a software-rendered runner (10 fps, p95 250 ms) instead of the GPU defaults it failed every week; the 15% history comparison still catches regressions.
393
-
394
- ### Fixed
395
-
396
- - The browser driver kills the whole browser process group when it times out or closes, instead of only the launcher. Surviving helper processes held the output pipes and kept `npm test` alive until the runner's 6 hour limit.
397
- - The browser start-up budget is 90 s and the CI `check` job is capped at 30 minutes; Linux Chrome runs with `--disable-dev-shm-usage --disable-gpu`.
398
-
399
- ## [0.36.0] - 2026-10-12
400
-
401
- The optional Lua integration uses Pyroeis, with a matching public subpath, factories and types. Games using the Lua host must update their imports to `mwl/pyroeis` and the `Pyroeis` names.
402
-
403
- ### Changed
404
-
405
- - Replace the optional `@datamoc/fengari` dependency with `@datamoc/pyroeis` `^0.6.0` and use `PyroeisVm`. Rename the public Lua subpath to `mwl/pyroeis`, the factories to `createPyroeisScriptHost` and `createPyroeisRuntime`, and all associated `Fengari*` types to `Pyroeis*`.
406
-
407
- - Docs: the 1.0 checklist's ports line is restated as an external condition rather than an open box, `LuaAI` is described as the Lua 5.4 provider it is, and the Lua host's byte budget is described as the VM's per-call allocation limit rather than the `lua_setallocf` hook it no longer rides. The 0.35.0 entry names the `^0.5.2` range that release shipped with.
408
-
409
- ## [0.35.1] - 2026-10-11
410
-
411
- The Lua host moves to `@datamoc/fengari` 0.5.4: tighter execution limits and a simpler `ScriptHost` setup.
412
-
413
- ### Changed
414
-
415
- - The optional Lua dependency moves to `@datamoc/fengari` `^0.5.4`. The `ScriptHost` uses its `print: 'native'` option instead of building the VM without libraries and re-opening them, which also drops the `string.dump` and `__random` clean-up the re-open made necessary. Execution limits now also hold against a limit overrun hidden by a script-created coroutine, global-path lookups and `Coroutine#close()`.
416
-
417
- ## [0.35.0] - 2026-10-11
418
-
419
- A Lua integration host for games that need synchronous API results and resumable dialogue, an offline Lua to JavaScript translator, and the Lua dependency moves to `@datamoc/fengari` 0.5.2.
420
-
421
- ### Added
422
-
423
- - `createFengariRuntime` on the optional `mwl/fengari` subpath: synchronous host functions with results, live indexed table bindings, owned Lua callback/table references, embedded `require`/`dofile`, and host-driven coroutines with request values and scene answers. `luaToJs` translates Lua source to readable JavaScript offline (fengari 0.5.0's `lua2js`), flagging untranslatable constructs, for a game leaving Lua scripting. The existing JSON-only `ScriptHost` stays unchanged. Calls, module compilation and coroutine resumes share bounded execution, with a fresh budget for each top-level operation.
424
-
425
- ### Changed
426
-
427
- - The optional Lua dependency moves to `@datamoc/fengari` `^0.5.2`, whose shipped TypeScript declarations replace the old `@ts-expect-error` import and the hand-written `luaToJs` types, and whose `vm.protect` and `vm.throwLuaError` replace the host-side protected-call code. The host reuses `FengariVm`'s execution guard while retaining text-only compilation, JSON-shaped tables and seeded randomness.
428
-
429
- ### Fixed
430
-
431
- - Lua instruction limits now interrupt native table moves and string searches, and cannot be swallowed by `pcall`, `xpcall` message handlers or coroutine resumes. Parsing and execution still share the per-call string/buffer allocation budget. The `ScriptHost` sandbox also drops `string.dump` and fengari's internal `__random`, which scripts could still reach.
432
-
433
- ## [0.34.0] - 2026-10-10
434
-
435
- Hex grids for the cave, dungeon and overworld generators, and the Lua host moves to the `@datamoc/fengari` 0.3.0 fork (`<const>`, `<close>`, `coroutine.close`).
436
-
437
- ### Added
438
-
439
- - `shape: 'hex'` on `generateDungeon`/`generateDungeonGraph`, `generateCave` and `generateOverworld`: the generators lay their output out on a hex grid (odd-q offsets, as `Level` does) instead of squares. The dungeon and cave `Level` carry the hex shape; a dungeon corridor leg runs as a hex line and `furthestRoom` counts hex steps on a hex level; a cave grows chambers by hex distance and walks passages by true on-screen distance, so a chamber is round rather than a skewed diamond; the overworld samples its value noise where each hex is drawn and steps rivers and roads across the six edges, with settlement spacing and the near-water test in hex steps. Square output is unchanged byte for byte.
440
- - `generateCave` accepts `random`, a `RandomSource`, in place of `seed`: the cave draws from that stream and advances it, and the ambient `Random` stack is left alone. Passing neither is refused by name.
441
-
442
- ### Changed
443
-
444
- - `@datamoc/fengari` moves to `^0.3.0`. Lua scripts in `mwl/fengari` and `ai/lua` now accept `<const>` and `<close>` variables and `coroutine.close`; a limit error (instructions or memory) unwinds through pending `__close` handlers, and a handler cannot buy extra instructions after the limit fired.
445
-
446
- ### Fixed
447
-
448
- - `mwg_emit(name, payload)` called from inside a coroutine read its payload from the main thread's stack, so it returned garbage or failed; it now reads from the calling coroutine.
449
-
450
- ## [0.33.0] - 2026-10-10
451
-
452
- Seven roadmap items in one release: the Wesnoth port's proposal file is now fully answered
453
- (405 shipped with 0.32.0, 406/407/409 this release, 408's first half, 401 parked with the
454
- port), alongside the skeletal puppet pair (399/400), SVG as inbound data (398), the overworld
455
- generator (410), and the Lua host riding the fork's new allocation hook.
456
-
457
- ### Added
458
-
459
- - `skeleton`, a new renderer-free root module (roadmap 399): a bone tree where a pose is one
460
- rotation per bone, keyframed clips (plain JSON, interpolation, looping, playback rate,
461
- crossfade), and additive layers mixing by priority that displace only the bones they name.
462
- `two-d/render` gains the drawing half (400): `SkeletalSprite` binds parts to bones by
463
- name, and `ArticulatedChain`/`ChainRig` draw a follower-rule spine with per-segment
464
- rotation limits.
465
- - `roguelike.generateCave` (407): chambers grown as blobs (`jagged`), winding passages
466
- (`windiness`, `width`, `chance`), starts with cleared rings, village density, and a forced
467
- join so a cave is always connected. `roguelike.generateOverworld` (410): seeded elevation
468
- and moisture fields classify seven terrains behind a `seaLevel` knob, rivers run downhill
469
- to the sea and drown lakes at ridges, settlements place themselves by suitability and join
470
- into a road tree that prefers flat ground (water a ford, not a wall), points of interest
471
- carry `leadsTo`, and every cell carries a coarse region id.
472
- - `assets` SVG inbound rules (398): `sanitizeSvg` refuses what it cannot prove inert by name,
473
- `svgScaleVariants` rasterizes one source per named scale, `splitSvgGroups` loads one part
474
- per top-level `<g>` group.
475
- - `testing` gains `createSceneControls` (408's first half): named steps a game opts into,
476
- driven by name, refused by name when unknown - the seam a headless driver calls a game's
477
- private scene flow through.
478
-
479
- ### Changed
480
-
481
- - `mwl/fengari` now requires `@datamoc/fengari@^0.2.0` and enforces `memoryLimit` through the
482
- fork's per-state allocation hook (`lua_setallocf`) instead of swapping the global
483
- `Uint8Array` constructor mid-call: no global mutation (and so no reentrancy hazard between
484
- hosts on one page), parsing is inside the budget, host callbacks allocate freely, and a
485
- refused allocation surfaces to scripts as Lua's standard `not enough memory` while the
486
- host still rejects the call.
487
- - MWL `test=` expressions can call `have_unit`/`have_location` and registered predicate hooks
488
- directly (406), `[while]` traces `while_limit` when its cap is reached with the condition
489
- still true (`on_limit=error` makes it a hard failure), and `[condition]` accepts free
490
- predicate attributes.
491
-
492
- ## [0.32.0] - 2026-10-10
493
-
494
- The optional Lua host hardens around what the `@datamoc/fengari` fork offers, and the
495
- phantom-leader bug the Wesnoth port's scenarios exposed is fixed.
496
-
497
- ### Changed
498
-
499
- - `mwl/fengari` moves to the `@datamoc/fengari` fork (Lua 5.4) and opens only the
500
- sandbox-safe Lua standard libraries (base, coroutine, math, string, table, utf8) through
501
- the fork's `luaL_openselectedlibs`: `io`, `os`, `debug` and `package` with its `require`
502
- are never constructed - identically in Node and the browser - instead of being opened and
503
- then nil'd. Chunks now compile in text mode, so a binary `\x1bLua` dump is rejected instead
504
- of reaching the bytecode undumper.
505
- - Roadmap item 390 (the tourney chess engine) is closed by accepting its recorded split:
506
- 4-piece tablebases stay a `tools/build-tablebases.mjs` run away rather than shipping tens
507
- of megabytes per ending; the compiled 3-piece tables stay under `data/tablebases`.
508
-
509
- ### Fixed
510
-
511
- - `MwlRuntime` no longer spawns a phantom leader when a `[side]`'s `leader=` names an
512
- already-declared unit: the named unit is the leader, a known unit type still spawns one
513
- leader per free start cell with its real stats, and a value that is neither is refused by
514
- name instead of creating a 1-hp, 0-move ghost (roadmap 405, which broke about ten of the
515
- Wesnoth port's scenarios with "unknown unit type").
516
-
517
- ## [0.31.0] - 2026-10-09
518
-
519
- Two pixel-dungeon proposals: P43, `SpriteMotion` (squash, hop, bob, wobble, spin, shear and flip over `Tweener`, reduced-motion aware), and P42, camera snapping in whole device pixels, which closes the thin tile seams at a fractional `devicePixelRatio`.
520
-
521
- ### Added
522
-
523
- - `two-d/render` `SpriteMotion` (pixel-dungeon proposal P43): squash, hop, bob, wobble, spin,
524
- shear and flip over any display object's transform, through a `Tweener`. Effects compose from
525
- a captured rest pose, never drift, cancel cleanly, and follow `setReducedMotion` (a looping
526
- bob holds still; `intent: 'meaningful'` is shortened instead of dropped).
527
-
528
- ### Fixed
529
-
530
- - `Camera` rounded its screen offset to a whole CSS pixel, which at a fractional
531
- `devicePixelRatio` (Windows at 150%) left thin seams between tiles. The offset now rounds to
532
- whole device pixels through the new `CameraOptions.resolution` (supplied by `createCamera`,
533
- read live), and `snapZoom` takes an optional `resolution` so `pixelPerfectTileSize` snaps to
534
- whole device pixels too.
535
-
536
- ## [0.30.0] - 2026-10-07
537
-
538
- P41, the browser driver's four measured gaps: the viewport option (inner size through the
539
- protocol, not window flags), the trusted keyboard channel (press through CDP key events and
540
- BiDi key actions, with the WebDriver key-value table), the Firefox tap that actually reaches
541
- Pixi 8's EventSystem (the in-page synthetic sequence, measured and documented), and headed
542
- mode. Live-verified on Chrome and Firefox: exact 800x600 viewport, keys delivered, the
543
- Firefox tap advancing a real Pixi page.
544
-
545
- ## [0.29.0] - 2026-10-07
546
-
547
- P37's touch half: the on-screen keyboard. Rows of keys as data, rendered through the
548
- theme's own Button, each tap feeding the same core.Input paths a physical key travels -
549
- dispatchText for a typing key, the new dispatchAction for an action key - so a TextPrompt
550
- cannot tell the two apart. TextPrompt grows a keyboard option that hosts one beneath the
551
- field and resizes the window to fit it, UPPERCASE_KEYBOARD is one shipped default, and
552
- the interface example's Name prompt carries it as the reviewed touch pattern.
553
-
554
- ## [0.28.0] - 2026-10-07
555
-
556
- The 0.27.0 consumer wave sharpened asks: the pixel-dungeon port proposal file
557
- audited what 0.27 shipped against what a real consumer needs, and this release
558
- closes the four framework-side gaps it found. Flights fades and spins in the
559
- units games author (fadeIn: progress, spinDegrees), Beam thins as it fades and
560
- stretches a single art asset along its span with anchor control,
561
- ParticleEmitter.attach gates visibility (fog-of-war) beside emission, and the
562
- interface example carries the reviewed TextPrompt hosting pattern a seed or name
563
- prompt can be copied from.
564
-
565
- ### Added
566
-
567
- - `Flights` fade and spin in the units consumers author them in (P40): `fadeIn:
568
- 'progress'` (or `true`) eases a sprite's alpha 0 to 1 along the flight's own
569
- progress - the tween's clock, so the fade cannot desynchronise from a duration
570
- the caller re-computed - while a number keeps its seconds-from-launch meaning,
571
- and `spinDegrees` is `spin` in degrees per second, converted once, so an
572
- authored angular speed needs no radian arithmetic at the call site.
573
-
574
- - `Beam` thins and stretches (P35): `thin: true` narrows the body with its own
575
- remaining life the way the alpha fades (a plain line's stroke, a strip's height,
576
- a stretched sprite's `scale.y`), and the `texture` option's object form -
577
- `{ source, stretch?, anchor? }` - stretches one art asset along the whole span
578
- instead of tiling it, anchored across the thickness (0.5 by default) for ray
579
- art that repeats badly. The bare-texture form tiles exactly as it always has.
580
-
581
- - `ParticleEmitter.attach` takes a `visible` callback beside `enabled` (P36): a
582
- false return hides the emitter and every particle it has in the air, so a
583
- fog-of-war gate keeps an aura's spray out of unexplored space without the
584
- consumer re-placing `visible` every frame. Drawing only - the simulation
585
- keeps stepping behind the invisibility, emission keeps following `enabled`,
586
- and `detach()` leaves the emitter visible.
587
-
588
- - The interface example's new Name button is the reviewed `TextPrompt` hosting
589
- pattern (P37): push it on a `WindowStack` and it owns typing, caret edits,
590
- confirm-gated-by-`validate`, cancellation and closing - a seed or name prompt
591
- with no DOM `<input>` overlay to copy around.
592
-
593
- ## [0.27.0] - 2026-10-07
594
-
595
- Two strands in one release. A run is durable and drives the AI (roadmap 396-397): the
596
- versioned replay envelope refuses another game or framework build by name, `LastRun` keeps
597
- the newest recording, `runCheckpoint`/`resumeRunPlayer` restore a run mid-run, and the
598
- `file://` plumbing (download, picker, Blob read) ships with it; `imitationFromReplay` turns
599
- a recorded run into training samples against its own seeded environment, `runSeededEpisode`
600
- plays a whole run from a named seed behind any deterministic chooser, and `ai.Suggester`
601
- is the throttled, non-mutating hint source. The render and UI strand: `Flights` owns live
602
- projectile flights, `Beam`/`Beams` draw one-shot beams, `TextPrompt` asks for one line with
603
- IME and screen-reader support, `MessageLog.lastEntries` reads retained entries back, and
604
- `ParticleEmitter.attach` follows a target; `core.FloatSource` narrows the injectable random
605
- stream for float-only helpers.
606
-
607
- ### Added
608
-
609
- - `core.FloatSource` splits `core.RandomSource`: helpers that draw floats only
610
- (`float`, `chance`, `weighted`, `weightedKey`) accept the narrower
611
- `{ float(): number }`, so a float-only stream needs no dead `int`. The
612
- integer helpers (`int`, `range`, `normalRange`, `element`, `shuffle`) keep
613
- requiring the full source; `element` stays wide deliberately, because it
614
- draws through `int()` and re-spelling that draw would change its stream.
615
-
616
- - `MessageLog.lastEntries(n)` reads the newest retained entries back as plain
617
- `{ text, level }` records, oldest first, without scraping rendered children:
618
- entries the wrapped-line budget already dropped are gone, over-count reads
619
- everything retained, and zero or negative reads nothing. The slice lives in
620
- the pure `takeLastEntries` beside the existing `linesToDrop` budget, so the
621
- readback contract is testable without a renderer.
622
-
623
- - `ParticleEmitter.attach(target)` follows a display object or position thunk on
624
- every update tick and every `burst()`, with `offsetX`/`offsetY`, an `enabled`
625
- callback gating tick emission, and auto-detach for destroyed targets;
626
- `detach()` keeps the last position. The follow math is tested headless through
627
- textureless emitters.
628
-
629
- - `Flights` owns a scene's live projectile flights over the existing `Projectile`:
630
- `add(sprite | texture, from, to, { speed, tint?, spin?, fadeIn?, onArrive? })`
631
- returns a handle, `update(dt)` drives positions with per-flight spin and fade,
632
- each arrival dispatches once after leaving the list, and `cancel()`/`clear()`
633
- forget without dispatching. Caller sprites stay caller-owned; texture-built
634
- sprites are parented here and destroyed with their flight.
635
-
636
- - `Beam`/`Beams` draw one-shot beams between two screen points: a fading line by
637
- default, a fading repeating texture strip with `texture`, additive blend unless
638
- opted out, `retarget` for tracking endpoints, and `update` reporting expiry
639
- exactly once so the `Beams` group can remove finished beams itself.
640
-
641
- - `TextPrompt` asks for one line of text over a `TextModel`: typing through
642
- `onText` (the newest open prompt wins), caret and edits through
643
- `left`/`right`/`backspace`/`delete` actions, `confirm` gated by `validate` and
644
- `cancel` giving up. IME compositions preview until they commit, and the
645
- message plus validation errors announce through `screenReader` (assertive for
646
- the errors), with an injectable announcer for tests.
647
-
648
- - A run is durable now (roadmap 396): `exportReplayFile`/`importReplayFile` wrap a
649
- recording in a versioned, self-describing envelope that refuses another game or
650
- framework build by name, `LastRun` keeps the newest recording (one deep, bounded,
651
- over the same storage a save slot uses), and `runCheckpoint`/`resumeRunPlayer`
652
- pair the partial recording with the saved state so a restored run resumes mid-run
653
- instead of restarting - `Recorder` and `Player` both take `fromFrame`, and
654
- `parseReplayEvents` factors out the half of `deserializeReplay`'s check that
655
- validates an already-parsed array. The `file://` plumbing rides along:
656
- `downloadReplayFile` (a Blob download, never `fetch()`), `pickReplayFile`
657
- (the file picker, null on cancel) and `readReplayFile` (any `Blob`, headless
658
- Node included).
659
-
660
- - Replays train and drive the AI (roadmap 397): `imitationFromReplay` walks a
661
- recorded run against the same seeded `TrainingEnvironment` it was played on and
662
- returns the `(observation, action)` samples a game's own trainer fits;
663
- `runSeededEpisode` plays a whole run with any deterministic chooser (a heuristic,
664
- a `NeuralPolicy`'s argmax, not just a `NeuralModel` like `runRollouts`) from a
665
- named seed, recording every chosen action so runs compare across builds and
666
- policies; and `ai.Suggester` is the in-game suggestion mode, the same decision
667
- call pointed at a hint UI instead of the world, throttled by a frame-count budget
668
- and never mutating state to compute a hint.
669
-
670
- ## [0.26.1] - 2026-10-07
671
-
672
- The 0.26.0 follow-up: its Chrome end-to-end test failed on every CI run, so the
673
- `tools/browser-driver` Chrome engine never actually worked on a CI machine (a cold
674
- Windows runner never reached the debugging endpoint in the old budget; an Ubuntu
675
- runner crashed in Chrome's sandbox). Chrome now launches against its own profile,
676
- the endpoint is watched on both output streams with a cold-start budget and a
677
- diagnostic that names what the browser printed, `close` releases the profile and
678
- the stdio pipes only after the child exits, and the CI workflows pass
679
- `--no-sandbox` on Linux through the driver's own `MWG_DRIVER_CHROME_ARGS` channel.
680
- 0.26.0 was tagged before this was known and its npm publish never ran.
681
-
682
- ### Fixed
683
-
684
- - `tools/browser-driver`'s Chrome engine launches against its own profile
685
- (`options.profileDir`, or a temp dir the driver creates and removes on `close`)
686
- instead of the machine's default one, watches both stdout and stderr for the
687
- debugging endpoint (which stream a build prints it on is not something to bet
688
- on), waits up to 30 s instead of 15 (a cold CI machine's first Chrome start can
689
- outrun the old budget), and names what the browser printed when the endpoint
690
- never arrives. This is the fix for the Chrome end-to-end test failing on every
691
- CI run since the driver landed: the default profile on a fresh runner never
692
- reached the endpoint in time. `close` now also destroys the child's stdio
693
- pipes (surviving browser helper processes could hold a suite open past the
694
- browser's own death) and releases the profile only after the child exits.
695
- The failing configuration is now diagnosed, not just reported: the timeout
696
- names what the browser printed. CI's Linux jobs pass `--no-sandbox` through
697
- the driver's `MWG_DRIVER_CHROME_ARGS` channel, since an Ubuntu 23.10+ runner
698
- that disables unprivileged user namespaces is a property of that machine,
699
- not of the tool.
700
-
701
- ## [0.26.0] - 2026-10-07
702
-
703
- The machine-readable surface and the audit tooling around it: `api-surface.json` ships as the
704
- `./api-manifest` subpath (one `{ name, kind, subpath, declaringModule }` row per export), the
705
- blessed `mwg/headless` entry imports every renderer-free module in one line, `tools/audit-adoptions`
706
- checks a consumer's imports and local definitions against that manifest, and the dependency-free
707
- `tools/browser-driver` harness drives real Chrome and Firefox. `core` gained injectable `RandomSource`
708
- streams for every derived helper and the shared square-grid rulers (`chebyshev`, `manhattan`,
709
- `euclidean`, `distance` by `DistanceMetric`), the coverage gate now enforces `two-d/ui` instead of
710
- excluding the whole tree, and the bundle-size baseline is refreshed for the growth those brought.
711
-
712
- ### Added
713
-
714
- - Exported the types a public signature already names: `mwl` move/evolution/matchup
715
- definitions, `core` achievement criteria and hex shape types, particle curve and spawn
716
- area types, screen effect steps, `rpg` route targets, asset loader options, and the
717
- `core.HttpTransport` base class its four clients already extend.
718
-
719
- - `core.NEIGHBOURS4`/`NEIGHBOURS8`/`CIRCLE8` share one frozen square-grid offset table
720
- instead of each module keeping its own: axial, row-major eight, and the clockwise ring
721
- (`roguelike`'s `neighbourOffsets` returns these now); `core.euclidean` is the
722
- straight-line ruler beside `roguelike`'s `chebyshevDistance`.
723
-
724
- - `core.chebyshev` is the king-move ruler beside `euclidean` (a diagonal costs one
725
- step) and `core.manhattan` the orthogonal-step count; `core.distance` measures with
726
- the ruler a `DistanceMetric` names, so a data-authored rule picks its geometry by
727
- name. `roguelike`'s `chebyshevDistance` delegates to `chebyshev` instead of spelling
728
- the arithmetic out again.
729
-
730
- - `api-surface.json` is the machine-readable API surface: one
731
- `{ name, kind, subpath, declaringModule }` entry per export per subpath,
732
- generated by the same `tools/api-report.mjs` pass that maintains
733
- `API_REPORT.md`, shipped in the package behind the `./api-manifest` subpath,
734
- and pinned by `tests/api-manifest.test.ts` (shape and coverage) plus the
735
- existing `--check` (agreement with the declarations). `node
736
- tools/api-report.mjs --diff OLD NEW` diffs two releases' surfaces, and the
737
- report parser no longer drops `export type { ... }` re-export lists.
738
-
739
- - `core.RandomSource` lets every derived helper (`chance`, `element`,
740
- `weighted`, `weightedKey`, `shuffle`, `int`, `range`, `normalRange`) draw
741
- from an injected stream: pass a rule-local `Generator` (or any
742
- `float`/`int` pair) as the trailing `source` and the ambient stream is left
743
- untouched, with identical draws and the same `null` reporting.
744
-
745
- - `node tools/api-report.mjs --diff OLD NEW` lists added, removed and
746
- kind-changed exports between two `api-surface.json` manifests, so a version
747
- bump yields a one-command surface diff.
748
-
749
- - `mwg/headless` is the blessed renderer-free entry: `core`, `simulation`,
750
- `mwl`, `i18n`, `actors`, `world`, `battle`, `roguelike`, `board`, `audio`,
751
- `rpg`, `ai`, `testing` and the two renderer-free asset halves, in one import
752
- with no DOM or WebGL globals. `tests/headless-smoke.test.ts` imports it in
753
- plain Node, walks the reachable graph for a renderer leak, and replays a
754
- seeded scenario through it.
755
-
756
- - `tools/audit-adoptions` (also `mwg-audit-adoptions`) is the shipped consumer
757
- adoption auditor: manifest plus reasons file plus config (type-only
758
- directories, subpath deny-lists, per-pattern import budgets), reporting
759
- unadopted exports, stale reasons, shadowing collisions and config violations
760
- with `file:line` and a non-zero exit.
761
-
762
- - `two-d/pixi-interop` now states the interop-only rationale on each
763
- re-exported primitive's own declaration: every histogram symbol
764
- (`Rectangle`, `Texture`, `Container`, `Sprite`, `Graphics`, `FillGradient`,
765
- `TilingSprite`) already has a facade family, so the note names the
766
- Pixi-typed seam that keeps the raw export, and `tests/pixi-interop-coverage`
767
- pins both halves.
768
-
769
- - `tools/browser-driver` is the dependency-free browser harness: a self-served
770
- static directory on an OS-chosen free port, Chrome over CDP and Firefox over
771
- WebDriver BiDi behind one surface (`goto`/`waitReady`/`tap` at canvas
772
- fractions/`evaluate`/`script`/`screenshot`/`consoleErrors`/`close`), reusing
773
- the `browser-smoke` readiness contract. Verified live on both engines.
774
-
775
- ### Changed
776
-
777
- - The coverage gate now enforces `two-d/ui` instead of excluding the whole tree:
778
- the widget tests the suite already ran carry it (97.3/92.6/94.3 against the
779
- 88/89/82 floors), so the exclusion was stale, and a wildcard also left every
780
- new UI file silently ungated. `EventDialogue` stays excluded as intended, under
781
- its real path (`two-d/ui`, where the old flag pointed at a nonexistent
782
- `two-d/stage` copy), and `SelectionModel` gained a direct contract test that
783
- covers it fully, where before only its embedding widgets exercised it.
784
-
785
- ## [0.25.0] - 2026-10-05
786
-
787
- Framework support for the Pixel Dungeon port's simulation and content proposals: numeric
788
- handle leases for clone-safe commands, journal-free dispatch, one shared random stream for
789
- scene and simulation draws, MWL node-namespace references, and type-safe table rows with a
790
- type-emission helper for game build scripts.
791
-
792
- ### Added
793
-
794
- - `core.Random.active()` returns the ambient generator the free functions draw from, so a
795
- `SimulationRuntime` constructed with it shares one stream with scene code; `snapshot`/
796
- `restore` of that generator replay identical continuations.
797
- - `SimulationRuntime.restore()` accepts `random` to adopt an externally-owned generator
798
- (such as the global one), keeping scene and command draws in lockstep across restore.
799
- - `core.createHandles()`/`Handles` - numeric leases for values a plain-data command cannot
800
- carry, with a scoped `with(value, body)` lease that drops even when the body throws.
801
- - `SimulationRuntime` accepts `journal: null` for a journal-free dispatch facade: no append
802
- cost, an empty journal in `snapshot()`, and plainly documented replay/undo semantics.
803
- - `mwl.MwlTableReference` accepts a node-id namespace target (`references: { node: 'monster' }`),
804
- checking table cells against authored node ids with the same table/row/value report.
805
- - `mwl.typedRows()`/`MwlTypedRow`/`MwlColumnValueType` read table rows through their declared
806
- columns (every field optional, an absent cell omits the key), and `mwl.emitTableTypes()`
807
- emits one named row interface plus one typed accessor per table for a game's build script,
808
- so a changed column type or a removed column fails type-checking at every use.
809
-
810
- ## [0.24.1] - 2026-10-02
811
-
812
- Dependency refresh: Babylon.js 9.29, `@capacitor/cli` held at 8.5.2 so it matches the other Capacitor
813
- packages, and the SBOM and bundle-size baseline regenerated. The global bundle grew 2.5% gzipped
814
- (356504 to 365318 B) from the newer Pixi and Babylon releases, which is accepted.
815
-
816
- ### Changed
817
-
818
- - Updated npm dependencies; `cap:sync` verified against Capacitor 8.5.2 on Android.
819
- - Refreshed `sbom.cdx.json` and `tools/bundle-size.json`.
820
-
821
- ## [0.24.0] - 2026-10-02
822
-
823
- Small neural policies and renderer-free training now share game simulation rules,
824
- with worker batches for larger workloads. A playable maze chase AI lab demonstrates
825
- live controller switching, and chess search keeps the interface responsive.
826
-
827
- ### Added
828
-
829
- - A playable maze chase example with independent player and ghost AI selectors,
830
- random turns, chase rules, path heuristics and a small neural policy trained
831
- without a UI on the same original simulation rules. Includes keyboard and touch
832
- steering, live mode switching, power dots and local-file browser checks.
833
-
834
- - `ai.NeuralPolicy`: validated, dependency-free dense-model inference with shared
835
- weights, legal-action masks, seeded softmax sampling, existing `JavaScriptAI`
836
- behaviour integration and cancellable worker inference batches.
837
- - `simulation.TrainingEnvironment`, `runRollouts` and `runRolloutsAsync`: seeded,
838
- UI-free episodes over game-owned simulation rules, distinct termination and
839
- truncation, bounded trajectories, resumable environment snapshots and worker
840
- batches that reuse a model throughout each episode shard.
841
- - A generated courier example with headless evolution training, resumable trainer
842
- checkpoints, exported browser weights, serial/parallel benchmarks and a `file://`
843
- regression check for frame time, input latency and cancellation of stale results.
844
- - `searchTourneyAsync` returns `rootScores` for choosing among near-best moves using
845
- the same worker search.
846
-
847
- ### Fixed
848
-
849
- - Chess example fuzzy moves now search on workers, with cancellation on reset and
850
- timeout. Clock and memory updates refresh text without rebuilding the board;
851
- worker lanes are capped at four and timeout fallback selects a legal move without
852
- blocking on another search.
853
-
854
- ## [0.23.0] - 2026-09-30
855
-
856
- MIDI humanization and groove tooling (`audio`), plus RPG Maker map details from the MWGP
857
- player: shadow layers, A2 table-edge strips and richer move routes.
858
-
859
- ### Added
860
-
861
- - `TileMap.addShadowLayer`: RPG Maker's per-cell shadow bits (map layer 4) as translucent
862
- quarter-tile quads, editable with `setTile` and left alone by `setCellColor`.
863
- - `AutotileSet.tableEdge` (MV slot 1) and `rpgmTableEdgeCells`: the front-edge strip the engine
864
- draws under an A2 table (`Tilemap._drawTableEdge`), with the engine's rule for which cells
865
- get one (a table tile above, none here, no A3/A4 wall on the ground layer).
866
-
867
- - `MoveRouteStep` covers what RPG Maker routes use beyond the four directions: `{ step: { dx, dy } }`
868
- (diagonals), `{ dir: 'forward' | 'backward' }` (from the mover's facing), `{ turn: 'around' | 'left90' | 'right90' }`,
869
- `{ turn: 'toward' | 'away' }`, and a `target: () => { x, y }` on `toward`/`away` steps for a target
870
- that keeps moving (`RouteTarget`).
871
- - MIDI humanization: `humanizeMidi` and `HumanizerFactory` run one shared pass that moves note
872
- events and nothing else (tempo, program, controller and meta events pass through untouched,
873
- note durations survive, `intensity: 0` reproduces the input exactly, a `seed` reproduces a
874
- run, and nothing lands before tick 0) under either shipped engine. `LiteHumanizer` shakes
875
- timing and velocity with gaussian noise over a seeded gradient drift, scaled by `style`, and
876
- holds the kick and the lowest notes near their slots; `GrooveHumanizer` applies a
877
- `GrooveTemplate`'s per-slot offsets and velocities instead, converted through the file's own
878
- tempo map (a mismatch reports itself through `onWarn`) and accenting local melody peaks. The
879
- `'magenta'` tier stays in the API and throws naming what it needs, since neither
880
- `@magenta/music` nor a PerformanceRNN checkpoint can be fetched from a `file://` build, and
881
- `MidiPlayer.create(file, { humanize })` humanizes before it schedules.
882
- - `GrooveExtractor` builds a `GrooveTemplate` three ways, each reduced to the median of each
883
- slot's deviations: a played pass against a straight one (matching within half a slot), a
884
- single file projected onto its own implied grid, or an `AudioBuffer` (hand-rolled spectral
885
- flux onset detection, no analysis dependency, tempo as an argument because a recording
886
- carries none). `GrooveConverter` round-trips a template through JSON exactly and through a
887
- Standard MIDI File within a tick and a hundredth, with the MIDI path enforcing its anchor
888
- and velocity bounds rather than rounding past them and reading back with a dedicated parser
889
- for the metas `parseMidi` drops; `ableton-agr` and `reaper-groove` are named in the format
890
- union and throw as not shipped. `subdivisionCount`/`assertGrooveTemplate` are the invariants
891
- both the extractor and the converter run on.
892
-
893
- ### Fixed
894
-
895
- - `RPGM_FLOOR_AUTOTILE_TABLE[46]` had the wrong bottom-left quadrant (`[0, 3]`, the engine has
896
- `[0, 5]`), so shape 46 of every floor-table kind, A4 `mixed` wall tops included, drew a stray
897
- corner.
898
-
899
- ## [0.22.0] - 2026-09-29
900
-
901
- Audio and event-runner asks from the MWGP player, plus the small widgets the Pixel
902
- Dungeon port was carrying (roadmap item 392): a message log, liquid and fog layers, a
903
- window zoom fit, a Java-compatible random generator, and native A4 autotiles.
904
-
905
- ### Added
906
-
907
- - Item 392, the small widgets the Pixel Dungeon port and the MWGP player were carrying:
908
- `two-d/ui.MessageLog` (coloured, line-capped message pane, with `linesToDrop`),
909
- `fitWindowZoom`/`sharpenText` (window zoom fit and crisp text under a zoomed container),
910
- `two-d/render.LiquidLayer` (scrolling liquid cells with ripples), `FogLayer`/`paintFogPixels`
911
- (smooth sub-tile fog), `TileMap.stampRect`, `AutotileSet.mode: 'mixed'` (the MV A4 sheet's
912
- floor and wall rows on one native autotile layer; the default for A4 stays the wall table),
913
- and `core.JavaRandom` (`java.util.Random` bit for bit, with a draw trace).
914
- - `rpg.EventRunnerOptions.onUnknownCommand`: called for any command the runner has no
915
- handler for, and for a `goto` in a straight `run()` (which then ends the list rather
916
- than throwing), so a converter's dropped commands can be made loud instead of silent.
917
- - `audio.parseVorbisLoopTags`/`loopRegionFromTags`: read the `LOOPSTART`/`LOOPLENGTH`
918
- comments of an Ogg Vorbis file (a bounded page walk, null on malformed input) and turn
919
- them into the `LoopRegion` a bus loader returns.
920
- - `audio.AudioBus.setMixer`/`mixer`: a per-kind (BGM, BGS, ME, SE) volume and mute on top
921
- of each track's own volume; snapshots keep reporting the level the game asked for.
922
-
923
- ### Changed
924
-
925
- - MIDI rendering voices pitch bend: each note is bent by the amount in effect when it
926
- starts (two semitones either way). `ScheduledNote.bend` carries it and is absent when the
927
- channel is centered, so files without bends render bit-identically.
928
-
929
- ### Fixed
930
-
931
- - `Label` ignores `setText`, `setColor` and the reveal calls after `destroy()`, which
932
- used to throw from Pixi's text update on the released texture (the confirm-spam
933
- `_getFinalPadding` error seen on a choice loop).
934
-
935
- ## [0.21.0] - 2026-09-27
936
-
937
- A tournament chess engine beside the small deterministic one, a playable options
938
- panel around it, and the missing standard form controls: radio groups, multiline
939
- text, and multi-select lists.
940
-
941
- ### Added
942
-
943
- - `board` bitboards: the chess rules on twelve 64-bit boards (`startingBitboard`,
944
- `bitboardFromChess`, `bitboardMoves`, `makeMove`/`unmakeMove`, `perft`), the mutable
945
- board the tournament engine will search. Differential tests keep it in agreement
946
- with `chess.ts`, and perft matches the published node counts.
947
- - `board.probeBook`/`parseUciMove` look a position up in a compiled opening book (ECO,
948
- name and UCI continuations) and read UCI moves back; `tools/compile-openings`
949
- (`mwg-openings`) builds the book from vendored CC0 tables, so the framework ships
950
- the probe and no table.
951
- - `board` tournament search: `searchTourney`/`searchTourneyAsync` over one
952
- self-contained `tourneyThink` task (negamax alpha-beta with PVS, null-move pruning,
953
- late-move reductions, iterative deepening with aspiration windows, a bounded Zobrist
954
- table, quiescence, hash/MVV-LVA/killer/history ordering, in-house piece-square
955
- evaluation), beside the small deterministic `board/Engine`, which the minigame path
956
- keeps.
957
- - `board` tablebases: `probeTablebase`/`loadTablebaseEnding`/`tablebaseId` plus the
958
- `huffEncode`/`huffDecode` codec, with WDL-plus-distance 3-piece endings compiled
959
- under `data/tablebases`; `tools/build-tablebases` (`mwg-tablebases`) generates and
960
- verifies 3-to-4-piece endings in parallel over `threads.spawn`.
961
- - `tools/play-uci` (`mwg-uci`): a UCI adapter over book, tablebase and tournament
962
- search for GUIs and rating runs, a Node tool never in the browser bundle.
963
- - `two-d/ui` form controls: `RadioGroup` (exactly one choice among several, arrows
964
- select at once), multiline `TextModel` (real newlines with row navigation and a
965
- sticky goal column; single-line fields strip them), and multi-select `ListView`
966
- (`multiple` checks rows instead of picking one).
967
-
968
- ### Changed
969
-
970
- - The chess example plays through the tournament engine (`board.searchTourneyAsync`,
971
- worker-parallel with a bounded synchronous fallback), with a thinking indicator,
972
- play-as-black, engine depth choice, a promotion picker, an in-check highlight, and
973
- arrow keys that move the cursor the way the board points.
974
- - The chess example gains an options panel: checkboxes for play-black, fuzzy moves,
975
- pondering, blitz clock, opening book and WDL tables, a FIDE time-control slider, a
976
- live search readout (depth reached, score, nodes, best line, opening name, clocks,
977
- workers and memory), a concede button, and a new-game offer at game over. The
978
- webpage Examples page shows the stronger game with its keys documented.
979
-
980
- ## [0.20.0] - 2026-09-27
981
-
982
- Long synchronous work leaves the main thread: a new worker runtime runs self-contained
983
- functions on a blob worker in the browser and on worker threads in Node, the offline
984
- MIDI render and the chess search each gain an async twin on top of it, and the
985
- build-time compressor works files in parallel.
986
-
987
- ### Added
988
-
989
- - `threads.spawn` runs a self-contained function on a worker thread: a blob worker under
990
- the shipped `file://` CSP in the browser, `node:worker_threads` in Node, one worker per
991
- task with transferable results, a failure that rejects instead of hanging, and `timeout`
992
- / `AbortSignal` cancellation. Off the root barrel: `@datamoc/mw_games/threads`.
993
- - `audio.renderMidiToBufferAsync` renders raw MIDI bytes (and optional raw SoundFont bytes)
994
- on a worker thread, so the seconds a real track costs no longer freeze the caller's
995
- thread; the result is bit-identical to `renderMidiToBuffer`, because both paths call the
996
- same render function.
997
- - `tools/compress-dist` compresses files in parallel over async `zlib`, with the lane
998
- count from `MWG_COMPRESS_JOBS` (else the machine's thread count, else 4) or the new
999
- `jobs` option; rows keep walk order, so the report is identical at any lane count.
1000
- - `ai.rootSplits`/`ai.firstWins` are the root-split halves of an off-thread search: the
1001
- split pairs each root move with its child in game order, first-wins reduces scored
1002
- moves keeping the earlier move on ties.
1003
- - `board.searchAsync` scores each chess root move on a worker thread and combines the
1004
- scores first-wins, so the 90 ms a depth-3 search costs no longer drops the caller's
1005
- frames; inside the node budget it chooses exactly the move `search` returns, past it
1006
- (or when cancelled) it resolves `{ move: null }` the same way.
1007
-
1008
- ## [0.19.0] - 2026-09-26
1009
-
1010
- A game that plays five instruments no longer ships all 128: the audio module learns which
1011
- programs its MIDI files actually use and writes a smaller SoundFont carrying only those.
1012
-
1013
- ### Added
1014
-
1015
- - `audio.collectSoundFontUsage` lists the (bank, program) pairs scheduled notes request
1016
- across MIDI files, with drums mapped to bank 128 the way the renderer maps them.
1017
- - `audio.subsetSoundFont` writes a smaller, valid SoundFont 2 file carrying only the used
1018
- programs, with zones, ranges, tuning, envelopes and sample loops copied verbatim and
1019
- every index remapped, so a compiled game ships just the samples it plays.
1020
-
1021
- ## [0.18.0] - 2026-09-25
1022
-
1023
- ### Added
1024
-
1025
- - `audio.parseMidi` keeps program-change, control-change and pitch-bend events and reports
1026
- the controller-111 loop marker as `loopStartTick`; `scheduleMidi` notes carry their channel
1027
- voice (`MidiVoice`: program, bank, gain, pan) and `midiLoopStart` resolves the marker to seconds.
1028
- - `audio.renderMidiToBuffer` renders a parsed MIDI file to stereo PCM frames, offline and
1029
- deterministic, voiced by an optional game-supplied `SoundFont` or the built-in waveform
1030
- synth, with the loop region attached.
1031
- - `audio.parseSoundFont` reads SoundFont 2 bytes into layered preset voices.
1032
- - `audio.Channel` (a seekable buffered WebAudio voice with volume, pitch, pan and a loop
1033
- region) and `audio.AudioBus` (independent BGM/BGS loops, ME jingles that suspend and resume
1034
- the BGM, overlapping SE one-shots, save and replay with playheads, plain-data snapshots).
1035
- ## [0.17.1] - 2026-09-25
1036
-
1037
- ### Fixed
1038
-
1039
- - A page built on a Windows checkout refused its own inline script. The HTML parser turns
1040
- newlines into LF before it hashes an inline script, while `contentSecurityPolicy` hashed the
1041
- CRLF bytes a `core.autocrlf=true` checkout hands over, so Chrome computed a different hash
1042
- from the one the policy allowed. The page logged a Content-Security-Policy violation that
1043
- `mwg-smoke`, the visual smoke and `mwg-bench` read as a page error, the source-page fallback
1044
- script never ran, and the same build on Linux stayed quiet - which is why no browser job had
1045
- caught it. Inline scripts are now hashed after CRLF and lone CR become LF; the standalone
1046
- page's unpacker scripts stay hashed as written, since no parser touches those. A CRLF
1047
- checkout and an LF checkout now produce the same policy, pinned by a test.
1048
- - The committed-artifact checks no longer read the checkout's line endings. `api:check`,
1049
- `stats:check`, `sbom:check` and the committed-SBOM test compared generated text against the
1050
- committed file byte for byte, so a Windows clone failed them on a tree `git diff` called
1051
- clean; `bundle.distRaw` summed the bytes `tsc` copies out of a source file's comments, which
1052
- recorded who generated the file rather than what ships.
1053
-
1054
- ### Changed
1055
-
1056
- - The `check` job runs on `windows-latest` alongside `ubuntu-latest`, so the two failures above
1057
- fail the push instead of reaching a Windows contributor. The gates themselves are unchanged,
1058
- and `fail-fast` is off so one OS failing still shows the other.
1059
-
1060
- ## [0.17.0] - 2026-09-25
1061
-
1062
- ### Security
1063
-
1064
- - One inbound pipeline, on by default (item 372). `core.parseInbound` runs the size cap,
1065
- the control-character check and a `JSON.parse` that refuses `__proto__`/`constructor`/
1066
- `prototype` at any depth. `SaveSystem.load`/`list`/`importSlot`, `Collection`, the stored
1067
- values behind `PlayerStats`/`RunHistory`/`NewsSeenTracker`, `Settings`, `NewsClient` and
1068
- `LockstepClient` all use it, with no call for a game to add. The reason: under `file://`,
1069
- Chromium shares one `localStorage` between every local page, so any HTML file opened on
1070
- the same machine can read or rewrite a game's saves. `load` now returns `null`, and `list`
1071
- skips the slot, for a tampered or malformed slot (a corrupt slot used to make `list`
1072
- throw). `importSlot` checks the `meta` shape and throws a named error.
1073
- `LockstepClient` caps server messages at `maxMessageBytes` (1 MB), type-checks `welcome`/
1074
- `tick`/`rejected`, and reports anything else on the new `onProtocolError` signal instead of
1075
- throwing out of `onmessage`. An unknown message type, which was silently ignored, is
1076
- reported there too.
1077
- - The Lua host bounds memory, not only instructions (item 373): `memoryLimit` (32 MB by
1078
- default, also accepted by `LuaAI`) charges every string and buffer a call allocates, so
1079
- `string.rep("x", 2^28)` or a doubling `s = s .. s` loop fails with "Lua memory limit
1080
- exceeded" in milliseconds instead of allocating hundreds of megabytes and freezing the tab.
1081
- A script-level `pcall` cannot swallow it. `getmetatable("")` no longer exposes the string
1082
- library.
1083
- - Every page `emitPage` finishes carries a Content-Security-Policy (item 374), so every
1084
- example and every game built through `mwgPage()`/`mwg-emit` gets it with no configuration:
1085
- `default-src 'none'`, scripts from the page's own folder plus hashes of its inline scripts
1086
- (including the scripts a compressed standalone page unpacks), images/fonts/media from
1087
- `data:`/`blob:` only, and `connect-src` limited to `data:`/`blob:` plus the origins a game
1088
- declares (`csp: { connect: [...] }`). Measured in Chromium from `file://`: a `fetch`, an image
1089
- beacon, a remote script and an injected inline script are all refused, and all 22 examples
1090
- and both standalone variants still start. `'unsafe-eval'` stays allowed, because Pixi 8
1091
- refuses to start without it unless the game imports `pixi.js/unsafe-eval` (`eval: false`
1092
- then drops it). `csp: false` leaves the policy out.
1093
- - Transport defaults (item 375): `FeedbackClient`, `NewsClient`, `SaveSyncClient`,
1094
- `TelemetryClient` and `LockstepClient` throw at construction for an `http:`/`ws:` url to
1095
- anything but this machine, unless `allowInsecure: true`. Response bodies stream through
1096
- `maxResponseBytes` (10 MB), checked against `content-length` first and cancelled as soon as
1097
- they pass it. `SaveSyncClient.download`/`list` parsed their JSON envelope with a bare
1098
- `response.json()`; they now go through `parseInbound` like every other reader.
1099
- - The reference lockstep server could be stopped by any one client (item 385): `ws` reports
1100
- an oversized or malformed frame as an `error` event on the socket, and with no listener that
1101
- event threw and ended the process, every room with it. It now has a listener, caps messages
1102
- at `maxMessageBytes` (64 KB, where `ws` accepted 100 MiB), reads them through `parseInbound`
1103
- (an input carrying `__proto__` counts as missing), closes a connection naming an invalid
1104
- room (1008) or a full one (`maxClientsPerRoom`, 64; 1013).
1105
- - `TelemetryClient` bounds what leaves the machine (item 378): strings (event name, property
1106
- names and values) are cut at `maxStringLength` (256), at most `maxProperties` (32) are sent,
1107
- and `allowedProperties`, when given, drops every other name. A path or an error message
1108
- passed by mistake leaves as a bounded fragment.
1109
- - README and `SaveSystem`'s doc state the rule item 377 settled on: under `file://`, any local
1110
- page shares a game's `localStorage`, so nothing in a save is private and no secret belongs
1111
- there.
1112
- - CI hardening (item 379): every GitHub Action is pinned to a commit SHA (the tag kept as a
1113
- comment), `ci.yml` and `benchmark-browser.yml` run with a read-only token, and Dependabot
1114
- keeps both the action pins and the npm dependencies current. `tests/workflows.test.ts`
1115
- fails on an unpinned action or a workflow without `permissions`.
1116
- - `extract-rgssad` wrote each entry to `path.join(outDir, name)` with the name taken from the
1117
- archive, so a crafted entry (`../x`, or `..\x` on Windows) could write outside the output
1118
- folder. Entry names are now normalised and refused unless they resolve inside it (item 389).
1119
- - Seeded fuzzing of every decoder that reads outside input (item 376) found four defects, all
1120
- fixed: `mwl.parseExpression` overflowed the stack on 13 000 nested parentheses (now bounded at
1121
- 256 levels and 4096 operators, which also bounds `evaluateExpression`'s recursion, and it no
1122
- longer copies the rest of the source for every token); `parseMapFile` trimmed lines with a
1123
- backtracking `/[,\s]+$/` that took a second on 28 000 spaces; `parseTerrain` spread every row
1124
- into `Math.max`, which overflows past about 100 000 rows, and had no size bound (now 1024x1024
1125
- cells); and `rpg.decodeMarshal` overflowed the stack on nested arrays (now 1000 levels).
1126
-
1127
- ### Added
1128
-
1129
- - The build step a game needs, shipped (item 381): `@datamoc/mw_games/tools/vite`'s
1130
- `mwgPage(options)` plugin makes `vite build` alone produce a page that opens from
1131
- `file://` (IIFE `game.js`, `base: './'`, `assets/` served in dev and compiled into the
1132
- build, raw copies left out, optional `singleFile`/`compress`/`toWebp`).
1133
- `@datamoc/mw_games/tools/emit-page` exports the underlying `emitPage(options)`, which every
1134
- example here still uses through its command line. The getting-started page's step 10 is
1135
- now that one plugin line; it used to tell users to make the edit by hand.
1136
- - `mwg-size dist` (`@datamoc/mw_games/tools/bundle-size`, item 386): the size budget this
1137
- repository gates its own build with, for a game's build. Every file a player receives, raw and
1138
- gzipped, plus the total, against `size-budget.json` (written on first run or with `--update`),
1139
- failing past `--tolerance` (2 %).
1140
- - `mwg-bench <page | dist>` (`@datamoc/mw_games/tools/benchmark-browser`'s `measurePage`, item
1141
- 387): a game's own frame-rate gate in headless Chrome, with mean fps, 95th-percentile frame
1142
- time, an optional history compared against its best run, and the software-WebGL switch for a
1143
- runner with no GPU.
1144
- - `@datamoc/mw_games/testing` (item 388): `memoryStorage`, `fakeAudio`/`fakeAudioWithEnded`,
1145
- `FakeSocket`, `fakeFetch` and `fakeGamepad`, the doubles for the seams mwg takes by injection. Off the root
1146
- barrel, renderer-free. This repository's own tests now use them, which removed twelve copies
1147
- of the same in-memory storage, six of the same fake audio element, two fake sockets and two fake gamepads.
1148
- `core.MemoryStorage`, the fallback `defaultStorage()` already used, is exported.
1149
- - Two developer tools ship (item 389): `mwg-placeholder-assets <folder>` writes the generated,
1150
- licence-free placeholder set the examples use (refusing to overwrite without `--force`), and
1151
- `mwg-extract-rgssad <archive> <outDir>` unpacks an RPG Maker XP/VX archive through the
1152
- vendored MIT decoder, now in the package with its licence.
1153
- - The translation editor ships (item 384): `npx mwg-i18n <base> <target> [--check]`
1154
- (`@datamoc/mw_games/tools/i18n-edit`) runs from an installed package, loading `dist` there
1155
- and the TypeScript sources inside this repository, so a game's CI can gate its translations
1156
- with `--check`.
1157
- - The reference lockstep server ships (item 385): `npx mwg-lockstep-server [port]
1158
- [--host=]` (`@datamoc/mw_games/tools/multiplayer-server`), with `ws` an optional peer. The
1159
- command listens on 127.0.0.1 unless `--host` says otherwise.
1160
- - CycloneDX SBOMs for a game (item 380): `mwgPage()` writes `dist/sbom.cdx.json`, the SBOM
1161
- of what the build ships (the packages vite's module graph put in the bundle, with versions
1162
- and licences, and every shipped file with its SHA-256; `sbom: false` skips it). For a small
1163
- consumer project, 8 packages and 3 files, where its lockfile lists 60 components.
1164
- `mwg-sbom [folder]` (`@datamoc/mw_games/tools/sbom`) writes the lockfile SBOM of any
1165
- project, an `application` when the project is `private`. The framework's own
1166
- `sbom.cdx.json` now ships in the package.
1167
- - `mwg-smoke <page | dist>` and `@datamoc/mw_games/tools/browser-smoke`'s `smokePage` (item
1168
- 383): a game's CI can prove its build still opens from `file://` (no page error, a ready game
1169
- on a WebGL/WebGPU canvas, non-blank pixels, a screenshot), exiting non-zero otherwise.
1170
- `playwright-core` is an optional peer. The Chrome lookup now also finds the newest Chromium
1171
- Playwright installed, whatever its revision, and knows the macOS install paths, so a
1172
- container or CI image no longer needs `CHROME_PATH`.
1173
- - `bin` entries (item 382): `mwg-emit <folder> [--dist=] [--assets=]` and `mwg-mwl`, so `npx`
1174
- runs them instead of a `node node_modules/...` path.
1175
- - `core.cloneData`/`core.uncloneablePath` - `structuredClone` whose failure names the first
1176
- value that cannot be copied and where it sits (`action.target.reactions.rules[0].when`),
1177
- plus that path lookup on its own for a game to assert its commands are plain data.
1178
-
1179
- ### Fixed
1180
-
1181
- - `SimulationRuntime.dispatch` committed a command's state and scheduler cost before
1182
- journalling it, so a command that could not be copied (one carrying a live actor that owns
1183
- a `ReactionTable`, say) threw a bare `DataCloneError` after the turn had already
1184
- happened. It now copies the event batch, the command and (with `history`) the checkpoint
1185
- state first, and on failure throws a `TypeError` naming the path and restores the random
1186
- stream, leaving state, scheduler and journal untouched. The plain-data contract for
1187
- `Command`, `Event` and `State` is now stated on the class.
1188
- - `ActionJournal.append` stored the caller's action object by reference, so mutating it
1189
- afterwards rewrote history; the action is now copied like the events, and a refused
1190
- append no longer consumes a sequence number.
1191
- - `Campaign.completeCurrent` assigned the carried-over state before copying the level's
1192
- result, so a result that could not be copied left the new state applied and the result
1193
- missing. Both are copied first now. `CanonicalState`, `StateRegistry`, `Campaign`,
1194
- `runHeadlessScenario` and the MWL save reader copy incoming values through
1195
- `core.cloneData`, so a non-data value names its path there too.
1196
-
1197
- ## [0.16.0] - 2026-09-19
1198
-
1199
- ### Added
1200
-
1201
- - First-class autotile layers on `TileMap` (item 370): `addAutotileLayer` takes raw
1202
- MV tile ids or XP tile values plus one `AutotileSet` per family slot (MV) or image
1203
- index (XP), and the map assembles each cell's quadrant halves straight from the
1204
- source sheet, no prebuilt atlas canvas in between. `setAutotileFrame`/
1205
- `getAutotileFrame` advance and read the animation frame (MV kind cycles, XP frame
1206
- stripes, wrapping); `setTile`/`getTile` keep working with raw ids. The standard MV
1207
- floor/wall shape tables ship as `RPGM_FLOOR_AUTOTILE_TABLE`/
1208
- `RPGM_WALL_AUTOTILE_TABLE` with the family address facts
1209
- (`RPGM_AUTOTILE_SLOT_BASES`/`RPGM_AUTOTILE_SLOT_COUNTS`, `rpgmAutotileSlot`), and
1210
- the XP side ships `XP_AUTOTILE_PATTERNS`/`XP_NEIGHBORS_TO_PATTERN` with
1211
- `xpAutotileRef` (baked cells) and `xpAutotilePattern` (procedural neighbourhoods);
1212
- `autotileCellParts`/`assertAutotileLayout` resolve and validate one cell
1213
- renderer-free.
1214
-
1215
- ## [0.15.0] - 2026-09-19
1216
-
1217
- ### Added
1218
-
1219
- - `mwl.MwlTableReference` and `MwlValidationOptions.tableReferences` - declarative
1220
- cross-table reference checks (item 362, from the Pixel Dungeon study's proposal P21). A
1221
- table column declares `references: { table, column }` or `oneOf: [...]`, and
1222
- `validateCatalog` checks every cell once for all tables, reporting `MWL_TABLE_REFERENCE`
1223
- with the table, the row, and the offending value. The declarations' contents (which column
1224
- points where, which set is legal) stay game data in the consuming repository; absent or
1225
- empty cells are skipped and a `list` cell checks each entry under the table's own
1226
- delimiter.
1227
-
1228
- - `core.Settings`/`GameSettings`/`SettingsOptions`/`CustomSettingValue` - persisted
1229
- player settings (item 363): music and sound-effect levels, master mute, zoom
1230
- preference, key bindings applied to `Input` on load, and a game-defined `custom` bag
1231
- (`hints`, `violence`, ...). `defaultSettings` names the fresh-game values,
1232
- `effectiveMusicVolume`/`effectiveSfxVolume` read 0 while muted, and corrupt storage
1233
- reads as defaults.
1234
-
1235
- - `two-d/ui.SettingsScreen`/`SettingsCustomRow` - a ready-made settings screen over
1236
- `core.Settings` (item 364): music/sfx sliders, mute checkbox, zoom slider, one row
1237
- per `custom` descriptor (boolean/number/choice), an embedded controls page that
1238
- writes rebinds back into `Settings` on exit, and a reset row.
1239
-
1240
- - Auto-pause and auto-mute on page hide (item 365): `Game` suspends the loop and
1241
- silences its `audio` rig while hidden and resumes both on show (`autoPause`, on by
1242
- default), via `suspend`/`resume` that park the clock at 0 and route through the top
1243
- scene's `onSuspend`/`onResume`. `Music`/`Sound`/`Orchestrator` gain matching
1244
- `suspend`/`resume`, and the player's own mute setting is never touched.
1245
-
1246
- - Frame-time quality scaling over the static device fit (item 366): a `QualityScaler`
1247
- steps the backing-store ratio down after sustained over-budget frames and back up
1248
- only after a much longer streak inside budget, wired to `Game` via the
1249
- `qualityScaling` option (off unless given) with the fitted ratio as its ceiling.
1250
-
1251
- - Audio ducking for dialogue and menus (item 367): `Music.duck` glides to an
1252
- attenuated level until `unduck`, through the existing fade path, with tracks started
1253
- while ducked starting ducked and pending fades retargeted. `Sound` is untouched.
1254
-
1255
- - A discrete meter widget, `two-d/ui.Meter` (item 368): N icons with a value filled,
1256
- the heart row or star rating to `Bar`'s continuous fill. Fractions clip mid-icon
1257
- through a mask, so halves need no extra art; flat theme pips by default, a
1258
- game-supplied filled/empty texture pair otherwise.
1259
-
1260
- - Animate only what is on screen, `two-d/render.SpriteGroup`/`isOnScreen` (item 369):
1261
- `update(camera, dt)` advances the members inside `camera.view` (plus `margin`) and leaves
1262
- the rest on their current frame. Members are `AnimatedSprite`s, `ParticleEmitter`s, or
1263
- anything with `x`/`y` in world units plus `update(dt)`; skipped members resume where they
1264
- left off, and a rotated camera tests the same over-inclusive box `TileMap.cull` uses, so
1265
- nothing visible ever freezes.
1266
-
1267
- ## [0.14.0] - 2026-09-15
1268
-
1269
- ### Added
1270
-
1271
- - `core.cellInside`/`cellIndex`/`cellX`/`cellY`/`cellKey`/`cellFromKey` - bounded-grid
1272
- indexing as one statement of the row-major convention, asked for by the Wesnoth port's own
1273
- MWG backlog ("primitives `inside`, `cellIndex` and coordinate keys", with the exit criterion
1274
- "no more duplicated indexing in the game systems; out-of-bounds tested"). The framework had
1275
- four private copies of exactly these two lines (`roguelike.Level`, `board.Classics`,
1276
- `board.FogOfWar`, `board/HexSkirmish`); all four now forward to the shared functions and
1277
- keep their own out-of-bounds policy, which is what differs between them: `Classics` still
1278
- throws, `FogOfWar` still answers `-1`, and `Level`'s public shape is unchanged. `cellIndex`
1279
- itself is deliberately unchecked arithmetic so a hot loop pays nothing for a check it has
1280
- already done, and `cellKey`/`cellFromKey` are the `'x,y'` spelling a `Map`/`Set` wants, which
1281
- consumers were each inventing for themselves (item 361).
1282
-
1283
- - `tools.md`'s "Packaging as a native app" section now covers the mobile (Capacitor/Android)
1284
- target beside the desktop one: the two toolchain prerequisites that stop a clean machine (JDK
1285
- 21 with `JAVA_HOME`, an SDK that Gradle can find), the five commands from a game's own folder
1286
- to an installed app on a device, and the three things the generated project gets wrong once and
1287
- never revisits. Each was reproduced rather than restated: the `.gz`/`.br` sidecars break the
1288
- asset merge (`mergeDebugAssets FAILED ... Duplicate resources`), `ignoreAssetsPattern` gaining
1289
- `:!*.gz:!*.br` clears it, and an unchanged `versionCode` refuses the second install
1290
- (`INSTALL_FAILED_VERSION_DOWNGRADE`). Finishes what item 351 left as a scaffold-only
1291
- verification and P18 asked for (item 357).
1292
-
1293
- - Package subpaths for the three shipped `tools/*.mjs` helpers a game imports as a library -
1294
- `./tools/classic-html`, `./tools/extract-html` and `./tools/single-file` - beside the three
1295
- that already had one. An `exports` map blocks every deep path it does not name, so naming
1296
- three of the seven shipped helpers left the other four unimportable outright:
1297
- `import { toClassicScript } from '@datamoc/mw_games/tools/classic-html'` failed with
1298
- `ERR_PACKAGE_PATH_NOT_EXPORTED` even though the file ships, pushing a consumer to hardcode a
1299
- `node_modules/@datamoc/mw_games/...` path that stops existing the moment the package is
1300
- installed under an npm alias. `tools/classic-html.mjs`'s own `@example` showed the
1301
- `.mjs`-suffixed spelling, which is exactly what the map refuses; it now shows the specifier
1302
- that resolves. `tools/mwl.mjs` deliberately keeps no subpath: it reads its arguments and
1303
- dispatches at import time, so one would make importing it run the CLI. Its library half,
1304
- `@datamoc/mw_games/mwl`, is the typed, already-exported entry point. `tests/package-tools.test.ts`
1305
- holds all of that (item 358).
1306
-
1307
- ### Changed
1308
-
1309
- - `desktop/MwgDesktopHost` loads the built game page named as its first argument instead of
1310
- only this repository's own `tower-defense` example, and a page it cannot find is reported in
1311
- a dialog naming what it looked for rather than an unhandled `FileNotFoundException`. With no
1312
- argument it still walks up to the example, so `npm run desktop:run` is unchanged. This is what
1313
- makes the reference host usable by a game that merely *uses* `mwg`: the published package
1314
- ships no packaging scaffold at all (`files` excludes `desktop/`, and every `desktop:`/`cap:`
1315
- script is repo-relative), so such a game copies the host's two files rather than installing
1316
- them. The consumer recipe is now written up, with the `dotnet publish` line and the
1317
- `--no-compress` requirement a native build needs, in `tools.md`'s new "Packaging as a native
1318
- app" section, in `desktop/README.md`, and as an optional step 11 of the getting-started page;
1319
- README's status note says where the packaging lives, and stops claiming v0.7.7, instead of
1320
- leaving the distance between its claim and the package for a consumer to discover. The mobile
1321
- (Capacitor) half of the same recipe followed as item 357, in the same section of `tools.md`.
1322
-
1323
- - `Game` keeps the renderer's resolution inside what the device reports it can make. The canvas
1324
- was sized to `window x devicePixelRatio` whatever the viewport, and a backing store past the
1325
- GPU's `MAX_TEXTURE_SIZE` is refused by WebGL *silently*, by clamping the drawing buffer: the
1326
- game carries on rendering into a surface that is not the one it asked for, and nothing is
1327
- reported anywhere. A full-window 816x1812 canvas at `devicePixelRatio` 2.625 asks for
1328
- 2121x4709, which a device reporting a 4096 limit answered with a 2121x4096 buffer (item 360).
1329
- That process also painted an entirely black screen, and that is *not* attributed here: the
1330
- failure never reproduced (every later run of the same emulator reported 8192) and a
1331
- deliberately clamped 1050x10500 request rendered correctly, so the black screen has no cause
1332
- recorded against it. What stands on its own is the clamped request the game never made. The
1333
- resolution is now reduced to the largest whole number that fits, with a warning naming the
1334
- limit, and re-fitted on rotation and on a `devicePixelRatio` change; a device that can afford
1335
- what it asked for is untouched.
1336
-
1337
- - `ROADMAP.md`'s one open 1.0 exit-checklist line (both reference ports complete and playable)
1338
- was corrected and its framework half tested, since the premise it was written on had gone
1339
- stale. It named a `mwg-wesno` directory that was never used: the Wesnoth port is `mwg-wesnoth`
1340
- inside a Wesnoth source checkout, and it was pinned at mwg 0.9.0, so it had never been tested
1341
- against this release. With 0.13.0 placed in its install for both names it imports, that port
1342
- typechecks, passes all 334 of its tests, builds (124 MB `dist/game.js`) and passes its own
1343
- headless-browser verification with `"errors": []`; the Pixel Dungeon port, already on
1344
- `^0.13.0`, builds and plays in a browser. Neither port's README claims completeness, so the
1345
- line stays unchecked with that evidence recorded beside it.
1346
-
1347
- ### Fixed
1348
-
1349
- - `tools/single-file.mjs`'s `output` is now documented and enforced as a file *name* written
1350
- inside `dist`. An absolute path used to be joined onto `dist` and fail later inside
1351
- `writeFile` with an `ENOENT` naming a doubled-up path; a value containing a separator is now
1352
- refused up front with an error naming the argument and the value, since the argument is what
1353
- was wrong. `tools/single-file.d.mts` and `tools/compress-dist.d.mts` gained the prose their
1354
- `.mjs` counterparts had and their declarations did not: `output` is a name, not a path,
1355
- `compressDist`'s `dir` is rewritten in place (its `.gz`/`.br`/`.xz` siblings appear inside it,
1356
- originals untouched), and each result field's meaning is stated, including that an unwritten
1357
- sibling reports 0 rather than being absent (item 359).
1358
-
1359
- ## [0.13.0] - 2026-09-15
1360
-
1361
- ### Added
1362
-
1363
- - `core.parseDialogueLines`/`DialogueLine` and `core.parseTwee`/`TweeCommand`/`TweeChoice`/
1364
- `TweeStory` - the two-speaker `@id`/`-` dialogue-text state machine and the Twee-notation
1365
- passage/link parser, each shared by a `two-d/stage` and an `rpg` wrapper (`parseDialogueText`,
1366
- `importTwee`) rather than copied between them, the same precedent `core.parseCSV` already
1367
- set for a generic text-format parser other modules build a typed result around.
1368
- `TweeCommand`/`TweeChoice` are structurally compatible with both `StoryScript`/`StageChoice`
1369
- and `EventStoryScript`/`EventChoice`, so neither wrapper needs a per-field conversion.
1370
- - `two-d/stage.parseDialogueText`/`extractDialogueCatalog` and `rpg.parseDialogueText`/
1371
- `extractDialogueCatalog` - a terse line-based dialogue format, alongside `importTwee`, for
1372
- straight (non-branching) scenes: `@id text` names the speaker, an unprefixed line
1373
- narrates, and `- text` alternates between the first two speakers a scene establishes
1374
- (capped at two; a third distinct speaker is refused rather than guessed at). Each is a
1375
- thin wrapper around `core.parseDialogueLines` naming its own command shape (`StageCommand`'s
1376
- `as` versus `EventCommand`'s `speaker`), so a text-only RPG needs no Pixi dependency to use
1377
- it and a Pixi-based visual novel needs no `rpg` dependency either. Each module's
1378
- `extractDialogueCatalog` builds an identity `i18n` catalog from the result (`two-d/stage`'s
1379
- also reads a `StoryScript`), the same shape MWL's `extractCatalog` builds from
1380
- `_("...")`-marked strings, so a translator has real entries to start from (item 355).
1381
- - `rpg.EventRunner.runStory`/`EventStoryScript`/`EventCommand`'s new `goto` variant/
1382
- `EventChoice.goto` - a named-passage graph for map-event scripts, the `EventCommand`
1383
- counterpart to `StageScript.runStory`/`StoryScript`: a `goto` command or a choice's own
1384
- `goto` jumps to a different passage, and a plain `run()` refuses a stray `goto` instead of
1385
- silently ignoring it.
1386
- - `rpg.importTwee`/`EventTwineStory` - imports Twee-notation Twine stories into
1387
- `EventStoryScript`, a thin wrapper around `core.parseTwee` (the same engine
1388
- `two-d/stage.importTwee` wraps for `StageCommand`/`StoryScript` instead), so a text-only
1389
- RPG can import a branching Twee story with no `two-d`/Pixi dependency (item 356).
1390
-
1391
- ## [0.12.0] - 2026-09-14
1392
-
1393
- ### Added
1394
-
1395
- - `rpg.EventRunner`'s `DialogueRequest` (and `EventCommand`'s `say`/`ask`) gained an optional
1396
- `portrait` field, threaded through to `two-d/ui.messageBoxPresenter` and `MessageBox`'s own
1397
- pre-existing `portrait` support - a portrait-bearing line no longer has to bypass `present`
1398
- and build its own `MessageBox` directly (item 352).
1399
- - `rpg.GridMover.jumpBy` - an instant reposition with no tween and no walk animation, for a
1400
- "jump" move-route step over terrain `moveBy`'s glide has no way to skip.
1401
- - `rpg.MoveRouteRunner`/`MoveRoute`/`MoveRouteStep`/`MoveRouteOptions` - drives any `GridMover`
1402
- through a scripted route (fixed/random/toward/away steps, turn, jump, wait) with `repeat` and
1403
- `skippable` policies, built entirely on `GridMover`'s existing primitives (item 353).
1404
- - `audio.Sound.play(gain, pitch)` - an optional pitch parameter as `HTMLAudioElement.
1405
- playbackRate`. No matching `pan`: a plain `<audio>` element has none to set, the same reason
1406
- `Positional.audioPan` only ever reported a number rather than owning a panner node (item 354).
1407
-
1408
- ### Fixed
1409
-
1410
- - `mobile:build` (and everything built on it: `cap:sync`, `cap:add:android`, `desktop:build`,
1411
- `desktop:run`) now passes `--no-compress` to `emit-page.mjs`. Item 349/350's `.gz`/`.br`
1412
- sidecar files, written by default into every build since those items shipped, broke the
1413
- Android/Capacitor asset merge (`Duplicate resources` from AAPT, which treats `game.js` and
1414
- `game.js.gz` as colliding) the first time the full pipeline was actually built and run
1415
- end to end (item 351) - those sidecars were always dead weight for a packaged native app
1416
- with no server to negotiate `Content-Encoding` for, so this drops them at the source rather
1417
- than special-casing the generated `android/` project.
1418
-
1419
- ### Changed
1420
-
1421
- - `android/` is no longer `.gitignore`d (item 110's original choice, kept since). The
1422
- Capacitor-scaffolded project's own generated `.gitignore` already excludes build output,
1423
- `local.properties`, and the copied web assets/config that `cap sync` regenerates every
1424
- build - the 53 files it leaves are ordinary scaffold source (manifest, Java, gradle files,
1425
- launcher/splash resources), the same kind of thing worth tracking as any other native
1426
- wrapper customization: this session's own `ignoreAssetsPattern` fix (above) would otherwise
1427
- have been silently lost the next time someone ran `cap add android` fresh.
1428
- - `webpage/assets/0c_framework_architecture.svg` regenerated - it had gone stale since the
1429
- `ai` and `mwl` modules were added to `src/`, so the "generated, never hand-drawn" diagram
1430
- was quietly wrong about the current module list until `npm run webpage:diagrams` was
1431
- actually re-run (item 351's Android/Windows verification pass turned this up while
1432
- double-checking related documentation).
1433
- - `webpage/design/architecture-explorer.html`, the interactive module-graph explorer, was
1434
- regenerated via the archify skill for the same reason: authored once at release 0.4.3, it
1435
- had never been updated and was missing `ai`/`mwl` entirely despite linking to itself as
1436
- "generated straight from src/'s own import graph". Rebuilt with real, verified import-graph
1437
- data for all 15 current modules and a fourth guided view ("mwl as data-authoring backbone").
1438
- - `desktop/README.md` documented only the older, unwired `desktop/webview2` host and never
1439
- mentioned `desktop/MwgDesktopHost` - the one `desktop:build`/`desktop:run` actually build -
1440
- or its `SetVirtualHostNameToFolderMapping` capability. Rewritten to cover both hosts and
1441
- which job each is for.
1442
-
1443
- ## [0.11.0] - 2026-09-14
1444
-
1445
- ### Added
1446
-
1447
- - `tools/webp-convert.mjs` (`toWebp`) and `compileResources`'s `toWebp`/`webpLossless`/
1448
- `webpQuality` options - convert `.png`/`.jpg`/`.jpeg` build assets to WebP before embedding,
1449
- lossless by default (verified pixel-for-pixel identical to the source) and only kept when
1450
- actually smaller, under the asset's unchanged key so `load('sprite.png')` keeps working the
1451
- same in dev and built modes. Needs the optional `sharp` devDependency, dynamically imported
1452
- only when `toWebp` is used, so a build that never asks for it never needs it installed
1453
- (item 350).
1454
- - `single-file.mjs`'s `algorithm: 'gzip' | 'brotli'` option (`--brotli[=quality]` on the CLI,
1455
- `--single-file-brotli[=quality]` on `emit-page`) - brotli compression for the single-file
1456
- build alongside the existing gzip path. gzip stays the broadly-supported default: a real
1457
- Chrome (153) tested directly during this feature's own verification throws for
1458
- `DecompressionStream('br')`, so brotli is documented as an advanced, narrower-reach option
1459
- rather than an assumed-safe default (item 350).
1460
-
1461
- ### Fixed
1462
-
1463
- - `single-file.mjs`'s generated bootstrap: `new DecompressionStream(format)` throws
1464
- synchronously for an unsupported format rather than rejecting a promise, which escaped the
1465
- bootstrap's own error handling entirely and left the splash screen stuck forever instead of
1466
- failing visibly - found live in the browser while verifying item 350's brotli option, fixed
1467
- for both gzip and brotli by converting the throw into a rejection.
1468
- - `assets.load`'s `data:` URI format hint now comes from the URI's own MIME type first, falling
1469
- back to the asset path's extension only when that is unavailable. Found while reviewing
1470
- item 350's WebP conversion: `toWebp` can compile a `sprite.png` path into `image/webp` bytes
1471
- (keeping the `.png` key so dev and built modes keep agreeing), and the old, path-only hint
1472
- would have told Pixi's resolver to run the PNG parser over WebP data.
1473
-
1474
- ## [0.10.0] - 2026-09-14
1475
-
1476
- ### Added
1477
-
1478
- - `tools/single-file.mjs` and `emit-page --single-file [--single-file-compress[=level]]` -
1479
- a genuinely single-file `file://` build with no sibling `.js` at all: every script an
1480
- example's build loads is inlined into one additional `standalone.html`, optionally gzipped
1481
- and unpacked at load through the browser's own `DecompressionStream` behind a splash
1482
- screen, additive to the existing multi-file output (item 349).
1483
-
1484
- ## [0.9.1] - 2026-09-14
1485
-
1486
- ### Added
1487
-
1488
- - `rpgmAutotileFrame` and `RpgmAutotileAtlas` - renderer-neutral RPG Maker MV autotile
1489
- atlas geometry, including four-slot decoding, quadrant selection, validation, and cached
1490
- frame descriptions (roadmap item 348).
1491
-
1492
- ## [0.9.0] - 2026-09-13
1493
-
1494
- ### Added
1495
-
1496
- - `core.CanonicalState` - a defensive, JSON-safe root state combined with `StateRegistry`
1497
- extensions, with snapshots, version migrations, transactions, and atomic restore covering
1498
- both pieces together (item 341).
1499
- - `simulation.validateSimulationReplay`, and an optional `history` option on `SimulationRuntime`:
1500
- replay a recorded journal from a checkpoint and compare deterministic event batches, and
1501
- restore complete state/scheduler/RNG/journal undo-redo checkpoints (item 341).
1502
- - `LockstepClient`/`createLockstepServer` carry a session seed and initial state, validate
1503
- game-supplied commands, and exchange per-tick state checksums, with new `onReject`/`onDesync`
1504
- signals reporting rejected input and diverging peers (item 341).
1505
- - MWL JSON5 authoring accepts schema-neutral named-node sugar (`{ unit_type: { id: 'hero' } }`
1506
- and repeated object children) alongside the generic `tag`/`children` envelope, lowered before
1507
- validation runs (item 338).
1508
- - `MwlDomainHook`/`MwlDomainHookRegistry`/`MwlDomainHookDeclaration` - game-declared hook
1509
- namespaces (`item-effect:potion-strength`) get a typed context/input/output boundary that MWG
1510
- validates and emits without knowing the domain's own types or rules (item 342).
1511
- - `HookWorld.random` - every MWL hook, built-in or domain, draws from the runtime's own seeded
1512
- `core.Generator` instead of `Math.random()`, via the new `MwlRuntimeOptions.random`; the draw
1513
- position is carried on `MwlWorld.random` and resumes exactly across save/restore (item 342).
1514
- Any game hand-building its own `HookWorld` (only `MwlRuntime` constructs one today) must now
1515
- provide this field too, the same rule item 319's `variableAt` addition already established.
1516
- - `MwlSaveableHookState`/`MwlHookRegistry.saveable` - a game may explicitly expose JSON-safe hook
1517
- state; `MwlRuntime.save()`/`restore()` round-trip it through the same save envelope (item 341).
1518
- - `MwlRuntime.journal`/`MwlRuntimeAction` - public runtime operations (running a trigger, firing
1519
- an event or a moveto watch, answering a dialogue choice) are recorded in order and persisted
1520
- with the save (item 341).
1521
- - The MWL parser and compiler retain exact JSON5 attribute and value source locations
1522
- (`MwlNode.attributeLocations`/`valueLocations`), used by schema, catalog, and macro
1523
- diagnostics instead of falling back to the owning node's own location (item 342).
1524
- - Unknown MWL macros and hook references are errors by default, with file/line/column
1525
- diagnostics; `MwlPreprocessOptions.macroPolicy: 'ignore'` restores the old silent-passthrough
1526
- behaviour for legacy content (item 342).
1527
- - `schema10`/`MWL_SCHEMA_10` - the published MWL 1.0 vocabulary: required attributes and child
1528
- cardinalities on top of the unchanged 0.1 tag/value contract; `mwl migrate --to 1.0` performs
1529
- a lossless upgrade (item 342).
1530
- - `validateCatalog` reports `MWL_ALIAS_CYCLE` for cycles in resolved `aliasof` chains, and the new
1531
- `MwlValidationOptions.mapBounds` rejects authored coordinates outside declared map dimensions
1532
- (item 342).
1533
- - `readTableMap`/`readTableIndex`/`tableKey` - typed table-row projections with collision-free
1534
- native composite keys, and inverse indexes that retain every matching row (items 339, 346).
1535
- - `mwl diagnostics`/`mwl ci` CLI modes emit stable, machine-readable JSON diagnostics; `mwl
1536
- format`/`mwl migrate --to 1.0` emit a deterministic canonical document (items 342, 346).
1537
- - `tests/random.test.ts` gained a hardcoded-output compatibility test for `core.Generator`'s
1538
- stream, guarding fixed seeds against a future silent algorithm change (item 342).
1539
-
1540
- ### Changed
1541
-
1542
- - `mwl/grammar.ts`'s macro expansion, gettext rewrite, and tag-site collection now share one
1543
- `skipStringOrComment` scan instead of three near-identical hand-rolled copies of it.
1544
- - `LockstepClient.submitInput` accepts an optional per-tick checksum and an optional client-side
1545
- `validateInput`; rejected input reports through the new `onReject` signal instead of silently
1546
- going nowhere.
1547
-
1548
- ### Fixed
1549
-
1550
- - `src/mwl/catalog.ts` carried a literal NUL byte, rather than an escaped `\0`, inside one
1551
- composite map key, which made the file register as binary to `git diff` and `grep`. Replaced
1552
- with the same `\0` escape already used for the identical purpose elsewhere in the file; no
1553
- behaviour change.
1554
-
1555
- ## [0.9.0-alpha] - 2026-09-13
1556
-
1557
- ### Changed
1558
-
1559
- - MWL authoring syntax is now JSON5 instead of the WML-inspired tag/`key=value`
1560
- form: every `.mwl` file is a top-level array of `{ tag, ...attributes, children }`
1561
- nodes, values are real JSON5 numbers, booleans and strings (stringified back to
1562
- the `Record<string, string>` the schema, compiler and runtime already see), and
1563
- translatable strings are marked `_("...")` via a preprocessor rewrite. The
1564
- `#define`/`#include`/`#ifdef` textual pass is unchanged. The `"""..."""` block
1565
- form (item 317) is superseded by JSON5 `\n` escapes and backslash line
1566
- continuations. Clean cutover: all fixtures, examples, tests and doc examples
1567
- are migrated, the old tag parser is deleted, and `json5` (pure JS, no native
1568
- build) is a runtime dependency.
1569
-
1570
- ## [0.8.2] - 2026-09-13
1571
-
1572
- ### Added
1573
-
1574
- - `tests/builtin-pipes.test.ts`: regression coverage confirming `TiledSprite`/`NinePatch`
1575
- resolve to Pixi's own registered `tilingSprite`/`nineSliceSprite` pipes, a guarantee previously
1576
- verified only by a downstream consumer's own uncommitted script (item 336).
1577
-
1578
- ### Changed
1579
-
1580
- - `mwl/runtime.ts`'s `executeNode` (a 226-line `switch` over 28 command tags, its own case
1581
- bodies inline) is now a `commandHandlers` dispatch table plus one small, independently-named
1582
- private method per command. No public API or behaviour change: `API_REPORT.md`'s diff is
1583
- purely additive private-method stubs, and all 166 `mwl-*.test.ts` tests pass unmodified
1584
- (item 337).
1585
- - `DEVELOPMENT.md` documents why `coverage`/`coverage:check` exclude `Game.ts`,
1586
- `ColorTransformBatcher.ts`, `Minimap.ts`, `three-d/Vox.ts`, `DialogueStage.ts`,
1587
- `EventDialogue.ts` and `two-d/ui/**` (Pixi rendering/layout, verified by the visual smokes
1588
- instead of a coverage percentage), and why `core` holds optional network-facing clients
1589
- alongside always-needed primitives (item 333, item 334).
1590
- - `GameOptions.extensions`'s doc comment now names `TiledSprite`/`NinePatch` alongside
1591
- `TintedSprite` as self-registering their Pixi render pipe automatically, closing a
1592
- documentation gap that likely explains why a cautious consumer wasn't confident enough to rely
1593
- on it (item 336).
1594
-
1595
- ### Fixed
1596
-
1597
- - `mwl`'s `validateWorld` rejects a `__proto__`/`constructor`/`prototype` key anywhere in a
1598
- decoded save (item 335): `MwlRuntime.restore` merges a decoded save into its own world with
1599
- `Object.assign`, which honours such a key as a prototype substitution rather than an ordinary
1600
- value. `core/Sanitize.ts` gains `assertNoForbiddenKeys`, the same rejection `validateSchema`
1601
- already applied to fixed-shape data, generalised to `mwl`'s dynamic, arbitrarily-nested world
1602
- shape.
1603
- - `SaveSystem.load` returns `null` for a corrupted or malformed slot instead of throwing an
1604
- uncaught `SyntaxError`, the same outcome a missing slot already produced; `importSlot` throws a
1605
- labelled `SaveSystem.importSlot: payload is not valid save data` error instead of a bare parse
1606
- error (item 331).
1607
- - `Container2D`/`Texture2D` in `two-d/render/Types2D.ts` each carried two adjacent JSDoc blocks,
1608
- so only the generic, less useful one reached generated documentation; merged into one comment
1609
- each (item 332).
1610
-
1611
- ## [0.8.1] - 2026-09-12
1612
-
1613
- ### Added
1614
-
1615
- - `MwlValue` is exported from the `mwl` barrel, alongside `MwlWorld`: the recursive
1616
- `string | number | boolean | MwlValue[] | { [key: string]: MwlValue }` that `MwlWorld.variables`
1617
- and a hook's own attributes already used, now nameable by a game's own code instead of only
1618
- inferred.
1619
- - `MessageParams` takes nested records, and a `{token}` may be a dotted path into them (item 329):
1620
- `t('hit', { side })` resolves `{side.stored.hitpoints}` by walking the params it was handed, so a
1621
- game whose scenario state is a tree passes the tree rather than flattening it into names first.
1622
- A path that names nothing - a step missing, an object where a value belongs, a path past a
1623
- scalar - leaves the placeholder as written, and an exact entry still wins over the walk, so a
1624
- literal dotted key resolves as it always did. The placeholder grammar (`tokenizeMessage`, shared
1625
- with the editor's `diffPlaceholders`) is what widened: a dotted token carries its `:spec` and
1626
- `!conv` like any other.
1627
- - `~ROTATE(degrees, linear)` and `rotatePixels`'s `RotateMode` (item 330): a rotation at an angle
1628
- that is not a quarter turn can now interpolate instead of sampling nearest-neighbour, which is
1629
- what keeps a tile rotated onto a hex grid from coming out as a staircase. `~ROTATE(45)` and
1630
- `rotatePixels(..., 'nearest')` are the default and are unchanged, still exact at multiples of 90
1631
- degrees; `'linear'` blends the four pixels around each sample point, premultiplied by alpha, so a
1632
- transparent neighbour contributes coverage and never colour - a straight RGBA blend would fringe
1633
- every cut-out sprite with whatever RGB its transparent pixels happen to hold, which is the one
1634
- way this can look worse than the fast path rather than better. Both modes are bake-time work, and
1635
- measured: `linear` costs 2.4 to 4.2 times `nearest` per image (0.45 ms against 0.12 ms for a
1636
- 64x64 tile at 60 degrees, 3.6 ms against 1.5 ms at 256x256), once, while the texture is built.
1637
- `parseRotateMode` is the argument's parser, exported beside the other path parsers so a game
1638
- rendering `~ROTATE` through its own canvas pipeline reads the same names.
1639
-
1640
- ### Changed
1641
-
1642
- - `parsePo` treats a `#, fuzzy` entry as untranslated (the Wesnoth port's non-adoption review),
1643
- which is what gettext's own tools make of it: the key is left out and the base language wins,
1644
- rather than shipping a translation a translator has not signed off on. Flags were previously
1645
- dropped on the floor along with comments; every other flag still changes nothing.
1646
- - `paletteRangeMapping` shades a reference palette by brightness rather than by position (item 327),
1647
- which is what a Wesnoth `[color_range]` team colour is defined by: the reference's first colour
1648
- is its anchor and becomes `mid`, every other entry blends towards `min` or `max` in proportion to
1649
- how its own channel average compares with the anchor's, and the arithmetic is the engine's own -
1650
- a floored average, a truncated blend, no rounding - so the shades come out byte for byte as
1651
- Wesnoth's `recolor_palette` gives them. A list no longer has to be sorted lightest-first for the
1652
- mapping to make sense, only to keep its anchor first, and the mode it pairs with is `'exact'`:
1653
- the mapping covers the reference exactly, so the pixels outside it (anti-aliased edges, outlines)
1654
- stay as the artists painted them, where the previous documentation pointed at `'nearest'` for it
1655
- and would have repainted the whole image. Verified against the port's own transliteration of the
1656
- engine over 699,996 sampled colours across five ranges, including the all-black and all-white
1657
- anchors, with no mismatch.
1658
-
1659
- ## [0.8.0] - 2026-09-12
1660
-
1661
- ### Added
1662
-
1663
- - `MwlHookDeclaration` and `validateHookAttributes` (item 321), plus `validAttributeValue`/
1664
- `attributeTypeDescription`: a hook declares the attributes its own `[hook]` calls carry, and
1665
- `validateCatalog`'s `hooks` option takes that declaration where a bare `type:name` id used to
1666
- be the only accepted shape. A typo in a hook attribute is now a compile-time `MWL_VALUE` or
1667
- `MWL_UNKNOWN_ATTRIBUTE` instead of a throw mid-scenario. The tag schema's own value check now
1668
- calls the same two exported functions, so the two cannot disagree.
1669
- - `HookWorld.variableAt(path)` (item 319): the read that matches `Emit.setVariable`'s write, both
1670
- resolving a nested variable through the same walker `[variable] name=` uses, so a hook no
1671
- longer has to cast away `Readonly` and walk paths itself (which produced flat dotted keys no
1672
- reader finds). `Emit.setVariable` is documented as the write half. Any game implementing its
1673
- own `HookWorld` must now provide the method; only the runtime constructs one today.
1674
- - `[set_variable] path=` (item 318), on both spellings: the computed target a converter needs for
1675
- a dynamic name, expanded from `$name`/`$(expression)` references before the same path walker a
1676
- literal `name=` uses resolves it. `name=`/`target=` keep their literal meaning.
1677
- - `[set_variable] mode=literal|number|expression` (item 316), on both spellings of the effect
1678
- (`[set_variable]` and `[command] name="set_variable"`): content declares what its own `value=`
1679
- means instead of `MwlRuntime` inferring it from the text. `literal` keeps the text exactly as
1680
- written, `number` parses it and throws on anything that is not one, `expression` evaluates it
1681
- through the same context `[if] test=` uses. A value with no `mode` is inferred as before, so
1682
- hand-authored content is unaffected.
1683
- - `mwl.MwlAttributeType` (item 316): a schema attribute's type may be the closed list of values
1684
- it accepts, not only one of the shared value types. A value outside the list is a compile-time
1685
- `MWL_VALUE` diagnostic naming the alternatives.
1686
- - `key="""..."""` attribute values (item 317): the one form that may span lines, taken exactly
1687
- as written, so wrapped message, objective and option-label text no longer needs a converter to
1688
- collapse its whitespace. The `_` gettext marker applies to it as to any other value.
1689
- - `roguelike.coneSector` (item 322): a circular sector aimed at an angle. Rays are cast every 0.5
1690
- degrees across an arc of `degrees`, each clamped to `range` and stopped by the first wall, so a
1691
- wall shadows the part of the cone behind it while the rest still reaches. `coneCells` snaps the
1692
- aim to one of the eight directions and sprays linearly from there; a sector keeps the angle it
1693
- was aimed at, which is what a breath weapon, a searchlight or a gas cloud wants. It needs the
1694
- level - that is what stops its rays - so it is a function rather than one of `AreaShape`'s kinds,
1695
- whose resolver works without one. Ray offsets round away from zero, so a sector aimed along an
1696
- axis is exactly symmetric rather than a cell wider on one side. Six tests in
1697
- `tests/targeting-shapes.test.ts`.
1698
- - `ParticleEmitter` colour ranges, curves and flicker (item 323): `tint` takes a `[from, to]` pair
1699
- each particle draws its own colour from (mixed channel by channel, where interpolating the packed
1700
- value would carry from one channel into the next), `scale`/`alpha` take a `ParticleCurve` of the
1701
- particle's own age instead of only the birth-to-death pair, and `flicker` multiplies the scale by
1702
- a seeded draw every frame, which is a torch's wobble rather than its fade. Each of those draws
1703
- happens only when its option is used, so an existing seeded spray is unchanged, and reduced
1704
- motion drops the flicker along with the travel. Five tests in `tests/particles.test.ts`.
1705
- - `Window({ blocker: true })` (item 324): a full-viewport child under the window's chrome that
1706
- swallows clicks, so a window over a map or a toolbar stops passing them to what is underneath,
1707
- and dismisses the window when the click lands outside it. A window's own widgets are hit first,
1708
- and a click on the frame or an empty part of the body is swallowed without dismissing, so the
1709
- body is never a close button by accident. `handleOutsideClick(x, y)` is that decision on its own,
1710
- headless-testable the way `handleAction` is. Off by default: it changes what the whole screen
1711
- answers to. Seven tests in `tests/window-blocker.test.ts`.
1712
- - `WindowStack.handleAction(action)` is public (item 325): a scene with its own keyboard handling
1713
- can now ask the windows before acting, instead of discovering that registration order decided it.
1714
- `Input.onAction` offers an action to the most recently registered listener first, and the stack
1715
- registers in its constructor, so a scene that builds its stack in `create()` and registers a
1716
- handler after it is offered every key before the open window is, and returning true for one takes
1717
- it away from the window. The class doc spells the race out and gives the one-line chain
1718
- (`stack.handleAction(action) || myOwnHandling(action)`), and the same doc now says what a scene
1719
- that does not chain has to do instead. `Window`'s own doc gains the other half: its frame and
1720
- empty body are not clickable, which `blocker` is the option that changes. Three tests in
1721
- `tests/window-stack-routing.test.ts`.
1722
- - `SpriteSheet.rect(index, x, y, width, height)` (item 326): arbitrary rectangles for the sheets
1723
- that are not grids - a hand-packed icon atlas, a strip of bar segments, a nine-patch's corners,
1724
- an item whose art is smaller than its cell. A rect is cached under its index exactly like a grid
1725
- frame, so `get`/`region`/`name`/`pick` treat it as one and asking twice returns the same
1726
- `Texture`, where the hand-written path built a fresh one per site (about twenty of them in the
1727
- port, plus its own helper). Declaring a rect over a grid index replaces that frame, which is what
1728
- a tightened sub-rect is. `grid`/`fromTexture` now take no frame size at all, leaving a sheet with
1729
- no grid and only the rects declared on it. Five tests in `tests/sprite-sheet-rects.test.ts`.
1730
-
1731
- ### Changed
1732
-
1733
- - `MessageBox` swallows clicks by default (item 324), through the same `blocker` layer: a box with
1734
- a page still to read, or a choice to answer, is not something a click on the world should be able
1735
- to act past. It is not closable, so this can only ever swallow a click, never dismiss the box,
1736
- and `blocker: false` is the opt-out for a box the player is meant to click past (the same case
1737
- `dims: false` is for). `examples/interface` uses both new halves: its bag window takes
1738
- `blocker: true`, and its map handler now asks `windows.handleAction` rather than relying on
1739
- having registered before the stack did.
1740
- - `sbom.cdx.json` carries a `serialNumber` (item 315): a version-5 UUID over the document's own
1741
- content, so it stays stable for a given lockfile and changes when the dependency set does, which
1742
- keeps the drift check and gives the serial the meaning CycloneDX asks of it. `metadata.timestamp`
1743
- stays absent on purpose: a generation time stamped into a committed file is one stale moment
1744
- every later read is dated to, and `CHANGELOG.md` already dates each version.
1745
-
1746
- ## [0.7.9] - 2026-09-12
1747
-
1748
- ### Added
1749
-
1750
- - `tools/sbom.mjs` with `npm run sbom`/`npm run sbom:check` (item 315): a CycloneDX 1.6 SBOM
1751
- (`sbom.cdx.json`) for the framework, built from `package.json` and `package-lock.json` alone
1752
- with no network access or added dependency, and checked in CI so a dependency change moves the
1753
- supply-chain document with it.
1754
- - `core.clamp`, replacing two byte-identical private `clamp` helpers in `rpg.Collision` and
1755
- `two-d.render.Camera`.
1756
- - `two-d/pixi-interop`'s `registerBuiltinPipes()` (item 297), plus re-exporting
1757
- `TilingSpritePipe`/`NineSliceSpritePipe` themselves, for a consumer bundler that tree-shook
1758
- a built-in Pixi pipe away despite importing the full `pixi.js` package.
1759
- - `ui.ListView.tapRow(index)` (item 299), the `IconGrid.tapCell`-shaped public method for the
1760
- select-and-confirm-in-one-step tap a row's own `pointerdown` handler already did.
1761
- - `assets.setAssetMap(map)` (item 300): hands `resolve`/`has`/`paths`/`isCompiled` a game's
1762
- own path-to-URI map directly, taking priority over `window.__MWG_ASSETS__` while set, for a
1763
- game whose own bundler compiles assets a different way than `tools/compile-resources`.
1764
- - `two-d.render.StatusVisuals.flash(color, strength, duration)` (item 301): a one-shot,
1765
- linearly-decaying additive pulse layered on top of whatever statuses are active.
1766
- - `two-d.render.ScreenEffects.sequence(steps)` and a new `hold` phase (item 302): chains
1767
- fade/hold/flash steps end to end as one call, for the hold-then-fade-back transition
1768
- `fadeOut`/`fadeIn`/`flash` alone cannot express; `update` keeps returning false at every
1769
- step boundary, true only once the whole sequence finishes.
1770
- - `two-d.render.Camera.shakeScreen(intensity, duration)` (item 303): `shake` taking screen
1771
- pixels instead of world units.
1772
- - `mwl.MwlValidationOptions.rowIdScope` (item 304): `'file'` scopes `MWL_DUPLICATE_ID`'s
1773
- `tag:id` key per source file instead of the whole compiled catalog, for a game whose id
1774
- convention reuses ids across files on purpose.
1775
- - `two-d.render.spriteColorMatrix(sprite, matrix)` (item 309): attaches any of
1776
- `blendMatrix`/`channelScaleMatrix`/`channelSwapMatrix`/`colorShiftMatrix` (or a game's own
1777
- matrix) to a sprite as a `ColorMatrixFilter`, without needing a direct `pixi.js` import just
1778
- to construct that one class.
1779
- - `assets.load` now supplies Pixi's `Assets.add` a `format` hint (the original path's own
1780
- extension) whenever the resolved `src` is a compiled build's `data:` URI (item 308), since
1781
- the URI itself carries no extension for Pixi's resolver to pick a parser from. No new
1782
- argument: a game still calls `load(['tiles.png'])` exactly as before.
1783
- - `[item]` accepts `image`/`icon` (item 307), carried through
1784
- `MwlItemDefinition.image`/`.icon`; both were already recognised as asset attributes by the
1785
- manifest scanner, so this closes the schema gate that was blocking them.
1786
- - `tools/classic-html.mjs`'s `toClassicScript(html)` (item 306), shipped in the npm package:
1787
- rewrites a bundler build's `<script type="module">` entry tag to a classic deferred one, so
1788
- the page opens via `file://`. `tools/emit-page.mjs` now uses it too, instead of its own copy
1789
- of the same rewrite.
1790
- - `two-d.render.applyAllImageModifiers(sprite, parsed, probe?, scale?)` (item 310): runs
1791
- `applyTextureModifiers`'s exact pixel-level baking and `applyImageModifiers`'s sprite-level
1792
- modifiers in the order a caller with a `~BLEND`/`~ROTATE` path needs, so the two no longer
1793
- have to be driven by hand.
1794
- - `two-d.render.createLayers(parent, names)` (item 312): builds one labeled `Node2D` per name,
1795
- attached to `parent` in the order given and returned keyed by name, for the conventionally
1796
- ordered layer stack (terrain, units, effects, UI, ...) a game otherwise hand-wires.
1797
- - `ui.RichLabel`/`ui.MarkupText` take `tagStyles` (item 313), the same custom-inline-tag option a
1798
- bare `Text2D` takes. `markup.parseMarkup` gained `MarkupOptions.tags` and a `MarkupSpan.tag`
1799
- field so the parser stays renderer-neutral: `MarkupText` applies each tag's Pixi style to its
1800
- run and measures under it, while `RichLabel` keeps a registered tag as a real element for
1801
- `HTMLText` and still escapes an unregistered one.
1802
- - `two-d.render.Projectile` takes an optional `animation` (item 311): the projectile advances
1803
- the flight frames with its own elapsed time and reports the current one through
1804
- `frame`/`frameOffset`, so a missile with `[missile_frame]` art no longer needs a parallel
1805
- animation and clock kept in step by the game.
1806
-
1807
- ### Changed
1808
-
1809
- - **Breaking:** `two-d.render.StatusVisuals` now composes every active status's colour
1810
- additively (each channel clipping at 1) instead of one status winning by declaration order,
1811
- and never writes the multiply `tint` any more, so a sprite's own identity tint survives
1812
- underneath (item 301). `TintTarget` is now just `{ colorAdd: number }`; `lerpTint`/
1813
- `resetColor` are no longer part of its contract.
1814
-
1815
- ### Fixed
1816
-
1817
- - Documented, in `tools/mwl.mjs` and README's MWL section, that a game needing more than
1818
- `mwl build`'s three standard files should write its own build script against the public MWL
1819
- library API rather than look for a CLI flag (item 305).
1820
- - Corrected two contradictory doc comments (item 298): `Shape2D.ts` claimed `Container2D` was
1821
- a type alias a game could not `new`, when it is a value re-export and always was; and
1822
- `pixi-interop.ts`'s "no registration needed" guarantee is `pixi.js`'s own `sideEffects` list
1823
- surviving the consumer's own bundler, not a universal property.
1824
- - `withTextureCanvas`'s pixel-level modifiers (`~BLIT`/`~MASK`/`~BLEND`/`~ROTATE` in
1825
- `applyTextureModifiers`, and `recolorTexture`) called a real
1826
- `CanvasRenderingContext2D.putImageData` with a plain `{data, width, height}` object, which a
1827
- real browser rejects (it needs an actual `ImageData`); a test-supplied `probe.createCanvas`
1828
- never hit the real canvas path, so the bug had no unit-test coverage. `withTextureCanvas` now
1829
- wraps the real context's `putImageData` to build a proper `ImageData` itself, so every
1830
- pixel-level modifier keeps writing the same plain object.
1831
- - `[filter]`/`[have_unit]` `x`/`y` now accept the comma-separated lists and inclusive ranges
1832
- (`x=1,2,4-5`) a moveto event's own `x`/`y` already did (item 314); the schema types them
1833
- `coordinate` and `unitMatchesFilter` reads them through the one `coordinateMatches`.
1834
-
1835
- ## [0.7.8] - 2026-09-12
1836
-
1837
- ### Added
1838
-
1839
- - Unit identity usable by the AI. MWL units now carry their own `name`, `role`/function and
1840
- `can_recruit` leader flag: `[unit]` sets them, a side's own leader is `can_recruit`, `[role]`
1841
- stamps the role onto the units it matches, `[store_unit]`/save keep them, and `unitMatchesFilter`
1842
- reads all three - which also wires up the `can_recruit` the `[filter]` schema already allowed but
1843
- the runtime ignored. On the AI side, `ScoreSubject` and `HeuristicCandidate` carry
1844
- `type`/`role`/`can_recruit`/`name`, and the new `subjectsWhere`/`ScoreSubjectFilter` select a world
1845
- on any of them, so a mind can find "the enemy leader" without re-deriving it from ids.
1846
- - Leader identity on the unit (item 296). An autospawned `[side] leader=` unit carries `leader: true`
1847
- beside its `can_recruit`, `[store_unit]`/unstore and a save keep it, and `unitMatchesFilter` reads
1848
- it, so `[filter] leader=yes` finds the side's own leader without recomputing
1849
- `sides[id].leader === id`.
1850
- - One variable-path resolver for every reader (item 295). `$name` resolution, `[condition]`/
1851
- `[filter_condition]` variable reads, message interpolation and the bare `$name` copy all resolve
1852
- through the same path walker `set_variable` writes with, so a dotted name like `a.b` reads what
1853
- `[set_variable] name=a.b` wrote. Array indices are in scope (`a[0].b` reads the node `a.0.b` or
1854
- `a[0].b` wrote), an index that is not a whole number is refused by name rather than becoming a
1855
- literal key, and the `id` schema type accepts brackets so such a name compiles.
1856
- - `TerrainGraphicsLayer` (item 257): the renderer half of `[terrain_graphics]`, drawing
1857
- `resolveTerrainGraphics`'s placements as one `Sprite2D` per placement, in `layer` order (a stable
1858
- sort, so the rule pass's own row-major walk survives within a layer) at the pixel position a
1859
- caller-supplied `project` callback reports, with images resolved through the asset resolver.
1860
- `setPlacements` redraws in place.
1861
- - The canvas backend for inline markup, closing the three pieces item 258's acceptance still
1862
- named as open: `positionMarkupLines` places `layoutMarkupLines`'s lines into positioned
1863
- `PositionedMarkupSpan` runs under a `MarkupLayout`'s `direction`/`align`, so an `rtl` line flows
1864
- right to left and alignment defaults to the direction's own edge, and `MarkupText` draws them as
1865
- the counterpart to `RichLabel`'s HTML text - one `Text2D` per styled run, one `Sprite2D` per
1866
- `<img>` span resolved through the asset resolver, so an image is drawn rather than left to the
1867
- caller to position. An RTL sample is now covered by `tests/markup.test.ts`.
1868
-
1869
- ### Fixed
1870
-
1871
- - One rule for the `id` value type, shared by the schema and `mwl.readers`. The schema accepts a
1872
- bracketed path like `a[0].b` as an `id` (a variable name legitimately carries index brackets),
1873
- but `readAttributes`' `id` and `id-list` kept a stricter copy of the pattern, so an adapter
1874
- reading a variable-name attribute raised `MWL_FIELD_TYPE` for a name the compiler had already
1875
- accepted. Both now call the exported `isMwlId`. One test in `tests/mwl.test.ts`.
1876
- - `actors.sell` is transactional again. It ignored the result of `Inventory.add`, so selling into
1877
- a shop stock with no room paid the seller and lost the item: two potions sold into a
1878
- capacity-1 stock produced 10 gold from nothing and left the potions nowhere. It now rolls the
1879
- bag back and refuses, exactly as `buy` already did for a full bag. One test in
1880
- `tests/shop.test.ts`.
1881
- - `board.goScore` counts territory again. Its `group` helper returned nothing for an empty
1882
- square, so the area-scoring loop never saw an enclosed empty region and only stones were
1883
- scored: four stones ringing a 3x3 board reported 4 instead of 9. `group` now groups connected
1884
- cells by value with `null` included, which leaves `liberties`/`playGo` unchanged because they
1885
- only ever pass a stone. One test, plus new coverage for `rollBackgammonDice`, a foundation
1886
- move from a tableau column, and `DiceCup.clearKept`, in `tests/classics.test.ts`.
1887
- - `board.addTacticalUnit` remembers each unit's own action budget, so `endTacticalTurn` refreshes
1888
- `actions` to it instead of a hardcoded two. A unit created with `actions: 3` was silently reset
1889
- to 2 every turn; the per-turn maximum is now `TacticalUnit.maxActions`, filled from the initial
1890
- `actions` when the caller does not set it. Six tests in `tests/tactics.test.ts`, which also
1891
- cover the overwatch reaction and attack paths that had none.
1892
- - `board.backgammonMoves` follows the bearing-off rules. It offered a bear-off from any point
1893
- whose roll reached past the off edge, so at the opening position a 6 came off from point 18
1894
- while checkers still sat on 0, 11 and 16. A bear-off now needs every checker in the home
1895
- board with none on the bar; an exact roll still takes any home checker, and an over-roll takes
1896
- only the checker nearest the off edge, since a checker must never skip past another. Three
1897
- tests in `tests/classics.test.ts`.
1898
- - An `[if]` branch no longer tries to execute its own `[condition]` child. The schema allows a
1899
- branch to carry one, but the executor ran every child, so an `[if]` whose condition held threw
1900
- `unknown MWL command: condition` instead of running its body; a false condition hid it because
1901
- the body never ran. `[if]`/`[else]` now run their command children only, the same rule
1902
- `[while]` already followed. Two tests in `tests/mwl-conditions.test.ts`.
1903
- - An `[else]` following an `[if]` is that branch's other half, so only one of the two runs. A
1904
- taken `[if]` used to run its own body and then fall through to the `[else]` as well, so both
1905
- branches executed; the `[else]` is now skipped when the `[if]` was taken, and run as the
1906
- fallback when it was not. Independent pairs still work, and a free-standing `[else]` with no
1907
- `[if]` before it still runs. Two tests in `tests/mwl-conditions.test.ts`.
1908
- - `[while]` had the same defect as `[if]`, so a loop body carrying a `[condition]` child threw.
1909
- It now runs its command children too. One test in `tests/mwl-variables.test.ts`.
1910
- - The variable-path readers item 295 named are now complete, closing three that were still flat:
1911
- a dialogue `[choice]`'s `variable=` gate, `[store_unit]`/`[unstore_unit]`/`[recall]`'s stored
1912
- list, and the hook host's `setVariable`, plus the public `execute()`'s `set_variable`. An
1913
- indexed path now builds a real array (`a[0]`, `a[1]`), so a stored list and an indexed write
1914
- agree on their shape. One test each in `tests/mwl-dialogue.test.ts`, `tests/mwl-actions.test.ts`
1915
- and `tests/mwl.test.ts`, and the `a[0].b` test now asserts the array.
1916
-
1917
- ### Changed
1918
-
1919
- - `board.skirmishMoves` computes every reachable cell from one Dijkstra pass over the map
1920
- instead of one per candidate cell. The old per-cell search also re-sorted its own frontier
1921
- every step and `shift()`ed it, so it went quadratic in path length; the pass now uses a
1922
- binary min-heap. Behaviour is unchanged, verified by a differential run of the old and new
1923
- implementations over 58 randomised terrain maps. A `[complexity]` test keeps 20 calls on a
1924
- 40x40 map under a ceiling far below the old cost, and a test pins that a cell held by
1925
- another unit is never offered as a move.
1926
-
1927
- ## [0.7.7] - 2026-09-11
1928
-
1929
- ### Added
1930
-
1931
- - Heuristic AI (item 269): `Aspects`, `Difficulty`, `Goals`, `RecruitmentPattern`, and a
1932
- `HeuristicAI` candidate/stage pipeline with `defaultWeigh`/`keepAwayScore`/`goalScore`. Aspects
1933
- ship no values; the numbers stay content, and `keep_away` is a real penalty.
1934
- - Achievements and battle statistics (item 273): `core.Achievements` gained sub-achievements
1935
- (multi-criterion unlocks via `AchievementDef.criteria`, read back with `subProgress`), and
1936
- `battle.BattleStats` tracks recruits/recalls/advances/kills/deaths/damage dealt/damage taken by
1937
- unit type for a `PlayerStats`/`RunHistory` summary to fold in.
1938
- - Free map rotation (item 286): `Camera.rotateTo`/`animateRotationTo` turn the view to any angle,
1939
- not only a grid's whole steps, sharing 285's layer-level transform and taking the shorter way
1940
- around a full turn when animated.
1941
- - Battle UI models (item 265): `AttackPreview` (damage totals and an animated frame timeline from
1942
- the game's own numbers), `AttackDialog` (the selector plus the preview and its clock),
1943
- `UnitSelector` (attacker then target), and `Whiteboard` (planned orders with undo/redo). All
1944
- renderer-free; the dialog's pixels are `Bar`/`Label` a game composes.
1945
- - Story screens (item 264): `StoryScreen` (a full-screen backdrop, title and text advanced by a
1946
- click) over the renderer-free `StorySequence` (`advance`/`back`/`goTo`/`skip`/`restart`, with the
1947
- current beat's `music` reported as a signal). `StoryBeat` matches `MwlWorld.story`'s shape.
1948
- - Data-driven shell layout and skins (item 263): `Layout` (`resolveAnchor`/`anchorAlign` over nine
1949
- named anchors plus `fill`, and a `Grid` of `size`-or-`grow` tracks) and `Skins` (per-widget,
1950
- per-state looks with a widget-state -> widget-idle -> wildcard fallback chain, and `Skins.from`
1951
- for plain data). Both renderer-free.
1952
- - The missing UI widgets (item 261): `Slider` (`sliderFraction`/`sliderValueAt`), `Checkbox`,
1953
- `Spinner` (`spinValue`), `Dropdown`, `TextModel`, `DataTable`, `TreeView` and `ScrollBox`
1954
- (`scrollOffset`). The rule-bearing parts are pure functions or renderer-free models tested
1955
- headlessly, the drawing is a thin theme-driven shell, and text fields pair `TextModel` with a
1956
- `Label` rather than a separate `TextArea`.
1957
- - Fixed-angle view rotation on `Camera` (item 285): `grid: 'square' | 'hex'` sets four quarter turns
1958
- or six 60-degree steps, `setRotationStep`/`rotate` move through them, `toScreen`/`toWorld` invert
1959
- the turn, `view` reports the box around the turned viewport for culling, and `uprightRotation`
1960
- keeps a label drawn into the world upright.
1961
- - WML action vocabulary in `[event]` (item 250): `fire_event`, `store_unit`/`unstore_unit`/`recall`,
1962
- `modify_unit`/`heal_unit`, `set_terrain`, `capture_village`, `clear_shroud`, and the scenario-level
1963
- `[role]`/`[object]`/`[story]`, backed by `MwlWorld.villages`/`clearedShroud`/`roles`/`objects`/
1964
- `story` (all saved). WML's scenario `[item]` is deliberately not added: the tag already means an
1965
- inventory item definition.
1966
- - `blendPixels`/`rotatePixels` in `ImageModifiers.ts`: `~BLEND` and `~ROTATE` moved from a
1967
- runtime sprite-property/`ColorMatrixFilter` approximation to an exact, baked-once per-pixel
1968
- operation in `applyTextureModifiers` (`~ROTATE` in particular now rotates the source pixels
1969
- and expands the surface, which a sprite's own `rotation` cannot do - needed for terrain and
1970
- anything else that must keep tiling after the rotation). `blendMatrix` stays available for a
1971
- caller that explicitly wants the cheaper live approximation instead.
1972
- - `PaletteRemapMode` (`'exact'` | `'nearest'`) on `remapPixels`/`recolorTexture`, defaulting to
1973
- `'exact'`: a pixel is now repainted only on an exact match to a `from` colour unless
1974
- `'nearest'` is asked for explicitly. The old always-nearest behaviour silently recoloured an
1975
- entire image the first time `~RC`/`~PAL` met a short, specific palette instead of a full
1976
- covering; `paletteRangeMapping`'s own gradient usage opts into `'nearest'` explicitly, since
1977
- that is the one case it is correct for.
1978
- - `ImageTextureProbe.resolveColor` and the exported `parseColorPairs`/`parsePaletteLists`: `~RC`
1979
- and `~PAL` now accept a named colour (`~RC(magenta>red)`), not hex only, and `~PAL`'s two
1980
- comma-separated colour lists parse correctly instead of only the first colour of each list
1981
- (`parseImagePath`'s own comma split does not respect that list's internal boundary, which
1982
- `parsePaletteLists` now reconstructs).
1983
- - `~BLIT`/`~MASK` now hand `resolveTexture` the argument exactly as written, nested modifiers
1984
- included (`~BLIT(unit.png~RC(magenta>red),0,0)` calls it with the full string, not a bare
1985
- path with the modifier silently dropped).
1986
- - `withTextureCanvas` is now exported from `two-d/render`, so a caller building its own
1987
- texture-level modifier can reuse the same canvas bookkeeping `recolorTexture`/`~BLIT`/`~MASK`/
1988
- `~BLEND`/`~ROTATE` all share instead of duplicating it.
1989
-
1990
- - `mwl.parseMapFile`/`MwlMapFile` (item 284): a Wesnoth-shaped `.map` loader. The `key=value`
1991
- header is split off and kept (keys not interpreted), and the comma-separated grid goes through
1992
- the same `parseTerrain` an inline `[map] terrain=` uses.
1993
- - `actors.craft` category-shaped ingredients (item 289): `Ingredient` now accepts `id` as a string
1994
- or a list, a `category` matched against the item definition's new `InventoryItem.category`
1995
- (kind-level, so it stays out of saves), or a `matches(item)` predicate. `craft` allocates against
1996
- a working copy so two flexible ingredients cannot count one stack twice.
1997
- - `two-d/render/SpriteAttachment.ts`: `SpriteAttachment` (item 291), ties a second sprite's
1998
- position to a first one's - `follow(x, y)` applies an offset, an optional `duration` makes
1999
- `update(dt)` report `done` once it elapses, so a permanent shadow and a temporary status icon
2000
- are the same class with different options. Renderer-neutral like `Projectile`/`LightningArc`.
2001
-
2002
- - `two-d/render/LightningArc.ts`: `LightningArc` (item 292), the position data for a jittered
2003
- line between two points - a lightning bolt, a tether, a chain-lightning link - geometry only,
2004
- drawn by the caller through `Shape2D`'s `Graphics`. `retarget` moves either endpoint for a
2005
- tether following two moving units; an optional `flickerInterval` re-rolls the jitter on a
2006
- timer instead of holding one fixed shape.
2007
- - `assets.load`'s `optional`/`onMissing` options (item 287): paths a game can do without load
2008
- separately from the required batch, so one missing file never aborts the rest; `texture`/`get`
2009
- take a `fallback` value returned instead of a throw for a path that never loaded.
2010
-
2011
- - `MultiTurnBeam` fronts, `blocker`, `onCell` and saved shape identity (item 278): a beam is now a
2012
- sequence of per-turn fronts rather than one captured cell per turn, so a game-supplied
2013
- `fronts(previous, turn)` expresses a cone, burst, fork or moving front. `BeamBlocker` replaces
2014
- the implicit blocker flags with one policy, `BeamStep.cells` reports every reached cell, and a
2015
- save carries the shape name so `fromJSON` refuses a mismatched shape; pre-fronts saves still load.
2016
- - `two-d/render/PaletteRemap.ts`: `remapPixels`/`paletteRangeMapping`/`recolorTexture` (item
2017
- 256), a nearest-colour palette remap for team-colour-by-range - `paletteRangeMapping` places a
2018
- reference palette's own lightest-to-darkest order along a `min -> mid -> max` gradient,
2019
- `remapPixels` is the renderer-free pixel core, and `recolorTexture` (via the new shared
2020
- `withTextureCanvas` helper) is the canvas-backed wrapper.
2021
- - Eleven more `image~MOD` suffixes in `ImageModifiers.ts` (item 255): `~O`, `~R`/`~G`/`~B`,
2022
- `~BLEND` and `~CHAN` join `~FL`/`~SCALE`/`~GS`/`~CS` as sprite-property/`ColorMatrixFilter`
2023
- operations on `applyImageModifiers`; `~ROTATE` sets the sprite's own rotation. `~RC`, `~PAL`,
2024
- `~BLIT` and `~MASK` needed real pixel access or a sibling texture, so they are the new
2025
- `applyTextureModifiers`, built on 256's `withTextureCanvas`. `~GS` no longer replaces a filter
2026
- already on the sprite (was clobbering, now appends).
2027
- - `two-d/render/TerrainGraphics.ts`: `resolveTerrainGraphics`/`TerrainRule`/`matchTerrainRule`/
2028
- `squareRotate`/`hexRotate` (item 257), a rule-driven `[terrain_graphics]`-style transition pass
2029
- generalising `Autotile`'s fixed 47-shape blob table: arbitrary flag conditions at arbitrary
2030
- offsets, multi-image placement (so a piece bigger than one cell is one rule's own data, not
2031
- something `TileMap`'s one-sprite-per-cell grid has to hold), rotation and probability. Returns
2032
- plain placement data; drawing it through a renderer is still open.
2033
- - `markupToHtml` now renders colour and size as an inline style; `markupAccessibilityText` is a
2034
- proper accessibility projection for markup (an image becomes a caller-described string instead
2035
- of its raw path); `layoutMarkupLines` wraps already-parsed spans word by word, each word
2036
- measured under its own span's style, so a bold or larger run wraps where its own wider glyphs
2037
- actually land (item 258's remaining acceptance, in part - see ROADMAP for what is still open).
2038
-
2039
- - `ParticleEmitter` spawn bounds (item 279): `ParticleSpawnArea` is an optional `spawn` on the
2040
- emitter's options, a `rect` or `ellipse` in local space so a burst spreads across an extent
2041
- instead of every particle starting at the emitter's single origin (a forge mouth, a flame
2042
- column, rain across a room). A point emitter draws nothing extra, so the seeded sequence an
2043
- existing replay recorded is unchanged.
2044
- - `roguelike.TargetingController` (item 280): the input-facing half of targeting, renderer-free.
2045
- A cursor moved by `move(dx, dy)` or a caller-resolved `moveTo(cell)`, range and line-of-sight
2046
- validation with an optional `validate` hook, a `preview()` of the shape's cells and a
2047
- `confirm()`/`cancel()` result carrying cells only, so damage, legality details and drawing stay
2048
- with the game. Hex levels step by their own six neighbours and measure in hex distance.
2049
- - `AudioListener`/`SoundSource`/`audioGain`/`audioPan`/`AudioFalloff` (item 271): positional
2050
- audio, renderer-free. A listener the game moves and turns, a `Sound` placed at a world point,
2051
- and the distance gain and stereo pan between them. `SoundSource.playFor(listener)` applies the
2052
- gain through `Sound.play`, which now takes an optional gain argument.
2053
- - `Input.onText`/`Input.onComposition`/`Input.textFromKey`/`Input.dispatchText`/
2054
- `Input.dispatchComposition` (item 262): the character a key press produces, and the three
2055
- phases of an input-method composition, so a free text field can be built. `onText` is a
2056
- stack-mode signal a focused field can consume.
2057
- - `MersenneTwister`/`MersenneTwisterState`/`RandomStreams` (item 266): MT19937 with the reference
2058
- `mt_rng`'s `seed`/`discard`/`discardCount` bookkeeping (verified against the standard test
2059
- vector) and named, independent streams derived from one base seed, so per-entity and per-usage
2060
- draws never shift each other. C++'s `uniform_int_distribution` is implementation-defined, so the
2061
- int mapping is MWG's own and documented as such.
2062
- - `i18n.parsePo`/`PoOptions` (item 270): a gettext `.po` loader into the same `Catalog` surface
2063
- as `parseFTL`, with `msgctxt`, `msgstr[N]` mapped onto the locale's CLDR categories,
2064
- untranslated entries left out for base fallback, and gettext `domain`-prefixed keys.
2065
- - `world.SideTurns`/`SideTurn`/`TimeOfDay`/`TimeArea`/`Alignment`/`alignmentBonus` (item 267): the
2066
- reference's outer turn model, sides in order with a schedule that steps per round, and a per-hex
2067
- `lawfulBonusAt` where a `TimeArea` overrides the global time of day.
2068
- - `ui.TabbedList`/`ListTab`/`TabbedListOptions` (item 281): a renderer-free model for a tabbed,
2069
- filtered, paged list with selection and a detail/close state, over caller-supplied rows and
2070
- predicates. The page is derived from the selection, so the two cannot disagree.
2071
- - `simulation.EventPresentation`/`EventPresentationOptions` (item 282): the documented recipe
2072
- tying a `SimulationRuntime` to a `PresentationQueue` - command result, animation lock,
2073
- scheduled secondary actor, cancellation, and save/load that resumes idle.
2074
- - `MwlWorld.sideStatus` and per-side `[victory]`/`[defeat]` under `[side]` (item 283): a side's
2075
- own condition is evaluated after the scenario-wide `[objectives]` ones, its result recorded by
2076
- side id, and `[win]`/`[lose]` record the side they name too. `MwlCommand`'s `win`/`lose` gained an
2077
- optional `side`.
2078
- - `simulation.CampaignSave`/`CampaignSaveState`/`CampaignSaveParts` (item 249): one `SaveSystem`
2079
- slot for a whole campaign, holding the campaign, world and simulation snapshots together, with
2080
- the world payload left opaque.
2081
- - `core.stateChecksum`/`core.SyncGuard` (item 272): a key-order-stable 32-bit checksum of JSON
2082
- state and a guard comparing the checksums peers compute per tick, so a lockstep run can notice
2083
- and locate a divergence.
2084
- - `ai.personalScoreView`/`ai.sideScoreView`/`ai.scoreWith`, over `ScoreSubject`/`ScoreView`/
2085
- `ScorePersonality` (items 274-276): the numbers a mind needs when a search is the wrong tool.
2086
- The game supplies what anything is worth, the framework assembles the view (own, allies and
2087
- enemies kept apart, with a `seen` count), and a personality is weights over the three, so a
2088
- selfish scout and a loyal one are content rather than two AI implementations. A unit's sight and a
2089
- whole side's read through the same two functions and differ only in the visibility set they are
2090
- handed, and `board.FactionFog.sees(side)` is that set as a predicate: it reads the shroud as it is
2091
- when called, not as it was when the predicate was made.
2092
- - `Animation`/`AnimatedSprite` frame timing (item 254): a frame is now a texture or
2093
- `{ texture, duration, offsetX, offsetY }`, so a frame carries its own time and its own place, as
2094
- Wesnoth's `image=a.png:120,b.png:80` does, and `AnimationOptions.startTime` is signed the way
2095
- Wesnoth writes it: positive holds the first frame, negative starts partway in (`start_time=-450`
2096
- over frames of 100ms opens on the fifth, which is how a swing is lined up with its damage frame).
2097
- `Animation.frameAt`/`frameIndexAt` are the rule, the sprite advances on its own elapsed time
2098
- rather than a leftover timer, and a frame's offset is reported through `AnimatedSprite.frameOffset`
2099
- for the caller to add where it already positions the sprite.
2100
- - `FactionFog.share(factions)` (item 268): factions put on one map, what is lit now and the shroud
2101
- they remember alike, which is what Wesnoth's `share_vision` means. Nothing shares until asked,
2102
- growing a group widens it rather than replacing it, and a share declared after a `sync` still
2103
- counts because the group is read when a cell is asked about. `sees(side)` follows it, so a side's
2104
- score view reads the team's eyes.
2105
- - `campaignChain` (item 247): a `[campaign]` pointed at `simulation.Campaign`. `first_scenario` opens
2106
- it, each `[scenario]`'s `next_scenario` is where it goes when it is won, and the chain ends where a
2107
- scenario has no next one. The order is content and the playing stays the game's, since the runner
2108
- is a callback; a scenario that decides for itself keeps its decision, which is where a runtime
2109
- `[endlevel]` will hook in. Malformed chains (no scenarios, one id twice, an unknown
2110
- `first_scenario`) throw by name. The `[campaign]` schema now accepts `first_scenario`, and
2111
- `contentCatalog` exposes each campaign's scenario links.
2112
- - `[endlevel]` and carry-over (item 248): a scenario ends with `result=victory|defeat`, and what it
2113
- hands on is `endLevelCarryover` - `bonus` plus a share of the side's gold (`carryover_percentage`,
2114
- 80% when unset, which is the reference's own default rather than an invented one), the units of
2115
- that side still standing as the recall list, and `next_scenario` for where the campaign goes (the
2116
- hook `campaignChain` already honours). `carryoverIntoScenario` is the other half of the rule: the
2117
- carried share is added to what the next scenario declares when `carryover_add` asks for it, and is
2118
- otherwise a floor under it. `MWL_DEFAULT_CARRYOVER_PERCENTAGE` names the default.
2119
- - `[kill]` as a filter (item 251): naming a unit that is not there still throws, while a `[kill]`
2120
- whose attributes are a filter over the world's units is a no-op when it matches nobody, as WML's
2121
- own `[kill]` is. It reads the same attributes an event filter does, an empty filter matches every
2122
- unit (there as here), and the schema entry is open on attributes so a filter can say what it
2123
- means.
2124
- - A scenario turn limit, as a native condition (item 253): `[game] turn_limit=N` makes the runtime
2125
- set `time_over` as a world variable and fire the `time_over` event once the turn counter passes N.
2126
- Content tests it like any variable and answers it like any event, `[endlevel]` included, because a
2127
- limit is usually a defeat and sometimes the whole scenario.
2128
- - An inline-markup contract, first half of item 258: `MarkupSpan` plus `parseMarkup`/`stripMarkup`/
2129
- `markupToHtml`/`escapeHtml` in `src/two-d/ui/markup.ts`. Nested emphasis, named and hex colours, a
2130
- size, a line break, an image span carrying a path, `$name` interpolation supplied by the caller,
2131
- and the five entities as escapes. Unknown or malformed tags and unset variables stay literal
2132
- rather than vanishing, and output text is escaped so no raw HTML can leak. What the item's
2133
- acceptance still wants (backend equivalence, wrapping after styling, images through the asset
2134
- resolver, an accessibility projection) is recorded on the item rather than implied here.
2135
- - The `[side]` surface, and one key of it with behaviour (item 252): the Wesnoth keys `team_name`,
2136
- `user_team_name`, `share_vision`, `village_gold`, `heal`, `fog`, `shroud`, `hidden` and `flag` are
2137
- read onto `MwlWorld.sides` as written (`yes`/`no` as booleans), and `sideVisionGroups` turns
2138
- `team_name` with `share_vision` into the groups `FactionFog.share` takes.
2139
- - Hex projection options, first half of item 259: `hexToPixel`/`pixelToHex` take
2140
- `HexShape`/`HexOrientation`/`HexOffset`, so a grid can be flat-top or pointy-top with either
2141
- offset parity, and the default is the flat-top odd-q layout the module always had. The inverse is
2142
- the nearest cell centre, which cannot disagree with the projection at a hex's edge.
2143
- - `Halo` (item 260): the glow around a unit, an aura, a shrine's light. An `AnimatedSprite` that
2144
- `follow(x, y)`s a target with its own offset applied once, additive by default, with z-order left
2145
- to the caller. `[halo_frame]` needed nothing new after 254 gave frames their own timing.
2146
-
2147
- ### Fixed
2148
-
2149
- - `FloatingTextStack` stacked the wrong way round: it moved the **newcomer** down by
2150
- `height + 1`, where Java's `FloatingText.push()` anchors the newcomer on the target and lifts
2151
- the lines already there to `below.top - height - 4`. A second pop-up on one target in one turn
2152
- therefore landed *below* the target instead of above the first - found by a consumer measuring
2153
- it, not by the tests, which asserted the offset's magnitude and never its direction.
2154
- `floatingTextStackOffset` is replaced by `floatingTextStackLift` (the position the older line
2155
- must take, rather than an offset the caller adds, so the sign cannot be got wrong quietly) and
2156
- by `floatingTextStackMoves`, the whole policy: which lines move, newest first, where each one
2157
- ends up, and what age each is forced to. The loop is arithmetic now, so it is checked as
2158
- arithmetic rather than through a rendered label. `FLOATING_TEXT_STACK_GAP` names Java's 4px gap.
2159
- - The lift survived exactly one frame. `FloatingText.update` wrote its own `y` from a base captured
2160
- on the first frame, so a line the stack had just moved snapped back on the next one: measured, a
2161
- line lifted to 166.6 was back at 194.4 beside the newcomer at 200, still overlapping it. The rise
2162
- now moves the pop-up's inner layer and never its position, which belongs to the caller and to the
2163
- stack; `baseY` is gone. A consumer repositioning a pop-up mid-flight no longer loses the position
2164
- on the next frame either.
2165
- - A pop-up scaled *after* `push` was measured before the scale, because a `FloatingText`'s `height`
2166
- includes its own scale. A port rasterising at 21px and drawing at 7 therefore spaced lifted lines
2167
- 33.4 world pixels apart for lines 9.8 tall. `push` now takes a `scale`, applied before the pop-up
2168
- is measured, so the entry records the size the line is actually drawn at.
2169
-
2170
- ### Changed
2171
-
2172
- - `FloatingText.shortenLife(seconds)` becomes `FloatingText.ageAtLeast(seconds)`, which does what
2173
- Java's rule says rather than something close: `above.timeLeft = Math.min(above.timeLeft,
2174
- LIFESPAN - numBelow / 5f)` caps what is *left*, and a cap on what is left is a floor under the
2175
- age. A line that has already lived past the floor keeps the age it has, where subtracting the
2176
- floor shortened it a second time. `floatingTextAgeAtLeast` is that arithmetic as a pure function,
2177
- so the difference is checked by a test; `floatingTextStackLifePenalty(linesBelow)` stays the
2178
- floor itself, a fifth of a second per line below.
2179
- - A stack keys on `key` alone, as Java's `stacks.get(key)` does. The old rule wanted the same key
2180
- *and* the same origin, which this framework had invented. A caller that reused one key for two
2181
- different targets now sees their lines stacked together, and has to give each target its own key.
2182
- - One side identity in `MwlWorld` (item 277): `unit.side`, `MwlMessage.side`, `MwlMap.starts` keys
2183
- and every `side`/`side_filter` attribute now hold the string `id` `[side]` declares, so a named
2184
- side (`id=rebels`) works throughout. `MwlSideRef` is just that id. The `[side] id` and the other
2185
- side-identifying schema attributes accept a string (numbers still validate), and the map
2186
- `<side> <code>` keep marker accepts a name.
2187
-
2188
- ### Fixed
2189
-
2190
- - `ui.Window` (item 290): `closed` is now a getter to guard a caller's reference after `close()`,
2191
- `close()` is idempotent, input and layout on a closed window are no-ops rather than throws on
2192
- freed Pixi internals, and `WindowStack.push` refuses a closed window with a named error.
2193
-
2194
- ## [0.7.6] - 2026-09-11
2195
-
2196
- ### Added
2197
-
2198
- - `Blob.spread` returns the cells it just emptied, in reading order, so a game can turn the ground
2199
- under a fire to embers at the moment the flames leave it instead of diffing `cellsAbove` between
2200
- two steps to notice. Cells emptied before the step (a doused one) are not reported.
2201
-
2202
- ### Changed
2203
-
2204
- - `pixi.js` moved from `dependencies` to an optional peer dependency, the treatment
2205
- `@babylonjs/core` already had (item 175's 1.0 decision). The install line now names it:
2206
- `npm install @datamoc/mw_games pixi.js vite`. A game that only uses the renderer-free modules
2207
- never downloads it. Verified from an empty directory on all three documented paths: the
2208
- registry install, the `npm pack` tarball installed by path, and the no-install
2209
- `mw_games.global.js` script tag.
2210
-
2211
- ## [0.7.4] - 2026-09-11
2212
-
2213
- ### Added
2214
-
2215
- - `FloatingTextStack` owns the pop-ups a game spawns over world points: one `push` per number, one
2216
- `update(dt)` to drive them all, and pop-ups sharing a key and an origin stack apart instead of
2217
- overprinting. `FloatingText` gained a `hold` option for the classic hold-then-fade curve, and its
2218
- rise now moves an inner layer rather than the container itself - it used to overwrite the
2219
- container's own `y`, so a pop-up positioned at a world point jumped to `y = 0` on its first
2220
- update. The fade curve and the stacking rule are exported as pure functions, so both are tested
2221
- without a DOM.
2222
- - `ParticleEmitter` accepts a `frames` texture sequence, walked per particle across its own life -
2223
- the four frames of a flame, the puff of smoke - in place of the single `texture`. The current
2224
- frame is exposed as `Particle.frame` for the same reason the rest of the particle state is.
2225
- - `Bar` recolours its fill at runtime with `setColor(color)` and takes a `background` colour for its
2226
- track; both are readable back through `color`/`background`, and a runtime colour counts as
2227
- explicit so a later theme change cannot throw it away. These were the two blockers for a consumer
2228
- whose bars change colour with state (a health bar going red as it empties) and whose track is
2229
- black rather than the theme's panel fill.
2230
-
2231
- ## [0.7.3] - 2026-09-11
2232
-
2233
- ### Added
2234
-
2235
- - Hex-map parity for targeting, cones, area resolution, minimaps, markers, automap validation,
2236
- and multi-turn beam traversal, with topology-specific tests.
2237
- - The `multi-turn-beam` example demonstrates blockers, moving targets, per-turn damage, and
2238
- deterministic multi-turn action state.
2239
-
2240
- ### Changed
2241
-
2242
- - The public reference and API report document the new hex-aware map capabilities.
2243
-
2244
- ## [0.7.2] - 2026-09-11
2245
-
2246
- ### Added
2247
-
2248
- - Renderer-free JavaScript and optional Lua AI modules, including bounded alpha-beta search for
2249
- local actors and top-level controllers.
2250
- - MWL typed tables, references, campaign metadata, deterministic artifact emission, and richer
2251
- event, dialogue, expression, and persistence support.
2252
- - Stable caller-chosen entity ids, typed 2D value exports, affix pool filtering, and shared
2253
- CSV/MWL cell coercion.
2254
-
2255
- ### Changed
2256
-
2257
- - The chess example now uses the shared MWG alpha-beta primitive.
2258
- - The standalone bundle baseline, API report, documentation, and roadmap were updated.
2259
- - Release checks now isolate npm audit and package-smoke caches from user-level npm settings.
2260
-
2261
- ## [0.7.1] - 2026-09-10
2262
-
2263
- ### Added
2264
-
2265
- - MWL content-directory builds now generate game data, i18n, and asset manifests, with the
2266
- battle example consuming generated MWL content.
2267
- - `extract:html` extracts inline scripts, styles, data URLs, CSS data URLs, and `srcset`
2268
- resources from a self-contained HTML file.
2269
-
2270
- ### Changed
2271
-
2272
- - MWL generated-source diagnostics now use deterministic relative paths.
2273
-
2274
- ## [0.7.0] - 2026-09-10
2275
-
2276
- ### Added
2277
-
2278
- - MWL build-time compilation with one command producing compiled data, i18n, and asset manifests.
2279
- - Generic MWL item adapters for inventory, equipment slots, and stat modifiers.
2280
- - Catalog validation for duplicate ids, slots, effects, and hook references, with source locations.
2281
- - Game-provided numeric expressions and versioned MWL save migrations.
2282
- - Wesnoth CFG asset fields including images, profiles, icons, and sounds.
2283
-
2284
- ## [0.6.0] - 2026-09-10
2285
-
2286
- This is a pre-alpha, not an "early release" any more, and the project says so in README. The
2287
- same note records the naming plan for future major versions: 1.0 takes a name beginning with A,
2288
- 2.0 one beginning with B, and so on, none of them chosen yet. Code-wise this release is the
2289
- reduced-motion cluster from WebKit's "Responsive Design for Motion", done properly rather than
2290
- as a single media query.
2291
-
2292
- ### Added
2293
- - Reduced motion beyond the media feature (roadmap items 199-202): `MotionIntent` and
2294
- `motionDuration` let a caller say whether a motion is decorative or meaningful, so a trigger
2295
- can be replaced by a fade rather than deleted; `Tweener.tween` takes `{ intent, alternate }`;
2296
- camera follow and `FloatingText`'s rise now respect the preference (and `AnimatedSprite`
2297
- documents why it deliberately does not); `watchReducedMotion` reports a change while a game is
2298
- running, so an in-flight tween, burst or fade stops instead of finishing; and the interface
2299
- example gained a motion demo that `npm run motion:smoke` opens three ways (no preference,
2300
- `prefers-reduced-motion: reduce` before load, and a flip mid-session) in a real browser.
2301
-
2302
- ## [0.5.5] - 2026-09-10
2303
-
2304
- Accessibility reaches the framework floor: a reduced-motion switch the tween, particle, camera
2305
- and screen-effect paths already consult, WCAG contrast helpers for a `theme` palette, and a
2306
- screen-reader bridge `Window` and `MessageBox` announce through. The verification story catches
2307
- up as well - a published-package `file://` smoke, a bundle-size budget, a coverage floor,
2308
- cross-version save fixtures and a build of every example, all gated in CI. `Blob` moves to
2309
- `core` (a breaking import change) with a per-cell `clear`, `assets.load` can rasterize a vector
2310
- source at a chosen resolution, and a new benchmark settles the CSS/SVG-animation question in
2311
- Pixi's favour.
2312
-
2313
- ### Added
2314
- - `assets.load(paths, { resolution })` (roadmap item 198): rasterizes a vector source (SVG)
2315
- at a multiple of its intrinsic size instead of only at intrinsic size, so a game that zooms
2316
- into an icon asks for `2` or `3` rather than shipping a soft bitmap. Passing `onProgress`
2317
- alone still works. The colour-transform example loads its gem SVG at 2x.
2318
- - `npm run benchmark:animation`: measures CSS/SVG element animation against Pixi sprites (and
2319
- both at once) at increasing counts, sampling rAF intervals in headless Chrome. On an RTX
2320
- 3070, 4000 composer-animated SVG elements fell to ~14 fps while 4000 Pixi sprites held 60.
2321
- - Accessibility (roadmap item 192): `core.reducedMotion`/`setReducedMotion`/
2322
- `prefersReducedMotion` (the OS `prefers-reduced-motion` preference with a per-game override,
2323
- consulted by `Tweener`, `Camera`, `ScreenEffects` and `ParticleEmitter`),
2324
- `ui.contrastRatio`/`meetsContrast`/`relativeLuminance` for WCAG-checking a palette, and
2325
- `ui.screenReader`, a hidden `aria-live` mirror that `Window` (its title) and `MessageBox`
2326
- (each page and its choices) already announce through.
2327
- - `npm run package:smoke` (roadmap item 193): packs the tarball, installs it into a scratch
2328
- directory outside the repo, builds the tutorial's own tiny game and opens both that page and
2329
- the standalone `mw_games.global.js` from `file://` in headless Chrome.
2330
- - `npm run size:check` / `size:update` (194): the global bundle and `dist` against the
2331
- committed `tools/bundle-size.json`, failing past a 2% growth.
2332
- - `npm run coverage:check` (195): the existing suite under Node's line/branch/function floors.
2333
- - Cross-version save fixtures (196): committed `tests/fixtures/saves/` blobs for a floor,
2334
- a `GameState` and a `Blob`, loaded by `tests/save-compat.test.ts`.
2335
- - `npm run examples:build` (197): runs every `example:*:build` script, so a vite or
2336
- `emit-page` regression in any example is caught, not just the benchmarked ones.
2337
- - `npm run coverage` and `npm run visual:smoke:ui`. Coverage reuses the existing Node test
2338
- suite through `--experimental-test-coverage`, so measuring it costs no dependency. The
2339
- visual smoke builds the interface example, opens it from `file://` in headless Chrome, and
2340
- fails when the page errors or the canvas paints nothing, attaching the screenshot as a
2341
- GitHub artifact; CI runs it on every pull request.
2342
- - `core.Blob` gained a per-cell `clear(x, y)` (roadmap item 191): it zeroes one cell's
2343
- volume and leaves its neighbours alone, so a game can douse a single tile, seal a breach,
2344
- or put out one patch of fire without rebuilding the field.
2345
- - `npm run api:report` / `npm run api:check`, backed by the new committed `API_REPORT.md`:
2346
- a generated index of every public export and its declaration, so API renames, removals
2347
- and signature changes are visible in review instead of discovered by consumers.
2348
- `tests/api-surface.test.ts` emits declarations with `tsc --emitDeclarationOnly` and fails
2349
- when the committed report drifts; CI also runs `api:check` after the build.
2350
- - `tests/barrel-collisions.test.ts`: a guard that fails when two `export *` sources in the
2351
- same barrel export the same name, which TypeScript would otherwise resolve by silently
2352
- exporting neither.
2353
- - `@datamoc/mw_games/two-d/pixi-interop` is now a real published subpath, matching the
2354
- escape hatch ADR-001 already documented.
2355
-
2356
- ### Changed
2357
- - CI now runs the coverage floor, the bundle-size budget, `examples:build` and the
2358
- published-package smoke alongside its existing check/test/build/api gates, so neither
2359
- coverage, bundle growth, an unbuildable example nor a broken packed install can land
2360
- unnoticed.
2361
- - Formatting is now gated: Prettier over `src`, `tests`, `examples` and `tools`
2362
- (`.prettierrc.json`, `npm run format`/`format:check`, run in CI). No ESLint rule set comes
2363
- with it, and the reformat changes no behaviour (line wrapping, trailing commas and the
2364
- like); `barrel-collisions.test.ts` now tolerates Prettier wrapping a long
2365
- `export { ... } from './...'` across lines.
2366
- - ROADMAP.md: five verification gaps are recorded as the open backlog at the tail (193, a
2367
- published-package `file://` smoke; 194, a bundle-size budget; 195, a coverage floor; 196,
2368
- cross-version save fixtures; 197, building every example in CI), each with the concrete
2369
- number or path it should assert against. The 1.0 checklist's API line widens from
2370
- `DEPRECATED` alone to a full stability-marker contract (`@experimental` plus `DEPRECATED`).
2371
- - ROADMAP.md: item 192 records the accessibility gaps the list had never named (screen-reader
2372
- text for `ui` widgets, `prefers-reduced-motion`, palette contrast) as one open backlog item
2373
- at the tail; the roadmap-progress test now guards that open items sit after every shipped
2374
- one rather than forbidding them, so a recorded idea needs no test edit. The 1.0 exit
2375
- checklist now decides the published `dist` map files explicitly instead of leaving them to
2376
- drift.
2377
- - **Breaking: `Blob` moved from `mwg/roguelike` to `mwg/core`.** A grid of volumes is not a
2378
- dungeon-crawl concern, so the field now lives in the renderer-free `core` module (still
2379
- reachable at the top level from `mw_games`) and imports nothing. Import it from
2380
- `@datamoc/mw_games/core` instead of `@datamoc/mw_games/roguelike`. `spread`'s predicate
2381
- parameter is now named `open` rather than `passable`; positional callers are unaffected.
2382
- - Documentation page is now the `REFERENCE.md` module guide (with a sidebar TOC), and
2383
- the TypeDoc symbol dump lives under `documentation/api/` instead of being the front
2384
- door.
2385
- - ROADMAP.md: the last open item (175, the `pixi.js` dependency-shape question) is closed
2386
- by decision - `pixi.js` stays a direct dependency for the 0.x line and moves to an
2387
- optional peer dependency with 1.0. The stale priority prose is replaced with a current
2388
- statement, and the new "Parked decisions" and "1.0 exit checklist" sections record what
2389
- actually remains before 1.0.
2390
- - ADR-001's known gap is narrowed: `Sprite2D` closed the constructible-sprite half; the
2391
- remaining value-level exception is the one documented pixi-interop file.
2392
-
2393
- ## [0.5.4] - 2026-09-10
2394
-
2395
- Inline sound markers now travel with translated dialogue strings and fire at their visible
2396
- position during `MessageBox` reveals. The reference docs, webpage features, and string-editor
2397
- example now document and demonstrate `{sound:path}` markers.
2398
-
2399
- ## [0.5.3] - 2026-09-10
2400
-
2401
- Closes ROADMAP items 184-190, the string stack requested directly across one session:
2402
- translation editing (CLI and web), sound cues, f-string specs, markdown, and progressive
2403
- display.
2404
-
2405
- ### Added
2406
- - `examples/string-editor` (roadmap item 190) - the string editor as a playable page:
2407
- an English reference beside an editable French translation, rendered live through
2408
- `RichLabel` with an adjustable `{HP_loose}` variable, placeholder-drift warnings, and
2409
- a blip/hit/pickup cue per string that fires on the progressive reveal. Listed on the
2410
- website's examples page with its own generated diagram.
2411
- - `i18n:edit` cue preview (roadmap item 189) - `Ctrl+P` plays the current row's sound
2412
- cue through the OS player (`afplay`, `aplay`/`paplay`/`ffplay`, Windows WAV via
2413
- SoundPlayer; `MWG_SFX_PLAYER` names a replacement), falling through only when the
2414
- command itself is missing. Plain `p` stays unbound so previews never start by accident.
2415
- - Shared progressive display (roadmap item 188) - `ui.startReveal`/`advanceReveal`/
2416
- `completeReveal`/`revealComplete` behind `Label.showProgressive`/`updateReveal` and
2417
- `RichLabel`'s markdown-aware counterpart (markers never count or leak, via
2418
- `ui.sliceSpans`); `MessageBox` now runs on the same primitive with its
2419
- confirm-completes-then-advances rule unchanged.
2420
- - `i18n:edit` placeholder and markdown rendering (roadmap item 187) - panes preview
2421
- markdown as terminal bold/italic (`v` toggles raw source), flag placeholder drift
2422
- with a `≠` marker and per-row detail, hint the needed tokens in the edit prompt, and
2423
- report both in `--check` mode. Backed by `i18n.tokenizeMessage`/`diffPlaceholders`,
2424
- the same grammar `t()` interpolates with, so the check cannot disagree with runtime.
2425
- - `ui.RichLabel`/`parseMarkdown`/`stripMarkdown` (roadmap item 186) - basic inline
2426
- markdown for UI text (`**bold**`, `*italic*`, combined `***both***`, backslash
2427
- escapes) through Pixi `HTMLText`. The parser is pure and unit-tested; unmatched
2428
- markers stay literal. Heavier than `Label`, so meant for descriptions and help
2429
- bodies, not per-frame numbers or typewriter reveal.
2430
- - `i18n.formatSpec` (roadmap item 185) - Python f-string-style value formatting for
2431
- catalog placeholders (`{dmg:03d}`, `{hp:.1%}`, `{name:>12}`), with `!s`/`!r`/`!a`
2432
- conversions and `=` debugging, wired into `t()`/`tRaw` and FTL parsing. Verified case
2433
- by case against CPython output; an ill-fitting spec leaves its placeholder untouched.
2434
- The one divergence nothing can close: JavaScript numbers carry no int/float
2435
- distinction, so integer-valued floats take the integer path.
2436
- - `i18n` semantic `audio` channel (roadmap item 184) - `format(message, 'audio')`
2437
- resolves `<type>.audio` to a sound path a game plays through `mwg/audio`'s `Sound`,
2438
- one more presentation of the same simulation event. Resolves raw via the new `tRaw`
2439
- (no typographic spacing, no RTL wrapping), returns `''` when no cue is declared, and
2440
- never falls back to a bare type holding a sentence. `validateMessageAudio` flags empty
2441
- and non-string audio entries.
2442
- - `tools/i18n-edit.mjs` (roadmap item 184) - a split-screen terminal translation editor:
2443
- reference language left, translation right, either side any language (`x` swaps them),
2444
- per-string cue editing (`s`, one cue per semantic family), JSON/FTL auto-detection,
2445
- and a `--check` mode for CI. Pure session logic lives in `i18n/EditSession.ts`.
2446
-
2447
- ## [0.5.2] - 2026-09-09
2448
-
2449
- Closes ROADMAP items 178-182, five ideas raised against a reference game whose `main.ts` had
2450
- grown to roughly 7,800 lines. 178 and 181 turned out to describe the same mechanism and were
2451
- built as one primitive rather than two.
2452
-
2453
- ### Added
2454
- - `core.Registry` (roadmap item 180) - a named lookup registered once and read back by name,
2455
- the dispatch primitive underneath a catalog of factories or handlers, in place of a
2456
- hand-written `if`/`switch` cascade. No auto-discovery: a game still imports and registers
2457
- each entry itself.
2458
- - `core.SceneComponentHost`/`SceneComponent` (roadmap items 178, 181) - composes a scene out
2459
- of named sections (map logic, encounter logic, UI wiring), each its own module with
2460
- whichever `Scene` lifecycle hooks it needs, instead of one scene class accreting every
2461
- responsibility. Composition, not a base class, so it works whether a scene extends `Scene`
2462
- or `two-d.Scene2D`; uses `core.Registry` internally for its by-name lookup.
2463
- - `rpg.questsFromRows`/`QuestStageRow` (roadmap item 179) - groups a flat table of stage rows
2464
- (typically a `core.parseCSV` result, one row per stage sharing a `questId`) into
2465
- `QuestDefinition`s a `QuestLog` can `define`, the same relational shape `core.parseCSV`
2466
- already models elsewhere, in place of a hand-written `.ts` object literal nesting each
2467
- quest's stage array.
2468
- - `actors.toEntitySaveState`/`fromEntitySaveState`/`EntitySaveState` (roadmap item 182) - a
2469
- `BuiltEntity`'s mutable state (base stat values, level/experience, the carried item) in the
2470
- same "definitions supplied fresh on load" shape `StatBlock`/`Progression` already draw;
2471
- `fromEntitySaveState` rebuilds via `buildEntity` from the same row and catalog, then
2472
- overlays the saved state on top.
2473
-
2474
- ## [0.5.1] - 2026-09-09
2475
-
2476
- Closes ROADMAP item 148 (the last item open before this pass) and corrects an overstated
2477
- renderer-boundary claim found while auditing the roadmap for anything still open.
2478
-
2479
- ### Added
2480
- - `board.HexSkirmish` (roadmap item 148) - `startingSkirmish`/`setSkirmishTerrain`/
2481
- `canPlaceSkirmishUnit`/`addSkirmishUnit`/`skirmishMoves`/`moveSkirmishUnit`/
2482
- `skirmishAttack`/`skirmishIncome`/`endSkirmishTurn`, a Wesnoth-style hex army-game rules
2483
- layer distinct from `board.Tactics`: per-terrain movement cost and defence, adjacency-only
2484
- attacks where a surviving defender always strikes back, capturable villages that grant
2485
- income and heal their owner's units, no zone of control.
2486
- - `two-d/render.Sprite2D` - a bare, untinted, MWG-named re-export of Pixi's `Sprite`,
2487
- alongside the existing `Node2D`/`Shape2D`/`Text2D`. Closes half the gap ADR-001 and
2488
- ROADMAP item 167 had overstated as fully closed (see Fixed below); prefer
2489
- `render.TintedSprite` the moment a colour transform is needed.
2490
- - `core.parseCSV` (roadmap item 176) - a header-row CSV string into an array of typed row
2491
- objects, so a table shaped like `actors.AffixTable` can be authored as a spreadsheet
2492
- instead of a hand-written `.ts` object literal. `columns` coerces named fields to
2493
- `'number'`/`'boolean'`/`'list'`/`'map'`; an empty cell omits that field entirely, the same
2494
- as an optional property never set. Takes a raw string with no opinion on how it was
2495
- loaded, the same boundary `i18n.parseFTL` already draws.
2496
- - `actors.buildEntity`/`buildEntities` (roadmap item 177) - one hero/monster file row
2497
- (typically a `core.parseCSV` result) into a fully wired entity: a `StatBlock` of base
2498
- stats (every non-reserved column), an optional `Progression` against a named growth
2499
- curve, a starting item carrying a named starting affix, and a `core.ReactionTable`
2500
- already holding a low-HP rule if the row names a threshold. Every named reference
2501
- resolves through a game-supplied `EntityTemplateCatalog` - `mwg` never invents what a
2502
- name means, the same boundary `AffixDef.id` already draws.
2503
-
2504
- ### Fixed
2505
- - `ADR.md`'s ADR-001 and ROADMAP item 167 claimed the renderer boundary was fully closed
2506
- ("nothing left... not a gap"). Corrected (ROADMAP item 173): every *type* position across
2507
- the public API genuinely no longer names a `pixi.js` type, but `two-d/pixi-interop.ts` is
2508
- itself a literal re-export from `pixi.js`, and `package.json`'s `dependencies` still lists
2509
- `pixi.js` directly - a real, still-open gap at the value level, tracked as ROADMAP item
2510
- 175 rather than rushed through as a breaking dependency-shape change to an
2511
- already-published version.
2512
-
2513
- ## [0.5.0] - 2026-09-09
2514
-
2515
- A declarative reactions primitive, closing the "branch cascade of `if HP < n`" gap named
2516
- directly, plus a new website page collecting the framework's original, non-obvious
2517
- mechanisms for a game-developer audience.
2518
-
2519
- ### Added
2520
- - `core.ReactionTable`/`ReactionRule` (roadmap item 172) - named `when`/`action` rules
2521
- checked against any state shape (a `StatBlock`'s values, or a plain object's own fields
2522
- such as an item's durability), firing `action` the moment `when` turns true and staying
2523
- quiet while it remains true - edge-triggered the same way `roguelike.BossPhases` tracks
2524
- entered phases. A `once` rule retires after firing; the default re-fires on the next
2525
- rising edge. Lives in `core`, not `actors`, so the same table watches a character or an
2526
- inanimate object without either module depending on the other.
2527
- - `webpage/features/index.html` - ten specific, original mwg mechanisms (declarative
2528
- reactions, the per-sprite multiply-and-add colour transform, `Barrier`'s outermost-first
2529
- layered absorption, `Advancement`'s unified points/branch/capstone track, `Affix`'s
2530
- trigger-routed curse-derived enchantments, `TriggerTracker`'s turn-window streaks, i18n's
2531
- bidi-isolate/typographic rules, `StatStages`'s bounded ladder as one modifier, `Scramble`'s
2532
- honestly-scoped obfuscation, and the deliberate `Scheduler`/`TurnClock` split), linked from
2533
- every hand-authored page's nav.
2534
-
2535
- ## [0.4.3] - 2026-09-08
2536
-
2537
- A simplification pass across storage, selection, and text options, one pathfinding
2538
- allocation fix, a new opt-in build tool, and an interactive architecture diagram on the
2539
- website.
2540
-
2541
- ### Added
2542
- - `tools/compress-dist.mjs` (`@datamoc/mw_games/tools/compress-dist`) - writes precompressed
2543
- `.gz`/`.br` siblings (optionally `.xz` via a system `xz` binary) next to a build's text
2544
- files, for a server that can negotiate `Content-Encoding`; the originals are untouched, so
2545
- a `file://` page keeps working unchanged. Wired into `tools/emit-page.mjs`'s example build
2546
- step (`--no-compress`/`MWG_NO_COMPRESS=1` to skip, `--xz` to also archive).
2547
- - `webpage/design/architecture-explorer.html` - an interactive, pannable/searchable diagram
2548
- of `mwg`'s real module dependency graph (which modules reach `core`, which reach a
2549
- renderer), generated from `src/`'s own import graph rather than hand-drawn, linked from
2550
- the design page's "Module boundaries" section.
2551
-
2552
- ### Changed
2553
- - `core.StoredValue` - the read-with-fallback/write/remove trio `PlayerStats`, `RunHistory`
2554
- and `NewsSeenTracker` each hand-rolled slightly differently now share one implementation.
2555
- - `core.NewsClient` is rebuilt on the shared `HttpTransport` every other injectable HTTPS
2556
- client here already used, rather than its own hand-rolled timeout/abort handling.
2557
- - `two-d/ui.SelectionModel` - the highlight/select/confirm/wrap-at-both-ends contract
2558
- `ListView` and `IconGrid` had begun to implement slightly differently now lives in one
2559
- place; each widget keeps only what actually differs (1-D rows vs. 2-D cells).
2560
- - `two-d/ui`'s `Label`/`BitmapLabel` share their text-option shape and RTL-aware default
2561
- alignment through a new internal `themedText` helper instead of two copies.
2562
- - `rpg`'s `FreeMover`/`GridMover` share their "play this animation if the sprite has it"
2563
- guard; `actors`'s `applyStatusEffect`/`applyItemStatusEffect` share their clock-lease/
2564
- cancel logic. Both were identical code living in two places.
2565
- - `vite.lib.config.ts` and the examples' shared Vite config turn off `reportCompressedSize`:
2566
- the estimate cost a full in-memory gzip of the bundle for a number `tools/compress-dist.mjs`
2567
- reports for real now.
2568
- - `roguelike.Level` gained `forEachNeighbor` (visits a cell's neighbours via callback instead
2569
- of allocating an array), used by `Pathfinder`'s flood fills and `Placement.cellsNear` - the
2570
- hottest per-cell allocation in map generation, now gone.
2571
-
2572
- ## [0.4.2] - 2026-09-08
2573
-
2574
- A roadmap-management pass alongside three real capability gaps closed: deterministic dungeon
2575
- content placement, i18n catalog content tooling, and 2D/3D asset loading unified where it
2576
- correctly can be.
2577
-
2578
- ### Added
2579
- - `tools/roadmap-progress.mjs`/`roadmapProgress.js` gained an item-management panel: search,
2580
- "only open items", and local (never committed to `ROADMAP.md`) priority/status/assignee
2581
- triage per item, with export/import.
2582
- - `roguelike.candidateCells`/`cellsNear`/`selectDistinctCells` - deterministic content
2583
- placement over a `Level`: terrain/occupancy/region filters, radius-based clustering, and
2584
- bounded distinct-cell selection with a JSON-safe roll trace, composing for neighbouring
2585
- items, scattered decorations, and single room/branch rewards.
2586
- - `i18n.messageText`/`levenshteinDistance`/`findSimilarMessages` - near-duplicate catalog
2587
- message detection by edit distance.
2588
- - `i18n.catalogUsage`/`catalogCompleteness`/`pluralFormCoverage` - catalog statistics: used
2589
- vs. unused keys against a caller-supplied reference list, translated-fraction completion,
2590
- and CLDR plural-category coverage.
2591
- - `i18n.mergeCatalogKeys` - drops a merged key from a catalog, keeping the surviving key's
2592
- text; rewriting call sites stays the caller's own job.
2593
- - `assets.loadBinary`/`getBinary`/`isBinaryLoaded`/`releaseBinary` (also its own
2594
- `@datamoc/mw_games/assets/binary` entry point) - a renderer-free raw-byte cache, the
2595
- direct fix for `three-d`'s `Vox.parseVox` needing a game to fetch bytes itself.
2596
- - `3d/models`' `loadModelContainer3D`/`isModelContainerLoaded`/`releaseModelContainer` -
2597
- loads a glTF/GLB source once, caching the Babylon `AssetContainer`; a game calls the
2598
- container's own `instantiateModelsToScene()` for each independent, unaliased copy it
2599
- wants placed, rather than importing (and re-fetching) the same model every time.
2600
-
2601
- ### Fixed
2602
- - `two-d/ui`'s right-to-left mirroring was incomplete: `Bar`'s fill always grew from the
2603
- left, `IconGrid` always laid its columns left-to-right and never swapped what the
2604
- `'left'`/`'right'` actions meant, and `HelpScreen` always put its topic list on the left.
2605
- All three now mirror under `theme().direction === 'rtl'`, matching `Window`/`ListView`/
2606
- `Button`/`Label`, which already did.
2607
- - `ROADMAP.md` had two items both numbered 161, a genuine duplicate; the misplaced one was
2608
- renumbered and moved to the true end of the list before being implemented.
2609
- - `tools/build-webpage-docs.mjs`'s nested `npm install` could fail when the caller's own
2610
- global `~/.npmrc` set an `allow-scripts` value npm rejects for a project-scoped install;
2611
- that env var is now explicitly cleared for the nested call.
2612
-
2613
- ## [0.4.1] - 2026-09-07
2614
-
2615
- A study of `mwg-pixel-dungeon` (a reference game, not in this repo) recommended closing the
2616
- PixiJS boundary the rest of the way, a formal simulation runtime, stable entity identity, and
2617
- semantic messaging as framework primitives. All of it landed this release, plus the eight
2618
- architecture decisions it proposed, recorded in the new `ADR.md`.
2619
-
2620
- ### Added
2621
- - `core.EntityRegistry`/`EntityId` - assigns and looks up stable string ids for live objects,
2622
- so events, saves, AI targets and buffs can name a creature or item without holding it.
2623
- `idOf` is what a game passes as `Scheduler.toJSON`'s or `SimulationRuntime.snapshot`'s
2624
- `actorId`.
2625
- - `core.PresentationQueue` - plays a batch of simulation events one at a time, each waiting on
2626
- its own `play()`-returned duration, freed of any renderer - the presentation-side
2627
- counterpart to a `SimulationRuntime.dispatch()`/`runScenario()` result.
2628
- - `simulation.SimulationRuntime`/`SimulationContext`/`SimulationOutcome`/
2629
- `SimulationRuntimeRule`/`SimulationSnapshot` - a facade over one state + one
2630
- `roguelike.Scheduler` + one `core.Generator` for the interactive half of a turn-based
2631
- simulation: `dispatch` runs a single command, threading `random`/`scheduler` as context and
2632
- charging any returned cost; `snapshot`/`restore` capture and rebuild the whole triple.
2633
- Composes with the existing `advanceToInput`/`runScenario` rather than replacing them.
2634
- `simulation` also re-exports `Scheduler`/`Actor`/`SchedulerSnapshot` from `roguelike`.
2635
- - `roguelike.Scheduler` gained `postpone` (delaying an actor other than the current one) and
2636
- `toJSON`/`restore` (a deterministic snapshot keyed by a caller-supplied actor id), making it
2637
- the sole, serialisable authority on logical time.
2638
- - `i18n.SemanticMessage`/`MessageChannel`/`MessageFormatter`/`createCatalogFormatter` - a
2639
- typed `{ type, params }` communication intent rendered differently per channel (log/
2640
- compact/accessibility/debug) from the same catalog, built on the existing `t()`/plural/
2641
- Fluent machinery rather than a parallel implementation.
2642
- - `i18n.formatNumber`/`formatDate`/`formatList` - locale-aware `Intl` formatting for a message
2643
- that needs more than `{token}` substitution.
2644
- - `i18n.diffCatalogKeys`/`validateCatalog` - catalog consistency checks: two catalogs' key
2645
- sets compared, and one catalog's own empty messages/incomplete plural forms flagged.
2646
- - `two-d.render.Container2D`/`Texture2D`/`Rect`/`TextureRegion`/`rectOf` - plain,
2647
- renderer-free public types in place of `pixi.js`'s own `Container`/`Texture`/`Rectangle`;
2648
- `Scene2D.stage` is now typed `Container2D`, `SpriteSheet.region` returns a `TextureRegion`.
2649
- - `two-d.render.Node2D`/`Shape2D`/`Text2D`/`TiledSprite`/`Gradient` - bare, MWG-named
2650
- re-exports of Pixi's `Container`/`Graphics`/`Text`/`TilingSprite`/`FillGradient`, so a game
2651
- never has to name `pixi.js` for a plain layer, vector drawing, one-off text, a scrolling
2652
- tile, or a gradient fill.
2653
- - `two-d.pixi-interop` - the one sanctioned, explicit escape hatch for the rare Pixi-specific
2654
- need the facade above does not cover.
2655
- - `TintedSprite` (and everything built on it - `AnimatedSprite`, `TileMap`, `DialogueStage`)
2656
- now registers its own colour-transform Pixi pipe automatically on import; a game no longer
2657
- passes `{ extensions: [registerColorTransform] }` to `Game`.
2658
- - `ADR.md` - the eight architecture decisions from the `mwg-pixel-dungeon` study, each
2659
- recorded against the code and tests that enforce it.
2660
-
2661
- ### Fixed
2662
- - `ButtonSkin.texture`, `ButtonOptions.icon`, `IconGridItem.icon`, `ListItem.icon`, and
2663
- `Theme.panel` were still typed as raw `pixi.js` `Texture`/`Container` in public interfaces;
2664
- all retyped to `Texture2D`/`Container2D` (the same underlying type, not a breaking change).
2665
-
2666
- ## [0.4.0] - 2026-09-06
2667
-
2668
- **The reshaping release, and intended to be the last one.**
2669
-
2670
- `mwg` grew fast, and grew by accretion: the renderer ended up inside `mwg/core`, an event
2671
- interpreter ended up importing a widget library, the same idea got solved three or four
2672
- different ways in different modules, and several names meant a different thing depending on
2673
- which file you were reading. None of that was going to get cheaper to fix. A rename costs a
2674
- line in this file today; after 1.0 it costs somebody else's build.
2675
-
2676
- So this release spends the breakage budget deliberately, all at once, while the version
2677
- number still says it is allowed:
2678
-
2679
- - **The renderer is no longer part of the core.** `mwg/core` now holds the scene lifecycle,
2680
- input, saves, RNG and signals, and pulls in no renderer at all. `Game` and the display half
2681
- of `Scene` moved to the new `mwg/two-d`, which is where `render`, `ui` and `stage` now live
2682
- as well. `mwg/3d` is its Babylon counterpart, and neither costs a game anything if it is
2683
- not used.
2684
- - **Game logic is renderer-free too.** `mwg/rpg` was the last module reaching a renderer by
2685
- accident; its event interpreter now takes an injected dialogue presenter. So dungeon
2686
- generation, map events, quests, stats, turn order, inventory and battles all run under a 2D
2687
- game, a 3D game, or a headless test, unchanged. `tests/renderer-isolation.test.ts` walks the
2688
- real import graph and enforces exactly which modules may reach PixiJS or Babylon.
2689
- - **One idea, one spelling.** `advance(turns)` is turns and `update(dt)` is real seconds.
2690
- `toJSON`/`fromJSON` is how a class saves. "Nothing to pick" is `null`, not `-1` or
2691
- `undefined`. Two identical hook registries became one.
2692
- - **The character sheet can be saved.** `Inventory`, `StatBlock`, `EquipmentSlots`,
2693
- `Progression`, `SkillPoints` and `Charges` gained serialization, so a game stops hand-rolling
2694
- the most important half of its own save file.
2695
-
2696
- The hope, stated plainly: **1.0 should be this shape.** What remains before it is coverage and
2697
- confidence, not another reshuffle. Additions rather than renames from here.
2698
-
2699
- ### Added
2700
- - `two-d.ParticleEmitter` - a pooled, seeded particle emitter (sparks, dust, rain). The pool
2701
- is allocated once at `max` and never grows, and every draw goes through `core.Random`, so a
2702
- replayed run reproduces the same spray. Given no `texture` it runs the simulation and draws
2703
- nothing, which is how it is tested without a DOM.
2704
- - `two-d.ScreenEffects` - a full-screen colour wash: `fadeOut`/`fadeIn`/`flash`/`setTint`,
2705
- driven by `update(dt)` returning true on the frame an effect completes.
2706
- - `two-d.Tooltip` - a hover explanation over a themed `Window`, with a frame-driven delay and
2707
- edge-aware placement that flips rather than running off screen.
2708
- - `roguelike.RoomBuilder`/`hallBuilder`/`eligibleBuilders`/`pickBuilder`, and
2709
- `DungeonOptions.builders` - composable room interiors: the generator places and joins rooms,
2710
- a builder carves each one. A room no builder fits falls back to a plain hall.
2711
- - `roguelike.generateDungeonGraph` - the same pipeline as `generateDungeon`, also returning the
2712
- room graph, a rejected-placement retry count, and which builder carved each room.
2713
- `DungeonOptions.hooks` fires `onRoomPlaced`/`onCorridorCarved` as the pipeline runs.
2714
- - `roguelike.FeatureLayer` - a floor feature/event layer: named kinds with
2715
- `inspect`/`interact`/`consequence`/`persistent` rules attached to generated cells.
2716
- - `roguelike.rollRoster` - a variant-spawn/content-roll API: rare additions, per-entry
2717
- alternative swaps, then a shuffle, with every roll traced (including an explicitly deferred
2718
- one) for parity tests.
2719
- - `roguelike.compareDungeonArtifacts`/`checkDeterminism` - a dungeon parity harness that tags
2720
- every mismatch `'graph'` or `'paint'`.
2721
- - **Save/load for the character sheet.** `Inventory`, `StatBlock`, `EquipmentSlots`,
2722
- `Progression`, `SkillPoints` and `Charges` all gain `toJSON`/`fromJSON`. `Inventory` saves
2723
- per-item instance state (level, wear, affix, `instanceId`) while taking kind-level fields
2724
- from the game's own item table on load, so rebalancing reaches old saves. `StatBlock` saves
2725
- base values and deliberately no modifiers, since whatever applied them reapplies them.
2726
- `Charges` saves banked regeneration progress, so reloading cannot shorten a recharge.
2727
- - `core.HookRegistry` - the named-event registry `battle.BattleHooks` and
2728
- `roguelike.CombatHooks` are now both built on.
2729
- - `two-d/ui.messageBoxPresenter` - wires `rpg.EventRunner`'s dialogue to a `MessageBox` in one
2730
- argument.
2731
- - `rpg.MovableSprite`, `rpg.AutomapTarget`, `rpg.DialoguePresenter` - the structural shapes
2732
- that replaced concrete renderer types in `mwg/rpg`'s signatures.
2733
- - `core.Input` gains touch input: `touchCode`/`bindTouch`/`pressTouch`/`releaseTouch` follow
2734
- the same synthetic-code pattern `bindButton`/`pollGamepads` already use for a gamepad, so
2735
- `isDown`/`justPressed`/`justReleased` work unmodified for a touch-driven action. `attachSwipe`
2736
- resolves a one-finger drag into one of 8 directional action pulses by angle, or a `tap`
2737
- action for a short drag. `core.PlayerInput` gains matching `bindTouch`/`pressTouch`/
2738
- `releaseTouch` wrappers.
2739
- - `ui.Button` gains `onPress`/`onRelease` signals (pointerdown, and pointerup/pointerupoutside),
2740
- the hook a virtual on-screen d-pad button needs to feed `pressTouch`/`releaseTouch` for
2741
- hold-to-repeat movement, independent of `onClick`.
2742
- - `mwg/3d` gains `Collision3D.ts` (`buildHeightIndex`, `cellAt`, `heightAt`,
2743
- `resolveCapsuleAgainstGrid`): horizontal collision against `createTileGrid3D`'s stepped
2744
- grid, stopping a moving capsule/AABB at a raised column's edge instead of clipping through
2745
- it. `Character3D` takes an optional third constructor argument, `collideXZ`, to plug this
2746
- in; omitted, movement behaves exactly as before.
2747
- - `assets.fetchWithByteProgress` reports real cumulative bytes transferred (and the known
2748
- total, from `Content-Length`) for a real origin - a dev server, or a desktop host serving
2749
- through a virtual origin rather than `file://`. `desktop/MwgDesktopHost` now serves the
2750
- built game through `CoreWebView2.SetVirtualHostNameToFolderMapping` (a real `https://`
2751
- origin) instead of a plain `file://` navigation, which is what makes this - and any other
2752
- real network call - actually usable inside it.
2753
-
2754
- ### Changed
2755
-
2756
- - **Breaking: `mwg/render`, `mwg/ui` and `mwg/stage` moved under `mwg/two-d`.** The Pixi half
2757
- of the framework is now one module, symmetric with `mwg/3d`. Import from
2758
- `@datamoc/mw_games/two-d` (or the granular `two-d/render`, `two-d/ui`, `two-d/stage`). No
2759
- legacy aliases were kept.
2760
- - **Breaking: `Game` moved from `mwg/core` to `mwg/two-d`, and `Scene` split.** `core.Scene` is
2761
- now the renderer-free lifecycle (`create`/`update`/`resize`/`onSuspend`/`onResume`/`destroy`);
2762
- `two-d.Scene2D` adds the Pixi container and is what a 2D game extends. `SceneStack` is generic
2763
- over the scene type, so a Babylon game gets scene management, suspend/resume and minigame
2764
- stacking. **`mwg/core` now pulls in no renderer at all**, and neither does `mwg/rpg`.
2765
- - **Breaking: `rpg.EventRunner` takes `present: DialoguePresenter` instead of `windows`.** The
2766
- event interpreter no longer builds a `MessageBox`; use
2767
- `present: messageBoxPresenter(this.windows)` for the previous behaviour. `boxWidth`,
2768
- `boxHeight` and `speed` moved onto the presenter.
2769
- - **Breaking: `loadTiledMap` moved from `mwg/rpg` to `mwg/two-d/render`**, where the `TileMap`
2770
- and `SpriteSheet` it builds already lived.
2771
- - **Breaking: every "pick one" now returns `null`.** `Random.weighted` returned `-1` and
2772
- `Random.element`/`Random.weightedKey` returned `undefined`; all three now match
2773
- `rollEncounter`/`rollLoot`.
2774
- - **Breaking: one meaning per name.** `advance(turns)` is turns or rounds and `update(dt)` is
2775
- real seconds, so `EnvironmentClock.advance(seconds)` became `update(dt)`,
2776
- `Barrier.decay(ticks)` and `AbilityCycle.tick()` became `advance(turns)`,
2777
- `BossPhases.update(hpFraction)` became `check(hpFraction)`, and `QuestLog.advance` became
2778
- `advanceStage`. `EnvironmentClock.snapshot`/`restore` and `SupportLedger.save`/`restore`
2779
- became `toJSON`/`fromJSON`.
2780
- - **Breaking: `GridMover`/`FreeMover` take a `MovableSprite`** rather than an `AnimatedSprite`,
2781
- so a static sprite (or anything with `x`/`y`) works; the animation members are optional.
2782
- - `mwg/assets` split into renderer-free path resolution (`assets/paths`, its own export
2783
- subpath) and the Pixi-backed loader, which is what took Pixi out of `mwg/3d` and `mwg/audio`.
2784
- - Per-module export subpaths now ship TypeScript types; previously only the package root did,
2785
- so `@datamoc/mw_games/core` resolved to `any` under `moduleResolution: bundler`/`node16`.
2786
- - `sideEffects` narrowed from a blanket `false` to the two `mwg/3d` files with real
2787
- side-effect imports, so a bundler can no longer drop Babylon's glTF and thin-instance
2788
- registrations.
2789
-
2790
- ### Fixed
2791
- - `examples/three-d`'s hero now actually collides with the raised ridge its demo path crosses,
2792
- rather than the path being hand-routed around it.
2793
-
2794
- ## [0.3.1] - 2026-09-05
2795
-
2796
- ### Added
2797
- - `audio.Music.playTracks(paths, fadeDuration)` plays a playlist rather than one looping
2798
- track: each track plays once, `HTMLAudioElement.onended` (when the backend exposes it)
2799
- advances to the next, and the sequence cycles once it reaches the end. `play()`/`stop()`
2800
- cancel an active playlist so a stale `onended` from a track already replaced cannot advance
2801
- a newer one.
2802
-
2803
- ## [0.3.0] - 2026-09-05
2804
-
2805
- ### Added
2806
- - `core.PlayerStats` (a lifetime total, folded per run - deliberately not derived from
2807
- `RunHistory`, which can drop old entries), `ui.StatsScreen` (a `label: value` display
2808
- recipe), and `core.TelemetryClient` (automatic structured events, off by default until a
2809
- game calls `setConsent(true)`).
2810
- - `tools/benchmark-browser.mjs` now records each run's fps/p95/memory to a per-page history
2811
- file (`benchmark-results/`, gitignored) and fails on a regression against the best-seen
2812
- prior run, not only its fixed gate. `npm run benchmark:tower-defense`/`benchmark:ui` cover
2813
- those examples the same way `benchmark:browser`/`benchmark:3d` already did.
2814
- `tools/benchmark-simulation.mjs` (`npm run benchmark:simulation`) measures headless
2815
- `runScenario`/`advanceToInput` throughput, with the same history tracking.
2816
- - `core.LockstepClient` and a reference server, `tools/multiplayer-server.mjs` (real-time
2817
- multiplayer's one exception to "`mwg` ships no backend"): lockstep tick authority over a
2818
- plain `WebSocket`, server-assigned identity, and a `?room=` matchmaking string. Run it with
2819
- `npm run multiplayer:server`.
2820
- - `core.SaveSyncClient.list()` returns every save-profile slot name an endpoint holds, so a
2821
- player's multiple named profiles (`SaveSystem` already supports as many as a game creates)
2822
- can each sync independently against one endpoint.
2823
- - `desktop/MwgDesktopHost`, a minimal WebView2 (WinForms, net8.0-windows) reference host that
2824
- loads a built example's own `index.html` via `file://` unmodified. `npm run desktop:build`/
2825
- `desktop:run` mirror the existing `cap:*` scripts' naming and target the same `tower-defense`
2826
- reference build. Verified with a real `dotnet build`/`dotnet run` and a screenshot of the
2827
- running window showing the game actually rendered.
2828
- - `assets.load` and `assets.AssetStream`'s `preload`/`preloadLikely` take an optional
2829
- `onProgress` (asset-count fraction, not literal bytes), threaded through `examples/loading`'s
2830
- own tasks into `LoadQueue.report`. Eviction under a tight budget was verified in a real
2831
- browser across 300 preload/evict cycles: resident texture count stayed pinned to the budget
2832
- throughout.
2833
- - `render.StatusVisuals` maps active status-effect names to a tint on a sprite (priority by
2834
- declaration order, an optional pulsing strength), bridging `actors.applyStatusEffect`'s
2835
- game-side data to what a character looks like without either module importing the other.
2836
- - `mwg/simulation` (`Simulation` on the standalone build): `advanceToInput` runs a
2837
- scheduler's automatic actions up to a budget until an actor needs input, and
2838
- `runScenario` applies a finite command sequence against caller-supplied rules. Both
2839
- are headless, with no rendering or browser imports, and take random state explicitly
2840
- for reproducibility.
2841
- - Button accepts a per-instance nine-patch skin with state tints and caption styling, including captions created later with setText.
2842
- - Label accepts stroke, resolution and roundPixels options. Existing defaults are unchanged. Textures remain owned by the caller.
2843
-
2844
- ### Changed
2845
- - **Breaking:** `core.SaveSyncClient.upload`/`download` now take a `slot` name -
2846
- `upload(payload)`/`download()` are `upload(slot, payload)`/`download(slot)` - so one
2847
- endpoint can hold more than one player profile.
2848
-
2849
-
2850
- ## [0.2.1] - 2026-09-05
2851
-
2852
- ### Fixed
2853
- - `Sound.play()`, `Music.play()` and `Synth.playTone()` discarded the `Promise` that
2854
- `HTMLAudioElement.play()` returns with no rejection handler. Reusing a pooled `Sound`
2855
- instance before its prior `play()` settled, or `Music`'s crossfade pausing the previous
2856
- track while the incoming one was still loading, rejects that promise ("The fetching
2857
- process for the media resource was aborted..."), which surfaced as an unhandled
2858
- rejection instead of being silently absorbed, the correct handling for an interruption
2859
- that is expected, not an error.
2860
- - `Camera.update()` computed its deadzone size through the `view` getter, which also
2861
- clamps to bounds and allocates a rectangle object - two needless allocations every
2862
- frame for values the deadzone calculation never used.
2863
-
2864
- ## [0.2.0] - 2026-09-05
2865
-
2866
- ### Added
2867
-
2868
- **Core**
2869
- - `Tweener`/`Easing`, `UndoHistory`, `PlayerInput` (rebindable action-to-key mapping),
2870
- `RunHistory` (per-run reports and rankings, no online component), `News` (`NewsClient`,
2871
- `NewsSeenTracker`), `Sanitize` (`checkSize`, `checkNoControlCharacters`,
2872
- `sanitizeInboundText`, `validateSchema` - a 10MB default size cap and no embedded control
2873
- characters on any inbound save/news/sync data), `Scramble`, `SaveSync` (`SaveSyncClient`),
2874
- `Save.exportSlot`/`importSlot`, `Loading` (`LoadQueue`), `Feedback` (`FeedbackClient`),
2875
- `Input.onWheel` (wheel scroll as a first-class input signal alongside keys, not just a
2876
- `ListView` feature - horizontal-scroll and zoom modifier keys resolve to a
2877
- `WheelAction`/`WheelInput` the game interprets, distinct from the browser's own scroll/zoom).
2878
- - `version`: `mwg`'s own version string, exported from `mwg/core` and kept in sync with
2879
- `package.json` by a dedicated test.
2880
-
2881
- **Render**
2882
- - `Viewport`/`splitScreenHalves` (local split-screen multiplayer), `Camera.setViewport`
2883
- screen offset, `ColorBlindness` (`createColorBlindnessFilter`, accessible colour modes),
2884
- `Capabilities.inspectGraphicsCapabilities`/`detectWebGpu` (real WebGPU shader-compile
2885
- probe, not just a `navigator.gpu` existence check), `Streaming.AssetStream`.
2886
-
2887
- **UI**
2888
- - `BitmapLabel`, `Toast`, `theme.highContrastTheme`, `LoadingScreen`, pointer and wheel
2889
- support on `ListView`/`IconGrid`, `Bar` fill/background textures with pixel rounding.
2890
-
2891
- **Audio**
2892
- - `Synth` (`synthesizeTone`, `playTone`), `Midi` (`parseMidi`, `scheduleMidi`,
2893
- `MidiPlayer`, `noteToFrequency`), `Captions` (`onCaption` - subtitles for accessibility).
2894
-
2895
- **Actors / World / Board / RPG**
2896
- - `Support` (`SupportLedger`), `ItemStatusEffect.applyItemStatusEffect` (temporary item
2897
- status), `Environment` (`EnvironmentClock`), `FogOfWar.FactionFog`, `Collision`
2898
- (`aabbOverlap`, `circleOverlap`, `circleAabbOverlap`, `resolveAabbAgainstTiles`).
2899
-
2900
- **i18n / Stage**
2901
- - `Fluent.parseFTL`, typographic apostrophes, `StageScript.history`/`showLast`/`skipSeen`,
2902
- `MessageBox` `nvl` mode and `autoAdvance`.
2903
-
2904
- **3D, mobile and desktop**
2905
- - `Character3D.playAnimation`/`stopAnimation`/`currentAnimation`,
2906
- `Heightmap.createHeightmapTerrain3D`, an Ionic Capacitor integration for native
2907
- iOS/Android packaging, and a WebView2 desktop host reference under `desktop/`.
2908
-
2909
- **Examples**
2910
- - `examples/loading` (`LoadQueue`/`LoadingScreen`/`AssetStream` end to end, including a
2911
- deliberately-failing-once task exercising retry), `examples/three-d`,
2912
- `examples/tower-defense`.
2913
-
2914
- ### Changed
2915
- - `graphics-capabilities`'s `wgsl` capability now defaults to `false` unless a real
2916
- WebGPU shader-compile probe supplies it, instead of asserting true from
2917
- `navigator.gpu`'s mere existence.
2918
- - `tools/find-chrome.mjs` extracted from the byte-identical `findChrome()` duplicated in
2919
- `benchmark-browser.mjs` and `graphics-capabilities.mjs`.
2920
-
2921
- ## [0.1.2] - 2026-09-03
2922
-
2923
- ### Added
2924
- - `Session`: counts how many times a game has launched, persisted across page loads (the
2925
- same `SaveStorage` abstraction `SaveSystem` uses) - the signal a native wrapper needs to
2926
- decide whether to ask for a store rating. `mwg` counts; it never prompts, and bundles no
2927
- store/ads/IAP SDK of any kind.
2928
-
2929
- ### Changed
2930
- - **Breaking:** `Game` no longer registers `mwg/render`'s colour-transform batcher
2931
- automatically. `mwg/core` imported from `mwg/render` to do this, meaning a game that
2932
- only imported `mwg/core` still compiled in the whole render module. `GameOptions` gained
2933
- `extensions`, a list of Pixi-extension registration functions the caller supplies
2934
- instead: a game using `TintedSprite` (directly, or via `TileMap`/`DialogueStage`/
2935
- `AnimatedSprite`) now passes `{ extensions: [registerColorTransform] }` explicitly.
2936
- `mwg/core` now imports from no other module.
2937
-
2938
- ## [0.1.1] - 2026-09-03
2939
-
2940
- First tagged release. Everything below shipped on `main` before this tag existed; nothing
2941
- in it is new as of the tag, only now given a version number to refer to.
2942
-
2943
- ### Added
2944
-
2945
- **Core**
2946
- - `Game` (owns the Pixi `Application`, the frame loop, current `Scene`), `Scene`, `Signal`
2947
- (typed event emitter, stack-mode listener order), seeded `Random` (save/restorable state,
2948
- `withSeed` for scoped determinism), keyboard `Input` with rebinding.
2949
- - `Achievements`: named milestones unlocked by counters crossing a target - unlocking is
2950
- derived, never stored; the increment that earns one reports it, `drainNew()` queues
2951
- announcements, and loaded counts announce nothing.
2952
- - `Game.step(dt)`, to drive a frame by hand - needed because Chrome throttles
2953
- `requestAnimationFrame` in a background tab.
2954
- - `SaveSystem`: named, versioned save slots over `localStorage`, with an in-memory fallback.
2955
- - `Recorder`/`Player`: action recording and replay for testing - every `Input.onAction`
2956
- stamped against the `Game.onFrame` count, re-dispatched at the same counts while the loop
2957
- is driven by hand with `Game.step(dt)`; `serializeReplay`/`deserializeReplay` round-trip
2958
- the log with validation.
2959
- - `Collection`: named record collections over `localStorage` (quest logs, bestiaries,
2960
- achievements) - `all`/`get`/`put`/`remove`/`where`/`clear` reading storage directly, so
2961
- there is no cached copy to go stale; `SaveSystem`'s memory fallback is now shared.
2962
- - `SceneStack` with `Game.pushScene`/`popScene`: a scene suspends underneath another and
2963
- resumes with a result via `Scene.onSuspend`/`onResume` - only the top scene updates, all
2964
- render, so overlays and opaque scenes both work.
2965
- - `Logger`: categories and severity over bare `console.log` - four levels, a filter, and a
2966
- sink tests capture instead of the console.
2967
- - `Hex`: cube-coordinate hex grid math (`hexNeighbors`, `hexDistance`, `hexLine`, `hexRange`,
2968
- `hexToPixel`/`pixelToHex`), orientation-agnostic and shared by `roguelike` and `render`.
2969
-
2970
- **Render**
2971
- - `Camera`, `TileMap` (chunked and culled against the camera; `square`, `hex`, `isometric`, and
2972
- `staggered` projections, all culled through one shape-agnostic bounding-box method), `SpriteSheet`, `AnimatedSprite`,
2973
- `TintedSprite`, and `ColorTransformBatcher` - a per-sprite multiply-and-add colour transform
2974
- in the batch shader, which Pixi's built-in tint cannot do.
2975
- - `LayeredSprite`, for characters built from swappable parts (skin, hair, garment).
2976
- - `ActorAnimator`: the idle/move/action animation-state convention `AnimatedSprite` and
2977
- `GridMover` never had on their own, with the one rule that makes them coherent - an action
2978
- interrupts idle/move, but is not itself interruptible while it plays.
2979
- - `Projectile`: tweens a sprite's position in a straight line, the render-side half of aiming
2980
- a thrown item or a wand bolt.
2981
- - `blobIndex`/`autotileFrames`/`BLOB_SHAPES`: the classic 256-combination-to-47-shape blob-tile
2982
- reduction for auto-tiling a terrain edge or corner from many small pieces.
2983
- - Verified: SVG textures load correctly through the compiled `data:` URI path; the render path
2984
- holds 60fps at 4000 tinted sprites and over a 160,000-cell synthetic map, with no silent
2985
- fallback off WebGL.
2986
- - `TileMap` reads one sheet per tileset (`tileFrame` packs naming the sheet; plain indices
2987
- still read as sheet 0), and cells carry an elevation: `setCellHeight` lifts the top tile
2988
- by `heightStep` per level, growing two shaded side faces per level on the diamond
2989
- projections, with `tileCenter` riding along so occupants stand on top.
2990
-
2991
- **Assets**
2992
- - `load`/`texture`/`get`/`resolve`, synchronous after one `load()` call per scene.
2993
- - `tools/compile-resources.mjs`: turns every asset into a `data:` URI script, so a compiled
2994
- build never needs `fetch`/XHR (both blocked from `file://`).
2995
-
2996
- **UI**
2997
- - `Window`, `WindowStack` (keyboard focus to the top window only), `ListView`, `MessageBox`,
2998
- `Label`, `NinePatch`, `VerticalLabel` (for vertical writing systems), `theme`.
2999
- - `IconGrid`: a multi-column icon grid alongside `ListView`, for SPD-sized item counts. Tap-
3000
- then-tap reordering and a frame-driven long-press-to-quickslot timer, both plain methods a
3001
- test can drive without simulating pointer events.
3002
-
3003
- **i18n**
3004
- - Message tables, `Intl.PluralRules`-backed plurals, `{token}` interpolation, and
3005
- `direction()` (ltr/rtl), which `ui`'s `Theme.direction` reads from a game's own glue code.
3006
-
3007
- **Actors**
3008
- - `StatBlock` (base + derived stats through a fixed add→multiply→set modifier order),
3009
- `EquipmentSlots` (ties an item's modifiers to a stat block on equip/unequip),
3010
- `Progression`/`powerCurve` (levels and experience over a replaceable growth curve),
3011
- `Inventory` (stacking, weight, containers), `skillCheck`.
3012
- - `SkillPoints`: a per-stat spendable ledger over a `StatBlock`, with a rising cost-per-rank
3013
- callback and an optional cap - deliberately not a wrapper around `Progression`, just bridged
3014
- to it by the points a level-up grants.
3015
- - `craft(inventory, recipe)`: consumes every ingredient and adds the result atomically - an
3016
- ingredient shortfall or a result that doesn't fit rolls back everything already removed.
3017
- - `applyStatusEffect`: a temporary buff/debuff - applies `StatBlock` modifiers and registers
3018
- their removal against any clock shaped like `TurnClock`'s `add`/`remove`, returning a handle
3019
- whose `cancel()` removes them early (a cure, a remove-curse scroll).
3020
- - `identify`/`enchant`/`damageItem`/`repairItem`: item-depth functions over a plain
3021
- `InventoryItem`, which gained `level`, `durability` and `maxDurability` fields - durability
3022
- is opt-in per item, a no-op without `maxDurability` set.
3023
- - `Charges`: a resource that regenerates on its own as turns pass (a wand's limited charges),
3024
- distinct from a `StatBlock` stat spent per use and restored only by an explicit event.
3025
- - `rollLoot`: a weighted drop table, the same shape as `world.rollEncounter` - roll whether
3026
- anything drops, then weight-pick which.
3027
- - `buy`/`sell`: a shop transaction between two `Inventory`s paid from a `StatBlock` currency
3028
- stat, all-or-nothing like `craft()` - a full stock/buyer-capacity rollback on failure.
3029
- - `Advancement`: tiered specialization (level-gated point tiers, one permanent branch choice,
3030
- one capstone) with a point ledger - never the spend rule, which stays game-side.
3031
- - `rollAffix`/`applyAffix`/`removeAffix`/`affixOf`: named item affixes carrying only trigger,
3032
- weight and curse flag; `InventoryItem` gained an optional `affix` field.
3033
- - `scaledModifiers`: `{stat, op, base, perLevel}` templates resolved to plain `Modifier`s at
3034
- a given item level.
3035
- - `Appearances`: per-run seeded shuffling of which look each unidentified kind wears, with
3036
- `toJSON`/`fromJSON`.
3037
- - `canAfford`/`spend`: a spendable per-use resource (mana, stamina) over a `StatBlock`
3038
- pool - one cost or several, all-or-nothing `craft()`-shaped, with a negative cost
3039
- refused as an authoring error rather than a refund.
3040
-
3041
- **Roguelike**
3042
- - `FieldOfView` (visible/explored/remembered), `Pathfinder` (A*, a Dijkstra distance map,
3043
- `autoExplore`), `Scheduler` (energy-cost turn order), `generateDungeon` (seeded, with an
3044
- optional `kinds` list for a game's own terrain ids alongside wall/floor).
3045
- - `decideMonsterAI`: a wander/hunt/flee behaviour loop over a monster's own `FieldOfView`
3046
- (not the player's), built entirely from already-shipped primitives.
3047
- - `Secrets`: discoverable/hidden tile state (secret doors, undiscovered traps). A concealed
3048
- cell is disguised straight in `Level`'s own terrain, so `FieldOfView`/`Pathfinder` need no
3049
- changes to support it.
3050
- - `chebyshevDistance`/`traceLine`/`hasLineOfSight`/`canTarget`/`resolveArea`: targeting via a
3051
- Bresenham line trace (a different, cheaper question than `FieldOfView`'s shadowcast), with
3052
- `single`/`line`/`burst` area resolution.
3053
- - `decideMonsterAI` gained a `disposition` option (`hostile`/`neutral`/`peaceful`, defaulting
3054
- to `hostile`, unchanged) and a `provoked` flag - a peaceful/neutral monster always wanders
3055
- until either overrides it back to hunting.
3056
- - `Doors`: open/closed/locked door state, `Secrets`' own shape reused - the state is just
3057
- terrain, swapped between a door's own open/closed kinds; locking is a separate flag that
3058
- keeps a door closed and unopenable until `unlock` is called.
3059
- - `BossPhases`/`AbilityCycle`: HP-fraction thresholds reporting newly entered phases in
3060
- order, plus named ability cooldowns with `tick`/`ready`/`use` - both JSON round-trippable.
3061
- - `Blob`: per-cell volumes diffused into passable neighbours and decayed per step, with
3062
- `cellsAbove` for the game to apply its own effects on.
3063
- - `Level`, `Secrets` and `Doors` gained `toJSON`/`fromJSON` - the game's own `kinds` table
3064
- (or live level) is supplied fresh on load, `QuestLog`'s own convention.
3065
- - `Elevation`: a discrete height per cell, in the `Secrets`/`Doors` sidecar shape.
3066
- `FieldOfView.update` takes it for asymmetric cliff sight (a cell blocks exactly when
3067
- above viewer and target alike), and `Pathfinder` takes it with a climb limit (ascent
3068
- capped, descent free).
3069
-
3070
- **World**
3071
- - `World` (many maps, each created once and kept alive, with an explicit non-persistent mode
3072
- for SPD-shaped floors that rebuild fresh every visit), `Overworld`, `TurnClock`,
3073
- `rollEncounter`.
3074
-
3075
- **RPG**
3076
- - `loadTiledMap` (orthogonal, single embedded tileset, uncompressed CSV layers; isometric and
3077
- staggered orientations too, each mapped to the matching `TileMap` shape), `GameState`
3078
- (switches/variables), `MapEvent`/`activePage` (last matching page wins), `EventRunner`,
3079
- `GridMover` (tweened tile movement, a walk cycle, and `turnTo` for facing without moving).
3080
- - `QuestLog`: staged quest/mission definitions (`canStart`/`start`/`advance`/`status`), with
3081
- `toJSON`/`fromJSON` for `SaveSystem`.
3082
- - `loadTiledMap` reads any number of tilesets - embedded or external (fetching an external
3083
- `.tsx`/JSON stays the caller's asset loading) - resolving each gid by Tiled's own
3084
- greatest-firstgid-at-or-below rule.
3085
- - `automap`: Tiled-style automapping rules - `input` patterns matched anywhere (`EMPTY`
3086
- constrains nothing), one `output` variant written per match (`EMPTY` leaves the cell
3087
- alone), rules applied in order with each rule's matches collected before any write.
3088
-
3089
- **Stage**
3090
- - `DialogueStage` (backdrop, characters standing in front of it, expressions, speaker focus)
3091
- and `StageScript`, a small command interpreter run as one awaited call.
3092
- - `StageScript.runStory`: a story as a graph of named passages - `{goto}` commands and
3093
- `StageChoice` jumps between them, falling off a passage ending the story.
3094
- - `importTwee`: Twine's Twee notation (plain text, no DOM needed) into a `StoryScript`:
3095
- text lines become `say`, `[[links]]` in all three forms become one closing `ask`, and
3096
- dangling links, doubled passages and setter links are refused rather than half-read.
3097
-
3098
- **Battle**
3099
- - `Creature` (wraps `actors.StatBlock`/`Progression`), `TypeMatrix`, `Party`, `battleOrder`,
3100
- `checkEvolution` (last-match-wins, so a multi-stage chain reaches its final form).
3101
- - `StatStages`: a bounded, symmetric stage ladder over a `StatBlock` stat (Swords Dance's own
3102
- shape) - replaces rather than stacks a stat's current modifier, and `resetAll()` clears
3103
- every stage in one call for the switch-out rule.
3104
- - `chooseMove`/`chooseSwitch`: battle AI built on `TypeMatrix.multiplierFor` - a move scored
3105
- by type effectiveness (or a custom `score`), and a switch suggested only when the bench has
3106
- a genuinely better defensive matchup than staying in.
3107
- - `BattleHooks`: a battle-scoped event/hook system for passive abilities and held items,
3108
- keyed by a plain event-name string a game's own battle loop defines; `offSource` removes
3109
- every hook tied to one source (an ability leaving the field on faint).
3110
- - `Field`: named, optionally-timed battle-wide conditions (weather, terrain, a screen) a game
3111
- reads directly (`field.has('rain')`) - distinct from any one creature's own `StatBlock`.
3112
-
3113
- **Board**
3114
- - `mwg/board`: a generic `BoardGrid` (owned pieces on a cell grid, move/capture) plus four
3115
- traditional games built on it - chess (`startingChess`/`legalMoves`/`applyMove`, FEN
3116
- parsing, check/mate/stalemate/draw detection, and a material-evaluation alpha-beta
3117
- `chooseMove`/`search` engine), checkers (forced captures, multi-jump chains, king
3118
- promotion), go (placement, capture-by-surrounding, ko, area scoring after two passes),
3119
- and backgammon (points, bar/off, dice, hitting a blot).
3120
- - `startingTactics`/`tacticalMoves`/`tacticalAttack`/`setTacticalOverwatch`: a small
3121
- grid-tactics layer (move/shoot/overwatch, one action budget per unit per turn) for an
3122
- XCOM-shaped turn.
3123
- - `createDeck`/`shuffleDeck`/`deal`: a standard 52-card deck (with optional jokers), shuffled
3124
- and dealt into equal hands; `trickWinner` resolves one trick - highest trump, or highest of
3125
- the lead suit with no trump played - leaving bidding and stakes to the game.
3126
- - `dealSolitaire`/`drawSolitaire`/`moveSolitaireTableau`/`moveSolitaireToFoundation`/
3127
- `solitaireWon`: a seeded Klondike deal and its four moves - stock/waste draw with
3128
- waste-recycling, alternating-colour descending tableau moves, ace-up same-suit foundation
3129
- moves, and the all-four-full win check.
3130
- - `rollDice`/`rollExpression`: `NdM` and `NdM±K` dice notation over `Random`. `DiceCup`: a
3131
- kept-die reroll cup (`keep`/`reRoll`/`clearKept`). `scoreDice`: all thirteen standard
3132
- Yahtzee-shaped categories over a five-die hand.
3133
-
3134
- **Roguelike**
3135
- - `CombatHooks`: named-event listeners for a grid actor's combat lifecycle
3136
- (`beforeAttack`/`beforeDamage`/`afterDamage`/`onKill`, or any game-defined event string),
3137
- optionally tagged by source for bulk removal; `modifyDamage` runs the `beforeDamage` seam
3138
- and clamps/reports whether the hit was fully prevented. HP, formulas and when each event
3139
- fires stay game-side.
3140
-
3141
- **Audio**
3142
- - `Sound` (pooled, round-robin) and `Music` (crossfade via `update(dt)`), both taking an
3143
- injectable `create()` in place of `new Audio()` for testing.
3144
-
3145
- **Examples**
3146
- - `colour-transform`, `interface`, `dialogue`, `village` (an NPC with switch-selected
3147
- conversation pages and an autorun cutscene), `battle`, `dungeon` - an SPD-shaped
3148
- mockup wiring together most of the above: generated floors, three-state fog of war,
3149
- bump-to-attack, wander/hunt/flee monsters, secret doors and hidden traps, a thrown flask
3150
- of oil, a dense icon-grid inventory, autosave-on-descend with permadeath - and `chess`, a
3151
- playable board against `mwg/board`'s search engine, moved by click-to-select-then-move or
3152
- a held/repeating arrow-key cursor.
3153
-
3154
- **Project**
3155
- - A project website with a live colour-transform demo, the capability-spec table, and the
3156
- roadmap, deployed to GitHub Pages.
3157
- - TypeDoc-generated API documentation, built through an isolated toolchain (TypeDoc needs
3158
- TypeScript's classic compiler API, which TS7 no longer exposes through its main package).
3159
-
3160
- ### Changed
3161
- - `generateDungeon` gained an optional `kinds` list, so a game can add its own terrain ids
3162
- (a trap kind, say) alongside the generator's wall/floor without forking it.
3163
- - `Targeting`'s `AreaShape` gained `cone`, and `coneCells`/`chainTargets`/`knockbackPath`
3164
- cover sprays, arcs and shoves alongside the existing `single`/`line`/`burst` resolution.
3165
- - `EquipmentSlots` gained an optional `locked` predicate - a locked slot reports `isLocked()`
3166
- and refuses both `unequip` and swaps; without it every slot behaves exactly as before.
3167
- - `examples/dungeon`'s inventory screen is an `IconGrid` now, not a `ListView`.
3168
- - `TurnClock`'s `TimedEffect` gained an optional `onExpire` callback, fired once right before
3169
- an effect whose duration has run out is removed - what `applyStatusEffect` needed to tie a
3170
- status effect's expiry to removing the `StatBlock` modifiers it applied.
3171
- - `Game`'s scenes run as a stack: `switchScene` replaces everything, `pushScene`/`popScene`
3172
- suspend and resume; only the top scene updates, all render, and resize reaches the whole
3173
- stack.
3174
- - `Pathfinder`'s search loops check the step (both ends on the map, climb within limit)
3175
- rather than the destination cell alone.
3176
-
3177
- ### Fixed
3178
- - `checkEvolution` was first-match-wins; a multi-stage evolution chain could get stuck on an
3179
- earlier form instead of reaching its final one. Now last-match-wins, matching
3180
- `Event.activePage`'s own convention.
3181
- - `GridMover` never updated `facing` on a *blocked* move, so approaching an NPC from certain
3182
- angles left a player unable to turn to face it. Added `turnTo`.
3183
- - A vault's floor and treasure (behind a secret door) were rendering through the "solid" wall
3184
- before the door was ever found, because the vault cell was carved eagerly instead of
3185
- staying genuinely undiscovered rock until the door opened.
3186
- - Sprites looked blurry under `pixelArt: true` on a hidpi display, even though nearest-neighbour
3187
- texture sampling was already on. The browser does a second, separate resize compositing the
3188
- canvas element onto the page (its backing buffer is rarely the same size as its CSS display
3189
- size), and that step defaults to smoothing regardless of anything Pixi does. Fixed by adding
3190
- a `.mwg-pixel-art { image-rendering: pixelated }` class to the canvas - a class survives
3191
- `autoDensity`/`resizeTo` rewriting the canvas's `style` attribute wholesale, where an inline
3192
- style did not.
3193
- - Off-map neighbours could alias real cells through `Level.index` (which does not
3194
- bounds-check), writing distances into the wrong cell once a search looked at the
3195
- step's origin rather than only its destination. Steps now refuse either end off
3196
- the map before any index is touched.