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
package/CHANGELOG.md ADDED
@@ -0,0 +1,2082 @@
1
+ # Changelog
2
+
3
+ Versions are in `VERSION` (data, schema, tool surface) and `package.json`.
4
+ Entries below start at the first public audit; earlier history is in git.
5
+
6
+ ## Unreleased
7
+
8
+ Data 771, schema 31, tools 2.3.1, package 0.17.0.
9
+
10
+ **Licence pass before npm publishing (data 771).** A measured check of
11
+ `docs/` found no copied prose (runs of 25 or more words shared with 108
12
+ cited sources and the classic references are number tables only) and no
13
+ substantial third-party code. Four fixes. `wireframe-ships` reproduced
14
+ Elite's 32 two-letter name tokens (QQ16), commercial game data; it now
15
+ uses its own table of the same shape, so its systems print GUBUDUIS ...
16
+ NEYA instead of TIBEDIED ... LAVE; seeds, coordinates and every cycle
17
+ count are unchanged, re-verified in VICE on both models (0 pixels from
18
+ the model). Three examples in `kickassembler-reference.md` (the SID
19
+ player, `ClearScreen`, `mov`) followed the KickAssembler manual line for
20
+ line; they are rewritten and now share no 8-word run with it, and the
21
+ new SID player was run in VICE against a test tune (one `play` per PAL
22
+ frame). `oscar64-headers-reference.md` said `license: MIT`; Oscar64 is
23
+ GPL-3.0. The SID ADSR table now names its source.
24
+
25
+ **npm package (package 0.17.0).** An installed package could not do
26
+ anything useful: batch ingest existed only as an npm script in a clone,
27
+ `docker-compose.yml` was not shipped, and state was written inside the
28
+ package folder. `c64-kb ingest` and `c64-kb services up|down|status` now
29
+ exist, and state goes to `$XDG_DATA_HOME/c64-kb` (or
30
+ `~/.local/share/c64-kb`, or `C64_KB_DATA_DIR`) when the package is under
31
+ `node_modules`; a clone still uses `data/`. CI installs the packed
32
+ tarball into an empty folder and runs services, ingest and a lookup. A
33
+ release workflow publishes on a `v*` tag; the first publish and the
34
+ licence check are open in #52.
35
+
36
+ **A routed game briefing names its starter (tools 2.3.1, package
37
+ 0.16.1).** `c64_game_briefing` with no `archetype` routes by the brief's
38
+ words, but its query did not select `a.starter`, so a routed briefing
39
+ never printed the `new-project` command. Naming the archetype did. The
40
+ route now carries the starter, and a test in `test/briefings.test.ts`
41
+ failed before the fix.
42
+
43
+ **Every #39 starter is named by its archetype.** `**Starter:**` lines for
44
+ `text_adventure` (adventure), `beat_em_up` (beat-em-up) and `demo_intro`
45
+ (demo), now that those starters are on main; `c64_game_briefing` and
46
+ `c64_demo_briefing` print their `new-project` command.
47
+
48
+ **Issue #39: `shmup-vertical` loses no frames on NTSC.**
49
+ - The lost-frame counter could not see a single late frame: it counted
50
+ frame-counter steps other than 1. It now checks the frame flag before
51
+ waiting.
52
+ - With it, NTSC play lost frames at play frames 282-321 and 454-477,
53
+ which the staged run never reached. The heaviest steps moved to
54
+ KickAssembler, and the latest end of work is now line 256 of 263 on
55
+ NTSC.
56
+ - `make joytest` plays 16 games per model with fire held and sweeping,
57
+ and fails on any lost frame. `make longplay` plays about 40,000 frames
58
+ per model with an invulnerable ship. Both run 0 lost.
59
+
60
+ **Issue #39: the `beat-em-up` starter lands; `lane_depth_engine`
61
+ corrected (data 769).**
62
+ - `templates/beat-em-up` is a three-stage street brawler in Oscar64 plus
63
+ KickAssembler:
64
+ - fighters of two sprites each in a band written near to far;
65
+ - a brute drawn in characters, with `$D01B` behind bits;
66
+ - attacks gated by lane and per-frame boxes;
67
+ - round-robin AI, and a tune with effects.
68
+ - It checks itself with a flicker check that renders every part from the
69
+ art, a VIC register read-back every frame, an independent hit re-check
70
+ and a game-over check. It passes on the local Oscar64 and on v1.32.273.
71
+ - Measured worst 14,960 / 9,359 PAL and 16,464 / 9,897 NTSC.
72
+ - The review measured that a Y-sorted multiplexer draws the farther
73
+ actor in front. `techniques/logic.md` `lane_depth_engine` said the
74
+ depth and raster orders agree; step 3 and "More actors" now say they
75
+ are opposite, with a correction clause.
76
+
77
+ **agent-harness: counting lost frames.** The meter reports cost, not
78
+ lateness, and the page did not say how to count a dropped frame. A check
79
+ at wake-up for a frame counter that moved by more than one misses every
80
+ single overrun (shmup-vertical 7974a7a: a frame made ~2,400 cycles late
81
+ left `OVERRUNS 00`); the page now says to test the next frame's flag when
82
+ the work ends.
83
+
84
+ **Issue #39: `shmup-vertical` gets enemy fire and a per-frame bullet
85
+ check.**
86
+ - Darts, weaves and swoops fire dots that drift towards the ship, from
87
+ a 6-dot pool in a fire window at Y 72-140. The dots' step, the
88
+ bullet draw list, the enemy boxes and the path step moved to
89
+ KickAssembler: the staged worst had reached 17,882 NTSC cycles, over
90
+ the frame.
91
+ - Staged worst now 15,991 PAL / 16,136 NTSC, with no frame lost; graded
92
+ run 12,912 / 13,015.
93
+ - Each bullet cell is read back against the map after every erase.
94
+ - `make joytest` plays to game over, reboots on the same disk and
95
+ requires the saved high score.
96
+ - It passes on the released Oscar64 v1.32.273.
97
+
98
+ **`verify:templates --selftest` runs each starter's own proof targets
99
+ (#42).** Several #39 fixes are proved only by a starter's own target: the
100
+ adventure's save validation by `disktest`, the platformer's scroll timing
101
+ by `tearcheck`, the demo's stable entry by `probe`. A starter lists them in
102
+ `VERIFY_TARGETS`; `--selftest` runs each after `make selftest`. Seven
103
+ starters with their targets: 7 of 7.
104
+
105
+ **Issue #39: `platformer` hardened after the other session's
106
+ comparison.**
107
+ - It builds and passes on the released Oscar64 v1.32.273, with
108
+ `surface_at` kept out of line (#30) and the score printed through
109
+ `put_digits`. v1.32.273 dropped digits from a loop; that fault is not
110
+ reduced yet.
111
+ - The live-enemy limit is 5: six live enemies overran the NTSC frame
112
+ (17,618 cycles staged). `make stage` fills every slot.
113
+ - `check_frame` checks four invariants every frame, each with its own
114
+ fault bit. The slope bit caught a mutation that the tear check missed.
115
+ - Hitboxes come per animation frame, with a group and a mask; the stomp
116
+ is a feet box on the falling frame.
117
+ - `tools/drive.py` runs at real speed and on a free port.
118
+
119
+ **Issue #39: `action-puzzle` hardened after the other session's
120
+ comparison.**
121
+ - The redraw is bounded. An overflowing dirty list used to redraw 280
122
+ cells in one frame (55,305 cycles); rows are now queued, two a frame.
123
+ - The right roll, the restart path over three lives, the high-score
124
+ read-back and the once-per-scan check are all gated. Each is proved
125
+ by a mutation.
126
+ - Dropped frames are counted from the `$D019` raster latch.
127
+ - It builds and passes on the released Oscar64 v1.32.273.
128
+ - Staged worst frame (16 boulders falling in one slice): 13,619 PAL /
129
+ 13,832 NTSC cycles.
130
+
131
+ **Issue #39: the `demo` starter lands, and the two stub skeletons are
132
+ removed.** `templates/demo` is pure KickAssembler:
133
+ - a part table with init, update, out step and teardown, and a
134
+ table-driven IRQ chain;
135
+ - a stable double-IRQ raster-bar kernel, a sprite sine chain, a
136
+ scroller, and an original tune with NTSC tempo skips.
137
+
138
+ It checks itself on PAL and NTSC with 229 screenshot checks, 8
139
+ jittered probe shots of the bar kernel, dispatcher counters (late and
140
+ bad frames), a deadline test on the frame slot, and a SID store trace
141
+ (`make audio`). Measured worst 7,332 / typical 6,586 cycles on PAL.
142
+ `templates/c64-demo-starter` and `templates/c64-game-starter` are
143
+ removed. The game starter fed a `.prg` to Oscar64 as source, which
144
+ Oscar64 ignores.
145
+
146
+ **Issue #39: the `adventure` starter, STARWATCH.** It is a 12-room text
147
+ adventure in Oscar64:
148
+ - the world is data in `tools/world.py`, and a Python model checks the
149
+ game line by line;
150
+ - a two-word parser with synonyms;
151
+ - text packed by byte-pair coding, 40% smaller;
152
+ - picture strips coded row by row;
153
+ - one window line printed per frame;
154
+ - SAVE and LOAD on drive 8, with the record versioned from the world.
155
+
156
+ Measured in VICE x64sc 3.10:
157
+ - worst 15,272 / typical 8,543 cycles on PAL; 15,488 / 8,842 on NTSC;
158
+ - `make disktest` saves, cold-resets and loads under true 1541
159
+ emulation, and refuses three bad saves.
160
+
161
+ Its review found a picture that overran the frame. `gen.py` now refuses
162
+ a script that does not show every picture. The other #39 session's
163
+ comparator chose this version as the base and its disk extras were
164
+ ported.
165
+
166
+ **Harness: `make released`, and the keypad joystick on `make run` (#39).**
167
+ The starters are verified with a patched Oscar64 (#25) while a downstream
168
+ agent has a release. `make released OSCAR64_RELEASED=<path>` builds the
169
+ autopilot program with that compiler and grades its PAL and NTSC shots
170
+ with the starter's own `expect.json`. On v1.32.273 it found the platformer
171
+ graded 7 of 23: `surface_at` inlined into `surface_walk` reads the slope
172
+ table with a stale X (listings on #30; `__noinline` passes 23 of 23).
173
+ action-puzzle graded 41 of 41. `make run` now passes `-joydev2 1`, so the
174
+ numeric keypad is joystick 2.
175
+
176
+ **Issue #39: one harness, and the briefing names the starter.** Two
177
+ sessions built #39 in parallel; the maintainer asked for one harness, the
178
+ best of both. Main's harness stays; four #42 items from the other build
179
+ are now in it:
180
+ - text and meter checks take `"dy"` (0-7 pixels) for a panel under a
181
+ scrolled playfield, which the YSCROLL-3 grid could not read;
182
+ - with `SHOT_DISK = 1` each headless run gets its own copy of the D64,
183
+ since VICE writes a save back into the image and the next run then
184
+ started from another disk (hello: two shots byte-identical, the release
185
+ D64 unchanged);
186
+ - `make zp` lists the zero page a build's C touches, from Oscar64's
187
+ listing. The pages said Oscar64 owns `$02`-`$52`; its temporaries run
188
+ from `$43` up by each function's temp count, and hello reaches `$55`,
189
+ platformer `$5B`, shmup-vertical `$5D`. hello's claim `$02`-`$52` failed
190
+ `make claims` (309 stores to `$53`-`$55`, KERNAL IRQ undeclared); it is
191
+ now `$02`-`$55` with `--kernal IRQ` and passes;
192
+ - `check.py` finds the character ROM in the repo's headless VICE, the
193
+ only copy on a CI runner.
194
+
195
+ A `**Starter:**` line under an archetype becomes the Archetype's
196
+ `starter` property (schema 31). `c64_game_briefing` and
197
+ `c64_demo_briefing` return it as `archetype.starter` and print the
198
+ `npm run new-project` command (tools 2.3.0: an added output field). A
199
+ test fails when a page names a starter with no Makefile and expect.json.
200
+ Lines for vertical_shmup, scrolling_platformer and puzzle.
201
+
202
+ `mixed_sprite_char_actors` had a measured Cost line and no
203
+ `**Cost measured on:**` line, so `plan-budget` printed "recipe not
204
+ stated"; it names `oscar64-mixed-fighters` now.
205
+
206
+ **Issue #39: the `shmup-vertical` starter.** It is a vertical shooter:
207
+ - Oscar64 game logic, with a KickAssembler IRQ chain, panel split,
208
+ multiplexer, row copy and music player;
209
+ - the playfield scrolls through all eight YSCROLL phases above a fixed
210
+ panel;
211
+ - waves on paths, character bullets, hitboxes per sprite frame, effects
212
+ on voice 3, and a disk high score.
213
+
214
+ Measured in VICE x64sc 3.10:
215
+ - worst 12,472 / typical 7,103 cycles on PAL; 12,721 / 7,293 on NTSC;
216
+ - the staged heaviest frame (`make stage`) is 14,073 PAL / 14,740 NTSC;
217
+ - `make phases` compares the panel at all eight phases.
218
+
219
+ Its review found that sprites on badlines during KERNAL serial I/O hang
220
+ a save in VICE (#43).
221
+
222
+ **Candidate list, batch 17, two of four: the tech-tech wobbler and DYSP,
223
+ from fixed designs with measured write-cycle sweeps (data 764).** The
224
+ tech-tech wobbler: a badline forced on every line of a six-row logo band
225
+ after the cycle-14 RC check, so the VIC refetches the video matrix each
226
+ line from whichever of eight pre-shifted screens `$D018` names, plus
227
+ XSCROLL for the remainder; the logo's left edge moves 62 pixels across
228
+ the band exactly as the sine table says, on both models; the sweep over
229
+ five write placements shows the one-early case resetting RC on every
230
+ line and the late cases losing one cell per cycle; the FLI-bug strip's
231
+ three cells and their colour are tabled; the XSCROLL-only control swings
232
+ seven pixels; 3,405 cycles a frame for the band. DYSP: four sprites at
233
+ different heights inside the opened right side border, each on its own
234
+ sine, with the border-opening write timed per line from a table indexed
235
+ by the SET of sprites active on that line; the border stays open on all
236
+ 150 band lines and every write lands on the same cycle whatever the set.
237
+ A table indexed by the COUNT of active sprites cannot do it, measured:
238
+ two cycles a sprite closes the border from the first line with a
239
+ non-zero sprite alone, three and four cycles close it earlier, and the
240
+ plain side-border timing closes all 150 lines. Pins byte-identical on two
241
+ runs per model, both reproduced by reviewers who also confirmed the
242
+ effect in their own pictures. Linecrunch and Kefrens bars, the other two
243
+ of the batch, stalled six times each on the workflow's watchdog and are
244
+ being rebuilt as standalone runs.
245
+
246
+ **Issue #39: the `platformer` starter.** It is a side-scrolling game in
247
+ Oscar64 with a KickAssembler part:
248
+ - a 2,048 px tile level with three screen pages;
249
+ - the next page is prepared five rows a frame and flipped in the
250
+ vertical blank;
251
+ - slopes, ledges and 8.8 jumps;
252
+ - walkers and hoppers wake in an activation window;
253
+ - a HUD under a raster split, and a tune.
254
+
255
+ Measured in VICE x64sc 3.10:
256
+ - worst frame 12,564 / typical 7,042 cycles on PAL; 12,991 / 7,443 on
257
+ NTSC;
258
+ - `make tearcheck` compares mid-play shots with the level and catches a
259
+ torn build.
260
+
261
+ Its review found Oscar64 fault 7 (#30; now in CLAUDE.md and
262
+ `oscar64-reference`). The harness also changed:
263
+ - claims-watch now recognises a JSR push logged after an IRQ entry;
264
+ - the meter finds its median by selection, not by sorting.
265
+
266
+ **Issue #39: the `action-puzzle` starter, CAVE RUN.** It is a Boulder
267
+ Dash-style game in Oscar64:
268
+ - the cave scan runs a quarter per frame;
269
+ - two RLE caves are decoded between levels;
270
+ - enemies follow walls;
271
+ - a two-voice tune plays, with effects on voice 3;
272
+ - a high-score table is saved to drive 8.
273
+
274
+ Measured in VICE x64sc 3.10:
275
+ - worst frame 10,033 cycles and typical 6,340 on PAL; 10,292 and 6,598
276
+ on NTSC;
277
+ - `make disktest` saves twice under true 1541 emulation, then cold-boots
278
+ and loads the table back, on PAL and NTSC;
279
+ - `make joy` with `tools/drive.py` plays the normal build headless.
280
+
281
+ **Candidate list, batch 16: four items from fixed designs, each a
282
+ technique entry and a pinned KickAssembler recipe (data 763).** The
283
+ sprites-only screen mode: the display enable bit held clear through line
284
+ 48 so no badline occurs all frame, set for line 51 so the vertical
285
+ border flip-flop resets, and the select bit toggled around line 251 so
286
+ it never sets again; eight sprites drawn at every height from line 8 to
287
+ the frame wrap, a free-CPU meter reading 904 iterations of a 20-cycle
288
+ loop per PAL frame against 847 with a normal display (the badline and
289
+ border cost by subtraction), the closed-border control hiding three
290
+ sprites and the display-off-only control showing none. BASIC ROM
291
+ floating-point routines called from machine code, every entry point
292
+ read from the 901226-01 ROM image with the monitor before it was used:
293
+ square root of two, 355 over 113, 0.1 plus 0.2 and the five bytes of
294
+ one tenth printed and compared against asserted strings, FMULT 1,079
295
+ cycles, FDIV 2,409, FSQR 43,752 and FOUT 7,412 with the display off, the
296
+ zero-page bytes the sequence changes listed, and the same calls with
297
+ BASIC banked out as the control. Depth-sorted sprite vector balls: eight
298
+ balls on a tilted ring, a single bubble pass per frame assigning sprite
299
+ numbers by depth so the hardware's fixed priority draws the nearer ball
300
+ on top (1,318 cycles a frame, the order unsorted only on the first six
301
+ frames), and a control without the sort drawing the farther ball over
302
+ the nearer one at the same overlap. Shade bobs: a blob adding one shade
303
+ step to a colour-RAM shade buffer under a luminance-ordered palette with
304
+ a decay pass every fourth frame, 590 cycles for the add, 26,514 for the
305
+ decay pass (over a frame, so it cannot fit the blank), and the buffer
306
+ dumped from memory matching colour RAM through the palette in all 1,000
307
+ cells. Eight pins byte-identical on two runs per model, each reproduced
308
+ by a reviewer from the page listing.
309
+
310
+ **The pseudo-3D road, with its per-line shift measured to work (data
311
+ 762).** A coarse layer of thirteen multicolour character rows redrawn in
312
+ the vertical blank from a Z table and an 8.8 fixed-point centre
313
+ accumulator, and a fine layer that writes one `$D016` value per road
314
+ raster line from a cycle-locked loop entered by the double-IRQ stable
315
+ raster method, with the write at cycle 11 of each line, a 23-cycle
316
+ iteration on badline rows in place of 63, and separate PAL and NTSC loops
317
+ chosen by region detection at boot. The first build's fine layer had no
318
+ effect because a spin-wait put the writes at cycles 20 to 28, past the
319
+ latch; the recipe records that and the fix. Measured: coarse redraw 6,332
320
+ cycles PAL and 6,162 NTSC, fine chain 6,523 and 6,729; the kerb's left
321
+ edge in the pinned picture moves by one to seven pixels between adjacent
322
+ lines where the first build moved only at row boundaries; rows seven and
323
+ eight of the road now carry their own scroll values. Pinned on both
324
+ models. The page says what one scroll value per line cannot do, that the
325
+ grass is not cleared per frame, and that the geometry is this recipe's,
326
+ not a game's.
327
+
328
+ **Issue #38: a game brief routes to its archetype (data 761, schema 30,
329
+ tools 2.2.0, package 0.15.0).** `c64_game_briefing` with no `archetype`
330
+ used to run as a demo plan with a "Demo Briefing" heading. For a Spy
331
+ Hunter brief it proposed horizontal scrolls and RAM-banking techniques
332
+ ("enemy cars ram"), and it missed the multiplexer, the hitboxes and
333
+ `vehicle_control`.
334
+
335
+ Each game archetype now has a `**Brief words:**` line
336
+ (`Archetype.brief_words`). A brief routes to the archetype whose words it
337
+ contains most; a tie routes nowhere. `vertical_shmup`'s fingerprint was
338
+ `sprite_multiplex_24` and `raster_bars`; it is now the panel split, the
339
+ game multiplexer, hitboxes and the wave director.
340
+
341
+ Five faults in discovery are fixed:
342
+ - techniques that match no word of the brief were proposed on their
343
+ recipe bonus alone;
344
+ - stop words matched name and title words;
345
+ - the verb "ram" matched the acronym RAM;
346
+ - H3 vector hits lost their technique name;
347
+ - a horizontal technique was proposed for a vertical brief.
348
+
349
+ Output gains an optional `archetype.inferred_from`. Run `ingest:clean`
350
+ after updating.
351
+
352
+ **Issue #39, part H: a real template harness (data 760).** The two
353
+ starters in `templates/` were stubs. The game starter's KickAssembler
354
+ step was skipped even with a working assembler, and when it did run it
355
+ fed a `.prg` to Oscar64 as source. Neither starter had a headless run, a
356
+ check, an NTSC run or a measured frame.
357
+
358
+ `templates/_harness/` now gives every starter these targets:
359
+ - `make`, which links KickAssembler code into Oscar64 through a
360
+ generated header;
361
+ - `make shot check`, headless on PAL and NTSC with the autopilot,
362
+ grading the pictures against `expect.json`;
363
+ - `make selftest`, which proves the check fails on a faulted build;
364
+ - `make disk` and `make claims`;
365
+ - a frame meter on CIA2 timer A, printing the worst frame and the
366
+ median frame on screen;
367
+ - a plan gate: no build and no write under `src/` until `PLAN.md` holds
368
+ the real `check-compatibility` and `plan-budget` output.
369
+
370
+ There are two minimal starters, `hello` (C plus asm) and `hello-kick`.
371
+ `npm run new-project` makes a working project outside the repo, and
372
+ `npm run verify:templates` runs every starter. The loop is explained in
373
+ `docs/workflow/agent-harness.md`. The per-archetype starters follow.
374
+
375
+ **Issue #38: vehicle control, car contact and lane-pursuit AI (data
376
+ 759).** There are three new techniques in `techniques/logic.md`:
377
+ `vehicle_control`, `car_contact_response` and `lane_pursuit_ai`. Each has
378
+ an Oscar64 recipe (`vehicle-control`, `car-contact`, `lane-pursuit`)
379
+ that matches a Python model frame by frame and is pinned on PAL and
380
+ NTSC.
381
+
382
+ Review changed code on each:
383
+ - `vehicle_control`: holding the throttle on the verge barely slowed
384
+ the car, so acceleration now stops at the surface limit.
385
+ - `car_contact_response`: a truck scene now exercises the cooling rule
386
+ and the truck's share of the push.
387
+ - `lane_pursuit_ai`: two fork rules were measured and dropped. When
388
+ the road splits, pursuers take the other channel in 375 of 452
389
+ car-frames, and the page says why.
390
+
391
+ Oscar64 fault 6 is in CLAUDE.md and `toolchains/oscar64-reference.md`,
392
+ with its repro on #30. `soft_scroll_v` lists the vehicle-control
393
+ recipe.
394
+
395
+ **Issue #22, steps 4 to 6: game designs, machine variants and the
396
+ claims watch; #36 decided (data 758, schema 29, tools 2.1.0, package
397
+ 0.14.0).** One bump over main's data 757, schema 27, tools 2.0.0, package
398
+ 0.13.0. Two shape changes land together, so the schema moves two: 28 is
399
+ GameDesign, 29 is MachineVariant. Step 6 changes seed values, not shape.
400
+ Tools 2.1.0 is a minor: every change to the surface is additive (a new
401
+ optional input, new output fields, and `position`, a field new in this
402
+ release, with a value no shipped consumer has seen). The package moves
403
+ with the tools minor.
404
+
405
+ GameDesign (schema 28). A new doc type, `docs/game-design/designs/*.md`
406
+ (`CONVENTIONS-game-designs.md`), makes a whole game a node: the archetype
407
+ it is an instance of (`INSTANCE_OF`), the recipe that builds it
408
+ (`REALISED_BY`), the techniques it runs in each phase (`COMPOSES`, with a
409
+ `phase` of play, init or transition) and what its frame measured
410
+ (`**Measured frame:**`, stored as `measured`). Three pages, one per
411
+ scaffold; the phases were read from each listing's `main()`, not its
412
+ frontmatter. `c64_plan_budget` takes `design` (CLI `--design`): the
413
+ design's members are budgeted by phase, and each measured frame is set
414
+ beside the prediction for its phase and region, with where it falls and
415
+ which members had no figure. `techniques` is now optional. `c64_game_briefing`
416
+ lists the resolved archetype's designs in `designs[]`.
417
+
418
+ What the validation showed, play phase, scratch graph:
419
+
420
+ | Design | Predicted (low-high + badlines) | Measured worst, PAL / NTSC | Members with no figure |
421
+ |---|---|---|---|
422
+ | `platformer_scaffold_oscar64` | 4,477-4,685 + 1,075 | 8,693 / 10,287, above by 2,933 / 4,527 | 5 |
423
+ | `falling_blocks_oscar64` | 5,902 + 1,075 | 6,276 / 6,491, within_incomplete | 4 |
424
+ | `simple_shmup_oscar64` | 5,628 + 1,075 | not timed | 1 |
425
+
426
+ Re-run on a scratch graph of the merged tree; the figures held. The
427
+ platformer's typical PAL frame (4,966, one frame's reading) lies within
428
+ its range. The falling-block agreement is partial: its one large
429
+ figure, `falling_block_rules`' 5,888, is a constructed upper bound, and
430
+ the render has no Cost line.
431
+
432
+ Corrections found on the way: the `falling-blocks` frontmatter named four
433
+ of the seven techniques its listing runs; the #22 design put
434
+ `tile_map_render` in the platformer's play phase, where it runs once at
435
+ init; the platformer's timer is CIA1 timer B, not CIA2.
436
+
437
+ MachineVariant (schema 29). Seven seeds, one per VICE `-model` word the
438
+ harness needs or the pages name (`c64`, `c64c`, `c64old`, `ntsc`,
439
+ `newntsc`, `oldntsc`, `drean`), with their chips, line length and lines.
440
+ `VERIFIED_ON` (Recipe to MachineVariant) is rebuilt after every ingest
441
+ from `docs/recipes/runs.json`, as `verify:recipes` runs each page, and
442
+ only where the committed screenshot exists: 242 edges on a scratch graph
443
+ of this merged tree (data 757), 0 problems; 131 recipes run on the c64c. `c64_recipe_lookup`
444
+ returns `verified_on[]`; `c64_recipes_for` takes `verified_on` (a variant
445
+ or PAL / NTSC). The R56A and the Drean are variants, not Regions, which
446
+ answers #8's question.
447
+
448
+ Review fixes, steps 4 and 5. `verified_on[]` applies a run's chip flags:
449
+ `cia-revision-detect` runs the c64c with `-ciamodel 0`, so its CIA is the
450
+ 6526, and `overrides[]` says so (it listed the c64c's 8521).
451
+ `c64_plan_budget` gives `within_incomplete` when the measured worst lies
452
+ inside the range while members have no figure; it said `within`. A typical
453
+ frame's excess is a share of the typical, not of the worst. `simple-shmup`
454
+ is an instance of `vertical_shmup` only (the listing scrolls vertically).
455
+ A runs.json page with `skip` (main's tape-turbo-loader) gets no
456
+ `VERIFIED_ON` edge; it was reported as a missing screenshot.
457
+
458
+ Claims watch (step 6). `scripts/claims-watch.ts` runs a PRG in the
459
+ windowless x64sc with a store trace and judges every store against the
460
+ claims its techniques declare, their REQUIRES closure, a harness list and
461
+ the KERNAL routines it names. Exit 1 on a store outside them. Validated on
462
+ four recipes: each fails on its page's declarations alone and passes once
463
+ its RAM, harness timers and missing units are declared; a multiplexer
464
+ with `sta $d40b` and `sta $fb` added fails on exactly those two stores.
465
+ The CIA timer and TOD units now own their bit of the interrupt control
466
+ register ($DC0D/$DD0D bits 0, 1, 2). `vice-reference.md` says how to run
467
+ it.
468
+
469
+ #36: VICE's default machine is the `c64c` configuration (VIC-II 8565, SID
470
+ 8580, CIA 8521), not the 6569 that `vice-reference.md`, `pal-ntsc-detect.md`,
471
+ CLAUDE.md, the README and twenty page statements said. `x64sc -default
472
+ -dumpconfig` is identical to `-model c64c`. Re-run for this entry:
473
+ `cia-revision-detect` with no `-ciamodel` reads the new CIA on the default,
474
+ `c64c` and `newntsc`, the old one on `c64` and `ntsc`; `palette-cells`
475
+ under `-model c64` differs from the default in eleven of sixteen entries.
476
+ The maintainer's decision: keep the default, say c64c. No screenshot is
477
+ re-baselined; every page that called the VICE PAL run a 6569 now names the
478
+ C64C with a clause saying what it said; `-model c64` is the check for the
479
+ older machine.
480
+
481
+ **Candidate list, Tier B batch 15: four more items from fixed designs,
482
+ each a technique entry and a pinned KickAssembler recipe (data 757).**
483
+ A sprite text scroller in the opened lower border: eight glyph sprites
484
+ at Y 254 under a border opened by the top-and-bottom recipe's method,
485
+ 829 cycles a typical frame and 1,586 on a hand-off frame, every sprite
486
+ row inside the PAL frame and the control build with the border left
487
+ closed showing no sprite pixel below line 251. A twister: a 64-pixel
488
+ column whose four faces come from one sine, its 64 phase images built at
489
+ assembly time so the frame loop is a 128-line copy of 13,001 cycles
490
+ blanked, the pinned edges matching the edge table at three rows and a
491
+ straight control with one row pattern on every line. The `$D017` sprite
492
+ stretcher, which this KB had marked unverified, reproduced in VICE: a
493
+ setting write on any cycle from 48 to 55 (cleared four cycles earlier)
494
+ makes a 21-row sprite 91 lines tall over 81 toggled lines, each row held
495
+ for eight lines, while cycle 56 gives 24 lines and cycles 57 to 62 give
496
+ 44, 50, 47 and 94; the fifteen-build sweep is on the page, the pinned
497
+ build is cycle 52, and the control with the stores aimed at RAM is the
498
+ plain 21 lines. An LFSR-ordered screen dissolve to finish the transitions
499
+ family: a maximal 10-bit register visiting each of 1,000 cells once, 20
500
+ cells a frame, 3,203 cycles on the worst frame, half the cells landed at
501
+ frame 25 and the last on frame 50, beside a sequential control that is a
502
+ wipe. Eight pins byte-identical on two runs per model, each reproduced
503
+ by a reviewer from the page listing.
504
+
505
+ **Candidate list, Tier B batch 14: four demo effects, each a technique
506
+ entry and a pinned KickAssembler recipe (data 756).** Multicolour
507
+ interlace: two multicolour bitmaps in two VIC banks alternated at the
508
+ frame with a one-hires-pixel shift on the odd frame, the diagonal one
509
+ pixel further right in the second field at every row measured, a PIL
510
+ average of the two fields showing four distinct columns per pixel pair
511
+ where one field shows two, and a frame loop of 34 or 32 cycles (the
512
+ brief's single-bank layout did not fit, 18,000 bytes into 16,384, and the
513
+ page says so). Dot flag: a 16 by 8 grid on two sines plotted and erased
514
+ through the hires plot, 119 cycles a dot, 15,233 a frame blanked and up
515
+ to 16,098 with the display on, exactly 128 lit pixels in the pinned
516
+ picture and 3,570 without the erase pass. Fire: a colour-RAM heat map
517
+ over a solid glyph with a luminance-ordered palette, 53,479 cycles for
518
+ the whole screen and 27,301 for the larger half, so the screen refreshes
519
+ every four frames; the pinned picture's colour census is on the page.
520
+ DYPP: a text scroller of eight sprites, each column on its own sine,
521
+ 1,147 cycles a frame for the position update and 715 for a character
522
+ re-render, the two sprites past X 255 drawn at 14 and 62 instead of 270
523
+ and 318 when the high-bit write is left out. Eight pins, byte-identical
524
+ on two runs per model, each reproduced by a reviewer from the page's own
525
+ listing; the three new anchors went on the pitfalls whose mechanism the
526
+ code meets.
527
+
528
+ **The isometric tile engine, built from a fixed specification (data
529
+ 756).** Two earlier attempts stalled on the open design; this one was
530
+ handed the map, the projection, the draw order and the depth rule and
531
+ built exactly that: an 8 by 8 room of 2:1 diamond tiles four characters
532
+ wide, blocks one and two tiles tall drawn back to front so nearer cells
533
+ overdraw, a hardware-sprite player whose one priority bit is set when a
534
+ block in front of it overlaps its character box, and a scripted walk.
535
+ Measured: a full room redraw of 42,034 cycles, one block of 527, the
536
+ depth bit set at three of the six positions (the specification predicted
537
+ one; the recipe says why the character box catches two more), and a
538
+ negative control with the painter's order reversed that fails the
539
+ verdict. Pinned on both models. The entry says what one priority bit
540
+ cannot do.
541
+
542
+ **Four more measured pitfalls, and a logic pitfall page (data 755).** A
543
+ one-byte breadth-first distance map that uses 255 for "unreached" wraps
544
+ on a path longer than 254 cells: on a serpentine corridor the live map
545
+ read 1, 0, 1, 2 across true distances 255 to 258, a chaser at 254 walked
546
+ two cells away from the player and every far chaser gathered on a false
547
+ zero; saturating at 254 and a two-byte map are both measured as fixes,
548
+ and the recipe's own maze, whose longest path is 76, cannot show it.
549
+ Asserting ATN from the C64 pulls the drive's DATA line low through the
550
+ 1541's ATNA gate whatever a resident drive program writes: DATA IN read
551
+ released with ATN released and low with it asserted under ATNA clear,
552
+ the mirror image under ATNA set, controls with DATA OUT held low, the
553
+ drive's own port read at each phase, a drive that leaves interrupts
554
+ enabled behaving the same, and the fix, a drive loop that copies ATN IN
555
+ into ATNA every pass, leaving DATA free in all three phases. Sprite
556
+ registers persist across a game-state change: a play state that enables
557
+ only its own sprite inherited the title's pointer, expansion, multicolour
558
+ and a latched collision on both models, a game-over screen kept the
559
+ player across its banner, and a per-state VIC baseline routine clears all
560
+ of it. A CharPad `.ctm` embedded whole puts its header on glyph 0 and
561
+ shifts every glyph by 18 bytes on a version 8 file, identically under
562
+ Oscar64 and KickAssembler; the offset-and-length forms of both embeds and
563
+ the raw export are the fixes. Follow-ups from those measurements: the IEC
564
+ page's VIA table now says that ATN IN reads 1 when ATN is asserted, and
565
+ that its snapshot rows were taken under ATN; the drive-upload technique
566
+ records a 34-byte `M-W` as measured; the pitfall conventions list the
567
+ maths and logic categories; the text-mode render page's intro no longer
568
+ numbers its entries.
569
+
570
+ **The deferred raster anchors (data 754).** `badline_cycle_loss` gains
571
+ sprite_color_swap_mid_line, solid_vector_3d, mode7_lookalike and
572
+ vsp_glitch, and `raster_irq_first_line_jitter` gains mode7_lookalike and
573
+ vsp_glitch, each on the sentence of the technique that meets the
574
+ mechanism (a colour split placed by write cycle inside the badline's
575
+ stolen span; a filler that budgets forty cycles a badline row; a
576
+ per-line register chain with no stabilisation in its budget; a trick
577
+ whose write cycle is the effect). The techniques still without a pitfall
578
+ are the two loader notes and three logic entries the triage judged to
579
+ need none. The two-bit fast loader candidate was attempted and not
580
+ landed: its transfer never ran, so its pages were not merged and the
581
+ attempt is kept as a private experiment record.
582
+
583
+ **Every technique a pitfall can reach now has one, bar seven (data
584
+ 753).** A read-only triage of the techniques no pitfall named sorted each
585
+ into an existing pitfall its text meets, a new measured pitfall, or none
586
+ with the reason. Eighteen anchors were added to existing entries on seven
587
+ pitfall pages, each checked against the technique sentence that meets the
588
+ mechanism, and `ram_under_rom_traps` gained cartridge ROM at `$8000` to
589
+ `$BFFF` as a fourth ROM-mapped range. Five new pitfall entries, each
590
+ measured first: a bank or mode write executed from the cartridge window
591
+ it switches hands the very next opcode fetch to the new bank (traced at
592
+ the cycle; the fix runs the switch from RAM or makes the switch site
593
+ identical in every bank); setting ECM while MCM is still on selects an
594
+ invalid mode that draws the whole window black while sprite collisions
595
+ and priority still work against the invisible field, on both models,
596
+ with ECM plus BMM tabled beside it; a new maths pitfall page with a sine
597
+ table of amplitude 128 that peaks at 256 and wraps seven entries to zero
598
+ under both toolchains, and a shift-and-subtract divide whose missing
599
+ carry guard is a 16/8 fault only, wrong for divisors of `$81` and above
600
+ (24,400 misses over the recipe's sweep) while the 8/8 and 16/16 loops
601
+ pass with the guard deleted; and Oscar64's assembler optimiser at `-O2`
602
+ rewriting a non-volatile inline block and duplicating it, so a store into
603
+ an operand byte lands in a copy that never runs (the executed and the
604
+ dead listings quoted; `volatile`, `#pragma optimize(noasm)` and a
605
+ data-patch form each measured as fixes). The divide measurement
606
+ corrected the technique page and the divide-check recipe, which had said
607
+ the guardless loop fails for divisors of `$80` or `$8000` and above; the
608
+ multiply technique's account of what the mis-optimised routine computes
609
+ was corrected from the executed listing. The seven techniques still
610
+ without an anchor are two loader notes and three logic entries the triage
611
+ judged to need none, and two whose anchors wait on the raster pitfall
612
+ page another agent is writing.
613
+
614
+ **Four pitfalls met while landing the night's recipes, each measured
615
+ before it was written (data 752).** A VIC colour register reads back as
616
+ the colour plus 240, so `IF PEEK(53280)=2` after `POKE 53280,2` is
617
+ silently false: every register from `$D020` to `$D02E` measured 0 to 15
618
+ on both models, with the other unused VIC bits (`$D016`, `$D018`,
619
+ `$D019`, `$D01A`) tabled beside them and the audited hardware page
620
+ agreeing on each. A self-extracting decruncher that runs from the zero
621
+ page leaves the KERNAL's variables full of its own code: Dali `--small`
622
+ and bitfire's stub both silenced a payload that prints through CHROUT,
623
+ and the zero-page diff at entry names the bytes, `$9A` set to the RS-232
624
+ device under one and to a serial device under the other, the editor's
625
+ line pointer at `$4CBA` under the second; Dali's standard stub and
626
+ pucrunch save what they clobber, and a prologue that banks the KERNAL in
627
+ and calls IOINIT and CINT prints under both. A colour RAM index of 1,024
628
+ or more writes CIA1's registers, with the sixteen bytes before and after
629
+ a fill to 1,040 (timer A stopped, the jiffy clock frozen, the port A
630
+ direction register left at the fill value) and the row-by-row fill that
631
+ leaves them untouched; the 24 spare bytes past cell 999 measured as
632
+ nibble RAM. One read of `$DC0D` or `$DD0D` clears every pending flag: a
633
+ FLAG poll took a timer underflow on its way past and the timer's own
634
+ check read `$00`, the copy-into-RAM pattern kept it, and a main-program
635
+ read racing CIA2's NMI lost the interrupt itself at one phase on NTSC
636
+ and on the old CIA model.
637
+
638
+ **Candidate list, Tier B batch 9, two of four (data 751).** A tape
639
+ mastering workflow page: a host writer that turns a PRG into a
640
+ KERNAL-format TAP (the three pulse lengths, the pair rule, the countdowns,
641
+ the two copies and the checksum the formats page measured), which a plain
642
+ LOAD then RUN accepts on both models; a decode-back checker that also
643
+ reads the TAP the KERNAL itself recorded; the turbo route, the turbo
644
+ loader mastered in KERNAL format as the stub with the turbo block
645
+ appended, loading from one image; timings by bisecting the cycle limit
646
+ (a 202-byte payload runs 33 seconds after LOAD on PAL, of which the FOUND
647
+ pause is a third; the KERNAL format costs 18,890 cycles a payload byte,
648
+ the turbo block 7.6 times less for the same 500 bytes); and the finding
649
+ that the jiffy clock is not a tape load timer, since both models printed
650
+ 770 jiffies for a load of over thirty seconds. The PSID header
651
+ corrected: the bytes at `$7A` and `$7B` are the second and third SID
652
+ addresses in versions 3 and 4, the flags bits 6 to 9 their models, the
653
+ RSID rules in one paragraph; headers written by hand round-trip, VICE's
654
+ windowless vsid accepts versions 2, 3 and 4 and logs the chip addresses,
655
+ rejects odd or out-of-range addresses as no second SID, reads `$7B` from
656
+ a version-3 file where the document reserves it, and gives every chip the
657
+ first SID's model; a census of the HVSC corpus gave the version counts
658
+ and the address ranges seen. The isometric tile engine and the pseudo-3D
659
+ road did not land: both writers stalled six times on the design, and they
660
+ wait for a fixed specification like the scroller's.
661
+
662
+ **Candidate list, Tier B batch 8 (data 750).** The 1541's VIA registers
663
+ and memory map measured through the command channel and a probe recipe:
664
+ the density bits follow the requested track's zone even when the head
665
+ did not step, the stepper bits move one half-step per write from the
666
+ DOS's routine every 14,848 drive cycles, the motor bit and the
667
+ write-protect sense read as the states say (the latter checked with a
668
+ read-only attach), the LED bit was set only during an auto-initialise,
669
+ byte-ready reaches the CPU only with the port-control register's CA2
670
+ line high, and the first job after power-up does not step. A tape turbo
671
+ loader with a TAP written on the host: one pulse per bit at 256 and 512
672
+ cycles, 321 bytes a second on PAL and 334 on NTSC against the KERNAL's
673
+ own rate, the pulse spread under VICE's default wobble, a 208-cycle bit
674
+ that failed and why, and a timer-read race that mismeasured one pulse in
675
+ sixty until the read was done high, low, high; the recipe cannot be
676
+ pinned by the verifier, which now honours a `"skip"` key in `runs.json`
677
+ with the reason, reports the page as skipped rather than failed, and
678
+ the conventions say so. The CharPad CTM v8 and SpritePad SPD v5 headers
679
+ decoded from the sample files Oscar64 ships and checked against what
680
+ its embed forms produce (v9 read from Oscar64's structures only, not
681
+ measured here); Oscar64's reader checks neither signature nor version,
682
+ so an old v5 file embeds silently and wrongly. The two-bit fast-loader
683
+ transfer did not land: its writer stalled six times on the protocol
684
+ design and runs again alone from a fixed specification.
685
+
686
+ **Candidate list, Tier B batch 7 (data 749).** A cc65 cartridge recipe
687
+ built through the verifier's cartridge path: the linker configuration
688
+ writes the .CRT container itself from a header segment and the result
689
+ is byte-identical to cartconv's, DATA is copied from ROM to RAM at
690
+ start (55 bytes, checksums equal), the runtime from CINT to main costs
691
+ 2,281 cycles, and the negative control with DATA left in ROM boots,
692
+ prints nothing and hits a BRK 1,049 cycles into the first print; a
693
+ Cartridge builds section on the cc65 page. The IEC bit timing measured
694
+ from the KERNAL's own port accesses under the monitor: the device-present
695
+ look 1,103 cycles after ATN, a send bit cell of 94 to 96 cycles stretched
696
+ to 136 to 139 by a badline, the listener's EOI acknowledge 539 cycles
697
+ after DATA is released, and the drive's replies as VICE's 1541 gives
698
+ them; the receive-side timer count is `$01FF` not `$0100` because the
699
+ KERNAL writes only timer B's high byte, and the page's older "about
700
+ 1,024 cycles" is flagged. `drive_code_upload_and_job_queue` on the
701
+ file-io page with a recipe: 68 bytes uploaded in three M-W commands and
702
+ read back, executed by M-E, a seek job then a read job of track 18
703
+ sector 0 through the queue returning the BAM, a read before any seek
704
+ failing with result `$0B` and a read of track 40 with `$03`, drive-side
705
+ durations by the drive's own clock; a job queue and buffers table on the
706
+ IEC page. A Spindle toolchain page (3.1 built from source with xa65):
707
+ two parts packaged with mkpef and linked with pefchain, the join between
708
+ parts measured at 55 cycles and accounted for instruction by instruction,
709
+ part timings on both models, the D64 layout, and pefchain's page-clash
710
+ warning; the pictures live under docs/figures because the verifier cannot
711
+ boot a prepared disk. Left open: the device-not-present timeout as a
712
+ firing timeout (no run without a responding device could be made under
713
+ VICE); the write, verify, bump and execute job codes; where Spindle's
714
+ drive code lives on the disk.
715
+
716
+ **Candidate list, Tier B batch 6 (data 748).** `basic_extension_wedge`
717
+ on the text page with a KickAssembler recipe: an IGONE wedge that adds
718
+ prefixed commands and falls through to the ROM, exercised after a colon,
719
+ inside IF THEN and on an unknown letter (the ROM's error still appears),
720
+ costing 10.2 cycles a statement on PAL and 10.4 on NTSC against 10 by
721
+ the instruction table; the ROM's own paths through `$0308` and `$0300`
722
+ read from the BASIC image at the addresses the page quotes.
723
+ `lane_depth_engine` on the logic page with an Oscar64 recipe for the
724
+ beat-em-up archetype: Y as depth, an insertion sort over the actors
725
+ setting both draw order and hit order (157 to 269 cycles a frame), a hit
726
+ window in Y and X keyed to the attack's active frames; the whole step
727
+ 1,413 cycles at its worst; the technique added to the archetype's
728
+ fingerprint. Sprite priority measured per pixel class in a recipe: a
729
+ multicolour sprite's own bit pair makes no difference to the priority
730
+ bit, the playfield's pattern decides (hires 1 bits and multicolour pairs
731
+ 10 and 11 are foreground; 0 bits and pairs 00 and 01 background whatever
732
+ colour they draw in), `$D01F` follows the same classes and ignores the
733
+ priority bit, and sprite order is decided before the playfield; the
734
+ mob_priority entry extended in place, and the VIC-II reference's layer
735
+ diagram, which the measurement contradicts, is reported on the
736
+ hardware-verification issue rather than edited. A unit-testing toolchain
737
+ page with sim6502 as its tool node and a KickAssembler test-driver
738
+ recipe: fourteen cases through a case table with the verdict in `$02FF`,
739
+ the same driver run in sim6502 in 0.12 s of host time against 0.4 s in
740
+ VICE, 64spec assembling unchanged with KickAssembler 5.25, and sim65's
741
+ exit-code channel measured. Left open: the 418-cycle residue between the
742
+ wedge's measured and arithmetic cost; sprite priority with both
743
+ overlapping sprites set; multicolour bitmap and ECM pixel classes.
744
+
745
+ **Candidate list, Tier B batch 5 (data 747).** The GCR encoding on the
746
+ formats page, measured: the sixteen code words derived from a G64 image
747
+ c1541 wrote and confirmed byte for byte against the 1541 ROM's encode
748
+ table at `$F77F` (the F code is `10101`; the writer's own memory said
749
+ otherwise and the ROM corrected it), the header and data block layouts
750
+ decoded with their checksums, the sync and gap as written, the four zone
751
+ track lengths and their bit cells as arithmetic, the zone tables at
752
+ `$FED1` and `$FED7`; the "4 bytes to 5" sentence corrected with a
753
+ clause; c1541 3.10 writes `$A0 $A0` as the header ID while the BAM holds
754
+ the command-line ID, and the drive ROM loads the disk anyway. A cc1541
755
+ toolchain page (4.2 built from source): how the directory-art tricks are
756
+ stored in the entry bytes (a DEL entry is type `$80`, an art line has no
757
+ blocks, a name's first `$A0` closes the quote in the listing), what a
758
+ LIST shows of them, decoded against the character ROM, and interleave and
759
+ placement options measured on the sector chain. `two_word_parser` on the
760
+ text page with an Oscar64 recipe for the text-adventure archetype (ten
761
+ scripted commands through the KERNAL buffer, parse cost 569 to 2,036
762
+ cycles a command, the end state checked), and the technique added to the
763
+ archetype's fingerprint. The .VSF section rewritten from a snapshot the
764
+ emulator wrote: the previous text claimed a 15-byte module header and
765
+ module names the file does not contain; measured, the header is 22 bytes,
766
+ twenty-six modules in a stated order, the 64 KiB RAM at byte 209 in
767
+ address order, colour RAM at offset 761 of the VIC-II module, and two
768
+ runs of the same program differ in 946 bytes of RAM the program never
769
+ wrote. Left open: which ID character c1541 should have written; the
770
+ meaning of the snapshot's unlabelled bytes; LOAD of a DEL entry.
771
+
772
+ **Candidate list, Tier B batch 4 (data 746).** A cartconv toolchain page
773
+ with the .CRT header and chip packets decoded from files cartconv wrote,
774
+ and what each type does when booted in VICE: the generic 8K type ignores a
775
+ bank-register write, Magic Desk switches an 8K bank at `$8000` through
776
+ `$DE00`, Ocean switches the same bank mirrored at `$A000`, and cartconv's
777
+ EasyFlash made from a Magic Desk layout checks clean and does not boot;
778
+ byte `$1A` of the header is the hardware revision, not reserved; a
779
+ two-bank Magic Desk recipe pinned through the verifier's cartridge path;
780
+ KickAssembler has no cartridge directive and Oscar64's three cartridge
781
+ targets are decoded. REL files: the directory entry, the side-sector block
782
+ and the data chain decoded from a disk image the recipe wrote (a one-byte
783
+ write to record 125 of a 254-byte-record file allocates 125 data blocks and
784
+ two side sectors), the P command's byte order, the record padding, and the
785
+ DOS replies for a record that does not fit; the file-io technique's side-
786
+ sector rule corrected. `zx0_lzsa_decrunchers` on the memory-banking page
787
+ beside pucrunch: ZX0 v2.2, bitfire's ZX0 packer, Dali 0.3.5, ZX02 and
788
+ LZSA 1.4.1 built from source; on the two pucrunch inputs Dali's
789
+ self-extractor is 1,041 bytes and 114,369 cycles against Exomizer's 1,103
790
+ and 189,276, and bitfire's 1,035 and 99,422; Dali's small mode and
791
+ bitfire's stub overwrite the KERNAL's zero page and the subject does not
792
+ run or prints nothing, measured; the candidate list credited Dali to the
793
+ wrong author (it is Bitbreaker's). `bfs_distance_map` on the logic page
794
+ with a recipe: one flood serves four chasers, 404 open cells in 115,912
795
+ cycles over fifteen frames at 32 cells a frame, the map equal to a host
796
+ BFS byte for byte, every chaser reaching the player in 145 frames; an
797
+ Oscar64 -O2 fault met on the way (the first inlined call of a
798
+ pointer-walking copy loop) is reported on the gotcha issue. Left open:
799
+ raw-mode decrunch times for the ZX0 family; record lengths 0 and 255; the
800
+ EasyFlash registers on the tool page are the memory-banking page's, not
801
+ measured here.
802
+
803
+ **Tier A, the eight-way scroller (data 745).** `eight_way_scroll_double_buffer`
804
+ on the scroll page with a KickAssembler recipe, after three attempts and
805
+ three reviews. A 64 by 48 tile world through a 40 by 25 window along an
806
+ eight-leg camera path, two screen matrices flipped by `$D018` in the
807
+ blank, the redraw spread over fields in bands of at most seven rows, and
808
+ colour RAM, which cannot be paged, rewritten in four calls after the flip.
809
+ The first design redrew seventeen rows a field from raster 152 and
810
+ overran the field about one apply in four, which stalled the camera and
811
+ showed a whole field of stale colours; its verdict could not see it
812
+ because its checks compared raster numbers inside a field. The shipped
813
+ version caps every band, runs the camera at one pixel every two fields so
814
+ a crossing gap of six fields covers the five-field redraw, and its verdict
815
+ counts late applies, skipped preps and a first colour band finishing after
816
+ row 6's badline, all zero over a full loop on both models. Worst field
817
+ 13,111 cycles on PAL and 13,152 on NTSC. Stated plainly on the page and in
818
+ the technique entry: after each tile crossing the rows not yet rewritten
819
+ show the previous position's colours for three displayed fields, about
820
+ one field in four over the path; the pin sits in the clean window. The
821
+ one-pixel-a-frame form is not shipped: on diagonals its crossing gap is
822
+ three fields against the five the redraw needs.
823
+
824
+ **Candidate list, Tier B batch 3 (data 745).** `light_pen_read` on
825
+ the input page with a KickAssembler recipe: the latch, the one trigger a
826
+ frame, the interrupt at 94 cycles through the KERNAL vector and the
827
+ two-pixel conversion checked on synthetic latch values; VICE 3.10's light
828
+ pen never triggers headlessly (no host mouse), and the fire-line route
829
+ through joystick autofire breaks the autostart before the program runs, so
830
+ the resting registers are measured and the moving pen is not, and the page
831
+ says so. A petcat toolchain page: tokenise and de-tokenise measured
832
+ against a hand count of tokens (a four-line stub is 64 bytes), the control
833
+ macros mapped to their PETSCII bytes, the round trip identical apart from
834
+ line-number padding, an unknown keyword accepted silently and failing on
835
+ the machine, upper-case keywords stored as text rather than tokens, and
836
+ the `-w2` against `-w3` difference on one keyword. `pucrunch_decruncher`
837
+ on the memory-banking page: pucrunch 1.14 built from source, its four
838
+ modes and Exomizer 3.1.3b0 measured on the same two inputs for size and
839
+ decrunch time (on a 4,519-byte mixed program pucrunch's default is 1,084
840
+ bytes and 349,505 cycles against Exomizer's 1,103 bytes and 189,276
841
+ cycles), the decruncher's footprint at `$F7` and `$0200`, and the
842
+ candidate list's claim that pucrunch decrunches faster not borne out on
843
+ either input. `text_window_and_menu` on the text page with an Oscar64
844
+ recipe: save-under of screen and colour RAM, a PETSCII frame matched glyph
845
+ by glyph against the character ROM, a five-item menu moved by joystick and
846
+ by the cursor keys through the KERNAL buffer, the restore exact byte for
847
+ byte; open 14,923 cycles and close 5,759 on PAL. Left open: what VICE
848
+ latches when its pen does trigger; the raw pucrunch decruncher was not
849
+ assembled; the anchor for the window technique on the text-mode-render
850
+ pitfall page waits for the eight-way scroll to release that page.
851
+
852
+ **Issue #22, step 3: the honest budget (schema 27, tools 2.0.0, package
853
+ 0.13.0).** Tools 2.0.0 is a major bump because the briefing's output
854
+ changes in a way a client can break on: `cycles_verdict` gains
855
+ `undetermined`, and it no longer says `under` when a figure is missing.
856
+ VERSION's rule makes a breaking output change a major. The package is
857
+ still 0.x, where a minor is the breaking step, so it goes to 0.13.0 as
858
+ every tools minor before it moved the package minor; 1.0.0 is a
859
+ maintainer's call, not a side effect.
860
+
861
+ New tool `c64_plan_budget` (CLI `plan-budget`) adds a list of techniques
862
+ up against a frame, each in a phase (`name`, `name:transition`,
863
+ `name:init`), on PAL, NTSC or both. The rules are in `src/domain/budget.ts`
864
+ and came from design 2.1, where summing Cost lines erred from −96 % to
865
+ about 10× over on built recipes:
866
+
867
+ - A missing figure is never zero. A member with no cycles figure is
868
+ listed as unknown, with the recipe to measure it on, and the verdict is
869
+ `undetermined`.
870
+ - A figure above one frame (19,656 PAL, 17,095 NTSC) is a multi-frame
871
+ operation and is not summed. It holds nothing in the frame, so a member
872
+ it includes is budgeted as itself.
873
+ - A new Cost key, `cycles_per_frame_typical`, gives a range: the low end
874
+ sums typical frames, the high end worst frames. The low end is not a
875
+ floor. The key may hold a common frame or a real run's worst frame
876
+ (`ghost_target_tile_ai`'s 4,171 and `game_tree_search`'s 5,325 are the
877
+ second kind), and two members' such frames need not coincide. So `over`
878
+ is judged on the floor alone: band and per-line charges, which run
879
+ every frame, plus the badline loss no summed figure can already hold.
880
+ This departs from the design, which said `over` whenever low plus
881
+ losses passed the frame; on NTSC that called `sprite_multiplex_game`'s
882
+ built 16,600-cycle reversal frame over, while the recipe runs on NTSC
883
+ with every actor drawn.
884
+ - New `**Cost includes:**` line: a member whose work is inside another's
885
+ figure is counted once. Includes are followed through the graph, and of
886
+ two pages that include each other the first listed is kept. A technique
887
+ with `cycles_per_line=63` and a line band is charged band lines × line
888
+ length, and its REQUIRES closure is not added again.
889
+ - New `**Cost measured on:**` line names the recipe and its conditions.
890
+ With the screen on, the badlines (lines 51-243, every eighth, 43 cycles
891
+ each) outside any band charge are charged unless every summed figure is
892
+ a band charge or says it was measured with the screen on. A stall takes
893
+ its cycles wherever the code runs, so the charge is exact when no
894
+ summed figure already holds stalls, and too high by what a screen-on
895
+ figure holds. Bytes flagged `whole PRG` are not summed, and a member
896
+ inside another's figure that states bytes is not summed either.
897
+ - A name listed twice in one phase is counted once and the repeat is
898
+ listed in `refused`. A region other than pal, ntsc or both is refused.
899
+ PAL-locked and NTSC-locked members in one set are named.
900
+
901
+ Review corrections before release, each found by running the tool on the
902
+ shipped pages: the badline charge was 1,075 even when `fli_image`'s band
903
+ 45-251 already held all 25 badlines, and was called "a ceiling: code that
904
+ runs in the border meets no badline", which is wrong (a stall takes its
905
+ cycles wherever the code runs). With `ghost_target_tile_ai`,
906
+ `wave_director` and `sprite_animation_table` beside it, that made a low
907
+ end of 18,739 into 19,814 and called the set over. `soft_scroll_h`, left
908
+ out as multi-frame, still hid `char_scroll_buffer_h`'s missing figure.
909
+
910
+ The briefing budget now calls the same planner, every proposed technique
911
+ in one play frame. Its `cycles_verdict` gains `undetermined` and it gains
912
+ `cycles_low`, `fixed_loss_cycles`, `excluded`, `unknown` and
913
+ `to_measure`. `c64_timing_budget` is unchanged. It answers a different
914
+ question, the cycles left on one raster line, and its README row no
915
+ longer claims per-frame math. Ingest now warns about, and counts, a
916
+ measured-on recipe that is no Recipe and an included name that is no
917
+ Technique.
918
+
919
+ Content: 68 Cost lines gained a measured-on line, five of them on the #21
920
+ pages merged from main. Five pages do not say where their figure came
921
+ from, so they got none. Eight gained a measured
922
+ typical frame, each one the page already stated: `wave_director`,
923
+ `dig_and_refill`, `difficulty_ramp_tables`, `ghost_target_tile_ai`,
924
+ `sprite_animation_table`, `sfx_engine_beside_music`, `sprite_cache_flip`
925
+ and `game_tree_search` (its worst measured four-node slice, 5,325, beside
926
+ the 9,316 bound). Three gained an includes line: `wave_director`
927
+ includes `object_pool`, `soft_scroll_h` includes `char_scroll_buffer_h`,
928
+ and `fli_image` includes its stable double-IRQ entry.
929
+
930
+ Four corrections:
931
+
932
+ - `fli_image` charged 200 lines (12,600). Its band, 45-251, is 207 lines,
933
+ so the figure is 13,041.
934
+ - `fli_image` said `bytes_code=3277` and `bytes_data=16384`: 3.2 KB and
935
+ 16 KB times 1,024. KickAssembler's `-showmem` for the recipe gives
936
+ 3,488 and 16,001, and the basis is now `arithmetic`, not `estimated`.
937
+ - `decimal_print` said `bytes_code=0`, a figure the page never measured,
938
+ and a budget summed it as zero bytes. The key is gone.
939
+ - `platformer-scaffold` plays a three-voice stub tune every frame but did
940
+ not list `sid_play_routine_pattern`; it does now, and the page says so.
941
+
942
+ Validation on PAL. "Old sum" is the previous briefing arithmetic over the same pages: every `cycles_per_frame` added, with a missing figure counted as zero.
943
+
944
+ | Composition | Old sum | New | Measured |
945
+ |---|---|---|---|
946
+ | platformer-scaffold | 4,953, "under" | [4,731, 4,939] + 1,075, undetermined, 5 unknowns | 4,966 one frame; peak 8,693 |
947
+ | simple-shmup | 5,628, "under" | 5,628 + 1,075, undetermined, `soft_scroll_v` unknown | not measured whole |
948
+ | cracktro-template | 75,358, "over" | 1,317 + 1,075, undetermined, `soft_scroll_h` multi-frame, `char_scroll_buffer_h` unknown | fits (about 7,000 in the blank) |
949
+ | fli-image | 12,884, "under" | 13,041, fits | 13,041 by arithmetic |
950
+ | scroll-panel-split | 413, "under" | 413, undetermined, 2 unknowns | carry frame 11,613 by arithmetic |
951
+ | sprite-multiplex-game | 16,600, "under" | 16,600 + 1,075, fits (NTSC undetermined) | parts measured in play: about 7,100-8,000 |
952
+ | wave-director | 3,568, "under" | [1,170, 3,188] + 1,075, fits | 3,188 worst, screen blanked |
953
+ | falling-blocks | 5,902, "under" | 5,902 + 1,075, undetermined, 2 unknowns | 6,276 dearest frame of the run |
954
+
955
+ `test/plan-budget.test.ts` rebuilds every row from the shipped pages.
956
+
957
+ Data 742, schema 26, tools 1.31.0, package 0.11.0.
958
+ **Candidate list, Tier B batch 2 (data 743).** Four measured items.
959
+ `irq_keyboard_own_scan` on the input page with a KickAssembler recipe: an
960
+ eight-column matrix scan in the game's interrupt with per-key age
961
+ counters, 252 cycles for the scan and 781 for scan, edge pass and ageing
962
+ with the matrix empty; the KERNAL's exit points read from the ROM (the
963
+ candidate list's phrasing of `$EA7B` was inverted and the page states the
964
+ measured one); port 2's fire line does not leak into the matrix image and
965
+ port 1's reads as row 4 closed in every column, both measured; no key was
966
+ pressed, since VICE's keyboard feed writes the KERNAL buffer, and the page
967
+ says so. `directory_read_and_select` on the file-io page with an Oscar64
968
+ recipe that writes three files, streams the "$" channel, parses the
969
+ listing and lets a selector pick one: 160 bytes with status `$40`, the
970
+ transfer 515,635 cycles on PAL and the parse 13,821; the disk name prints
971
+ as graphics glyphs because c1541 stores it as shifted PETSCII, explained
972
+ on the page. `hires_plot` and `bresenham_line` on the bitmap page with a
973
+ recipe: 63 cycles a plot, 136 a further line pixel, a 320-pixel line
974
+ 43,606 cycles with the display off and about 47,000 with it on, the
975
+ badline stalls counted by the CIA; the eleven lines set 2,056 pixels,
976
+ matching a host Bresenham and the sum of the endpoints' spans.
977
+ `seeded_level_fill` on the logic page with a recipe: a 40 by 22 field from
978
+ a 16-bit seed against three thresholds and a five-object list, regenerated
979
+ byte for byte, a second seed giving a different checksum, 97,643 cycles a
980
+ generation; a flood-fill solvability check is described and not built, and
981
+ none of the three levels is claimed solvable. Left open: the steep-loop
982
+ line cost is from the instruction table; the standing disagreement between
983
+ the high-score-persist and file-io pages about a bare OPEN 15 with no
984
+ drive, which the lint still records.
985
+
986
+ **Issue #21, the last items.** `mixed_sprite_char_actors` (a sprite
987
+ fighter and a character fighter, priority per frame), a reference page on
988
+ which game and engine sources may be adapted and which are facts only
989
+ (`game-design/reference-game-sources.md`; the Oscar64 GPL question is
990
+ #31), and tool pages for `sidreloc` and `png2prg`, both run here.
991
+ Corrected, each with a clause: `vic-ii-reference.md` defined sprite
992
+ priority and `$D01F` background by colour register (multicolour pairs 00
993
+ and 01 are background; Bauer 3.8.2 and measured); `asset-pipelines.md`
994
+ had the Koala bit pairs swapped; `bitmap-koala-viewer.md` gave an
995
+ `#embed` form that does not compile and offsets two bytes late.
996
+
997
+ **Issue #21, GR-05/10, GR-06, GR-07, GR-11.** Engines for games at the
998
+ scale of Elite and Lemmings, each self-checked against a Python model:
999
+ `wireframe_pipeline` and `procedural_seed_universe` (pixel-exact
1000
+ wireframes; Elite's galaxy names reproduced), `adventure_database_engine`,
1001
+ `game_tree_search` (with a time-sliced form that misses no frame), and
1002
+ `destructible_char_terrain` with `creature_state_machine`. Two more
1003
+ Oscar64 faults recorded with their upstream status (#30).
1004
+
1005
+ Data 740, schema 26, tools 1.31.0, package 0.11.0 (step 2, below).
1006
+
1007
+ **Issue #22, step 2: the zero page each KERNAL routine writes (schema 26,
1008
+ tools 1.31.0, package 0.11.0).** A `CLOBBERS_ZP` edge from each
1009
+ KernalRoutine to the `zero_page` unit, from new `**Clobbers zero page:**`
1010
+ lines on `hardware/kernal-routines-reference.md`. A `may` line per
1011
+ jump-table routine is a static walk of the 901227-03 ROM through the
1012
+ power-on vectors (`scripts/kernal-zp-walk.ts`; `npm test` fails when the
1013
+ page and the walk disagree). `must` lines, 18 calls of 17 routines, are
1014
+ what a VICE x64sc store trace saw with every interrupt masked
1015
+ (`scripts/kernal-zp-trace.ts`); every traced byte lies inside its may
1016
+ set. `c64_check_compatibility` has a new soft kind, `kernal_clobbers_zp`:
1017
+ a technique's KERNAL calls may write bytes a technique claims. It also
1018
+ runs inside one input's own chain, the technique against itself and its
1019
+ own prerequisites.
1020
+
1021
+ The design's sets were too small. It put CHROUT, OPEN and the other large
1022
+ routines at 49-55 bytes; the walk gives 88-94. A tape routine installs
1023
+ one of four IRQ handlers at `$0314` (table at `$FD9B`) that runs inside
1024
+ the call, and those handlers write `$92`, `$96`, `$A7`, `$B1` and `$BF`.
1025
+ SCNKEY dispatches through `$028F`, a vector RESTOR does not set; the walk
1026
+ follows it to `$EB48`, the value CINT stores, which adds `$F5-$F6`. The
1027
+ IRQ entry's BRK branch (`JMP ($0316)` at `$FF55`) is not followed: the
1028
+ tape code's fake IRQ through `$FF43` never takes it, and following it ran
1029
+ the warm start and counted all of zero page. The traced CHROUT, scrolling
1030
+ the screen, wrote `$D9-$F4`, the line-link table, so Krill's default
1031
+ zero page `$E0-$EF` is inside what printing writes.
1032
+
1033
+ `krill_loader_integration`'s `**Uses kernal:**` said LOAD, CHKIN, CHKOUT.
1034
+ The v194 source calls no LOAD; the line now lists the fifteen routines
1035
+ `install` calls and the fallback's TKSA. Every check naming Krill now
1036
+ carries a soft `kernal_clobbers_zp` of Krill against itself (a lead to
1037
+ trace, on #22). The `serial_bus_busy` rule listed CIOUT and ACPTR, names
1038
+ no KernalRoutine node has; it now uses IECOUT and IECIN. The trace ran
1039
+ only on the windowed x64sc; it now runs on the windowless build too.
1040
+
1041
+ **Issue #21, GR-01 to GR-04.** Four small complete games, each a
1042
+ technique plus a self-playing recipe checked against a Python model of
1043
+ the same rules: `falling_block_rules` (NES tables per region, scoring at
1044
+ the level after the clear), `ghost_target_tile_ai` (the Pac-Man Dossier's
1045
+ target tiles), `cave_scan_engine` (the scanned flag that stops the double
1046
+ move) and `dig_and_refill` (Lode Runner's holes and guards; four guards
1047
+ overrun a frame). A third Oscar64 1.32.271 miscompile, reproduced: at -O2
1048
+ a loop-invariant `array + signed char` is zero-extended (#30).
1049
+
1050
+
1051
+ **Issue #22, steps 0 and 1: hardware claims (schema 25, tools 1.30.0, package 0.10.0).**
1052
+ `HardwareUnit` nodes (SID voices, sprites, CIA timers, TOD and ports, the
1053
+ VIC bank, the serial bus, the raster IRQ, the four vectors, the expansion
1054
+ pages, zero page) and `CLAIMS` edges from a technique's new `**Claims:**`
1055
+ line, in four modes: owns, shares, reads, init. `c64_check_compatibility`
1056
+ now names the unit two techniques contend for (`unit_contention`,
1057
+ `zero_page_overlap`, `unit_shared`, `unit_read_while_driven`,
1058
+ `init_order`, the last at a new `info` severity that leaves the verdict
1059
+ alone). Before, two raster-IRQ owners or two players on the same voices
1060
+ drew at most a soft shared-register warning. A technique with no Claims line reads as unknown,
1061
+ never as claiming nothing, and the text says a unit conflict with it
1062
+ cannot be ruled out. A `prerequisite_conflict` now carries the rule that
1063
+ fired in `underlying_kind`; it was reported as hard whatever the rule.
1064
+ Recipe-chosen zero page and vectors are not checked yet (step 8).
1065
+
1066
+ A first cut made every raster technique own the raster IRQ, and set
1067
+ techniques that the KB's own VICE-verified recipes run together against
1068
+ each other as hard conflicts (fli-image, sideborder-open, fld,
1069
+ stable-raster-irq, the Oscar64 raster-bars). `stable_raster_irq` and
1070
+ `double_irq` are ways into a handler, so they now `share` the raster
1071
+ compare and the effect run from the handler owns it. A technique is not
1072
+ set against a prerequisite it runs inside its own handler. A test now
1073
+ checks every recipe's technique set and fails naming any recipe with a
1074
+ hard unit conflict. The Kick `sprite-multiplex-24` recipe also named
1075
+ `sprite_multiplex_8`, a second multiplexer it does not contain. `fli_image`
1076
+ claims the VIC bank and requires `vic_bank_select`: its layout needs bank
1077
+ 1 or 3, because banks 0 and 2 show character ROM where four of the eight
1078
+ screens go. A resident Krill loader beside a VIC bank owner now says not
1079
+ to write `$DD00` raw while the loader is armed; it said Krill should
1080
+ follow the bank owner. `irq_chain_table` against a raster effect names
1081
+ the table as the host. `sid_play_routine_pattern`'s claims rest on the
1082
+ player contract, not a listing: basis `estimated`.
1083
+
1084
+ Step 0: `sprite_multiplex_8`'s Cost held the recipe's demo payload
1085
+ (9,162); the three multiplexer calls measure at most 5,301. `simple-shmup`
1086
+ named `soft_scroll_h` and `sprite_collision_detect`, which it does not
1087
+ implement.
1088
+ **Candidate list, Tier B batch 1 (data 737).** Four measured items.
1089
+ `high_score_table_insert` on the text page with a KickAssembler recipe:
1090
+ a BCD compare from the most significant byte, a bounded shift and the
1091
+ tie rule, four inserts checked against an expected table byte for byte,
1092
+ the worst insert 481 cycles by CIA timer and by the instruction count;
1093
+ it realises the "table re-sorted" check on the front-end pattern, which
1094
+ the complete-game build of the night before skipped. The CIA revision:
1095
+ VICE 3.10 models the one-cycle difference between the old 6526 and the
1096
+ 6526A or 8521, measured as an alternating latency pair of `$12`/`$11`
1097
+ under `-ciamodel 0` and `$10`/`$11` under model 1, the default behaving
1098
+ as the new part; new pitfall `cia_revision_irq_one_cycle_late` with a
1099
+ detection recipe pinned under the old model on both regions. The
1100
+ time-of-day alarm: `tod_alarm_interrupt` with a recipe that sets the
1101
+ clock, arms an alarm three seconds ahead and reads the time in the
1102
+ handler; it fired after 149 PAL and 179 NTSC frames against 150 and 180
1103
+ expected, the one-frame shortfall being the mains tick's phase, and with
1104
+ the 50/60 Hz bit the wrong way the same alarm took 180 PAL frames and 149
1105
+ NTSC, the drift the page quotes. `isqrt_16bit` and `atan2_8bit` on the
1106
+ maths page: the root exact on 35 cases and within bounds on all 65,536
1107
+ inputs (869 cycles worst), the angle within one unit of 256 on 36 cases
1108
+ on the machine and on all 65,536 pairs in the host model (381 cycles
1109
+ worst). The VICE reference now says that the exit screenshot is the
1110
+ draw buffer at the cycle the limit hits, rows above the beam new and
1111
+ rows below from the previous field, measured on the eight-way scroll
1112
+ recipe while its pin was chosen. Left open: the PAL alarm's arrival
1113
+ varying by about fifty cycles between identical runs; the machine sweep
1114
+ of every atan2 pair; every CIA figure is VICE's, none from silicon.
1115
+
1116
+ **Issue #21, ES-19 to ES-22.** `reu_dma` (one cycle a byte blanked;
1117
+ badlines and sprites slow it with the screen on), `four_player_read`
1118
+ (the user-port adapter; directions under the select are from the sources,
1119
+ since VICE cannot drive them headless), `cartridge_save` (EasyFlash flash
1120
+ writes need Ultimax mode; a save survives across two runs) and
1121
+ `raster_profile_bars` (border bars and a CIA table agree within a line),
1122
+ each with a recipe pinned on PAL and NTSC. `verify:recipes` now runs
1123
+ cartridge recipes: a `cartridge` key in runs.json boots the `.crt` the
1124
+ listing writes, once or several times on the same copy. A new Oscar64
1125
+ gotcha: `#define A()` with an empty parameter list is refused.
1126
+ **Design layer, slice 4 (data 735).** Four Oscar64 recipes that realise
1127
+ the pattern pages, each with a technique entry, a pinned verdict on both
1128
+ models and its name on the pattern's Realised-by line.
1129
+ `attract_mode_input_replay` (`oscar64/attract-replay`): the demo is the
1130
+ game fed from a recorded input stream through the same input byte, with
1131
+ the random generator reseeded; the reseeded build ends its 285-frame
1132
+ replay at the recorded position and the unseeded build 210 pixels away,
1133
+ both agreeing with a host model; the replay step costs 68 cycles a frame.
1134
+ `difficulty_ramp_tables` (`oscar64/difficulty-tables`): a six-row level
1135
+ table read at level start with a region scaler from the detection
1136
+ routine; compensated, level 3 arrives at 22,500 ms on PAL and 22,586 ms
1137
+ on NTSC; uncompensated, at the same frame count on both and 18,839 ms on
1138
+ NTSC, the 50:60 ratio. `two_player_state_swap` (`oscar64/two-player`):
1139
+ alternating play swaps an 8-byte block per player on death (206 cycles),
1140
+ simultaneous play reads both ports each frame; with `$DC00` set to `$FF`
1141
+ before the port-1 read, none of 40 reads was column-selected, without it
1142
+ all 40 were; the phantom press itself is not measured because VICE's
1143
+ keyboard feed writes the KERNAL buffer, not the matrix.
1144
+ `flip_screen_rooms` (`oscar64/flip-screen-rooms`): room records with edge
1145
+ exits and RLE tiles, five rooms, a scripted walk through all of them;
1146
+ the worst full-room redraw is 42,141 cycles, about two PAL frames, so the
1147
+ screen is blanked for two frames on PAL and three on NTSC rather than
1148
+ drawn in one vertical blank, and the pattern page's sentence saying
1149
+ otherwise is corrected. A defect met on the way and worth a pitfall: a
1150
+ colour-RAM index past 1,000 lands in the CIA1 register mirror at `$DC00`.
1151
+
1152
+ **Candidate list, Tier A batch 5 (data 734).** Four corrections and one
1153
+ new technique, each measured with a tool built or driven here. The
1154
+ KERNAL tape encoding: the TAP section said two pulse lengths; a TAP that
1155
+ the windowless VICE recorded from a real SAVE shows three (modes 376,
1156
+ 536 and 704 cycles), a bit as a pulse pair, a byte marker, twenty pulses
1157
+ a byte with odd parity, the countdown from `$89` and from `$09`, two
1158
+ copies of every block and the XOR checksum, all decoded with no parity
1159
+ failure over 448 bytes; new pitfall `tape_bit_is_a_pulse_pair_not_a_pulse`.
1160
+ GoatTracker: the asset-pipelines page named a converter, `gt2asm`, that
1161
+ the 2.77 distribution does not contain (it ships five executables, and
1162
+ the export path is the relocator, `gt2reloc`, measured: 1,786 bytes at
1163
+ `$1000` for one example song, byte-identical when imported into
1164
+ KickAssembler); the five wrong invocations are corrected and a `.SNG`
1165
+ field table joins the formats page, checked by parsing the distribution's
1166
+ fourteen example songs. `pwm_digi` on the SID page with a recipe: the
1167
+ sample rides the pulse width under a fixed carrier; measured from a WAV
1168
+ VICE wrote, the carrier at 3,848.6 Hz and the recovered tone at 240.5 Hz
1169
+ against a synthesised 240.54 Hz, 128 cycles a sample kept exactly on
1170
+ both models, reSID's 8580 at 0.74 of the 6581's level; the page's
1171
+ TEST-bit paragraph now says it was not Harsfalvi's method. Nobody
1172
+ listened. Exomizer 3.1.3b0 built from source: the default stream is
1173
+ `-P39`, `-P0` differs in 86 bytes, and the shipped decruncher at its
1174
+ defaults decrunches `-P39` and crashes on `-P0`, `-P7` and `-P55` (the
1175
+ `-P0` case ran its output pointer below the destination and overwrote its
1176
+ own data), while a single-bit mismatch completes silently with wrong
1177
+ bytes; new pitfall `exomizer3_proto_flags_mismatch`, `exomizer_basics`
1178
+ corrected in place. Left open: the PWM loop's true floor between 36 and
1179
+ 128 cycles a sample; the GoatTracker GTS2 to GTS4 layouts; an Exomizer 2
1180
+ decruncher against a 3.x stream.
1181
+
1182
+ **Code quality, phases C–F (tools 1.29.0, package 0.9.0).** Every MCP
1183
+ tool now has a `title` and `annotations` (read-only, destructive,
1184
+ idempotent), per the MCP spec; names, descriptions and schemas are
1185
+ unchanged. Search returned a different top five on repeated identical
1186
+ queries: Qdrant orders RRF-tied points arbitrarily. Ties now break by
1187
+ point id. The code was restructured without changing output: 20 CLI
1188
+ commands, text and JSON, are identical to the previous tree; a clean
1189
+ ingest into a throwaway graph gives the same 717 nodes, 2903 edges and
1190
+ 3555 points. `extractGraphEntities` (cognitive complexity 291),
1191
+ `checkCompatibility` (150), `buildBriefing` (97) and ingest's `main`
1192
+ (81) are now tables of small functions, each under 15. The compatibility
1193
+ rules are a pure function with their own tests, and its per-technique
1194
+ queries are batched. ESLint (typescript-eslint strict, a complexity
1195
+ budget), Prettier and knip are gates: 848 lint findings to 0. The
1196
+ type check adds `noUncheckedIndexedAccess` and
1197
+ `exactOptionalPropertyTypes`. `health` reported an unreachable graph as
1198
+ healthy with zero nodes; it now fails. The CLI rejects out-of-set
1199
+ values for `--region`, `--toolchain`, `--language`; `pal-ntsc-diff`
1200
+ fell back to "both" silently. `verify:recipes --jobs` ran jobs one at a
1201
+ time; it now runs them in parallel. CI runs the gates (the VICE
1202
+ screenshots included: a Linux build of the headless VICE matched every
1203
+ pinned PNG it could run). Oscar64 recipes pass only with a locally
1204
+ patched compiler; that is #25.
1205
+
1206
+ **Design layer, slice 1 (data 733).** Four pages above the mechanics
1207
+ layer, written as original prose from public sources by people who
1208
+ shipped, facts and names only: `game-design/game-structure.md` (the
1209
+ state machine, level end conditions, level transitions, the front end
1210
+ and attract mode), `game-design/enemy-behaviour-and-difficulty.md`
1211
+ (interaction patterns, personality by target, attack pattern tables, the
1212
+ difficulty ramp, a playtest protocol), `game-design/production-planning.md`
1213
+ (build order, memory budget first, scope and region, tooling and editors,
1214
+ where the surviving documents are) and `demo-design/demo-composition.md`
1215
+ (the part lifecycle, transition conditions, pacing and length, music
1216
+ continuity across parts, the composition workflow). Each pattern is an
1217
+ H2 in the technique style with `Kind`, `Applies to` (archetypes that
1218
+ exist), `Realised by` (techniques and recipes that exist), `Sources` and
1219
+ a `Checks` list of statements a headless harness can test on a build.
1220
+ The extractor reads these pages as prose only; the metadata lines are
1221
+ laid out so a later extractor can read them without a rewrite (issue 24
1222
+ has the plan for Pattern nodes and a Structure section in the briefing).
1223
+ The pages exist because every game generated from the base on
1224
+ 2026-09-22 shared three faults they describe: levels ending on a frame
1225
+ counter, sprites and score digits left on the title after game over, no
1226
+ working restart. Nothing on them was measured in VICE; every figure is
1227
+ its source's or arithmetic, and each page says what its sources did not
1228
+ say. Not found in the sweep and therefore not on the pages: attract-mode
1229
+ construction from an original developer, music direction from a
1230
+ composer, first-person design retrospectives of the major demos.
1231
+
1232
+ **Issue #21, ES-15 to ES-18.** `iffl_single_file` (the KERNAL skip
1233
+ fallback, measured; drive-side scan described, not built),
1234
+ `runtime_relocation` (two-origin diff, 855 cycles for 19 bytes),
1235
+ `sfx_in_player` and `goattracker_player_api`, and
1236
+ `irq_owns_processor_port` (18 cycles a handler), each with a recipe
1237
+ pinned on PAL and NTSC.
1238
+
1239
+ **Issue #20, corrections.** The Sparkle section is rewritten from its
1240
+ manual (by Sparta, PAL and NTSC, blocking calls, 72 cycles a byte); the
1241
+ `$DD00`/`$DD02` rule is scoped per loader; the VSP crash paragraph follows
1242
+ lft's article (no detection method); GoatTracker 2 has one SID model
1243
+ setting; a new pitfall for SID replacements that cannot read `$D41B`;
1244
+ `c64-file-formats` now says a last sector stores the index of the last
1245
+ used byte. Each carries a correction clause.
1246
+
1247
+
1248
+ **Candidate list, Tier A batch 4 (data 731).** Three of the four items
1249
+ landed. `mouse_1351_read` on the input page with a KickAssembler recipe:
1250
+ the 1351's proportional mode is a six-bit position counter in bits 1 to
1251
+ 6 of the pot registers, not the quadrature the SID page still describes.
1252
+ Measured in VICE's 1351 model: the masked counter read 32 on both axes on
1253
+ every one of 250 frames on PAL and NTSC, raw bit 0 changed between
1254
+ consecutive frames over a hundred times per run, so the picture prints
1255
+ the masked value only; the signed modulo-64 delta is checked on ten
1256
+ compiled-in samples including both wraps and both half-turn cases; one
1257
+ read of both axes costs 104 cycles by the instruction count and 103 by
1258
+ the CIA timer, a one-cycle gap the page leaves open. The buttons' lines
1259
+ (fire and up) are from the documentation, not pressed here. The SID
1260
+ page's quadrature sentence is reported, not edited (see issue 9).
1261
+ `fld_flexible_line_distance` on the raster page with a recipe that
1262
+ bounces the display by rewriting YSCROLL each line: the top text row sat
1263
+ exactly N lines lower on both models, the first badline landed on line
1264
+ 51 plus N on every frame, and every gap line showed the idle fetch of
1265
+ `$3FFF`, which is the new pitfall `idle_fetch_byte_shows_in_gaps`; a
1266
+ YSCROLL value that matches the next line only at its first cycle moves
1267
+ the display one line, not N. The sideborder recipe's dangling `fld` and
1268
+ `vsp` links now point at real techniques. `d64_error_byte_is_a_controller_code`
1269
+ on the loader page, with the D64 section of the file-formats page
1270
+ corrected in place: the per-sector byte is the controller's job code,
1271
+ and read back through the drive's error channel under VICE 3.10 the codes
1272
+ `$02`, `$03`, `$04`, `$05`, `$09` and `$0B` are honoured and `$07`, `$08`
1273
+ and `$0F` ignored; a lone sector flagged `$03` or `$0B` reads 20, and
1274
+ only a whole track carrying the code reads 21 or 29. The IEC page's
1275
+ "not measured here" sentence on that point now cites the measurement.
1276
+ The eight-way scroller did not land: its writer stalled six times in the
1277
+ reading phase and runs again alone.
1278
+
1279
+ **Runtime fixes, phase B (tools 1.28.1, package 0.8.1).** Nothing
1280
+ listened for the FalkorDB client's `error` event, so a FalkorDB restart
1281
+ would throw and end the MCP server; it now logs to stderr and the
1282
+ client reconnects. Two tool calls on a cold server each opened a
1283
+ connection; the connection promise is now shared. The server ignored
1284
+ stdin closing, the MCP spec's shutdown signal; it now closes its
1285
+ connections and exits (6 ms after stdin closed, measured by the new
1286
+ `test/mcp-stdio.test.ts`, which also asserts stdout carries only
1287
+ JSON-RPC). It reported version 0.1.0; it reports the package version.
1288
+ `c64_ingest_doc` indexed new content without writing it when the file
1289
+ existed, and kept a page's old chunks, so removed sections stayed
1290
+ searchable; it now writes the file and replaces the chunks.
1291
+ `c64_run_game` and the memorization check returned failures without
1292
+ `isError`; the memorization tool is registered only where `analyzer/`
1293
+ exists, which is not this repository. `c64_run_game` killed every
1294
+ `x64sc` on the machine; it kills only the one on its monitor port.
1295
+ `ensureSchema` swallowed every error, not only "already indexed" and
1296
+ "Constraint already exists" (messages measured on FalkorDB 4.18.7).
1297
+ Gap logging ran select-then-insert without a transaction across two
1298
+ processes. CLI commands ended in `process.exit()`, which can truncate
1299
+ piped `--json`; they now close their connections and set the exit code.
1300
+ A malformed environment variable stops start-up with its name instead of
1301
+ becoming `NaN`.
1302
+
1303
+ **Issue #21, ES-11 to ES-14.** `nav_area_pathfinding` (a next-hop table
1304
+ over platform areas; 0 of 160 hops differ from a Python model),
1305
+ `multi_sprite_object` (a boss from six sprites across the X 255 seam,
1306
+ registers checked every frame), `charset_parallax` (background glyphs
1307
+ rolled at half the foreground's speed; 0 of 55,936 pixels differ from a
1308
+ model), `world_state_bits` and `password_encoding` (every single-letter
1309
+ typo and every neighbour swap caught for all 2^20 states). A new Oscar64
1310
+ gotcha, measured: at -O1 to -O3, `c == 255 ? 255 : a[c]` with `a`
1311
+ shorter than 256 loses its guard and reads `a[255]`.
1312
+
1313
+
1314
+ **Tooling, phase A (no tool surface change).** `tsc --noEmit` checked
1315
+ `src/` only, so `scripts/` and `test/` were never type-checked; three
1316
+ errors in `test/config.test.ts` and six unused symbols had gone unseen.
1317
+ `tsconfig.json` now checks all three and emits nothing;
1318
+ `tsconfig.build.json` builds `dist/` and leaves tests out. Relative
1319
+ imports end in `.ts`, so Node 24.12+ runs the sources directly and `tsx`
1320
+ is gone (`node src/cli.ts`, `npm run health`, `npm run typecheck`). `npm
1321
+ pack` shipped no `dist/` (`.gitignore` excluded it and there was no
1322
+ `files` list), so a published `bin` would not have run; `files` and
1323
+ `prepack` fix that. Removed four dependencies nothing imported (`yaml`,
1324
+ `js-yaml`, `@types/js-yaml`, `@anthropic-ai/vertex-sdk`). Qdrant and
1325
+ FalkorDB are pinned by digest instead of `:latest`. Tests split into a
1326
+ `unit` project (no services, parallel) and an `integration` project. The
1327
+ Claude Code hooks match `Edit|Write` (`MultiEdit` no longer exists), call
1328
+ the project's own `tsc` (`npx tsc` without `node_modules` fetched an
1329
+ unrelated package), and a new Stop hook builds `dist/` and runs the unit
1330
+ tests once per turn instead of rebuilding after every edit.
1331
+
1332
+ **Candidate list, Tier A, batch 3.** The start-up hang a blind build hit is
1333
+ now a pitfall with a measured table behind it,
1334
+ `first_open_after_reset_hangs_on_pal`: on PAL a program whose first OPEN
1335
+ follows the autostart by ten frames hung three times out of three while
1336
+ zero, five, twenty and fifty frames ran, so the wait is not the cure it
1337
+ looked like; NTSC never hung; loading the program through the drive
1338
+ instead of injecting it ran to game over; the monitor at the hang shows
1339
+ the C64 waiting for CLK with the drive a few dozen cycles from TALK, and
1340
+ why it never arrives unperturbed is still open. `level-rle-decoder` (Oscar64)
1341
+ compresses three real-shaped rooms, decodes them on the machine against a
1342
+ host checksum and shows ratio, cycles and decoder bytes per room; the
1343
+ patterns page's unmeasured ratio and decoder-size sentences now carry the
1344
+ measured figures. `paddle_read` on the input page with the KickAssembler
1345
+ recipe `paddle-read`: the port-select dance, the settle measured on both
1346
+ models (within 480 cycles at six of eight phases, 544 at two) and the
1347
+ keyboard scan's interference counted; positions and buttons are not
1348
+ measured because a headless host cannot move a paddle. The eight-way
1349
+ scroller planned for this batch did not land: its writer stalled and will
1350
+ run again on its own.
1351
+
1352
+ **Issue #21, engine subsystems ES-01 to ES-10.** Ten techniques from an
1353
+ online sweep of how shipped games were built, each with a recipe pinned on
1354
+ PAL and NTSC: `sprite_multiplex_game` (an assembly multiplexer with the
1355
+ sort kept between frames and a late-IRQ guard; 611 cycles for 24 sorted
1356
+ actors), `scroll_panel_split` with the pitfall
1357
+ `scroll_phase_breaks_panel_split` (a naive split breaks at one YSCROLL
1358
+ phase, the split line mod 8, measured at all eight), `logic_rate_decoupling`,
1359
+ `actor_activation_window`, `wave_director`, `per_frame_hitbox`,
1360
+ `char_bullets`, `sprite_cache_flip`, `sprite_animation_table` and
1361
+ `slope_collision`. Each Cost line is the measured worst frame of the
1362
+ technique's own work. Facts from Cadaver's articles and c64gameframework
1363
+ (MIT), codebase64 and Corescape (GPL); the code is original.
1364
+
1365
+ **Ontology from #21 (schema 24, tools 1.28.0).** A `**Raster band:**` line
1366
+ on techniques: `c64_check_compatibility` no longer reports two
1367
+ every-line techniques as a conflict when their stated bands are disjoint,
1368
+ and lists such pairs in `band_separated`; FLI, AFLI and IFLI state
1369
+ 45-251, the side border `movable`. `c64_timing_budget` subtracts sprite
1370
+ DMA (3 + 2 per sprite, the minimum for sprites numbered without gaps;
1371
+ input `sprites_per_line`); it did not before. The Demands word
1372
+ `serial_bus_exclusive` on the Krill loader, with a hard conflict
1373
+ `serial_bus_busy` against techniques that call KERNAL serial routines.
1374
+ Tool nodes carry `version_verified` from the toolchain pages. Corrections:
1375
+ `multi_load_sequencing` said `Uses kernal: LOAD`, but it loads through
1376
+ Krill; the ontology's Tool table listed a `category` the code never
1377
+ wrote. `dd00_plain_stores` was not added: it is Bitfire's rule and false
1378
+ for Krill.
1379
+
1380
+
1381
+ **Candidate list, Tier A, batch 2.** `charset_copy_rom_to_ram` on the
1382
+ banking page, with the KickAssembler recipe `charset-copy-rom-to-ram`: the
1383
+ 2 KB copy under the I/O window costs 19,733 cycles with the display off
1384
+ and about a thousand more with it on, the copy is checked against the
1385
+ ROM image's checksum, and the same program makes the copy once with
1386
+ interrupts enabled and shows what happens: the KERNAL interrupt fires
1387
+ into the mapped ROM and the loop never finishes, caught by a timer NMI
1388
+ watchdog. That is the new pitfall `irq_during_charen_window`.
1389
+ `nmi_handler_and_restore_key` on the CPU page, with the recipe
1390
+ `nmi-timer-tick`: the vectors, the RTI stub that disarms RESTORE, the
1391
+ `$DD0D` acknowledge and the lock without it, measured with a CIA2 timer
1392
+ standing in for the key the rig cannot press; a new pitfall
1393
+ `kernal_nmi_handler_runs_stop_check`. `software_sprite_preshifted` on the
1394
+ sprite page, with the recipe `software-sprite-preshifted`: a 24x21 masked
1395
+ object pre-shifted for eight positions in a character back buffer, 1,428
1396
+ cycles a blit at every shift, against the multiplexer for when each wins.
1397
+ A new pitfall `sprite_x_range_hidden_and_seam` with the visible window
1398
+ measured column by column on both models (X 24 to 343 visible, 23 and
1399
+ 344 not) and the PAL seam pinned between $1F7 and $200. The autopilot
1400
+ pattern from the same tier is covered by the headless-verify recipe's
1401
+ autopilot section.
1402
+
1403
+ **Candidate list, Tier A, batch 1: four things every agent reaches for
1404
+ and the KB did not have.** `petscii_screen_code_conversion` (text page):
1405
+ the PETSCII to screen-code rule measured over all 224 printable codes by
1406
+ writing each with CHROUT and reading screen RAM back, the reverse-video
1407
+ bit, the shifted set through `$D018`, the colour RAM consequence, and where
1408
+ in the KERNAL the fold lives, with the Oscar64 recipe `petscii-screen-codes`
1409
+ proving the rule both ways on screen; a new pitfall
1410
+ `petscii_written_to_screen_ram` for the letters-come-out-as-graphics
1411
+ symptom. `compare_16bit_and_signed` (maths page): unsigned 16-bit compare
1412
+ high byte first, the signed idiom with the overflow flag and why a bare
1413
+ BMI fails across the boundary, ranged compares, and what Oscar64 emits,
1414
+ with the KickAssembler recipe `compare-16bit-signed` sweeping the boundary
1415
+ pairs and counting the bad form's failures (16,384 of them); a new pitfall
1416
+ `signed_compare_bmi_overflow`. `division_8_16bit` (maths page):
1417
+ shift-and-subtract division in three widths, reciprocal multiply with its
1418
+ error bound, divide by ten against the subtract-powers route, with the
1419
+ Oscar64 recipe `divide-check` checking quotient and remainder over the
1420
+ full 8-bit range and timing every route. `sine_table_generation` (CPU
1421
+ page): quarter-wave, second-difference and parabola generation with the
1422
+ worst and mean error of each against a host table and the cycles to build
1423
+ 256 entries, with the KickAssembler recipe `sine-table-runtime` driving a
1424
+ visible sprite sine from the table it just built. Every new technique is
1425
+ anchored on the pitfalls its code meets.
1426
+
1427
+ **The recipe lookup carries the listing.** `c64_recipe_lookup` and the
1428
+ CLI's `recipe-lookup` returned a recipe's Build, Synopsis and Expected
1429
+ output sections and never its Source listing, so a caller with no file
1430
+ access, an MCP client on another machine or a model that will not open a
1431
+ page, could not copy the code. Nine builds of one game showed it: the two
1432
+ strong models that read the page file shipped the recipe; the one that
1433
+ trusted the answer built from prose. The answer now ends with the page's
1434
+ Source fence, the one the listing gate builds and the pinned screenshot was
1435
+ made from, and the structured output carries it as `source_code`. Tools
1436
+ 1.27.0.
1437
+
1438
+ **Batch 9c: transitions, disk work and a release disk.** The transitions
1439
+ page is complete: `colour_cycling` (one step over eight rows of colour RAM,
1440
+ 3,265 cycles on either model) and `screen_wipe` (a row written out in 491
1441
+ cycles, in at 708 or 709), each with a KickAssembler recipe pinned mid-
1442
+ effect and checked pixel by pixel against its own formula; both recipes
1443
+ record a first draft whose single-compare busy-wait fell through the
1444
+ raster line twice a frame and double-counted. `load-asset-runtime`
1445
+ (Oscar64) builds a charset, saves it, loads it back to an address of its
1446
+ own choosing and shows it, with the KERNAL's LOAD measured to leave the
1447
+ raster interrupt armed and `$D011` alone; the technique page gained the
1448
+ secondary-address facts and the header page's `krnio_load` note. The new
1449
+ technique `kernal_relative_file_io` and its recipe `relative-file-records`
1450
+ create a REL file with 32-byte records, position with the P command, and
1451
+ quote what the drive says, including the 50 and 51 replies provoked in
1452
+ VICE for the first time here. `toolchains/release-disk.md` builds a D64
1453
+ from the platformer scaffold with c1541, lists it, autostarts the disk
1454
+ itself headless and shows the game running from it, with the block
1455
+ arithmetic and a Makefile target; two screenshots of that boot ride with
1456
+ the scaffold recipe. The verifier still only formats a disk; a `files` key
1457
+ to place a built PRG on it is proposed on the page and not built.
1458
+ For a few hours the verifier and the pages carried `-minimized` on every
1459
+ headless VICE command to stop a batch of runs taking the desktop's focus;
1460
+ it was withdrawn the same night because a window that opens and then
1461
+ minimises is worse than one that opens, and the pictures were byte-identical
1462
+ either way. The fix landed the same night: VICE 3.10 built with
1463
+ `--enable-headlessui` has no window at all and its exit screenshots are
1464
+ byte-identical to the pins (four recipes, both models, and the disk-backed
1465
+ ones); `npm run vice:headless` builds one into `.tools/` from the pinned
1466
+ tarball, and every emulator launch in the repository (the verifier, the
1467
+ run tool) prefers it when present, with `X64SC_BIN` as an override; the
1468
+ VICE page says how it works and the one flag-order trap.
1469
+
1470
+ **Pitfalls reached through a technique's registers, and a graph report.**
1471
+ A technique also meets every pitfall that a register or KERNAL routine it
1472
+ declares triggers. Both ends of that join are exact declarations on the
1473
+ pages, so the edge is derived rather than guessed, which is the one kind
1474
+ of graph edge the literature on retrieval finds worth having. The
1475
+ pitfalls tool now adds those pitfalls after the direct ones and names the
1476
+ register that carried each; `ecm_mode` went from no answer to four
1477
+ pitfalls, and thirteen techniques with no direct anchor now reach one.
1478
+ `npm run graph:report` prints the graph's shape: node and edge counts,
1479
+ technique degree, connected components and the largest one's share,
1480
+ isolated nodes, techniques without a recipe or without any pitfall by any
1481
+ route, and per-archetype feature, risk and scaffold counts. Its first
1482
+ reading, in the commit that added it, said the largest component held two
1483
+ thirds of the nodes and the rest were isolated memory regions, and that
1484
+ fourteen techniques had no pitfall by any route. Those are the numbers to
1485
+ watch before expecting the graph to pull ahead of the text.
1486
+
1487
+ **Source lints compiled from the pitfalls (tools 1.26.0).** A new MCP
1488
+ tool, `c64_lint_source`, and CLI subcommand, `lint <file>`, run the
1489
+ knowledge base's rules over an agent's own C or assembly source with no
1490
+ graph or vector store involved. Eight rules, each named after the
1491
+ pitfall it compiles and pointing at its page: `sid_write_only_registers`,
1492
+ `cia1_ddr_cleared_kills_keyboard`, `empty_name_open_15_hangs_on_read`
1493
+ (from the high-score recipe's warning), `raster_poll_with_kernal_irq_live`
1494
+ (anchored on `raster_irq_first_line_jitter` and the frame-sync recipe),
1495
+ `lfsr_zero_state_lockup`, `decimal_mode_in_irq_handler`,
1496
+ `d016_unmasked_rmw_clobbers_csel_mcm` and `jmp_indirect_page_boundary_bug`.
1497
+ Every finding carries a certainty (`definite`, `likely`, `heuristic`) and
1498
+ the message uses the page's own words for the mechanism and the fix. The
1499
+ test runs the linter over the two platformer builds from the 2026-09-22
1500
+ three-arm test, copied into `test/fixtures/`: on the build made without
1501
+ the knowledge base it reports the SID read-modify-write, the DDR clear,
1502
+ the empty-name OPEN and the raster poll at their lines; on the build made
1503
+ with it, no definite finding. The first draft flagged
1504
+ `#include <c64/sid.h>` as a SID read; preprocessor lines are now skipped.
1505
+ Review of the first draft against every listing in `docs/` changed four
1506
+ rules. The decimal-mode rule had the pitfall backwards (it flagged a SED
1507
+ that reaches RTI, where the page's fault is a handler that reaches ADC
1508
+ or SBC before any CLD); it now follows an installed handler from its
1509
+ label and has no C form, since in C the arithmetic is the compiler's.
1510
+ Read that way it fires on the KB's own `stable-raster-irq`,
1511
+ `cracktro-template`, `dycp-scroller` and `sine-scroller` handlers, none
1512
+ of which CLD; none of those programs executes SED either, so those are
1513
+ heuristic, and the pitfall page and the recipes are left to be
1514
+ reconciled. The `$D016` rule read the first `lda #` in its window
1515
+ rather than the one that feeds the store, which flagged
1516
+ `sideborder-open` and missed a bad store; it walks back to the load
1517
+ now. The empty-name OPEN rule is `heuristic`, not `likely`: the
1518
+ high-score recipe measured a bare OPEN of channel 15 returning success
1519
+ with no drive, while `techniques/file-io.md` opens the channel bare and
1520
+ expects the carry set, and the message names both rather than pick one.
1521
+ Language detection strips comments and tests for assembler signatures
1522
+ first, so a KickAssembler `.for` block no longer reads as C. The package
1523
+ version follows at release.
1524
+
1525
+ **Schema 23: the scaffold is an edge.** A recipe page may now carry
1526
+ `scaffolds: [vertical_shmup, horizontal_shmup]` in its frontmatter, an
1527
+ array of Archetype names; the ingest links `Recipe -[:SCAFFOLDS]->
1528
+ Archetype` in pass 2 with both ends matched, drops a name that matches
1529
+ no Archetype with a warning, and reports `scaffolds … dropped` on the
1530
+ summary line beside the other relations. `c64_game_briefing` reads that
1531
+ edge for its first build step in place of matching the string "shmup"
1532
+ against the archetype name and offering `oscar64-simple-shmup` by name;
1533
+ the step's text now also names the recipe's page so an agent knows which
1534
+ file to copy. The fallback tables, used only by a graph with no
1535
+ Archetype nodes, still offer the shmup scaffold by name. The shmup
1536
+ recipe carries the key for both shmup archetypes. `ONTOLOGY.md` and
1537
+ `CONVENTIONS-recipes.md` document the edge and the key.
1538
+
1539
+ **Batch 9b: text and demo effects the gap map still owed.** Four new
1540
+ techniques, each with a pinned, measured recipe. `big_font_2x2` on the
1541
+ text page: a 2x2 charset built from the ROM font at start (about 58,000
1542
+ cycles once) and a two-row scroller whose rotate costs 708 cycles on
1543
+ either model, with the KickAssembler recipe `big-font-scroller`.
1544
+ `charset_animation` on the render page: rewriting a glyph's eight bytes
1545
+ in place against flipping whole charsets with `$D018`, 196 cycles a frame
1546
+ for the rewrite, with the Oscar64 recipe `charset-animation`; the writer
1547
+ found and fixed an NTSC ordering fault of its own on the way, a HUD write
1548
+ that spilled past the shorter vertical blank. `speedcode_generation` on
1549
+ the CPU page: a generator that emits unrolled load and store pairs into
1550
+ RAM from address tables, measured against a loop for the same copy, with
1551
+ the KickAssembler recipe `speedcode-generator`, whose text records that
1552
+ its first verdict was placed after the timed loop and passed a red case
1553
+ until it was moved. `dycp_scroller` on the scroll page: letters on a sine
1554
+ wave by copying glyph rows into per-column charset strips, with the
1555
+ KickAssembler recipe `dycp-scroller` pinned at nine million cycles and
1556
+ its PAL and NTSC timer readings as a clean illustration of the badline
1557
+ cost. Every new technique is anchored on the pitfalls its code meets.
1558
+
1559
+ **Batch 9a: what the three-arm build test said was missing.** A new
1560
+ technique page, `techniques/logic.md`, opens with `tile_grid_collision`
1561
+ (requires `tile_map_render`; 2,345 cycles on its worst frame, measured
1562
+ with the CIA timer inside the vertical blank) and `object_pool` (the
1563
+ update pass over eight live slots, 380 cycles, from the object-pool
1564
+ recipe's own harness); both platformer fingerprints now name the
1565
+ collision, so a platformer briefing proposes it. The recipe
1566
+ `tile-grid-collision` walks a scripted sprite through a landing, a wall,
1567
+ a ceiling bump, a ladder and a pit with an assert every frame, and found
1568
+ on the way that side probes must sit no further apart than a tile. The
1569
+ recipe `fixed-point-jump-velocity` jumps from two different heights with
1570
+ one velocity table, which the fixed-ground table on the older recipe
1571
+ cannot do. `headless-verify` gained an autopilot input (one define swaps
1572
+ the joystick read for a scripted port byte through the same edge
1573
+ detector) and a self-test (a forced-fault build must make the same
1574
+ verify script exit 1 before its green is trusted), and the VICE page a
1575
+ palette-safe border grading by channel dominance. Measured, a raster
1576
+ IRQ left armed through a 2 KB file write and read back corrupts nothing
1577
+ on either model, but its handler enters up to about 240 lines late while
1578
+ the bus is busy, so a border split wanders; `rirq_stop()` is a bare
1579
+ `sei` that the KERNAL's own `cli` cancels, so wrapping the calls in it
1580
+ changes nothing, and clearing `$D01A` is what actually keeps the
1581
+ interrupt out. That is the new pitfall `raster_irq_during_serial_io` and
1582
+ a section on the high-score recipe. The PAL start-up hang a blind build
1583
+ hit is located but not explained: the KERNAL waits with no timeout for
1584
+ the drive to pull CLK at the talk turnaround, and why the emulated 1541
1585
+ does not is open. Two lines elsewhere were wrong and are corrected: the
1586
+ IEC page's "approximately 64 ms" timeout (the only timeout is about
1587
+ 1,024 cycles around the acknowledge wait, and a stalled turnaround never
1588
+ returns) and the Oscar64 header page's `rirq_stop()` "disables it".
1589
+ Three more pitfall anchors on the KERNAL page for the decimal-mode,
1590
+ IRQ-chain and text-input techniques.
1591
+
1592
+ **The briefing proposer, measured against a real brief.** The three-arm
1593
+ build test handed the game briefing a nine-part platformer brief and it
1594
+ proposed eight techniques the brief did not need while missing eight of
1595
+ its nouns. Four causes, each fixed and tested on the fixture graph. The
1596
+ keyword scorer matched substrings, so "budget bar" proposed raster bars
1597
+ and "tile map" reached every bitmap technique through the category word;
1598
+ it matches whole words now. It kept ten candidates whatever the brief's
1599
+ length, so the LFSR fell off the end; the limit scales with the brief.
1600
+ The vector supplement filled every remaining slot with guesses; it adds
1601
+ at most four when the brief's own words already found most of the plan.
1602
+ And the toolchain handoff sent stable raster IRQs, raster bars and the
1603
+ multiplexer to KickAssembler although this knowledge base carries an
1604
+ Oscar64 recipe for each; a cycle-tight technique with a recipe in the
1605
+ primary toolchain now stays there and is named as kept, and only one
1606
+ that needs every cycle of the line, is scene-tier, or has no Oscar64
1607
+ recipe is handed off. Every plan now ends with a headless verification
1608
+ step naming the Oscar64 harness recipe, because a brief that asks for a
1609
+ harness had no technique node to reach it through. Two nouns that
1610
+ existed only as recipes have technique nodes: `decimal_print` in
1611
+ `techniques/text.md`, with the print-number recipe's measured cycle
1612
+ figures as its cost line, and `memory_layout_plan` in
1613
+ `techniques/memory-banking.md`, implemented by the memory-layout recipe.
1614
+ On the same brief the proposal now carries the LFSR, the file read, the
1615
+ fixed-point and jump-table techniques and the decimal print it missed,
1616
+ and the handoff is one technique instead of three.
1617
+
1618
+ **Pitfall anchors for the new techniques.** A briefing agent asked
1619
+ `pitfalls-for frame_sync_loop` and got nothing, although the badline,
1620
+ raster-jitter, `$D012` wrap and PAL/NTSC pitfalls all apply to it: the
1621
+ techniques added this month had no pitfall naming them, so the graph had
1622
+ no edge to follow. Twenty-seven pitfall entries now name the techniques
1623
+ whose code meets their mechanism, added only where the pitfall's own text
1624
+ supports it; a double buffer is listed as a mitigation of the full-field
1625
+ redraw overrun rather than a trigger of it. One pitfall is new,
1626
+ `cia1_ddr_cleared_kills_keyboard`: clearing `$DC02` to read joystick 2
1627
+ leaves the KERNAL keyboard scan driving nothing, which a blind build did
1628
+ today and no headless run can see. `npm run check:pitfall-anchors`
1629
+ reports the techniques still without an anchor and fails on a dangling
1630
+ name; the ones that remain are mostly effects and packers for which no
1631
+ written pitfall applies yet.
1632
+
1633
+ **Two tool faults from the blind build test.** An agent that built a
1634
+ game from the knowledge base alone logged what got in its way; two of
1635
+ the items were the tools, not the pages. Every CLI lookup now honours
1636
+ the global `--json` flag and prints the same structured object the MCP
1637
+ server returns; only the briefings did before. And a briefing given a
1638
+ partial archetype name resolves it when exactly one archetype contains
1639
+ every word of it (`racing`, `cracktro`), reports the candidates when
1640
+ several do (`platformer` names two, `shmup` two), and only then falls
1641
+ back to listing every known name; the builder had spent a call learning
1642
+ that `platformer` was not a name. Tools 1.25.1.
1643
+
1644
+ **A cost line per technique, so a briefing can add a plan up (#17).** A
1645
+ technique page may now carry `**Cost:**` with integer pairs from a fixed
1646
+ vocabulary (`cycles_per_line`, `cycles_per_frame`, `lines_active`,
1647
+ `bytes_code`, `bytes_data`, `zp_bytes`, `irq_slots`) and a companion
1648
+ `**Cost basis:**` line that says how the figures were obtained, one word
1649
+ from `measured-vice`, `derived-listing`, `arithmetic` or `estimated`.
1650
+ The extractor skips an unknown key or a non-integer value with a
1651
+ warning and drops the whole line for a basis word outside the set or a
1652
+ missing basis line; the values land on the `Technique` node as
1653
+ `cost_<key>` and `cost_basis` (schema 22), cleared again when a page
1654
+ drops the line. `c64_technique_lookup` returns them as `cost`.
1655
+ `c64_demo_briefing` and `c64_game_briefing` gain a `budget` block: the
1656
+ sum of `cycles_per_frame` over the proposed set against the region's
1657
+ frame (PAL 19,656; NTSC 17,095) and the sum of code and data bytes
1658
+ against a stated 38,911-byte budget, with the techniques that have no
1659
+ cost line named so the sums read as floors, an over or under verdict,
1660
+ and the weakest basis word among the contributors. The techniques
1661
+ whose recipe pages state figures carry a line, each figure taking the
1662
+ basis its page supports and no more; a figure the page measured in VICE is `measured-vice`, one
1663
+ read off a build's segment listing is `derived-listing`, one worked
1664
+ from settled constants is `arithmetic`, and a judgement is `estimated`.
1665
+ `cycles_per_frame` is the worst frame the technique produces, not an
1666
+ average, and it is the technique's own work: the soft scroller states
1667
+ its carry frame as the shipped listing measured it, the frame-sync loop
1668
+ does not state its demonstration's stand-in payload, and a level-start
1669
+ map expand states nothing per frame.
1670
+ `c64_timing_budget` no longer reads `t.irq_overhead`, a property nothing
1671
+ ever wrote; the read always fell through to the 36-cycle default and
1672
+ the constant now stands alone.
1673
+
1674
+
1675
+ **The text monitor for debugging, and cc65 symbols in it (#15).** The
1676
+ VICE reference gained a section written from real sessions: how to reach
1677
+ the monitor prompt headless (the `-console` route fails on this build,
1678
+ measured; the remote monitor works), the stop and register lines and
1679
+ what their columns mean, step, next and until, break, watch and
1680
+ conditional breaks with their transcripts, measuring cycles between two
1681
+ breakpoints from two register lines and cross-checking the delta against
1682
+ sim6502 and arithmetic, memory dump and save, and what `-limitcycles`
1683
+ does to a stopped machine. The cc65 page gained "Debugging with VICE":
1684
+ build with the label-file flag, load the labels, break on `_main`, the
1685
+ hit quoted. The symbol-file table names the cc65 route.
1686
+
1687
+ **Demo forms are archetypes too (#17).** The cracktro pattern page is now
1688
+ an archetype reference of kind `demo`: the crack intro, the demo intro,
1689
+ the pack intro, the dentro and the 4K party intro are each an `Archetype`
1690
+ node with the same `FEATURES` and `RISKS` edges the game page has, every
1691
+ name taken from the page's own text and checklist and resolving in the
1692
+ graph. Demo parts are not a node type; a form is one node. `c64_demo_briefing`
1693
+ gains an optional `archetype` input and the path `c64_game_briefing`
1694
+ already had: the form's fingerprint is forced into the plan past the
1695
+ three-per-category cap, its pitfalls join the pitfalls, and the output
1696
+ carries `archetype` or `archetype_not_found` with every known name across
1697
+ both kinds. A demo form has no built-in fallback table. The CLI's
1698
+ `demo-briefing` gains `--archetype` and honours `--json`. Tools 1.24.0
1699
+ for the input; data 717 for the page.
1700
+
1701
+ **Batch seven: multi-file projects and error tables on the toolchain
1702
+ pages, a sprite sine chain, a luminance fade.** Each toolchain page has
1703
+ a "Multi-file projects" section with a real two-file project built and
1704
+ the failing forms provoked (Oscar64 pulls a library's source in through
1705
+ `#pragma compile` from its header; one positional file with an extern
1706
+ fails with 3022; KickAssembler's `.import source` without a namespace
1707
+ clashes), and a "Reading the errors" table whose every message was
1708
+ provoked against the installed tool and quoted verbatim, the minimal
1709
+ sources kept under `toolchains/error-sources/`. `sprite_sine_chain` on
1710
+ the sprite page with the `sprite-sine-chain` recipe: eight sprites
1711
+ phased along one table across the full width with the $D010 wrap on the
1712
+ picture; the cracktro pattern page had named a multiplexer for this. A
1713
+ new `techniques/transitions.md` with `colour_fade` and the `colour-fade`
1714
+ recipe: a sixteen-step luminance-ordered fade, pinned mid-way on both
1715
+ models with every bar's colour checked against the table's formula; the
1716
+ first listing had an index overflow at the last step that the review
1717
+ caught. Colour cycling and the screen wipe are still to be written on
1718
+ that page.
1719
+
1720
+ **The 1541 DOS error codes (#14).** The IEC disk reference gained a
1721
+ table of every channel-15 code the 1541 DOS 2.6 ROM can produce, with the
1722
+ message text as the ROM spells it, the cause, and a class for an agent
1723
+ (retry, media, user error, program bug), read from the drive ROM image on
1724
+ this machine with the offsets cited, plus the mapping from D64 error
1725
+ bytes to DOS codes, which are not the same numbers. Four codes are
1726
+ provoked against a fresh disk by the `dos-error-codes` recipe and the
1727
+ replies pinned on both models; the codes that come only from the ROM text
1728
+ are marked as such. The file I/O page's two "not measured here" notes on
1729
+ message length and on codes 74 and 01 are closed by this and by the
1730
+ persistence recipe.
1731
+
1732
+ **Game archetypes are graph nodes (#17).** The archetype page had a
1733
+ technique fingerprint and a pitfall list for every archetype, and
1734
+ `c64_game_briefing` read none of them: it widened the search from a four-word table in code,
1735
+ forced techniques from a two-entry table and seeded a recipe for the one
1736
+ string "shmup". The page is now the source of truth. Each H2 with an
1737
+ `**Archetype:**` line is an `Archetype` node; its fingerprint becomes
1738
+ `FEATURES` edges to techniques and its common-pitfalls line `RISKS` edges
1739
+ to pitfalls, both MATCHed at both ends so a misspelt name is warned about
1740
+ and counted in the ingest summary, never dropped in silence
1741
+ (`docs/CONVENTIONS-archetypes.md`). The briefing looks the archetype up,
1742
+ forces every `FEATURES` target into the plan (exempt from the
1743
+ three-per-category cap), adds every `RISKS` target to the pitfalls and
1744
+ searches on the archetype's title; the output gains an `archetype` field
1745
+ repeating what the graph held, and a name the graph does not have returns
1746
+ `archetype_not_found` with the known names instead of doing nothing. The
1747
+ built-in tables survive only for a graph with no Archetype nodes, which
1748
+ is what the test fixtures build. Schema 21 for the label and two edge
1749
+ types; tools 1.23.0 for the two output fields; data 714 for the page.
1750
+
1751
+ **Two ontology repairs from the gap map (#17).** The briefing's toolchain
1752
+ handoff now decides by what a technique demands of the machine, read from
1753
+ the DEMANDS edges the compatibility checker already uses, instead of by
1754
+ category name: a technique that needs the CPU every line, raster
1755
+ interrupts inside the display, interrupts all frame, a badline-free
1756
+ region or a changing sprite set goes to KickAssembler, as does anything
1757
+ scene-tier. By category, starfield (effect) was handed to assembly and
1758
+ sprite_multiplex_24 (sprite) to C. And the recipe-to-tool link the
1759
+ ingester had always written now carries the ontology's name,
1760
+ `REQUIRES_TOOL`; it had been written as `USES`, which is why the
1761
+ ontology listed `REQUIRES_TOOL` as populated by nothing while the fact
1762
+ sat in the graph under the wrong label. Only `BUILDS_ON` remains
1763
+ unpopulated. Tools 1.22.2 for the handoff change (no surface change).
1764
+
1765
+ **Batch five: save-file policy, a sound-effect engine, memory layout in
1766
+ three toolchains, headless verification.** A "Save-file policy" section
1767
+ on the game-design page with the `high-score-persist` recipe: first run
1768
+ with no file, scratch-then-write with the scratch reply read, a version
1769
+ byte, and what the KERNAL reports with no disk (74) and with no drive
1770
+ emulated at all (the OPEN never returns in VICE; a real empty bus is not
1771
+ measured). Two things it measured that the file I/O page had marked as
1772
+ not measured: the drive's 74 reply and the command channel's "01, FILES
1773
+ SCRATCHED" reply, which is lost if channel 15 is closed before it is
1774
+ read. `sfx_engine_beside_music` on the SID page with the `sfx-engine`
1775
+ recipe: a table-driven effect with priority, borrowing a voice from a
1776
+ tune that writes all three and giving it back, verified at register
1777
+ level with a checksum over the writes; the page says nobody has listened
1778
+ to it. A new page `toolchains/memory-layout-planning.md`: the constraints
1779
+ that decide a layout and one worked layout expressed in KickAssembler,
1780
+ Oscar64 and cc65, each confirmed from its map output and each with a
1781
+ `memory-layout` recipe pinned on both models; the cc65 one needed a
1782
+ linker configuration, so `check:listings` and `verify:recipes` now pass
1783
+ a config a cc65 page carries in a fence tagged `cfg`, which is what let
1784
+ that recipe land instead of being held back. "Verifying a run without a
1785
+ human" on the VICE reference with two `headless-verify` recipes: a
1786
+ result byte at $02FF and the border colour, read back either from the
1787
+ exit screenshot or over the monitor, returning a shell exit code; both
1788
+ routes run on the green and the red case.
1789
+
1790
+ **Batch four: double buffer, Oscar64 save and load, text input, the IRQ
1791
+ chain.** `screen_double_buffer_d018` on the banking page with the
1792
+ `double-buffer` recipe and a companion built without the sprite-pointer
1793
+ mirror, whose corrupted sprite is identified byte for byte; the
1794
+ game-design page's "2 KB per page" corrected to 1 KB. The
1795
+ `save-load-seq-file` recipe: Oscar64's kernalio.h writing a score table,
1796
+ reading it back with the library status after every step and the drive's
1797
+ own reply, and a provoked 62 FILE NOT FOUND. A new page
1798
+ `techniques/text.md` (category `text`) with `text_input_line` and the
1799
+ `text-input` recipe, driven headless through VICE's keyboard buffer with
1800
+ the escape syntax that actually works quoted. `irq_chain_table` on the
1801
+ raster page with the `irq-chain` recipe: a three-slot table walked by one
1802
+ dispatcher, band boundaries measured from the picture and the frame
1803
+ counter predicted and matched. The verifier now switches the emulated
1804
+ drive's RPM wobble off for disk recipes: with it on, a disk run's elapsed
1805
+ cycles moved by a digit between runs and the NTSC round-trip picture
1806
+ failed to repeat.
1807
+
1808
+ **Batch three: object pool, KERNAL file I/O, and the instrument itself
1809
+ documented.** An "Object pool" section on the game-design patterns page
1810
+ with the `object-pool` recipe: slot table, spawn scan and free list,
1811
+ wave-table byte layout, despawn, per-slot timers, iterating active slots
1812
+ only, each timed, and the scripted scenario checksummed on the 6502. A
1813
+ new page `techniques/file-io.md` under the `io` category with
1814
+ `kernal_file_write_seq`, `kernal_file_read_seq`, `error_channel_check`
1815
+ and `kernal_load_to_address`, linked from three existing pitfalls, and
1816
+ the `file-io-roundtrip` recipe, which writes a file to a fresh disk,
1817
+ reads it back, checks the error channel before and after and prints the
1818
+ match and checksum; the verifier formats that disk with c1541 before
1819
+ every run. The VICE reference gained rows for every flag the KB's own
1820
+ protocol uses, each confirmed against `x64sc -help` and the
1821
+ autostart modes measured, and a section "Reading the exit screenshot"
1822
+ with the pixel geometry for both models, the sixteen palette RGB triples
1823
+ measured by the new `palette-cells` recipe, and a decode snippet; the
1824
+ recipe conventions, CLAUDE.md and the screenshot READMEs now point at it
1825
+ instead of carrying their own copies.
1826
+
1827
+ **Game foundations, batch two: tile maps, printing numbers, random
1828
+ numbers, lookup tables.** Four more gap-map items (#13, #16), same
1829
+ writer, reviewer and reviser shape. `tile_map_render` on the scroll page
1830
+ with the `tile-map-render` recipe: a hand-written RLE-compressed metatile
1831
+ map decoded to screen and colour RAM, every one of its 880 cells compared
1832
+ against a Python render of the same source data with zero differences,
1833
+ and the decoder's cost measured. A "Printing numbers" section on the
1834
+ game-design patterns page with the `print-number` recipe: subtract-powers
1835
+ and double-dabble in C and in assembly, every value from 0 to 65535
1836
+ rendered on the 6502 and folded into a checksum that matches Python, and
1837
+ the routes timed, which corrected the page's earlier "about 300 cycles"
1838
+ for double-dabble. `lfsr_random` on the maths page with the
1839
+ `lfsr-random` recipe and a fixed-seed companion: 8- and 16-bit LFSRs
1840
+ with measured periods and a histogram, seeding from SID voice 3 noise
1841
+ with the output muted, the CIA timer and player timing, and a new
1842
+ pitfall `lfsr_zero_state_lockup` with its MITIGATED_BY edge.
1843
+ `table_generation` on the CPU tricks page: sine, reciprocal and multiply
1844
+ tables at KickAssembler assembly time and in Oscar64, with the table bytes
1845
+ dumped from the built PRG and diffed to zero against Python for two
1846
+ scalings. Cross-links added from the pages that already used these
1847
+ things without naming them (the scroll pattern, the CharPad section, the
1848
+ sine scroller, the `.fill` row, the perspective divide, the $D41B
1849
+ paragraph).
1850
+
1851
+ **Game foundations, batch one: input, the frame loop, fixed-point
1852
+ movement.** The first additive batch from the gap map (#12, #13),
1853
+ written by one writer, one reviewer and one reviser per item. Two new
1854
+ technique pages and one new entry: `techniques/input.md` with
1855
+ `joystick_edge_detect`, `joystick_autorepeat` and `keyboard_matrix_scan`
1856
+ (category `input`); `techniques/maths.md` with `fixed_point_8_8`,
1857
+ `table_multiply_8x8` and `jump_arc_table` (category `maths`); and
1858
+ `frame_sync_loop` on the raster page, with the seven `vic_wait*`
1859
+ functions documented on the Oscar64 headers page from the header and its
1860
+ source. Each has an Oscar64 recipe with pinned, measured screenshots on
1861
+ PAL and NTSC: `joystick-input`, `frame-sync-loop` (plus a deliberate
1862
+ overrun build that shows the budget bar wrap and the dropped-frame
1863
+ counter climb), and `fixed-point-jump`. The arithmetic is checked
1864
+ exhaustively on the 6502 itself: the edge and repeat logic over all
1865
+ 65,536 previous/current port pairs, the tick arithmetic over all 65,536
1866
+ counter pairs, the multiply and signed add over all 65,536 operand
1867
+ pairs, each folded to a checksum that matches the same computation in
1868
+ Python and is quoted on the page. What could not be done headless is
1869
+ said plainly: no joystick or key was pressed in any run, so the live
1870
+ counters prove the no-input state and the logic is proven by the
1871
+ exhaustive checks.
1872
+
1873
+ **Every recipe, toolchain and runtime page audited against the installed
1874
+ tools, and every recipe now has a reproducible screenshot.** The seven
1875
+ toolchain and runtime references went through the same auditor, three
1876
+ refuters and fixer procedure as the earlier waves: 95 corrections, among
1877
+ them x64sc 3.10 options that do not exist, Oscar64 API names and
1878
+ signatures checked against the headers on disk, KickAssembler behaviour
1879
+ measured on 5.25, the cc65 CPU flag for illegal mnemonics, and the
1880
+ binary-monitor claims. The twenty recipe pages went through a lean pass
1881
+ instead, one instrument-backed agent per page with no refuter fleet,
1882
+ because the maintainer asked for the token spend to come down: 102
1883
+ corrections, 60 claims qualified as not measured here. Among the
1884
+ corrections: the KERNAL's full interrupt service costs about 190 cycles
1885
+ idle and about 1,600 with a key held, not "about a thousand" (raster-bars
1886
+ and the pages that quoted it); the FLI entry pad was one cycle late and
1887
+ the committed picture showed the symptom on line 52; the side-border
1888
+ recipe's sixth sprite had the wrong MSB and sat invisible; the Oscar64
1889
+ soft-scroller wrote PETSCII where screen codes were needed and never
1890
+ showed its message; the Koala viewer cleared CSEL while enabling
1891
+ multicolour and embedded a zero-filled stub, and now draws a computed
1892
+ test image; `vspr_init` does not call `rirq_init`, so two recipes ran
1893
+ without an IRQ dispatcher; PSID header offsets were shifted by a word;
1894
+ the filter-cutoff byte split was backwards; `joy_poll(1)` read port 1
1895
+ where port 2 was documented. Then `verify:recipes` re-ran all twenty
1896
+ recipes at pinned cycles and every baseline was looked at against its
1897
+ page before adoption: nine recipes that had no committed picture have one,
1898
+ six unpinned or wrong-path baselines were replaced, and the NTSC playfield
1899
+ picture is now taken at the same cycle count as the PAL one. The
1900
+ soft-scroller's coarse shift still takes about four frames and tears;
1901
+ that is issue #18. Two cross-page debts the agents flagged were closed by
1902
+ hand: the raster technique page's KERNAL figure and the stable-raster
1903
+ recipe's register list. Clean ingest afterwards: 2,605 chunks from 79
1904
+ files, 574 nodes, 1,308 edges, 0 dropped references, no category refused.
1905
+
1906
+ **Schema 20: technique categories for game and application foundations,
1907
+ and the category set is enforced.** `input`, `logic`, `maths`, `text` and
1908
+ `io` join the Technique category set, and `render`, which the text-mode
1909
+ page had used since it was written without ever being listed, is now
1910
+ listed. The extractor refuses a technique doc whose category is outside
1911
+ the set, with a warning, the way it already refused an unknown Demands
1912
+ word; before this a typo would have created a category the briefing
1913
+ tools do not know. Briefings place input and maths in the memory-layout
1914
+ step, logic and text in the rendering step, io in the loader step, and
1915
+ give each a reason string. This is item ONTO-01 of the gap map (#12,
1916
+ #17) and lands first because the game-foundation pages file under
1917
+ categories that did not exist. Tools 1.22.1: the `c64_timing_budget`
1918
+ description said 23 badline cycles and a 14-cycle default IRQ overhead
1919
+ while the tool computed 43 and 36; the description now matches the
1920
+ computation and its worked example is the tool's actual output.
1921
+
1922
+ **Every technique and pitfall page audited against the instruments.** The
1923
+ same procedure as the hardware pages — one auditor per page, three
1924
+ refuters per finding, majority-upheld corrections only — over all 22
1925
+ pages: 259 corrections landed, each with the earlier wrong statement named
1926
+ beside it. The largest: the stable-raster polling loop bounds jitter to
1927
+ one iteration and does not remove it (`double_irq` does); the KERNAL's IRQ
1928
+ path never executes CLD; a `$0314` handler that ends in RTI pops the
1929
+ dispatcher's registers as its return frame, and four listings did; the
1930
+ `$D017` "double-write" trick does nothing and the sprite crunch is one
1931
+ cycle, one shot and lengthens the sprite; sprite DMA is 2 cycles per
1932
+ sprite plus 3 per group, never 4; badlines cost 40-43 cycles, plan on 43;
1933
+ the main-loop joystick "phantom press" race cannot happen; Krill v194
1934
+ hooks no KERNAL vector; ByteBoozer 2's depacker is about 200 bytes, not
1935
+ 85; every depacker time quoted in milliseconds was under one cycle per
1936
+ byte; the Oscar64 vspr multiplexer costs about 250 cycles a slot, not 25;
1937
+ a 1000-cell text redraw does not fit a frame; PSID header offsets were
1938
+ shifted by a word; the filter cannot be observed from software, so the
1939
+ ENV3 chip-detect probe never worked. Sixteen findings nothing on this
1940
+ machine can reach are listed for follow-up. Metadata lines changed on
1941
+ eight pages, so the graph was rebuilt clean: 2,597 chunks from 78 files,
1942
+ 574 nodes, 1,296 edges, 0 dropped references.
1943
+
1944
+ **Every hardware reference page audited against the instruments.** Nine
1945
+ pages (6510, VIC-II, PAL/NTSC, registers, KERNAL routines, CIA, SID,
1946
+ memory map, illegal opcodes): one auditor per page, three independent
1947
+ refuters per finding, majority-upheld corrections only. 193 corrections
1948
+ landed, each with the earlier wrong statement named beside it — among
1949
+ them the KERNAL's ~60 Hz jiffy on PAL as well as NTSC, the region flag at
1950
+ $02A6, the last default badline at 243, the TOD latch on hours, RESTORE
1951
+ outside CIA2, the SID's held bus byte, $EA7E as an exit rather than a
1952
+ shortcut, and the rebuilt KERNAL/BASIC ROM sub-maps. Twelve findings the
1953
+ refuters could not settle with anything on this machine are left as
1954
+ they stand and listed for follow-up. VICE on this machine is 3.10, and
1955
+ the instrument table says so.
1956
+
1957
+ **Two relations the graph could not state.** `REQUIRES` (Technique →
1958
+ Technique, schema 19): "this technique presupposes that one is set up or
1959
+ running underneath it", authored with a `**Requires:**` line. Twelve
1960
+ entries carry one, each from its own text — `text_zoom` requires
1961
+ `stable_raster_irq` ("a stable raster IRQ set to fire on every scanline"),
1962
+ `infinite_scroll_h` requires `soft_scroll_h` and `char_scroll_buffer_h`,
1963
+ `sideborder_open` requires `double_irq`, `ifli_image` requires `fli_image`,
1964
+ the SID filter, play-routine and hard-restart digi entries require
1965
+ `sid_voice_setup` (`digi_4bit` does not: it drives the $D418 volume DAC
1966
+ with every voice gated off, and a line only another entry's text supports
1967
+ is not authored — an earlier draft had it). `double_irq` is a variant of
1968
+ `stable_raster_irq`, not a prerequisite, and has no REQUIRES edge to or
1969
+ from it; it is the target of `sideborder_open`'s REQUIRES and of
1970
+ `raster_irq_first_line_jitter`'s MITIGATED_BY. `MITIGATED_BY` (Pitfall →
1971
+ Technique): "applying this
1972
+ technique is the Fix", authored with `**Mitigated by techniques:**`, which
1973
+ separates the remedy from the trigger the one vocabulary used to carry —
1974
+ `sprite_dma_overflow` is triggered by a naive multiplexer and mitigated by
1975
+ a correct one, `raster_irq_first_line_jitter` by `stable_raster_irq` and
1976
+ `double_irq`, the three region-timing pitfalls by `pal_ntsc_detection`,
1977
+ which had no edge to any of them, and `jmp_indirect_page_boundary_bug` by
1978
+ `jump_table_dispatch`'s store-then-jump form. Both edges MATCH both ends
1979
+ (no stubs from typos), are counted in the ingest summary, and a REQUIRES
1980
+ line that would close a cycle is refused. `BUILDS_ON` is still listed and
1981
+ still emitted by nothing; the ontology now says so.
1982
+
1983
+ **Tools (1.22.0, additive).** `c64_technique_lookup` gains `requires`,
1984
+ `required_by` and `mitigates`; `c64_techniques_for` gains a `requires`
1985
+ filter that follows the chain; `c64_pitfalls_for` answers for a technique
1986
+ that is only a remedy and reports `mitigated_by[]` apart from
1987
+ `triggered_by[]`; `c64_check_compatibility` takes each technique's
1988
+ REQUIRES closure and runs its hard rules between one technique's
1989
+ prerequisites and the other, reporting `prerequisite_conflict` (with the
1990
+ implied techniques in `via`) and a `missing_prerequisite` note for every
1991
+ technique the set leans on without naming — never against a prerequisite
1992
+ the technique declared itself, and without changing any technique's
1993
+ demands. `c64_suggest_links` proposes `pitfall_mitigated_by_technique`
1994
+ for a technique named in a Fix section instead of misfiling it as a
1995
+ trigger. `text_zoom` also gains `**Demands:** midframe_raster_irqs` from
1996
+ its own text, so `fli_image + text_zoom` is refused directly (cpu_vs_irq)
1997
+ rather than through a closure that both techniques' shared prerequisite
1998
+ would silence. Single-file ingest (`ingest-doc`) now applies `DEMANDS`
1999
+ edges too; it had skipped them — and `OCCUPIES` (a recipe's load
2000
+ addresses), which an exhaustiveness guard added to its switch found
2001
+ skipped as well; the next omission is a compile error, not a silent skip.
2002
+
2003
+ **RESTORE is not a CIA2 interrupt source.** Three pages said the RESTORE
2004
+ key reached the CPU through CIA2's /FLAG pin as `$DD0D` bit 4 and that
2005
+ `$DD0D = $10` switched it off; the key drives the 6510's /NMI pin directly,
2006
+ in parallel with CIA2's /IRQ, and no `$DD0D` write affects it. The KERNAL
2007
+ handler at `$FE43` is `SEI : JMP ($0318)` with the register pushes at
2008
+ `$FE47` *after* the vector, no BRK test, and a `BMI` on `$DD0D` bit 7 —
2009
+ it recognises RESTORE by finding *no* CIA2 flag (ROM bytes of 901227-03).
2010
+ New pitfall `restore_nmi_not_maskable` in `pitfalls/kernal-and-io.md`,
2011
+ triggered by `DD0D`, `RESTOR`, `VECTOR`: taking `$0318` costs 20 cycles a
2012
+ press (7 + 2 + 5 + 6), and an unacknowledged CIA2 NMI locks the
2013
+ edge-triggered input (two Timer A underflows, one NMI) — both measured in
2014
+ VICE x64sc 3.10. `cia-reference.md`'s NMI-vector list and its
2015
+ "re-entered immediately because the 555 still holds the line low" bullet
2016
+ rewritten; `c64-registers-reference.md` and `c64-memory-map.md` wiring
2017
+ lines corrected; the reset table's `$DC00 = $7F` now reads "column 7 low".
2018
+
2019
+ **Source catalogs removed from `docs/`.** `docs/catalogs/` held two
2020
+ manifests — `source-catalog.json` (137 entries) and
2021
+ `source-corpus-catalog.json` (71 entries) — plus their two readmes. They
2022
+ listed third-party C64 sources, per-author repository inventories, and
2023
+ in-repo path fingerprints (`pattern_signals`) for code this project never
2024
+ ingested, and the readmes cross-referenced unrelated projects of the
2025
+ author's. None of it fed the knowledge base: the ingest reads `*.md` only,
2026
+ so the two JSON manifests were never indexed at all, and the two readmes
2027
+ carried no frontmatter and no metadata lines, so they extracted zero graph
2028
+ entities. The measured impact is 18 Qdrant chunks and the `catalogs` bucket
2029
+ in `c64-kb health`, whose entry in `C64_BUCKETS` (`src/services/qdrant.ts`)
2030
+ is dropped with them. No graph node, edge, tool, recipe, listing or test
2031
+ referenced the directory. Doc counts in `README.md` and `CLAUDE.md` drop
2032
+ from 75/69 markdown files to 73/67.
2033
+
2034
+ **README chunk figure re-measured.** It read 2,422 and was stale: neither
2035
+ `36d1843` nor the 6510 audit in `5526a80` updated it, and the 6510 page
2036
+ alone went 258 -> 264 chunks. Running `chunkMarkdown` over all 73 files at
2037
+ this commit gives 2,516, which is what a clean ingest would upsert. The
2038
+ table now says it is a chunker measurement, not a live collection reading.
2039
+
2040
+ Note: the files remain in git history from `fac663a` onward and in the
2041
+ public fork. Removing them here removes them from the working tree, not
2042
+ from the record.
2043
+
2044
+ ## 0.8.0 — 2026-09-22
2045
+
2046
+ Data 702, schema 18, tools 1.21.1.
2047
+
2048
+ **Recipes: assembled, run, rewritten.** None of the eight KickAssembler
2049
+ recipes had been assembled before this release: six did not assemble, one
2050
+ ran and did nothing, one was a plain raster IRQ named "stable". All eight
2051
+ are rewritten, built with KickAssembler 5.25, run headless in VICE x64sc
2052
+ and measured from the screenshot, with the pictures kept in
2053
+ `docs/recipes/kickassembler/screenshots/`. Four Oscar64 recipes fixed
2054
+ (compiler crash on a const function pointer, unreferenced stub array
2055
+ dropped by the linker, IRQ slot table overflow, GCC attribute syntax).
2056
+ `npm run check:listings` builds every listing and is part of `npm test`.
2057
+
2058
+ **Technique text corrected.** Badline budget is 20 cycles guaranteed
2059
+ (23 optimistic), not 23 flat. FLI is a forced badline per line with the
2060
+ $D011 write on cycle 15. The side border is one write cycle (56) with no
2061
+ left-border toggle. VSP is a late-$D011 DMA delay, not a CSEL toggle. The
2062
+ KERNAL dispatcher is at $FF48 (29 cycles); $EA31 is the full service
2063
+ routine, $EA81 the bare exit. DEN is sampled once per frame on line $30.
2064
+
2065
+ **Compatibility checker can say no.** Technique entries carry a
2066
+ `**Demands:**` line from a fixed vocabulary; `c64_check_compatibility`
2067
+ derives hard conflicts (cpu_exclusive, cpu_vs_irq, sprite_set,
2068
+ kernal_banked_out, region_mismatch) with a resolution each, keeps shared
2069
+ register / KERNAL as soft warnings, and reports per technique what the
2070
+ graph does not know instead of clearing it. `timing-budget` uses 43 cycles
2071
+ lost per badline and 36 of IRQ overhead.
2072
+
2073
+ **Graph and ingest.** New `Resource` node label and `DEMANDS`, `IN_REGION`,
2074
+ `OCCUPIES` edges (schema 18). Ingest deletes a file's old chunks before
2075
+ upserting, `--clean`/`--force` recreate the vector collection, unresolved
2076
+ references are warned about and counted, and eight that had been dropped
2077
+ silently are fixed in the docs.
2078
+
2079
+ **Hardening.** `npm test` runs against a throwaway graph and collection.
2080
+ README, ARCHITECTURE and ONTOLOGY rewritten to match the code: 23 tools,
2081
+ 12 resources, 12 node labels, 15 edge types, Node 24, root `.mcp.json`.
2082
+ Eight npm scripts pointing at files not in this repository removed.