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