c64-kb 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (970) hide show
  1. package/CHANGELOG.md +2082 -0
  2. package/LICENSE +29 -0
  3. package/README.md +559 -0
  4. package/VERSION +25 -0
  5. package/dist/cli/setup.js +66 -0
  6. package/dist/cli/setup.js.map +1 -0
  7. package/dist/cli-memorize-audit.js +97 -0
  8. package/dist/cli-memorize-audit.js.map +1 -0
  9. package/dist/cli.js +335 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/config.js +83 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/context.js +53 -0
  14. package/dist/context.js.map +1 -0
  15. package/dist/domain/budget-notes.js +104 -0
  16. package/dist/domain/budget-notes.js.map +1 -0
  17. package/dist/domain/budget.js +417 -0
  18. package/dist/domain/budget.js.map +1 -0
  19. package/dist/domain/game-design.js +77 -0
  20. package/dist/domain/game-design.js.map +1 -0
  21. package/dist/domain/timing.js +39 -0
  22. package/dist/domain/timing.js.map +1 -0
  23. package/dist/graph/apply.js +132 -0
  24. package/dist/graph/apply.js.map +1 -0
  25. package/dist/graph/claims.js +231 -0
  26. package/dist/graph/claims.js.map +1 -0
  27. package/dist/graph/extract/archetype.js +118 -0
  28. package/dist/graph/extract/archetype.js.map +1 -0
  29. package/dist/graph/extract/common.js +69 -0
  30. package/dist/graph/extract/common.js.map +1 -0
  31. package/dist/graph/extract/failure.js +37 -0
  32. package/dist/graph/extract/failure.js.map +1 -0
  33. package/dist/graph/extract/game-design.js +189 -0
  34. package/dist/graph/extract/game-design.js.map +1 -0
  35. package/dist/graph/extract/hardware.js +124 -0
  36. package/dist/graph/extract/hardware.js.map +1 -0
  37. package/dist/graph/extract/pitfall.js +62 -0
  38. package/dist/graph/extract/pitfall.js.map +1 -0
  39. package/dist/graph/extract/raster-band.js +56 -0
  40. package/dist/graph/extract/raster-band.js.map +1 -0
  41. package/dist/graph/extract/recipe.js +71 -0
  42. package/dist/graph/extract/recipe.js.map +1 -0
  43. package/dist/graph/extract/technique-entities.js +180 -0
  44. package/dist/graph/extract/technique-entities.js.map +1 -0
  45. package/dist/graph/extract/technique.js +179 -0
  46. package/dist/graph/extract/technique.js.map +1 -0
  47. package/dist/graph/extract/toolchain.js +67 -0
  48. package/dist/graph/extract/toolchain.js.map +1 -0
  49. package/dist/graph/extract/types.js +3 -0
  50. package/dist/graph/extract/types.js.map +1 -0
  51. package/dist/graph/extract/vocabulary.js +65 -0
  52. package/dist/graph/extract/vocabulary.js.map +1 -0
  53. package/dist/graph/extract.js +43 -0
  54. package/dist/graph/extract.js.map +1 -0
  55. package/dist/graph/kernal-clobbers.js +64 -0
  56. package/dist/graph/kernal-clobbers.js.map +1 -0
  57. package/dist/graph/machine-variants.js +208 -0
  58. package/dist/graph/machine-variants.js.map +1 -0
  59. package/dist/ingest/files.js +99 -0
  60. package/dist/ingest/files.js.map +1 -0
  61. package/dist/ingest/passes.js +104 -0
  62. package/dist/ingest/passes.js.map +1 -0
  63. package/dist/ingest/points.js +50 -0
  64. package/dist/ingest/points.js.map +1 -0
  65. package/dist/ingest/report.js +140 -0
  66. package/dist/ingest/report.js.map +1 -0
  67. package/dist/ingest/tally.js +81 -0
  68. package/dist/ingest/tally.js.map +1 -0
  69. package/dist/ingest/verified-on.js +43 -0
  70. package/dist/ingest/verified-on.js.map +1 -0
  71. package/dist/ingest.js +135 -0
  72. package/dist/ingest.js.map +1 -0
  73. package/dist/schemas/cost-basis.js +5 -0
  74. package/dist/schemas/cost-basis.js.map +1 -0
  75. package/dist/schemas/machine-variant.js +25 -0
  76. package/dist/schemas/machine-variant.js.map +1 -0
  77. package/dist/schemas/plan-budget.js +121 -0
  78. package/dist/schemas/plan-budget.js.map +1 -0
  79. package/dist/schemas/tool-outputs.js +526 -0
  80. package/dist/schemas/tool-outputs.js.map +1 -0
  81. package/dist/server/define-tool.js +52 -0
  82. package/dist/server/define-tool.js.map +1 -0
  83. package/dist/server/defined-only.js +9 -0
  84. package/dist/server/defined-only.js.map +1 -0
  85. package/dist/server/tools-briefings.js +70 -0
  86. package/dist/server/tools-briefings.js.map +1 -0
  87. package/dist/server/tools-lookup.js +180 -0
  88. package/dist/server/tools-lookup.js.map +1 -0
  89. package/dist/server/tools-maintenance.js +116 -0
  90. package/dist/server/tools-maintenance.js.map +1 -0
  91. package/dist/server/tools-pitfalls.js +89 -0
  92. package/dist/server/tools-pitfalls.js.map +1 -0
  93. package/dist/server/tools-recipes.js +296 -0
  94. package/dist/server/tools-recipes.js.map +1 -0
  95. package/dist/server/tools-runtime.js +48 -0
  96. package/dist/server/tools-runtime.js.map +1 -0
  97. package/dist/server/tools.js +43 -0
  98. package/dist/server/tools.js.map +1 -0
  99. package/dist/server.js +95 -0
  100. package/dist/server.js.map +1 -0
  101. package/dist/services/analytics/schema.js +78 -0
  102. package/dist/services/analytics/schema.js.map +1 -0
  103. package/dist/services/analytics/statements.js +99 -0
  104. package/dist/services/analytics/statements.js.map +1 -0
  105. package/dist/services/analytics.js +195 -0
  106. package/dist/services/analytics.js.map +1 -0
  107. package/dist/services/bm25.js +158 -0
  108. package/dist/services/bm25.js.map +1 -0
  109. package/dist/services/chunker.js +81 -0
  110. package/dist/services/chunker.js.map +1 -0
  111. package/dist/services/embeddings.js +58 -0
  112. package/dist/services/embeddings.js.map +1 -0
  113. package/dist/services/falkor/base.js +85 -0
  114. package/dist/services/falkor/base.js.map +1 -0
  115. package/dist/services/falkor/links.js +361 -0
  116. package/dist/services/falkor/links.js.map +1 -0
  117. package/dist/services/falkor/nodes.js +183 -0
  118. package/dist/services/falkor/nodes.js.map +1 -0
  119. package/dist/services/falkor/params.js +45 -0
  120. package/dist/services/falkor/params.js.map +1 -0
  121. package/dist/services/falkor/schema.js +77 -0
  122. package/dist/services/falkor/schema.js.map +1 -0
  123. package/dist/services/falkor.js +100 -0
  124. package/dist/services/falkor.js.map +1 -0
  125. package/dist/services/qdrant.js +238 -0
  126. package/dist/services/qdrant.js.map +1 -0
  127. package/dist/services/versions.js +73 -0
  128. package/dist/services/versions.js.map +1 -0
  129. package/dist/services/vice-bin.js +51 -0
  130. package/dist/services/vice-bin.js.map +1 -0
  131. package/dist/tools/briefings/archetype.js +174 -0
  132. package/dist/tools/briefings/archetype.js.map +1 -0
  133. package/dist/tools/briefings/budget.js +177 -0
  134. package/dist/tools/briefings/budget.js.map +1 -0
  135. package/dist/tools/briefings/build-order.js +135 -0
  136. package/dist/tools/briefings/build-order.js.map +1 -0
  137. package/dist/tools/briefings/build.js +185 -0
  138. package/dist/tools/briefings/build.js.map +1 -0
  139. package/dist/tools/briefings/discovery.js +290 -0
  140. package/dist/tools/briefings/discovery.js.map +1 -0
  141. package/dist/tools/briefings/plan-pitfalls.js +69 -0
  142. package/dist/tools/briefings/plan-pitfalls.js.map +1 -0
  143. package/dist/tools/briefings/render.js +151 -0
  144. package/dist/tools/briefings/render.js.map +1 -0
  145. package/dist/tools/briefings/rows.js +41 -0
  146. package/dist/tools/briefings/rows.js.map +1 -0
  147. package/dist/tools/briefings/toolchain.js +63 -0
  148. package/dist/tools/briefings/toolchain.js.map +1 -0
  149. package/dist/tools/briefings/why-proposed.js +69 -0
  150. package/dist/tools/briefings/why-proposed.js.map +1 -0
  151. package/dist/tools/briefings.js +44 -0
  152. package/dist/tools/briefings.js.map +1 -0
  153. package/dist/tools/feedback.js +97 -0
  154. package/dist/tools/feedback.js.map +1 -0
  155. package/dist/tools/hydrate.js +75 -0
  156. package/dist/tools/hydrate.js.map +1 -0
  157. package/dist/tools/intelligence.js +67 -0
  158. package/dist/tools/intelligence.js.map +1 -0
  159. package/dist/tools/lint/asm-decimal.js +86 -0
  160. package/dist/tools/lint/asm-decimal.js.map +1 -0
  161. package/dist/tools/lint/asm-rules.js +221 -0
  162. package/dist/tools/lint/asm-rules.js.map +1 -0
  163. package/dist/tools/lint/asm-shared.js +3 -0
  164. package/dist/tools/lint/asm-shared.js.map +1 -0
  165. package/dist/tools/lint/c-rules.js +215 -0
  166. package/dist/tools/lint/c-rules.js.map +1 -0
  167. package/dist/tools/lint/text.js +122 -0
  168. package/dist/tools/lint/text.js.map +1 -0
  169. package/dist/tools/lint/types.js +40 -0
  170. package/dist/tools/lint/types.js.map +1 -0
  171. package/dist/tools/lint.js +76 -0
  172. package/dist/tools/lint.js.map +1 -0
  173. package/dist/tools/memorization-mcp.js +111 -0
  174. package/dist/tools/memorization-mcp.js.map +1 -0
  175. package/dist/tools/pitfalls/bm25.js +53 -0
  176. package/dist/tools/pitfalls/bm25.js.map +1 -0
  177. package/dist/tools/pitfalls/format.js +58 -0
  178. package/dist/tools/pitfalls/format.js.map +1 -0
  179. package/dist/tools/pitfalls/graph.js +124 -0
  180. package/dist/tools/pitfalls/graph.js.map +1 -0
  181. package/dist/tools/pitfalls.js +134 -0
  182. package/dist/tools/pitfalls.js.map +1 -0
  183. package/dist/tools/prompts.js +81 -0
  184. package/dist/tools/prompts.js.map +1 -0
  185. package/dist/tools/query/compatibility/closure.js +62 -0
  186. package/dist/tools/query/compatibility/closure.js.map +1 -0
  187. package/dist/tools/query/compatibility/facts.js +28 -0
  188. package/dist/tools/query/compatibility/facts.js.map +1 -0
  189. package/dist/tools/query/compatibility/fetch.js +164 -0
  190. package/dist/tools/query/compatibility/fetch.js.map +1 -0
  191. package/dist/tools/query/compatibility/hard-rules.js +159 -0
  192. package/dist/tools/query/compatibility/hard-rules.js.map +1 -0
  193. package/dist/tools/query/compatibility/index.js +27 -0
  194. package/dist/tools/query/compatibility/index.js.map +1 -0
  195. package/dist/tools/query/compatibility/kernal-zp-rule.js +90 -0
  196. package/dist/tools/query/compatibility/kernal-zp-rule.js.map +1 -0
  197. package/dist/tools/query/compatibility/render.js +106 -0
  198. package/dist/tools/query/compatibility/render.js.map +1 -0
  199. package/dist/tools/query/compatibility/rules.js +337 -0
  200. package/dist/tools/query/compatibility/rules.js.map +1 -0
  201. package/dist/tools/query/compatibility/unit-rules.js +253 -0
  202. package/dist/tools/query/compatibility/unit-rules.js.map +1 -0
  203. package/dist/tools/query/game-design.js +83 -0
  204. package/dist/tools/query/game-design.js.map +1 -0
  205. package/dist/tools/query/lookups.js +220 -0
  206. package/dist/tools/query/lookups.js.map +1 -0
  207. package/dist/tools/query/plan-budget.js +266 -0
  208. package/dist/tools/query/plan-budget.js.map +1 -0
  209. package/dist/tools/query/recipes.js +214 -0
  210. package/dist/tools/query/recipes.js.map +1 -0
  211. package/dist/tools/query/retrieval.js +128 -0
  212. package/dist/tools/query/retrieval.js.map +1 -0
  213. package/dist/tools/query/shared.js +121 -0
  214. package/dist/tools/query/shared.js.map +1 -0
  215. package/dist/tools/query/techniques.js +331 -0
  216. package/dist/tools/query/techniques.js.map +1 -0
  217. package/dist/tools/query/timing.js +106 -0
  218. package/dist/tools/query/timing.js.map +1 -0
  219. package/dist/tools/query/types.js +11 -0
  220. package/dist/tools/query/types.js.map +1 -0
  221. package/dist/tools/query.js +21 -0
  222. package/dist/tools/query.js.map +1 -0
  223. package/dist/tools/resources.js +186 -0
  224. package/dist/tools/resources.js.map +1 -0
  225. package/dist/tools/run-game.js +249 -0
  226. package/dist/tools/run-game.js.map +1 -0
  227. package/dist/tools/selfimprovement.js +367 -0
  228. package/dist/tools/selfimprovement.js.map +1 -0
  229. package/docker-compose.yml +35 -0
  230. package/docs/ARCHITECTURE.md +164 -0
  231. package/docs/CONVENTIONS-archetypes.md +158 -0
  232. package/docs/CONVENTIONS-failures.md +46 -0
  233. package/docs/CONVENTIONS-game-designs.md +75 -0
  234. package/docs/CONVENTIONS-hardware-reference.md +184 -0
  235. package/docs/CONVENTIONS-pitfalls.md +91 -0
  236. package/docs/CONVENTIONS-recipes.md +106 -0
  237. package/docs/CONVENTIONS-techniques.md +309 -0
  238. package/docs/CONVENTIONS-toolchain-reference.md +89 -0
  239. package/docs/ONTOLOGY.md +655 -0
  240. package/docs/art/art-production-reference.md +157 -0
  241. package/docs/art/asset-pipelines.md +586 -0
  242. package/docs/c64-failure-patterns.md +693 -0
  243. package/docs/demo-design/demo-composition.md +349 -0
  244. package/docs/demo-design/demo-design-philosophy.md +320 -0
  245. package/docs/demo-design/intro-cracktro-patterns.md +435 -0
  246. package/docs/figures/ctm-spd-embed-probe.png +0 -0
  247. package/docs/figures/dot-flag-mid-5000000.png +0 -0
  248. package/docs/figures/dot-flag-no-erase-12000000.png +0 -0
  249. package/docs/figures/edges.json +1 -0
  250. package/docs/figures/fig6-architecture.png +0 -0
  251. package/docs/figures/fig7-ontology.png +0 -0
  252. package/docs/figures/screen-dissolve-mid-frame25.png +0 -0
  253. package/docs/figures/screen-dissolve-wipe-frame25.png +0 -0
  254. package/docs/figures/spindle-two-parts-part1.png +0 -0
  255. package/docs/figures/spindle-two-parts-part2.png +0 -0
  256. package/docs/figures/starters/action-puzzle.png +0 -0
  257. package/docs/figures/starters/adventure.png +0 -0
  258. package/docs/figures/starters/beat-em-up.png +0 -0
  259. package/docs/figures/starters/demo.png +0 -0
  260. package/docs/figures/starters/platformer.png +0 -0
  261. package/docs/figures/starters/shmup-vertical.png +0 -0
  262. package/docs/figures/tape-kernal-master-ntsc.png +0 -0
  263. package/docs/figures/tape-kernal-master-pal.png +0 -0
  264. package/docs/figures/tape-turbo-loader-ntsc.png +0 -0
  265. package/docs/figures/tape-turbo-loader-pal.png +0 -0
  266. package/docs/figures/tape-turbo-master-ntsc.png +0 -0
  267. package/docs/figures/tape-turbo-master-pal.png +0 -0
  268. package/docs/figures/tech-tech-pad2-12000000.png +0 -0
  269. package/docs/figures/tech-tech-pad4-12000000.png +0 -0
  270. package/docs/figures/tech-tech-seven-12000000.png +0 -0
  271. package/docs/figures/twister-mid-5000000.png +0 -0
  272. package/docs/figures/twister-straight-12000000.png +0 -0
  273. package/docs/figures/vector-balls-nosort-ntsc.png +0 -0
  274. package/docs/figures/vector-balls-nosort.png +0 -0
  275. package/docs/formats/c64-file-formats.md +1212 -0
  276. package/docs/formats/iec-disk-reference.md +754 -0
  277. package/docs/game-design/c64-game-archetypes.md +273 -0
  278. package/docs/game-design/designs/falling-blocks.md +54 -0
  279. package/docs/game-design/designs/platformer-scaffold.md +48 -0
  280. package/docs/game-design/designs/simple-shmup.md +27 -0
  281. package/docs/game-design/enemy-behaviour-and-difficulty.md +349 -0
  282. package/docs/game-design/game-design-patterns.md +1189 -0
  283. package/docs/game-design/game-structure.md +354 -0
  284. package/docs/game-design/production-planning.md +349 -0
  285. package/docs/game-design/reference-game-sources.md +90 -0
  286. package/docs/hardware/6502-illegal-opcodes.md +1353 -0
  287. package/docs/hardware/6510-cpu-reference.md +2112 -0
  288. package/docs/hardware/c64-memory-map.md +3184 -0
  289. package/docs/hardware/c64-registers-reference.md +996 -0
  290. package/docs/hardware/cia-reference.md +1281 -0
  291. package/docs/hardware/kernal-routines-reference.md +1836 -0
  292. package/docs/hardware/pal-ntsc-reference.md +813 -0
  293. package/docs/hardware/sid-reference.md +1137 -0
  294. package/docs/hardware/vic-ii-reference.md +1714 -0
  295. package/docs/music/music-production-reference.md +403 -0
  296. package/docs/pitfalls/banking.md +1067 -0
  297. package/docs/pitfalls/cia.md +1147 -0
  298. package/docs/pitfalls/cpu.md +874 -0
  299. package/docs/pitfalls/input.md +282 -0
  300. package/docs/pitfalls/kernal-and-io.md +1615 -0
  301. package/docs/pitfalls/loader.md +1191 -0
  302. package/docs/pitfalls/logic.md +94 -0
  303. package/docs/pitfalls/maths.md +187 -0
  304. package/docs/pitfalls/raster-and-badline.md +721 -0
  305. package/docs/pitfalls/region-timing.md +660 -0
  306. package/docs/pitfalls/scroll.md +207 -0
  307. package/docs/pitfalls/sid.md +738 -0
  308. package/docs/pitfalls/sprite.md +979 -0
  309. package/docs/pitfalls/text-mode-render.md +1172 -0
  310. package/docs/recipes/cc65/cartridge-8k.md +398 -0
  311. package/docs/recipes/cc65/hello-world-conio.md +76 -0
  312. package/docs/recipes/cc65/memory-layout.md +312 -0
  313. package/docs/recipes/cc65/screenshots/README.md +14 -0
  314. package/docs/recipes/cc65/screenshots/cartridge-8k-ntsc.png +0 -0
  315. package/docs/recipes/cc65/screenshots/cartridge-8k.png +0 -0
  316. package/docs/recipes/cc65/screenshots/hello-world-conio.png +0 -0
  317. package/docs/recipes/cc65/screenshots/memory-layout-ntsc.png +0 -0
  318. package/docs/recipes/cc65/screenshots/memory-layout.png +0 -0
  319. package/docs/recipes/kickassembler/basic-float-calls.md +578 -0
  320. package/docs/recipes/kickassembler/basic-wedge.md +398 -0
  321. package/docs/recipes/kickassembler/big-font-scroller.md +620 -0
  322. package/docs/recipes/kickassembler/charset-copy-rom-to-ram.md +623 -0
  323. package/docs/recipes/kickassembler/cia-revision-detect.md +366 -0
  324. package/docs/recipes/kickassembler/colour-cycling.md +343 -0
  325. package/docs/recipes/kickassembler/colour-fade.md +303 -0
  326. package/docs/recipes/kickassembler/compare-16bit-signed.md +1007 -0
  327. package/docs/recipes/kickassembler/cracktro-template.md +526 -0
  328. package/docs/recipes/kickassembler/crt-banked.md +276 -0
  329. package/docs/recipes/kickassembler/dos-error-codes.md +466 -0
  330. package/docs/recipes/kickassembler/dot-flag.md +576 -0
  331. package/docs/recipes/kickassembler/drive-job-queue.md +667 -0
  332. package/docs/recipes/kickassembler/drive-via-probe.md +690 -0
  333. package/docs/recipes/kickassembler/dycp-scroller.md +568 -0
  334. package/docs/recipes/kickassembler/dypp-sprite-scroller.md +681 -0
  335. package/docs/recipes/kickassembler/dysp.md +670 -0
  336. package/docs/recipes/kickassembler/easyflash-save.md +800 -0
  337. package/docs/recipes/kickassembler/eight-way-scroll.md +1484 -0
  338. package/docs/recipes/kickassembler/file-io-roundtrip.md +546 -0
  339. package/docs/recipes/kickassembler/fire-effect.md +420 -0
  340. package/docs/recipes/kickassembler/fld.md +414 -0
  341. package/docs/recipes/kickassembler/fli-image.md +336 -0
  342. package/docs/recipes/kickassembler/four-player-read.md +672 -0
  343. package/docs/recipes/kickassembler/headless-verify.md +228 -0
  344. package/docs/recipes/kickassembler/hello-world.md +98 -0
  345. package/docs/recipes/kickassembler/high-score-insert.md +660 -0
  346. package/docs/recipes/kickassembler/hires-plot-line.md +723 -0
  347. package/docs/recipes/kickassembler/irq-chain.md +316 -0
  348. package/docs/recipes/kickassembler/irq-owns-port.md +668 -0
  349. package/docs/recipes/kickassembler/isometric-room.md +1145 -0
  350. package/docs/recipes/kickassembler/light-pen-read.md +926 -0
  351. package/docs/recipes/kickassembler/logic-rate-decoupling.md +670 -0
  352. package/docs/recipes/kickassembler/mci-interlace.md +543 -0
  353. package/docs/recipes/kickassembler/memory-layout.md +277 -0
  354. package/docs/recipes/kickassembler/mouse-1351-read.md +801 -0
  355. package/docs/recipes/kickassembler/nmi-timer-tick.md +562 -0
  356. package/docs/recipes/kickassembler/own-keyscan.md +881 -0
  357. package/docs/recipes/kickassembler/paddle-read.md +751 -0
  358. package/docs/recipes/kickassembler/palette-cells.md +219 -0
  359. package/docs/recipes/kickassembler/pseudo-3d-road.md +930 -0
  360. package/docs/recipes/kickassembler/pwm-digi.md +463 -0
  361. package/docs/recipes/kickassembler/raster-bars.md +264 -0
  362. package/docs/recipes/kickassembler/reu-dma.md +1019 -0
  363. package/docs/recipes/kickassembler/runtime-relocation.md +743 -0
  364. package/docs/recipes/kickassembler/screen-dissolve.md +545 -0
  365. package/docs/recipes/kickassembler/screen-wipe.md +408 -0
  366. package/docs/recipes/kickassembler/screenshots/README.md +72 -0
  367. package/docs/recipes/kickassembler/screenshots/basic-float-calls-ntsc.png +0 -0
  368. package/docs/recipes/kickassembler/screenshots/basic-float-calls.png +0 -0
  369. package/docs/recipes/kickassembler/screenshots/basic-wedge-ntsc.png +0 -0
  370. package/docs/recipes/kickassembler/screenshots/basic-wedge.png +0 -0
  371. package/docs/recipes/kickassembler/screenshots/big-font-scroller-ntsc.png +0 -0
  372. package/docs/recipes/kickassembler/screenshots/big-font-scroller.png +0 -0
  373. package/docs/recipes/kickassembler/screenshots/charset-copy-rom-to-ram-ntsc.png +0 -0
  374. package/docs/recipes/kickassembler/screenshots/charset-copy-rom-to-ram.png +0 -0
  375. package/docs/recipes/kickassembler/screenshots/cia-revision-detect-ntsc.png +0 -0
  376. package/docs/recipes/kickassembler/screenshots/cia-revision-detect.png +0 -0
  377. package/docs/recipes/kickassembler/screenshots/colour-cycling-ntsc.png +0 -0
  378. package/docs/recipes/kickassembler/screenshots/colour-cycling.png +0 -0
  379. package/docs/recipes/kickassembler/screenshots/colour-fade-ntsc.png +0 -0
  380. package/docs/recipes/kickassembler/screenshots/colour-fade.png +0 -0
  381. package/docs/recipes/kickassembler/screenshots/compare-16bit-signed-ntsc.png +0 -0
  382. package/docs/recipes/kickassembler/screenshots/compare-16bit-signed.png +0 -0
  383. package/docs/recipes/kickassembler/screenshots/cracktro-template.png +0 -0
  384. package/docs/recipes/kickassembler/screenshots/crt-banked-ntsc.png +0 -0
  385. package/docs/recipes/kickassembler/screenshots/crt-banked.png +0 -0
  386. package/docs/recipes/kickassembler/screenshots/dos-error-codes-ntsc.png +0 -0
  387. package/docs/recipes/kickassembler/screenshots/dos-error-codes.png +0 -0
  388. package/docs/recipes/kickassembler/screenshots/dot-flag-ntsc.png +0 -0
  389. package/docs/recipes/kickassembler/screenshots/dot-flag.png +0 -0
  390. package/docs/recipes/kickassembler/screenshots/drive-job-queue-ntsc.png +0 -0
  391. package/docs/recipes/kickassembler/screenshots/drive-job-queue.png +0 -0
  392. package/docs/recipes/kickassembler/screenshots/drive-via-probe-ntsc.png +0 -0
  393. package/docs/recipes/kickassembler/screenshots/drive-via-probe.png +0 -0
  394. package/docs/recipes/kickassembler/screenshots/dycp-scroller-ntsc.png +0 -0
  395. package/docs/recipes/kickassembler/screenshots/dycp-scroller.png +0 -0
  396. package/docs/recipes/kickassembler/screenshots/dypp-sprite-scroller-ntsc.png +0 -0
  397. package/docs/recipes/kickassembler/screenshots/dypp-sprite-scroller.png +0 -0
  398. package/docs/recipes/kickassembler/screenshots/dysp-ntsc.png +0 -0
  399. package/docs/recipes/kickassembler/screenshots/dysp.png +0 -0
  400. package/docs/recipes/kickassembler/screenshots/easyflash-save-ntsc-run2.png +0 -0
  401. package/docs/recipes/kickassembler/screenshots/easyflash-save-ntsc.png +0 -0
  402. package/docs/recipes/kickassembler/screenshots/easyflash-save-run2.png +0 -0
  403. package/docs/recipes/kickassembler/screenshots/easyflash-save.png +0 -0
  404. package/docs/recipes/kickassembler/screenshots/eight-way-scroll-ntsc.png +0 -0
  405. package/docs/recipes/kickassembler/screenshots/eight-way-scroll.png +0 -0
  406. package/docs/recipes/kickassembler/screenshots/file-io-roundtrip-ntsc.png +0 -0
  407. package/docs/recipes/kickassembler/screenshots/file-io-roundtrip.png +0 -0
  408. package/docs/recipes/kickassembler/screenshots/fire-effect-ntsc.png +0 -0
  409. package/docs/recipes/kickassembler/screenshots/fire-effect.png +0 -0
  410. package/docs/recipes/kickassembler/screenshots/fld-ntsc.png +0 -0
  411. package/docs/recipes/kickassembler/screenshots/fld.png +0 -0
  412. package/docs/recipes/kickassembler/screenshots/fli-image.png +0 -0
  413. package/docs/recipes/kickassembler/screenshots/four-player-read-ntsc.png +0 -0
  414. package/docs/recipes/kickassembler/screenshots/four-player-read.png +0 -0
  415. package/docs/recipes/kickassembler/screenshots/headless-verify-ntsc.png +0 -0
  416. package/docs/recipes/kickassembler/screenshots/headless-verify.png +0 -0
  417. package/docs/recipes/kickassembler/screenshots/hello-world.png +0 -0
  418. package/docs/recipes/kickassembler/screenshots/high-score-insert-ntsc.png +0 -0
  419. package/docs/recipes/kickassembler/screenshots/high-score-insert.png +0 -0
  420. package/docs/recipes/kickassembler/screenshots/hires-plot-line-ntsc.png +0 -0
  421. package/docs/recipes/kickassembler/screenshots/hires-plot-line.png +0 -0
  422. package/docs/recipes/kickassembler/screenshots/irq-chain-ntsc.png +0 -0
  423. package/docs/recipes/kickassembler/screenshots/irq-chain.png +0 -0
  424. package/docs/recipes/kickassembler/screenshots/irq-owns-port-ntsc.png +0 -0
  425. package/docs/recipes/kickassembler/screenshots/irq-owns-port.png +0 -0
  426. package/docs/recipes/kickassembler/screenshots/isometric-room-ntsc.png +0 -0
  427. package/docs/recipes/kickassembler/screenshots/isometric-room.png +0 -0
  428. package/docs/recipes/kickassembler/screenshots/light-pen-read-ntsc.png +0 -0
  429. package/docs/recipes/kickassembler/screenshots/light-pen-read.png +0 -0
  430. package/docs/recipes/kickassembler/screenshots/logic-rate-decoupling-ntsc.png +0 -0
  431. package/docs/recipes/kickassembler/screenshots/logic-rate-decoupling.png +0 -0
  432. package/docs/recipes/kickassembler/screenshots/mci-interlace-average.png +0 -0
  433. package/docs/recipes/kickassembler/screenshots/mci-interlace-frame-b.png +0 -0
  434. package/docs/recipes/kickassembler/screenshots/mci-interlace-ntsc.png +0 -0
  435. package/docs/recipes/kickassembler/screenshots/mci-interlace.png +0 -0
  436. package/docs/recipes/kickassembler/screenshots/memory-layout-ntsc.png +0 -0
  437. package/docs/recipes/kickassembler/screenshots/memory-layout.png +0 -0
  438. package/docs/recipes/kickassembler/screenshots/mouse-1351-read-ntsc.png +0 -0
  439. package/docs/recipes/kickassembler/screenshots/mouse-1351-read.png +0 -0
  440. package/docs/recipes/kickassembler/screenshots/nmi-timer-tick-ntsc.png +0 -0
  441. package/docs/recipes/kickassembler/screenshots/nmi-timer-tick.png +0 -0
  442. package/docs/recipes/kickassembler/screenshots/own-keyscan-ntsc.png +0 -0
  443. package/docs/recipes/kickassembler/screenshots/own-keyscan.png +0 -0
  444. package/docs/recipes/kickassembler/screenshots/paddle-read-ntsc.png +0 -0
  445. package/docs/recipes/kickassembler/screenshots/paddle-read.png +0 -0
  446. package/docs/recipes/kickassembler/screenshots/palette-cells-ntsc.png +0 -0
  447. package/docs/recipes/kickassembler/screenshots/palette-cells.png +0 -0
  448. package/docs/recipes/kickassembler/screenshots/pseudo-3d-road-ntsc.png +0 -0
  449. package/docs/recipes/kickassembler/screenshots/pseudo-3d-road.png +0 -0
  450. package/docs/recipes/kickassembler/screenshots/pwm-digi-ntsc.png +0 -0
  451. package/docs/recipes/kickassembler/screenshots/pwm-digi.png +0 -0
  452. package/docs/recipes/kickassembler/screenshots/raster-bars.png +0 -0
  453. package/docs/recipes/kickassembler/screenshots/reu-dma-ntsc.png +0 -0
  454. package/docs/recipes/kickassembler/screenshots/reu-dma.png +0 -0
  455. package/docs/recipes/kickassembler/screenshots/runtime-relocation-ntsc.png +0 -0
  456. package/docs/recipes/kickassembler/screenshots/runtime-relocation.png +0 -0
  457. package/docs/recipes/kickassembler/screenshots/screen-dissolve-ntsc.png +0 -0
  458. package/docs/recipes/kickassembler/screenshots/screen-dissolve.png +0 -0
  459. package/docs/recipes/kickassembler/screenshots/screen-wipe-ntsc.png +0 -0
  460. package/docs/recipes/kickassembler/screenshots/screen-wipe.png +0 -0
  461. package/docs/recipes/kickassembler/screenshots/scroll-panel-split-ntsc.png +0 -0
  462. package/docs/recipes/kickassembler/screenshots/scroll-panel-split.png +0 -0
  463. package/docs/recipes/kickassembler/screenshots/sfx-in-player-ntsc.png +0 -0
  464. package/docs/recipes/kickassembler/screenshots/sfx-in-player.png +0 -0
  465. package/docs/recipes/kickassembler/screenshots/shadebobs-ntsc.png +0 -0
  466. package/docs/recipes/kickassembler/screenshots/shadebobs.png +0 -0
  467. package/docs/recipes/kickassembler/screenshots/sideborder-open.png +0 -0
  468. package/docs/recipes/kickassembler/screenshots/sine-scroller.png +0 -0
  469. package/docs/recipes/kickassembler/screenshots/sine-table-runtime-ntsc.png +0 -0
  470. package/docs/recipes/kickassembler/screenshots/sine-table-runtime.png +0 -0
  471. package/docs/recipes/kickassembler/screenshots/software-sprite-preshifted-ntsc.png +0 -0
  472. package/docs/recipes/kickassembler/screenshots/software-sprite-preshifted.png +0 -0
  473. package/docs/recipes/kickassembler/screenshots/speedcode-generator-ntsc.png +0 -0
  474. package/docs/recipes/kickassembler/screenshots/speedcode-generator.png +0 -0
  475. package/docs/recipes/kickassembler/screenshots/sprite-border-scroller-ntsc.png +0 -0
  476. package/docs/recipes/kickassembler/screenshots/sprite-border-scroller.png +0 -0
  477. package/docs/recipes/kickassembler/screenshots/sprite-cache-flip-ntsc.png +0 -0
  478. package/docs/recipes/kickassembler/screenshots/sprite-cache-flip.png +0 -0
  479. package/docs/recipes/kickassembler/screenshots/sprite-multiplex-24.png +0 -0
  480. package/docs/recipes/kickassembler/screenshots/sprite-multiplex-game-ntsc.png +0 -0
  481. package/docs/recipes/kickassembler/screenshots/sprite-multiplex-game.png +0 -0
  482. package/docs/recipes/kickassembler/screenshots/sprite-priority-classes-ntsc.png +0 -0
  483. package/docs/recipes/kickassembler/screenshots/sprite-priority-classes.png +0 -0
  484. package/docs/recipes/kickassembler/screenshots/sprite-sine-chain-ntsc.png +0 -0
  485. package/docs/recipes/kickassembler/screenshots/sprite-sine-chain.png +0 -0
  486. package/docs/recipes/kickassembler/screenshots/sprite-stretcher-ntsc.png +0 -0
  487. package/docs/recipes/kickassembler/screenshots/sprite-stretcher.png +0 -0
  488. package/docs/recipes/kickassembler/screenshots/sprites-only-screen-ntsc.png +0 -0
  489. package/docs/recipes/kickassembler/screenshots/sprites-only-screen.png +0 -0
  490. package/docs/recipes/kickassembler/screenshots/sqrt-atan2-ntsc.png +0 -0
  491. package/docs/recipes/kickassembler/screenshots/sqrt-atan2.png +0 -0
  492. package/docs/recipes/kickassembler/screenshots/stable-raster-irq-control.png +0 -0
  493. package/docs/recipes/kickassembler/screenshots/stable-raster-irq.png +0 -0
  494. package/docs/recipes/kickassembler/screenshots/tech-tech-ntsc.png +0 -0
  495. package/docs/recipes/kickassembler/screenshots/tech-tech.png +0 -0
  496. package/docs/recipes/kickassembler/screenshots/tod-alarm-ntsc.png +0 -0
  497. package/docs/recipes/kickassembler/screenshots/tod-alarm.png +0 -0
  498. package/docs/recipes/kickassembler/screenshots/topbottom-border-open.png +0 -0
  499. package/docs/recipes/kickassembler/screenshots/twister-ntsc.png +0 -0
  500. package/docs/recipes/kickassembler/screenshots/twister.png +0 -0
  501. package/docs/recipes/kickassembler/screenshots/unit-test-driver-ntsc.png +0 -0
  502. package/docs/recipes/kickassembler/screenshots/unit-test-driver.png +0 -0
  503. package/docs/recipes/kickassembler/screenshots/vector-balls-ntsc.png +0 -0
  504. package/docs/recipes/kickassembler/screenshots/vector-balls.png +0 -0
  505. package/docs/recipes/kickassembler/screenshots/wireframe-ships-ntsc.png +0 -0
  506. package/docs/recipes/kickassembler/screenshots/wireframe-ships.png +0 -0
  507. package/docs/recipes/kickassembler/scroll-panel-split.md +381 -0
  508. package/docs/recipes/kickassembler/sfx-in-player.md +907 -0
  509. package/docs/recipes/kickassembler/shadebobs.md +522 -0
  510. package/docs/recipes/kickassembler/sideborder-open.md +338 -0
  511. package/docs/recipes/kickassembler/sine-scroller.md +321 -0
  512. package/docs/recipes/kickassembler/sine-table-runtime.md +815 -0
  513. package/docs/recipes/kickassembler/software-sprite-preshifted.md +725 -0
  514. package/docs/recipes/kickassembler/speedcode-generator.md +606 -0
  515. package/docs/recipes/kickassembler/sprite-border-scroller.md +696 -0
  516. package/docs/recipes/kickassembler/sprite-cache-flip.md +1071 -0
  517. package/docs/recipes/kickassembler/sprite-multiplex-24.md +326 -0
  518. package/docs/recipes/kickassembler/sprite-multiplex-game.md +986 -0
  519. package/docs/recipes/kickassembler/sprite-priority-classes.md +463 -0
  520. package/docs/recipes/kickassembler/sprite-sine-chain.md +338 -0
  521. package/docs/recipes/kickassembler/sprite-stretcher.md +501 -0
  522. package/docs/recipes/kickassembler/sprites-only-screen.md +550 -0
  523. package/docs/recipes/kickassembler/sqrt-atan2.md +1014 -0
  524. package/docs/recipes/kickassembler/stable-raster-irq.md +360 -0
  525. package/docs/recipes/kickassembler/tape-turbo-loader.md +875 -0
  526. package/docs/recipes/kickassembler/tech-tech.md +679 -0
  527. package/docs/recipes/kickassembler/tod-alarm.md +754 -0
  528. package/docs/recipes/kickassembler/topbottom-border-open.md +407 -0
  529. package/docs/recipes/kickassembler/twister.md +518 -0
  530. package/docs/recipes/kickassembler/unit-test-driver.md +314 -0
  531. package/docs/recipes/kickassembler/vector-balls.md +545 -0
  532. package/docs/recipes/kickassembler/wireframe-ships.md +2324 -0
  533. package/docs/recipes/oscar64/actor-activation-window.md +807 -0
  534. package/docs/recipes/oscar64/adventure-engine.md +1094 -0
  535. package/docs/recipes/oscar64/attract-replay.md +465 -0
  536. package/docs/recipes/oscar64/beat-em-up-lanes.md +563 -0
  537. package/docs/recipes/oscar64/bfs-distance-map.md +723 -0
  538. package/docs/recipes/oscar64/bitmap-koala-viewer.md +355 -0
  539. package/docs/recipes/oscar64/car-contact.md +950 -0
  540. package/docs/recipes/oscar64/cave-scan.md +609 -0
  541. package/docs/recipes/oscar64/char-bullets.md +477 -0
  542. package/docs/recipes/oscar64/charset-animation.md +383 -0
  543. package/docs/recipes/oscar64/charset-parallax.md +401 -0
  544. package/docs/recipes/oscar64/destructible-terrain.md +1099 -0
  545. package/docs/recipes/oscar64/difficulty-tables.md +654 -0
  546. package/docs/recipes/oscar64/dig-and-guards.md +975 -0
  547. package/docs/recipes/oscar64/directory-reader.md +535 -0
  548. package/docs/recipes/oscar64/divide-check.md +581 -0
  549. package/docs/recipes/oscar64/double-buffer-nomirror.md +205 -0
  550. package/docs/recipes/oscar64/double-buffer.md +255 -0
  551. package/docs/recipes/oscar64/falling-blocks.md +874 -0
  552. package/docs/recipes/oscar64/fixed-point-jump-velocity.md +289 -0
  553. package/docs/recipes/oscar64/fixed-point-jump.md +210 -0
  554. package/docs/recipes/oscar64/flip-screen-rooms.md +793 -0
  555. package/docs/recipes/oscar64/frame-sync-loop-overrun.md +214 -0
  556. package/docs/recipes/oscar64/frame-sync-loop.md +254 -0
  557. package/docs/recipes/oscar64/game-tree-search.md +743 -0
  558. package/docs/recipes/oscar64/ghost-targeting.md +867 -0
  559. package/docs/recipes/oscar64/headless-verify.md +345 -0
  560. package/docs/recipes/oscar64/hello-world.md +83 -0
  561. package/docs/recipes/oscar64/high-score-persist.md +772 -0
  562. package/docs/recipes/oscar64/iffl-kernal-skip.md +421 -0
  563. package/docs/recipes/oscar64/joystick-input.md +358 -0
  564. package/docs/recipes/oscar64/lane-pursuit.md +1028 -0
  565. package/docs/recipes/oscar64/level-rle-decoder.md +620 -0
  566. package/docs/recipes/oscar64/lfsr-random-seed2.md +338 -0
  567. package/docs/recipes/oscar64/lfsr-random.md +403 -0
  568. package/docs/recipes/oscar64/load-asset-runtime.md +492 -0
  569. package/docs/recipes/oscar64/memory-layout.md +232 -0
  570. package/docs/recipes/oscar64/mixed-fighters.md +781 -0
  571. package/docs/recipes/oscar64/multi-sprite-object.md +533 -0
  572. package/docs/recipes/oscar64/nav-area-pathfinding.md +881 -0
  573. package/docs/recipes/oscar64/object-pool.md +572 -0
  574. package/docs/recipes/oscar64/pal-ntsc-detect.md +257 -0
  575. package/docs/recipes/oscar64/password-state.md +532 -0
  576. package/docs/recipes/oscar64/per-frame-hitbox.md +651 -0
  577. package/docs/recipes/oscar64/petscii-screen-codes.md +428 -0
  578. package/docs/recipes/oscar64/platformer-scaffold.md +1467 -0
  579. package/docs/recipes/oscar64/print-number.md +367 -0
  580. package/docs/recipes/oscar64/raster-bars.md +239 -0
  581. package/docs/recipes/oscar64/raster-profile-bars.md +404 -0
  582. package/docs/recipes/oscar64/rel-side-sectors.md +391 -0
  583. package/docs/recipes/oscar64/relative-file-records.md +378 -0
  584. package/docs/recipes/oscar64/save-load-seq-file.md +365 -0
  585. package/docs/recipes/oscar64/screenshots/README.md +99 -0
  586. package/docs/recipes/oscar64/screenshots/actor-activation-window-ntsc.png +0 -0
  587. package/docs/recipes/oscar64/screenshots/actor-activation-window.png +0 -0
  588. package/docs/recipes/oscar64/screenshots/adventure-engine-ntsc.png +0 -0
  589. package/docs/recipes/oscar64/screenshots/adventure-engine.png +0 -0
  590. package/docs/recipes/oscar64/screenshots/attract-replay-ntsc.png +0 -0
  591. package/docs/recipes/oscar64/screenshots/attract-replay.png +0 -0
  592. package/docs/recipes/oscar64/screenshots/beat-em-up-lanes-ntsc.png +0 -0
  593. package/docs/recipes/oscar64/screenshots/beat-em-up-lanes.png +0 -0
  594. package/docs/recipes/oscar64/screenshots/bfs-distance-map-ntsc.png +0 -0
  595. package/docs/recipes/oscar64/screenshots/bfs-distance-map.png +0 -0
  596. package/docs/recipes/oscar64/screenshots/bitmap-koala-viewer.png +0 -0
  597. package/docs/recipes/oscar64/screenshots/car-contact-ntsc.png +0 -0
  598. package/docs/recipes/oscar64/screenshots/car-contact.png +0 -0
  599. package/docs/recipes/oscar64/screenshots/cave-scan-ntsc.png +0 -0
  600. package/docs/recipes/oscar64/screenshots/cave-scan.png +0 -0
  601. package/docs/recipes/oscar64/screenshots/char-bullets-ntsc.png +0 -0
  602. package/docs/recipes/oscar64/screenshots/char-bullets.png +0 -0
  603. package/docs/recipes/oscar64/screenshots/charset-animation-ntsc.png +0 -0
  604. package/docs/recipes/oscar64/screenshots/charset-animation.png +0 -0
  605. package/docs/recipes/oscar64/screenshots/charset-parallax-ntsc.png +0 -0
  606. package/docs/recipes/oscar64/screenshots/charset-parallax.png +0 -0
  607. package/docs/recipes/oscar64/screenshots/destructible-terrain-ntsc.png +0 -0
  608. package/docs/recipes/oscar64/screenshots/destructible-terrain.png +0 -0
  609. package/docs/recipes/oscar64/screenshots/difficulty-tables-ntsc.png +0 -0
  610. package/docs/recipes/oscar64/screenshots/difficulty-tables.png +0 -0
  611. package/docs/recipes/oscar64/screenshots/dig-and-guards-ntsc.png +0 -0
  612. package/docs/recipes/oscar64/screenshots/dig-and-guards.png +0 -0
  613. package/docs/recipes/oscar64/screenshots/directory-reader-ntsc.png +0 -0
  614. package/docs/recipes/oscar64/screenshots/directory-reader.png +0 -0
  615. package/docs/recipes/oscar64/screenshots/divide-check-ntsc.png +0 -0
  616. package/docs/recipes/oscar64/screenshots/divide-check.png +0 -0
  617. package/docs/recipes/oscar64/screenshots/double-buffer-nomirror.png +0 -0
  618. package/docs/recipes/oscar64/screenshots/double-buffer-ntsc.png +0 -0
  619. package/docs/recipes/oscar64/screenshots/double-buffer.png +0 -0
  620. package/docs/recipes/oscar64/screenshots/falling-blocks-ntsc.png +0 -0
  621. package/docs/recipes/oscar64/screenshots/falling-blocks.png +0 -0
  622. package/docs/recipes/oscar64/screenshots/fixed-point-jump-ntsc.png +0 -0
  623. package/docs/recipes/oscar64/screenshots/fixed-point-jump-velocity-ntsc.png +0 -0
  624. package/docs/recipes/oscar64/screenshots/fixed-point-jump-velocity.png +0 -0
  625. package/docs/recipes/oscar64/screenshots/fixed-point-jump.png +0 -0
  626. package/docs/recipes/oscar64/screenshots/flip-screen-rooms-ntsc.png +0 -0
  627. package/docs/recipes/oscar64/screenshots/flip-screen-rooms.png +0 -0
  628. package/docs/recipes/oscar64/screenshots/frame-sync-loop-ntsc.png +0 -0
  629. package/docs/recipes/oscar64/screenshots/frame-sync-loop-overrun.png +0 -0
  630. package/docs/recipes/oscar64/screenshots/frame-sync-loop.png +0 -0
  631. package/docs/recipes/oscar64/screenshots/game-tree-search-ntsc.png +0 -0
  632. package/docs/recipes/oscar64/screenshots/game-tree-search.png +0 -0
  633. package/docs/recipes/oscar64/screenshots/ghost-targeting-ntsc.png +0 -0
  634. package/docs/recipes/oscar64/screenshots/ghost-targeting.png +0 -0
  635. package/docs/recipes/oscar64/screenshots/headless-verify-ntsc.png +0 -0
  636. package/docs/recipes/oscar64/screenshots/headless-verify.png +0 -0
  637. package/docs/recipes/oscar64/screenshots/hello-world.png +0 -0
  638. package/docs/recipes/oscar64/screenshots/high-score-persist-ntsc.png +0 -0
  639. package/docs/recipes/oscar64/screenshots/high-score-persist.png +0 -0
  640. package/docs/recipes/oscar64/screenshots/iffl-kernal-skip-ntsc.png +0 -0
  641. package/docs/recipes/oscar64/screenshots/iffl-kernal-skip.png +0 -0
  642. package/docs/recipes/oscar64/screenshots/joystick-input-ntsc.png +0 -0
  643. package/docs/recipes/oscar64/screenshots/joystick-input.png +0 -0
  644. package/docs/recipes/oscar64/screenshots/lane-pursuit-ntsc.png +0 -0
  645. package/docs/recipes/oscar64/screenshots/lane-pursuit.png +0 -0
  646. package/docs/recipes/oscar64/screenshots/level-rle-decoder-ntsc.png +0 -0
  647. package/docs/recipes/oscar64/screenshots/level-rle-decoder.png +0 -0
  648. package/docs/recipes/oscar64/screenshots/lfsr-random-ntsc.png +0 -0
  649. package/docs/recipes/oscar64/screenshots/lfsr-random-seed2.png +0 -0
  650. package/docs/recipes/oscar64/screenshots/lfsr-random.png +0 -0
  651. package/docs/recipes/oscar64/screenshots/load-asset-runtime-ntsc.png +0 -0
  652. package/docs/recipes/oscar64/screenshots/load-asset-runtime.png +0 -0
  653. package/docs/recipes/oscar64/screenshots/memory-layout-ntsc.png +0 -0
  654. package/docs/recipes/oscar64/screenshots/memory-layout.png +0 -0
  655. package/docs/recipes/oscar64/screenshots/mixed-fighters-ntsc.png +0 -0
  656. package/docs/recipes/oscar64/screenshots/mixed-fighters.png +0 -0
  657. package/docs/recipes/oscar64/screenshots/multi-sprite-object-ntsc.png +0 -0
  658. package/docs/recipes/oscar64/screenshots/multi-sprite-object.png +0 -0
  659. package/docs/recipes/oscar64/screenshots/nav-area-pathfinding-ntsc.png +0 -0
  660. package/docs/recipes/oscar64/screenshots/nav-area-pathfinding.png +0 -0
  661. package/docs/recipes/oscar64/screenshots/object-pool-ntsc.png +0 -0
  662. package/docs/recipes/oscar64/screenshots/object-pool.png +0 -0
  663. package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-ntsc.png +0 -0
  664. package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-oldntsc.png +0 -0
  665. package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-pal.png +0 -0
  666. package/docs/recipes/oscar64/screenshots/password-state-ntsc.png +0 -0
  667. package/docs/recipes/oscar64/screenshots/password-state.png +0 -0
  668. package/docs/recipes/oscar64/screenshots/per-frame-hitbox-ntsc.png +0 -0
  669. package/docs/recipes/oscar64/screenshots/per-frame-hitbox.png +0 -0
  670. package/docs/recipes/oscar64/screenshots/petscii-screen-codes-ntsc.png +0 -0
  671. package/docs/recipes/oscar64/screenshots/petscii-screen-codes.png +0 -0
  672. package/docs/recipes/oscar64/screenshots/platformer-scaffold-d64-ntsc.png +0 -0
  673. package/docs/recipes/oscar64/screenshots/platformer-scaffold-d64.png +0 -0
  674. package/docs/recipes/oscar64/screenshots/platformer-scaffold-ntsc.png +0 -0
  675. package/docs/recipes/oscar64/screenshots/platformer-scaffold.png +0 -0
  676. package/docs/recipes/oscar64/screenshots/print-number-ntsc.png +0 -0
  677. package/docs/recipes/oscar64/screenshots/print-number.png +0 -0
  678. package/docs/recipes/oscar64/screenshots/raster-bars.png +0 -0
  679. package/docs/recipes/oscar64/screenshots/raster-profile-bars-ntsc.png +0 -0
  680. package/docs/recipes/oscar64/screenshots/raster-profile-bars.png +0 -0
  681. package/docs/recipes/oscar64/screenshots/rel-side-sectors-ntsc.png +0 -0
  682. package/docs/recipes/oscar64/screenshots/rel-side-sectors.png +0 -0
  683. package/docs/recipes/oscar64/screenshots/relative-file-records-ntsc.png +0 -0
  684. package/docs/recipes/oscar64/screenshots/relative-file-records.png +0 -0
  685. package/docs/recipes/oscar64/screenshots/save-load-seq-file-ntsc.png +0 -0
  686. package/docs/recipes/oscar64/screenshots/save-load-seq-file.png +0 -0
  687. package/docs/recipes/oscar64/screenshots/seeded-level-fill-ntsc.png +0 -0
  688. package/docs/recipes/oscar64/screenshots/seeded-level-fill.png +0 -0
  689. package/docs/recipes/oscar64/screenshots/sfx-engine-ntsc.png +0 -0
  690. package/docs/recipes/oscar64/screenshots/sfx-engine.png +0 -0
  691. package/docs/recipes/oscar64/screenshots/sid-music-player.png +0 -0
  692. package/docs/recipes/oscar64/screenshots/simple-shmup.png +0 -0
  693. package/docs/recipes/oscar64/screenshots/slope-collision-ntsc.png +0 -0
  694. package/docs/recipes/oscar64/screenshots/slope-collision.png +0 -0
  695. package/docs/recipes/oscar64/screenshots/soft-scroll-h.png +0 -0
  696. package/docs/recipes/oscar64/screenshots/sprite-animation-table-ntsc.png +0 -0
  697. package/docs/recipes/oscar64/screenshots/sprite-animation-table.png +0 -0
  698. package/docs/recipes/oscar64/screenshots/sprite-multiplex-8.png +0 -0
  699. package/docs/recipes/oscar64/screenshots/stable-raster-irq.png +0 -0
  700. package/docs/recipes/oscar64/screenshots/text-input-ntsc.png +0 -0
  701. package/docs/recipes/oscar64/screenshots/text-input.png +0 -0
  702. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-gameover.png +0 -0
  703. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-notrail-control.png +0 -0
  704. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-ntsc.png +0 -0
  705. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-ungated-control.png +0 -0
  706. package/docs/recipes/oscar64/screenshots/text-overlay-playfield.png +0 -0
  707. package/docs/recipes/oscar64/screenshots/text-window-menu-ntsc.png +0 -0
  708. package/docs/recipes/oscar64/screenshots/text-window-menu.png +0 -0
  709. package/docs/recipes/oscar64/screenshots/tile-grid-collision-ntsc.png +0 -0
  710. package/docs/recipes/oscar64/screenshots/tile-grid-collision.png +0 -0
  711. package/docs/recipes/oscar64/screenshots/tile-map-render-ntsc.png +0 -0
  712. package/docs/recipes/oscar64/screenshots/tile-map-render.png +0 -0
  713. package/docs/recipes/oscar64/screenshots/two-player-ntsc.png +0 -0
  714. package/docs/recipes/oscar64/screenshots/two-player.png +0 -0
  715. package/docs/recipes/oscar64/screenshots/two-word-parser-ntsc.png +0 -0
  716. package/docs/recipes/oscar64/screenshots/two-word-parser.png +0 -0
  717. package/docs/recipes/oscar64/screenshots/vehicle-control-ntsc.png +0 -0
  718. package/docs/recipes/oscar64/screenshots/vehicle-control.png +0 -0
  719. package/docs/recipes/oscar64/screenshots/wave-director-ntsc.png +0 -0
  720. package/docs/recipes/oscar64/screenshots/wave-director.png +0 -0
  721. package/docs/recipes/oscar64/seeded-level-fill.md +364 -0
  722. package/docs/recipes/oscar64/sfx-engine.md +514 -0
  723. package/docs/recipes/oscar64/sid-music-player.md +441 -0
  724. package/docs/recipes/oscar64/simple-shmup.md +1000 -0
  725. package/docs/recipes/oscar64/slope-collision.md +610 -0
  726. package/docs/recipes/oscar64/soft-scroll-h.md +261 -0
  727. package/docs/recipes/oscar64/sprite-animation-table.md +671 -0
  728. package/docs/recipes/oscar64/sprite-multiplex-8.md +314 -0
  729. package/docs/recipes/oscar64/stable-raster-irq.md +236 -0
  730. package/docs/recipes/oscar64/text-input.md +274 -0
  731. package/docs/recipes/oscar64/text-overlay-playfield.md +617 -0
  732. package/docs/recipes/oscar64/text-window-menu.md +551 -0
  733. package/docs/recipes/oscar64/tile-grid-collision.md +563 -0
  734. package/docs/recipes/oscar64/tile-map-render.md +395 -0
  735. package/docs/recipes/oscar64/two-player.md +528 -0
  736. package/docs/recipes/oscar64/two-word-parser.md +510 -0
  737. package/docs/recipes/oscar64/vehicle-control.md +771 -0
  738. package/docs/recipes/oscar64/wave-director.md +787 -0
  739. package/docs/recipes/runs.json +1606 -0
  740. package/docs/runtime/sim6502-reference.md +466 -0
  741. package/docs/runtime/vice-mcp-reference.md +351 -0
  742. package/docs/runtime/vice-reference.md +1393 -0
  743. package/docs/techniques/bitmap-modes.md +685 -0
  744. package/docs/techniques/cpu-cycle-tricks.md +1570 -0
  745. package/docs/techniques/effects-vector-3d.md +1431 -0
  746. package/docs/techniques/file-io.md +1427 -0
  747. package/docs/techniques/input.md +1072 -0
  748. package/docs/techniques/loaders-packers.md +768 -0
  749. package/docs/techniques/logic.md +3091 -0
  750. package/docs/techniques/maths.md +1524 -0
  751. package/docs/techniques/memory-banking.md +1686 -0
  752. package/docs/techniques/music-sid.md +1144 -0
  753. package/docs/techniques/raster.md +1543 -0
  754. package/docs/techniques/scroll.md +1292 -0
  755. package/docs/techniques/sprite.md +2566 -0
  756. package/docs/techniques/text-mode-render.md +717 -0
  757. package/docs/techniques/text.md +1095 -0
  758. package/docs/techniques/transitions.md +405 -0
  759. package/docs/toolchains/cartconv-reference.md +262 -0
  760. package/docs/toolchains/cc1541-reference.md +316 -0
  761. package/docs/toolchains/cc65-reference.md +667 -0
  762. package/docs/toolchains/error-sources/cc65/README.md +1 -0
  763. package/docs/toolchains/error-sources/cc65/missing-setcpu.s +4 -0
  764. package/docs/toolchains/error-sources/cc65/range-error.s +4 -0
  765. package/docs/toolchains/error-sources/cc65/segment-overflow.c +6 -0
  766. package/docs/toolchains/error-sources/cc65/unresolved-external.c +6 -0
  767. package/docs/toolchains/error-sources/kickassembler/README.md +1 -0
  768. package/docs/toolchains/error-sources/kickassembler/branch-out-of-range.asm +4 -0
  769. package/docs/toolchains/error-sources/kickassembler/failed-assert.asm +3 -0
  770. package/docs/toolchains/error-sources/kickassembler/flat-lib.asm +4 -0
  771. package/docs/toolchains/error-sources/kickassembler/import-source-no-namespace.asm +5 -0
  772. package/docs/toolchains/error-sources/kickassembler/macro-without-parentheses.asm +6 -0
  773. package/docs/toolchains/error-sources/kickassembler/memory-block-overlap.asm +4 -0
  774. package/docs/toolchains/error-sources/kickassembler/symbol-clash-lib.asm +5 -0
  775. package/docs/toolchains/error-sources/kickassembler/symbol-clash-main.asm +6 -0
  776. package/docs/toolchains/error-sources/kickassembler/unknown-symbol.asm +4 -0
  777. package/docs/toolchains/error-sources/oscar64/README.md +1 -0
  778. package/docs/toolchains/error-sources/oscar64/asm-addressing-mode.c +7 -0
  779. package/docs/toolchains/error-sources/oscar64/region-overflow.c +6 -0
  780. package/docs/toolchains/error-sources/oscar64/undefined-extern-var.c +5 -0
  781. package/docs/toolchains/error-sources/oscar64/undefined-extern.c +6 -0
  782. package/docs/toolchains/error-sources/oscar64/unknown-vic-field.c +6 -0
  783. package/docs/toolchains/error-sources/oscar64/void-main.c +3 -0
  784. package/docs/toolchains/kickassembler-reference.md +1020 -0
  785. package/docs/toolchains/memory-layout-planning.md +362 -0
  786. package/docs/toolchains/oscar64-headers-reference.md +583 -0
  787. package/docs/toolchains/oscar64-reference.md +892 -0
  788. package/docs/toolchains/petcat-reference.md +290 -0
  789. package/docs/toolchains/png2prg.md +188 -0
  790. package/docs/toolchains/release-disk.md +314 -0
  791. package/docs/toolchains/sidreloc.md +236 -0
  792. package/docs/toolchains/spindle-reference.md +487 -0
  793. package/docs/toolchains/tape-mastering.md +592 -0
  794. package/docs/toolchains/unit-testing-6502.md +281 -0
  795. package/docs/workflow/agent-harness.md +478 -0
  796. package/package.json +105 -0
  797. package/templates/_harness/CLAUDE.md.template +91 -0
  798. package/templates/_harness/PLAN.md.template +72 -0
  799. package/templates/_harness/check.py +442 -0
  800. package/templates/_harness/claude/settings.json +17 -0
  801. package/templates/_harness/gen-asm-header.py +96 -0
  802. package/templates/_harness/harness.mk +273 -0
  803. package/templates/_harness/hooks/plan-gate.py +185 -0
  804. package/templates/_harness/meter/frame_meter.asm +311 -0
  805. package/templates/_harness/meter/frame_meter.c +155 -0
  806. package/templates/_harness/meter/frame_meter.h +80 -0
  807. package/templates/_harness/zp-used.py +104 -0
  808. package/templates/action-puzzle/.claude/settings.json +17 -0
  809. package/templates/action-puzzle/.mcp.json +10 -0
  810. package/templates/action-puzzle/CLAUDE.md +120 -0
  811. package/templates/action-puzzle/Makefile +125 -0
  812. package/templates/action-puzzle/PLAN.md +388 -0
  813. package/templates/action-puzzle/README.md +240 -0
  814. package/templates/action-puzzle/expect.json +25 -0
  815. package/templates/action-puzzle/src/cave.c +280 -0
  816. package/templates/action-puzzle/src/cave.h +80 -0
  817. package/templates/action-puzzle/src/gen_autopilot.h +20 -0
  818. package/templates/action-puzzle/src/gen_caves.h +59 -0
  819. package/templates/action-puzzle/src/gen_notes.h +16 -0
  820. package/templates/action-puzzle/src/hiscore.c +152 -0
  821. package/templates/action-puzzle/src/hiscore.h +41 -0
  822. package/templates/action-puzzle/src/level.c +64 -0
  823. package/templates/action-puzzle/src/level.h +24 -0
  824. package/templates/action-puzzle/src/main.c +599 -0
  825. package/templates/action-puzzle/src/render.c +239 -0
  826. package/templates/action-puzzle/src/render.h +31 -0
  827. package/templates/action-puzzle/src/sound.c +158 -0
  828. package/templates/action-puzzle/src/sound.h +22 -0
  829. package/templates/action-puzzle/tools/disk_check.py +77 -0
  830. package/templates/action-puzzle/tools/drive.py +106 -0
  831. package/templates/action-puzzle/tools/gen.py +454 -0
  832. package/templates/action-puzzle/tools/model_check.py +49 -0
  833. package/templates/action-puzzle/tools/verdict_codes.py +24 -0
  834. package/templates/adventure/.claude/settings.json +17 -0
  835. package/templates/adventure/.mcp.json +10 -0
  836. package/templates/adventure/CLAUDE.md +118 -0
  837. package/templates/adventure/Makefile +113 -0
  838. package/templates/adventure/PLAN.md +396 -0
  839. package/templates/adventure/README.md +277 -0
  840. package/templates/adventure/expect.json +25 -0
  841. package/templates/adventure/src/engine.c +543 -0
  842. package/templates/adventure/src/engine.h +48 -0
  843. package/templates/adventure/src/gen_script.h +141 -0
  844. package/templates/adventure/src/gen_world.h +511 -0
  845. package/templates/adventure/src/main.c +439 -0
  846. package/templates/adventure/src/picture.c +83 -0
  847. package/templates/adventure/src/picture.h +16 -0
  848. package/templates/adventure/src/save.c +159 -0
  849. package/templates/adventure/src/save.h +25 -0
  850. package/templates/adventure/src/sound.c +71 -0
  851. package/templates/adventure/src/sound.h +16 -0
  852. package/templates/adventure/src/text.c +349 -0
  853. package/templates/adventure/src/text.h +40 -0
  854. package/templates/adventure/tools/disk_check.py +128 -0
  855. package/templates/adventure/tools/drive.py +119 -0
  856. package/templates/adventure/tools/gen.py +1033 -0
  857. package/templates/adventure/tools/world.py +356 -0
  858. package/templates/beat-em-up/.claude/settings.json +17 -0
  859. package/templates/beat-em-up/.mcp.json +10 -0
  860. package/templates/beat-em-up/CLAUDE.md +136 -0
  861. package/templates/beat-em-up/Makefile +96 -0
  862. package/templates/beat-em-up/PLAN.md +502 -0
  863. package/templates/beat-em-up/README.md +315 -0
  864. package/templates/beat-em-up/expect-gameover.json +8 -0
  865. package/templates/beat-em-up/expect.json +29 -0
  866. package/templates/beat-em-up/src/anim.c +70 -0
  867. package/templates/beat-em-up/src/art.c +344 -0
  868. package/templates/beat-em-up/src/autopilot.h +154 -0
  869. package/templates/beat-em-up/src/brute.c +273 -0
  870. package/templates/beat-em-up/src/enemy.c +281 -0
  871. package/templates/beat-em-up/src/engine.asm +512 -0
  872. package/templates/beat-em-up/src/fighter.c +384 -0
  873. package/templates/beat-em-up/src/game.h +269 -0
  874. package/templates/beat-em-up/src/hud.c +135 -0
  875. package/templates/beat-em-up/src/main.c +341 -0
  876. package/templates/beat-em-up/src/sound.c +44 -0
  877. package/templates/beat-em-up/src/street.c +93 -0
  878. package/templates/beat-em-up/src/verdict.h +523 -0
  879. package/templates/beat-em-up/src/view.c +362 -0
  880. package/templates/beat-em-up/tools/drive.py +105 -0
  881. package/templates/beat-em-up/tools/flickercheck.py +273 -0
  882. package/templates/demo/.claude/settings.json +17 -0
  883. package/templates/demo/.mcp.json +10 -0
  884. package/templates/demo/CLAUDE.md +129 -0
  885. package/templates/demo/Makefile +66 -0
  886. package/templates/demo/PLAN.md +401 -0
  887. package/templates/demo/README.md +322 -0
  888. package/templates/demo/expect.json +945 -0
  889. package/templates/demo/src/config.asm +80 -0
  890. package/templates/demo/src/framework.asm +390 -0
  891. package/templates/demo/src/main.asm +139 -0
  892. package/templates/demo/src/music.asm +197 -0
  893. package/templates/demo/src/part_main.asm +279 -0
  894. package/templates/demo/src/part_title.asm +79 -0
  895. package/templates/demo/src/parts.asm +43 -0
  896. package/templates/demo/src/tables.asm +73 -0
  897. package/templates/demo/src/verdict.asm +179 -0
  898. package/templates/demo/tools/audio.py +80 -0
  899. package/templates/demo/tools/gen_expect.py +167 -0
  900. package/templates/demo/tools/probe.py +95 -0
  901. package/templates/hello/.claude/settings.json +17 -0
  902. package/templates/hello/.mcp.json +10 -0
  903. package/templates/hello/CLAUDE.md +100 -0
  904. package/templates/hello/Makefile +38 -0
  905. package/templates/hello/PLAN.md +200 -0
  906. package/templates/hello/expect.json +20 -0
  907. package/templates/hello/src/main.c +161 -0
  908. package/templates/hello/src/sprite.asm +27 -0
  909. package/templates/hello-kick/.claude/settings.json +17 -0
  910. package/templates/hello-kick/.mcp.json +10 -0
  911. package/templates/hello-kick/CLAUDE.md +100 -0
  912. package/templates/hello-kick/Makefile +17 -0
  913. package/templates/hello-kick/PLAN.md +199 -0
  914. package/templates/hello-kick/expect.json +20 -0
  915. package/templates/hello-kick/src/main.asm +233 -0
  916. package/templates/platformer/.claude/settings.json +17 -0
  917. package/templates/platformer/.mcp.json +10 -0
  918. package/templates/platformer/CLAUDE.md +125 -0
  919. package/templates/platformer/Makefile +86 -0
  920. package/templates/platformer/PLAN.md +360 -0
  921. package/templates/platformer/README.md +277 -0
  922. package/templates/platformer/expect.json +32 -0
  923. package/templates/platformer/src/actors.c +289 -0
  924. package/templates/platformer/src/anim.c +51 -0
  925. package/templates/platformer/src/art.c +212 -0
  926. package/templates/platformer/src/autopilot.h +30 -0
  927. package/templates/platformer/src/engine.asm +253 -0
  928. package/templates/platformer/src/game.h +248 -0
  929. package/templates/platformer/src/hud.c +90 -0
  930. package/templates/platformer/src/level.c +184 -0
  931. package/templates/platformer/src/main.c +306 -0
  932. package/templates/platformer/src/player.c +268 -0
  933. package/templates/platformer/src/sound.c +42 -0
  934. package/templates/platformer/src/verdict.h +206 -0
  935. package/templates/platformer/src/view.c +331 -0
  936. package/templates/platformer/stage-expect.json +6 -0
  937. package/templates/platformer/tools/drive.py +112 -0
  938. package/templates/platformer/tools/tearcheck.py +229 -0
  939. package/templates/shmup-vertical/.claude/settings.json +17 -0
  940. package/templates/shmup-vertical/.mcp.json +10 -0
  941. package/templates/shmup-vertical/CLAUDE.md +137 -0
  942. package/templates/shmup-vertical/Makefile +131 -0
  943. package/templates/shmup-vertical/PLAN.md +569 -0
  944. package/templates/shmup-vertical/README.md +189 -0
  945. package/templates/shmup-vertical/expect.json +38 -0
  946. package/templates/shmup-vertical/src/bullets.c +158 -0
  947. package/templates/shmup-vertical/src/bullets.h +35 -0
  948. package/templates/shmup-vertical/src/display.c +239 -0
  949. package/templates/shmup-vertical/src/display.h +40 -0
  950. package/templates/shmup-vertical/src/game.h +85 -0
  951. package/templates/shmup-vertical/src/glyph.asm +358 -0
  952. package/templates/shmup-vertical/src/hiscore.c +141 -0
  953. package/templates/shmup-vertical/src/hiscore.h +16 -0
  954. package/templates/shmup-vertical/src/hit.asm +180 -0
  955. package/templates/shmup-vertical/src/hitbox.c +59 -0
  956. package/templates/shmup-vertical/src/hitbox.h +25 -0
  957. package/templates/shmup-vertical/src/kernel.asm +330 -0
  958. package/templates/shmup-vertical/src/level.c +174 -0
  959. package/templates/shmup-vertical/src/level.h +27 -0
  960. package/templates/shmup-vertical/src/main.c +824 -0
  961. package/templates/shmup-vertical/src/mux.asm +321 -0
  962. package/templates/shmup-vertical/src/sound.asm +255 -0
  963. package/templates/shmup-vertical/src/step.asm +169 -0
  964. package/templates/shmup-vertical/src/waves.c +195 -0
  965. package/templates/shmup-vertical/src/waves.h +33 -0
  966. package/templates/shmup-vertical/stage-expect.json +6 -0
  967. package/templates/shmup-vertical/tools/drive.py +152 -0
  968. package/templates/shmup-vertical/tools/joytest.py +159 -0
  969. package/templates/shmup-vertical/tools/meter.py +15 -0
  970. package/templates/shmup-vertical/tools/phases.py +73 -0
@@ -0,0 +1,617 @@
1
+ ---
2
+ recipe: text-overlay-playfield
3
+ toolchain: oscar64
4
+ output_format: PRG
5
+ region: both
6
+ techniques: [text_mode_overlay_render]
7
+ file_formats: [PRG]
8
+ uses_registers: [D011, D012, D020, D021]
9
+ uses_kernal: []
10
+ ---
11
+
12
+ <!-- doc-type: recipe -->
13
+
14
+ # Oscar64 Text-Mode Playfield with a Moving-Piece Overlay
15
+
16
+ ## Synopsis
17
+
18
+ A 10×20 playfield in text mode, drawn two characters wide per cell, with
19
+ one falling tetromino on top of it. The piece is never in the playfield
20
+ array: each frame the program repaints the piece's previous cells from
21
+ `field[][]` and then draws its current cells, eight cells in all. The whole
22
+ field is repainted only at start and when a piece locks. The program measures
23
+ both costs itself and prints them on the bottom row in raster lines, next to
24
+ a tick counter, so the budget argument in `text_mode_overlay_render` is on
25
+ the screen rather than in a comment; the KERNAL's 60 Hz interrupt is
26
+ switched off first, so that the two numbers are the paint and the overlay
27
+ and nothing else. There is no input and no random number generator: the
28
+ piece sequence is fixed, so the screen at any tick is predictable, which is
29
+ how the page was verified. Use it as the render shell for a Tetris-,
30
+ Sokoban- or board-game-shaped project; the game logic is a stub (spawn,
31
+ fall, lock, game over) and is meant to be replaced.
32
+
33
+ ## Source
34
+
35
+ ```c
36
+ // text-overlay-playfield.c
37
+ //
38
+ // A 10x20 text-mode playfield with one falling tetromino drawn as an
39
+ // overlay. Each frame repaints only the piece's previous cells (from
40
+ // field[][]) and its current cells. The whole field is repainted once at
41
+ // start and once per lock. Both costs are measured in raster lines and
42
+ // shown on the bottom row, next to a tick counter on the top row. The
43
+ // KERNAL's 60 Hz IRQ is switched off first: left running, its service
44
+ // routine lands inside the timed paths and adds four or five raster lines
45
+ // to whichever number it happens to hit.
46
+ //
47
+ // Deterministic: fixed piece sequence, no input, no RNG. The screen at any
48
+ // tick is predictable, which is how the recipe was verified.
49
+ //
50
+ // Build: oscar64 -tm=c64 -O2 -o=text-overlay-playfield.prg text-overlay-playfield.c
51
+ #include <c64/vic.h>
52
+
53
+ #define Screen ((char *)0x0400)
54
+ #define Color ((char *)0xD800)
55
+ #define COLS 40
56
+
57
+ #define FIELD_W 10
58
+ #define FIELD_H 20
59
+ #define FIELD_COL0 10 // screen column of field x = 0; each cell is 2 chars
60
+ #define FIELD_ROW0 2 // screen row of field y = 0
61
+ #define GRAVITY 8 // ticks (frames) per row of fall
62
+ #define LINES_PER_FRAME 312 // PAL 6569; 263 for NTSC 6567R8 (timer display only)
63
+
64
+ #define ST_PLAY 0
65
+ #define ST_OVER 1
66
+
67
+ // Persistent playfield: 0 = empty, otherwise piece type + 1.
68
+ static char field[FIELD_H][FIELD_W];
69
+
70
+ // Seven tetrominoes, one orientation each: four (dx, dy) pairs in a 4x2 box.
71
+ static const char piece_cells[7][8] = {
72
+ { 0,1, 1,1, 2,1, 3,1 }, // I
73
+ { 1,0, 2,0, 1,1, 2,1 }, // O
74
+ { 1,0, 0,1, 1,1, 2,1 }, // T
75
+ { 2,0, 0,1, 1,1, 2,1 }, // L
76
+ { 0,0, 0,1, 1,1, 2,1 }, // J
77
+ { 1,0, 2,0, 0,1, 1,1 }, // S
78
+ { 0,0, 1,0, 1,1, 2,1 }, // Z
79
+ };
80
+
81
+ // Colour per field value; index 0 is the empty cell (a space, colour unused).
82
+ static const char piece_color[8] = {
83
+ VCOL_BLACK, VCOL_CYAN, VCOL_YELLOW, VCOL_PURPLE,
84
+ VCOL_ORANGE, VCOL_LT_BLUE, VCOL_GREEN, VCOL_RED
85
+ };
86
+
87
+ // Fixed spawn sequence (type, x), repeated until a piece cannot spawn.
88
+ #define SEQ_LEN 8
89
+ static const char seq_type[SEQ_LEN] = { 1, 0, 2, 3, 4, 5, 6, 0 };
90
+ static const char seq_x[SEQ_LEN] = { 0, 2, 6, 3, 0, 6, 3, 6 };
91
+
92
+ // The active piece, and where render_piece last drew it.
93
+ static char cur_type, cur_x, cur_y;
94
+ static char prev_type, prev_x, prev_y;
95
+ static bool have_prev;
96
+ static char seq_pos, gravity, state;
97
+
98
+ static char tick_digits[5]; // tick counter, shown on row 0
99
+ static unsigned paint_lines; // raster lines the last render_field took
100
+
101
+ // ----------------------------------------------------------------- timing
102
+
103
+ // Current raster line, 0..LINES_PER_FRAME-1, from $D012 and RST8 in $D011.
104
+ // Re-reads once if RST8 changed between the two reads.
105
+ static unsigned raster_line(void)
106
+ {
107
+ char hi = vic.ctrl1;
108
+ char lo = vic.raster;
109
+ if ((vic.ctrl1 ^ hi) & VIC_CTRL1_RST8) {
110
+ hi = vic.ctrl1;
111
+ lo = vic.raster;
112
+ }
113
+ return (hi & VIC_CTRL1_RST8) ? 256 + lo : lo;
114
+ }
115
+
116
+ // ---------------------------------------------------------------- drawing
117
+
118
+ // Paint one field cell (two screen columns) from a field value.
119
+ static void paint_cell(char x, char y, char v)
120
+ {
121
+ unsigned o = (unsigned)(FIELD_ROW0 + y) * COLS + FIELD_COL0 + 2 * x;
122
+ char code = v ? 0xA0 : 0x20;
123
+ char col = piece_color[v];
124
+ Screen[o] = code; Screen[o + 1] = code;
125
+ Color[o] = col; Color[o + 1] = col;
126
+ }
127
+
128
+ // Full paint of the persistent field: 200 cells, row pointers. Start and
129
+ // lock only. The raster is sampled once per row so a frame wrap during the
130
+ // paint is counted instead of folding the result back into 0..311.
131
+ static void render_field(void)
132
+ {
133
+ char *s = Screen + FIELD_ROW0 * COLS + FIELD_COL0;
134
+ char *c = Color + FIELD_ROW0 * COLS + FIELD_COL0;
135
+ const char *f = field[0];
136
+ unsigned start = raster_line(), last = start, wraps = 0;
137
+
138
+ for (char y = 0; y < FIELD_H; y++) {
139
+ for (char x = 0; x < 2 * FIELD_W; x += 2) {
140
+ char v = *f++;
141
+ char code = v ? 0xA0 : 0x20;
142
+ char col = piece_color[v];
143
+ s[x] = code; s[x + 1] = code;
144
+ c[x] = col; c[x + 1] = col;
145
+ }
146
+ s += COLS; c += COLS;
147
+
148
+ unsigned now = raster_line();
149
+ if (now < last)
150
+ wraps++;
151
+ last = now;
152
+ }
153
+ paint_lines = last - start + wraps * LINES_PER_FRAME;
154
+ have_prev = false; // nothing left on screen that is not in field[][]
155
+ }
156
+
157
+ // Per-frame overlay: erase the previous position from field[][], then
158
+ // draw the current one. Eight cells, whatever the field size.
159
+ static void render_piece(void)
160
+ {
161
+ if (have_prev) {
162
+ const char *q = piece_cells[prev_type];
163
+ for (char i = 0; i < 8; i += 2) {
164
+ char x = prev_x + q[i], y = prev_y + q[i + 1];
165
+ paint_cell(x, y, field[y][x]);
166
+ }
167
+ }
168
+ const char *p = piece_cells[cur_type];
169
+ for (char i = 0; i < 8; i += 2)
170
+ paint_cell(cur_x + p[i], cur_y + p[i + 1], cur_type + 1);
171
+ prev_type = cur_type; prev_x = cur_x; prev_y = cur_y;
172
+ have_prev = true;
173
+ }
174
+
175
+ // White text at (col, row). The S"" prefix makes the literal screen codes;
176
+ // with lowercase s the letters come out as the shifted glyphs instead.
177
+ static void put_text(char col, char row, const char *s)
178
+ {
179
+ unsigned o = (unsigned)row * COLS + col;
180
+ while (*s) {
181
+ Screen[o] = *s++;
182
+ Color[o] = VCOL_WHITE;
183
+ o++;
184
+ }
185
+ }
186
+
187
+ // Grey walls around the field so the empty cells read as a board.
188
+ static void draw_walls(void)
189
+ {
190
+ char c0 = FIELD_COL0 - 1, c1 = FIELD_COL0 + 2 * FIELD_W;
191
+ for (char r = FIELD_ROW0; r <= FIELD_ROW0 + FIELD_H; r++) {
192
+ unsigned o = (unsigned)r * COLS;
193
+ if (r == FIELD_ROW0 + FIELD_H) {
194
+ for (char c = c0; c <= c1; c++) { Screen[o + c] = 0xA0; Color[o + c] = VCOL_MED_GREY; }
195
+ } else {
196
+ Screen[o + c0] = 0xA0; Color[o + c0] = VCOL_MED_GREY;
197
+ Screen[o + c1] = 0xA0; Color[o + c1] = VCOL_MED_GREY;
198
+ }
199
+ }
200
+ }
201
+
202
+ // Advance and show the tick counter (row 0, columns 5..9).
203
+ static void show_tick(void)
204
+ {
205
+ char i = 4;
206
+ while (++tick_digits[i] == 10) {
207
+ tick_digits[i] = 0;
208
+ if (i == 0) break;
209
+ i--;
210
+ }
211
+ for (char d = 0; d < 5; d++)
212
+ Screen[5 + d] = 48 + tick_digits[d];
213
+ }
214
+
215
+ // Decimal digits of n, right-aligned in `width` cells at screen offset o.
216
+ static void show_number(unsigned o, char width, unsigned n)
217
+ {
218
+ while (width--) {
219
+ Screen[o + width] = 48 + (char)(n % 10);
220
+ n /= 10;
221
+ }
222
+ }
223
+
224
+ #define PAINT_DIGITS (24 * COLS + 11) // row 24: "FULL PAINT nnnn LINES"
225
+ #define OVERLAY_DIGITS (24 * COLS + 32) // row 24: "OVERLAY nn LINES"
226
+
227
+ // ------------------------------------------------------------------- game
228
+
229
+ static bool fits(char type, char x, char y)
230
+ {
231
+ const char *p = piece_cells[type];
232
+ for (char i = 0; i < 8; i += 2) {
233
+ char cy = y + p[i + 1];
234
+ if (cy >= FIELD_H || field[cy][x + p[i]])
235
+ return false;
236
+ }
237
+ return true;
238
+ }
239
+
240
+ static void spawn(void)
241
+ {
242
+ cur_type = seq_type[seq_pos];
243
+ cur_x = seq_x[seq_pos];
244
+ cur_y = 0;
245
+ gravity = GRAVITY;
246
+ if (++seq_pos == SEQ_LEN)
247
+ seq_pos = 0;
248
+ if (!fits(cur_type, cur_x, cur_y)) {
249
+ state = ST_OVER;
250
+ put_text(FIELD_COL0 + 5, FIELD_ROW0 + 1, S"GAME OVER");
251
+ }
252
+ }
253
+
254
+ // The piece enters field[][]; that is the one persistent-state change,
255
+ // so it is the one place the full paint runs.
256
+ static void lock_piece(void)
257
+ {
258
+ const char *p = piece_cells[cur_type];
259
+ for (char i = 0; i < 8; i += 2)
260
+ field[cur_y + p[i + 1]][cur_x + p[i]] = cur_type + 1;
261
+ render_field();
262
+ show_number(PAINT_DIGITS, 4, paint_lines);
263
+ spawn();
264
+ }
265
+
266
+ static void tick(void)
267
+ {
268
+ if (--gravity)
269
+ return;
270
+ gravity = GRAVITY;
271
+ if (fits(cur_type, cur_x, cur_y + 1))
272
+ cur_y++;
273
+ else
274
+ lock_piece();
275
+ }
276
+
277
+ int main(void)
278
+ {
279
+ __asm { sei } // KERNAL IRQ off; see "Why this works"
280
+ vic.color_border = VCOL_BLACK;
281
+ vic.color_back = VCOL_BLACK;
282
+ for (unsigned i = 0; i < 1000; i++) {
283
+ Screen[i] = 0x20;
284
+ Color[i] = VCOL_BLACK;
285
+ }
286
+ draw_walls();
287
+ put_text(0, 0, S"TICK 00000");
288
+ put_text(0, 24, S"FULL PAINT ---- LINES");
289
+ put_text(24, 24, S"OVERLAY -- LINES");
290
+
291
+ render_field(); // initial paint of the (empty) field
292
+ show_number(PAINT_DIGITS, 4, paint_lines);
293
+ spawn();
294
+
295
+ for (;;) {
296
+ vic_waitFrame(); // returns when RST8 sets: line 256
297
+ show_tick();
298
+ if (state == ST_PLAY) {
299
+ tick(); // may lock, repaint, spawn, or end the game
300
+ if (state == ST_PLAY) { // gate the overlay on the state AFTER tick()
301
+ unsigned t0 = raster_line();
302
+ render_piece();
303
+ show_number(OVERLAY_DIGITS, 2,
304
+ (raster_line() + LINES_PER_FRAME - t0) % LINES_PER_FRAME);
305
+ }
306
+ }
307
+ }
308
+ return 0;
309
+ }
310
+ ```
311
+
312
+ ## Build
313
+
314
+ ```bash
315
+ oscar64 -tm=c64 -O2 -o=text-overlay-playfield.prg text-overlay-playfield.c
316
+ ```
317
+
318
+ Oscar64 build 2026-05-19, zero diagnostics; the PRG is 1,769 bytes. `-O2`
319
+ matters for the numbers below: the page's measurements were taken at that
320
+ level and nowhere else.
321
+
322
+ ## Expected output
323
+
324
+ Black border and background. A medium-grey wall in the shape of a U: columns
325
+ 9 and 30 from screen row 2 to 21, and a floor across columns 9–30 on row 22.
326
+ Inside it the playfield, 20 columns by 20 rows, starts empty. Row 0 reads
327
+ `TICK nnnnn` in white and counts up once per frame. Row 24 reads
328
+ `FULL PAINT 0275 LINES OVERLAY 33 LINES` until the first lock at tick 152,
329
+ `FULL PAINT 0272 LINES` after it, `0273` after the second, third and fourth
330
+ locks, and `0277` when the board is full at the end. The overlay figure is
331
+ `33` on every frame except the first one and the frame of each lock, which
332
+ have no previous position to erase and read `17` (rung 1: a probe build of
333
+ this listing that keeps the minimum, the maximum and a histogram of the
334
+ overlay figure read, over its first 654 frames, 33 in 649 and 17 in 5, no
335
+ other value).
336
+
337
+ Pieces fall one field row every 8 frames and lock when they cannot fall
338
+ further. The sequence is fixed: O (yellow, column 0), I (cyan, column 2),
339
+ T (purple, column 6), L (orange, column 3), J (light blue, column 0),
340
+ S (green, column 6), Z (red, column 3), I (cyan, column 6), then repeats.
341
+ The first lock is at tick 152, the thirtieth at tick 2368; the piece that
342
+ should follow it cannot spawn, `GAME OVER` appears in white across field
343
+ row 1 (screen row 3, columns 15–23) and the overlay stops. The tick counter
344
+ keeps going.
345
+
346
+ ![text-overlay-playfield](screenshots/text-overlay-playfield.png)
347
+
348
+ The picture is the 16,000,000-cycle capture, tick 654. Verified in VICE
349
+ x64sc 3.10 (PAL, the default C64C: 8565, 8580, 8521; an earlier version said
350
+ 6569), headless, warp, with `+autostart-delay-random`.
351
+ That switch is not in the usual invocation and it matters here: without it
352
+ three identical runs at `-limitcycles 8000000` read ticks 249, 238 and 240,
353
+ because VICE adds a random delay before the autostart `RUN` by default;
354
+ with it, three runs read 250, 250, 250. Read the counter, never the cycle
355
+ count, to know which frame a capture shows.
356
+
357
+ Measured (rung 1, script over the PNG, not by eye): every one of the 40×25
358
+ cells was decoded by matching its 8×8 block against the glyphs of
359
+ `chargen-901225-01.bin`, with the 16 colours taken from a calibration run of
360
+ the same VICE build (a PRG that shows the 16 colours as reverse spaces), and
361
+ compared with a Python model of this listing run for the number of ticks on
362
+ screen. The cell origin was measured too: text row 0 begins at PNG row 35 and
363
+ column 0 at x 32, so a cell is the block at `(32 + 8·col, 35 + 8·row)`; the
364
+ grey wall's first pixel row is 51 and its first column x 104. The display
365
+ window's 200 lines therefore occupy PNG rows 35–234, which is raster 51–250
366
+ minus 16, not minus 14; the committed `kickassembler/screenshots/raster-bars.png`
367
+ has its window at the same rows. On the 384×247 NTSC capture text row 0
368
+ begins at PNG row 23 (raster 51 minus 28), column 0 at the same x 32.
369
+
370
+ | `-limitcycles` | tick | on screen | locked cells | cells matching the model |
371
+ |---|---|---|---|---|
372
+ | 5,000,000 | 99 | O (yellow) at field row 12, nothing locked yet; row 24 reads `0275` | 0 | 994 of 994 |
373
+ | 8,000,000 | 250 | I (cyan) at field row 12 after one lock (the O) | 4 | 994 of 994 |
374
+ | 16,000,000 | 654 | J (light blue) at field row 10 after four locks — the picture above | 16 | 994 of 994 |
375
+ | 60,000,000 | 2867 | `GAME OVER`, all nine characters intact, 30 locks — `screenshots/text-overlay-playfield-gameover.png` | 120 | 994 of 994 |
376
+ | 8,000,000, `-model ntsc` | 281 | as the 8 M PAL row; row 24 reads `0315` and `81` (see below) — `screenshots/text-overlay-playfield-ntsc.png` | 4 | 994 of 994 |
377
+
378
+ 994 is 1,000 cells minus the six digit cells of the two on-screen
379
+ measurements, which are read from the picture rather than modelled. Per
380
+ capture the script asserts that (a) the four piece cells are solid `$A0` in
381
+ the piece's colour, (b) the cells of the piece's previous position hold
382
+ whatever `field[][]` holds there, (c) every locked cell is still on screen,
383
+ (d) nothing outside the field differs from the model, (e) every other field
384
+ cell is empty, and (f) every cell decodes to a character-ROM glyph. All pass
385
+ in all five. A capture that landed mid-frame while the piece moved would
386
+ fail (e) or (f); none did, and the piece had not moved on any captured tick
387
+ anyway (99, 250, 654 and 281 are not multiples of 8). One capture did land
388
+ mid-write: a 16 M NTSC run (tick 745) caught `show_number` between the two
389
+ overlay digits and the decoder refused that cell. It is not in the table,
390
+ and it is the reason the counter, not the cycle count, names a frame.
391
+ (Audit note, 2026-09-22, rung 1: `docs/recipes/runs.json` pins this
392
+ recipe at 16,000,000 cycles for *both* models, so `verify-recipes` renders
393
+ that same tick-745 NTSC frame — `OVERLAY 8?` with the units digit
394
+ half-written — and reports it as differing from the committed NTSC picture,
395
+ which is the 8 M capture at tick 281. The PAL arm matches pixel for pixel
396
+ at 16 M. Until the NTSC pin is 8,000,000 that mismatch is the pin, not the
397
+ listing.)
398
+
399
+ The two numbers on row 24 (rung 1, read from the same captures):
400
+
401
+ - `FULL PAINT 0272 LINES` with 4 cells filled, `0273` with 8 to 16, `0277`
402
+ with 120, and `0275` for the empty field painted from `main` before the
403
+ loop starts. At 63 cycles a line that is 17,100–17,450 cycles for 200
404
+ cells, about 86 cycles a cell; badline stalls inside the paint are counted
405
+ in, since this is wall time. (The spread is consistent with the
406
+ `v ? 0xA0 : 0x20` branch costing a cycle more per filled cell, and with
407
+ the first paint starting wherever `main` had got to rather than at line
408
+ 256 and so meeting a different number of badlines; neither was measured
409
+ on its own.) It is nearly five times the 56 lines between the RST8 rise
410
+ at line 256 and the wrap, and 2.5 times the 107 lines before the display
411
+ window resumes at raster 51.
412
+ - `OVERLAY 33 LINES`, 2,079 cycles, for the eight `paint_cell` calls plus
413
+ the two raster reads that bracket them. `render_piece` alone is 1,998
414
+ cycles on CIA 2's timer A in a probe build; the two reads are the rest.
415
+
416
+ **Correction.** The first version of this page had no `sei`, and its row-24
417
+ figures — `FULL PAINT 0277` at 4 and at 16 cells, `0285` at 120,
418
+ `OVERLAY 33` — were the paint plus the KERNAL's interrupt. Oscar64's C64
419
+ start-up leaves the 60 Hz IRQ running (the one `sei` in its `crt.c` is under
420
+ the NES target, and the assembly it generated for that listing contained
421
+ none), and the service routine, four to five raster lines each time, landed
422
+ once or twice inside every paint and inside about one overlay in eight: the
423
+ same histogram probe with the interrupt on read 33 in 569 of 654 frames, 37
424
+ in 12, 17 in 3, and some other value in the remaining 70. The paint figure
425
+ also depended on where the interrupt fell — 277 in runs with
426
+ `+autostart-delay-random`, 281 in a run without it at tick 244, same lock,
427
+ same picture otherwise — and that page's "277 for the empty field" was
428
+ wrong twice over: 277 was the 4-cell paint after the first lock, and the
429
+ empty-field paint had never been captured (it is 275, tick 99 above). The
430
+ cycle figures derived from those numbers (17,450–17,950 cycles, 88 a cell)
431
+ were high by the same amount. With the interrupt off nothing else moves:
432
+ the 8 M, 16 M and 60 M captures land on the same ticks as before (250, 654,
433
+ 2867) with the same 994 cells matching, so the lost frame per lock below
434
+ never depended on it.
435
+
436
+ And one number the counter gives for free: between the 8 M and 16 M captures
437
+ the emulated C64 ran 8,000,000 cycles, 407.0 PAL frames, and the counter
438
+ advanced 404. Three locks lie between those ticks (288, 440, 568), and 10 M
439
+ and 12 M captures (ticks 351 and 452) agree: one lock, one lost frame. The
440
+ lock frame is well over 312 lines of work counted from line 256: 272 of
441
+ paint, 19 for the four-digit display, 17 of overlay and 23 for its own
442
+ display come to 331 before the field writes, `spawn` and the wrap
443
+ arithmetic, and a probe bracket around the whole frame, with its own
444
+ instrumentation inside it, read 371 (each part on CIA 2's timer A in a
445
+ probe build). So it runs past line 256 of the following frame and
446
+ `vic_waitFrame` waits for the frame after that. The two controls below were measured the same way; their
447
+ pictures are in the same directory, and the digits on their row 24
448
+ (`OVERLAY 16` and `18`) are those builds' own numbers, not this listing's.
449
+
450
+ On NTSC (`-model ntsc`, 6567R8, 8,000,000 cycles, the same switches) the
451
+ capture is 384×247, the tick is 281, all 994 modelled cells match, and row
452
+ 24 reads `FULL PAINT 0315 LINES OVERLAY 81 LINES`. Both are 49 too high,
453
+ 312 − 263, because `LINES_PER_FRAME` is still 312: the paint wraps once and
454
+ the wrap is counted as 312 lines, and the overlay begins after line 256 and
455
+ crosses the wrap, so the modulo adds a frame's worth. The true values are
456
+ 266 and 32 lines — 17,290 and 2,080 cycles at 65 a line, against 17,136 and
457
+ 2,079 on PAL — and the overlay itself has no region dependence. Set
458
+ `LINES_PER_FRAME` to 263 for a build whose display is right on NTSC. The
459
+ first version of this page said it had not been run on NTSC; the shipped
460
+ build of that version reads `0319` and `81` there, the interrupt inside the
461
+ paint again.
462
+
463
+ ## Why this works
464
+
465
+ ### Two passes and one invariant
466
+
467
+ `render_piece` does what `text_mode_overlay_render` prescribes: pass one
468
+ repaints the four cells the piece occupied last frame *from `field[][]`*,
469
+ pass two writes `$A0` in the piece's colour at the four cells it occupies
470
+ now. Nothing on screen is ever anything but `field[][]` plus the current
471
+ piece, and the erase pass needs no memory of what was under the piece
472
+ because the field array is that memory. When the piece locks it is written
473
+ into `field[][]` and `have_prev` is cleared, so the erase pass is skipped on
474
+ that frame and the new piece starts clean. `prev_type` is carried as well as
475
+ `prev_x, prev_y` for the general form of the technique, where the shape can
476
+ change between frames — a rotation, or a lock that does not repaint — and
477
+ erasing the new shape's cells at the old position would leave the old
478
+ shape's cells behind. In this listing it is redundant: `cur_type` changes
479
+ only in `spawn()`, which is reached only through `render_field()`, which
480
+ clears `have_prev`, so whenever the erase pass runs `prev_type == cur_type`.
481
+
482
+ ### Why the full paint is not per frame
483
+
484
+ `render_field` is the honest cost of "just redraw everything": 272 raster
485
+ lines for this loop, which is already the fast form, with row pointers,
486
+ unrolled two-column stores and no per-cell multiply. The first draft of this
487
+ page routed the 200 cells through `paint_cell` and measured 707 lines, 2.3
488
+ frames, and lost two frames at every lock. The generated `paint_cell` is
489
+ about 60 instructions — shift-and-add for `(2 + y) × 40`, the `2·x` offset,
490
+ four indirect stores — and an opcode tally of the body Oscar64 emitted comes
491
+ to 173–175 cycles before the `JSR`/`RTS` and the caller's argument setup
492
+ (rung 3, from the rung-1 listing). Measured, it is about 250 cycles a call
493
+ as `render_piece` runs it (1,998 cycles for eight) and 707 × 63 / 200 ≈ 220
494
+ in that first draft's loop, interrupt included. The first version of this
495
+ page said "about 50 instructions, roughly 100 cycles a call", which its own
496
+ numbers contradicted. Fine eight times a frame, ruinous two hundred times.
497
+ That draft also displayed `83`, because the timer took the difference of two
498
+ raster reads modulo 312 and the true value was 83 + 2 × 312. The counter
499
+ caught it: the run lost 58 ticks over 29 locks. The `render_field` above
500
+ samples the raster after every row and counts the wraps, so its number
501
+ cannot alias unless a single row takes a whole frame.
502
+
503
+ The whole per-frame path — `show_tick`, `tick`, `render_piece` and the
504
+ overlay's own number display — measures 57 lines (rung 1: a probe build of
505
+ this listing that brackets the loop body instead of the overlay alone, tick
506
+ 250, same VICE run parameters; 41 on the first frame, whose overlay is the
507
+ 17-line kind, and up to 63 on some others — every eighth frame `tick` runs
508
+ `fits()` and moves the piece, which is the likely extra, not separately
509
+ measured). The parts, on CIA 2's timer A in the same
510
+ probe: `show_tick` 123 cycles, `tick` 22 on a frame with no move,
511
+ `render_piece` 1,998, and the display 1,445 — two raster reads at 57 each,
512
+ the two digits at 522, and 809 for the `% LINES_PER_FRAME`, which is a
513
+ 16-bit division in Oscar64's runtime because 312 does not fit a byte. The
514
+ first version of this page gave 43 lines here, which is what the bracket
515
+ reads when that modulo falls outside it; the display is a real cost of this
516
+ listing and belongs inside. The eight cell writes are done within the first
517
+ 35 of the 57 lines, inside the 56 between `vic_waitFrame`'s return and the
518
+ wrap; the digit arithmetic runs a line past the wrap and stores into row 24
519
+ while the beam is in the top border. The display window does not resume
520
+ until raster 51, so there are 107 lines of race-free time and the per-frame
521
+ work uses 53 % of them. The full paint at 272 lines cannot fit, and that is
522
+ the whole point of the technique: the redraw is reserved for the events that
523
+ change `field[][]`.
524
+
525
+ On the lock frame in this listing the paint is invisible: the overlay had
526
+ already drawn the piece where it locked, in the same code and colour, so
527
+ the 200 writes change nothing on screen. The one-frame stall is the only
528
+ symptom. A line clear, which this stub does not implement, would shift the
529
+ field and make the paint visible for one frame; the technique page calls
530
+ that tear acceptable, and it is, once per clear.
531
+
532
+ ### The three pitfalls, by name
533
+
534
+ - `dirty_cell_skip_leaves_overlay_trail` — the trail appears whenever the
535
+ cells the piece just left are not rewritten. Here they are rewritten
536
+ unconditionally by the erase pass, from the field array. The control
537
+ build with that pass deleted (`if (false)` in place of `if (have_prev)`)
538
+ shows, at tick 250, the cyan I piece smeared over its twelve previous
539
+ rows: 96 cells differ from the correct model, and zero differ from a
540
+ model with the erase pass removed. Picture:
541
+ `screenshots/text-overlay-playfield-notrail-control.png`.
542
+ - `render_during_state_transition_clobbers_banner` — `tick()` can flip
543
+ `state` to `ST_OVER` and draw the banner in the same iteration; the
544
+ overlay is gated on `state` *after* `tick()` returns, so the frame that
545
+ ends the game draws nothing over the banner. The control build with that
546
+ inner `if` removed paints the un-spawnable red Z over the banner on that
547
+ one frame: four of the nine characters (`E OV`) become red cells and stay
548
+ that way, since nothing repaints them, and the piece's upper two cells
549
+ land on four empty cells of field row 0 above them — eight cells differ
550
+ from the correct model, zero from a model with the gate removed. Picture:
551
+ `screenshots/text-overlay-playfield-ungated-control.png`.
552
+ - `full_field_redraw_exceeds_vblank` — measured above: 272 lines against a
553
+ 56-line blank, one lost frame per lock even with the paint at its
554
+ fastest. Call `render_field` per frame and every frame is that frame.
555
+ The technique page's figure of about 18,400 cycles for this size of
556
+ field came from a different program; this listing's 17,100–17,450 is
557
+ the same number by a different instrument.
558
+
559
+ ### Oscar64 details that cost time
560
+
561
+ - The KERNAL's IRQ is live in an Oscar64 program until you stop it. The
562
+ C64 start-up in `crt.c` never executes `sei` (its one `sei` is under
563
+ `OSCAR_TARGET_NES`), so without the `__asm { sei }` at the top of `main`
564
+ the 60 Hz service routine — four to five raster lines each time — lands
565
+ inside anything longer than a frame, and inside a 33-line bracket about
566
+ one time in eight, and a raster-line timer reports it as the cost of
567
+ whatever it interrupted. `__asm { sei }` is the spelling the `sprmux32.c`
568
+ sample uses. A game built on this shell that needs the keyboard reads the
569
+ matrix itself (`<c64/keyboard.h>`, `keyb_poll`) or installs its own
570
+ interrupt; this listing needs neither.
571
+ - `% LINES_PER_FRAME` on an `unsigned` costs about 810 cycles, thirteen
572
+ raster lines (rung 1, CIA 2 timer A): 312 does not fit a byte, so the
573
+ expression goes through the runtime's 16-by-16-bit `divmod` loop. The
574
+ two-digit `show_number` is 522 cycles by the same route on a smaller
575
+ scale, one `divmod` per digit, and the four-digit one 1,209. None of it
576
+ matters once a frame; all of it would in a loop of two hundred.
577
+ - `S"GAME OVER"` gives screen codes 7, 1, 13, 5, 32, 15, 22, 5, 18. The
578
+ lowercase prefix `s"GAME OVER"` does not: it case-flips letters before the
579
+ PETSCII-to-screen-code step, so uppercase ASCII becomes the shifted
580
+ glyphs (`$47, $41, …`, graphics in the default font) and only `s"game
581
+ over"` would give the letters. Capital `S` folds both cases to the
582
+ unshifted letters. That is in the compiler's scanner, and the first build
583
+ of this page printed its labels as graphics glyphs because of it.
584
+ - `vic_waitFrame()` from `<c64/vic.h>` spins on bit 7 of `$D011` twice:
585
+ until RST8 is clear, then until it is set. It returns at the start of
586
+ line 256, which is why the per-frame budget above is counted from there.
587
+ `raster_line()` reads `$D011` and `$D012` itself, once more if RST8
588
+ changed between the two reads; that is why those two registers are in
589
+ the frontmatter, and `$D020`/`$D021` because `main` writes them.
590
+ - `bool`, `true` and `false` are built in; no `<stdbool.h>` is needed or
591
+ included.
592
+ - The `Screen`/`Color` macros and the `Screen[40 * y + x]` idiom are the
593
+ ones the Oscar64 game samples use; they read the same source, not the
594
+ same code.
595
+
596
+ ## Sources
597
+
598
+ - `docs/techniques/text-mode-render.md` (`text_mode_overlay_render`: the
599
+ two-pass design, the erase-prev/draw-current variant, the frame-budget
600
+ trap) and `docs/pitfalls/text-mode-render.md` (the three pitfalls named
601
+ above), this repository.
602
+ - `docs/hardware/vic-ii-reference.md`, this repository, for the 25-row
603
+ display window at raster 51–250 and the RST8 bit.
604
+ - Oscar64 (build 2026-05-19): `include/c64/vic.h` and `vic.c` for
605
+ `vic_waitFrame`, `VIC_CTRL1_RST8` and the `vic` struct; `include/crt.c`
606
+ for what the C64 start-up does and does not do about interrupts;
607
+ `include/c64/cia.h` for the `cia2` struct the probe builds timed with;
608
+ `oscar64.md`, section on PETSCII and string prefixes; `oscar64/Scanner.cpp`,
609
+ the string-literal mode switch, for what `s` and `S` do to letter case;
610
+ `samples/games/snake.c` for the screen/colour macro idiom and
611
+ `samples/sprites/sprmux32.c` for `__asm { sei }`, read not copied.
612
+ - VICE 3.10, `x64sc -help`, for `+autostart-delay-random` and
613
+ `-model ntsc`; the C64 character ROM `chargen-901225-01.bin` shipped
614
+ with it, for the glyph matching; a 16-colour calibration PRG run in the
615
+ same build for the palette.
616
+ - `docs/recipes/oscar64/simple-shmup.md`, this repository, for the recipe
617
+ shape and the `Screen`/`Color` define style.