picopilot 0.0.0 → 0.1.1

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 (334) hide show
  1. package/LICENSE +661 -0
  2. package/dist/bin.d.ts +3 -0
  3. package/dist/bin.d.ts.map +1 -0
  4. package/dist/bin.js +4 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/cli.d.ts +15 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +59 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/commands/audio.d.ts +17 -0
  11. package/dist/commands/audio.d.ts.map +1 -0
  12. package/dist/commands/audio.js +315 -0
  13. package/dist/commands/audio.js.map +1 -0
  14. package/dist/commands/export.d.ts +36 -0
  15. package/dist/commands/export.d.ts.map +1 -0
  16. package/dist/commands/export.js +257 -0
  17. package/dist/commands/export.js.map +1 -0
  18. package/dist/commands/gfx.d.ts +28 -0
  19. package/dist/commands/gfx.d.ts.map +1 -0
  20. package/dist/commands/gfx.js +521 -0
  21. package/dist/commands/gfx.js.map +1 -0
  22. package/dist/commands/init.d.ts +34 -0
  23. package/dist/commands/init.d.ts.map +1 -0
  24. package/dist/commands/init.js +151 -0
  25. package/dist/commands/init.js.map +1 -0
  26. package/dist/commands/lint.d.ts +20 -0
  27. package/dist/commands/lint.d.ts.map +1 -0
  28. package/dist/commands/lint.js +90 -0
  29. package/dist/commands/lint.js.map +1 -0
  30. package/dist/commands/minify.d.ts +20 -0
  31. package/dist/commands/minify.d.ts.map +1 -0
  32. package/dist/commands/minify.js +129 -0
  33. package/dist/commands/minify.js.map +1 -0
  34. package/dist/commands/music.d.ts +13 -0
  35. package/dist/commands/music.d.ts.map +1 -0
  36. package/dist/commands/music.js +241 -0
  37. package/dist/commands/music.js.map +1 -0
  38. package/dist/commands/playtest.d.ts +29 -0
  39. package/dist/commands/playtest.d.ts.map +1 -0
  40. package/dist/commands/playtest.js +631 -0
  41. package/dist/commands/playtest.js.map +1 -0
  42. package/dist/commands/run.d.ts +30 -0
  43. package/dist/commands/run.d.ts.map +1 -0
  44. package/dist/commands/run.js +224 -0
  45. package/dist/commands/run.js.map +1 -0
  46. package/dist/commands/serve.d.ts +50 -0
  47. package/dist/commands/serve.d.ts.map +1 -0
  48. package/dist/commands/serve.js +213 -0
  49. package/dist/commands/serve.js.map +1 -0
  50. package/dist/commands/sfx.d.ts +13 -0
  51. package/dist/commands/sfx.d.ts.map +1 -0
  52. package/dist/commands/sfx.js +254 -0
  53. package/dist/commands/sfx.js.map +1 -0
  54. package/dist/commands/tokens.d.ts +36 -0
  55. package/dist/commands/tokens.d.ts.map +1 -0
  56. package/dist/commands/tokens.js +129 -0
  57. package/dist/commands/tokens.js.map +1 -0
  58. package/dist/commands/verify.d.ts +57 -0
  59. package/dist/commands/verify.d.ts.map +1 -0
  60. package/dist/commands/verify.js +213 -0
  61. package/dist/commands/verify.js.map +1 -0
  62. package/dist/commands/version.d.ts +12 -0
  63. package/dist/commands/version.d.ts.map +1 -0
  64. package/dist/commands/version.js +24 -0
  65. package/dist/commands/version.js.map +1 -0
  66. package/dist/engine/audio/index.d.ts +14 -0
  67. package/dist/engine/audio/index.d.ts.map +1 -0
  68. package/dist/engine/audio/index.js +14 -0
  69. package/dist/engine/audio/index.js.map +1 -0
  70. package/dist/engine/audio/music.d.ts +116 -0
  71. package/dist/engine/audio/music.d.ts.map +1 -0
  72. package/dist/engine/audio/music.js +138 -0
  73. package/dist/engine/audio/music.js.map +1 -0
  74. package/dist/engine/audio/section.d.ts +34 -0
  75. package/dist/engine/audio/section.d.ts.map +1 -0
  76. package/dist/engine/audio/section.js +67 -0
  77. package/dist/engine/audio/section.js.map +1 -0
  78. package/dist/engine/audio/sfx.d.ts +141 -0
  79. package/dist/engine/audio/sfx.d.ts.map +1 -0
  80. package/dist/engine/audio/sfx.js +506 -0
  81. package/dist/engine/audio/sfx.js.map +1 -0
  82. package/dist/engine/cart/cart.d.ts +75 -0
  83. package/dist/engine/cart/cart.d.ts.map +1 -0
  84. package/dist/engine/cart/cart.js +153 -0
  85. package/dist/engine/cart/cart.js.map +1 -0
  86. package/dist/engine/cart/errors.d.ts +29 -0
  87. package/dist/engine/cart/errors.d.ts.map +1 -0
  88. package/dist/engine/cart/errors.js +26 -0
  89. package/dist/engine/cart/errors.js.map +1 -0
  90. package/dist/engine/cart/gfx.d.ts +79 -0
  91. package/dist/engine/cart/gfx.d.ts.map +1 -0
  92. package/dist/engine/cart/gfx.js +171 -0
  93. package/dist/engine/cart/gfx.js.map +1 -0
  94. package/dist/engine/cart/index.d.ts +15 -0
  95. package/dist/engine/cart/index.d.ts.map +1 -0
  96. package/dist/engine/cart/index.js +15 -0
  97. package/dist/engine/cart/index.js.map +1 -0
  98. package/dist/engine/cart/map.d.ts +46 -0
  99. package/dist/engine/cart/map.d.ts.map +1 -0
  100. package/dist/engine/cart/map.js +118 -0
  101. package/dist/engine/cart/map.js.map +1 -0
  102. package/dist/engine/config/config.d.ts +74 -0
  103. package/dist/engine/config/config.d.ts.map +1 -0
  104. package/dist/engine/config/config.js +103 -0
  105. package/dist/engine/config/config.js.map +1 -0
  106. package/dist/engine/config/index.d.ts +7 -0
  107. package/dist/engine/config/index.d.ts.map +1 -0
  108. package/dist/engine/config/index.js +7 -0
  109. package/dist/engine/config/index.js.map +1 -0
  110. package/dist/engine/gfx/grid.d.ts +51 -0
  111. package/dist/engine/gfx/grid.d.ts.map +1 -0
  112. package/dist/engine/gfx/grid.js +116 -0
  113. package/dist/engine/gfx/grid.js.map +1 -0
  114. package/dist/engine/gfx/index.d.ts +17 -0
  115. package/dist/engine/gfx/index.d.ts.map +1 -0
  116. package/dist/engine/gfx/index.js +17 -0
  117. package/dist/engine/gfx/index.js.map +1 -0
  118. package/dist/engine/gfx/label.d.ts +34 -0
  119. package/dist/engine/gfx/label.d.ts.map +1 -0
  120. package/dist/engine/gfx/label.js +190 -0
  121. package/dist/engine/gfx/label.js.map +1 -0
  122. package/dist/engine/gfx/overlap.d.ts +42 -0
  123. package/dist/engine/gfx/overlap.d.ts.map +1 -0
  124. package/dist/engine/gfx/overlap.js +57 -0
  125. package/dist/engine/gfx/overlap.js.map +1 -0
  126. package/dist/engine/gfx/palette.d.ts +29 -0
  127. package/dist/engine/gfx/palette.d.ts.map +1 -0
  128. package/dist/engine/gfx/palette.js +46 -0
  129. package/dist/engine/gfx/palette.js.map +1 -0
  130. package/dist/engine/gfx/png.d.ts +31 -0
  131. package/dist/engine/gfx/png.d.ts.map +1 -0
  132. package/dist/engine/gfx/png.js +165 -0
  133. package/dist/engine/gfx/png.js.map +1 -0
  134. package/dist/engine/gfx/render.d.ts +42 -0
  135. package/dist/engine/gfx/render.d.ts.map +1 -0
  136. package/dist/engine/gfx/render.js +72 -0
  137. package/dist/engine/gfx/render.js.map +1 -0
  138. package/dist/engine/index.d.ts +22 -0
  139. package/dist/engine/index.d.ts.map +1 -0
  140. package/dist/engine/index.js +22 -0
  141. package/dist/engine/index.js.map +1 -0
  142. package/dist/engine/pico8/adapter.d.ts +267 -0
  143. package/dist/engine/pico8/adapter.d.ts.map +1 -0
  144. package/dist/engine/pico8/adapter.js +37 -0
  145. package/dist/engine/pico8/adapter.js.map +1 -0
  146. package/dist/engine/pico8/drive.d.ts +308 -0
  147. package/dist/engine/pico8/drive.d.ts.map +1 -0
  148. package/dist/engine/pico8/drive.js +581 -0
  149. package/dist/engine/pico8/drive.js.map +1 -0
  150. package/dist/engine/pico8/harness.d.ts +146 -0
  151. package/dist/engine/pico8/harness.d.ts.map +1 -0
  152. package/dist/engine/pico8/harness.js +251 -0
  153. package/dist/engine/pico8/harness.js.map +1 -0
  154. package/dist/engine/pico8/index.d.ts +21 -0
  155. package/dist/engine/pico8/index.d.ts.map +1 -0
  156. package/dist/engine/pico8/index.js +21 -0
  157. package/dist/engine/pico8/index.js.map +1 -0
  158. package/dist/engine/pico8/sentinel.d.ts +63 -0
  159. package/dist/engine/pico8/sentinel.d.ts.map +1 -0
  160. package/dist/engine/pico8/sentinel.js +86 -0
  161. package/dist/engine/pico8/sentinel.js.map +1 -0
  162. package/dist/engine/pico8/session-daemon-entry.d.ts +10 -0
  163. package/dist/engine/pico8/session-daemon-entry.d.ts.map +1 -0
  164. package/dist/engine/pico8/session-daemon-entry.js +11 -0
  165. package/dist/engine/pico8/session-daemon-entry.js.map +1 -0
  166. package/dist/engine/pico8/session-daemon-main.d.ts +44 -0
  167. package/dist/engine/pico8/session-daemon-main.d.ts.map +1 -0
  168. package/dist/engine/pico8/session-daemon-main.js +71 -0
  169. package/dist/engine/pico8/session-daemon-main.js.map +1 -0
  170. package/dist/engine/pico8/session-daemon.d.ts +68 -0
  171. package/dist/engine/pico8/session-daemon.d.ts.map +1 -0
  172. package/dist/engine/pico8/session-daemon.js +264 -0
  173. package/dist/engine/pico8/session-daemon.js.map +1 -0
  174. package/dist/engine/pico8/session.d.ts +140 -0
  175. package/dist/engine/pico8/session.d.ts.map +1 -0
  176. package/dist/engine/pico8/session.js +250 -0
  177. package/dist/engine/pico8/session.js.map +1 -0
  178. package/dist/engine/pico8/shell.d.ts +103 -0
  179. package/dist/engine/pico8/shell.d.ts.map +1 -0
  180. package/dist/engine/pico8/shell.js +324 -0
  181. package/dist/engine/pico8/shell.js.map +1 -0
  182. package/dist/engine/pico8/supervisor.d.ts +137 -0
  183. package/dist/engine/pico8/supervisor.d.ts.map +1 -0
  184. package/dist/engine/pico8/supervisor.js +140 -0
  185. package/dist/engine/pico8/supervisor.js.map +1 -0
  186. package/dist/engine/scaffold/index.d.ts +8 -0
  187. package/dist/engine/scaffold/index.d.ts.map +1 -0
  188. package/dist/engine/scaffold/index.js +8 -0
  189. package/dist/engine/scaffold/index.js.map +1 -0
  190. package/dist/engine/scaffold/scaffold.d.ts +49 -0
  191. package/dist/engine/scaffold/scaffold.d.ts.map +1 -0
  192. package/dist/engine/scaffold/scaffold.js +259 -0
  193. package/dist/engine/scaffold/scaffold.js.map +1 -0
  194. package/dist/engine/shrinko/adapter.d.ts +167 -0
  195. package/dist/engine/shrinko/adapter.d.ts.map +1 -0
  196. package/dist/engine/shrinko/adapter.js +107 -0
  197. package/dist/engine/shrinko/adapter.js.map +1 -0
  198. package/dist/engine/shrinko/index.d.ts +13 -0
  199. package/dist/engine/shrinko/index.d.ts.map +1 -0
  200. package/dist/engine/shrinko/index.js +13 -0
  201. package/dist/engine/shrinko/index.js.map +1 -0
  202. package/dist/engine/shrinko/shell.d.ts +69 -0
  203. package/dist/engine/shrinko/shell.d.ts.map +1 -0
  204. package/dist/engine/shrinko/shell.js +156 -0
  205. package/dist/engine/shrinko/shell.js.map +1 -0
  206. package/dist/engine/skills/index.d.ts +8 -0
  207. package/dist/engine/skills/index.d.ts.map +1 -0
  208. package/dist/engine/skills/index.js +8 -0
  209. package/dist/engine/skills/index.js.map +1 -0
  210. package/dist/engine/skills/skills.d.ts +104 -0
  211. package/dist/engine/skills/skills.d.ts.map +1 -0
  212. package/dist/engine/skills/skills.js +149 -0
  213. package/dist/engine/skills/skills.js.map +1 -0
  214. package/dist/index.d.ts +10 -0
  215. package/dist/index.d.ts.map +1 -0
  216. package/dist/index.js +10 -0
  217. package/dist/index.js.map +1 -0
  218. package/dist/version.d.ts +2 -0
  219. package/dist/version.d.ts.map +1 -0
  220. package/dist/version.js +19 -0
  221. package/dist/version.js.map +1 -0
  222. package/package.json +48 -2
  223. package/src/bin.ts +4 -0
  224. package/src/cli.ts +61 -0
  225. package/src/commands/audio.test.ts +280 -0
  226. package/src/commands/audio.ts +410 -0
  227. package/src/commands/export.test.ts +310 -0
  228. package/src/commands/export.ts +316 -0
  229. package/src/commands/gfx-io.test.ts +178 -0
  230. package/src/commands/gfx.test.ts +470 -0
  231. package/src/commands/gfx.ts +645 -0
  232. package/src/commands/init.test.ts +482 -0
  233. package/src/commands/init.ts +193 -0
  234. package/src/commands/lint.test.ts +137 -0
  235. package/src/commands/lint.ts +117 -0
  236. package/src/commands/minify.test.ts +166 -0
  237. package/src/commands/minify.ts +156 -0
  238. package/src/commands/music.test.ts +272 -0
  239. package/src/commands/music.ts +288 -0
  240. package/src/commands/playtest.test.ts +317 -0
  241. package/src/commands/playtest.ts +773 -0
  242. package/src/commands/run.test.ts +264 -0
  243. package/src/commands/run.ts +285 -0
  244. package/src/commands/serve.test.ts +227 -0
  245. package/src/commands/serve.ts +272 -0
  246. package/src/commands/sfx.test.ts +349 -0
  247. package/src/commands/sfx.ts +300 -0
  248. package/src/commands/tokens.test.ts +212 -0
  249. package/src/commands/tokens.ts +168 -0
  250. package/src/commands/verify.test.ts +238 -0
  251. package/src/commands/verify.ts +256 -0
  252. package/src/commands/version.test.ts +70 -0
  253. package/src/commands/version.ts +24 -0
  254. package/src/engine/audio/index.ts +47 -0
  255. package/src/engine/audio/music.test.ts +188 -0
  256. package/src/engine/audio/music.ts +218 -0
  257. package/src/engine/audio/section.test.ts +124 -0
  258. package/src/engine/audio/section.ts +79 -0
  259. package/src/engine/audio/sfx.test.ts +410 -0
  260. package/src/engine/audio/sfx.ts +694 -0
  261. package/src/engine/cart/cart.test.ts +304 -0
  262. package/src/engine/cart/cart.ts +211 -0
  263. package/src/engine/cart/errors.ts +39 -0
  264. package/src/engine/cart/fixtures/crlf.p8 +6 -0
  265. package/src/engine/cart/fixtures/full.p8 +174 -0
  266. package/src/engine/cart/fixtures/header-only.p8 +2 -0
  267. package/src/engine/cart/fixtures/malformed-no-header.p8 +2 -0
  268. package/src/engine/cart/fixtures/minimal.p8 +10 -0
  269. package/src/engine/cart/fixtures/no-trailing-newline.p8 +6 -0
  270. package/src/engine/cart/gfx.ts +195 -0
  271. package/src/engine/cart/index.ts +27 -0
  272. package/src/engine/cart/map.ts +134 -0
  273. package/src/engine/config/config.ts +115 -0
  274. package/src/engine/config/index.ts +12 -0
  275. package/src/engine/gfx/grid.test.ts +128 -0
  276. package/src/engine/gfx/grid.ts +136 -0
  277. package/src/engine/gfx/index.ts +34 -0
  278. package/src/engine/gfx/label.test.ts +105 -0
  279. package/src/engine/gfx/label.ts +229 -0
  280. package/src/engine/gfx/overlap.test.ts +71 -0
  281. package/src/engine/gfx/overlap.ts +66 -0
  282. package/src/engine/gfx/palette.test.ts +35 -0
  283. package/src/engine/gfx/palette.ts +54 -0
  284. package/src/engine/gfx/png.test.ts +111 -0
  285. package/src/engine/gfx/png.ts +196 -0
  286. package/src/engine/gfx/render.test.ts +180 -0
  287. package/src/engine/gfx/render.ts +106 -0
  288. package/src/engine/index.ts +21 -0
  289. package/src/engine/pico8/adapter.ts +303 -0
  290. package/src/engine/pico8/drive.test.ts +415 -0
  291. package/src/engine/pico8/drive.ts +729 -0
  292. package/src/engine/pico8/harness.test.ts +181 -0
  293. package/src/engine/pico8/harness.ts +354 -0
  294. package/src/engine/pico8/index.ts +20 -0
  295. package/src/engine/pico8/sentinel.test.ts +80 -0
  296. package/src/engine/pico8/sentinel.ts +93 -0
  297. package/src/engine/pico8/session-daemon-entry.ts +12 -0
  298. package/src/engine/pico8/session-daemon-main.ts +98 -0
  299. package/src/engine/pico8/session-daemon.test.ts +212 -0
  300. package/src/engine/pico8/session-daemon.ts +306 -0
  301. package/src/engine/pico8/session.test.ts +239 -0
  302. package/src/engine/pico8/session.ts +321 -0
  303. package/src/engine/pico8/shell.test.ts +583 -0
  304. package/src/engine/pico8/shell.ts +412 -0
  305. package/src/engine/pico8/supervisor.test.ts +105 -0
  306. package/src/engine/pico8/supervisor.ts +197 -0
  307. package/src/engine/scaffold/index.ts +15 -0
  308. package/src/engine/scaffold/scaffold.ts +278 -0
  309. package/src/engine/shrinko/adapter.ts +241 -0
  310. package/src/engine/shrinko/fixtures/count-no-compressed.txt +2 -0
  311. package/src/engine/shrinko/fixtures/count-over-budget.txt +3 -0
  312. package/src/engine/shrinko/fixtures/count-under-budget.txt +3 -0
  313. package/src/engine/shrinko/index.ts +33 -0
  314. package/src/engine/shrinko/shell.ts +224 -0
  315. package/src/engine/shrinko/shrinko.test.ts +182 -0
  316. package/src/engine/skills/index.ts +14 -0
  317. package/src/engine/skills/skills.test.ts +376 -0
  318. package/src/engine/skills/skills.ts +205 -0
  319. package/src/index.ts +13 -0
  320. package/src/skills/game-design-reference/SKILL.md +70 -0
  321. package/src/skills/game-jam/SKILL.md +45 -0
  322. package/src/skills/picopilot-art/SKILL.md +62 -0
  323. package/src/skills/picopilot-audio/SKILL.md +194 -0
  324. package/src/skills/picopilot-code/SKILL.md +97 -0
  325. package/src/skills/picopilot-code/reference/README.md +42 -0
  326. package/src/skills/picopilot-code/reference/mode7-racing.md +95 -0
  327. package/src/skills/picopilot-code/reference/platformer.md +119 -0
  328. package/src/skills/picopilot-code/reference/puzzle-grid.md +106 -0
  329. package/src/skills/picopilot-code/reference/rpg-menus-dialog.md +122 -0
  330. package/src/skills/picopilot-code/reference/top-down-adventure.md +117 -0
  331. package/src/skills/picopilot-code/reference/twin-stick-arcade.md +128 -0
  332. package/src/skills/picopilot-debug/SKILL.md +195 -0
  333. package/src/skills/picopilot-overview/SKILL.md +52 -0
  334. package/src/version.ts +22 -0
@@ -0,0 +1,506 @@
1
+ /**
2
+ * `engine/audio` — the shrinko-free picopilot-MML to `__sfx__` codec.
3
+ *
4
+ * This module OWNS the picopilot-MML dialect and its transpilation into ONE
5
+ * `__sfx__` text row (the friendly text surface PICO-8 serializes, NOT the
6
+ * scattered RAM bit-packing). It is the greenfield/algorithmic seam of the audio
7
+ * path; the `sfx from-mml` command is thin wiring over {@link mmlToSfxRow}.
8
+ *
9
+ * The mapping is the CLOSED spec from the ADR-0005 spike, verified byte-for-byte
10
+ * against PICO-8 v0.2.7:
11
+ * `work/notes/findings/pico8-audio-sfx-music-layout-and-mml-subset.md` (Part A =
12
+ * the `__sfx__` text layout; Part B = the picopilot-MML grammar + mapping).
13
+ *
14
+ * The KEY reframe (finding B.4 / B.7 #1): PICO-8 has NO per-note duration or
15
+ * tempo. Every note occupies exactly one tracker ROW; all rows share ONE
16
+ * SFX-level `speed`. A picopilot-MML length is therefore a ROW COUNT, not a
17
+ * musical fraction, and there is no tempo/BPM token. Holding a note for M rows
18
+ * re-emits the same note in the following (M-1) rows (PICO-8 has no cross-row
19
+ * sustain bit).
20
+ *
21
+ * Out-of-range pitch and >32 rows are STRUCTURED ERRORS ({@link AudioMmlError}),
22
+ * never silent clamps: a silent clamp produces wrong-sounding music the author
23
+ * cannot see (finding B.2 / B.4, matching picopilot's smart-refuse philosophy).
24
+ *
25
+ * SFX-level FILTER directives (finding A.7): `!noiz !buzz !detune1/!detune2
26
+ * !reverb[1|2] !dampen[1|2]` set PICO-8's 5 per-SFX filters (the first header
27
+ * byte), reaching the class of DESIGNED sounds (explosion = DAMPEN body + REVERB
28
+ * tail, engine hum, pad) that no per-note pitch/waveform/volume MML can
29
+ * synthesize. `!`-prefixed keywords never collide with the note grammar (unlike
30
+ * the rejected bare-letter effect mnemonics, ADR-0008). A bad DAMPEN/REVERB level
31
+ * is a structured refusal, never a clamp.
32
+ */
33
+ /** A `__sfx__` row is exactly this many hex chars: 8 header + 32 notes x 5. */
34
+ export const SFX_ROW_LENGTH = 168;
35
+ /** The number of tracker rows (notes) in one SFX. A hard PICO-8 limit. */
36
+ export const SFX_MAX_ROWS = 32;
37
+ /** The lowest representable pitch: C0 = 0 (finding A.2 / B.2). */
38
+ export const PITCH_MIN = 0;
39
+ /** The highest representable pitch: D#5 = 63 (finding A.2 / B.2). */
40
+ export const PITCH_MAX = 63;
41
+ /** The default octave when none is set (`o2`, pitch 24 = C2; finding B.2). */
42
+ export const DEFAULT_OCTAVE = 2;
43
+ /** The default SFX speed (ticks/row) when `s<N>` is omitted (finding B.5). */
44
+ export const DEFAULT_SPEED = 16;
45
+ /** The default note length in tracker rows (one row; finding B.4). */
46
+ export const DEFAULT_LENGTH = 1;
47
+ /**
48
+ * The per-SFX FILTER switches (finding A.7). They live in the FIRST header byte
49
+ * of the `__sfx__` row (the `[0:2]` hex pair, the byte A.1 called "editor mode"):
50
+ * an 8-bit bitfield whose LOW bit is the cosmetic pitch/tracker mode flag and
51
+ * whose upper 7 bits are the filters. picopilot emits mode 0 (pitch mode), so the
52
+ * byte is exactly the OR of the selected filter values below.
53
+ *
54
+ * Decoded byte-for-byte on PICO-8 v0.2.7 by poke-and-readback + single-bit audio
55
+ * diff (finding A.7). NOIZ applies only to instrument 6 (`@6`, manual);
56
+ * DAMPEN/REVERB have 2 levels each (`!dampen`/`!dampen2`, `!reverb`/`!reverb2`).
57
+ */
58
+ export const FILTER_NOIZ = 0x02;
59
+ export const FILTER_BUZZ = 0x04;
60
+ export const FILTER_DETUNE_1 = 0x08;
61
+ export const FILTER_DETUNE_2 = 0x10;
62
+ /** REVERB (echo) switch (`0x20`); see the level note below (finding A.7). */
63
+ export const FILTER_REVERB = 0x20;
64
+ /**
65
+ * DAMPEN (low-pass) level 1 (`0x80`) and level 2 (`0xc0`); 0 = off (finding
66
+ * A.7). Verified progressive: `0xc0` low-passes strictly more than `0x80`.
67
+ */
68
+ export const FILTER_DAMPEN_LEVEL = [0x00, 0x80, 0xc0];
69
+ /** The highest level DAMPEN (`!dampen<N>`) accepts (finding A.7). */
70
+ export const FILTER_MAX_LEVEL = 2;
71
+ /**
72
+ * Semitone offset of each note letter from C, within an octave (finding B.2:
73
+ * `c=0,d=2,e=4,f=5,g=7,a=9,b=11`).
74
+ */
75
+ const SEMITONE = {
76
+ c: 0,
77
+ d: 2,
78
+ e: 4,
79
+ f: 5,
80
+ g: 7,
81
+ a: 9,
82
+ b: 11,
83
+ };
84
+ /**
85
+ * A structured picopilot-MML transpile failure. Carries a machine-readable
86
+ * `code` (surfaced by the command as incur's `error({code,...})` envelope) plus
87
+ * a human-readable, actionable `message`. Never thrown for a case the spec
88
+ * defines a clamp/round for; only the genuine refusals + parse errors.
89
+ */
90
+ export class AudioMmlError extends Error {
91
+ code;
92
+ constructor(code, message) {
93
+ super(message);
94
+ this.name = 'AudioMmlError';
95
+ this.code = code;
96
+ }
97
+ }
98
+ /**
99
+ * Transpiles a picopilot-MML string into ONE `__sfx__` text row (finding Part
100
+ * A/B). Emits the friendly text nibbles directly.
101
+ *
102
+ * Modal state model (finding B.1): `@<hex>` waveform, `v<0-7>` volume,
103
+ * `e<0-7>`/mnemonic effect, `o<0-5>` octave, `l<N>` default length, `>`/`<`
104
+ * octave shift, all sticky. A bare note emits one row using the current state.
105
+ *
106
+ * SFX-level directives (finding B.5): `s<N>` speed (default 16), `{`/`}` loop
107
+ * markers (single `{` = the LEN special case).
108
+ *
109
+ * Durations are TRACKER ROWS (finding B.4): a length `N` = N rows, emitted as
110
+ * the note then `(N-1)` tie rows re-striking it; `.` multiplies by 1.5 (rounded
111
+ * to the nearest whole row, warned); `r` = silent rows; `^` extends the previous
112
+ * note.
113
+ *
114
+ * @throws {AudioMmlError} `audio-mml-pitch-out-of-range` (a note below C0 / above
115
+ * D#5), `audio-mml-sfx-overflow` (>32 rows), or `audio-mml-parse-error` (a
116
+ * token that cannot be parsed, incl. a tempo-style input).
117
+ */
118
+ export function mmlToSfxRow(mml) {
119
+ const state = {
120
+ octave: DEFAULT_OCTAVE,
121
+ waveform: 0,
122
+ volume: 7,
123
+ effect: 0,
124
+ length: DEFAULT_LENGTH,
125
+ };
126
+ const notes = [];
127
+ const warnings = [];
128
+ let speed = DEFAULT_SPEED;
129
+ let filters = 0;
130
+ let loopStartRow;
131
+ let loopEndRow;
132
+ let lastNote;
133
+ const src = mml;
134
+ let i = 0;
135
+ const len = src.length;
136
+ /** The overflow check, applied every time rows are appended (finding B.4). */
137
+ const pushNote = (note) => {
138
+ if (notes.length + 1 > SFX_MAX_ROWS) {
139
+ throw new AudioMmlError('audio-mml-sfx-overflow', `picopilot-MML produced more than ${SFX_MAX_ROWS} tracker rows (an SFX holds at most ${SFX_MAX_ROWS} rows). Split the melody across multiple SFX + a music pattern, or shorten it. (Remember: a length is a ROW COUNT, not a musical note value.)`);
140
+ }
141
+ notes.push(note);
142
+ };
143
+ while (i < len) {
144
+ const ch = src[i];
145
+ // Whitespace + `|` bar separators are cosmetic and ignored (readability).
146
+ if (/\s/.test(ch) || ch === '|') {
147
+ i++;
148
+ continue;
149
+ }
150
+ const lower = ch.toLowerCase();
151
+ // --- SFX-level directives -------------------------------------------------
152
+ if (lower === 's') {
153
+ const { value, next } = readInt(src, i + 1);
154
+ if (value === undefined) {
155
+ throw parseError(src, i, "expected a number after 's' (SFX speed)");
156
+ }
157
+ if (value < 1 || value > 255) {
158
+ throw parseError(src, i, `SFX speed 's${value}' out of range 1..255 (ticks per row)`);
159
+ }
160
+ speed = value;
161
+ i = next;
162
+ continue;
163
+ }
164
+ // `!<name>[<level>]`: an SFX-level FILTER directive (finding A.7). A `!` head
165
+ // never collides with the note grammar (unlike the rejected `sl vb dr`
166
+ // mnemonics, which WERE bare note-letter sequences, ADR-0008). They set the
167
+ // first header byte; DAMPEN/REVERB take an optional 1..2 level (default 1).
168
+ if (ch === '!') {
169
+ const parsed = readFilter(src, i);
170
+ filters |= parsed.bits;
171
+ i = parsed.next;
172
+ continue;
173
+ }
174
+ if (ch === '{') {
175
+ loopStartRow = notes.length;
176
+ i++;
177
+ continue;
178
+ }
179
+ if (ch === '}') {
180
+ loopEndRow = notes.length;
181
+ i++;
182
+ continue;
183
+ }
184
+ // --- Modal setters --------------------------------------------------------
185
+ if (lower === '@') {
186
+ // `@<hexdigit>`: waveform 0..7 built-in, 8..15 custom SFX-instrument.
187
+ const hd = src[i + 1];
188
+ const wv = hd === undefined ? Number.NaN : Number.parseInt(hd, 16);
189
+ if (Number.isNaN(wv)) {
190
+ throw parseError(src, i, "expected a hex digit 0-f after '@' (waveform 0-7, 8-f = custom SFX-instrument)");
191
+ }
192
+ state.waveform = wv;
193
+ i += 2;
194
+ continue;
195
+ }
196
+ if (lower === 'v') {
197
+ const { value, next } = readInt(src, i + 1);
198
+ if (value === undefined || value > 7) {
199
+ throw parseError(src, i, "expected a digit 0-7 after 'v' (volume)");
200
+ }
201
+ state.volume = value;
202
+ i = next;
203
+ continue;
204
+ }
205
+ if (lower === 'o') {
206
+ const { value, next } = readInt(src, i + 1);
207
+ if (value === undefined || value > 5) {
208
+ throw parseError(src, i, "expected a digit 0-5 after 'o' (octave)");
209
+ }
210
+ state.octave = value;
211
+ i = next;
212
+ continue;
213
+ }
214
+ if (lower === 'l') {
215
+ // `l<N>[.]`: default note length in ROWS (may be dotted).
216
+ const { value, next } = readInt(src, i + 1);
217
+ if (value === undefined || value < 1) {
218
+ throw parseError(src, i, "expected a positive number after 'l' (default note length in rows)");
219
+ }
220
+ const dots = countDots(src, next);
221
+ const token = src.slice(i, dots.next);
222
+ const rows = resolveRows(value, dots.count, token, warnings);
223
+ state.length = rows;
224
+ i = dots.next;
225
+ continue;
226
+ }
227
+ if (ch === '>') {
228
+ state.octave += 1;
229
+ i++;
230
+ continue;
231
+ }
232
+ if (ch === '<') {
233
+ state.octave -= 1;
234
+ i++;
235
+ continue;
236
+ }
237
+ // --- Effect ---------------------------------------------------------------
238
+ // `e` is BOTH a note letter and the effect prefix (finding B.1). The
239
+ // committed disambiguation (finding B.3: `e0..e7` is "the canonical,
240
+ // unambiguous form"): `e` FOLLOWED BY a digit 0-7 is the effect token; a
241
+ // bare `e` (or `e` + accidental/dot) falls through to the note-E handler
242
+ // below. So note E takes the default length (`l4 e`) rather than `e4`
243
+ // (which is effect 4). Documented in the command help (ADR-0008).
244
+ if (lower === 'e') {
245
+ const d = src[i + 1];
246
+ if (d !== undefined && d >= '0' && d <= '7') {
247
+ state.effect = Number.parseInt(d, 10);
248
+ i += 2;
249
+ continue;
250
+ }
251
+ if (d !== undefined && d >= '8' && d <= '9') {
252
+ throw parseError(src, i, "effect 'e8'/'e9' out of range; effects are e0..e7");
253
+ }
254
+ // else: fall through, `e` is the note E.
255
+ }
256
+ // --- Rest -----------------------------------------------------------------
257
+ if (lower === 'r') {
258
+ const dur = readDuration(src, i, i + 1, state.length);
259
+ for (let k = 0; k < dur.rows; k++) {
260
+ pushNote({ pitch: 0, waveform: state.waveform, volume: 0, effect: 0 });
261
+ }
262
+ collectWarning(dur, warnings);
263
+ lastNote = undefined;
264
+ i = dur.next;
265
+ continue;
266
+ }
267
+ // --- Tie: extend the previous note ---------------------------------------
268
+ if (ch === '^') {
269
+ if (lastNote === undefined) {
270
+ throw parseError(src, i, "'^' (tie) with no preceding note to extend");
271
+ }
272
+ const dur = readDuration(src, i, i + 1, state.length);
273
+ for (let k = 0; k < dur.rows; k++)
274
+ pushNote({ ...lastNote });
275
+ collectWarning(dur, warnings);
276
+ i = dur.next;
277
+ continue;
278
+ }
279
+ // --- Note -----------------------------------------------------------------
280
+ if (lower in SEMITONE) {
281
+ let semitone = SEMITONE[lower];
282
+ let j = i + 1;
283
+ // Accidental: `+`/`#` sharp, `-` flat.
284
+ if (src[j] === '+' || src[j] === '#') {
285
+ semitone += 1;
286
+ j++;
287
+ }
288
+ else if (src[j] === '-') {
289
+ semitone -= 1;
290
+ j++;
291
+ }
292
+ const pitch = 12 * state.octave + semitone;
293
+ const noteToken = src.slice(i, j);
294
+ if (pitch < PITCH_MIN || pitch > PITCH_MAX) {
295
+ throw new AudioMmlError('audio-mml-pitch-out-of-range', `note '${noteToken}' at octave o${state.octave} maps to pitch ${pitch}, outside PICO-8's range C0..D#5 (0..${PITCH_MAX}). PICO-8 has no notes above D#5 or below C0; pick an octave in range rather than transposing off the keyboard.`);
296
+ }
297
+ const dur = readDuration(src, i, j, state.length);
298
+ const note = {
299
+ pitch,
300
+ waveform: state.waveform,
301
+ volume: state.volume,
302
+ effect: state.effect,
303
+ };
304
+ for (let k = 0; k < dur.rows; k++)
305
+ pushNote({ ...note });
306
+ collectWarning(dur, warnings);
307
+ lastNote = note;
308
+ i = dur.next;
309
+ continue;
310
+ }
311
+ throw parseError(src, i, `unexpected token '${ch}'`);
312
+ }
313
+ const { loopStart, loopEnd } = resolveLoop(loopStartRow, loopEndRow, notes.length);
314
+ return {
315
+ row: emitRow({ filters, speed, loopStart, loopEnd, notes }),
316
+ rows: notes.length,
317
+ speed,
318
+ loopStart,
319
+ loopEnd,
320
+ filters,
321
+ roundingWarnings: warnings,
322
+ };
323
+ }
324
+ /**
325
+ * Reads an optional `[length][dots]` after a note/rest/tie head at `from`. If no
326
+ * explicit length digit is present the current default `length` (already in
327
+ * rows) is used, and any dots still multiply it.
328
+ */
329
+ function readDuration(src, head, from, defaultRows) {
330
+ const { value, next } = readInt(src, from);
331
+ const dots = countDots(src, value === undefined ? from : next);
332
+ if (value === undefined && dots.count === 0) {
333
+ return { rows: defaultRows, next: dots.next };
334
+ }
335
+ const base = value ?? defaultRows;
336
+ const warnings = [];
337
+ const token = src.slice(head, dots.next);
338
+ const rows = resolveRows(base, dots.count, token, warnings);
339
+ return { rows, next: dots.next, warning: warnings[0] };
340
+ }
341
+ /**
342
+ * Resolves a base row count + dot count into an integer row count. Each dot
343
+ * multiplies by an added 1/2, 1/4, ... (dotted-note convention): `n` dots =>
344
+ * factor `2 - (1/2)^n`. Fractional results round to the nearest whole row (min
345
+ * 1), and a rounding is recorded so the command can warn (finding B.4).
346
+ */
347
+ function resolveRows(base, dots, token, warnings) {
348
+ if (dots === 0)
349
+ return base;
350
+ const factor = 2 - 0.5 ** dots;
351
+ const exact = base * factor;
352
+ const rounded = Math.max(1, Math.round(exact));
353
+ if (rounded !== exact) {
354
+ warnings.push({ token, exactRows: exact, roundedRows: rounded });
355
+ }
356
+ return rounded;
357
+ }
358
+ /** Pushes a duration's rounding warning (if any) into the accumulator. */
359
+ function collectWarning(dur, warnings) {
360
+ if (dur.warning)
361
+ warnings.push(dur.warning);
362
+ }
363
+ /** Counts consecutive `.` dots from `at`, returning the count + resume index. */
364
+ function countDots(src, at) {
365
+ let n = at;
366
+ while (src[n] === '.')
367
+ n++;
368
+ return { count: n - at, next: n };
369
+ }
370
+ /** Reads a non-negative integer at `at`, or `undefined` if none; returns resume index. */
371
+ function readInt(src, at) {
372
+ let j = at;
373
+ while (j < src.length && src[j] >= '0' && src[j] <= '9')
374
+ j++;
375
+ if (j === at)
376
+ return { value: undefined, next: at };
377
+ return { value: Number.parseInt(src.slice(at, j), 10), next: j };
378
+ }
379
+ /** Builds an `audio-mml-parse-error` naming the offending column (1-based). */
380
+ function parseError(src, at, why) {
381
+ const col = at + 1;
382
+ const near = src.slice(at, at + 8);
383
+ return new AudioMmlError('audio-mml-parse-error', `picopilot-MML parse error at column ${col} (near "${near}"): ${why}. Note: durations are TRACKER ROWS (l4 = 4 rows), not tempo/BPM; there is no tempo token.`);
384
+ }
385
+ /**
386
+ * Parses one `!<name>[<level>]` FILTER directive at `at` (the `!`), returning the
387
+ * filter bits to OR into the SFX header byte + the resume index (finding A.7).
388
+ *
389
+ * The 5 switches: `!noiz` (instrument-6-only), `!buzz`, `!detune1`, `!detune2`,
390
+ * `!reverb[1|2]`, `!dampen[1|2]`. DAMPEN/REVERB take an optional level 1..2
391
+ * (default 1); `!dampen`/`!dampen1` = level 1, `!dampen2` = level 2. A level
392
+ * OUTSIDE 1..2 is a STRUCTURED refusal ({@link AudioMmlError}
393
+ * `audio-mml-filter-level-out-of-range`), never a silent clamp (matching the
394
+ * pitch/overflow refusals, ADR-0008). `!detune` requires an explicit 1/2 (the
395
+ * two detunes are distinct sub-modes, not levels of one).
396
+ *
397
+ * @throws {AudioMmlError} `audio-mml-filter-level-out-of-range` (bad DAMPEN/
398
+ * REVERB/DETUNE level) or `audio-mml-parse-error` (an unknown `!<name>`).
399
+ */
400
+ function readFilter(src, at) {
401
+ // Read the lowercase name letters after `!`.
402
+ let j = at + 1;
403
+ while (j < src.length && /[a-z]/i.test(src[j]))
404
+ j++;
405
+ const name = src.slice(at + 1, j).toLowerCase();
406
+ // Read an optional trailing level digit (e.g. `!dampen2`, `!detune1`).
407
+ const { value: level, next } = readInt(src, j);
408
+ const token = src.slice(at, next);
409
+ const leveled = (table, label, defaultLevel) => {
410
+ const lvl = level ?? defaultLevel;
411
+ if (lvl < 1 || lvl > FILTER_MAX_LEVEL) {
412
+ throw new AudioMmlError('audio-mml-filter-level-out-of-range', `filter '${token}' has ${label} level ${lvl}, outside 1..${FILTER_MAX_LEVEL}. PICO-8 gives ${label} exactly ${FILTER_MAX_LEVEL} levels; use !${name}1 or !${name}2.`);
413
+ }
414
+ return table[lvl];
415
+ };
416
+ switch (name) {
417
+ case 'noiz':
418
+ rejectLevel(src, at, token, name, level);
419
+ return { bits: FILTER_NOIZ, next };
420
+ case 'buzz':
421
+ rejectLevel(src, at, token, name, level);
422
+ return { bits: FILTER_BUZZ, next };
423
+ case 'reverb':
424
+ rejectLevel(src, at, token, name, level);
425
+ return { bits: FILTER_REVERB, next };
426
+ case 'detune': {
427
+ // `!detune` needs an explicit 1 or 2 (they are distinct sub-modes).
428
+ if (level === undefined) {
429
+ throw new AudioMmlError('audio-mml-filter-level-out-of-range', `filter '${token}' needs a mode: !detune1 (flange) or !detune2 (octave). PICO-8 has two distinct detunes, not a level.`);
430
+ }
431
+ if (level === 1)
432
+ return { bits: FILTER_DETUNE_1, next };
433
+ if (level === 2)
434
+ return { bits: FILTER_DETUNE_2, next };
435
+ throw new AudioMmlError('audio-mml-filter-level-out-of-range', `filter '${token}' mode ${level} is not 1 (flange) or 2 (octave).`);
436
+ }
437
+ case 'detune1':
438
+ return { bits: FILTER_DETUNE_1, next };
439
+ case 'detune2':
440
+ return { bits: FILTER_DETUNE_2, next };
441
+ case 'dampen':
442
+ return { bits: leveled(FILTER_DAMPEN_LEVEL, 'DAMPEN', 1), next };
443
+ default:
444
+ throw parseError(src, at, `unknown filter '${token}'. The 5 SFX filters are !noiz !buzz !detune1/!detune2 !reverb !dampen[1|2]`);
445
+ }
446
+ }
447
+ /** Refuses a level on a filter that has none (`!noiz2`, `!buzz1`), no silent drop. */
448
+ function rejectLevel(src, at, token, name, level) {
449
+ if (level !== undefined) {
450
+ throw new AudioMmlError('audio-mml-filter-level-out-of-range', `filter '${token}' takes no level; !${name} is a simple on/off switch (only !dampen and !reverb have levels).`);
451
+ }
452
+ }
453
+ /**
454
+ * Resolves the raw `{`/`}` marker rows into header `loopStart`/`loopEnd` values
455
+ * (finding A.1 / B.5):
456
+ * - neither marker: loop off (`0 0`).
457
+ * - both: `loopStart` = row at `{`, `loopEnd` = row at `}`.
458
+ * - only `{`: the LEN special case (`loopEnd == 0`, `loopStart` reinterpreted as
459
+ * the pattern length): emit `loopStart = rowCount`, `loopEnd = 0`.
460
+ */
461
+ function resolveLoop(loopStartRow, loopEndRow, rowCount) {
462
+ if (loopStartRow === undefined && loopEndRow === undefined) {
463
+ return { loopStart: 0, loopEnd: 0 };
464
+ }
465
+ if (loopStartRow !== undefined && loopEndRow === undefined) {
466
+ // Single `{` = LEN special case: this SFX is `rowCount` rows long.
467
+ return { loopStart: rowCount, loopEnd: 0 };
468
+ }
469
+ // `}` present (with or without `{`): a real loop. A bare `}` loops back to 0.
470
+ return { loopStart: loopStartRow ?? 0, loopEnd: loopEndRow ?? 0 };
471
+ }
472
+ /** Serializes the header + notes into the 168-char `__sfx__` text row (finding A). */
473
+ function emitRow(sfx) {
474
+ // Header: filter-byte(2) speed(2) loopstart(2) loopend(2). The first byte is the
475
+ // per-SFX FILTER bitfield (finding A.7); its low bit is the cosmetic pitch/
476
+ // tracker mode flag, which we leave 0 (pitch mode), so the byte is exactly the
477
+ // OR of the selected filter values.
478
+ const header = byte(sfx.filters) +
479
+ byte(sfx.speed) +
480
+ byte(sfx.loopStart) +
481
+ byte(sfx.loopEnd);
482
+ let body = '';
483
+ for (let r = 0; r < SFX_MAX_ROWS; r++) {
484
+ const note = sfx.notes[r];
485
+ if (note === undefined) {
486
+ // Unfilled rows are all-zero (pitch 0, wave 0, vol 0 = silent, eff 0).
487
+ body += '00000';
488
+ continue;
489
+ }
490
+ body +=
491
+ byte(note.pitch) +
492
+ nib(note.waveform) +
493
+ nib(note.volume) +
494
+ nib(note.effect);
495
+ }
496
+ return header + body;
497
+ }
498
+ /** A byte as two lowercase hex chars. */
499
+ function byte(n) {
500
+ return n.toString(16).padStart(2, '0');
501
+ }
502
+ /** A nibble as one lowercase hex char. */
503
+ function nib(n) {
504
+ return n.toString(16);
505
+ }
506
+ //# sourceMappingURL=sfx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sfx.js","sourceRoot":"","sources":["../../../src/engine/audio/sfx.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * The section names picopilot models in a text-format `.p8` cart. These are the
3
+ * markers PICO-8 writes (`__lua__`, `__gfx__`, ...); `__label__` is the cart
4
+ * label image, also hex.
5
+ */
6
+ export declare const CART_SECTION_NAMES: readonly ["lua", "gfx", "gff", "label", "map", "sfx", "music"];
7
+ /** A recognised `.p8` section name (without the surrounding `__`). */
8
+ export type CartSectionName = (typeof CART_SECTION_NAMES)[number];
9
+ /**
10
+ * The in-memory model of a text-format `.p8` cart: the load-bearing seam every
11
+ * cart-touching command (init, gfx, tokens, verify) reads and writes through.
12
+ *
13
+ * Design contract:
14
+ *
15
+ * - **Round-trip is identity.** `Cart.parse(text).serialize() === text`, byte
16
+ * for byte, for any well-formed cart, regardless of newline style or trailing
17
+ * newline. Achieved by preserving the header, each marker line, and each
18
+ * section body verbatim, and never normalising whitespace on the way through.
19
+ * - **Sections are independently addressable.** {@link getSection} /
20
+ * {@link setSection} read and replace one section without disturbing the
21
+ * others (or the header).
22
+ * - **gfx/map are addressable as regions, not opaque strings.** The `__gfx__`
23
+ * and `__map__` hex bodies are exposed as row/pixel grids (see `gfx.ts` /
24
+ * `map.ts`) so the gfx codec and the 0x1000 overlap check can target specific
25
+ * sprites/map rows.
26
+ */
27
+ export declare class Cart {
28
+ /**
29
+ * The raw text before the first section marker (the `pico-8 cartridge ...`
30
+ * line, the `version N` line, and any trailing blank lines), preserved
31
+ * verbatim so it round-trips exactly.
32
+ */
33
+ readonly header: string;
34
+ private readonly sections;
35
+ private constructor();
36
+ /**
37
+ * Parses a `.p8` text blob into a {@link Cart}.
38
+ *
39
+ * Malformed input throws a {@link CartParseError} with a machine-readable
40
+ * `code` (missing header/version, unknown or duplicate section) rather than
41
+ * crashing, so the command layer can surface a structured failure.
42
+ */
43
+ static parse(text: string): Cart;
44
+ /** The names of the sections present in this cart, in file order. */
45
+ sectionNames(): CartSectionName[];
46
+ /** True if the cart contains the named section. */
47
+ hasSection(name: CartSectionName): boolean;
48
+ /**
49
+ * Returns the raw body text of a section (everything after the marker line,
50
+ * verbatim including its own newlines), or `undefined` if the section is not
51
+ * present. The gfx/map region helpers build on this.
52
+ */
53
+ getSection(name: CartSectionName): string | undefined;
54
+ /**
55
+ * Replaces one section's body in place, leaving every other section and the
56
+ * header untouched. If the section is not yet present it is appended (with a
57
+ * `__name__\n` marker in the file's dominant newline style).
58
+ *
59
+ * The body is written verbatim; callers that want a trailing newline must
60
+ * include it. Region-level helpers (gfx/map) go through here.
61
+ */
62
+ setSection(name: CartSectionName, body: string): void;
63
+ /**
64
+ * Serializes the cart back to a `.p8` text blob. For an unmodified cart this
65
+ * is byte-identical to the text it was parsed from.
66
+ */
67
+ serialize(): string;
68
+ /**
69
+ * The dominant newline style of the file, inferred from the header, used only
70
+ * when APPENDING a brand-new section marker (existing markers keep their own
71
+ * terminator verbatim). Defaults to `\n`.
72
+ */
73
+ private newline;
74
+ }
75
+ //# sourceMappingURL=cart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cart.d.ts","sourceRoot":"","sources":["../../../src/engine/cart/cart.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,gEAQrB,CAAC;AAEX,sEAAsE;AACtE,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AA+BlE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,IAAI;IAChB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IAEzC,OAAO;IAKP;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAiEhC,qEAAqE;IACrE,YAAY,IAAI,eAAe,EAAE;IAIjC,mDAAmD;IACnD,UAAU,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO;IAI1C;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS;IAIrD;;;;;;;OAOG;IACH,UAAU,CAAC,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IASrD;;;OAGG;IACH,SAAS,IAAI,MAAM;IAQnB;;;;OAIG;IACH,OAAO,CAAC,OAAO;CAGf"}