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,478 @@
1
+ ---
2
+ tool: agent-harness
3
+ tool_kind: reference-catalog
4
+ maintainer: bdgscotland
5
+ license: BSD-3-Clause
6
+ home_url: https://github.com/bdgscotland/c64-kb
7
+ ---
8
+
9
+ <!-- doc-type: toolchain-reference -->
10
+
11
+ # The agent harness: build, run, shoot, check, measure
12
+
13
+ ## Tool
14
+
15
+ `templates/_harness` is the loop every starter in `templates/` shares. A
16
+ starter's Makefile sets a few variables and includes `harness.mk`; from then
17
+ on `make shot check` builds the program, runs it headless in VICE on PAL and
18
+ on NTSC with scripted input, and grades both exit screenshots against the
19
+ expectations the starter wrote down. A frame meter prints the program's
20
+ measured cycle cost where the checker can read it back. `templates/hello`
21
+ (Oscar64 calling KickAssembler) and `templates/hello-kick` (KickAssembler
22
+ alone) are the smallest starters that use every target.
23
+
24
+ Every figure on this page was measured on 2026-09-23 with VICE x64sc 3.10
25
+ (the windowless build), KickAssembler 5.25, Oscar64 as named in `CLAUDE.md`,
26
+ c1541 from VICE 3.10 and GNU Make 3.81, unless it says otherwise.
27
+
28
+ ## Starting a project
29
+
30
+ ```bash
31
+ npm run new-project -- hello ~/c64/mygame # or hello-kick; --list names the starters
32
+ ```
33
+
34
+ `scripts/new-project.ts` copies the starter whole, dotfiles included,
35
+ vendors `templates/_harness` into `<dir>/harness`, writes `.mcp.json` with
36
+ this checkout's absolute `dist/cli.js`, and writes `local.mk` (read by the
37
+ harness first) with `C64KB` set to this checkout and the tool paths this
38
+ machine has. It proves the copy with `make shot check`, then renames the
39
+ starter's `PLAN.md` to `PLAN-<starter>-example.md` and puts a blank one in
40
+ its place, so the new program is held by the plan gate until its own plan
41
+ is filled.
42
+
43
+ ## The loop
44
+
45
+ | Command | What it does |
46
+ |---|---|
47
+ | `make` | Builds `build/<name>.prg` once `PLAN.md` passes (see "The plan gate") |
48
+ | `make run` | The windowed x64sc with the normal build, for a human; joystick port 2 on the numeric keypad (8 2 4 6, fire 0) |
49
+ | `make shot` | Builds the AUTOPILOT variant and writes `shots/pal.png` and `shots/ntsc.png` at the pinned cycle counts |
50
+ | `make check` | `check.py expect.json shots/pal.png shots/ntsc.png`; exit 1 names each failed check |
51
+ | `make selftest` | Builds with FORCE_FAULT and shoots it; passes only when `check.py` exits 1 with FAIL lines |
52
+ | `make disk` | `build/<name>.d64` with the PRG and `DISK_FILES`, then lists it |
53
+ | `make claims` | c64-kb's `scripts/claims-watch.ts` over the AUTOPILOT PRG, when the checkout has it |
54
+ | `make released` | With `OSCAR64_RELEASED=<path>`: the autopilot build from that compiler, shot on PAL and NTSC and graded with the same `expect.json`. On v1.32.273, platformer graded 7 of 23 (a miscompile, #30) and action-puzzle 41 of 41 |
55
+ | `make zp` | The zero-page addresses the compiled C touches, read from Oscar64's listing; with `ZP_CLAIM='$02-$55'` a gate |
56
+ | `make clean` | Removes `build/` and `shots/` |
57
+
58
+ The headless runs use `-default -warp +sound +autostart-delay-random
59
+ -autostartprgmode 1 -limitcycles N`, add `-model ntsc` for NTSC, and are
60
+ wrapped in `timeout 180`. The windowless x64sc at
61
+ `~/Developer/c64/vice-headless/bin/x64sc` is used when it exists. A shot is
62
+ re-taken when the PRG, the starter's Makefile or the pin changes: the pin
63
+ is a stamp file named by its cycle count.
64
+
65
+ `npm run verify:templates` makes a project from each starter with an
66
+ `expect.json`, as new-project does, in a temporary directory, and runs
67
+ `make`, `make shot check` and `make disk` there (`--selftest` adds
68
+ `make selftest` and every target the starter lists in `VERIFY_TARGETS`,
69
+ `--only <name>` picks one). A starter's own proof targets (action-puzzle's
70
+ `disktest`, `modelcheck` and `selftest-scan`, adventure's `disktest`,
71
+ platformer's `tearcheck`, shmup-vertical's `stage`, demo's `probe`) prove
72
+ fixes that `make check` cannot see: the adventure's three save-validation
73
+ checks, for instance, fail only in `disktest`. Measured 2026-09-23: seven
74
+ starters with `--selftest` and their targets, 7 of 7, about 3.5 minutes.
75
+
76
+ ## A starter's files
77
+
78
+ | File | Holds |
79
+ |---|---|
80
+ | `Makefile` | `NAME`, `C_MAIN` and/or `KICK_SRC`, `SHOT_CYCLES_PAL`, `SHOT_CYCLES_NTSC`, `CLAIMS_ARGS`, optional `DISK_FILES`, then `include $(HARNESS)/harness.mk`, with a clear error when the harness is missing |
81
+ | `src/` | The program. `AUTOPILOT` selects scripted input; `FORCE_FAULT` must make the program's own verdict fail and move something a screenshot check sees |
82
+ | `expect.json` | The checks `check.py` runs on both shots |
83
+ | `PLAN.md` | The plan, with the pasted output of `check-compatibility` and `plan-budget` |
84
+ | `CLAUDE.md` | `_harness/CLAUDE.md.template` plus a section on this starter |
85
+ | `.claude/settings.json` | `_harness/claude/settings.json`: the plan gate as a PreToolUse hook |
86
+
87
+ `HARNESS` is `./harness` in a project and `../_harness` inside this
88
+ repository. The tools come from `local.mk`, then `OSCAR64`, `KICKASS_JAR`,
89
+ `X64SC`, `X64SC_WINDOWED`, `C1541` and `C64KB` in the environment, then
90
+ PATH and this machine's default locations; `make tools` prints them.
91
+
92
+ ## Reading the screenshots
93
+
94
+ `check.py` takes its geometry and palette from
95
+ [vice-reference](../runtime/vice-reference.md), "Reading the exit
96
+ screenshot": PAL 384 x 272 with screenshot row = raster line - 16; NTSC
97
+ 384 x 247 with row = line - 28, NTSC lines 0 to 11 landing on rows 235 to
98
+ 246; x = VIC-II X coordinate + 8; text cell (r, c) at x = 32 + 8c,
99
+ y = 35 + 8r on PAL and 23 + 8r on NTSC; sixteen exact RGB triples per
100
+ model.
101
+
102
+ One geometry fact was measured here: a sprite whose Y register holds y is
103
+ drawn from raster line y + 1. hello's sprite at X 188, Y 116 covered
104
+ screenshot x 196 to 219 and rows 101 to 121 on PAL, 89 to 109 on NTSC,
105
+ 504 pixels each: lines 117 to 137 on both. A check written for line y
106
+ fails; the first draft of hello's `expect.json` did.
107
+
108
+ `check.py` validates `expect.json` before it grades: at least one check and
109
+ one `verdict` check, the keys each type needs, colours 0 to 15, and every
110
+ point and area inside the picture on each model the check names. A fault
111
+ is exit 2 with the check's name, never a pass and never a traceback.
112
+
113
+ | Check type | Passes when |
114
+ |---|---|
115
+ | `verdict` | The border sample point is colour 5. Colour 2 is the program's own FAIL; anything else means it never reached its verdict |
116
+ | `pixel` | The point has the colour index. The point is `x`/`y`, `vic_x`/`line`, or `row`/`col` (a cell's centre) |
117
+ | `rect` | Every pixel of an area (`vic_x`, `line`, `width`, `height`) has the colour: a raster bar, or a span with height 1 |
118
+ | `sprite` | The pixels of the colour inside `search` (default the expected box grown by 16) have exactly the expected bounding box |
119
+ | `text` | The cells from `row`, `col` read `text` |
120
+ | `same` | Every pixel of the `cells` rectangle, or of an `area`, has the same colour index on PAL and NTSC |
121
+ | `meter` | The meter's readout is there; optional `frames` must match; worst fits `max_worst` (default one frame: 19,656 cycles PAL, 17,095 NTSC); typical is at least 1 (recording has finished) |
122
+
123
+ Text is decoded against the power-on ROM set (`chargen-901225-01.bin`;
124
+ `C64_CHARGEN` overrides the path), or `"charset": "rom-lower"`, or a
125
+ 2,048-byte glyph file named by the check, with or without a two-byte load
126
+ address. A cell's ink is every pixel that is not its majority colour, so no
127
+ background colour is needed; multicolour cells do not decode. The meter's
128
+ cells need glyphs for 0 to 9, F, W and T in the set on screen.
129
+
130
+ The verdict follows the result-byte contract in vice-reference, "Verifying
131
+ a run without a human": `$02FF` = `$01` and a green border on pass, `$02`
132
+ and red on fail.
133
+
134
+ ## Linking KickAssembler into Oscar64
135
+
136
+ Oscar64 has no object linker, and a `.prg` given on its command line is
137
+ ignored ([oscar64-reference](../toolchains/oscar64-reference.md), "Calling
138
+ KickAssembler code from Oscar64"). The old `c64-game-starter`, since removed, fed
139
+ one in that way. The harness uses the placed-blob method that page describes, and
140
+ automates the addresses:
141
+
142
+ 1. KickAssembler assembles `KICK_SRC` with `-binfile -symbolfile`:
143
+ `build/asm.bin` is the raw bytes from the lowest address, no load
144
+ address; `build/<src>.sym` holds every label with its scope.
145
+ 2. `gen-asm-header.py` writes `build/asm.h`: `ASM_ORG` from KickAssembler's
146
+ memory map, `ASM_END` = `ASM_ORG` + the blob's size, `ASM_<LABEL>` for a
147
+ top-level label and `ASM_<SCOPE>_<LABEL>` inside a scope or namespace. It
148
+ refuses, naming both, two labels that give one name (`put_sprite` and
149
+ `Put_Sprite`), and a label that would redefine `ASM_ORG`, `ASM_END`,
150
+ `ASM_SIZE` or `ASM_H`. The `.sym` file is read, not the `-vicesymbols`
151
+ file, because the latter flattens scopes into `loop__0`, `loop__1`,
152
+ names that change with source order.
153
+ 3. The C side places the blob and calls it. Oscar64 expands the macros
154
+ inside `#pragma region` and inside `__asm`, and finds `#embed "asm.bin"`
155
+ through `-i=build`.
156
+
157
+ hello's KickAssembler half, whole:
158
+
159
+ ```asm
160
+ // sprite.asm: sprite 0 to (spr_x, spr_y); the parameters live in the blob.
161
+ * = $0900 "asm"
162
+
163
+ put_sprite:
164
+ lda spr_x
165
+ sta $d000
166
+ lda $d010
167
+ and #$fe
168
+ ldx spr_x+1
169
+ beq !+
170
+ ora #$01
171
+ !: sta $d010
172
+ lda spr_y
173
+ sta $d001
174
+ rts
175
+
176
+ spr_x: .word 0
177
+ spr_y: .byte 0
178
+ ```
179
+
180
+ The header the harness wrote from it, and the C that uses it (from
181
+ `templates/hello/src/main.c`, which `verify:templates` builds):
182
+
183
+ ```text
184
+ #define ASM_ORG 0x0900
185
+ #define ASM_END 0x091f
186
+ #define ASM_SIZE 31
187
+ #if ASM_ORG < 0x0880
188
+ #error "the KickAssembler blob starts below $0880, over the Oscar64 startup code: raise its * = address"
189
+ #endif
190
+ #define ASM_PUT_SPRITE 0x0900
191
+ #define ASM_SPR_X 0x091c
192
+ #define ASM_SPR_Y 0x091e
193
+
194
+ #pragma section( asmcode, 0 )
195
+ #pragma region( asmreg, ASM_ORG, 0x1000, , , { asmcode } )
196
+ #pragma region( main, 0x1000, 0xa000, , , { code, data, bss, heap, stack } )
197
+ #pragma data( asmcode )
198
+ __export const char asm_blob[] = {
199
+ #embed "asm.bin"
200
+ };
201
+ #pragma data( data )
202
+ ...
203
+ SPR_X = x; // *(volatile unsigned *)ASM_SPR_X
204
+ SPR_Y = y;
205
+ __asm { jsr ASM_PUT_SPRITE }
206
+ ```
207
+
208
+ Evidence, rung 1:
209
+
210
+ - `build/hello.map`: `0900 - 1000 : 091f, 001f, asmreg` and
211
+ `0900 - 091f : asm_blob, DATA:asmcode`; `main` starts at `$1000`.
212
+ - `build/hello.asm`: `1118 : 20 00 09 JSR $0900 ; (asm_blob[0] + 0)`.
213
+ - The AUTOPILOT build moves the sprite through the scripted path, reads
214
+ `$D000`, `$D001` and `$D010` back at frame 150, and grades them; the
215
+ screenshots show the green border and the sprite at X 188, lines 117 to
216
+ 137, on PAL and NTSC. Only the KickAssembler routine writes those
217
+ registers, so the call and its arguments arrived.
218
+
219
+ Rules the mechanism brings. The blob lives between `$0880` and `$1000`.
220
+ Below `$0880` it would overlap Oscar64's startup code, which the linker
221
+ allows in silence (a blob at `$0810` linked, and the program never
222
+ started); `asm.h`'s `#error` stops that build with "error 3032: the
223
+ KickAssembler blob starts below $0880". Past `$1000` the link fails with
224
+ "Could not place object". Arguments go through bytes the blob owns, not
225
+ Oscar64's zero page. The compiler's fixed registers start at `$02`
226
+ (`BC_REG_WORK_Y`) and each function's temporaries run from `$43`
227
+ (`BC_REG_TMP`) up by that function's own temp count, past
228
+ `BC_REG_TMP_SAVED` (`$53`): temps above it are saved and restored around
229
+ calls but still live in zero page (`MachineTypes.cpp`, `InterCode.cpp`,
230
+ read). So the top depends on the program; `make zp` reads it from the
231
+ build's listing (see "Zero page a build uses"). An earlier version of this
232
+ paragraph gave `$02` to `$52` as the whole range; hello's code reaches
233
+ `$55`, platformer's `$5B`, shmup-vertical's `$5D`.
234
+ The routine may change A, X and Y. A pure KickAssembler starter leaves
235
+ `C_MAIN` empty and `KICK_SRC` is the whole program.
236
+
237
+ ## Zero page a build uses
238
+
239
+ `zp-used.py` reads the `.asm` listing Oscar64 writes beside the PRG. A
240
+ listed instruction two bytes long that is not immediate and not a branch
241
+ addresses zero page through its second byte; the BASIC stub at
242
+ `$0801`-`$080C`, which the listing decodes as instructions, is skipped.
243
+ It sees the compiled C and inline `__asm`; a KickAssembler blob is data
244
+ in the listing, so its zero page is what its own source says.
245
+
246
+ Measured on 2026-09-23 with the local Oscar64: hello's code touches
247
+ `$0D`-`$11`, `$13`, `$16`, `$19`-`$20`, `$23`-`$24` and `$43`-`$55` (plus
248
+ `$00` from the startup's indexed clear); platformer's reaches `$5B` and
249
+ shmup-vertical's `$5D`. claims-watch agreed on hello: its run stored to
250
+ `$53`-`$55`, outside the `$02`-`$52` it then claimed.
251
+
252
+ ## Text under another YSCROLL
253
+
254
+ `text` and `meter` checks read cells on the grid a screen with YSCROLL 3
255
+ draws (rows start on line 51 + 8r). A panel that starts on another line,
256
+ as the one under a vertically scrolled playfield does (YSCROLL 7, rows on
257
+ line 55 + 8r), is read with `"dy": 4`: the pixel offset below that grid,
258
+ 0 to 7. Measured on a panel at line 215 with YSCROLL 7: with `"dy": 4` the
259
+ score row decoded as written, without it every cell read `?`.
260
+
261
+ ## A fresh disk per run
262
+
263
+ With `SHOT_DISK = 1` each headless run attaches its own copy of
264
+ `build/<name>.d64` (`shots/pal.d64`, `shots/ntsc.d64`), made just before the
265
+ run. VICE writes a save back into the image it attached, so two runs on one
266
+ shared image start from different disks and the pinned shot moves. Measured
267
+ with hello and `SHOT_DISK=1`: two `make shot` runs gave byte-identical
268
+ PNGs and `build/hello.d64` kept its checksum.
269
+
270
+ ## The frame meter
271
+
272
+ `meter/frame_meter.h` (Oscar64) and `meter/frame_meter.asm` (KickAssembler
273
+ macros) implement one contract. The program brackets its frame's work with
274
+ `METER_START` / `METER_STOP` (`FrameMeterStart()` / `FrameMeterStop()`),
275
+ then prints. Work split between a main loop and IRQ handlers is summed:
276
+ `METER_START` ... `METER_PAUSE` as often as needed, `METER_STOP` once a
277
+ frame. Brackets must not nest. The readout is `F<frames> W<worst>
278
+ T<typical>`, five digits each, 20 cells from row 24, column 20.
279
+
280
+ - **Timer.** CIA2 timer A, counting phi2 cycles, force-loaded with `$FFFF`
281
+ at start and stopped before its two bytes are read, as in
282
+ [raster-profile-bars](../recipes/oscar64/raster-profile-bars.md). The
283
+ KERNAL IRQ uses CIA1 timer A and the KERNAL serial routines write CIA1
284
+ timer B (issue #35), so neither collides. CIA2 timer A is the KERNAL's
285
+ RS-232 bit timer: no device 2 while the meter runs. Init masks timer A's
286
+ NMI only (`$DD0D` = `$01`).
287
+ - **What it counts.** Wall time between the two stores: badline and sprite
288
+ DMA steals and any interrupt that lands inside a bracket are in the
289
+ figure. The empty bracket's own count is subtracted: the least of four
290
+ tries at raster line 0, with interrupts off, where no DMA falls. More
291
+ than 65,535 cycles reads 65,535 (the underflow flag in `$DD0D`).
292
+ - **Recording.** The meter records the first `hold` frames (1 to 255) and
293
+ then stops, so a pinned screenshot shows fixed figures and `check.py` can
294
+ require the count. Make `hold` the autopilot script's play frames, so no
295
+ title or idle frame counts.
296
+ - **Worst** is the largest recorded frame. **Typical** is the median of the
297
+ recorded frames, computed when recording stops (0 until then): a cost
298
+ some play frame took, with at least half the frames at or under it. The
299
+ C meter finds it by selection (Wirth's FIND). Its first version sorted
300
+ the samples by insertion, which held the platformer starter's main loop
301
+ for about 94 frames (1.85M cycles) at its 255th play frame; with the
302
+ selection its verdict came about 2M cycles sooner. The KickAssembler
303
+ meter still sorts by insertion (not re-measured here). That
304
+ is the `cycles_per_frame_typical` of
305
+ [CONVENTIONS-techniques](../CONVENTIONS-techniques.md), the frame play
306
+ spends most of its time on, when the recorded frames are play. An
307
+ earlier version used the mean of the last 16 frames: hello's figure was
308
+ then the mean of idle frames after its script, and an alternating load
309
+ read a cost no frame took.
310
+ - **Lost frames are not the meter's job, and are easy to count wrong.**
311
+ The meter reports cost, not lateness: a starter that must not drop a
312
+ frame counts drops itself. Count after the work: when the frame's work
313
+ ends, test whether the next frame's IRQ has already fired (its flag or
314
+ counter), and count that as a lost frame. A check at wake-up for a
315
+ counter that moved by more than one misses every single overrun: work
316
+ that ends just after the next IRQ still sees it move by exactly one.
317
+ Measured on shmup-vertical 7974a7a: one frame made ~2,400 cycles late
318
+ left the program's `wait_frame` counter at `OVERRUNS 00`, and a detector
319
+ that tests the frame flag when the work ends found NTSC joystick play
320
+ losing a frame in 6 of 15 runs. The demo's frame slot, which must end
321
+ before a split line, reads the raster when its work ends instead.
322
+ - **Build switch.** `FRAME_METER` defaults to `AUTOPILOT`. Without it every
323
+ macro is empty and the release carries none of the meter.
324
+ - **Interrupts.** The KERNAL serial routines end in `CLI`: the ROM bytes at
325
+ `$EDAB`, `$EDB5`, `$EDDB` and `$EE82` are `58 60` or `58 18` (read from
326
+ `kernal-901227-03.bin`). A program that runs with the KERNAL IRQ off must
327
+ `SEI` again after any disk call, or that IRQ lands inside its brackets.
328
+
329
+ Calibration, rung 1, C and KickAssembler, PAL and NTSC:
330
+
331
+ | Bracketed code | Cycles by arithmetic | Read |
332
+ |---|---|---|
333
+ | `ldx #200` / `dex` / `bne` | 2 + 199 x 5 + 4 = 1,001 | `W01001 T01001` |
334
+ | A 12-cycle table lookup (`lda abs`, `and #3`, `tay`, `ldx abs,y`) replacing `ldx #`, then `inc abs`: 1,017 for 200, 517 for 100, one frame in four at 200 | 1,001 - 2 + 12 + 6 = 1,017; 501 - 2 + 12 + 6 = 517 | `W01017 T00517` over 48 frames |
335
+ | Two brackets a frame, 1,001 and 501, untimed work between | 1,502 | `W01502 T01502` |
336
+
337
+ The C meter's `meter_init` started at raster lines `$33`, `$37`, `$60`,
338
+ `$91` and `$F8` (badlines among them) read the same `W01017 T00517` each
339
+ time. The review of this harness found that the earlier single calibration
340
+ could land on DMA and read 5 cycles low; that is what the line-0 minimum
341
+ fixes. The same review saw W move between 1,510 and 1,538 cycles, in steps
342
+ of 14, with code layout alone, which it put down to branches crossing pages
343
+ (not re-measured here): compare two builds' W knowing that.
344
+
345
+ hello's figures: worst 194, typical 172 cycles (195 and 173 since the
346
+ selection changed the meter's code layout); hello-kick's: worst 178,
347
+ typical 154; each over the script's 144 play frames and the same on PAL and
348
+ NTSC. Both bracket from raster line 250, below the last badline (`$F7`),
349
+ and the sprite is on lines 117 to 137, so no DMA falls in the bracket. The
350
+ grading at frame 150 runs after `METER_STOP` and is in neither figure.
351
+
352
+ ## The plan gate
353
+
354
+ `hooks/plan-gate.py` passes `PLAN.md` when it has no `FILL:` line left,
355
+ holds check-compatibility's output (a `# Compatibility: a + b` line and its
356
+ `**Verdict:**` line) and plan-budget's (`# Budget plan:`, `Techniques:`, a
357
+ `## play (` section with its `Range` line) for the same techniques, and
358
+ lists each of them as a row of its Techniques table. With `C64KB`
359
+ reachable, `make` also re-runs check-compatibility on the pasted names and
360
+ wants the same Verdict line; the result is cached on `PLAN.md`'s hash.
361
+
362
+ Every PRG depends on the gate, so `make`, `shot`, `check`, `selftest`,
363
+ `disk`, `claims` and `run` all stop while it fails. As a PreToolUse hook it
364
+ blocks (exit 2) an Edit, MultiEdit, Write or NotebookEdit under `src/`,
365
+ after resolving the path with realpath. `make PLAN_GATE=off` is the
366
+ deliberate override. It replaces the old starters' `.kb-briefing-done`
367
+ marker, which `touch` satisfied.
368
+
369
+ Measured: two hand-typed heading lines fail it; a pasted Verdict changed
370
+ from WARNINGS to COMPATIBLE fails the re-run; a Write to `lib/../src/x.c`
371
+ and one under a `CLAUDE_PROJECT_DIR` with a trailing slash are blocked;
372
+ hello's plan passes. It cannot catch outputs edited by hand into the right
373
+ shape with the right verdict, or a write to `src/` made through a shell
374
+ command, which the hook never sees.
375
+
376
+ ## make claims
377
+
378
+ When `$(C64KB)/scripts/claims-watch.ts` exists, `make claims` runs it from
379
+ the c64-kb checkout over the AUTOPILOT PRG with the starter's
380
+ `CLAIMS_ARGS`; otherwise it prints that the script is not available and
381
+ exits 0. The script lands with issue #22 step 6 and is not on this branch.
382
+ Run against the copy on the `onto22-watch` branch, hello first failed:
383
+ Oscar64's zero page and the `$FF` store to `$DC00` were undeclared, and so
384
+ was the meter's one `$DD0D` store, which claims-watch counts against
385
+ `cia2_timer_b` and `cia2_tod` as well as `cia2_timer_a`. With
386
+ `zero_page $02-$52` and `cia1_port_a` claimed and all three CIA2 units
387
+ declared as harness, hello and hello-kick both reported `PASS: 0 stores in 0
388
+ violation groups`. Against main's claims-watch on 2026-09-23 hello failed
389
+ again: 309 stores to `$53`-`$55` outside the claim, and the KERNAL IRQ's
390
+ zero-page stores with no routine declared. Its claim is now
391
+ `zero_page $02-$55` with `--kernal IRQ`, and `make claims` reports `PASS: 0
392
+ stores in 0 violation groups`.
393
+
394
+ ## End-to-end transcript
395
+
396
+ A project made from hello outside the repository, then each target in
397
+ turn. The last lines of each:
398
+
399
+ ```text
400
+ $ npm run new-project -- hello <scratch>/mygame
401
+ PASS PAL frame meter, the script's 144 play frames: frames 144, worst 194, typical 172 cycles (CIA2 timer A; limit 19656)
402
+ PASS NTSC frame meter, the script's 144 play frames: frames 144, worst 194, typical 172 cycles (CIA2 timer A; limit 17095)
403
+ check: 15 of 15 passed
404
+ new-project: ready. The starter's plan is now PLAN-hello-example.md; PLAN.md is blank.
405
+ $ make shot check # the blank plan
406
+ plan-gate: the plan does not pass, so nothing is built.
407
+ 11 FILL: placeholder(s) left
408
+ $ cp PLAN-hello-example.md PLAN.md; make
409
+ oscar64 -tm=c64 -O2 -i=<project>/build -i=<project>/harness/meter -o=build/hello.prg src/main.c
410
+ $ make selftest
411
+ selftest: PASS, check.py rejected the FORCE_FAULT build
412
+ $ make disk
413
+ 0 "hello " 01 2a
414
+ 10 "hello" prg
415
+ 654 blocks free.
416
+ $ make claims # C64KB = this branch
417
+ claims: not available. <c64-kb>/scripts/claims-watch.ts does not exist (it lands in c64-kb with issue #22 step 6).
418
+ claims: set C64KB=/path/to/c64-kb to a checkout that has it. Nothing was checked.
419
+ $ make claims C64KB=<a checkout of onto22-watch>
420
+ PASS: 0 stores in 0 violation groups
421
+ $ npm run verify:templates -- --selftest # from this repository
422
+ verify-templates: 2 of 2 starters passed
423
+ ```
424
+
425
+ The FORCE_FAULT build fails four checks on both models, not only its own verdict: the
426
+ border and verdict text, and the sprite's box and solidity, because it ends
427
+ at X 189. The disk image boots: `x64sc -autostart build/hello.d64` for
428
+ 25,000,000 cycles on PAL showed `HELLO HARNESS` on row 1. The shots are
429
+ stable: hello's and hello-kick's PAL pictures at 7,000,000 and 8,000,000
430
+ cycles, and their NTSC pictures at 8,000,000 and 12,000,000, were identical
431
+ pixel for pixel, because nothing on screen changes after the grade.
432
+
433
+ ## Writing a starter
434
+
435
+ 1. Make a project from `hello` (C with a KickAssembler part) or
436
+ `hello-kick` (KickAssembler alone) under `templates/<name>`, or copy one.
437
+ 2. Fill `PLAN.md` from `game-briefing`, `check-compatibility` and
438
+ `plan-budget` before any code.
439
+ 3. Give the program an AUTOPILOT script that plays from its first frame, a
440
+ verdict after the script that reads real state back, outside the
441
+ meter's bracket, and a FORCE_FAULT that turns it red and moves something
442
+ a check can see.
443
+ 4. Keep row 24, columns 20 to 39 free in AUTOPILOT builds. Set the meter's
444
+ `hold` to the script's play frames. Bracket the whole frame's work,
445
+ summing IRQ work with `METER_PAUSE`.
446
+ 5. Write `expect.json`: the verdict, the text, a `sprite` or `rect` or
447
+ `pixel` check for each feature, a `same` area, the meter with `frames`.
448
+ 6. Pin `SHOT_CYCLES_*` after the verdict, where the screen no longer
449
+ changes; prove it with two pins.
450
+ 7. `make shot check selftest disk`, then `npm run verify:templates --
451
+ --only <name> --selftest`.
452
+
453
+ ## Not measured here
454
+
455
+ - The settings.json hook wrapper string was not executed by Claude Code in
456
+ this session; `plan-gate.py` itself was run in hook mode with sample tool
457
+ calls.
458
+ - A starter that uses `SHOT_DISK=1`, `DISK_FILES` or IRQ work inside the
459
+ meter's brackets. hello and hello-kick use none of them; the review ran
460
+ `SHOT_DISK=1` on hello and it passed.
461
+ - Reads of `$D41B` and `$D41C` under `+sound`. An earlier version of this
462
+ page repeated issue #2's claim that the dummy sound driver breaks them;
463
+ the review read 16 different values from a noise voice under the pinned
464
+ command, so the claim is withdrawn, not replaced.
465
+ - Any VICE other than 3.10, or a palette other than `-default`; `check.py`
466
+ matches exact triples and would fail closed.
467
+ - The released Oscar64 (issue #25): the starters were built with the
468
+ build `CLAUDE.md` names.
469
+ - Real hardware.
470
+
471
+ ## See also
472
+
473
+ - [vice-reference](../runtime/vice-reference.md), "Reading the exit screenshot" and "Verifying a run without a human"
474
+ - [oscar64-reference](../toolchains/oscar64-reference.md), "Calling KickAssembler code from Oscar64"
475
+ - [release-disk](../toolchains/release-disk.md), for a release image
476
+ - Recipes: [oscar64/headless-verify](../recipes/oscar64/headless-verify.md),
477
+ [kickassembler/headless-verify](../recipes/kickassembler/headless-verify.md),
478
+ [oscar64/raster-profile-bars](../recipes/oscar64/raster-profile-bars.md)
package/package.json ADDED
@@ -0,0 +1,105 @@
1
+ {
2
+ "name": "c64-kb",
3
+ "version": "0.17.0",
4
+ "description": "Commodore 64 knowledge base — CLI + MCP server with Qdrant vectors + FalkorDB graph",
5
+ "license": "BSD-3-Clause",
6
+ "type": "module",
7
+ "main": "dist/cli.js",
8
+ "bin": {
9
+ "c64-kb": "dist/cli.js"
10
+ },
11
+ "scripts": {
12
+ "build": "tsc -p tsconfig.build.json",
13
+ "dev": "node src/cli.ts",
14
+ "dev:serve": "node src/cli.ts serve",
15
+ "services": "docker compose up -d",
16
+ "services:stop": "docker compose down",
17
+ "start": "node dist/cli.js",
18
+ "ingest": "node src/ingest.ts",
19
+ "ingest:force": "node src/ingest.ts --force",
20
+ "ingest:clean": "node src/ingest.ts --clean",
21
+ "memorize:audit": "node src/cli-memorize-audit.ts",
22
+ "feedback:log": "node src/tools/feedback.ts",
23
+ "check:listings": "node scripts/check-listings.ts",
24
+ "check:pitfall-anchors": "node scripts/check-pitfall-anchors.ts",
25
+ "graph:report": "node scripts/graph-report.ts",
26
+ "vice:headless": "sh scripts/build-vice-headless.sh",
27
+ "verify:recipes": "node scripts/verify-recipes.ts",
28
+ "verify:templates": "node scripts/verify-templates.ts",
29
+ "new-project": "node scripts/new-project.ts",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest",
32
+ "typecheck": "tsc -p tsconfig.json",
33
+ "prepack": "npm run build",
34
+ "health": "node src/cli.ts health",
35
+ "test:unit": "vitest run --project unit",
36
+ "test:integration": "vitest run --project integration",
37
+ "lint": "eslint --max-warnings=0 .",
38
+ "lint:fix": "eslint --fix .",
39
+ "format": "prettier --write .",
40
+ "format:check": "prettier --check .",
41
+ "knip": "knip"
42
+ },
43
+ "dependencies": {
44
+ "@modelcontextprotocol/sdk": "^1.29.0",
45
+ "@qdrant/js-client-rest": "^1.19.0",
46
+ "better-sqlite3": "^12.10.0",
47
+ "commander": "^14.0.3",
48
+ "falkordb": "^6.6.2",
49
+ "zod": "^4.4.3"
50
+ },
51
+ "devDependencies": {
52
+ "@eslint/js": "^10.0.1",
53
+ "@tsconfig/node24": "^24.0.5",
54
+ "@types/better-sqlite3": "^7.6.13",
55
+ "@types/node": "^25.8.0",
56
+ "eslint": "^10.11.0",
57
+ "eslint-config-prettier": "^10.1.8",
58
+ "eslint-plugin-sonarjs": "^4.2.1",
59
+ "knip": "^6.37.0",
60
+ "lefthook": "^2.1.14",
61
+ "prettier": "^3.9.8",
62
+ "typescript": "^6.0.3",
63
+ "typescript-eslint": "^8.70.1",
64
+ "vitest": "^4.1.6"
65
+ },
66
+ "engines": {
67
+ "node": ">=24.12"
68
+ },
69
+ "files": [
70
+ "dist",
71
+ "docs",
72
+ "templates",
73
+ "VERSION",
74
+ "CHANGELOG.md",
75
+ "docker-compose.yml"
76
+ ],
77
+ "exports": {
78
+ "./package.json": "./package.json"
79
+ },
80
+ "publishConfig": {
81
+ "access": "public"
82
+ },
83
+ "repository": {
84
+ "type": "git",
85
+ "url": "git+https://github.com/bdgscotland/c64-kb.git"
86
+ },
87
+ "allowScripts": {
88
+ "better-sqlite3": true,
89
+ "fsevents": false,
90
+ "lefthook": false
91
+ },
92
+ "keywords": [
93
+ "commodore-64",
94
+ "c64",
95
+ "6502",
96
+ "mcp",
97
+ "model-context-protocol",
98
+ "knowledge-base",
99
+ "retro"
100
+ ],
101
+ "homepage": "https://github.com/bdgscotland/c64-kb#readme",
102
+ "bugs": {
103
+ "url": "https://github.com/bdgscotland/c64-kb/issues"
104
+ }
105
+ }
@@ -0,0 +1,91 @@
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
+ ## Before any code
15
+
16
+ 1. Brief: `npx tsx src/cli.ts game-briefing "<concept>" --archetype <name>`
17
+ (or `demo-briefing`), in the c64-kb checkout. Read what it proposes.
18
+ 2. For each technique you keep: `technique-lookup <name>` and
19
+ `pitfalls-for <name>`. Start from the recipe it names (`recipe-lookup`).
20
+ 3. Fill `PLAN.md`: paste the whole output of `check-compatibility` and of
21
+ `plan-budget` (same techniques) into their sections, list every technique
22
+ in its table, and replace every `FILL:` line.
23
+
24
+ Until `PLAN.md` passes, a hook blocks Edit and Write under `src/`, and every
25
+ make target that builds stops (`make plan-gate` says what is missing). With
26
+ C64KB set, `make` re-runs `check-compatibility` and wants the pasted Verdict.
27
+ The gate cannot see writes made through a shell command, or outputs edited
28
+ into shape by hand: do neither. `make PLAN_GATE=off` overrides it; say why in
29
+ `PLAN.md` if you do.
30
+
31
+ ## The loop
32
+
33
+ ```bash
34
+ make # build build/<name>.prg
35
+ make shot check # autopilot build, headless PAL and NTSC, graded by expect.json
36
+ make selftest # the FORCE_FAULT build must fail the same checks
37
+ make disk # build/<name>.d64
38
+ make claims # every store the program makes, against what it declares
39
+ make run # windowed VICE, for a human
40
+ ```
41
+
42
+ ## Rules
43
+
44
+ - Build before claiming. Code that has not built is not done.
45
+ - Measure screenshots with `check.py` through `expect.json`, never by eye.
46
+ Every visible claim gets a check. Add one before you trust a change.
47
+ - PAL and NTSC: both shots pass, or it is not done.
48
+ - Name the rung for every number: measured here (`make shot`, the meter, the
49
+ VICE monitor), taken from a c64-kb page (say which), arithmetic, or not
50
+ measured. Never call something verified that was not run.
51
+ - Frame cost comes from the meter: CIA2 timer A, printed as
52
+ `F<frames> W<worst> T<typical>` at row 24, columns 20 to 39, in AUTOPILOT
53
+ builds. It records the first `hold` frames: make that the autopilot
54
+ script's play frames. Typical is the median of those frames, the KB's
55
+ `cycles_per_frame_typical`. Keep grading, logging and printing outside the
56
+ bracket; work split between the main loop and IRQs is summed with
57
+ `METER_PAUSE` / `METER_START`.
58
+ - Do not invent a register, routine or address. Look it up:
59
+ `lookup-register`, `lookup-kernal`, `memory-map`.
60
+ - Lint every source you change: `npx tsx src/cli.ts lint <file>`.
61
+ - Commit named paths only. Never `git add -A` or `git add .`. `build/`,
62
+ `shots/` and `local.mk` are never committed.
63
+
64
+ ## Harness facts you will need
65
+
66
+ - `AUTOPILOT=1` builds read a scripted joystick byte instead of `$DC00` and
67
+ grade themselves: `$02FF` = `$01` and a green border on pass, `$02` and red
68
+ on fail. `FORCE_FAULT=1` must turn the verdict red and move something a
69
+ screenshot check can see.
70
+ - Screenshot geometry (c64-kb `docs/runtime/vice-reference.md`): PAL 384 x 272,
71
+ row = raster line - 16; NTSC 384 x 247, row = line - 28; x = VIC X + 8. A
72
+ sprite at Y register y is drawn from line y + 1.
73
+ - `check.py` reads text in the ROM character set unless a check names a
74
+ `charset` file; the meter's cells need 0-9, F, W and T in the set on screen.
75
+ - A KickAssembler part called from C is a raw blob at its own `* =` address,
76
+ `$0880` or above; `build/asm.h` gives C its labels as `ASM_<LABEL>`
77
+ (`ASM_<SCOPE>_<LABEL>` inside a scope). Pass arguments through bytes in the
78
+ blob, not Oscar64's zero page (`$02` up; the top depends on the program:
79
+ `make zp` lists what the build's code touches).
80
+ - The meter takes CIA2 timer A. Do not open RS-232 (device 2) while it runs.
81
+ - The KERNAL serial routines end in `CLI` (ROM bytes `58 60` / `58 18` at
82
+ `$EDAB`, `$EDB5`, `$EDDB`, `$EE82`). After any disk call, `SEI` again if
83
+ the program runs with the KERNAL IRQ off: otherwise that IRQ lands inside
84
+ the meter's brackets and rewrites `$DC00`.
85
+
86
+ ## Calling c64-kb
87
+
88
+ - CLI, from the c64-kb checkout (`C64KB` in `local.mk`):
89
+ `npx tsx src/cli.ts <command>`; `npx tsx src/cli.ts --help` lists them.
90
+ - MCP: `.mcp.json` starts `node <c64-kb>/dist/cli.js serve` (run
91
+ `npm run build` in c64-kb first).