@lewismoten/gamemaker-sandbox-tools 0.0.0-stage → 3.4.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 (252) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/LICENSE +24 -0
  3. package/NOTICE.md +121 -0
  4. package/README.md +362 -2
  5. package/dist/audio-files.js +82 -0
  6. package/dist/audio.js +25 -0
  7. package/dist/block-merge.js +43 -0
  8. package/dist/color-reduce.js +44 -0
  9. package/dist/colors.js +87 -0
  10. package/dist/delta.js +75 -0
  11. package/dist/disk-diff.js +220 -0
  12. package/dist/drawing.js +85 -0
  13. package/dist/embroidery/compile.js +85 -0
  14. package/dist/embroidery/dst.js +79 -0
  15. package/dist/embroidery/exp.js +26 -0
  16. package/dist/embroidery/fill.js +49 -0
  17. package/dist/embroidery/geom.js +82 -0
  18. package/dist/embroidery/pes.js +79 -0
  19. package/dist/embroidery/satin.js +29 -0
  20. package/dist/embroidery/simulate.js +30 -0
  21. package/dist/embroidery/strokeFont.js +253 -0
  22. package/dist/embroidery/svg.js +24 -0
  23. package/dist/embroidery/types.js +13 -0
  24. package/dist/embroidery/units.js +26 -0
  25. package/dist/embroidery/validate.js +15 -0
  26. package/dist/formats/blocks.js +1 -0
  27. package/dist/formats/character.js +1 -0
  28. package/dist/formats/cmf.js +1 -0
  29. package/dist/formats/fli.js +1 -0
  30. package/dist/formats/fliLimits.js +1 -0
  31. package/dist/formats/game.js +1 -0
  32. package/dist/formats/gif.js +1 -0
  33. package/dist/formats/graphicScripts.js +1 -0
  34. package/dist/formats/map.js +1 -0
  35. package/dist/formats/monster.js +1 -0
  36. package/dist/formats/palette.js +1 -0
  37. package/dist/formats/recording.js +1 -0
  38. package/dist/formats/sound.js +1 -0
  39. package/dist/formats/voc.js +1 -0
  40. package/dist/gif-shrink.js +56 -0
  41. package/dist/image/png.js +42 -0
  42. package/dist/images.js +88 -0
  43. package/dist/kit/actors.js +19 -0
  44. package/dist/kit/align.js +204 -0
  45. package/dist/kit/blit.js +45 -0
  46. package/dist/kit/blockRoles.js +97 -0
  47. package/dist/kit/clips.js +40 -0
  48. package/dist/kit/coverPaint.js +18 -0
  49. package/dist/kit/disk.js +76 -0
  50. package/dist/kit/fadeOut.js +13 -0
  51. package/dist/kit/fliClips.js +133 -0
  52. package/dist/kit/fliShrink.js +277 -0
  53. package/dist/kit/gameSim.js +235 -0
  54. package/dist/kit/hopBot.js +142 -0
  55. package/dist/kit/levelGen.js +1423 -0
  56. package/dist/kit/levelGrid.js +33 -0
  57. package/dist/kit/levelPicture.js +27 -0
  58. package/dist/kit/menuVersion.js +19 -0
  59. package/dist/kit/microText.js +35 -0
  60. package/dist/kit/mumble.js +74 -0
  61. package/dist/kit/music.js +8 -0
  62. package/dist/kit/palRamps.js +32 -0
  63. package/dist/kit/palette.js +49 -0
  64. package/dist/kit/pcText.js +72 -0
  65. package/dist/kit/photo.js +150 -0
  66. package/dist/kit/pixels.js +79 -0
  67. package/dist/kit/png.js +40 -0
  68. package/dist/kit/quantize.js +72 -0
  69. package/dist/kit/raytrace.js +379 -0
  70. package/dist/kit/recordedDemo.js +10 -0
  71. package/dist/kit/reel.js +77 -0
  72. package/dist/kit/road3d.js +67 -0
  73. package/dist/kit/routeChecks.js +8 -0
  74. package/dist/kit/saveSlots.js +11 -0
  75. package/dist/kit/sceneInit.js +13 -0
  76. package/dist/kit/sceneSim.js +112 -0
  77. package/dist/kit/screenText.js +15 -0
  78. package/dist/kit/sdftext.js +237 -0
  79. package/dist/kit/shading.js +69 -0
  80. package/dist/kit/song.js +251 -0
  81. package/dist/kit/songFx.js +179 -0
  82. package/dist/kit/sound.js +52 -0
  83. package/dist/kit/synthParts.js +20 -0
  84. package/dist/kit/tar.js +53 -0
  85. package/dist/kit/textBounds.js +84 -0
  86. package/dist/kit/textfit.js +246 -0
  87. package/dist/kit/transforms.js +57 -0
  88. package/dist/kit/tune.js +21 -0
  89. package/dist/look-alike.js +50 -0
  90. package/dist/menu-version.js +4 -0
  91. package/dist/mesh/colorBodies.js +137 -0
  92. package/dist/mesh/decimate.js +207 -0
  93. package/dist/mesh/meshCheck.js +51 -0
  94. package/dist/mesh/overhang.js +41 -0
  95. package/dist/mesh/sampledField.js +12 -0
  96. package/dist/mesh/stl.js +36 -0
  97. package/dist/mesh/surfaceNets.js +79 -0
  98. package/dist/mesh/tetraMesh.js +62 -0
  99. package/dist/mesh/threeMf.js +58 -0
  100. package/dist/mesh/zipFile.js +52 -0
  101. package/dist/microFont.js +101 -0
  102. package/dist/music/compose.js +72 -0
  103. package/dist/pack/meshPack.js +198 -0
  104. package/dist/pack/threeMfPack.js +92 -0
  105. package/dist/palette-reserve.js +116 -0
  106. package/dist/palettes.js +138 -0
  107. package/dist/release-notes.js +40 -0
  108. package/dist/simulation.js +18 -0
  109. package/dist/text.js +74 -0
  110. package/dist/types/audio.d.ts +4 -0
  111. package/dist/types/audioFiles.d.ts +22 -0
  112. package/dist/types/audioWav.d.ts +4 -0
  113. package/dist/types/blockMerge.d.ts +24 -0
  114. package/dist/types/colorReduce.d.ts +23 -0
  115. package/dist/types/colors.d.ts +26 -0
  116. package/dist/types/delta.d.ts +32 -0
  117. package/dist/types/diskDiff.d.ts +47 -0
  118. package/dist/types/drawing.d.ts +15 -0
  119. package/dist/types/embroidery/compile.d.ts +3 -0
  120. package/dist/types/embroidery/dst.d.ts +13 -0
  121. package/dist/types/embroidery/exp.d.ts +8 -0
  122. package/dist/types/embroidery/fill.d.ts +6 -0
  123. package/dist/types/embroidery/geom.d.ts +19 -0
  124. package/dist/types/embroidery/pes.d.ts +10 -0
  125. package/dist/types/embroidery/satin.d.ts +11 -0
  126. package/dist/types/embroidery/simulate.d.ts +19 -0
  127. package/dist/types/embroidery/strokeFont.d.ts +20 -0
  128. package/dist/types/embroidery/svg.d.ts +3 -0
  129. package/dist/types/embroidery/types.d.ts +70 -0
  130. package/dist/types/embroidery/units.d.ts +10 -0
  131. package/dist/types/embroidery/validate.d.ts +22 -0
  132. package/dist/types/formats/blocks.d.ts +1 -0
  133. package/dist/types/formats/character.d.ts +1 -0
  134. package/dist/types/formats/cmf.d.ts +1 -0
  135. package/dist/types/formats/fli.d.ts +1 -0
  136. package/dist/types/formats/fliLimits.d.ts +1 -0
  137. package/dist/types/formats/game.d.ts +1 -0
  138. package/dist/types/formats/gif.d.ts +1 -0
  139. package/dist/types/formats/graphicScripts.d.ts +1 -0
  140. package/dist/types/formats/map.d.ts +1 -0
  141. package/dist/types/formats/monster.d.ts +1 -0
  142. package/dist/types/formats/palette.d.ts +1 -0
  143. package/dist/types/formats/recording.d.ts +1 -0
  144. package/dist/types/formats/sound.d.ts +1 -0
  145. package/dist/types/formats/voc.d.ts +1 -0
  146. package/dist/types/gifShrink.d.ts +8 -0
  147. package/dist/types/image/animatedGif.d.ts +9 -0
  148. package/dist/types/image/png.d.ts +10 -0
  149. package/dist/types/image/surface.d.ts +26 -0
  150. package/dist/types/images.d.ts +13 -0
  151. package/dist/types/kit/actors.d.ts +7 -0
  152. package/dist/types/kit/align.d.ts +93 -0
  153. package/dist/types/kit/audioEvents.d.ts +26 -0
  154. package/dist/types/kit/blit.d.ts +20 -0
  155. package/dist/types/kit/blockRoles.d.ts +243 -0
  156. package/dist/types/kit/clips.d.ts +36 -0
  157. package/dist/types/kit/coverPaint.d.ts +7 -0
  158. package/dist/types/kit/disk.d.ts +15 -0
  159. package/dist/types/kit/fadeOut.d.ts +12 -0
  160. package/dist/types/kit/fliClips.d.ts +32 -0
  161. package/dist/types/kit/fliShrink.d.ts +149 -0
  162. package/dist/types/kit/gameSim.d.ts +112 -0
  163. package/dist/types/kit/hopBot.d.ts +72 -0
  164. package/dist/types/kit/laserClearance.d.ts +16 -0
  165. package/dist/types/kit/laserJoints.d.ts +39 -0
  166. package/dist/types/kit/laserLayout.d.ts +54 -0
  167. package/dist/types/kit/laserPixels.d.ts +52 -0
  168. package/dist/types/kit/laserPreview.d.ts +9 -0
  169. package/dist/types/kit/laserSvg.d.ts +35 -0
  170. package/dist/types/kit/levelGen/castle.d.ts +17 -0
  171. package/dist/types/kit/levelGen/dungeon.d.ts +11 -0
  172. package/dist/types/kit/levelGen/forest.d.ts +17 -0
  173. package/dist/types/kit/levelGen/furnish.d.ts +31 -0
  174. package/dist/types/kit/levelGen/grid.d.ts +46 -0
  175. package/dist/types/kit/levelGen/index.d.ts +138 -0
  176. package/dist/types/kit/levelGen/interior.d.ts +18 -0
  177. package/dist/types/kit/levelGen/jumpModel.d.ts +78 -0
  178. package/dist/types/kit/levelGen/needs.d.ts +44 -0
  179. package/dist/types/kit/levelGen/overworld.d.ts +21 -0
  180. package/dist/types/kit/levelGen/platform.d.ts +59 -0
  181. package/dist/types/kit/levelGen/platformCap.d.ts +13 -0
  182. package/dist/types/kit/levelGen/platformReach.d.ts +37 -0
  183. package/dist/types/kit/levelGen/props.d.ts +37 -0
  184. package/dist/types/kit/levelGen/town.d.ts +24 -0
  185. package/dist/types/kit/levelGrid.d.ts +16 -0
  186. package/dist/types/kit/levelPicture.d.ts +9 -0
  187. package/dist/types/kit/menuVersion.d.ts +7 -0
  188. package/dist/types/kit/microText.d.ts +18 -0
  189. package/dist/types/kit/mumble.d.ts +41 -0
  190. package/dist/types/kit/music.d.ts +1 -0
  191. package/dist/types/kit/palMerge.d.ts +10 -0
  192. package/dist/types/kit/palRamps.d.ts +28 -0
  193. package/dist/types/kit/palette.d.ts +16 -0
  194. package/dist/types/kit/pcText.d.ts +19 -0
  195. package/dist/types/kit/photo.d.ts +69 -0
  196. package/dist/types/kit/pixels.d.ts +26 -0
  197. package/dist/types/kit/png.d.ts +7 -0
  198. package/dist/types/kit/quantize.d.ts +20 -0
  199. package/dist/types/kit/raytrace.d.ts +169 -0
  200. package/dist/types/kit/recordedDemo.d.ts +1 -0
  201. package/dist/types/kit/reel.d.ts +34 -0
  202. package/dist/types/kit/road3d.d.ts +71 -0
  203. package/dist/types/kit/routeChecks.d.ts +6 -0
  204. package/dist/types/kit/saveSlots.d.ts +17 -0
  205. package/dist/types/kit/sceneInit.d.ts +11 -0
  206. package/dist/types/kit/sceneSim.d.ts +84 -0
  207. package/dist/types/kit/screenText.d.ts +3 -0
  208. package/dist/types/kit/sdftext.d.ts +34 -0
  209. package/dist/types/kit/shading.d.ts +23 -0
  210. package/dist/types/kit/shareBlocks.d.ts +20 -0
  211. package/dist/types/kit/song.d.ts +89 -0
  212. package/dist/types/kit/songFx.d.ts +99 -0
  213. package/dist/types/kit/sound.d.ts +29 -0
  214. package/dist/types/kit/synthParts.d.ts +7 -0
  215. package/dist/types/kit/tar.d.ts +13 -0
  216. package/dist/types/kit/textBounds.d.ts +51 -0
  217. package/dist/types/kit/textfit.d.ts +74 -0
  218. package/dist/types/kit/transforms.d.ts +8 -0
  219. package/dist/types/kit/tune.d.ts +6 -0
  220. package/dist/types/lookAlike.d.ts +31 -0
  221. package/dist/types/menuVersionEntry.d.ts +1 -0
  222. package/dist/types/mesh/colorBodies.d.ts +18 -0
  223. package/dist/types/mesh/decimate.d.ts +10 -0
  224. package/dist/types/mesh/fieldTrinket.d.ts +40 -0
  225. package/dist/types/mesh/figureShapes.d.ts +24 -0
  226. package/dist/types/mesh/mesh.d.ts +9 -0
  227. package/dist/types/mesh/meshCheck.d.ts +22 -0
  228. package/dist/types/mesh/overhang.d.ts +24 -0
  229. package/dist/types/mesh/pixelFigure.d.ts +41 -0
  230. package/dist/types/mesh/sampledField.d.ts +3 -0
  231. package/dist/types/mesh/sdfShapes.d.ts +20 -0
  232. package/dist/types/mesh/stl.d.ts +9 -0
  233. package/dist/types/mesh/strokeText.d.ts +8 -0
  234. package/dist/types/mesh/surfaceNets.d.ts +14 -0
  235. package/dist/types/mesh/tetraMesh.d.ts +4 -0
  236. package/dist/types/mesh/threeMf.d.ts +12 -0
  237. package/dist/types/mesh/trinketKinds.d.ts +72 -0
  238. package/dist/types/mesh/trinketTool.d.ts +26 -0
  239. package/dist/types/mesh/voxel.d.ts +10 -0
  240. package/dist/types/mesh/zipFile.d.ts +13 -0
  241. package/dist/types/microFont.d.ts +6 -0
  242. package/dist/types/music/compose.d.ts +51 -0
  243. package/dist/types/pack/meshPack.d.ts +26 -0
  244. package/dist/types/pack/threeMfPack.d.ts +11 -0
  245. package/dist/types/palettePresetData.d.ts +4 -0
  246. package/dist/types/palettePresets.d.ts +12 -0
  247. package/dist/types/paletteReserve.d.ts +52 -0
  248. package/dist/types/palettes.d.ts +4 -0
  249. package/dist/types/releaseNotes.d.ts +3 -0
  250. package/dist/types/simulation.d.ts +6 -0
  251. package/dist/types/text.d.ts +41 -0
  252. package/package.json +190 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,44 @@
1
+ # Changelog
2
+
3
+ Changes to `@lewismoten/gamemaker-sandbox-tools`, released as `tools-v*` tags. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [3.4.0] - 2026-11-07
9
+
10
+ Most of the game-building kit moves into the package: a seeded level generator for dungeons, forests, towns, castles
11
+ and side views, block roles, nonsense-talk voices, and tools for FLI shrinking, palettes, disk diffs, embroidery, and
12
+ 3D-printable and laser models.
13
+
14
+ ### Added
15
+
16
+ - `kit/levelGen`, a seeded level generator with no DOM: dungeons, forests, homes, shops, castles, towns, overworlds and platform side views, with each key reachable before its lock.
17
+ - Shared game-building APIs move into the package: DOS disk writing, native character and text-screen builders, route checks, the engine-backed simulator and more.
18
+ - `kit/blockRoles`, `kit/mumble` (nonsense talk as a .VOC), `kit/levelGrid` and `image/animatedGif`.
19
+ - Mesh, embroidery and laser-kit tools: surface nets and STL files, a stitch generator with DST, EXP and PES files, finger-joint panels and a wooden-nickel builder.
20
+ - `diskDiff` and `kit/fliShrink`.
21
+
22
+ ### Changed
23
+
24
+ - Game builds replace `disk/` files in place, and `kit/tar` is browser-safe.
25
+
26
+ ### Fixed
27
+
28
+ - `kit/gameSim`: a scene with a blank character or character-blocks slot keeps the last scene's, as PLAYGAME's loadscene does.
29
+
30
+ Full list: [changes/release/tools/3.4.0.md](https://github.com/lewismoten/GameMaker-SandboxEdition/blob/tools-v3.4.0/changes/release/tools/3.4.0.md)
31
+
32
+ ## [3.1.0] - 2026-10-29
33
+
34
+ The first release of the development tools as an npm package: drawing, palettes, fonts, music and PNG builders.
35
+
36
+ ### Added
37
+
38
+ - The tools package, scoped as `@lewismoten/gamemaker-sandbox-tools` and published to GitHub Packages from version tags.
39
+ - CP437 and micro text drawn as indexed game pixels, with documented font, text-effect and lighting APIs.
40
+ - Reusable color ramps and time-of-day VGA lighting.
41
+
42
+ [Unreleased]: https://github.com/lewismoten/GameMaker-SandboxEdition/compare/tools-v3.4.0...HEAD
43
+ [3.4.0]: https://github.com/lewismoten/GameMaker-SandboxEdition/compare/tools-v3.1.0...tools-v3.4.0
44
+ [3.1.0]: https://github.com/lewismoten/GameMaker-SandboxEdition/releases/tag/tools-v3.1.0
package/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 gandrewstone
4
+ Copyright (c) 2026 Lewis Moten (modifications: the web port, the 1994 desk, the
5
+ Sandbox Software and Bard of Bizarre games, and the Mac, Windows and Linux players;
6
+ see NOTICE.md)
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in all
16
+ copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ SOFTWARE.
package/NOTICE.md ADDED
@@ -0,0 +1,121 @@
1
+ # Notices
2
+
3
+ This development toolkit is extracted from Game-Maker: Sandbox Edition by Lewis Moten, released under the MIT License. It owns the drawing and audio builders and headless reference simulation; shared native format codecs, runtime types and CP437 font data come through its declared engine dependency, and archive support through its declared archives dependency.
4
+
5
+ The reference engine is a TypeScript port of RSD Game-Maker 3.0 by Recreational Software Designs: G. Andrew Stone, G. Oliver Stone, Oliver Stone Jr. and Joan Stone. Andy Stone released the original source under the MIT License in 2014. The original copyright notice is retained in LICENSE. Peter Savage wrote the original Sound Blaster voice-file and joystick routines.
6
+
7
+ ## Fonts
8
+
9
+ - **8×8 ASCII and selected CP437 glyphs:** Daniel Hepper's [font8x8](https://github.com/dhepper/font8x8), specifically `font8x8_basic`, `font8x8_ext_latin`, `font8x8_greek`, and `font8x8_misc`. Each upstream header declares **Public Domain** and credits **Marcel Sondaar** and **International Business Machines (public domain VGA fonts)** as its basis. See the [upstream source header](https://github.com/dhepper/font8x8/blob/master/font8x8_basic.h). This data is used in `web/packages/engine/src/gfx/font8x8.ts` and the marked entries of `web/packages/engine/src/gfx/cp437Glyphs.ts`, exposed here through `FONT8X8` and `FONT_CP437`.
10
+ - **Additional CP437 glyphs:** the other symbols and box-drawing glyphs in `web/packages/engine/src/gfx/cp437Glyphs.ts` were drawn for Game-Maker: Sandbox Edition using **Anthropic Claude Opus 5.5**, under **Lewis Moten's** direction, and are distributed under the project's **MIT License**. These additions were not copied from IBM's ROM; the full 256-glyph table combines them with the public-domain data above.
11
+ - **3×5 micro font (`MICRO_GLYPHS`):** the project's small sign font, introduced in `games/teddy/draw.ts` by **Lewis Moten using Anthropic Claude Opus 5.5**, then maintained in `games/teddy/src/art/draw.ts`. Its provenance is recorded in [commit 7241036f49cab9dea52f58541e30ce6c9ce86052](https://github.com/lewismoten/GameMaker-SandboxEdition/commit/7241036f49cab9dea52f58541e30ce6c9ce86052). It is distributed under the project's **MIT License**, not the public-domain dedication of Hepper's font. **OpenAI Codex (GPT-6/6.1)** extracted the table into this toolkit's `src/microFont.ts` and added the reusable rendering APIs under Lewis's direction.
12
+
13
+ ## Other formats and tooling
14
+
15
+ The lighting presets were written for this project. GIF, FLI, Creative Voice File, Creative Music File, and ZIP/PNG support follow their respective file formats; CRC-32 uses the reflected polynomial 0xEDB88320.
16
+
17
+ The underlying web port and game-building tools were written with Anthropic Claude Opus 5.5 under Lewis Moten's direction. OpenAI Codex (GPT-6/6.1) prepared the toolkit packaging, consumer migration, documentation, and verification under his direction.
18
+
19
+ No game-specific artwork, palettes, characters, recordings, or complete games are included. Consumers supply and credit their own content.
20
+
21
+ ## Optional source audio conversion
22
+
23
+ `audio-files` invokes an independently installed [FFmpeg](https://ffmpeg.org/) executable
24
+ by the FFmpeg developers; no FFmpeg code or binary is included in this package. FFmpeg is
25
+ LGPL-2.1-or-later, or GPL-2.0-or-later when its GPL components are enabled; see its
26
+ [licensing information](https://ffmpeg.org/legal.html). FLAC is the lossless audio format
27
+ maintained by Xiph.Org; its [FAQ](https://xiph.org/flac/faq.html) describes sample-exact
28
+ compression. The process wrapper and VOC conversion APIs were implemented with OpenAI
29
+ Codex under Lewis Moten's direction, using this project's existing native VOC encoder.
30
+
31
+ The native mono 8-bit PCM WAV reader uses RIFF/WAVE chunk layout and PCM format fields
32
+ from [Microsoft's WAVEFORMATEX documentation](https://learn.microsoft.com/en-us/windows/win32/api/mmeapi/ns-mmeapi-waveformatex).
33
+ No Microsoft implementation code is included. The reader was implemented with OpenAI
34
+ Codex under Lewis Moten's direction and is distributed under this project's MIT License.
35
+
36
+ ## Additional micro-font glyphs and variants
37
+
38
+ The extended rounded repertoire and square technical-label variant are project-owned
39
+ font data by Lewis Moten using Anthropic Claude Opus 5.5, under this project's MIT License.
40
+ They consolidate the existing tables in the public games' art helpers (including the
41
+ expanded punctuation in `games/brief/src/art/draw.ts` and `games/blaster/src/art/draw.ts`,
42
+ and the cent sign in `games/year2000/src/art/font.ts`). The square face originated in
43
+ [the original Ohm Sweet Ohm drawing helpers](https://github.com/lewismoten/GameMaker-SandboxEdition/commit/1a746bffa).
44
+ OpenAI Codex consolidated the data and APIs under Lewis Moten's direction.
45
+ These fonts are distinct from the separately credited public-domain CP437 glyphs above.
46
+
47
+ ## Shared rendering methods and stroke lettering
48
+
49
+ The rounded stroke lettering in `kit/sdftext` is project font data by Lewis Moten using
50
+ Anthropic Claude Opus 5.5, introduced with the original software-rendered logo helpers
51
+ ([source commit](https://github.com/lewismoten/GameMaker-SandboxEdition/commit/7bb0e7b7c)).
52
+ It is distributed under the project's MIT License, alongside the project-owned rendering,
53
+ quantization, synthesis and object-building code extracted from `games/kit`. OpenAI Codex
54
+ consolidated these modules and their consumers under Lewis Moten's direction.
55
+
56
+ Method references: Paul S. Heckbert, *Color Image Quantization for Frame Buffer Display*
57
+ ([author's publication list](https://www.cs.cmu.edu/~ph/)), for median-cut quantization;
58
+ John C. Hart, *Sphere Tracing: A Geometric Method for the Antialiased Ray Tracing of
59
+ Implicit Surfaces* ([paper](https://graphics.stanford.edu/courses/cs348b-20-spring-content/uploads/hart.pdf)),
60
+ for distance-based sphere tracing. The implementations and project font data here use
61
+ the project's MIT License.
62
+
63
+ ## Original CD Library palette
64
+
65
+ `src/palettes.ts` embeds a byte-for-byte copy of `cd/gameware/library/default.pal`
66
+ from the original RSD Game-Maker CD, by Recreational Software Designs (G. Andrew
67
+ Stone, G. Oliver Stone, Oliver Stone Jr. and Joan Stone). It is distributed under
68
+ the original project's MIT License; this package retains that license in `LICENSE`.
69
+ [Source palette](https://github.com/lewismoten/GameMaker-SandboxEdition/blob/master/cd/gameware/library/default.pal).
70
+ OpenAI Codex packaged this data and the fresh-copy API under Lewis Moten's direction.
71
+
72
+ ## Ready-made palette reference data
73
+
74
+ `src/palettePresetData.ts` contains RGB swatches adapted to six-bit VGA by OpenAI Codex
75
+ under Lewis Moten's direction. Analog console colors are reference approximations, not
76
+ a claim that every television or hardware revision produces identical RGB. No third-party
77
+ font, image, emulator or generator executable is bundled with these swatches.
78
+
79
+ - Atari 2600 NTSC and PAL: Ricardo Cancho Niemietz, 2008, released by the author into the
80
+ public domain (with unrestricted-use fallback). Swatches sampled at the centers of the
81
+ 16×8 color charts; NTSC retains 128 hardware slots, including one duplicated RGB value;
82
+ PAL's repeated gray columns are removed to give 104 slots. Sources and release statements:
83
+ [NTSC](https://commons.wikimedia.org/wiki/File:Atari2600_NTSC_palette.png),
84
+ [PAL](https://commons.wikimedia.org/wiki/File:Atari2600_PAL_palette.png).
85
+ - NES: Persune, Pally, MIT No Attribution (MIT-0), copyright 2024 Persune. The first 64 RGB
86
+ entries (no emphasis) of `docs/NESDev/2C02G_U_wiki.pal` are reduced to 54 distinct swatches.
87
+ [Source at commit 9635e9b71505f969014c7efa15dca3ba35ade871](https://github.com/Gumball2415/pally/blob/9635e9b71505f969014c7efa15dca3ba35ade871/docs/NESDev/2C02G_U_wiki.pal),
88
+ [license](https://github.com/Gumball2415/pally/blob/9635e9b71505f969014c7efa15dca3ba35ade871/LICENSE).
89
+ - Commodore 64 NTSC CXA2025 reference: Groepaz, unrestricted free use, including
90
+ redistribution, commercial use and modification; attribution appreciated. Sixteen
91
+ color-bar centers sampled from the reference, with color 0 normalized to menu black.
92
+ [Author's reference](https://hitmen.c02.at/linked/c64_ntsc_cxa2025.bmp.png),
93
+ [permission and provenance](https://commons.wikimedia.org/wiki/File:C64_ntsc_cxa2025.bmp.png).
94
+
95
+ The RGBI and SMS bit mappings are project-owned MIT implementations of hardware facts,
96
+ referencing IBM's *Technical Reference: Options and Adapters*, volume 2, April 1984
97
+ ([manufacturer's manual](https://bitsavers.org/pdf/ibm/pc/cards/Technical_Reference_Options_and_Adapters_Volume_2_Apr84.pdf)),
98
+ and Maxim / SMS Power contributors' [palette documentation](https://www.smspower.org/Development/Palette).
99
+ Monochrome ramps, the EGA skin/hair additions and LCD-green approximations were designed
100
+ for this project by Lewis Moten using OpenAI Codex, under the project's MIT License.
101
+
102
+ Pally's MIT-0 license:
103
+
104
+ ```text
105
+ MIT No Attribution
106
+
107
+ Copyright 2024 Persune
108
+
109
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
110
+ software and associated documentation files (the "Software"), to deal in the Software
111
+ without restriction, including without limitation the rights to use, copy, modify,
112
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
113
+ permit persons to whom the Software is furnished to do so.
114
+
115
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
116
+ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
117
+ PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
118
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
119
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
120
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
121
+ ```
package/README.md CHANGED
@@ -1,3 +1,363 @@
1
- # Temporary Holding Version
1
+ # @lewismoten/gamemaker-sandbox-tools
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Tools for creating and checking native RSD Game-Maker data. Browser playback belongs to `@lewismoten/gamemaker-sandbox-engine`; this package has no game artwork, recordings, characters, or game-specific palettes.
4
+
5
+ Requires Node.js 22.12 or newer. Install as a development dependency from your configured npm registry:
6
+
7
+ ```sh
8
+ npm install --save-dev @lewismoten/gamemaker-sandbox-tools
9
+ ```
10
+
11
+ If your registry requires authentication or a scope mapping, configure npm using that registry's instructions.
12
+
13
+ ## APIs
14
+
15
+ - `formats/blocks`, `character`, `game`, `map`, `monster`, `palette`, `gif`, `graphicScripts`, `sound`, `fli`, `fliLimits`, `voc`, `recording`, and `cmf`: native readers, writers, types, and limits. Each is a separate `formats/<name>` subpath.
16
+ - `gif-shrink`: `shrinkGif(bytes)` returns a smaller GIF with a trimmed color table, or `undefined` when it can't shrink without changing what PLAYGAME shows.
17
+ - `drawing`: indexed pixels, VGA palette builders, font drawing, shading, compositing, and cartoon reels.
18
+ - `audio`: original FM instrument presets, CMF composition, PC speaker effects, and VOC synthesis.
19
+ - `images`: indexed PNG encoding, CRC-32, color reduction, indexed drawing and picture transforms.
20
+ - `simulation`: headless `Sim`, `GameSim`, `readDisk`, `diskSim`, and `newCharInfo` for fixture checks. This includes the reference simulation; it does not replace testing the browser engine package.
21
+
22
+ The browser-safe `images` entry also exports `Pixels`, `flipX`, `flipY`, `turn90`,
23
+ `turn180`, and `shiftPixels` for indexed pictures of any size. Quarter turns return a
24
+ picture with exchanged dimensions. `mirrorAll`, `line`, `box`, and `floodFill` support
25
+ painting across tile boundaries. Fill accepts optional mask and writer callbacks for
26
+ missing cells or repeated references to the same tile; traversal uses the original
27
+ pixels so writes to shared cells do not break the fill.
28
+ Shift offsets use whole pixels. Fill ignores seeds outside the image, inside a masked
29
+ cell, or at non-integer coordinates; mismatched buffer dimensions throw a `RangeError`.
30
+
31
+ ```ts
32
+ import { emptyBlock, serializeBlocks } from '@lewismoten/gamemaker-sandbox-tools/formats/blocks';
33
+ import { Pixels } from '@lewismoten/gamemaker-sandbox-tools/drawing';
34
+
35
+ const blocks = Array.from({ length: 150 }, (_, i) => emptyBlock(i));
36
+ blocks[0].pixels.set(new Pixels(20, 20, 1).px);
37
+ const data = serializeBlocks(blocks);
38
+ ```
39
+
40
+ `medianCutRgba` from `images` chooses up to a requested 1–256 eight-bit RGB colors from portable RGBA image buffers. It needs no canvas or DOM; flatten transparency onto the intended background before calling it. The palette is based on pixel colors and their frequency, not unused color-table entries.
41
+
42
+ Keep drawing and simulation imports in Node build scripts and tests; those entry points reject browser imports. Browser-safe `audio`, `images`, `text`, `colors`, `microFont`, `music/compose`, `image/png`, `kit/tar`, `kit/blockRoles` and `menu-version` (stamps "v1.0" on a game menu picture) entry points also support the web editor. Playback through the engine and archives packages does not load this toolkit. Generated game data and your own copied assets belong in the consuming project.
43
+
44
+ ## Fonts, text images, and lighting
45
+
46
+ `drawing` exports the complete `FONT_CP437` (256 × 8 rows, bit 0 leftmost), including DOS symbols, accents, block shading, and box drawing. NUL, space, and nonbreaking space are intentionally blank. The legacy `FONT8X8` and `text` helpers retain their ASCII behavior. `glyphRows(code)` returns a copy; `encodeText`, `toCp437`, and `fromCp437` convert Unicode DOS symbols and CP437 codes. This is the DOS glyph set, not an ANSI escape-sequence parser.
47
+
48
+ `MICRO_GLYPHS` exposes the project's original 3×5 uppercase font and punctuation. `glyphRows(code, 'micro')` accepts lowercase as uppercase and uses `?` for unsupported glyphs. It does not include game-specific lettering.
49
+
50
+ ```ts
51
+ import { renderText, encodeText, PaletteBuilder, lightColor, TIME_OF_DAY_SKY } from '@lewismoten/gamemaker-sandbox-tools/drawing';
52
+
53
+ const caption = renderText('╔═╗\n║é║\n╚═╝', {
54
+ color: 12, outline: 0, shadow: { color: 8 },
55
+ });
56
+ // caption.width, caption.height, caption.pixels suit indexed GIF/picture builders.
57
+ // Copy small images into a native block's 20×20 pixel array before serializing it.
58
+ const sign = renderText('GO!', { font: 'micro', color: 15, scale: 2 });
59
+ const rawGlyphs = renderText(Uint8Array.of(1, 3, 10, 219), { color: 15 });
60
+ const dosTextBytes = encodeText('Café ♥');
61
+
62
+ const palette = new PaletteBuilder();
63
+ palette.designerColors();
64
+ const [dark, light, middle] = TIME_OF_DAY_SKY.sunset;
65
+ palette.ramp('sky', 8, dark, light, middle);
66
+ const lit = lightColor([100, 180, 80], 'night');
67
+ ```
68
+
69
+ `renderText` returns row-major indexed pixels with transparent index 255 and an origin for the first text cell. It pads the output for a one-pixel outline and shadow, even at larger scales or negative shadow offsets. Strings support LF/CRLF lines; raw byte arrays draw every byte as a glyph on one line. Empty text returns a 0×0 image. Unsupported Unicode throws rather than selecting an unrelated glyph. Ink indexes are 0–254.
70
+
71
+ `outline` and `dropShadow` also decorate `Pixels` sprites within their existing bounds; edges clip. The existing sprite outline uses four neighbors, while text outlines include all eight neighbors.
72
+
73
+ `colorRamp` returns eight-bit RGB stops without allocating palette entries. `rgbToHsv` and `hsvToRgb` convert eight-bit RGB and hue in degrees with saturation/value in 0..1, without changing inputs. `PaletteBuilder.ramp` allocates named ramps in a six-bit VGA palette. `TIME_OF_DAY_LIGHT`, `TIME_OF_DAY_SKY`, and `lightColor` provide morning, noon, afternoon, sunset, night, and stage-light presets. `adjustPalette` returns an adjusted native VGA palette without mutating its input. By default it preserves indexes 0 and 255; pass a custom index list to protect glowing colors or designer inks. Game-specific ramp names and cast colors belong in the consumer.
74
+
75
+ ## Source audio files to VOC (Node.js)
76
+
77
+ Mono unsigned 8-bit PCM WAV files at the requested rate decode directly in Node.js, with
78
+ no additional software. For Ogg, FLAC, other WAV variants or resampling, install
79
+ [FFmpeg](https://ffmpeg.org/download.html) separately and make `ffmpeg` available on PATH,
80
+ or pass its executable path as `ffmpegPath`. No decoder binary is bundled, and browser
81
+ playback gains no dependency.
82
+
83
+ ```ts
84
+ import { audioFileToVoc, decodeAudioFile } from '@lewismoten/gamemaker-sandbox-tools/audio-files';
85
+ import { writeFileSync } from 'node:fs';
86
+
87
+ writeFileSync('VOICE.VOC', audioFileToVoc(new URL('./voice.wav', import.meta.url), {
88
+ sampleRate: 11025, maxBytes: 39999,
89
+ }));
90
+ const samples = decodeAudioFile('voice.ogg', { sampleRate: 8000 });
91
+ ```
92
+
93
+ FLAC, Ogg, WAV and other formats supported by your FFmpeg build are accepted. Output is
94
+ mono at the requested sample rate (11025 Hz by default). VOC conversion defaults to a
95
+ 65535-byte DOS limit; oversized clips fail instead of being shortened. `decodeAudioFile`
96
+ returns samples for mixing or other authoring operations, bounded by `maxSamples`
97
+ (default 16 MiB). Both functions accept `timeoutMs` (default 30000).
98
+
99
+ Use PCM WAV sources for inline GitHub audio previews and sample-exact native game builds.
100
+ Lossless FLAC input is also supported at its original sample rate.
101
+ The converter disables dithering and uses the inverse of the native VOC encoder's byte
102
+ mapping. Lossy sources such as Ogg Vorbis are supported for new audio, but cannot recreate
103
+ a previous recording's exact samples. Source `.wav`/`.ogg`/`.flac` files are authoring assets; only
104
+ 8.3-named `.VOC` files belong on the generated DOS disk.
105
+
106
+ ### Extended micro fonts
107
+
108
+ `microFont` exports `MICRO_GLYPHS`, `MICRO_SQUARE_GLYPHS`, and `microGlyphs(characters, square?)`.
109
+ The shared repertoire includes the sign and technical-label additions such as `µ`, `¢`,
110
+ `#`, `%`, `@`, `~`, quotes, underscore, and backslash. Both rounded and square letterforms
111
+ are preserved. `renderText(text, {font: 'micro-square'})` selects the square style;
112
+ `glyphRows(code, 'micro-square')` returns its five rows. `microGlyphs` can select an exact
113
+ legacy repertoire when an existing game's unsupported-character behavior must stay the same.
114
+ See NOTICE.md for the source and license of both project fonts.
115
+
116
+ ### Shared text renderers
117
+
118
+ `drawing` exports `createMicroText` and `createPcText` for adapting existing lettering
119
+ without copying drawing loops. Micro text accepts a glyph repertoire, fallback, spacing,
120
+ and optional consumer-owned multicolor glyphs. PC text accepts custom glyph artwork,
121
+ scaled or absolute shadow offsets, and outline spacing. Both report ink to the existing
122
+ text-bounds audit. The default `text`, `outlined`, and `centered` retain their old behavior.
123
+
124
+ ### Sprite composition
125
+
126
+ `drawing` also exports ASCII sprites, nearest-pixel rotations and reflections, and
127
+ `resampleBlit` for fractional scaling. `outline` can ignore existing outline-colored
128
+ neighbors or use an explicit transparent index; `outlineInPlace` keeps the original
129
+ canvas. `scaleBlitTransparent` selects transparency without changing its mirroring flag.
130
+ `bevel` accepts separate top/left/bottom/right shade offsets, and `pool` paints radial light.
131
+
132
+ `microWidth` measures visible cells with zero width for an empty string; `microAdvance`
133
+ retains the older cell-advance formula when preserving legacy layout. Default micro
134
+ drawing recognizes direct symbols such as `µ` before trying their uppercase forms.
135
+
136
+ ### Palette and texture helpers
137
+
138
+ `drawing` and `kit/coverPaint` expose seeded tileable value noise, RGB mixing, smoothstep,
139
+ and clamping. `kit/palRamps` exports `Pal` and `wrap` for named palette ramps.
140
+
141
+ ### Software rendering
142
+
143
+ `kit/quantize` chooses shared VGA palettes and ordered dithering for RGB frames.
144
+ `kit/sdftext` provides rounded stroke lettering, distance grids and extrusion; `kit/raytrace`
145
+ provides shapes, transforms, cameras and lighting. Consumers supply their own scenes.
146
+ The stroke glyphs, implementation provenance and method references are in NOTICE.md.
147
+
148
+ ### Archives for downloads
149
+
150
+ `kit/blockRoles` is the block-role vocabulary (wall, door, locked door and key with a lock number, furniture with a facing...), `suggestRoles` (guesses from a block's behavior and picture; it never decides) and `cleanRoles`/`packRoles` for editor companion data; it needs no DOM and changes no game bytes.
151
+
152
+ `kit/levelGen` draws a dungeon (binary space partition: rooms joined by corridors) or a forest (cellular automata on a tree mask, clearings, a winding path) into a rectangle of a map from the blocks that hold roles. `checkNeeds(kind, roles)` says which roles a kind needs and which it uses when present; `generate(roles, { kind, seed, rect })` returns block numbers, the plain kind of each cell, the cells a terrain brush should give edges to, and a proposed entry and exit (never applied or linked), or a plain message when a needed role is missing; `offerSeed` gives the four seeds of a set of offers; `verifyReach` checks every open cell can be reached from the entry. Dungeons also get locked doors (a one-wide passage that cuts the entry from the exit, with the matching key placed in the part still reachable with that lock and every later one shut), treasure and a heart in corners and dead ends, and `monsters` (pass monster numbers in `params.monsters`; spread out, five or more steps from the entry); forests get treasure, a heart and monsters. `proveResult` plays the keys out and checks reach, key-before-lock and that everything can be collected. It needs no DOM, runs in a Worker, and the same seed always gives the same blocks. It writes no game data: the map editor places the cells. `town` (a winding main street between two gates, cross streets that end on one side only, a plaza, and houses with a door on the street) and `overworld` (value noise for sea level, mountains and forest, periodic when `GenParams.wrap` is set so the land lines up across the seam; a road cut between three to five sites) also return `links`: doors and sites a person could link to other scenes (`SceneLink`: cell, kind, label). They are proposals only; nothing creates a scene or a link, and `proveResult` checks each can be reached from the entry (`linked`).
153
+
154
+ `generatePlatform({ roles, hero, seed, rect, difficulty, monsters })` draws a **side view** (platform) level and is meant for a game's `build.ts` as well as the editor. `hero` is the parsed character file (`hero.chr`): `heroPhysics(chr)` reads his walk speed, the jump's upward push (the momentum sequence) and whether he climbs, and plays them with the engine's gravity (one pixel a tick back, at most 11 pixels a tick). Nothing about the hero is written in the generator, so a game with a bigger or smaller jump gets bigger or smaller pits. `capability(physics)` measures, with the reach model, the highest step he jumps onto and the widest pit he clears on level ground (and spikes); `difficulty` (percent, 80 by default) is the share of those the layout asks. The layout has ground with pits (spiked at the bottom with a hazard block), steps up and down, towers with a ladder (only with a ladder block and a hero who climbs), spikes to jump over, stepping stones across wide pits, ledges to jump up to (`platform` blocks, solid on top only), coins where the jumps pass, a heart at the highest place he can stand, one tall locked door with its key on an earlier stretch, and monsters on the long stretches. It needs wall and sky blocks; every other role is optional. The entry is on the left and the exit on the right (proposals; nothing is linked). The result's `platform.proof` says whether the reach model (`reachFrom`: walks, jumps with every steering length, falls off edges and ladders tick by tick against the cells) proved the exit reachable, every coin, heart and key touchable, and the locked door a real barrier (the exit unreachable until the key); a layout that cannot be proven is drawn again, easier. The same seed always draws the same layout; `proveResult` and the Generate dialog's chip use the proof. The editor goes one step further (`editors/map/generate/platformBot.ts`): a bot presses the hero's own keys along the model's route on the real engine and the chip says "Bot won". Monsters and fun are not judged.
155
+
156
+ `kit/tar` writes and reads POSIX ustar archives (`createTar`, `createTarGz`, `readTar`). Entries keep
157
+ their Unix mode, so a game folder's programs and scripts unpack executable, and names over 100
158
+ bytes use the header's prefix field. It has no dependencies and runs in Node and browsers
159
+ (`.tar.gz` uses the platform's `CompressionStream`).
160
+
161
+ ### Native object builders
162
+
163
+ `kit/laserJoints` makes flat wooden-box panel outlines for the laser kits: finger (box) joints whose two sides mesh,
164
+ rectilinear outlines from rectangles, and mitered kerf offsets (`jointOutline`, `outlineFromRects`, `offsetPoly`).
165
+ `kit/laserLayout` has `Part` (one flat piece with named elements, kerf applied, spacing-checked with
166
+ `kit/laserClearance`) and `packRows`, which lays parts out on a Glowforge-bed sheet and throws if they do not fit.
167
+ Games' laser kits (`games/sleuth/laser/`) build on them with `kit/laserSvg`, `laserPixels` and `laserPreview`.
168
+
169
+ `embroidery/*` turns a vector design into machine-embroidery files. A `Design` is color blocks of items: `fill` (polygons), `satin` (a center line and a width) and `run`. `compile` sews each item with an underlay (an edge walk inside the shape, loose rows under big shapes, a center walk and zigzag under satin) and then its top stitching, and adds the jumps, trims, small tie stitches, color stops and an end, capping every stitch at 7 mm (`Params`: fill rows 0.4 mm apart with 3.5 mm stitches whose holes are staggered in thirds, satin 0.4 mm apart, 0.3 mm of pull compensation on satin and 0.15 mm on fills, a satin wider than 7 mm sewn as lanes). `fill` makes the tatami rows (a notched shape becomes several chains), `satin` the zigzag columns and their underlay, `strokeFont` a single-line capital alphabet that `arcText` bends around a circle for satin lettering (draw it 5 mm tall or more), and `geom` the outlines (`circle`, `star`, `inset`). `dst` (Tajima: a text header and 3-byte ternary records, a trim written as tiny jumps), `exp` (Melco, Bernina) and `pes` (Brother, Baby Lock: PES v1 written by hand, its PEC section with 7- and 12-bit moves, thread-chart indices and bitmaps) each write and read a `Pattern` (the readers are for checks). `units` turns a pattern into 0.1 mm moves and splits long jumps, `validate` reports stitch count, longest stitch, extents, jumps and color changes against a hoop, `simulate` draws the stitches thread by thread, and `svg` writes the design as a vector drawing in millimeters. None of it has been run on a real machine; sew a test on scrap first. `games/maximus/patch/` is the first design.
170
+
171
+ `kit/actors` builds character sequences and monster paths. `kit/screenText` validates
172
+ 30-column, 16-line DOS text pages and looks up caller-supplied named sprites.
173
+
174
+ `kit/road3d` provides three-lane perspective geometry, timed spawner chains and sprite
175
+ shrinking. `kit/saveSlots` provides PLAYGAME's save-slot rectangles and their backgrounds.
176
+ These helpers take the consuming game's data and palette.
177
+
178
+ ### Image preparation and previews
179
+
180
+ `kit/photo` reads a caller-supplied JPEG (`readScan`) and provides resampling, toning,
181
+ quantization, dithering and indexed photo composition. No photographs are included.
182
+ `kit/png` writes synchronous RGB preview PNGs with a checkerboard for transparent pixels
183
+ and builds block sheets. `kit/levelPicture` renders a level region with its placed monsters, and `kit/levelGrid` is a character grid to paint a level in code.
184
+ These Node build helpers complement the browser-safe `images` API.
185
+
186
+ ### Sound and arrangement helpers
187
+
188
+ `audio` / `kit/synthParts` expose low-pass noise, envelopes, gates and filtering.
189
+ `kit/song` builds CMF arrangements from caller-supplied sections; `kit/songFx` adds native
190
+ CMF swells, arpeggios, glides, echoes and rhythm effects. Instrument presets are original
191
+ project data under the MIT License; recordings and complete songs are not included.
192
+
193
+ ### Mumble-speak (nonsense talk as VOC)
194
+
195
+ `kit/mumble` is a small formant synthesizer that says nonsense, the way a game of 1994 might hum a character's
196
+ talk. A line is a list of syllables `[vowel, fromHz, toHz, seconds, restSeconds?]`. `mumble(line, { rate, gain })`
197
+ returns samples in -1..1, `mumbleVoc(line)` returns an 8-bit mono 11 kHz .VOC, and `syllablesFromText(text, { pitch, speed, seed })`
198
+ turns a line of text into syllables (vowels from its letters, so the same line and seed mumble the same way;
199
+ a question rises, a sentence falls). `MUMBLE_VOICES` has `bright`, `deep` and `small` settings.
200
+
201
+ ```ts
202
+ import { MUMBLE_VOICES, mumbleVoc, syllablesFromText } from '@lewismoten/gamemaker-sandbox-tools/kit/mumble';
203
+
204
+ const voc = mumbleVoc(syllablesFromText('Welcome to the show!', MUMBLE_VOICES.bright)); // write it as HELLO.VOC
205
+ ```
206
+
207
+ ### Native animations and demos
208
+
209
+ `kit/fadeOut` adds palette-only FLI fades. `kit/fliClips` splits long animations at stable
210
+ palette boundaries and builds their slide-list entries; its opt-in `ClipOptions` leave out
211
+ the closing ring frame no player shows (`noLoopFrame`, also an `encodeFli` option) and put
212
+ cuts where a whole frame costs the fewest extra bytes (`cheapCuts`), and run `shrink` steps first.
213
+ `kit/fliShrink` is the size report (`fliReport`: bytes per chunk type per frame, and why) and the shrink
214
+ steps (`sparsePalettesStep` lossless; `holdStillStep`, `snapColorsStep`, `maxColorsStep`,
215
+ `flattenDitherStep`, `dropFramesStep` lossy), each returning the new frames, the bytes saved and how
216
+ visible the change is (`Visibility`: mean, worst, changed share); `decodeFli`/`encodeFrames` convert,
217
+ `shrinkFrames` chains steps. `kit/recordedDemo` turns delta/key
218
+ pairs into a native title demo with configurable Escape press and release delays.
219
+
220
+ ### Shared block sets
221
+
222
+ `kit/shareBlocks` merges several scenes' background blocks into one `.BBL`: only the blocks a
223
+ map uses (and what they change into) are kept, matching blocks and rings become one, a pinned
224
+ number (such as a felt egg's) stays put, and each scene's map is renumbered.
225
+
226
+ ### Look-alike blocks
227
+
228
+ `findLookAlikes` finds background blocks that are drawn the same colors under every palette a set
229
+ is shown with and play the same (it keeps what they turn into in step), and lists blocks that
230
+ share a shape in other colors without joining them: a scene has one palette. `applyFold` removes
231
+ the folded blocks and renumbers maps and links. Import from `@lewismoten/gamemaker-sandbox-tools/look-alike`.
232
+
233
+ ### Versions as deltas
234
+
235
+ `diffVersions`, `applyDelta` and `deltaSize` keep a game's earlier versions like a git repository: a binary file
236
+ is a list of byte-range patches (one recolored block or map cell is a few bytes), a text file (lst, txt, json,
237
+ md...) a line patch, so each version costs only what changed. Lossless for any bytes. Import from
238
+ `@lewismoten/gamemaker-sandbox-tools/delta`.
239
+
240
+ ### Color reduction
241
+
242
+ `reduceBlocks` moves the pixels of blocks that use colors outside their allowed set (a block type's reserved
243
+ range plus the colors nobody reserved) to the nearest allowed color, and scores the change in CIELAB delta E
244
+ (mean over changed pixels, worst pixel; a block is flagged above 6 mean or 20 worst, thresholds a guess). Index
245
+ 0 and 255 never move. Import from `@lewismoten/gamemaker-sandbox-tools/color-reduce`.
246
+
247
+ ### Palette reservations
248
+
249
+ `planRanges` proposes, for a game with no reservations, a range of color numbers for monsters and one for
250
+ characters (sized by the different colors their blocks draw, at most 48 each, starting at 16 because 1-15 look
251
+ like the engine's own interface colors, placed where the fewest other blocks already draw). `syncRange` makes a
252
+ reserved range identical in every palette a role's files are shown with: the role's colors move into the range
253
+ (pixels renumbered, palettes updated), and colors beyond the range's size become the nearest kept one, all scored
254
+ in delta E. Import from `@lewismoten/gamemaker-sandbox-tools/palette-reserve`.
255
+
256
+ ### Joining block sets
257
+
258
+ `mergeBackgroundSets` moves one background set's drawn blocks into another's free slots (reusing an
259
+ identical block already there) and renumbers the moved set's maps; the kept set is not renumbered.
260
+ Pickups, required and starting items and block 0 keep their number or the join is refused.
261
+ Import from `@lewismoten/gamemaker-sandbox-tools/block-merge`.
262
+
263
+ ### Meshes for 3D printing
264
+
265
+ `mesh/surfaceNets` turns a signed distance field (negative inside) into a closed triangle mesh
266
+ (`surfaceNets(field, { min, max, cell })`; it retries with a shifted grid until every edge is in exactly two
267
+ triangles), `mesh/stl` writes and reads binary STL (`writeStl`, `readStl`; a color per triangle goes in the
268
+ attribute bytes the VisCAM way, which slicers ignore) and `mesh/meshCheck` reports whether a mesh is closed,
269
+ how many pieces it has, its size and volume (`inspectMesh`). `mesh/tetraMesh` is the other mesher (four times
270
+ the triangles, but closed for any field, and neighbors meet on the same vertices); `mesh/overhang` measures what
271
+ an FDM printer cannot print (`overhang`) and builds the support pillars as a body of their own (`supportBody`);
272
+ `mesh/colorBodies` picks at most four colors from a colored mesh (`pickPalette`) and splits the solid into one
273
+ closed body per color (`colorBodies`, thinned and grown to the volume you give it); `mesh/decimate` takes the triangles a
274
+ closed mesh does not need out by quadric edge collapse (`decimate(mesh, { maxError })`: stays closed and in one piece, and the
275
+ borders between a triangle color and the next stay put); `mesh/sampledField` samples a field once on a grid and reads it back
276
+ by trilinear interpolation, for the many passes over one figure (`sampledField`); `mesh/threeMf` writes and reads multi-color 3MF files (`write3mf(parts,
277
+ title, codec)`, `read3mf`: parts are a mesh and a color), over the small ZIP writer `mesh/zipFile` (pass Node's
278
+ `deflateRawSync` as `codec.deflate` to compress). `pack/meshPack` packs a binary STL losslessly into a much smaller file
279
+ (`packStl`, `unpackStl`: a table of distinct corners in byte planes, corner numbers as varints, normals worked out again;
280
+ deflate the result) and gives the pieces (`toPlanes`, `packIndices`) for other mesh files; `pack/threeMfPack` does the same
281
+ for a 3MF `write3mf` wrote (`pack3mf`, `unpack3mf`: corners in thousandths, as the file has them; `threeMfEntries` makes
282
+ its inner files again, the same bytes, to zip with any deflate). `mesh/voxel` meshes filled voxels (`voxelMesh`: coplanar faces merged into
283
+ rectangles, no T-junctions, so it stays closed) and `mesh/pixelFigure` turns a pixel sprite into a standee on a base with at
284
+ most four color bodies (`pixelFigure`). They are browser safe, except `mesh/trinketTool`.
285
+
286
+ Trinkets made of distance fields (Depth Perception's, Quest for the Round Tuit's) share one pipeline, all in millimeters
287
+ with the floor at z = 0: `mesh/sdfShapes` has the 2D shapes (circle, rounded rectangle, polygon, ring, capsule and
288
+ `pixelText2`, lettering in the 3x5 micro font), `extrude` and the solid combiners; `mesh/strokeText` (`strokeText2`, `ringText2`) letters raised or sunk text in smooth capsule strokes (capitals, digits, marks; use it instead of the stair-stepped `pixelText2` for anything printed); `mesh/figureShapes` has ellipsoids, round cones, a smooth union and `place3` for 3D figures; `mesh/trinketKinds` builds a `plate` (coin,
289
+ token, key-chain tag or badge: outline, raised rim, raised relief, sunk art, holes, a pin-back `pocket` from `pinBack`), a key-chain `ringTab`, a faceted `gem` (also a crystal shard) and a `die`; `mesh/fieldTrinket`
290
+ (`meshFieldTrinket`) meshes a field with a color per triangle and gives the checks (eroded pieces and specks, overhang),
291
+ up to four color bodies and supports; `mesh/trinketTool` (`runTrinketTool`, Node only) writes the STL, 3MF and manifest.json
292
+ of a game's trinkets, with a source key so an unchanged game is skipped, in worker threads when `--workers N` runs a bundle.
293
+ A game keeps its designs in `games/<id>/src/trinkets/` (`TRINKETS` and `makeTrinket`) and a four-line `tools/trinkets.ts`.
294
+ Surface nets need a cell smaller than half of any gap between pieces (a 0.6 mm kerf wants a 0.26 mm cell).
295
+
296
+ ### Disk comparison
297
+
298
+ `diffDisks(a, b)` takes two `Map<name, bytes>` disks and returns the added, removed and changed files, with a plain-text
299
+ summary per changed file by type (`.gam`, `.pal`, blocks, `.map`, `.chr`, `.mon`, text, GIF, FLI, VOC, else bytes).
300
+ `formatDiff` prints it, sorted and the same every time. Import from
301
+ `@lewismoten/gamemaker-sandbox-tools/disk-diff`; `npm run disk:diff` in `web/` is the command line.
302
+ `releaseNotes(diff)` (`.../release-notes`) turns a diff into short paste-ready text grouped by kind of file, such as
303
+ "Changed 2 maps (A.MAP, B.MAP) and 1 palette (X.PAL). Added 1 sound (SONG3.VOC)."; `disk:diff -- --notes` prints it.
304
+
305
+ ### Headless checking
306
+
307
+ `kit/hopBot` provides configurable hopping, steering and retry support for `GameSim`.
308
+ `kit/align` audits caller-supplied disks, multi-block layouts and pixel seams; finding the
309
+ games to audit and reporting the results belong to the consumer. `simulation` also exposes route scene
310
+ assertions and scene initialization that delegates to the engine. `GameSimState` names
311
+ the snapshot type; compatibility initialization preserves older block-birth bookkeeping.
312
+
313
+ ### DOS disk output
314
+
315
+ `kit/disk` exports `Disk` for collecting 8.3-named files and writing a clean output
316
+ directory, plus the legacy `dosText` byte conversion. Destination and metadata are
317
+ caller-supplied. `kit/menuVersion` can stamp a supplied version on a native menu GIF;
318
+ this package reads no game metadata files and imposes no version policy.
319
+
320
+ `kit/palRamps` also exports `wrapWithBuilder` and `buildRampPalette`: supply ramp
321
+ descriptors, optional named endpoint replacements, and a color transform. The game
322
+ keeps its actual colors and lighting choices. `colors` and `text` are direct browser-safe
323
+ entries for the existing lighting, ramp, glyph-row, and rendered-text APIs.
324
+
325
+ `kit/textfit` audits caller-supplied native files for menu, save-slot, score-table and
326
+ text-page layout and contrast. Choosing which games to check, and printing the results, are left to the consumer.
327
+
328
+ ## Original Library palette
329
+
330
+ `libraryDefaultPalette()` from `@lewismoten/gamemaker-sandbox-tools/palettes` returns
331
+ an independent 768-byte copy of the CD Library's `DEFAULT.PAL`, with black at index
332
+ zero. This is the original RSD palette, rather than the engine's generated fallback.
333
+ It works in browsers and Node without fetching the CD or using repository files.
334
+ See `NOTICE.md` for its source and license.
335
+
336
+ ### Palette templates
337
+
338
+ `PALETTE_PRESETS` from `palettes` lists 20 ready-made templates with names, descriptions,
339
+ occupied entry counts and DOS-safe filename stems. `createPalettePreset(id)` returns a fresh
340
+ 768-byte VGA palette with menu black at index 0, transparency reserved at 255, and unused
341
+ entries black. Templates include monochrome, Atari NTSC/PAL, NES, CGA, EGA, EGA with skin/hair
342
+ ramps, LCD greens, Sega Master System, Commodore 64, web-safe colors and grayscale steps.
343
+ 128-step grayscale necessarily repeats VGA's 64 distinct gray shades. LCD greens include
344
+ four green shades plus menu black. Console RGB references and their licenses are in NOTICE.md;
345
+ all values are adapted to six-bit VGA and do not impose the original consoles' drawing limits.
346
+
347
+ ## Developing
348
+
349
+ This package's source lives in [the project's repository](https://github.com/lewismoten/GameMaker-SandboxEdition), in `web/packages/tools`. The folder holds its builders in `src/`, build configuration, license and notices. Shared codecs and runtime types come through declared engine and archives dependencies, and it never reads source from another repository folder. After `npm install` in a standalone copy, or `npm ci` at the repository root:
350
+
351
+ ```sh
352
+ npm run build
353
+ npm run verify
354
+ npm pack
355
+ ```
356
+
357
+ The build bundles source from the format, drawing, audio, and simulation modules. It does not use or restart the site's Vite configuration. The tarball contains JavaScript, declarations, this guide, the MIT license, and notices. From the repository root, `npm run verify:packages` copies each package outside the repository, builds it with packed declared dependencies, and tests its npm distribution, which also supports unpublished sibling versions.
358
+
359
+ `verify` installs the tarball in a temporary npm consumer and checks codecs, drawing, sound generation, headless simulation, NodeNext declarations, absence of game content, and rejected browser imports. Tarballs are local build artifacts and must not be committed to a consuming project. The [monorepo guide](https://github.com/lewismoten/GameMaker-SandboxEdition/blob/master/docs/monorepo.md) covers the workspace layout, and the [package release guide](https://github.com/lewismoten/GameMaker-SandboxEdition/blob/master/docs/package-releases.md) covers publishing.
360
+
361
+ ## License and notices
362
+
363
+ The source is MIT licensed. The published package carries `LICENSE` and `NOTICE.md` (credits for third-party code and formats); it includes no game assets.