c64-kb 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (970) hide show
  1. package/CHANGELOG.md +2082 -0
  2. package/LICENSE +29 -0
  3. package/README.md +559 -0
  4. package/VERSION +25 -0
  5. package/dist/cli/setup.js +66 -0
  6. package/dist/cli/setup.js.map +1 -0
  7. package/dist/cli-memorize-audit.js +97 -0
  8. package/dist/cli-memorize-audit.js.map +1 -0
  9. package/dist/cli.js +335 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/config.js +83 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/context.js +53 -0
  14. package/dist/context.js.map +1 -0
  15. package/dist/domain/budget-notes.js +104 -0
  16. package/dist/domain/budget-notes.js.map +1 -0
  17. package/dist/domain/budget.js +417 -0
  18. package/dist/domain/budget.js.map +1 -0
  19. package/dist/domain/game-design.js +77 -0
  20. package/dist/domain/game-design.js.map +1 -0
  21. package/dist/domain/timing.js +39 -0
  22. package/dist/domain/timing.js.map +1 -0
  23. package/dist/graph/apply.js +132 -0
  24. package/dist/graph/apply.js.map +1 -0
  25. package/dist/graph/claims.js +231 -0
  26. package/dist/graph/claims.js.map +1 -0
  27. package/dist/graph/extract/archetype.js +118 -0
  28. package/dist/graph/extract/archetype.js.map +1 -0
  29. package/dist/graph/extract/common.js +69 -0
  30. package/dist/graph/extract/common.js.map +1 -0
  31. package/dist/graph/extract/failure.js +37 -0
  32. package/dist/graph/extract/failure.js.map +1 -0
  33. package/dist/graph/extract/game-design.js +189 -0
  34. package/dist/graph/extract/game-design.js.map +1 -0
  35. package/dist/graph/extract/hardware.js +124 -0
  36. package/dist/graph/extract/hardware.js.map +1 -0
  37. package/dist/graph/extract/pitfall.js +62 -0
  38. package/dist/graph/extract/pitfall.js.map +1 -0
  39. package/dist/graph/extract/raster-band.js +56 -0
  40. package/dist/graph/extract/raster-band.js.map +1 -0
  41. package/dist/graph/extract/recipe.js +71 -0
  42. package/dist/graph/extract/recipe.js.map +1 -0
  43. package/dist/graph/extract/technique-entities.js +180 -0
  44. package/dist/graph/extract/technique-entities.js.map +1 -0
  45. package/dist/graph/extract/technique.js +179 -0
  46. package/dist/graph/extract/technique.js.map +1 -0
  47. package/dist/graph/extract/toolchain.js +67 -0
  48. package/dist/graph/extract/toolchain.js.map +1 -0
  49. package/dist/graph/extract/types.js +3 -0
  50. package/dist/graph/extract/types.js.map +1 -0
  51. package/dist/graph/extract/vocabulary.js +65 -0
  52. package/dist/graph/extract/vocabulary.js.map +1 -0
  53. package/dist/graph/extract.js +43 -0
  54. package/dist/graph/extract.js.map +1 -0
  55. package/dist/graph/kernal-clobbers.js +64 -0
  56. package/dist/graph/kernal-clobbers.js.map +1 -0
  57. package/dist/graph/machine-variants.js +208 -0
  58. package/dist/graph/machine-variants.js.map +1 -0
  59. package/dist/ingest/files.js +99 -0
  60. package/dist/ingest/files.js.map +1 -0
  61. package/dist/ingest/passes.js +104 -0
  62. package/dist/ingest/passes.js.map +1 -0
  63. package/dist/ingest/points.js +50 -0
  64. package/dist/ingest/points.js.map +1 -0
  65. package/dist/ingest/report.js +140 -0
  66. package/dist/ingest/report.js.map +1 -0
  67. package/dist/ingest/tally.js +81 -0
  68. package/dist/ingest/tally.js.map +1 -0
  69. package/dist/ingest/verified-on.js +43 -0
  70. package/dist/ingest/verified-on.js.map +1 -0
  71. package/dist/ingest.js +135 -0
  72. package/dist/ingest.js.map +1 -0
  73. package/dist/schemas/cost-basis.js +5 -0
  74. package/dist/schemas/cost-basis.js.map +1 -0
  75. package/dist/schemas/machine-variant.js +25 -0
  76. package/dist/schemas/machine-variant.js.map +1 -0
  77. package/dist/schemas/plan-budget.js +121 -0
  78. package/dist/schemas/plan-budget.js.map +1 -0
  79. package/dist/schemas/tool-outputs.js +526 -0
  80. package/dist/schemas/tool-outputs.js.map +1 -0
  81. package/dist/server/define-tool.js +52 -0
  82. package/dist/server/define-tool.js.map +1 -0
  83. package/dist/server/defined-only.js +9 -0
  84. package/dist/server/defined-only.js.map +1 -0
  85. package/dist/server/tools-briefings.js +70 -0
  86. package/dist/server/tools-briefings.js.map +1 -0
  87. package/dist/server/tools-lookup.js +180 -0
  88. package/dist/server/tools-lookup.js.map +1 -0
  89. package/dist/server/tools-maintenance.js +116 -0
  90. package/dist/server/tools-maintenance.js.map +1 -0
  91. package/dist/server/tools-pitfalls.js +89 -0
  92. package/dist/server/tools-pitfalls.js.map +1 -0
  93. package/dist/server/tools-recipes.js +296 -0
  94. package/dist/server/tools-recipes.js.map +1 -0
  95. package/dist/server/tools-runtime.js +48 -0
  96. package/dist/server/tools-runtime.js.map +1 -0
  97. package/dist/server/tools.js +43 -0
  98. package/dist/server/tools.js.map +1 -0
  99. package/dist/server.js +95 -0
  100. package/dist/server.js.map +1 -0
  101. package/dist/services/analytics/schema.js +78 -0
  102. package/dist/services/analytics/schema.js.map +1 -0
  103. package/dist/services/analytics/statements.js +99 -0
  104. package/dist/services/analytics/statements.js.map +1 -0
  105. package/dist/services/analytics.js +195 -0
  106. package/dist/services/analytics.js.map +1 -0
  107. package/dist/services/bm25.js +158 -0
  108. package/dist/services/bm25.js.map +1 -0
  109. package/dist/services/chunker.js +81 -0
  110. package/dist/services/chunker.js.map +1 -0
  111. package/dist/services/embeddings.js +58 -0
  112. package/dist/services/embeddings.js.map +1 -0
  113. package/dist/services/falkor/base.js +85 -0
  114. package/dist/services/falkor/base.js.map +1 -0
  115. package/dist/services/falkor/links.js +361 -0
  116. package/dist/services/falkor/links.js.map +1 -0
  117. package/dist/services/falkor/nodes.js +183 -0
  118. package/dist/services/falkor/nodes.js.map +1 -0
  119. package/dist/services/falkor/params.js +45 -0
  120. package/dist/services/falkor/params.js.map +1 -0
  121. package/dist/services/falkor/schema.js +77 -0
  122. package/dist/services/falkor/schema.js.map +1 -0
  123. package/dist/services/falkor.js +100 -0
  124. package/dist/services/falkor.js.map +1 -0
  125. package/dist/services/qdrant.js +238 -0
  126. package/dist/services/qdrant.js.map +1 -0
  127. package/dist/services/versions.js +73 -0
  128. package/dist/services/versions.js.map +1 -0
  129. package/dist/services/vice-bin.js +51 -0
  130. package/dist/services/vice-bin.js.map +1 -0
  131. package/dist/tools/briefings/archetype.js +174 -0
  132. package/dist/tools/briefings/archetype.js.map +1 -0
  133. package/dist/tools/briefings/budget.js +177 -0
  134. package/dist/tools/briefings/budget.js.map +1 -0
  135. package/dist/tools/briefings/build-order.js +135 -0
  136. package/dist/tools/briefings/build-order.js.map +1 -0
  137. package/dist/tools/briefings/build.js +185 -0
  138. package/dist/tools/briefings/build.js.map +1 -0
  139. package/dist/tools/briefings/discovery.js +290 -0
  140. package/dist/tools/briefings/discovery.js.map +1 -0
  141. package/dist/tools/briefings/plan-pitfalls.js +69 -0
  142. package/dist/tools/briefings/plan-pitfalls.js.map +1 -0
  143. package/dist/tools/briefings/render.js +151 -0
  144. package/dist/tools/briefings/render.js.map +1 -0
  145. package/dist/tools/briefings/rows.js +41 -0
  146. package/dist/tools/briefings/rows.js.map +1 -0
  147. package/dist/tools/briefings/toolchain.js +63 -0
  148. package/dist/tools/briefings/toolchain.js.map +1 -0
  149. package/dist/tools/briefings/why-proposed.js +69 -0
  150. package/dist/tools/briefings/why-proposed.js.map +1 -0
  151. package/dist/tools/briefings.js +44 -0
  152. package/dist/tools/briefings.js.map +1 -0
  153. package/dist/tools/feedback.js +97 -0
  154. package/dist/tools/feedback.js.map +1 -0
  155. package/dist/tools/hydrate.js +75 -0
  156. package/dist/tools/hydrate.js.map +1 -0
  157. package/dist/tools/intelligence.js +67 -0
  158. package/dist/tools/intelligence.js.map +1 -0
  159. package/dist/tools/lint/asm-decimal.js +86 -0
  160. package/dist/tools/lint/asm-decimal.js.map +1 -0
  161. package/dist/tools/lint/asm-rules.js +221 -0
  162. package/dist/tools/lint/asm-rules.js.map +1 -0
  163. package/dist/tools/lint/asm-shared.js +3 -0
  164. package/dist/tools/lint/asm-shared.js.map +1 -0
  165. package/dist/tools/lint/c-rules.js +215 -0
  166. package/dist/tools/lint/c-rules.js.map +1 -0
  167. package/dist/tools/lint/text.js +122 -0
  168. package/dist/tools/lint/text.js.map +1 -0
  169. package/dist/tools/lint/types.js +40 -0
  170. package/dist/tools/lint/types.js.map +1 -0
  171. package/dist/tools/lint.js +76 -0
  172. package/dist/tools/lint.js.map +1 -0
  173. package/dist/tools/memorization-mcp.js +111 -0
  174. package/dist/tools/memorization-mcp.js.map +1 -0
  175. package/dist/tools/pitfalls/bm25.js +53 -0
  176. package/dist/tools/pitfalls/bm25.js.map +1 -0
  177. package/dist/tools/pitfalls/format.js +58 -0
  178. package/dist/tools/pitfalls/format.js.map +1 -0
  179. package/dist/tools/pitfalls/graph.js +124 -0
  180. package/dist/tools/pitfalls/graph.js.map +1 -0
  181. package/dist/tools/pitfalls.js +134 -0
  182. package/dist/tools/pitfalls.js.map +1 -0
  183. package/dist/tools/prompts.js +81 -0
  184. package/dist/tools/prompts.js.map +1 -0
  185. package/dist/tools/query/compatibility/closure.js +62 -0
  186. package/dist/tools/query/compatibility/closure.js.map +1 -0
  187. package/dist/tools/query/compatibility/facts.js +28 -0
  188. package/dist/tools/query/compatibility/facts.js.map +1 -0
  189. package/dist/tools/query/compatibility/fetch.js +164 -0
  190. package/dist/tools/query/compatibility/fetch.js.map +1 -0
  191. package/dist/tools/query/compatibility/hard-rules.js +159 -0
  192. package/dist/tools/query/compatibility/hard-rules.js.map +1 -0
  193. package/dist/tools/query/compatibility/index.js +27 -0
  194. package/dist/tools/query/compatibility/index.js.map +1 -0
  195. package/dist/tools/query/compatibility/kernal-zp-rule.js +90 -0
  196. package/dist/tools/query/compatibility/kernal-zp-rule.js.map +1 -0
  197. package/dist/tools/query/compatibility/render.js +106 -0
  198. package/dist/tools/query/compatibility/render.js.map +1 -0
  199. package/dist/tools/query/compatibility/rules.js +337 -0
  200. package/dist/tools/query/compatibility/rules.js.map +1 -0
  201. package/dist/tools/query/compatibility/unit-rules.js +253 -0
  202. package/dist/tools/query/compatibility/unit-rules.js.map +1 -0
  203. package/dist/tools/query/game-design.js +83 -0
  204. package/dist/tools/query/game-design.js.map +1 -0
  205. package/dist/tools/query/lookups.js +220 -0
  206. package/dist/tools/query/lookups.js.map +1 -0
  207. package/dist/tools/query/plan-budget.js +266 -0
  208. package/dist/tools/query/plan-budget.js.map +1 -0
  209. package/dist/tools/query/recipes.js +214 -0
  210. package/dist/tools/query/recipes.js.map +1 -0
  211. package/dist/tools/query/retrieval.js +128 -0
  212. package/dist/tools/query/retrieval.js.map +1 -0
  213. package/dist/tools/query/shared.js +121 -0
  214. package/dist/tools/query/shared.js.map +1 -0
  215. package/dist/tools/query/techniques.js +331 -0
  216. package/dist/tools/query/techniques.js.map +1 -0
  217. package/dist/tools/query/timing.js +106 -0
  218. package/dist/tools/query/timing.js.map +1 -0
  219. package/dist/tools/query/types.js +11 -0
  220. package/dist/tools/query/types.js.map +1 -0
  221. package/dist/tools/query.js +21 -0
  222. package/dist/tools/query.js.map +1 -0
  223. package/dist/tools/resources.js +186 -0
  224. package/dist/tools/resources.js.map +1 -0
  225. package/dist/tools/run-game.js +249 -0
  226. package/dist/tools/run-game.js.map +1 -0
  227. package/dist/tools/selfimprovement.js +367 -0
  228. package/dist/tools/selfimprovement.js.map +1 -0
  229. package/docker-compose.yml +35 -0
  230. package/docs/ARCHITECTURE.md +164 -0
  231. package/docs/CONVENTIONS-archetypes.md +158 -0
  232. package/docs/CONVENTIONS-failures.md +46 -0
  233. package/docs/CONVENTIONS-game-designs.md +75 -0
  234. package/docs/CONVENTIONS-hardware-reference.md +184 -0
  235. package/docs/CONVENTIONS-pitfalls.md +91 -0
  236. package/docs/CONVENTIONS-recipes.md +106 -0
  237. package/docs/CONVENTIONS-techniques.md +309 -0
  238. package/docs/CONVENTIONS-toolchain-reference.md +89 -0
  239. package/docs/ONTOLOGY.md +655 -0
  240. package/docs/art/art-production-reference.md +157 -0
  241. package/docs/art/asset-pipelines.md +586 -0
  242. package/docs/c64-failure-patterns.md +693 -0
  243. package/docs/demo-design/demo-composition.md +349 -0
  244. package/docs/demo-design/demo-design-philosophy.md +320 -0
  245. package/docs/demo-design/intro-cracktro-patterns.md +435 -0
  246. package/docs/figures/ctm-spd-embed-probe.png +0 -0
  247. package/docs/figures/dot-flag-mid-5000000.png +0 -0
  248. package/docs/figures/dot-flag-no-erase-12000000.png +0 -0
  249. package/docs/figures/edges.json +1 -0
  250. package/docs/figures/fig6-architecture.png +0 -0
  251. package/docs/figures/fig7-ontology.png +0 -0
  252. package/docs/figures/screen-dissolve-mid-frame25.png +0 -0
  253. package/docs/figures/screen-dissolve-wipe-frame25.png +0 -0
  254. package/docs/figures/spindle-two-parts-part1.png +0 -0
  255. package/docs/figures/spindle-two-parts-part2.png +0 -0
  256. package/docs/figures/starters/action-puzzle.png +0 -0
  257. package/docs/figures/starters/adventure.png +0 -0
  258. package/docs/figures/starters/beat-em-up.png +0 -0
  259. package/docs/figures/starters/demo.png +0 -0
  260. package/docs/figures/starters/platformer.png +0 -0
  261. package/docs/figures/starters/shmup-vertical.png +0 -0
  262. package/docs/figures/tape-kernal-master-ntsc.png +0 -0
  263. package/docs/figures/tape-kernal-master-pal.png +0 -0
  264. package/docs/figures/tape-turbo-loader-ntsc.png +0 -0
  265. package/docs/figures/tape-turbo-loader-pal.png +0 -0
  266. package/docs/figures/tape-turbo-master-ntsc.png +0 -0
  267. package/docs/figures/tape-turbo-master-pal.png +0 -0
  268. package/docs/figures/tech-tech-pad2-12000000.png +0 -0
  269. package/docs/figures/tech-tech-pad4-12000000.png +0 -0
  270. package/docs/figures/tech-tech-seven-12000000.png +0 -0
  271. package/docs/figures/twister-mid-5000000.png +0 -0
  272. package/docs/figures/twister-straight-12000000.png +0 -0
  273. package/docs/figures/vector-balls-nosort-ntsc.png +0 -0
  274. package/docs/figures/vector-balls-nosort.png +0 -0
  275. package/docs/formats/c64-file-formats.md +1212 -0
  276. package/docs/formats/iec-disk-reference.md +754 -0
  277. package/docs/game-design/c64-game-archetypes.md +273 -0
  278. package/docs/game-design/designs/falling-blocks.md +54 -0
  279. package/docs/game-design/designs/platformer-scaffold.md +48 -0
  280. package/docs/game-design/designs/simple-shmup.md +27 -0
  281. package/docs/game-design/enemy-behaviour-and-difficulty.md +349 -0
  282. package/docs/game-design/game-design-patterns.md +1189 -0
  283. package/docs/game-design/game-structure.md +354 -0
  284. package/docs/game-design/production-planning.md +349 -0
  285. package/docs/game-design/reference-game-sources.md +90 -0
  286. package/docs/hardware/6502-illegal-opcodes.md +1353 -0
  287. package/docs/hardware/6510-cpu-reference.md +2112 -0
  288. package/docs/hardware/c64-memory-map.md +3184 -0
  289. package/docs/hardware/c64-registers-reference.md +996 -0
  290. package/docs/hardware/cia-reference.md +1281 -0
  291. package/docs/hardware/kernal-routines-reference.md +1836 -0
  292. package/docs/hardware/pal-ntsc-reference.md +813 -0
  293. package/docs/hardware/sid-reference.md +1137 -0
  294. package/docs/hardware/vic-ii-reference.md +1714 -0
  295. package/docs/music/music-production-reference.md +403 -0
  296. package/docs/pitfalls/banking.md +1067 -0
  297. package/docs/pitfalls/cia.md +1147 -0
  298. package/docs/pitfalls/cpu.md +874 -0
  299. package/docs/pitfalls/input.md +282 -0
  300. package/docs/pitfalls/kernal-and-io.md +1615 -0
  301. package/docs/pitfalls/loader.md +1191 -0
  302. package/docs/pitfalls/logic.md +94 -0
  303. package/docs/pitfalls/maths.md +187 -0
  304. package/docs/pitfalls/raster-and-badline.md +721 -0
  305. package/docs/pitfalls/region-timing.md +660 -0
  306. package/docs/pitfalls/scroll.md +207 -0
  307. package/docs/pitfalls/sid.md +738 -0
  308. package/docs/pitfalls/sprite.md +979 -0
  309. package/docs/pitfalls/text-mode-render.md +1172 -0
  310. package/docs/recipes/cc65/cartridge-8k.md +398 -0
  311. package/docs/recipes/cc65/hello-world-conio.md +76 -0
  312. package/docs/recipes/cc65/memory-layout.md +312 -0
  313. package/docs/recipes/cc65/screenshots/README.md +14 -0
  314. package/docs/recipes/cc65/screenshots/cartridge-8k-ntsc.png +0 -0
  315. package/docs/recipes/cc65/screenshots/cartridge-8k.png +0 -0
  316. package/docs/recipes/cc65/screenshots/hello-world-conio.png +0 -0
  317. package/docs/recipes/cc65/screenshots/memory-layout-ntsc.png +0 -0
  318. package/docs/recipes/cc65/screenshots/memory-layout.png +0 -0
  319. package/docs/recipes/kickassembler/basic-float-calls.md +578 -0
  320. package/docs/recipes/kickassembler/basic-wedge.md +398 -0
  321. package/docs/recipes/kickassembler/big-font-scroller.md +620 -0
  322. package/docs/recipes/kickassembler/charset-copy-rom-to-ram.md +623 -0
  323. package/docs/recipes/kickassembler/cia-revision-detect.md +366 -0
  324. package/docs/recipes/kickassembler/colour-cycling.md +343 -0
  325. package/docs/recipes/kickassembler/colour-fade.md +303 -0
  326. package/docs/recipes/kickassembler/compare-16bit-signed.md +1007 -0
  327. package/docs/recipes/kickassembler/cracktro-template.md +526 -0
  328. package/docs/recipes/kickassembler/crt-banked.md +276 -0
  329. package/docs/recipes/kickassembler/dos-error-codes.md +466 -0
  330. package/docs/recipes/kickassembler/dot-flag.md +576 -0
  331. package/docs/recipes/kickassembler/drive-job-queue.md +667 -0
  332. package/docs/recipes/kickassembler/drive-via-probe.md +690 -0
  333. package/docs/recipes/kickassembler/dycp-scroller.md +568 -0
  334. package/docs/recipes/kickassembler/dypp-sprite-scroller.md +681 -0
  335. package/docs/recipes/kickassembler/dysp.md +670 -0
  336. package/docs/recipes/kickassembler/easyflash-save.md +800 -0
  337. package/docs/recipes/kickassembler/eight-way-scroll.md +1484 -0
  338. package/docs/recipes/kickassembler/file-io-roundtrip.md +546 -0
  339. package/docs/recipes/kickassembler/fire-effect.md +420 -0
  340. package/docs/recipes/kickassembler/fld.md +414 -0
  341. package/docs/recipes/kickassembler/fli-image.md +336 -0
  342. package/docs/recipes/kickassembler/four-player-read.md +672 -0
  343. package/docs/recipes/kickassembler/headless-verify.md +228 -0
  344. package/docs/recipes/kickassembler/hello-world.md +98 -0
  345. package/docs/recipes/kickassembler/high-score-insert.md +660 -0
  346. package/docs/recipes/kickassembler/hires-plot-line.md +723 -0
  347. package/docs/recipes/kickassembler/irq-chain.md +316 -0
  348. package/docs/recipes/kickassembler/irq-owns-port.md +668 -0
  349. package/docs/recipes/kickassembler/isometric-room.md +1145 -0
  350. package/docs/recipes/kickassembler/light-pen-read.md +926 -0
  351. package/docs/recipes/kickassembler/logic-rate-decoupling.md +670 -0
  352. package/docs/recipes/kickassembler/mci-interlace.md +543 -0
  353. package/docs/recipes/kickassembler/memory-layout.md +277 -0
  354. package/docs/recipes/kickassembler/mouse-1351-read.md +801 -0
  355. package/docs/recipes/kickassembler/nmi-timer-tick.md +562 -0
  356. package/docs/recipes/kickassembler/own-keyscan.md +881 -0
  357. package/docs/recipes/kickassembler/paddle-read.md +751 -0
  358. package/docs/recipes/kickassembler/palette-cells.md +219 -0
  359. package/docs/recipes/kickassembler/pseudo-3d-road.md +930 -0
  360. package/docs/recipes/kickassembler/pwm-digi.md +463 -0
  361. package/docs/recipes/kickassembler/raster-bars.md +264 -0
  362. package/docs/recipes/kickassembler/reu-dma.md +1019 -0
  363. package/docs/recipes/kickassembler/runtime-relocation.md +743 -0
  364. package/docs/recipes/kickassembler/screen-dissolve.md +545 -0
  365. package/docs/recipes/kickassembler/screen-wipe.md +408 -0
  366. package/docs/recipes/kickassembler/screenshots/README.md +72 -0
  367. package/docs/recipes/kickassembler/screenshots/basic-float-calls-ntsc.png +0 -0
  368. package/docs/recipes/kickassembler/screenshots/basic-float-calls.png +0 -0
  369. package/docs/recipes/kickassembler/screenshots/basic-wedge-ntsc.png +0 -0
  370. package/docs/recipes/kickassembler/screenshots/basic-wedge.png +0 -0
  371. package/docs/recipes/kickassembler/screenshots/big-font-scroller-ntsc.png +0 -0
  372. package/docs/recipes/kickassembler/screenshots/big-font-scroller.png +0 -0
  373. package/docs/recipes/kickassembler/screenshots/charset-copy-rom-to-ram-ntsc.png +0 -0
  374. package/docs/recipes/kickassembler/screenshots/charset-copy-rom-to-ram.png +0 -0
  375. package/docs/recipes/kickassembler/screenshots/cia-revision-detect-ntsc.png +0 -0
  376. package/docs/recipes/kickassembler/screenshots/cia-revision-detect.png +0 -0
  377. package/docs/recipes/kickassembler/screenshots/colour-cycling-ntsc.png +0 -0
  378. package/docs/recipes/kickassembler/screenshots/colour-cycling.png +0 -0
  379. package/docs/recipes/kickassembler/screenshots/colour-fade-ntsc.png +0 -0
  380. package/docs/recipes/kickassembler/screenshots/colour-fade.png +0 -0
  381. package/docs/recipes/kickassembler/screenshots/compare-16bit-signed-ntsc.png +0 -0
  382. package/docs/recipes/kickassembler/screenshots/compare-16bit-signed.png +0 -0
  383. package/docs/recipes/kickassembler/screenshots/cracktro-template.png +0 -0
  384. package/docs/recipes/kickassembler/screenshots/crt-banked-ntsc.png +0 -0
  385. package/docs/recipes/kickassembler/screenshots/crt-banked.png +0 -0
  386. package/docs/recipes/kickassembler/screenshots/dos-error-codes-ntsc.png +0 -0
  387. package/docs/recipes/kickassembler/screenshots/dos-error-codes.png +0 -0
  388. package/docs/recipes/kickassembler/screenshots/dot-flag-ntsc.png +0 -0
  389. package/docs/recipes/kickassembler/screenshots/dot-flag.png +0 -0
  390. package/docs/recipes/kickassembler/screenshots/drive-job-queue-ntsc.png +0 -0
  391. package/docs/recipes/kickassembler/screenshots/drive-job-queue.png +0 -0
  392. package/docs/recipes/kickassembler/screenshots/drive-via-probe-ntsc.png +0 -0
  393. package/docs/recipes/kickassembler/screenshots/drive-via-probe.png +0 -0
  394. package/docs/recipes/kickassembler/screenshots/dycp-scroller-ntsc.png +0 -0
  395. package/docs/recipes/kickassembler/screenshots/dycp-scroller.png +0 -0
  396. package/docs/recipes/kickassembler/screenshots/dypp-sprite-scroller-ntsc.png +0 -0
  397. package/docs/recipes/kickassembler/screenshots/dypp-sprite-scroller.png +0 -0
  398. package/docs/recipes/kickassembler/screenshots/dysp-ntsc.png +0 -0
  399. package/docs/recipes/kickassembler/screenshots/dysp.png +0 -0
  400. package/docs/recipes/kickassembler/screenshots/easyflash-save-ntsc-run2.png +0 -0
  401. package/docs/recipes/kickassembler/screenshots/easyflash-save-ntsc.png +0 -0
  402. package/docs/recipes/kickassembler/screenshots/easyflash-save-run2.png +0 -0
  403. package/docs/recipes/kickassembler/screenshots/easyflash-save.png +0 -0
  404. package/docs/recipes/kickassembler/screenshots/eight-way-scroll-ntsc.png +0 -0
  405. package/docs/recipes/kickassembler/screenshots/eight-way-scroll.png +0 -0
  406. package/docs/recipes/kickassembler/screenshots/file-io-roundtrip-ntsc.png +0 -0
  407. package/docs/recipes/kickassembler/screenshots/file-io-roundtrip.png +0 -0
  408. package/docs/recipes/kickassembler/screenshots/fire-effect-ntsc.png +0 -0
  409. package/docs/recipes/kickassembler/screenshots/fire-effect.png +0 -0
  410. package/docs/recipes/kickassembler/screenshots/fld-ntsc.png +0 -0
  411. package/docs/recipes/kickassembler/screenshots/fld.png +0 -0
  412. package/docs/recipes/kickassembler/screenshots/fli-image.png +0 -0
  413. package/docs/recipes/kickassembler/screenshots/four-player-read-ntsc.png +0 -0
  414. package/docs/recipes/kickassembler/screenshots/four-player-read.png +0 -0
  415. package/docs/recipes/kickassembler/screenshots/headless-verify-ntsc.png +0 -0
  416. package/docs/recipes/kickassembler/screenshots/headless-verify.png +0 -0
  417. package/docs/recipes/kickassembler/screenshots/hello-world.png +0 -0
  418. package/docs/recipes/kickassembler/screenshots/high-score-insert-ntsc.png +0 -0
  419. package/docs/recipes/kickassembler/screenshots/high-score-insert.png +0 -0
  420. package/docs/recipes/kickassembler/screenshots/hires-plot-line-ntsc.png +0 -0
  421. package/docs/recipes/kickassembler/screenshots/hires-plot-line.png +0 -0
  422. package/docs/recipes/kickassembler/screenshots/irq-chain-ntsc.png +0 -0
  423. package/docs/recipes/kickassembler/screenshots/irq-chain.png +0 -0
  424. package/docs/recipes/kickassembler/screenshots/irq-owns-port-ntsc.png +0 -0
  425. package/docs/recipes/kickassembler/screenshots/irq-owns-port.png +0 -0
  426. package/docs/recipes/kickassembler/screenshots/isometric-room-ntsc.png +0 -0
  427. package/docs/recipes/kickassembler/screenshots/isometric-room.png +0 -0
  428. package/docs/recipes/kickassembler/screenshots/light-pen-read-ntsc.png +0 -0
  429. package/docs/recipes/kickassembler/screenshots/light-pen-read.png +0 -0
  430. package/docs/recipes/kickassembler/screenshots/logic-rate-decoupling-ntsc.png +0 -0
  431. package/docs/recipes/kickassembler/screenshots/logic-rate-decoupling.png +0 -0
  432. package/docs/recipes/kickassembler/screenshots/mci-interlace-average.png +0 -0
  433. package/docs/recipes/kickassembler/screenshots/mci-interlace-frame-b.png +0 -0
  434. package/docs/recipes/kickassembler/screenshots/mci-interlace-ntsc.png +0 -0
  435. package/docs/recipes/kickassembler/screenshots/mci-interlace.png +0 -0
  436. package/docs/recipes/kickassembler/screenshots/memory-layout-ntsc.png +0 -0
  437. package/docs/recipes/kickassembler/screenshots/memory-layout.png +0 -0
  438. package/docs/recipes/kickassembler/screenshots/mouse-1351-read-ntsc.png +0 -0
  439. package/docs/recipes/kickassembler/screenshots/mouse-1351-read.png +0 -0
  440. package/docs/recipes/kickassembler/screenshots/nmi-timer-tick-ntsc.png +0 -0
  441. package/docs/recipes/kickassembler/screenshots/nmi-timer-tick.png +0 -0
  442. package/docs/recipes/kickassembler/screenshots/own-keyscan-ntsc.png +0 -0
  443. package/docs/recipes/kickassembler/screenshots/own-keyscan.png +0 -0
  444. package/docs/recipes/kickassembler/screenshots/paddle-read-ntsc.png +0 -0
  445. package/docs/recipes/kickassembler/screenshots/paddle-read.png +0 -0
  446. package/docs/recipes/kickassembler/screenshots/palette-cells-ntsc.png +0 -0
  447. package/docs/recipes/kickassembler/screenshots/palette-cells.png +0 -0
  448. package/docs/recipes/kickassembler/screenshots/pseudo-3d-road-ntsc.png +0 -0
  449. package/docs/recipes/kickassembler/screenshots/pseudo-3d-road.png +0 -0
  450. package/docs/recipes/kickassembler/screenshots/pwm-digi-ntsc.png +0 -0
  451. package/docs/recipes/kickassembler/screenshots/pwm-digi.png +0 -0
  452. package/docs/recipes/kickassembler/screenshots/raster-bars.png +0 -0
  453. package/docs/recipes/kickassembler/screenshots/reu-dma-ntsc.png +0 -0
  454. package/docs/recipes/kickassembler/screenshots/reu-dma.png +0 -0
  455. package/docs/recipes/kickassembler/screenshots/runtime-relocation-ntsc.png +0 -0
  456. package/docs/recipes/kickassembler/screenshots/runtime-relocation.png +0 -0
  457. package/docs/recipes/kickassembler/screenshots/screen-dissolve-ntsc.png +0 -0
  458. package/docs/recipes/kickassembler/screenshots/screen-dissolve.png +0 -0
  459. package/docs/recipes/kickassembler/screenshots/screen-wipe-ntsc.png +0 -0
  460. package/docs/recipes/kickassembler/screenshots/screen-wipe.png +0 -0
  461. package/docs/recipes/kickassembler/screenshots/scroll-panel-split-ntsc.png +0 -0
  462. package/docs/recipes/kickassembler/screenshots/scroll-panel-split.png +0 -0
  463. package/docs/recipes/kickassembler/screenshots/sfx-in-player-ntsc.png +0 -0
  464. package/docs/recipes/kickassembler/screenshots/sfx-in-player.png +0 -0
  465. package/docs/recipes/kickassembler/screenshots/shadebobs-ntsc.png +0 -0
  466. package/docs/recipes/kickassembler/screenshots/shadebobs.png +0 -0
  467. package/docs/recipes/kickassembler/screenshots/sideborder-open.png +0 -0
  468. package/docs/recipes/kickassembler/screenshots/sine-scroller.png +0 -0
  469. package/docs/recipes/kickassembler/screenshots/sine-table-runtime-ntsc.png +0 -0
  470. package/docs/recipes/kickassembler/screenshots/sine-table-runtime.png +0 -0
  471. package/docs/recipes/kickassembler/screenshots/software-sprite-preshifted-ntsc.png +0 -0
  472. package/docs/recipes/kickassembler/screenshots/software-sprite-preshifted.png +0 -0
  473. package/docs/recipes/kickassembler/screenshots/speedcode-generator-ntsc.png +0 -0
  474. package/docs/recipes/kickassembler/screenshots/speedcode-generator.png +0 -0
  475. package/docs/recipes/kickassembler/screenshots/sprite-border-scroller-ntsc.png +0 -0
  476. package/docs/recipes/kickassembler/screenshots/sprite-border-scroller.png +0 -0
  477. package/docs/recipes/kickassembler/screenshots/sprite-cache-flip-ntsc.png +0 -0
  478. package/docs/recipes/kickassembler/screenshots/sprite-cache-flip.png +0 -0
  479. package/docs/recipes/kickassembler/screenshots/sprite-multiplex-24.png +0 -0
  480. package/docs/recipes/kickassembler/screenshots/sprite-multiplex-game-ntsc.png +0 -0
  481. package/docs/recipes/kickassembler/screenshots/sprite-multiplex-game.png +0 -0
  482. package/docs/recipes/kickassembler/screenshots/sprite-priority-classes-ntsc.png +0 -0
  483. package/docs/recipes/kickassembler/screenshots/sprite-priority-classes.png +0 -0
  484. package/docs/recipes/kickassembler/screenshots/sprite-sine-chain-ntsc.png +0 -0
  485. package/docs/recipes/kickassembler/screenshots/sprite-sine-chain.png +0 -0
  486. package/docs/recipes/kickassembler/screenshots/sprite-stretcher-ntsc.png +0 -0
  487. package/docs/recipes/kickassembler/screenshots/sprite-stretcher.png +0 -0
  488. package/docs/recipes/kickassembler/screenshots/sprites-only-screen-ntsc.png +0 -0
  489. package/docs/recipes/kickassembler/screenshots/sprites-only-screen.png +0 -0
  490. package/docs/recipes/kickassembler/screenshots/sqrt-atan2-ntsc.png +0 -0
  491. package/docs/recipes/kickassembler/screenshots/sqrt-atan2.png +0 -0
  492. package/docs/recipes/kickassembler/screenshots/stable-raster-irq-control.png +0 -0
  493. package/docs/recipes/kickassembler/screenshots/stable-raster-irq.png +0 -0
  494. package/docs/recipes/kickassembler/screenshots/tech-tech-ntsc.png +0 -0
  495. package/docs/recipes/kickassembler/screenshots/tech-tech.png +0 -0
  496. package/docs/recipes/kickassembler/screenshots/tod-alarm-ntsc.png +0 -0
  497. package/docs/recipes/kickassembler/screenshots/tod-alarm.png +0 -0
  498. package/docs/recipes/kickassembler/screenshots/topbottom-border-open.png +0 -0
  499. package/docs/recipes/kickassembler/screenshots/twister-ntsc.png +0 -0
  500. package/docs/recipes/kickassembler/screenshots/twister.png +0 -0
  501. package/docs/recipes/kickassembler/screenshots/unit-test-driver-ntsc.png +0 -0
  502. package/docs/recipes/kickassembler/screenshots/unit-test-driver.png +0 -0
  503. package/docs/recipes/kickassembler/screenshots/vector-balls-ntsc.png +0 -0
  504. package/docs/recipes/kickassembler/screenshots/vector-balls.png +0 -0
  505. package/docs/recipes/kickassembler/screenshots/wireframe-ships-ntsc.png +0 -0
  506. package/docs/recipes/kickassembler/screenshots/wireframe-ships.png +0 -0
  507. package/docs/recipes/kickassembler/scroll-panel-split.md +381 -0
  508. package/docs/recipes/kickassembler/sfx-in-player.md +907 -0
  509. package/docs/recipes/kickassembler/shadebobs.md +522 -0
  510. package/docs/recipes/kickassembler/sideborder-open.md +338 -0
  511. package/docs/recipes/kickassembler/sine-scroller.md +321 -0
  512. package/docs/recipes/kickassembler/sine-table-runtime.md +815 -0
  513. package/docs/recipes/kickassembler/software-sprite-preshifted.md +725 -0
  514. package/docs/recipes/kickassembler/speedcode-generator.md +606 -0
  515. package/docs/recipes/kickassembler/sprite-border-scroller.md +696 -0
  516. package/docs/recipes/kickassembler/sprite-cache-flip.md +1071 -0
  517. package/docs/recipes/kickassembler/sprite-multiplex-24.md +326 -0
  518. package/docs/recipes/kickassembler/sprite-multiplex-game.md +986 -0
  519. package/docs/recipes/kickassembler/sprite-priority-classes.md +463 -0
  520. package/docs/recipes/kickassembler/sprite-sine-chain.md +338 -0
  521. package/docs/recipes/kickassembler/sprite-stretcher.md +501 -0
  522. package/docs/recipes/kickassembler/sprites-only-screen.md +550 -0
  523. package/docs/recipes/kickassembler/sqrt-atan2.md +1014 -0
  524. package/docs/recipes/kickassembler/stable-raster-irq.md +360 -0
  525. package/docs/recipes/kickassembler/tape-turbo-loader.md +875 -0
  526. package/docs/recipes/kickassembler/tech-tech.md +679 -0
  527. package/docs/recipes/kickassembler/tod-alarm.md +754 -0
  528. package/docs/recipes/kickassembler/topbottom-border-open.md +407 -0
  529. package/docs/recipes/kickassembler/twister.md +518 -0
  530. package/docs/recipes/kickassembler/unit-test-driver.md +314 -0
  531. package/docs/recipes/kickassembler/vector-balls.md +545 -0
  532. package/docs/recipes/kickassembler/wireframe-ships.md +2324 -0
  533. package/docs/recipes/oscar64/actor-activation-window.md +807 -0
  534. package/docs/recipes/oscar64/adventure-engine.md +1094 -0
  535. package/docs/recipes/oscar64/attract-replay.md +465 -0
  536. package/docs/recipes/oscar64/beat-em-up-lanes.md +563 -0
  537. package/docs/recipes/oscar64/bfs-distance-map.md +723 -0
  538. package/docs/recipes/oscar64/bitmap-koala-viewer.md +355 -0
  539. package/docs/recipes/oscar64/car-contact.md +950 -0
  540. package/docs/recipes/oscar64/cave-scan.md +609 -0
  541. package/docs/recipes/oscar64/char-bullets.md +477 -0
  542. package/docs/recipes/oscar64/charset-animation.md +383 -0
  543. package/docs/recipes/oscar64/charset-parallax.md +401 -0
  544. package/docs/recipes/oscar64/destructible-terrain.md +1099 -0
  545. package/docs/recipes/oscar64/difficulty-tables.md +654 -0
  546. package/docs/recipes/oscar64/dig-and-guards.md +975 -0
  547. package/docs/recipes/oscar64/directory-reader.md +535 -0
  548. package/docs/recipes/oscar64/divide-check.md +581 -0
  549. package/docs/recipes/oscar64/double-buffer-nomirror.md +205 -0
  550. package/docs/recipes/oscar64/double-buffer.md +255 -0
  551. package/docs/recipes/oscar64/falling-blocks.md +874 -0
  552. package/docs/recipes/oscar64/fixed-point-jump-velocity.md +289 -0
  553. package/docs/recipes/oscar64/fixed-point-jump.md +210 -0
  554. package/docs/recipes/oscar64/flip-screen-rooms.md +793 -0
  555. package/docs/recipes/oscar64/frame-sync-loop-overrun.md +214 -0
  556. package/docs/recipes/oscar64/frame-sync-loop.md +254 -0
  557. package/docs/recipes/oscar64/game-tree-search.md +743 -0
  558. package/docs/recipes/oscar64/ghost-targeting.md +867 -0
  559. package/docs/recipes/oscar64/headless-verify.md +345 -0
  560. package/docs/recipes/oscar64/hello-world.md +83 -0
  561. package/docs/recipes/oscar64/high-score-persist.md +772 -0
  562. package/docs/recipes/oscar64/iffl-kernal-skip.md +421 -0
  563. package/docs/recipes/oscar64/joystick-input.md +358 -0
  564. package/docs/recipes/oscar64/lane-pursuit.md +1028 -0
  565. package/docs/recipes/oscar64/level-rle-decoder.md +620 -0
  566. package/docs/recipes/oscar64/lfsr-random-seed2.md +338 -0
  567. package/docs/recipes/oscar64/lfsr-random.md +403 -0
  568. package/docs/recipes/oscar64/load-asset-runtime.md +492 -0
  569. package/docs/recipes/oscar64/memory-layout.md +232 -0
  570. package/docs/recipes/oscar64/mixed-fighters.md +781 -0
  571. package/docs/recipes/oscar64/multi-sprite-object.md +533 -0
  572. package/docs/recipes/oscar64/nav-area-pathfinding.md +881 -0
  573. package/docs/recipes/oscar64/object-pool.md +572 -0
  574. package/docs/recipes/oscar64/pal-ntsc-detect.md +257 -0
  575. package/docs/recipes/oscar64/password-state.md +532 -0
  576. package/docs/recipes/oscar64/per-frame-hitbox.md +651 -0
  577. package/docs/recipes/oscar64/petscii-screen-codes.md +428 -0
  578. package/docs/recipes/oscar64/platformer-scaffold.md +1467 -0
  579. package/docs/recipes/oscar64/print-number.md +367 -0
  580. package/docs/recipes/oscar64/raster-bars.md +239 -0
  581. package/docs/recipes/oscar64/raster-profile-bars.md +404 -0
  582. package/docs/recipes/oscar64/rel-side-sectors.md +391 -0
  583. package/docs/recipes/oscar64/relative-file-records.md +378 -0
  584. package/docs/recipes/oscar64/save-load-seq-file.md +365 -0
  585. package/docs/recipes/oscar64/screenshots/README.md +99 -0
  586. package/docs/recipes/oscar64/screenshots/actor-activation-window-ntsc.png +0 -0
  587. package/docs/recipes/oscar64/screenshots/actor-activation-window.png +0 -0
  588. package/docs/recipes/oscar64/screenshots/adventure-engine-ntsc.png +0 -0
  589. package/docs/recipes/oscar64/screenshots/adventure-engine.png +0 -0
  590. package/docs/recipes/oscar64/screenshots/attract-replay-ntsc.png +0 -0
  591. package/docs/recipes/oscar64/screenshots/attract-replay.png +0 -0
  592. package/docs/recipes/oscar64/screenshots/beat-em-up-lanes-ntsc.png +0 -0
  593. package/docs/recipes/oscar64/screenshots/beat-em-up-lanes.png +0 -0
  594. package/docs/recipes/oscar64/screenshots/bfs-distance-map-ntsc.png +0 -0
  595. package/docs/recipes/oscar64/screenshots/bfs-distance-map.png +0 -0
  596. package/docs/recipes/oscar64/screenshots/bitmap-koala-viewer.png +0 -0
  597. package/docs/recipes/oscar64/screenshots/car-contact-ntsc.png +0 -0
  598. package/docs/recipes/oscar64/screenshots/car-contact.png +0 -0
  599. package/docs/recipes/oscar64/screenshots/cave-scan-ntsc.png +0 -0
  600. package/docs/recipes/oscar64/screenshots/cave-scan.png +0 -0
  601. package/docs/recipes/oscar64/screenshots/char-bullets-ntsc.png +0 -0
  602. package/docs/recipes/oscar64/screenshots/char-bullets.png +0 -0
  603. package/docs/recipes/oscar64/screenshots/charset-animation-ntsc.png +0 -0
  604. package/docs/recipes/oscar64/screenshots/charset-animation.png +0 -0
  605. package/docs/recipes/oscar64/screenshots/charset-parallax-ntsc.png +0 -0
  606. package/docs/recipes/oscar64/screenshots/charset-parallax.png +0 -0
  607. package/docs/recipes/oscar64/screenshots/destructible-terrain-ntsc.png +0 -0
  608. package/docs/recipes/oscar64/screenshots/destructible-terrain.png +0 -0
  609. package/docs/recipes/oscar64/screenshots/difficulty-tables-ntsc.png +0 -0
  610. package/docs/recipes/oscar64/screenshots/difficulty-tables.png +0 -0
  611. package/docs/recipes/oscar64/screenshots/dig-and-guards-ntsc.png +0 -0
  612. package/docs/recipes/oscar64/screenshots/dig-and-guards.png +0 -0
  613. package/docs/recipes/oscar64/screenshots/directory-reader-ntsc.png +0 -0
  614. package/docs/recipes/oscar64/screenshots/directory-reader.png +0 -0
  615. package/docs/recipes/oscar64/screenshots/divide-check-ntsc.png +0 -0
  616. package/docs/recipes/oscar64/screenshots/divide-check.png +0 -0
  617. package/docs/recipes/oscar64/screenshots/double-buffer-nomirror.png +0 -0
  618. package/docs/recipes/oscar64/screenshots/double-buffer-ntsc.png +0 -0
  619. package/docs/recipes/oscar64/screenshots/double-buffer.png +0 -0
  620. package/docs/recipes/oscar64/screenshots/falling-blocks-ntsc.png +0 -0
  621. package/docs/recipes/oscar64/screenshots/falling-blocks.png +0 -0
  622. package/docs/recipes/oscar64/screenshots/fixed-point-jump-ntsc.png +0 -0
  623. package/docs/recipes/oscar64/screenshots/fixed-point-jump-velocity-ntsc.png +0 -0
  624. package/docs/recipes/oscar64/screenshots/fixed-point-jump-velocity.png +0 -0
  625. package/docs/recipes/oscar64/screenshots/fixed-point-jump.png +0 -0
  626. package/docs/recipes/oscar64/screenshots/flip-screen-rooms-ntsc.png +0 -0
  627. package/docs/recipes/oscar64/screenshots/flip-screen-rooms.png +0 -0
  628. package/docs/recipes/oscar64/screenshots/frame-sync-loop-ntsc.png +0 -0
  629. package/docs/recipes/oscar64/screenshots/frame-sync-loop-overrun.png +0 -0
  630. package/docs/recipes/oscar64/screenshots/frame-sync-loop.png +0 -0
  631. package/docs/recipes/oscar64/screenshots/game-tree-search-ntsc.png +0 -0
  632. package/docs/recipes/oscar64/screenshots/game-tree-search.png +0 -0
  633. package/docs/recipes/oscar64/screenshots/ghost-targeting-ntsc.png +0 -0
  634. package/docs/recipes/oscar64/screenshots/ghost-targeting.png +0 -0
  635. package/docs/recipes/oscar64/screenshots/headless-verify-ntsc.png +0 -0
  636. package/docs/recipes/oscar64/screenshots/headless-verify.png +0 -0
  637. package/docs/recipes/oscar64/screenshots/hello-world.png +0 -0
  638. package/docs/recipes/oscar64/screenshots/high-score-persist-ntsc.png +0 -0
  639. package/docs/recipes/oscar64/screenshots/high-score-persist.png +0 -0
  640. package/docs/recipes/oscar64/screenshots/iffl-kernal-skip-ntsc.png +0 -0
  641. package/docs/recipes/oscar64/screenshots/iffl-kernal-skip.png +0 -0
  642. package/docs/recipes/oscar64/screenshots/joystick-input-ntsc.png +0 -0
  643. package/docs/recipes/oscar64/screenshots/joystick-input.png +0 -0
  644. package/docs/recipes/oscar64/screenshots/lane-pursuit-ntsc.png +0 -0
  645. package/docs/recipes/oscar64/screenshots/lane-pursuit.png +0 -0
  646. package/docs/recipes/oscar64/screenshots/level-rle-decoder-ntsc.png +0 -0
  647. package/docs/recipes/oscar64/screenshots/level-rle-decoder.png +0 -0
  648. package/docs/recipes/oscar64/screenshots/lfsr-random-ntsc.png +0 -0
  649. package/docs/recipes/oscar64/screenshots/lfsr-random-seed2.png +0 -0
  650. package/docs/recipes/oscar64/screenshots/lfsr-random.png +0 -0
  651. package/docs/recipes/oscar64/screenshots/load-asset-runtime-ntsc.png +0 -0
  652. package/docs/recipes/oscar64/screenshots/load-asset-runtime.png +0 -0
  653. package/docs/recipes/oscar64/screenshots/memory-layout-ntsc.png +0 -0
  654. package/docs/recipes/oscar64/screenshots/memory-layout.png +0 -0
  655. package/docs/recipes/oscar64/screenshots/mixed-fighters-ntsc.png +0 -0
  656. package/docs/recipes/oscar64/screenshots/mixed-fighters.png +0 -0
  657. package/docs/recipes/oscar64/screenshots/multi-sprite-object-ntsc.png +0 -0
  658. package/docs/recipes/oscar64/screenshots/multi-sprite-object.png +0 -0
  659. package/docs/recipes/oscar64/screenshots/nav-area-pathfinding-ntsc.png +0 -0
  660. package/docs/recipes/oscar64/screenshots/nav-area-pathfinding.png +0 -0
  661. package/docs/recipes/oscar64/screenshots/object-pool-ntsc.png +0 -0
  662. package/docs/recipes/oscar64/screenshots/object-pool.png +0 -0
  663. package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-ntsc.png +0 -0
  664. package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-oldntsc.png +0 -0
  665. package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-pal.png +0 -0
  666. package/docs/recipes/oscar64/screenshots/password-state-ntsc.png +0 -0
  667. package/docs/recipes/oscar64/screenshots/password-state.png +0 -0
  668. package/docs/recipes/oscar64/screenshots/per-frame-hitbox-ntsc.png +0 -0
  669. package/docs/recipes/oscar64/screenshots/per-frame-hitbox.png +0 -0
  670. package/docs/recipes/oscar64/screenshots/petscii-screen-codes-ntsc.png +0 -0
  671. package/docs/recipes/oscar64/screenshots/petscii-screen-codes.png +0 -0
  672. package/docs/recipes/oscar64/screenshots/platformer-scaffold-d64-ntsc.png +0 -0
  673. package/docs/recipes/oscar64/screenshots/platformer-scaffold-d64.png +0 -0
  674. package/docs/recipes/oscar64/screenshots/platformer-scaffold-ntsc.png +0 -0
  675. package/docs/recipes/oscar64/screenshots/platformer-scaffold.png +0 -0
  676. package/docs/recipes/oscar64/screenshots/print-number-ntsc.png +0 -0
  677. package/docs/recipes/oscar64/screenshots/print-number.png +0 -0
  678. package/docs/recipes/oscar64/screenshots/raster-bars.png +0 -0
  679. package/docs/recipes/oscar64/screenshots/raster-profile-bars-ntsc.png +0 -0
  680. package/docs/recipes/oscar64/screenshots/raster-profile-bars.png +0 -0
  681. package/docs/recipes/oscar64/screenshots/rel-side-sectors-ntsc.png +0 -0
  682. package/docs/recipes/oscar64/screenshots/rel-side-sectors.png +0 -0
  683. package/docs/recipes/oscar64/screenshots/relative-file-records-ntsc.png +0 -0
  684. package/docs/recipes/oscar64/screenshots/relative-file-records.png +0 -0
  685. package/docs/recipes/oscar64/screenshots/save-load-seq-file-ntsc.png +0 -0
  686. package/docs/recipes/oscar64/screenshots/save-load-seq-file.png +0 -0
  687. package/docs/recipes/oscar64/screenshots/seeded-level-fill-ntsc.png +0 -0
  688. package/docs/recipes/oscar64/screenshots/seeded-level-fill.png +0 -0
  689. package/docs/recipes/oscar64/screenshots/sfx-engine-ntsc.png +0 -0
  690. package/docs/recipes/oscar64/screenshots/sfx-engine.png +0 -0
  691. package/docs/recipes/oscar64/screenshots/sid-music-player.png +0 -0
  692. package/docs/recipes/oscar64/screenshots/simple-shmup.png +0 -0
  693. package/docs/recipes/oscar64/screenshots/slope-collision-ntsc.png +0 -0
  694. package/docs/recipes/oscar64/screenshots/slope-collision.png +0 -0
  695. package/docs/recipes/oscar64/screenshots/soft-scroll-h.png +0 -0
  696. package/docs/recipes/oscar64/screenshots/sprite-animation-table-ntsc.png +0 -0
  697. package/docs/recipes/oscar64/screenshots/sprite-animation-table.png +0 -0
  698. package/docs/recipes/oscar64/screenshots/sprite-multiplex-8.png +0 -0
  699. package/docs/recipes/oscar64/screenshots/stable-raster-irq.png +0 -0
  700. package/docs/recipes/oscar64/screenshots/text-input-ntsc.png +0 -0
  701. package/docs/recipes/oscar64/screenshots/text-input.png +0 -0
  702. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-gameover.png +0 -0
  703. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-notrail-control.png +0 -0
  704. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-ntsc.png +0 -0
  705. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-ungated-control.png +0 -0
  706. package/docs/recipes/oscar64/screenshots/text-overlay-playfield.png +0 -0
  707. package/docs/recipes/oscar64/screenshots/text-window-menu-ntsc.png +0 -0
  708. package/docs/recipes/oscar64/screenshots/text-window-menu.png +0 -0
  709. package/docs/recipes/oscar64/screenshots/tile-grid-collision-ntsc.png +0 -0
  710. package/docs/recipes/oscar64/screenshots/tile-grid-collision.png +0 -0
  711. package/docs/recipes/oscar64/screenshots/tile-map-render-ntsc.png +0 -0
  712. package/docs/recipes/oscar64/screenshots/tile-map-render.png +0 -0
  713. package/docs/recipes/oscar64/screenshots/two-player-ntsc.png +0 -0
  714. package/docs/recipes/oscar64/screenshots/two-player.png +0 -0
  715. package/docs/recipes/oscar64/screenshots/two-word-parser-ntsc.png +0 -0
  716. package/docs/recipes/oscar64/screenshots/two-word-parser.png +0 -0
  717. package/docs/recipes/oscar64/screenshots/vehicle-control-ntsc.png +0 -0
  718. package/docs/recipes/oscar64/screenshots/vehicle-control.png +0 -0
  719. package/docs/recipes/oscar64/screenshots/wave-director-ntsc.png +0 -0
  720. package/docs/recipes/oscar64/screenshots/wave-director.png +0 -0
  721. package/docs/recipes/oscar64/seeded-level-fill.md +364 -0
  722. package/docs/recipes/oscar64/sfx-engine.md +514 -0
  723. package/docs/recipes/oscar64/sid-music-player.md +441 -0
  724. package/docs/recipes/oscar64/simple-shmup.md +1000 -0
  725. package/docs/recipes/oscar64/slope-collision.md +610 -0
  726. package/docs/recipes/oscar64/soft-scroll-h.md +261 -0
  727. package/docs/recipes/oscar64/sprite-animation-table.md +671 -0
  728. package/docs/recipes/oscar64/sprite-multiplex-8.md +314 -0
  729. package/docs/recipes/oscar64/stable-raster-irq.md +236 -0
  730. package/docs/recipes/oscar64/text-input.md +274 -0
  731. package/docs/recipes/oscar64/text-overlay-playfield.md +617 -0
  732. package/docs/recipes/oscar64/text-window-menu.md +551 -0
  733. package/docs/recipes/oscar64/tile-grid-collision.md +563 -0
  734. package/docs/recipes/oscar64/tile-map-render.md +395 -0
  735. package/docs/recipes/oscar64/two-player.md +528 -0
  736. package/docs/recipes/oscar64/two-word-parser.md +510 -0
  737. package/docs/recipes/oscar64/vehicle-control.md +771 -0
  738. package/docs/recipes/oscar64/wave-director.md +787 -0
  739. package/docs/recipes/runs.json +1606 -0
  740. package/docs/runtime/sim6502-reference.md +466 -0
  741. package/docs/runtime/vice-mcp-reference.md +351 -0
  742. package/docs/runtime/vice-reference.md +1393 -0
  743. package/docs/techniques/bitmap-modes.md +685 -0
  744. package/docs/techniques/cpu-cycle-tricks.md +1570 -0
  745. package/docs/techniques/effects-vector-3d.md +1431 -0
  746. package/docs/techniques/file-io.md +1427 -0
  747. package/docs/techniques/input.md +1072 -0
  748. package/docs/techniques/loaders-packers.md +768 -0
  749. package/docs/techniques/logic.md +3091 -0
  750. package/docs/techniques/maths.md +1524 -0
  751. package/docs/techniques/memory-banking.md +1686 -0
  752. package/docs/techniques/music-sid.md +1144 -0
  753. package/docs/techniques/raster.md +1543 -0
  754. package/docs/techniques/scroll.md +1292 -0
  755. package/docs/techniques/sprite.md +2566 -0
  756. package/docs/techniques/text-mode-render.md +717 -0
  757. package/docs/techniques/text.md +1095 -0
  758. package/docs/techniques/transitions.md +405 -0
  759. package/docs/toolchains/cartconv-reference.md +262 -0
  760. package/docs/toolchains/cc1541-reference.md +316 -0
  761. package/docs/toolchains/cc65-reference.md +667 -0
  762. package/docs/toolchains/error-sources/cc65/README.md +1 -0
  763. package/docs/toolchains/error-sources/cc65/missing-setcpu.s +4 -0
  764. package/docs/toolchains/error-sources/cc65/range-error.s +4 -0
  765. package/docs/toolchains/error-sources/cc65/segment-overflow.c +6 -0
  766. package/docs/toolchains/error-sources/cc65/unresolved-external.c +6 -0
  767. package/docs/toolchains/error-sources/kickassembler/README.md +1 -0
  768. package/docs/toolchains/error-sources/kickassembler/branch-out-of-range.asm +4 -0
  769. package/docs/toolchains/error-sources/kickassembler/failed-assert.asm +3 -0
  770. package/docs/toolchains/error-sources/kickassembler/flat-lib.asm +4 -0
  771. package/docs/toolchains/error-sources/kickassembler/import-source-no-namespace.asm +5 -0
  772. package/docs/toolchains/error-sources/kickassembler/macro-without-parentheses.asm +6 -0
  773. package/docs/toolchains/error-sources/kickassembler/memory-block-overlap.asm +4 -0
  774. package/docs/toolchains/error-sources/kickassembler/symbol-clash-lib.asm +5 -0
  775. package/docs/toolchains/error-sources/kickassembler/symbol-clash-main.asm +6 -0
  776. package/docs/toolchains/error-sources/kickassembler/unknown-symbol.asm +4 -0
  777. package/docs/toolchains/error-sources/oscar64/README.md +1 -0
  778. package/docs/toolchains/error-sources/oscar64/asm-addressing-mode.c +7 -0
  779. package/docs/toolchains/error-sources/oscar64/region-overflow.c +6 -0
  780. package/docs/toolchains/error-sources/oscar64/undefined-extern-var.c +5 -0
  781. package/docs/toolchains/error-sources/oscar64/undefined-extern.c +6 -0
  782. package/docs/toolchains/error-sources/oscar64/unknown-vic-field.c +6 -0
  783. package/docs/toolchains/error-sources/oscar64/void-main.c +3 -0
  784. package/docs/toolchains/kickassembler-reference.md +1020 -0
  785. package/docs/toolchains/memory-layout-planning.md +362 -0
  786. package/docs/toolchains/oscar64-headers-reference.md +583 -0
  787. package/docs/toolchains/oscar64-reference.md +892 -0
  788. package/docs/toolchains/petcat-reference.md +290 -0
  789. package/docs/toolchains/png2prg.md +188 -0
  790. package/docs/toolchains/release-disk.md +314 -0
  791. package/docs/toolchains/sidreloc.md +236 -0
  792. package/docs/toolchains/spindle-reference.md +487 -0
  793. package/docs/toolchains/tape-mastering.md +592 -0
  794. package/docs/toolchains/unit-testing-6502.md +281 -0
  795. package/docs/workflow/agent-harness.md +478 -0
  796. package/package.json +105 -0
  797. package/templates/_harness/CLAUDE.md.template +91 -0
  798. package/templates/_harness/PLAN.md.template +72 -0
  799. package/templates/_harness/check.py +442 -0
  800. package/templates/_harness/claude/settings.json +17 -0
  801. package/templates/_harness/gen-asm-header.py +96 -0
  802. package/templates/_harness/harness.mk +273 -0
  803. package/templates/_harness/hooks/plan-gate.py +185 -0
  804. package/templates/_harness/meter/frame_meter.asm +311 -0
  805. package/templates/_harness/meter/frame_meter.c +155 -0
  806. package/templates/_harness/meter/frame_meter.h +80 -0
  807. package/templates/_harness/zp-used.py +104 -0
  808. package/templates/action-puzzle/.claude/settings.json +17 -0
  809. package/templates/action-puzzle/.mcp.json +10 -0
  810. package/templates/action-puzzle/CLAUDE.md +120 -0
  811. package/templates/action-puzzle/Makefile +125 -0
  812. package/templates/action-puzzle/PLAN.md +388 -0
  813. package/templates/action-puzzle/README.md +240 -0
  814. package/templates/action-puzzle/expect.json +25 -0
  815. package/templates/action-puzzle/src/cave.c +280 -0
  816. package/templates/action-puzzle/src/cave.h +80 -0
  817. package/templates/action-puzzle/src/gen_autopilot.h +20 -0
  818. package/templates/action-puzzle/src/gen_caves.h +59 -0
  819. package/templates/action-puzzle/src/gen_notes.h +16 -0
  820. package/templates/action-puzzle/src/hiscore.c +152 -0
  821. package/templates/action-puzzle/src/hiscore.h +41 -0
  822. package/templates/action-puzzle/src/level.c +64 -0
  823. package/templates/action-puzzle/src/level.h +24 -0
  824. package/templates/action-puzzle/src/main.c +599 -0
  825. package/templates/action-puzzle/src/render.c +239 -0
  826. package/templates/action-puzzle/src/render.h +31 -0
  827. package/templates/action-puzzle/src/sound.c +158 -0
  828. package/templates/action-puzzle/src/sound.h +22 -0
  829. package/templates/action-puzzle/tools/disk_check.py +77 -0
  830. package/templates/action-puzzle/tools/drive.py +106 -0
  831. package/templates/action-puzzle/tools/gen.py +454 -0
  832. package/templates/action-puzzle/tools/model_check.py +49 -0
  833. package/templates/action-puzzle/tools/verdict_codes.py +24 -0
  834. package/templates/adventure/.claude/settings.json +17 -0
  835. package/templates/adventure/.mcp.json +10 -0
  836. package/templates/adventure/CLAUDE.md +118 -0
  837. package/templates/adventure/Makefile +113 -0
  838. package/templates/adventure/PLAN.md +396 -0
  839. package/templates/adventure/README.md +277 -0
  840. package/templates/adventure/expect.json +25 -0
  841. package/templates/adventure/src/engine.c +543 -0
  842. package/templates/adventure/src/engine.h +48 -0
  843. package/templates/adventure/src/gen_script.h +141 -0
  844. package/templates/adventure/src/gen_world.h +511 -0
  845. package/templates/adventure/src/main.c +439 -0
  846. package/templates/adventure/src/picture.c +83 -0
  847. package/templates/adventure/src/picture.h +16 -0
  848. package/templates/adventure/src/save.c +159 -0
  849. package/templates/adventure/src/save.h +25 -0
  850. package/templates/adventure/src/sound.c +71 -0
  851. package/templates/adventure/src/sound.h +16 -0
  852. package/templates/adventure/src/text.c +349 -0
  853. package/templates/adventure/src/text.h +40 -0
  854. package/templates/adventure/tools/disk_check.py +128 -0
  855. package/templates/adventure/tools/drive.py +119 -0
  856. package/templates/adventure/tools/gen.py +1033 -0
  857. package/templates/adventure/tools/world.py +356 -0
  858. package/templates/beat-em-up/.claude/settings.json +17 -0
  859. package/templates/beat-em-up/.mcp.json +10 -0
  860. package/templates/beat-em-up/CLAUDE.md +136 -0
  861. package/templates/beat-em-up/Makefile +96 -0
  862. package/templates/beat-em-up/PLAN.md +502 -0
  863. package/templates/beat-em-up/README.md +315 -0
  864. package/templates/beat-em-up/expect-gameover.json +8 -0
  865. package/templates/beat-em-up/expect.json +29 -0
  866. package/templates/beat-em-up/src/anim.c +70 -0
  867. package/templates/beat-em-up/src/art.c +344 -0
  868. package/templates/beat-em-up/src/autopilot.h +154 -0
  869. package/templates/beat-em-up/src/brute.c +273 -0
  870. package/templates/beat-em-up/src/enemy.c +281 -0
  871. package/templates/beat-em-up/src/engine.asm +512 -0
  872. package/templates/beat-em-up/src/fighter.c +384 -0
  873. package/templates/beat-em-up/src/game.h +269 -0
  874. package/templates/beat-em-up/src/hud.c +135 -0
  875. package/templates/beat-em-up/src/main.c +341 -0
  876. package/templates/beat-em-up/src/sound.c +44 -0
  877. package/templates/beat-em-up/src/street.c +93 -0
  878. package/templates/beat-em-up/src/verdict.h +523 -0
  879. package/templates/beat-em-up/src/view.c +362 -0
  880. package/templates/beat-em-up/tools/drive.py +105 -0
  881. package/templates/beat-em-up/tools/flickercheck.py +273 -0
  882. package/templates/demo/.claude/settings.json +17 -0
  883. package/templates/demo/.mcp.json +10 -0
  884. package/templates/demo/CLAUDE.md +129 -0
  885. package/templates/demo/Makefile +66 -0
  886. package/templates/demo/PLAN.md +401 -0
  887. package/templates/demo/README.md +322 -0
  888. package/templates/demo/expect.json +945 -0
  889. package/templates/demo/src/config.asm +80 -0
  890. package/templates/demo/src/framework.asm +390 -0
  891. package/templates/demo/src/main.asm +139 -0
  892. package/templates/demo/src/music.asm +197 -0
  893. package/templates/demo/src/part_main.asm +279 -0
  894. package/templates/demo/src/part_title.asm +79 -0
  895. package/templates/demo/src/parts.asm +43 -0
  896. package/templates/demo/src/tables.asm +73 -0
  897. package/templates/demo/src/verdict.asm +179 -0
  898. package/templates/demo/tools/audio.py +80 -0
  899. package/templates/demo/tools/gen_expect.py +167 -0
  900. package/templates/demo/tools/probe.py +95 -0
  901. package/templates/hello/.claude/settings.json +17 -0
  902. package/templates/hello/.mcp.json +10 -0
  903. package/templates/hello/CLAUDE.md +100 -0
  904. package/templates/hello/Makefile +38 -0
  905. package/templates/hello/PLAN.md +200 -0
  906. package/templates/hello/expect.json +20 -0
  907. package/templates/hello/src/main.c +161 -0
  908. package/templates/hello/src/sprite.asm +27 -0
  909. package/templates/hello-kick/.claude/settings.json +17 -0
  910. package/templates/hello-kick/.mcp.json +10 -0
  911. package/templates/hello-kick/CLAUDE.md +100 -0
  912. package/templates/hello-kick/Makefile +17 -0
  913. package/templates/hello-kick/PLAN.md +199 -0
  914. package/templates/hello-kick/expect.json +20 -0
  915. package/templates/hello-kick/src/main.asm +233 -0
  916. package/templates/platformer/.claude/settings.json +17 -0
  917. package/templates/platformer/.mcp.json +10 -0
  918. package/templates/platformer/CLAUDE.md +125 -0
  919. package/templates/platformer/Makefile +86 -0
  920. package/templates/platformer/PLAN.md +360 -0
  921. package/templates/platformer/README.md +277 -0
  922. package/templates/platformer/expect.json +32 -0
  923. package/templates/platformer/src/actors.c +289 -0
  924. package/templates/platformer/src/anim.c +51 -0
  925. package/templates/platformer/src/art.c +212 -0
  926. package/templates/platformer/src/autopilot.h +30 -0
  927. package/templates/platformer/src/engine.asm +253 -0
  928. package/templates/platformer/src/game.h +248 -0
  929. package/templates/platformer/src/hud.c +90 -0
  930. package/templates/platformer/src/level.c +184 -0
  931. package/templates/platformer/src/main.c +306 -0
  932. package/templates/platformer/src/player.c +268 -0
  933. package/templates/platformer/src/sound.c +42 -0
  934. package/templates/platformer/src/verdict.h +206 -0
  935. package/templates/platformer/src/view.c +331 -0
  936. package/templates/platformer/stage-expect.json +6 -0
  937. package/templates/platformer/tools/drive.py +112 -0
  938. package/templates/platformer/tools/tearcheck.py +229 -0
  939. package/templates/shmup-vertical/.claude/settings.json +17 -0
  940. package/templates/shmup-vertical/.mcp.json +10 -0
  941. package/templates/shmup-vertical/CLAUDE.md +137 -0
  942. package/templates/shmup-vertical/Makefile +131 -0
  943. package/templates/shmup-vertical/PLAN.md +569 -0
  944. package/templates/shmup-vertical/README.md +189 -0
  945. package/templates/shmup-vertical/expect.json +38 -0
  946. package/templates/shmup-vertical/src/bullets.c +158 -0
  947. package/templates/shmup-vertical/src/bullets.h +35 -0
  948. package/templates/shmup-vertical/src/display.c +239 -0
  949. package/templates/shmup-vertical/src/display.h +40 -0
  950. package/templates/shmup-vertical/src/game.h +85 -0
  951. package/templates/shmup-vertical/src/glyph.asm +358 -0
  952. package/templates/shmup-vertical/src/hiscore.c +141 -0
  953. package/templates/shmup-vertical/src/hiscore.h +16 -0
  954. package/templates/shmup-vertical/src/hit.asm +180 -0
  955. package/templates/shmup-vertical/src/hitbox.c +59 -0
  956. package/templates/shmup-vertical/src/hitbox.h +25 -0
  957. package/templates/shmup-vertical/src/kernel.asm +330 -0
  958. package/templates/shmup-vertical/src/level.c +174 -0
  959. package/templates/shmup-vertical/src/level.h +27 -0
  960. package/templates/shmup-vertical/src/main.c +824 -0
  961. package/templates/shmup-vertical/src/mux.asm +321 -0
  962. package/templates/shmup-vertical/src/sound.asm +255 -0
  963. package/templates/shmup-vertical/src/step.asm +169 -0
  964. package/templates/shmup-vertical/src/waves.c +195 -0
  965. package/templates/shmup-vertical/src/waves.h +33 -0
  966. package/templates/shmup-vertical/stage-expect.json +6 -0
  967. package/templates/shmup-vertical/tools/drive.py +152 -0
  968. package/templates/shmup-vertical/tools/joytest.py +159 -0
  969. package/templates/shmup-vertical/tools/meter.py +15 -0
  970. package/templates/shmup-vertical/tools/phases.py +73 -0
@@ -0,0 +1,179 @@
1
+ // verdict.asm: AUTOPILOT only. Once the main part has frozen, the main loop
2
+ // reads the demo's real state back and grades it against what the assembler
3
+ // predicts from config.asm. $02FF = $01 and a green border on pass, $02 and
4
+ // red on fail; "RESULT 01 PASS" or "RESULT 02 FAIL" on row 24.
5
+
6
+ .const EXP_PX = (FREEZE_UPDATES * CHAIN_SX) & 255 // the frozen phases
7
+ .const EXP_PY = (FREEZE_UPDATES * CHAIN_SY) & 255
8
+ .const EXP_PB = (FREEZE_UPDATES * BAR_SPEED) & 255
9
+ .const EXP_SHIFTS = floor(FREEZE_UPDATES / 8) // XSCROLL 7 - (k mod 8)
10
+ .const EXP_XSCROLL = 7 - mod(FREEZE_UPDATES, 8)
11
+
12
+ .function SinR(amp, step) { .return round(amp * sin(toRadians(step * 360 / 256))) }
13
+ .function ExpX(n) { .return CHAIN_X0 + n * CHAIN_DX + SinR(CHAIN_AX, (EXP_PX + n * CHAIN_PX) & 255) }
14
+ .function ExpY(n) { .return CHAIN_Y0 + SinR(CHAIN_AY, (EXP_PY + n * CHAIN_PY) & 255) }
15
+
16
+ .var msb_bits = 0
17
+ .for (var n = 0; n < 8; n++) {
18
+ .if (ExpX(n) > 255) .eval msb_bits = msb_bits | (1 << n)
19
+ }
20
+ .const exp_msb = msb_bits
21
+
22
+ // A failed check jumps to vfail; the checks are too long for one branch.
23
+ .macro FailNe() {
24
+ beq !+
25
+ jmp vfail
26
+ !:
27
+ }
28
+ .macro FailEq() {
29
+ bne !+
30
+ jmp vfail
31
+ !:
32
+ }
33
+
34
+ verdict:
35
+ jsr hard_cut // no part in the table names hard_cut, so the
36
+ bcs !+ // verdict runs it: it must end a part (carry set)
37
+ jmp vfail
38
+ !:
39
+ lda part // the transition happened: the main part plays,
40
+ cmp #MAIN_PART // the wipe cleared all 40 columns, the
41
+ FailNe() // title's teardown ran
42
+ lda seq_state
43
+ cmp #PLAY
44
+ FailNe()
45
+ lda tr_step
46
+ cmp #40
47
+ FailNe()
48
+ lda title_done
49
+ FailEq()
50
+ .for (var n = 0; n < 8; n++) { // the chain against the sine formula
51
+ lda $d000 + 2 * n
52
+ cmp #<ExpX(n)
53
+ FailNe()
54
+ lda $d001 + 2 * n
55
+ cmp #ExpY(n)
56
+ FailNe()
57
+ }
58
+ lda $d010
59
+ cmp #exp_msb
60
+ FailNe()
61
+ lda xscroll // the scroller: phase, read pointer, row 22
62
+ cmp #EXP_XSCROLL
63
+ FailNe()
64
+ lda msg_read+1
65
+ cmp #<(message + MSG_START + EXP_SHIFTS)
66
+ FailNe()
67
+ lda msg_read+2
68
+ cmp #>(message + MSG_START + EXP_SHIFTS)
69
+ FailNe()
70
+ ldx #37
71
+ !: lda SCREEN + SCROLL_ROW * 40 + 1,x
72
+ cmp message + EXP_SHIFTS + 1,x
73
+ FailNe()
74
+ dex
75
+ bpl !-
76
+ ldx #BARS_LINES - 1 // the bar table the kernel draws
77
+ !: lda bar_colours,x
78
+ cmp exp_bars,x
79
+ FailNe()
80
+ dex
81
+ bpl !-
82
+ lda music_calls // every frame slot played or (NTSC) skipped
83
+ clc
84
+ adc music_skips
85
+ tax
86
+ lda music_calls+1
87
+ adc music_skips+1
88
+ cmp frames+1
89
+ FailNe()
90
+ cpx frames
91
+ FailNe()
92
+ lda music_skips // PAL never skips; NTSC skips one in six
93
+ ora music_skips+1
94
+ ldx model
95
+ beq !pal+
96
+ cmp #0
97
+ FailEq()
98
+ jmp !pass+
99
+ !pal: cmp #0
100
+ FailNe()
101
+ !pass:
102
+ lda irq_late // every IRQ on its line, every chain whole,
103
+ ora irq_bad // every frame slot done before the next chain
104
+ ora frame_late
105
+ FailNe()
106
+ // The player's place against its call count: after c calls the
107
+ // tick is c mod STEP_FRAMES and the step (c div STEP_FRAMES) mod
108
+ // STEPS. Read together, with the IRQ that advances them held off.
109
+ sei
110
+ lda music_calls
111
+ sta v_calls
112
+ lda music_calls+1
113
+ sta v_calls+1
114
+ lda m_tick
115
+ sta v_tick
116
+ lda m_step
117
+ sta v_step
118
+ cli
119
+ ldx #0 // v_calls div STEP_FRAMES, low byte in X
120
+ !: lda v_calls
121
+ sec
122
+ sbc #STEP_FRAMES
123
+ tay
124
+ lda v_calls+1
125
+ sbc #0
126
+ bcc !+
127
+ sta v_calls+1
128
+ sty v_calls
129
+ inx
130
+ jmp !-
131
+ !: lda v_calls // the remainder
132
+ cmp v_tick
133
+ FailNe()
134
+ txa
135
+ and #STEPS - 1
136
+ cmp v_step
137
+ FailNe()
138
+ lda #1
139
+ ldy #5
140
+ ldx #0
141
+ jmp !say+
142
+ vfail: lda #2
143
+ ldy #2
144
+ ldx #pass_end - pass
145
+ !say: sta RESULT
146
+ sty border_colour // the bar kernel writes it after the last bar
147
+ sty $d020
148
+ ldy #0
149
+ !: lda pass,x
150
+ sta SCREEN + 24 * 40 + 1,y
151
+ lda #1
152
+ sta COLOUR + 24 * 40 + 1,y
153
+ inx
154
+ iny
155
+ cpy #pass_end - pass
156
+ bne !-
157
+ lda #1
158
+ sta verdict_done
159
+ rts
160
+
161
+ // The bar table at the frozen phase, drawn as fill_bars draws it.
162
+ .var expected = List()
163
+ .for (var i = 0; i < BARS_LINES; i++) .eval expected.add(0)
164
+ .for (var b = 0; b < 4; b++) {
165
+ .var top = BARS_CENTRE + SinR(BARS_AMP, (EXP_PB + b * BAR_STEP) & 255)
166
+ .for (var i = 0; i < BAR_H; i++) .eval expected.set(top + i, bar_ramps.get(b).get(i))
167
+ }
168
+ exp_bars:
169
+ .for (var i = 0; i < BARS_LINES; i++) .byte expected.get(i)
170
+
171
+ .encoding "screencode_upper"
172
+ pass: .text "RESULT 01 PASS"
173
+ pass_end:
174
+ .text "RESULT 02 FAIL"
175
+ verdict_done: .byte 0
176
+ v_calls: .word 0
177
+ v_tick: .byte 0
178
+ v_step: .byte 0
179
+
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env python3
2
+ """Grade the tune by the stores it makes to the SID, from a VICE store trace.
3
+
4
+ usage: audio.py --c64kb DIR --x64sc PATH [--cycles N] build/demo-auto.prg
5
+
6
+ The demo cannot read its own sound back: under the harness's `+sound`,
7
+ VICE returns values from $D41B and $D41C that do not follow the voice
8
+ (measured here: they change with no SID write at all), so the verdict
9
+ cannot hear a silent player. This check runs c64-kb's claims-watch over the
10
+ AUTOPILOT PRG on PAL and counts the program's stores to each SID unit:
11
+
12
+ - voice 2 (the arpeggio) is written twice every play call, and the tune is
13
+ played every PAL frame from the chain's start. So its stores, less the
14
+ twelve of init, over two, must match the frames from its first store to
15
+ the end of the trace, within SLACK (measured: 447 calls in 451 frames).
16
+ - voice 1 (bass) and voice 3 (drums) change on steps, so each must have at
17
+ least one store per step of seven frames; the volume at least one.
18
+
19
+ Exit 0 when all hold, 1 when one fails, 2 when the trace cannot be run.
20
+ """
21
+ import argparse
22
+ import json
23
+ import os
24
+ import subprocess
25
+ import sys
26
+ import tempfile
27
+
28
+ PAL_FRAME = 19656
29
+ STEP_FRAMES = 7
30
+ INIT_V2 = 12 # m_init: 7 in its clearing loop, 5 to set the voice up
31
+ SLACK = 6 # frames between init and the first play call:
32
+ # measured 4 (the meter's calibration and the
33
+ # title's init run between them)
34
+
35
+
36
+ def main():
37
+ ap = argparse.ArgumentParser()
38
+ ap.add_argument("--c64kb", required=True)
39
+ ap.add_argument("--x64sc", required=True)
40
+ ap.add_argument("--cycles", type=int, default=12000000)
41
+ ap.add_argument("prg")
42
+ a = ap.parse_args()
43
+ with tempfile.TemporaryDirectory() as t:
44
+ out = os.path.join(t, "claims.json")
45
+ r = subprocess.run(
46
+ ["node", "scripts/claims-watch.ts", os.path.abspath(a.prg),
47
+ "--claim", "sid_voice_1, sid_voice_2, sid_voice_3, sid_filter_volume",
48
+ "--cycles", str(a.cycles), "--json", out],
49
+ cwd=a.c64kb, env={**os.environ, "X64SC_BIN": a.x64sc}, capture_output=True, text=True)
50
+ if not os.path.exists(out):
51
+ print(r.stdout[-2000:], r.stderr[-2000:])
52
+ print("audio: claims-watch wrote no trace")
53
+ return 2
54
+ with open(out) as f:
55
+ tallies = json.load(f)["tallies"]
56
+ units = {t["target"]: t for t in tallies if t["source"] == "program" and t["target"].startswith("sid_")}
57
+ ok = True
58
+ v2 = units.get("sid_voice_2")
59
+ if not v2:
60
+ print("FAIL audio: no store to voice 2 at all")
61
+ return 1
62
+ calls = (a.cycles - v2["first"]["clock"]) // PAL_FRAME + 1
63
+ played = (v2["count"] - INIT_V2) // 2
64
+ line = f"voice 2: {v2['count']} stores = {played} play calls; {calls} frames from its first store"
65
+ if abs(played - calls) > SLACK:
66
+ print(f"FAIL audio: {line}")
67
+ ok = False
68
+ else:
69
+ print(f"PASS audio: {line}")
70
+ for unit, least in (("sid_voice_1", calls // STEP_FRAMES), ("sid_voice_3", calls // STEP_FRAMES),
71
+ ("sid_filter_volume", 1)):
72
+ n = units.get(unit, {}).get("count", 0)
73
+ print(f"{'PASS' if n >= least else 'FAIL'} audio: {unit}: {n} stores, want at least {least}")
74
+ ok = ok and n >= least
75
+ print("audio: " + ("the tune writes the SID every frame" if ok else "FAILED"))
76
+ return 0 if ok else 1
77
+
78
+
79
+ if __name__ == "__main__":
80
+ sys.exit(main())
@@ -0,0 +1,167 @@
1
+ #!/usr/bin/env python3
2
+ """Write expect.json for the demo starter from src/config.asm.
3
+
4
+ usage: python3 tools/gen_expect.py > expect.json (or: make expect)
5
+
6
+ The numbers (lines, amplitudes, speeds, the freeze) are read from the plain
7
+ `.const NAME = number` lines of src/config.asm; the picture is computed here
8
+ again, in Python, not taken from the assembler: where the eight sprites
9
+ sit, which colour every bar line has, where row 22's ink falls at the
10
+ frozen XSCROLL (from the character ROM).
11
+ KickAssembler's round() is Java's Math.round, floor(x + 0.5), and so is
12
+ rnd() below.
13
+ """
14
+ import json
15
+ import math
16
+ import os
17
+ import re
18
+
19
+ HERE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
20
+ with open(os.path.join(HERE, "src", "config.asm")) as f:
21
+ CONFIG = f.read()
22
+ C = {m.group(1): int(m.group(2), 0) for m in re.finditer(r"^\.const (\w+)\s*=\s*(\d+)\b", CONFIG, re.M)}
23
+
24
+ # The ramps and the message, from their source lines.
25
+ RAMPS = [[int(v) for v in m.group(1).split(",")]
26
+ for m in re.finditer(r"List\(\)\.add\(([\d, ]+)\)", CONFIG)]
27
+ with open(os.path.join(HERE, "src", "tables.asm")) as f:
28
+ TABLES = f.read()
29
+ MESSAGE = "".join(re.findall(r'\.text "([^"]*)"', TABLES[TABLES.index("message:"):]))
30
+ SUBTITLE = re.search(r'subtitle:\s*\.text "([^"]*)"', TABLES).group(1)
31
+ # scroll_colours: ".byte a, b, c / .fill n, v / .byte ..." read in order.
32
+ SCROLL_COLOURS = []
33
+ for kind, args in re.findall(r"\.(byte|fill) ([\d, ]+)", TABLES[TABLES.index("scroll_colours:"):TABLES.index(".encoding")]):
34
+ vals = [int(v) for v in args.split(",")]
35
+ SCROLL_COLOURS += vals if kind == "byte" else [vals[1]] * vals[0]
36
+
37
+ # The power-on character set, for where the scroller's ink falls (the same
38
+ # ROM check.py decodes text with).
39
+ CHARGEN_PATHS = [
40
+ os.environ.get("C64_CHARGEN", ""),
41
+ "/opt/homebrew/opt/vice/share/vice/C64/chargen-901225-01.bin",
42
+ "/usr/local/share/vice/C64/chargen-901225-01.bin",
43
+ "/usr/share/vice/C64/chargen-901225-01.bin",
44
+ "/usr/lib/vice/C64/chargen-901225-01.bin",
45
+ ]
46
+
47
+ BORDER_PASS = 5
48
+ BLACK = 0
49
+
50
+
51
+ def rnd(x):
52
+ return math.floor(x + 0.5)
53
+
54
+
55
+ def sin256(amp, step):
56
+ return rnd(amp * math.sin(2 * math.pi * (step & 255) / 256))
57
+
58
+
59
+ def sprites(k):
60
+ px, py = (k * C["CHAIN_SX"]) & 255, (k * C["CHAIN_SY"]) & 255
61
+ out = []
62
+ for n in range(8):
63
+ x = C["CHAIN_X0"] + n * C["CHAIN_DX"] + sin256(C["CHAIN_AX"], px + n * C["CHAIN_PX"])
64
+ y = C["CHAIN_Y0"] + sin256(C["CHAIN_AY"], py + n * C["CHAIN_PY"])
65
+ out.append((x, y, C["CHAIN_COL_A"] if n % 2 == 0 else C["CHAIN_COL_B"]))
66
+ return out
67
+
68
+
69
+ def bar_lines(k):
70
+ pb = (k * C["BAR_SPEED"]) & 255
71
+ lines = [BLACK] * C["BARS_LINES"]
72
+ for b, ramp in enumerate(RAMPS):
73
+ top = C["BARS_CENTRE"] + sin256(C["BARS_AMP"], pb + b * C["BAR_STEP"])
74
+ lines[top:top + C["BAR_H"]] = ramp
75
+ return lines
76
+
77
+
78
+ def screen_code(ch):
79
+ """KickAssembler's screencode_upper for the characters the message uses."""
80
+ return ord(ch) - 64 if "A" <= ch <= "Z" else ord(ch)
81
+
82
+
83
+ def scroller_checks(k, rom):
84
+ """Row 22 at the freeze: 38 columns, XSCROLL 7 - (k mod 8), after k // 8 shifts.
85
+ For each visible cell, the leftmost ink pixel of its first inked glyph row
86
+ and the pixel just left of it. A missing or wrong $D016 write moves them."""
87
+ shifts, xs = k // 8, 7 - k % 8
88
+ row = MESSAGE[shifts:shifts + 40]
89
+ line0 = 51 + 8 * C["SCROLL_ROW"]
90
+
91
+ def colour_at(vic_x, r):
92
+ cell, bit = divmod(vic_x - 24 - xs, 8)
93
+ if not 0 <= cell < 40:
94
+ return BLACK
95
+ glyph = rom[screen_code(row[cell]) * 8 + r]
96
+ return SCROLL_COLOURS[cell] if glyph & (0x80 >> bit) else BLACK
97
+
98
+ out = []
99
+ for c in range(1, 38):
100
+ code = screen_code(row[c])
101
+ glyph = rom[code * 8: code * 8 + 8]
102
+ r = next((r for r in range(8) if glyph[r]), None)
103
+ if r is None:
104
+ continue
105
+ bit = next(b for b in range(8) if glyph[r] & (0x80 >> b))
106
+ x = 24 + 8 * c + xs + bit
107
+ for vx, what in ((x, "ink"), (x - 1, "left of it")):
108
+ out.append({"name": f"scroller cell {c} '{row[c]}', XSCROLL {xs}: {what} at X {vx}, line {line0 + r}",
109
+ "type": "pixel", "vic_x": vx, "line": line0 + r, "colour": colour_at(vx, r)})
110
+ # 38 columns: the border covers X 24-30 and 335-343 on the scroller's lines only.
111
+ out.append({"name": "scroller in 38 columns: left border X 24-30", "type": "rect", "colour": BORDER_PASS,
112
+ "vic_x": 24, "line": line0, "width": 7, "height": 8})
113
+ out.append({"name": "scroller in 38 columns: right border X 335-343", "type": "rect", "colour": BORDER_PASS,
114
+ "vic_x": 335, "line": line0, "width": 9, "height": 8})
115
+ return out
116
+
117
+
118
+ def main():
119
+ k = C["FREEZE_UPDATES"]
120
+ top = C["BARS_TOP"]
121
+ checks = [
122
+ {"name": "own verdict (border)", "type": "verdict"},
123
+ {"name": "verdict line", "type": "text", "row": 24, "col": 1, "text": "RESULT 01 PASS"},
124
+ {"name": "subtitle under the logo (row 5)", "type": "text", "row": 5, "col": 0, "text": SUBTITLE},
125
+ ]
126
+ # The logo: two cells of the D's stem and one gap, rows 0 to 4.
127
+ for row, colour in enumerate([4, 10, 7, 10, 4]):
128
+ checks.append({"name": f"logo row {row}: the D's stem", "type": "pixel", "row": row, "col": 7, "colour": colour})
129
+ checks.append({"name": "logo: the gap between D and E", "type": "pixel", "row": 2, "col": 13, "colour": BLACK})
130
+
131
+ for n, (x, y, colour) in enumerate(sprites(k)):
132
+ checks.append({
133
+ "name": f"sprite {n} at X {x}, Y {y} (lines {y + 1}-{y + 21}), from the sine formula",
134
+ "type": "sprite", "colour": colour, "vic_x": x, "line": y + 1, "width": 24, "height": 21,
135
+ "search": {"vic_x": x - 16, "line": y - 7, "width": 56, "height": 37},
136
+ })
137
+
138
+ # Every bar line, left border to right border, one colour: runs of equal
139
+ # colour become one rect each. The title card's rows 13, 15 and 17 lie in
140
+ # these lines, so these checks also prove the wipe cleared it.
141
+ lines = bar_lines(k)
142
+ i = 0
143
+ while i < len(lines):
144
+ j = i
145
+ while j + 1 < len(lines) and lines[j + 1] == lines[i]:
146
+ j += 1
147
+ checks.append({
148
+ "name": f"bar lines {top + i}-{top + j}: colour {lines[i]} across the whole line",
149
+ "type": "rect", "colour": lines[i], "vic_x": -8, "line": top + i, "width": 384, "height": j - i + 1,
150
+ })
151
+ i = j + 1
152
+ for line, what in ((top - 1, "above"), (top + len(lines), "below")):
153
+ checks.append({"name": f"line {line}, {what} the bars: border", "type": "rect", "colour": BORDER_PASS,
154
+ "vic_x": -8, "line": line, "width": 32, "height": 1})
155
+ checks.append({"name": f"line {line}, {what} the bars: background", "type": "rect", "colour": BLACK,
156
+ "vic_x": 24, "line": line, "width": 320, "height": 1})
157
+
158
+ rom = next(open(p, "rb").read() for p in CHARGEN_PATHS if p and os.path.exists(p))
159
+ checks += scroller_checks(k, rom)
160
+ checks.append({"name": "rows 0 to 23 the same on PAL and NTSC", "type": "same", "cells": [0, 0, 23, 39]})
161
+ checks.append({"name": f"frame meter, {C['HOLD']} frames: title, wipe and main part", "type": "meter",
162
+ "row": 24, "col": 20, "frames": C["HOLD"]})
163
+ print(json.dumps({"checks": checks}, indent=2))
164
+
165
+
166
+ if __name__ == "__main__":
167
+ main()
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env python3
2
+ """Where the bar kernel's colour stores land, read off the PROBE build's shots.
3
+
4
+ usage: probe.py probe-pal-*.png probe-ntsc-*.png (at least 8 shots a model)
5
+
6
+ The PROBE build delays the whole kernel by 20 cycles, so the second store
7
+ of each line ($D021, the background) lands inside the visible line instead
8
+ of in the horizontal blank. On every bar line whose colour differs from the
9
+ line above, the first pixel of the new colour inside the display window is
10
+ that store. One column on every line, in every shot, means the entry is
11
+ stable and every badline chunk has the right length. Taking the 20 cycles
12
+ (160 pixels) back off says how far the real stores sit from the visible
13
+ edges: the $D020 store is 4 cycles (32 pixels) before the $D021 store.
14
+
15
+ Exit 0 when each model shows one column, PROBE_COLUMN from config.asm,
16
+ over all its shots, and the stores
17
+ of every chunk fall in the horizontal blank without the probe; 1 otherwise.
18
+ Geometry from c64-kb docs/runtime/vice-reference.md: row = line - 16 (PAL),
19
+ line - 28 (NTSC); a PAL line is 504 pixels (63 cycles), an NTSC one 520.
20
+ """
21
+ import os
22
+ import re
23
+ import sys
24
+
25
+ from PIL import Image
26
+
27
+ HERE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
28
+ with open(os.path.join(HERE, "src", "config.asm")) as f:
29
+ CONST = {m.group(1): int(m.group(2)) for m in re.finditer(r"^\.const (\w+)\s*=\s*(\d+)\b", f.read(), re.M)}
30
+ SHIFT_PX = 20 * 8
31
+ MIN_SHOTS = 8 # the review saw wrong pads show one column in 16 of 16 single shots
32
+ GREY_DOT = (205, 205, 205) # light grey, the same triple on both models
33
+ MODELS = {"pal": (16, 504), "ntsc": (28, 520)}
34
+
35
+
36
+ def columns(path, offset):
37
+ """(line, x) of the first new-colour pixel in the display, per changing line."""
38
+ im = Image.open(path).convert("RGB")
39
+ top, n = CONST["BARS_TOP"], CONST["BARS_LINES"]
40
+ out = []
41
+ for line in range(top, top + n + 1):
42
+ y = line - offset
43
+ new, old = im.getpixel((383, y)), im.getpixel((0, y))
44
+ # VICE's PAL default, a C64C, draws the grey dot: one light grey pixel
45
+ # where a colour register changes. A change to or from light grey is
46
+ # skipped, so the column is always the first pixel of the new colour.
47
+ if new == old or GREY_DOT in (new, old):
48
+ continue
49
+ out.append((line, next((x for x in range(32, 352) if im.getpixel((x, y)) == new), None)))
50
+ return out
51
+
52
+
53
+ def main():
54
+ shots = {"pal": [], "ntsc": []}
55
+ for path in sys.argv[1:]:
56
+ shots["ntsc" if "ntsc" in os.path.basename(path) else "pal"].append(path)
57
+ last_line = CONST["BARS_TOP"] + CONST["BARS_LINES"]
58
+ ok = True
59
+ for model, paths in shots.items():
60
+ offset, line_px = MODELS[model]
61
+ body, last = set(), set()
62
+ for p in paths:
63
+ for line, x in columns(p, offset):
64
+ (last if line == last_line else body).add(x)
65
+ print(f"{model}: {len(paths)} shot(s), $D021 store column(s) {sorted(body, key=str)}")
66
+ if len(paths) < MIN_SHOTS:
67
+ print(f"{model}: FAIL, {len(paths)} shot(s); a wrong SYNC_PAD can look right in fewer than {MIN_SHOTS}")
68
+ ok = False
69
+ continue
70
+ if len(body) != 1 or None in body:
71
+ print(f"{model}: FAIL, the stores do not line up")
72
+ ok = False
73
+ continue
74
+ if body != {CONST["PROBE_COLUMN"]}:
75
+ print(f"{model}: FAIL, the stores line up at x {next(iter(body))}, not PROBE_COLUMN "
76
+ f"{CONST['PROBE_COLUMN']} (config.asm): the entry moved")
77
+ ok = False
78
+ continue
79
+ x2 = next(iter(body)) - SHIFT_PX # the real $D021 store, relative to x = 0
80
+ x1 = x2 - 32 # the $D020 store, four cycles earlier
81
+ # The last chunk's $D021 store writes black over black, so it never
82
+ # shows; it is two cycles later than the others by the code.
83
+ xl = x2 + 16
84
+ after = x1 + line_px - 383 # pixels past the line above's last visible pixel
85
+ print(f"{model}: without the probe, $D020 at x {x1} and $D021 at x {x2} (the last chunk's "
86
+ f"$D021 at {xl} by the code, not measured), x 0 being the line's first visible pixel; "
87
+ f"the $D020 store is {after} pixels after the line above leaves the picture")
88
+ if not (xl < 0 and after > 0):
89
+ print(f"{model}: FAIL, a store would land in the visible line")
90
+ ok = False
91
+ return 0 if ok else 1
92
+
93
+
94
+ if __name__ == "__main__":
95
+ sys.exit(main())
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/claude-code-settings.json",
3
+ "hooks": {
4
+ "PreToolUse": [
5
+ {
6
+ "matcher": "Edit|MultiEdit|Write|NotebookEdit",
7
+ "hooks": [
8
+ {
9
+ "type": "command",
10
+ "command": "h=\"$CLAUDE_PROJECT_DIR/harness/hooks/plan-gate.py\"; [ -f \"$h\" ] || h=\"$CLAUDE_PROJECT_DIR/../_harness/hooks/plan-gate.py\"; exec python3 \"$h\"",
11
+ "timeout": 10
12
+ }
13
+ ]
14
+ }
15
+ ]
16
+ }
17
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "mcpServers": {
3
+ "c64-kb": {
4
+ "type": "stdio",
5
+ "command": "node",
6
+ "args": ["../../dist/cli.js", "serve"],
7
+ "env": {}
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,100 @@
1
+ # Rules for an agent working on this C64 program
2
+
3
+ This program runs on a stock Commodore 64, PAL and NTSC. It is built on the
4
+ c64-kb harness (`./harness`, vendored from c64-kb's `templates/_harness`).
5
+ c64-kb is the reference: its pages give the registers, timings, techniques,
6
+ pitfalls and recipes this program is built from. A wrong number becomes a torn
7
+ screen or a crash, so every claim here is measured or says it is not.
8
+
9
+ A new program starts in c64-kb with `npm run new-project -- <starter> <dir>`.
10
+ That copies the starter and the harness, points `.mcp.json` and `local.mk`
11
+ at the c64-kb checkout, proves the copy with `make shot check`, and leaves a
12
+ blank `PLAN.md`.
13
+
14
+ ## This starter: hello
15
+
16
+ The smallest program that uses every harness target. `src/main.c` (Oscar64)
17
+ runs the loop; `src/sprite.asm` (KickAssembler) places sprite 0; the meter
18
+ times each frame. Start a program from it with
19
+ `npm run new-project -- hello <dir>` in c64-kb. `PLAN.md` here is a plan
20
+ filled from real tool output; new-project keeps it as
21
+ `PLAN-hello-example.md` and gives the new program a blank one.
22
+
23
+ ## Before any code
24
+
25
+ 1. Brief: `npx tsx src/cli.ts game-briefing "<concept>" --archetype <name>`
26
+ (or `demo-briefing`), in the c64-kb checkout. Read what it proposes.
27
+ 2. For each technique you keep: `technique-lookup <name>` and
28
+ `pitfalls-for <name>`. Start from the recipe it names (`recipe-lookup`).
29
+ 3. Fill `PLAN.md`: paste the whole output of `check-compatibility` and of
30
+ `plan-budget` (same techniques) into their sections, list every technique
31
+ in its table, and replace every `FILL:` line.
32
+
33
+ Until `PLAN.md` passes, a hook blocks Edit and Write under `src/`, and every
34
+ make target that builds stops (`make plan-gate` says what is missing). With
35
+ C64KB set, `make` re-runs `check-compatibility` and wants the pasted Verdict.
36
+ The gate cannot see writes made through a shell command, or outputs edited
37
+ into shape by hand: do neither. `make PLAN_GATE=off` overrides it; say why in
38
+ `PLAN.md` if you do.
39
+
40
+ ## The loop
41
+
42
+ ```bash
43
+ make # build build/<name>.prg
44
+ make shot check # autopilot build, headless PAL and NTSC, graded by expect.json
45
+ make selftest # the FORCE_FAULT build must fail the same checks
46
+ make disk # build/<name>.d64
47
+ make claims # every store the program makes, against what it declares
48
+ make run # windowed VICE, for a human
49
+ ```
50
+
51
+ ## Rules
52
+
53
+ - Build before claiming. Code that has not built is not done.
54
+ - Measure screenshots with `check.py` through `expect.json`, never by eye.
55
+ Every visible claim gets a check. Add one before you trust a change.
56
+ - PAL and NTSC: both shots pass, or it is not done.
57
+ - Name the rung for every number: measured here (`make shot`, the meter, the
58
+ VICE monitor), taken from a c64-kb page (say which), arithmetic, or not
59
+ measured. Never call something verified that was not run.
60
+ - Frame cost comes from the meter: CIA2 timer A, printed as
61
+ `F<frames> W<worst> T<typical>` at row 24, columns 20 to 39, in AUTOPILOT
62
+ builds. It records the first `hold` frames: make that the autopilot
63
+ script's play frames. Typical is the median of those frames, the KB's
64
+ `cycles_per_frame_typical`. Keep grading, logging and printing outside the
65
+ bracket; work split between the main loop and IRQs is summed with
66
+ `METER_PAUSE` / `METER_START`.
67
+ - Do not invent a register, routine or address. Look it up:
68
+ `lookup-register`, `lookup-kernal`, `memory-map`.
69
+ - Lint every source you change: `npx tsx src/cli.ts lint <file>`.
70
+ - Commit named paths only. Never `git add -A` or `git add .`. `build/`,
71
+ `shots/` and `local.mk` are never committed.
72
+
73
+ ## Harness facts you will need
74
+
75
+ - `AUTOPILOT=1` builds read a scripted joystick byte instead of `$DC00` and
76
+ grade themselves: `$02FF` = `$01` and a green border on pass, `$02` and red
77
+ on fail. `FORCE_FAULT=1` must turn the verdict red and move something a
78
+ screenshot check can see.
79
+ - Screenshot geometry (c64-kb `docs/runtime/vice-reference.md`): PAL 384 x 272,
80
+ row = raster line - 16; NTSC 384 x 247, row = line - 28; x = VIC X + 8. A
81
+ sprite at Y register y is drawn from line y + 1.
82
+ - `check.py` reads text in the ROM character set unless a check names a
83
+ `charset` file; the meter's cells need 0-9, F, W and T in the set on screen.
84
+ - A KickAssembler part called from C is a raw blob at its own `* =` address,
85
+ `$0880` or above; `build/asm.h` gives C its labels as `ASM_<LABEL>`
86
+ (`ASM_<SCOPE>_<LABEL>` inside a scope). Pass arguments through bytes in the
87
+ blob, not Oscar64's zero page (`$02` up; the top depends on the program:
88
+ `make zp` lists what the build's code touches).
89
+ - The meter takes CIA2 timer A. Do not open RS-232 (device 2) while it runs.
90
+ - The KERNAL serial routines end in `CLI` (ROM bytes `58 60` / `58 18` at
91
+ `$EDAB`, `$EDB5`, `$EDDB`, `$EE82`). After any disk call, `SEI` again if
92
+ the program runs with the KERNAL IRQ off: otherwise that IRQ lands inside
93
+ the meter's brackets and rewrites `$DC00`.
94
+
95
+ ## Calling c64-kb
96
+
97
+ - CLI, from the c64-kb checkout (`C64KB` in `local.mk`):
98
+ `npx tsx src/cli.ts <command>`; `npx tsx src/cli.ts --help` lists them.
99
+ - MCP: `.mcp.json` starts `node <c64-kb>/dist/cli.js serve` (run
100
+ `npm run build` in c64-kb first).