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,174 @@
1
+ pico-8 cartridge // http://www.pico-8.com
2
+ version 42
3
+ __lua__
4
+ -- full fixture
5
+ function _draw() spr(1,60,60) end
6
+ __gfx__
7
+ 00000000e8e8e8e80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
8
+ 000000008e8e8e8e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
9
+ 00000000e8e8e8e80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
10
+ 000000008e8e8e8e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
11
+ 00000000e8e8e8e80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
12
+ 000000008e8e8e8e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
13
+ 00000000e8e8e8e80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
14
+ 000000008e8e8e8e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
15
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
16
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
17
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
18
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
19
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
20
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
21
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
22
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
23
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
24
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
25
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
26
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
27
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
28
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
29
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
30
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
31
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
32
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
33
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
34
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
35
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
36
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
37
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
38
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
39
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
40
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
41
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
42
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
43
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
44
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
45
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
46
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
47
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
48
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
49
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
50
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
51
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
52
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
53
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
54
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
55
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
56
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
57
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
58
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
59
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
60
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
61
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
62
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
63
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
64
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
65
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
66
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
67
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
68
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
69
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
70
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
71
+ 00000000000000007777777700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
72
+ 00000000000000007777777700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
73
+ 00000000000000007777777700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
74
+ 00000000000000007777777700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
75
+ 00000000000000007777777700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
76
+ 00000000000000007777777700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
77
+ 00000000000000007777777700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
78
+ 00000000000000007777777700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
79
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
80
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
81
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
82
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
83
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
84
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
85
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
86
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
87
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
88
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
89
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
90
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
91
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
92
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
93
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
94
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
95
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
96
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
97
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
98
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
99
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
100
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
101
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
102
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
103
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
104
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
105
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
106
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
107
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
108
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
109
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
110
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
111
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
112
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
113
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
114
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
115
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
116
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
117
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
118
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
119
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
120
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
121
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
122
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
123
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
124
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
125
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
126
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
127
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
128
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
129
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
130
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
131
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
132
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
133
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
134
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
135
+ __gff__
136
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
137
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
138
+ __map__
139
+ 0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
140
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
141
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
142
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
143
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
144
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
145
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
146
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
147
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
148
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
149
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
150
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
151
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
152
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
153
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
154
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
155
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
156
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
157
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
158
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
159
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
160
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
161
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
162
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
163
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
164
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
165
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
166
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
167
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
168
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
169
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
170
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
171
+ __sfx__
172
+ 000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
173
+ __music__
174
+ 00 41424344
@@ -0,0 +1,2 @@
1
+ pico-8 cartridge // http://www.pico-8.com
2
+ version 42
@@ -0,0 +1,2 @@
1
+ this is not a pico-8 cart
2
+ just some text
@@ -0,0 +1,10 @@
1
+ pico-8 cartridge // http://www.pico-8.com
2
+ version 42
3
+ __lua__
4
+ -- minimal cart
5
+ function _init() end
6
+ function _update() end
7
+ function _draw() cls() end
8
+ __gfx__
9
+ 00000000000000000000000000000000
10
+ 00000000000000000000000000000000
@@ -0,0 +1,6 @@
1
+ pico-8 cartridge // http://www.pico-8.com
2
+ version 42
3
+ __lua__
4
+ print("no trailing newline")
5
+ __gfx__
6
+ 00000000
@@ -0,0 +1,195 @@
1
+ import type {Cart} from './cart.js';
2
+ import {CartRangeError} from './errors.js';
3
+
4
+ /**
5
+ * Addressable view over a cart's `__gfx__` section: the 128x128 spritesheet as a
6
+ * grid of per-pixel colour nibbles (0..15), NOT an opaque hex string.
7
+ *
8
+ * The spritesheet holds 256 8x8 sprites laid out 16 per row: sprite `n` lives at
9
+ * pixel column `(n % 16) * 8`, row `(n \ 16) * 8`. Sprites 0..127 are the base
10
+ * bank; sprites 128..255 (`0x1000` in memory) alias `__map__` rows 32..63 (the
11
+ * overlap the smart-refuse depends on); see {@link mapRowsForSprite}.
12
+ *
13
+ * Reads/writes go through the parsed grid; call {@link commit} to write the grid
14
+ * back into the cart's `__gfx__` body (preserving its trailing-newline style).
15
+ * If the section body is shorter than the full sheet (a partial/authored cart),
16
+ * missing pixels read as 0 and short rows are padded to full width on commit.
17
+ */
18
+ export const GFX_WIDTH = 128;
19
+ export const GFX_HEIGHT = 128;
20
+ export const SPRITE_SIZE = 8;
21
+ export const SPRITES_PER_ROW = 16;
22
+
23
+ export class GfxSheet {
24
+ /** `pixels[y][x]` is the colour index 0..15 at pixel (x, y). */
25
+ private readonly pixels: number[][];
26
+
27
+ /** The newline that terminates each row line in the source body (`\n` default). */
28
+ private readonly newline: string;
29
+
30
+ private constructor(pixels: number[][], newline: string) {
31
+ this.pixels = pixels;
32
+ this.newline = newline;
33
+ }
34
+
35
+ /**
36
+ * Builds an addressable sheet from a cart's `__gfx__` body. A missing or empty
37
+ * section yields an all-zero sheet, so the codec can still address any sprite.
38
+ */
39
+ static fromBody(body: string | undefined): GfxSheet {
40
+ const newline = body !== undefined && /\r\n/.test(body) ? '\r\n' : '\n';
41
+ const pixels: number[][] = [];
42
+ const lines = body === undefined ? [] : body.split(/\r?\n/);
43
+ for (let y = 0; y < GFX_HEIGHT; y++) {
44
+ const line = lines[y] ?? '';
45
+ const row: number[] = [];
46
+ for (let x = 0; x < GFX_WIDTH; x++) {
47
+ const ch = line[x];
48
+ row.push(ch === undefined ? 0 : hexNibble(ch));
49
+ }
50
+ pixels.push(row);
51
+ }
52
+ return new GfxSheet(pixels, newline);
53
+ }
54
+
55
+ /** Reads the colour index (0..15) at pixel (x, y). */
56
+ getPixel(x: number, y: number): number {
57
+ this.assertPixel(x, y);
58
+ return this.pixels[y]?.[x] ?? 0;
59
+ }
60
+
61
+ /** Writes the colour index (0..15) at pixel (x, y). */
62
+ setPixel(x: number, y: number, color: number): void {
63
+ this.assertPixel(x, y);
64
+ if (!Number.isInteger(color) || color < 0 || color > 15) {
65
+ throw new CartRangeError(`colour ${color} out of range 0..15`);
66
+ }
67
+ const row = this.pixels[y];
68
+ if (row !== undefined) row[x] = color;
69
+ }
70
+
71
+ /**
72
+ * Reads one 8x8 sprite (0..255) as an 8-row grid of colour indices, `grid[r][c]`.
73
+ */
74
+ getSprite(n: number): number[][] {
75
+ const {x0, y0} = spriteOrigin(n);
76
+ const grid: number[][] = [];
77
+ for (let r = 0; r < SPRITE_SIZE; r++) {
78
+ const row: number[] = [];
79
+ for (let c = 0; c < SPRITE_SIZE; c++)
80
+ row.push(this.getPixel(x0 + c, y0 + r));
81
+ grid.push(row);
82
+ }
83
+ return grid;
84
+ }
85
+
86
+ /**
87
+ * Writes one 8x8 sprite (0..255) from an 8-row grid of colour indices. The
88
+ * grid must be 8x8; each cell 0..15.
89
+ */
90
+ setSprite(n: number, grid: number[][]): void {
91
+ if (grid.length !== SPRITE_SIZE) {
92
+ throw new CartRangeError(
93
+ `sprite grid must have ${SPRITE_SIZE} rows, got ${grid.length}`,
94
+ );
95
+ }
96
+ const {x0, y0} = spriteOrigin(n);
97
+ for (let r = 0; r < SPRITE_SIZE; r++) {
98
+ const gridRow = grid[r];
99
+ if (gridRow === undefined || gridRow.length !== SPRITE_SIZE) {
100
+ throw new CartRangeError(
101
+ `sprite grid row ${r} must have ${SPRITE_SIZE} cells`,
102
+ );
103
+ }
104
+ for (let c = 0; c < SPRITE_SIZE; c++)
105
+ this.setPixel(x0 + c, y0 + r, gridRow[c] ?? 0);
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Serializes the grid back to a `__gfx__` body (128 lines of 128 hex nibbles),
111
+ * using the source body's newline style and terminating the last line, so it
112
+ * matches what PICO-8 writes.
113
+ */
114
+ toBody(): string {
115
+ const lines: string[] = [];
116
+ for (let y = 0; y < GFX_HEIGHT; y++) {
117
+ let line = '';
118
+ for (let x = 0; x < GFX_WIDTH; x++)
119
+ line += (this.pixels[y]?.[x] ?? 0).toString(16);
120
+ lines.push(line);
121
+ }
122
+ return lines.join(this.newline) + this.newline;
123
+ }
124
+
125
+ /** Writes the grid back into the cart's `__gfx__` section. */
126
+ commit(cart: Cart): void {
127
+ cart.setSection('gfx', this.toBody());
128
+ }
129
+
130
+ private assertPixel(x: number, y: number): void {
131
+ if (
132
+ !Number.isInteger(x) ||
133
+ !Number.isInteger(y) ||
134
+ x < 0 ||
135
+ y < 0 ||
136
+ x >= GFX_WIDTH ||
137
+ y >= GFX_HEIGHT
138
+ ) {
139
+ throw new CartRangeError(
140
+ `pixel (${x}, ${y}) out of range 0..${GFX_WIDTH - 1}`,
141
+ );
142
+ }
143
+ }
144
+ }
145
+
146
+ /** The top-left pixel origin of sprite `n` (0..255) in the 128x128 sheet. */
147
+ export function spriteOrigin(n: number): {x0: number; y0: number} {
148
+ if (!Number.isInteger(n) || n < 0 || n > 255) {
149
+ throw new CartRangeError(`sprite ${n} out of range 0..255`);
150
+ }
151
+ return {
152
+ x0: (n % SPRITES_PER_ROW) * SPRITE_SIZE,
153
+ y0: Math.floor(n / SPRITES_PER_ROW) * SPRITE_SIZE,
154
+ };
155
+ }
156
+
157
+ /**
158
+ * Whether sprite `n` lives in the shared upper bank (128..255) that aliases the
159
+ * bottom half of `__map__`. The gfx/map overlap smart-refuse (next task) keys
160
+ * off this.
161
+ */
162
+ export function spriteAliasesMap(n: number): boolean {
163
+ if (!Number.isInteger(n) || n < 0 || n > 255) {
164
+ throw new CartRangeError(`sprite ${n} out of range 0..255`);
165
+ }
166
+ return n >= 128;
167
+ }
168
+
169
+ /**
170
+ * The `__map__` rows a shared-bank sprite (128..255) aliases, or `undefined` for
171
+ * a base-bank sprite (0..127) that aliases nothing.
172
+ *
173
+ * Memory layout: sprite `n`'s 8 pixel rows sit at gfx rows `(n \ 16) * 8`; for
174
+ * the shared bank those are gfx rows 64..127, which occupy the SAME memory as
175
+ * `__map__` rows 32..63. Each map row is 128 bytes = 2 gfx pixel rows (128 gfx
176
+ * nibbles map to 128/... ). Concretely: gfx row `g` (64..127) aliases map row
177
+ * `32 + (g - 64) \ 2`, so a single 8-row sprite covers 4 map rows.
178
+ */
179
+ export function mapRowsForSprite(
180
+ n: number,
181
+ ): {start: number; end: number} | undefined {
182
+ if (!spriteAliasesMap(n)) return undefined;
183
+ const {y0} = spriteOrigin(n);
184
+ // y0 is 64..120 for the shared bank; each pair of gfx rows aliases one map row.
185
+ const start = 32 + Math.floor((y0 - 64) / 2);
186
+ return {start, end: start + SPRITE_SIZE / 2}; // 8 gfx rows = 4 map rows: [start, end)
187
+ }
188
+
189
+ function hexNibble(ch: string): number {
190
+ const v = Number.parseInt(ch, 16);
191
+ if (Number.isNaN(v)) {
192
+ throw new CartRangeError(`invalid hex nibble "${ch}" in __gfx__`);
193
+ }
194
+ return v;
195
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The picopilot cart model: parse a text-format `.p8` into a typed, section-level
3
+ * model, read/modify individual sections, address the `__gfx__`/`__map__` hex as
4
+ * pixel/tile regions, and serialize back byte-identically.
5
+ *
6
+ * This is the load-bearing seam every cart-touching command (init, gfx, tokens,
7
+ * verify) reads and writes through. See `cart.ts` for the round-trip-identity
8
+ * contract; `gfx.ts` / `map.ts` for the addressable regions (and the 0x1000
9
+ * overlap the smart-refuse depends on).
10
+ */
11
+ export {Cart, CART_SECTION_NAMES, type CartSectionName} from './cart.js';
12
+ export {
13
+ CartParseError,
14
+ type CartParseErrorCode,
15
+ CartRangeError,
16
+ } from './errors.js';
17
+ export {
18
+ GfxSheet,
19
+ GFX_HEIGHT,
20
+ GFX_WIDTH,
21
+ mapRowsForSprite,
22
+ SPRITE_SIZE,
23
+ SPRITES_PER_ROW,
24
+ spriteAliasesMap,
25
+ spriteOrigin,
26
+ } from './gfx.js';
27
+ export {MapData, MAP_ROWS, MAP_WIDTH} from './map.js';
@@ -0,0 +1,134 @@
1
+ import type {Cart} from './cart.js';
2
+ import {CartRangeError} from './errors.js';
3
+
4
+ /**
5
+ * Addressable view over a cart's `__map__` section: the tile map as a grid of
6
+ * 8-bit tile indices, NOT an opaque hex string.
7
+ *
8
+ * The text `__map__` stores the base map: up to 32 rows of 128 tiles, each tile
9
+ * a byte written as two hex chars (`grid[y][x]`). Rows 32..63 (the shared half)
10
+ * are NOT stored here in the text format (they live in `__gfx__`'s upper bank
11
+ ), see `gfx.ts` {@link mapRowsForSprite}; this view models the `__map__` body
12
+ * as written. The 0x1000 overlap check reads a shared-bank sprite's aliased map
13
+ * region through {@link nonZeroTilesInRows} to decide whether a write clobbers
14
+ * real tiles.
15
+ *
16
+ * Reads/writes go through the parsed grid; call {@link commit} to write it back
17
+ * into the cart's `__map__` body. A missing/short section reads as zero tiles.
18
+ */
19
+ export const MAP_WIDTH = 128;
20
+ export const MAP_ROWS = 32;
21
+
22
+ export class MapData {
23
+ /** `tiles[y][x]` is the 0..255 tile index at map cell (x, y). */
24
+ private readonly tiles: number[][];
25
+
26
+ private readonly newline: string;
27
+
28
+ private constructor(tiles: number[][], newline: string) {
29
+ this.tiles = tiles;
30
+ this.newline = newline;
31
+ }
32
+
33
+ /** Builds an addressable map from a cart's `__map__` body (all-zero if absent). */
34
+ static fromBody(body: string | undefined): MapData {
35
+ const newline = body !== undefined && /\r\n/.test(body) ? '\r\n' : '\n';
36
+ const lines = body === undefined ? [] : body.split(/\r?\n/);
37
+ const tiles: number[][] = [];
38
+ for (let y = 0; y < MAP_ROWS; y++) {
39
+ const line = lines[y] ?? '';
40
+ const row: number[] = [];
41
+ for (let x = 0; x < MAP_WIDTH; x++) {
42
+ const hi = line[x * 2];
43
+ const lo = line[x * 2 + 1];
44
+ row.push(hi === undefined || lo === undefined ? 0 : hexByte(hi, lo));
45
+ }
46
+ tiles.push(row);
47
+ }
48
+ return new MapData(tiles, newline);
49
+ }
50
+
51
+ /** Reads the tile index (0..255) at map cell (x, y). */
52
+ getTile(x: number, y: number): number {
53
+ this.assertCell(x, y);
54
+ return this.tiles[y]?.[x] ?? 0;
55
+ }
56
+
57
+ /** Writes the tile index (0..255) at map cell (x, y). */
58
+ setTile(x: number, y: number, value: number): void {
59
+ this.assertCell(x, y);
60
+ if (!Number.isInteger(value) || value < 0 || value > 255) {
61
+ throw new CartRangeError(`tile value ${value} out of range 0..255`);
62
+ }
63
+ const row = this.tiles[y];
64
+ if (row !== undefined) row[x] = value;
65
+ }
66
+
67
+ /** Reads one full map row (128 tile indices) at row `y`. */
68
+ getRow(y: number): number[] {
69
+ if (!Number.isInteger(y) || y < 0 || y >= MAP_ROWS) {
70
+ throw new CartRangeError(`map row ${y} out of range 0..${MAP_ROWS - 1}`);
71
+ }
72
+ return (this.tiles[y] ?? []).slice();
73
+ }
74
+
75
+ /**
76
+ * Counts non-zero tiles across a half-open row range `[start, end)`, clamped
77
+ * to the stored `__map__` rows (0..31). Shared-bank rows (32..63) that the
78
+ * text `__map__` does not store contribute zero. This is the primitive the
79
+ * gfx/map overlap smart-refuse uses to decide whether a shared-bank sprite
80
+ * write would clobber real map data.
81
+ */
82
+ nonZeroTilesInRows(start: number, end: number): number {
83
+ let count = 0;
84
+ for (let y = Math.max(0, start); y < Math.min(MAP_ROWS, end); y++) {
85
+ for (let x = 0; x < MAP_WIDTH; x++)
86
+ if ((this.tiles[y]?.[x] ?? 0) !== 0) count++;
87
+ }
88
+ return count;
89
+ }
90
+
91
+ /** Serializes the grid back to a `__map__` body (32 lines of 256 hex chars). */
92
+ toBody(): string {
93
+ const lines: string[] = [];
94
+ for (let y = 0; y < MAP_ROWS; y++) {
95
+ let line = '';
96
+ for (let x = 0; x < MAP_WIDTH; x++)
97
+ line += byteHex(this.tiles[y]?.[x] ?? 0);
98
+ lines.push(line);
99
+ }
100
+ return lines.join(this.newline) + this.newline;
101
+ }
102
+
103
+ /** Writes the grid back into the cart's `__map__` section. */
104
+ commit(cart: Cart): void {
105
+ cart.setSection('map', this.toBody());
106
+ }
107
+
108
+ private assertCell(x: number, y: number): void {
109
+ if (
110
+ !Number.isInteger(x) ||
111
+ !Number.isInteger(y) ||
112
+ x < 0 ||
113
+ y < 0 ||
114
+ x >= MAP_WIDTH ||
115
+ y >= MAP_ROWS
116
+ ) {
117
+ throw new CartRangeError(
118
+ `map cell (${x}, ${y}) out of range 0..${MAP_WIDTH - 1} x 0..${MAP_ROWS - 1}`,
119
+ );
120
+ }
121
+ }
122
+ }
123
+
124
+ function hexByte(hi: string, lo: string): number {
125
+ const v = Number.parseInt(`${hi}${lo}`, 16);
126
+ if (Number.isNaN(v)) {
127
+ throw new CartRangeError(`invalid hex byte "${hi}${lo}" in __map__`);
128
+ }
129
+ return v;
130
+ }
131
+
132
+ function byteHex(value: number): string {
133
+ return value.toString(16).padStart(2, '0');
134
+ }