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,717 @@
1
+ ---
2
+ category: render
3
+ chip: VIC-II
4
+ ---
5
+
6
+ <!-- doc-type: technique-reference -->
7
+
8
+ # Text-Mode Render Techniques
9
+
10
+ Text-mode rendering on the C64 is cheap per byte and not free per frame.
11
+ Writing screen RAM is one STA absolute (4 cycles) per byte, but a redraw
12
+ from a field array needs a load and a store for the screen code and
13
+ again for the colour byte: 16 cycles per cell fully unrolled (a 12 KB
14
+ code footprint for 1000 cells), about 24 cycles per cell in a compact
15
+ indexed loop (both measured in VICE x64sc, CIA timer, DEN off). A 40×25
16
+ redraw with colour is therefore 16,000–24,000 cycles against a PAL frame
17
+ of 19,656 cycles, of which the CPU keeps roughly 18,600 once the 25
18
+ badlines have taken their 40-odd cycles each — most of a frame at best,
19
+ more than a frame in the looped form, and far more from a compiled loop
20
+ (see "Cycle budget"). An earlier version of this page said "a 4-cycle
21
+ operation per cell" and "~4000 cycles — about 1/5 of a PAL frame"; 4
22
+ cycles is one STA of a constant (a screen clear), not a redraw, and
23
+ that figure was below the page's own 1000-cell budget further down.
24
+ Redrawing unconditionally does avoid a class of bugs
25
+ (`dirty_cell_skip_leaves_overlay_trail`) that dirty-cell tracking opens,
26
+ but whether the budget allows it depends on the field size and the
27
+ toolchain — read "The frame-budget trap" before choosing.
28
+
29
+ Most C64 games that look like Tetris, Boulder Dash, Sokoban, or any
30
+ top-down puzzle/board game ship a single tight render loop that walks
31
+ the playfield array each frame (in hand-written assembly, at the costs
32
+ below), then layers the active piece(s) on top as a second pass. The active piece(s) never live in the playfield
33
+ array — they're an overlay drawn last, and the next frame's
34
+ field-redraw is what erases them.
35
+
36
+ ---
37
+
38
+ ## text_mode_overlay_render — Playfield + moving-piece overlay in text mode
39
+
40
+ **Complexity:** low
41
+ **Region:** both
42
+ **Uses registers:** (none)
43
+ **Uses kernal:** (none)
44
+
45
+ ### Why
46
+
47
+ Tetris-likes, Sokoban-likes, Boulder Dash variants, and most C64
48
+ puzzle / board games need to draw a mostly-static playfield with one
49
+ or more *moving* pieces on top of it. The pieces aren't part of the
50
+ playfield's persistent state — they move every gravity tick — so the
51
+ question is how the rendering layer keeps the field cells correct
52
+ while also drawing the piece on top of them. The technique touches no
53
+ VIC or CIA register: it is direct screen and colour RAM writes only.
54
+
55
+ The answer that "feels professional" is to track dirty cells and
56
+ repaint only what changed; the simplest answer that works on a stock
57
+ C64 in text mode is to repaint the whole field every frame and draw the
58
+ piece overlay last — where the budget allows it. In hand assembly a
59
+ 400-screen-cell field is 4,800–9,500 cycles a frame (see "Cycle
60
+ budget"), which fits; from an Oscar64 -O2 loop the same field is
61
+ 17,100–19,400 cycles (recipe, measured in VICE x64sc), which does not
62
+ fit the blank window and tears — see "The frame-budget trap". An
63
+ earlier version of this section said "the frame budget is more than
64
+ ample" without that qualification, while the trap section below said
65
+ the opposite. The dirty-cell approach has a subtle invariant that's
66
+ easy to miss (see `dirty_cell_skip_leaves_overlay_trail` in
67
+ `pitfalls/text-mode-render.md`); the erase-prev/draw-current overlay
68
+ described under the trap avoids both problems.
69
+
70
+ ### How
71
+
72
+ Two passes per frame. The piece overlay never writes back to the
73
+ playfield array — it's pure pixels on top of the field's render:
74
+
75
+ 1. **render_field()** — walk every cell of `field[FIELD_H][FIELD_W]`,
76
+ write its screen code + color to screen / color RAM. Empty cells
77
+ get `$20` (space). Filled cells get `$A0` (reverse-space) in the
78
+ piece's designated color.
79
+ 2. **render_piece()** — walk the 4 cells of the active piece (read
80
+ from a pieces-table indexed by `current_type`, `current_rot`),
81
+ write `$A0` + piece color to screen / color RAM at the piece's
82
+ absolute screen offset.
83
+
84
+ `render_piece` runs second, so its writes win for the cells the piece
85
+ currently occupies. Next frame, `render_field` re-paints every cell
86
+ based on the persistent playfield — which still has those cells as
87
+ empty, so they go back to spaces — and then `render_piece` redraws
88
+ the piece at its new (gravity-advanced) position. The "trail" from
89
+ the previous frame is implicitly cleared by render_field's
90
+ unconditional rewrite.
91
+
92
+ The piece only enters `field[][]` when it locks. From that point the
93
+ field redraw alone keeps it on screen and `render_piece` switches to
94
+ drawing the *next* piece.
95
+
96
+ ### Why it works
97
+
98
+ `render_piece` writes second so its 4 piece cells overwrite the
99
+ empties `render_field` just laid down. Next frame, `render_field`
100
+ re-clears everything from `field[][]` (which doesn't contain the
101
+ moving piece), and `render_piece` re-overlays at the new position.
102
+ The old position is implicitly erased — no per-overlay book-keeping.
103
+
104
+ ### The frame-budget trap
105
+
106
+ The naive "unconditional full redraw every frame" pattern WILL exceed
107
+ the PAL vblank window if you do it on a typical Oscar64 build. Empirical
108
+ numbers from puzzle-tetris-c64-kb (DEMO-DOG-T, 2026-05-18):
109
+
110
+ - 10×20 playfield rendered 2-chars wide = 200 cells × ~92 cycles
111
+ (Oscar64 -O2: indexed-loop overhead, two screen writes, two color
112
+ writes per cell) = **~18,400 cycles**. Measured since at 272 raster
113
+ lines, 17,100–17,450 cycles, about 86 a cell (recipe, CIA-timed in
114
+ VICE x64sc); a naive build reads up to ~19,400. Same order either way.
115
+ - After `vic_waitBottom` returns at raster 256 there are 107 raster
116
+ lines = **~6,700 cycles** (56 lines of lower border and blanking to
117
+ the wrap, then 51 of upper border) before the 25-row display window
118
+ resumes at raster 51. The 56 lines to the wrap alone are ~3,500
119
+ cycles, which is what an earlier version of this page called "the
120
+ vblank window"; the race-free budget is nearly twice that.
121
+ - CPU writes continue while the VIC raster has already started drawing
122
+ the next frame top-down. Upper rows show stale content (the old
123
+ frame's piece position OR an "in-between" state from `render_field`).
124
+ Lower rows show the new piece (CPU caught up before the raster).
125
+
126
+ The visible symptom is "pieces only appear in the last 4-5 rows of
127
+ the playfield, even though the in-memory state has them moving from
128
+ the top." See pitfall `full_field_redraw_exceeds_vblank`.
129
+
130
+ The fix is to NOT call `render_field` every frame. Use the
131
+ "erase-prev + draw-current" overlay pattern instead:
132
+
133
+ 1. Track `prev_x, prev_y, prev_type, prev_rot` (the piece's last-frame
134
+ state).
135
+ 2. Each frame, erase the prev-position cells by repainting them from
136
+ `field[][]` (which now has the locked piece at those cells if the
137
+ piece just locked, so this "erase" pass correctly redraws a
138
+ just-locked piece).
139
+ 3. Draw the current-position cells with `$A0` + piece color.
140
+ 4. Eight cell writes per frame: about **2,000 cycles** as the Oscar64
141
+ recipe measures it (~33 raster lines; `render_piece` 1,998 cycles on
142
+ CIA 2 timer A — see `recipes/oscar64/text-overlay-playfield.md`), or
143
+ roughly 150–200 cycles in hand assembly with precomputed addresses.
144
+ Either way well inside the 107-line window between raster 256 and
145
+ the display window resuming at line 51. An earlier version said
146
+ "~120 cycles", which is 15 a cell against the ~92 this section had
147
+ just priced an Oscar64 cell write at.
148
+
149
+ `render_field` is reserved for events that change persistent state:
150
+ line-clear shift (rare), game-over restart (rare), initial paint. The
151
+ brief tearing on those one-frame events is acceptable.
152
+
153
+ ### Variations
154
+
155
+ - **Two-byte-wide cells.** A 40-column screen with a 10-wide playfield
156
+ often renders each playfield cell as 2 screen columns wide to give
157
+ square-ish character cells. Same loop, but each cell now needs a
158
+ second screen-code store and a second colour store. That is not
159
+ cheap: one extra STA abs,X is 5 cycles on a ~24-cycle indexed cell
160
+ (measured in VICE x64sc: 9,490 → 11,490 cycles over 400 cells,
161
+ +21 %), and with the matching colour store it is 13,490 cycles,
162
+ +42 % indexed; +50 % fully unrolled (16 → 24 cycles per cell).
163
+ Budget for roughly one and a half times the single-width cost, not
164
+ a rounding error. (An earlier version said "under 3 %".) The one
165
+ form that stays cheap is sharing the load: read the field byte once
166
+ and store it to both columns — see "Cycle budget".
167
+ - **Color-only flash for line-clear.** During an animation (e.g.
168
+ Tetris line clear), don't rewrite screen codes — just toggle the color
169
+ RAM byte per cell on/off per N frames. Skip the screen-RAM write
170
+ pass entirely.
171
+ - **Skip render during state transitions.** When the game flips to a
172
+ non-playing state mid-frame (game-over banner drawn, line-flash
173
+ starting), gate the render_field+render_piece pair on the state so the
174
+ banner / flash isn't immediately clobbered.
175
+
176
+ ### Cycle budget
177
+
178
+ All hand-assembly figures below were measured in VICE x64sc (PAL, CIA 1
179
+ timer A, DEN off so no badline steals the count); frame lengths are
180
+ from `hardware/pal-ntsc-reference.md` (PAL 19,656; NTSC 6567R8 17,095;
181
+ 6567R56A 16,768).
182
+
183
+ For a 10×20 playfield rendered as 2-char-wide cells (= 20×20 screen
184
+ cells), per frame, hand assembly:
185
+
186
+ - render_field, fully unrolled and sharing one LDA between the two
187
+ columns of each field cell (LDA field / STA scr / STA scr+1 / LDA
188
+ colr / STA col / STA col+1): 200 field cells × 24 cyc = 4,800 cycles
189
+ (24 % of a PAL frame, 28 % NTSC). That is the only form in which
190
+ "~12 cycles per screen cell" is true; a cell whose code and colour
191
+ are read individually costs at least 16 (LDA abs / STA abs for the
192
+ code and again for the colour) — 400 × 16 = 6,400 (33 % PAL, 37 %
193
+ NTSC).
194
+ - The compact indexed loop (LDA field,x / STA screen,x / LDA colr,x /
195
+ STA colour,x / INX / BNE): 23.7 cycles per cell, 9,490 for 400 cells
196
+ (48 % PAL, 56 % NTSC).
197
+ - Oscar64 -O2 in C: about 86–97 cycles per two-wide field cell,
198
+ 17,100–19,400 for 200 cells (recipe; measured in VICE x64sc) — see
199
+ "The frame-budget trap" above.
200
+ - render_piece: 8 screen cells × 16 cyc = ~128 cycles unrolled, ~190
201
+ looped, ~2,000 in Oscar64 (negligible against the field either way).
202
+ - Total, hand assembly: ~4,900 cycles shared-unrolled (25 % PAL, 29 %
203
+ NTSC R8), ~6,500 unrolled (33 % / 38 %), ~9,700 looped (49 % / 57 %).
204
+ An earlier version said "< 27 % of an NTSC frame" for 4,896 cycles;
205
+ 4,896 / 17,095 is 28.6 %.
206
+
207
+ For a full-screen 40×25 redraw (Boulder Dash-style map, every cell
208
+ distinct, so no shared load):
209
+
210
+ - 1000 cells × 16 cyc = 16,000 cycles fully unrolled (81 % of a PAL
211
+ frame, 94 % of an NTSC R8 frame, and ~12 KB of code); the indexed
212
+ loop is ~23,700 cycles — more than a PAL frame (19,656).
213
+
214
+ That's the point at which dirty-cell tracking or a partial redraw pays
215
+ off: a looped 1000-cell screen+colour redraw does not fit in one frame.
216
+ An earlier version of this section said ~12 cycles per cell, 12,000
217
+ cycles for 1000 cells, and that "even a 1000-cell redraw fits inside a
218
+ single frame"; 12 is below the 16-cycle unrolled floor for a cell whose
219
+ code and colour are read individually, and holds only for the
220
+ two-column-shared unrolled form (4,800 for 200 field cells, measured as
221
+ above). Fitting inside a frame is not the criterion in any case: unless
222
+ screen RAM is double-buffered via `$D018`, the redraw races the beam,
223
+ so the budget is the blank window — 107 lines from raster 256 through
224
+ the wrap to raster 51, about 6,700 cycles — not the whole frame.
225
+
226
+ ### Recipes
227
+
228
+ - `recipes/oscar64/text-overlay-playfield.md`
229
+
230
+ ---
231
+
232
+ ## charset_animation — Animating tiles by changing the glyph, not the cells
233
+
234
+ **Complexity:** low
235
+ **Region:** both
236
+ **Uses registers:** D018
237
+ **Uses kernal:** (none)
238
+ **Cost:** cycles_per_frame=196
239
+ **Cost basis:** measured-vice
240
+ **Cost measured on:** oscar64-charset-animation (one glyph a frame, in the vertical blank)
241
+
242
+ ### Why
243
+
244
+ Water, fire, lava, conveyor belts and blinking lights are the same tile
245
+ repeated across a field. Redrawing every cell that shows the tile each
246
+ frame costs cycles in proportion to the field: 12 cycles a cell from an
247
+ Oscar64 `-O2` store loop, 2,429 for 200 cells (recipe, CIA-timed in VICE
248
+ x64sc), so 240 water cells would be about 2,880 and a full screen of
249
+ them more than a blank window. The VIC has no copy of a glyph. It fetches
250
+ the 8 bytes for each cell's code from the character base on every raster
251
+ line it draws, so changing those 8 bytes changes every cell that shows
252
+ the code at once, whatever the field holds. That is the whole technique,
253
+ in two forms.
254
+
255
+ ### How
256
+
257
+ **(a) Rewrite the glyph in place.** Keep an animation table of N phases,
258
+ 8 bytes each, and once per frame copy phase `frame mod N` over the
259
+ glyph's 8 bytes in the charset the VIC is showing. Every cell with that
260
+ code animates. The cost is one 8-byte copy per animated glyph per frame,
261
+ independent of how many cells show it: 196 cycles in Oscar64 with the
262
+ call and pointer set-up inside the timed window, of which the eight
263
+ `LDA (zp),Y / STA (zp),Y` pairs with their index loads are 120
264
+ (recipe); 64 cycles in hand assembly as eight `LDA abs,Y / STA abs`
265
+ pairs (arithmetic, not measured here). An eight-phase table is 64 bytes.
266
+
267
+ **(b) Flip whole charsets.** Prepare two or more 2 KB charsets in the VIC
268
+ bank that differ in the animated glyphs, and once per frame write the
269
+ one to show into `$D018` bits 1 to 3. One 4-cycle store (the recipe's
270
+ harness reads 14 with its index load and its own stop store) moves the
271
+ glyph source for the whole screen. The cost is the same whether one cell
272
+ or a thousand shows the animated code, and the same however many glyphs
273
+ differ between the sets: a fire glyph, a water glyph and a belt glyph
274
+ can all step at once for the same store. The price is memory, 2 KB a
275
+ phase, and the bank: all the sets, the screen and any sprites must sit
276
+ in the one 16 KB VIC bank, and a compiler will not stop code growing
277
+ into a hardcoded set address (`charset_blit_overruns_grown_code`).
278
+
279
+ ### Why it works
280
+
281
+ `$D018` bits 1 to 3 give the character base in 2 KB steps inside the VIC
282
+ bank, and the character generator reads glyph row `line & 7` of each
283
+ code at `base + code * 8` as it draws. Both forms change what that read
284
+ returns. (a) changes the bytes at the address; (b) changes the address.
285
+ The difference is atomicity. A `$D018` store is one write and the VIC
286
+ reads the register at each fetch, so there is no half state: rows above
287
+ the store show the old set, rows below it the new one, and if the store
288
+ is made below the display nobody sees the seam. An 8-byte rewrite is
289
+ eight writes. If a fetch of that glyph falls between them, the rows
290
+ above show the old glyph, the rows below the new one, and the text row
291
+ the beam is in can show old and new pixel rows of the same glyph. Do the
292
+ rewrite after the last display line and before the first badline: from
293
+ line 256 that is 107 lines on PAL and 58 on the 6567R8 (arithmetic from
294
+ the settled frame lengths). The recipe rewrites first thing after
295
+ `vic_waitFrame()`, 196 cycles, inside four raster lines of line 256
296
+ (arithmetic at 63 cycles a line).
297
+
298
+ Reading `$D018` back gives bit 0 as 1 whatever was written; mask it
299
+ before comparing (measured: the monitor shows `1D` for a stored `1C`).
300
+
301
+ ### Variations
302
+
303
+ - **Animate a subset of rows.** The glyph is global, so cells that must
304
+ not animate need a different code with a static copy of the glyph. A
305
+ raster split that writes `$D018` mid-frame gives the rows below it a
306
+ different set; it needs a stable raster IRQ and the store must land in
307
+ the horizontal blank or the seam line shows both sets.
308
+ - **Double-buffered charsets.** Combine the two forms: rewrite glyphs
309
+ into the set that is not being shown, anywhere in the frame, and flip
310
+ `$D018` to it in the blank. The rewrite can then be spread across the
311
+ frame and the flip is atomic. The recipe's in-place band does the
312
+ single-buffered version, writing only the set about to be shown.
313
+ - **Colour RAM alongside.** The glyph carries shape, colour RAM carries
314
+ the cell's colour; cycling colour RAM under an animated glyph gives a
315
+ second axis (a fire glyph stepping through yellow, orange, red) at one
316
+ store per cell, which is the redraw cost again. Use it on few cells.
317
+ - **More phases in (a) than (b).** An eight-phase table costs 64 bytes;
318
+ eight charsets cost 16 KB, the whole bank. Long animations go in (a),
319
+ many simultaneous glyphs in (b).
320
+
321
+ ### Cycle budget
322
+
323
+ Per frame, in the blank: 196 cycles for one in-place glyph and 14 for a
324
+ flip as the recipe's harness reads them, 3,368 for the recipe's whole
325
+ loop including its 200-cell redraw comparison and the self-check, all
326
+ measured in VICE x64sc on both models with identical figures because
327
+ nothing runs across a badline. Against the 107-line PAL blank (about
328
+ 6,700 cycles) an in-place glyph is 3 %; the 58-line NTSC blank (about
329
+ 3,770) holds nineteen of them. The Cost line above is the in-place
330
+ form, 196 cycles; its 64-byte table is stated here and not on the line,
331
+ so that the line keeps the basis of its measured figure. The flip form's
332
+ per-frame cost is under 20 cycles and its data cost is 2,048 bytes a
333
+ set, which the line does not carry because the set count is the
334
+ design's.
335
+
336
+ ### Recipes
337
+
338
+ - `recipes/oscar64/charset-animation.md`
339
+
340
+ ---
341
+
342
+ ## char_bullets — Bullets drawn as characters, merged into reserved glyphs
343
+
344
+ **Complexity:** medium
345
+ **Region:** both
346
+ **Uses registers:** D018
347
+ **Uses kernal:** (none)
348
+ **Cost:** cycles_per_frame=3995
349
+ **Cost basis:** measured-vice
350
+ **Cost measured on:** oscar64-char-bullets (eight bullets, worst frame)
351
+
352
+ ### Why
353
+
354
+ A shoot-'em-up or run-and-gun runs out of sprites for bullets first.
355
+ Eight hardware sprites go to the player and the enemies, and a
356
+ multiplexer is a poor fit for dozens of objects a few pixels across
357
+ that share raster lines. A bullet drawn into the character screen costs
358
+ no sprite at all. The naive form, writing a bullet glyph into the cell,
359
+ wipes out the background under it. The form here keeps the background
360
+ visible and puts the bullet at pixel precision inside the cell.
361
+
362
+ ### How
363
+
364
+ Reserve a few screen codes in a RAM charset, one per bullet: eight
365
+ codes, $F8 to $FF, in the recipe. Keep a table per bullet of its pixel
366
+ position, the screen code and colour it saved, and the cell it was
367
+ drawn in. Each frame:
368
+
369
+ 1. **Restore, in reverse draw order.** Write each bullet's saved code
370
+ and colour back to its cell, last-drawn bullet first.
371
+ 2. **Move** the bullets.
372
+ 3. **Draw, in forward order.** For each bullet, find its cell from the
373
+ position (`x >> 3`, `y >> 3` through a row-address table). Save the
374
+ code and colour there. Copy the saved code's 8 glyph bytes into the
375
+ bullet's reserved glyph, then OR the bullet's pixels into it at row
376
+ `y & 7`, shifted by `x & 7`. Write the reserved code into the cell,
377
+ and a colour if the bullet has one.
378
+
379
+ **Shared cells.** When bullet B lands in bullet A's cell, it saves A's
380
+ reserved code and builds its glyph from A's merged glyph, so both show.
381
+ Restoring B before A puts A's code back and then the background. That is
382
+ why restore runs in reverse. Forward order leaves A's reserved code on
383
+ screen for good (measured in the recipe: the compare fails).
384
+
385
+ **Pixel positioning.** The bullet's bits are shifted within the glyph by
386
+ `x & 7` and placed on row `y & 7`. A bullet that stays inside one cell
387
+ needs one reserved glyph. The recipe keeps both coordinates even and the
388
+ bullet 2 by 2, so it never crosses an edge. A bullet that can straddle a
389
+ cell edge needs two cells (four at a corner) and as many reserved glyphs.
390
+
391
+ **Collision with the background.** The saved code says what the bullet
392
+ is over. Look its class up in a 256-byte table (solid, destructible,
393
+ empty). If the saved code is itself a reserved code, the bullet is over
394
+ another bullet: follow that bullet's saved code until it is below the
395
+ reserved range. Bullets drawn earlier in the same frame have current
396
+ saved codes, so the walk ends. A reserved code left on screen by a
397
+ wrong restore can make a bullet save its own code, and the walk then
398
+ never ends (measured: the recipe's forward-order variant hung).
399
+
400
+ **Colour RAM.** A hires cell has one foreground colour, so a bullet
401
+ coloured differently from its cell also recolours the background pixels
402
+ in that cell. Either leave colour RAM alone (the bullet takes the
403
+ cell's colour, cost 0) or save and restore it with the code, as the
404
+ recipe does. Colour RAM is 4 bits wide and its upper nibble reads back
405
+ as bus noise; mask it with `$0F` before comparing a saved value.
406
+
407
+ **What the reserved count limits.** Each bullet on screen needs its own
408
+ reserved glyph, so the reserved count is the bullet limit, and every
409
+ reserved code is lost to the background art. The codebase64 merge page reserves
410
+ eight, $F8 to $FF (not measured here). A bullet that straddles cells needs more than one.
411
+
412
+ ### Why it works
413
+
414
+ The VIC reads each cell's glyph from the charset on every raster line
415
+ it draws. A reserved glyph that is a copy of the background glyph plus
416
+ bullet bits therefore shows the background cell with the bullet on it.
417
+ The background glyph itself is never written, so every other cell with
418
+ the same code is untouched. Restoring is one code store and one colour
419
+ store per bullet.
420
+
421
+ The reserved glyphs are rewritten while their codes are off screen: the
422
+ restore runs first, and each glyph is built before its code goes into a
423
+ cell. So a glyph cannot tear the way an in-place glyph rewrite can
424
+ (compare `charset_animation`). What can still show is the gap between
425
+ restore and draw. If the beam passes a bullet's row in that gap, the
426
+ bullet is missing for that frame. Run restore and draw in the lower
427
+ border, or at least before the beam reaches the first row bullets can
428
+ occupy (`full_field_redraw_exceeds_vblank`). In the recipe the draw ends
429
+ on line 108 (PAL) or 156 (NTSC), and the arena starts on line 171.
430
+
431
+ ### Variations
432
+
433
+ - **Masked bullets.** AND the glyph with an inverted mask before the OR,
434
+ so a bullet with a dark outline shows on a busy background. That is
435
+ the form the codebase64 "merge char bullets" page describes. It costs
436
+ one more operation per glyph row touched.
437
+ - **Whole-cell bullets.** Save the code under the bullet, write one fixed
438
+ bullet code, restore on move: no glyph build, no pixel positioning,
439
+ and the background in that cell disappears. Escape From New York uses
440
+ this form, with 16 bullets moving 8 pixels a frame (Cadaver's source
441
+ dissection, not measured here).
442
+ - **Hand assembly.** The recipe is Oscar64 C. Hand-written 6502 with an
443
+ unrolled glyph copy should draw a bullet in fewer cycles than the
444
+ recipe's 407; not measured here.
445
+
446
+ ### Cycle budget
447
+
448
+ Measured in VICE x64sc on both models with the recipe's CIA timers
449
+ (Oscar64 `-O2`): 641 cycles to restore eight bullets, 80 a bullet;
450
+ 3,258 to 3,354 to draw eight, 407 to 419 a bullet. The Cost line is the
451
+ worst frame seen over about 240 frames on each model, 3,354 + 641 =
452
+ 3,995 cycles, about a fifth of a PAL frame. The draw varies with shared
453
+ cells (one more chain step) and wall hits. The recipe's full-arena
454
+ compare, 5,873 cycles on PAL and 6,131 on NTSC, is its self-check and
455
+ not part of the technique.
456
+
457
+ ### Recipes
458
+
459
+ - `recipes/oscar64/char-bullets.md`
460
+
461
+ ### Sources
462
+
463
+ - codebase64, "Character bullets": https://codebase.c64.org/doku.php?id=base:character_bullets
464
+ - codebase64, "Merge char bullets": https://codebase.c64.org/doku.php?id=base:merge_char_bullets
465
+ - Cadaver, Escape From New York source dissection: https://cadaver.github.io/rants/dissect.html
466
+
467
+ ---
468
+
469
+ ## destructible_char_terrain — Destructible terrain in characters: private glyphs from a pool, pixel edits and pixel probes
470
+
471
+ **Complexity:** high
472
+ **Region:** both
473
+ **Uses registers:** D018
474
+ **Uses kernal:** (none)
475
+ **Cost:** cycles_per_frame=1450
476
+ **Cost basis:** measured-vice
477
+ **Cost measured on:** oscar64-destructible-terrain (one dig step, three pixel edits)
478
+
479
+ ### Why
480
+
481
+ A game where creatures dig tunnels and build bridges through the
482
+ landscape needs terrain that changes one pixel at a time. A bitmap does
483
+ that directly but costs 8 KB. Characters cost
484
+ 1 KB of screen and 2 KB of charset, and most of a landscape is a few
485
+ repeated textures. The catch is that a glyph is shared: editing the
486
+ earth glyph to dig one hole digs it in every earth cell on screen. The
487
+ form here gives each edited cell its own copy.
488
+
489
+ ### How
490
+
491
+ Draw the level with a few **shared glyphs** (the recipe has three:
492
+ empty, earth, and a 2-pixel step) and set aside a block of codes as a
493
+ **pool of private glyphs** ($80 to $FF, 128 codes, in the recipe), kept
494
+ as a stack of free codes.
495
+
496
+ **Editing a pixel.** Find the cell (`x >> 2`, `y >> 3` in multicolour;
497
+ `x >> 3` in hires) and its screen code.
498
+
499
+ 1. If the pixel already has the wanted value, stop. This keeps a dig
500
+ through empty air from allocating anything.
501
+ 2. If the code is shared, pop a free code, copy the shared glyph's 8
502
+ bytes into it and write the new code into the cell. If the pool is
503
+ empty, refuse the edit and count it.
504
+ 3. Change the pixel in the private glyph: clear its pair to dig, set it
505
+ to build.
506
+ 4. Compare the private glyph with each shared glyph. On a match, write
507
+ the shared code back into the cell and push the private code on the
508
+ free stack.
509
+
510
+ One cell owns each private glyph, so step 4 needs no reference count: a
511
+ cell dug out completely becomes the empty glyph again and its code goes
512
+ back (the recipe's two side-by-side diggers free two cells this way).
513
+
514
+ **Probing a pixel.** Cell from the coordinates, screen code from the
515
+ cell, glyph byte at row `y & 7`, then a mask for the pixel (`x & 3` in
516
+ multicolour, `x & 7` in hires). A non-zero result is terrain. The probe
517
+ reads what the VIC shows, so collision and picture cannot disagree.
518
+ Anything drawn into the glyphs that is not terrain, such as creatures
519
+ merged in the `char_bullets` way, must be restored before probes run.
520
+
521
+ **Pool exhaustion.** Choose a policy and state it. The recipe refuses:
522
+ the pixel stays as it was and a counter goes up. Its digger still steps
523
+ down, into earth it could not remove; a game should end the dig
524
+ instead. The other policy merges: before taking a new
525
+ code, look for a private glyph with the same 8 bytes and share it, which
526
+ needs a reference count per code and a search or hash (not built here).
527
+ Refusing is simpler and cannot corrupt anything; merging helps where
528
+ many edits make identical cells, such as a flat bridge.
529
+
530
+ **The code budget.** A charset has 256 codes. The recipe spends 64 on
531
+ HUD letters and digits, 3 on shared terrain, 48 on creatures (two per
532
+ creature for 24) and 128 on the pool; 13 are unused. So a level with
533
+ this HUD, these creatures and three shared glyphs can afford at most
534
+ 141 private glyphs at once (arithmetic). A private glyph is needed for
535
+ each cell whose pixels match no shared glyph. In the recipe a shaft
536
+ through a 16-pixel platform, dug by two creatures side by side, and a
537
+ twelve-brick staircase used at most 7 at once;
538
+ 24 simultaneous dig steps on untouched floor took 36. More shared
539
+ textures cost codes but do not change this: every edited cell that is
540
+ not back to a shared glyph costs one code.
541
+
542
+ ### Why it works
543
+
544
+ The VIC-II reads each cell's glyph from the charset on every raster
545
+ line it draws, so a changed byte in a private glyph shows the next time
546
+ the beam draws that row of the cell. Shared glyphs are never written, so the cells
547
+ that still use them are untouched. A cell's screen code is the only
548
+ link between the cell and its private glyph, which is why freeing only
549
+ needs the cell's code rewritten.
550
+
551
+ An edit changes a glyph that is on screen. If the beam is inside that
552
+ cell's rows at that moment, one frame shows the old and new byte on
553
+ different lines. A dig or brick step changes one row of one or two
554
+ cells, so at most that row of a cell is late by a frame. The in-place
555
+ rewrite in `charset_animation` has the same effect over whole glyphs.
556
+
557
+ ### Variations
558
+
559
+ - **Hires.** 8 pixels a byte, one colour a cell from colour RAM. The
560
+ probe mask comes from `x & 7`. Pixels are twice as fine and the cells
561
+ hold one colour, so terrain texture has to come from the pattern.
562
+ - **Different textures.** Every shared texture is one more code and one
563
+ more comparison in step 4. A private glyph only returns to the pool
564
+ when it equals one of them exactly.
565
+ - **Two charsets.** A raster interrupt that changes `$D018` part way
566
+ down the screen gives the lower part its own 256 codes. Not built
567
+ here.
568
+
569
+ ### Cycle budget
570
+
571
+ Measured in VICE x64sc 3.10 with the recipe's CIA timers (Oscar64
572
+ `-O2`). A probe costs 52 cycles: 160 probes along one pixel row take
573
+ 10,912 cycles and the same loop without the probe 2,580, with the
574
+ display off. The Cost line is one dig step's terrain work, the
575
+ technique called once: 3 pixel edits on untouched floor. The dearest
576
+ of 24 such steps took 1,450 cycles on both models, timer calls
577
+ included; half the steps span two cells and allocate twice.
578
+
579
+ A frame's terrain cost is edits times about 452. The 72 edits of 24 dig
580
+ steps at once, 36 of which allocate, took 32,037 cycles on PAL and
581
+ 32,555 on NTSC, about 452 an edit and 1,356 a dig step. That is more
582
+ than a PAL frame (19,656 cycles) and nearly two NTSC frames (17,095).
583
+ A typical frame of the recipe edits nothing or one or two cells.
584
+ Hand-written assembly with a table of glyph addresses would be cheaper;
585
+ not measured here.
586
+
587
+ ### Recipes
588
+
589
+ - `recipes/oscar64/destructible-terrain.md` — a 40 by 16 cell multicolour level; 24 creatures dig, build and block; terrain glyph bytes and creature states checked against a Python model after 360 ticks; worst frames timed on both models
590
+
591
+ ---
592
+
593
+ ## isometric_tile_engine — Diamond-grid projection, draw order and sprite depth for isometric rooms
594
+
595
+ **Complexity:** high
596
+ **Region:** both
597
+ **Uses registers:** D018, D01B, D015, D000, D001, D010, DC04, DC05, DC0E
598
+ **Uses kernal:** (none)
599
+ **Cost:** cycles_per_frame=42034
600
+ **Cost basis:** measured-vice
601
+ **Cost measured on:** kickassembler-isometric-room (the frame that redraws the whole 8 by 8 room, which is the worst frame; a frame that only moves the player is far cheaper, and one block draw is 527 cycles, see Cycle budget)
602
+ **Requires:** tile_map_render
603
+
604
+ ### Why
605
+
606
+ A top-down puzzle or action game that wants depth cues without a bitmap mode
607
+ uses an isometric projection: tiles are drawn as 2:1 diamonds, blocks as cubes,
608
+ and the painter's diagonal sort hides the z-buffer. The VIC-II hardware sprite
609
+ depth register (`$D01B`) gives the player figure a single behind-or-in-front
610
+ state relative to the entire playfield, which is enough for most rooms.
611
+
612
+ ### How
613
+
614
+ **Layout.** One VIC bank holds the screen at `$0400`, a 2 KB custom charset at
615
+ `$3000`, and the sprite data. `$D018 = $1C` selects them. The map is a flat
616
+ byte array: 0 = floor, 1 = block (one tile tall), 2 = tall block (two tiles).
617
+
618
+ **Tiles.** Three shapes, all 4 character columns wide:
619
+
620
+ - Floor diamond: 2 rows tall. Eight chars (top-face row 0, top-face row 1).
621
+ - Block: 4 rows tall. Top face (2 rows, same chars as floor) above two rows of
622
+ solid side-face chars.
623
+ - Tall block: 6 rows tall. Top face (2 rows) above four rows of side-face chars.
624
+
625
+ The custom charset holds 13 glyphs: one blank, four for the top-face top row,
626
+ four for the top-face bottom row, and four for the side face. Colour RAM sets
627
+ the foreground colour of each tile type.
628
+
629
+ **Projection.** For map cell (x, y):
630
+
631
+ ```
632
+ char_col = ORIG_COL + 2 * (x - y)
633
+ char_row = ORIG_ROW + (x + y)
634
+ ```
635
+
636
+ With `ORIG_COL = 18` and `ORIG_ROW = 4` an 8-by-8 map lands in screen columns
637
+ 4 to 35 and rows 4 to 19, fitting the 40-by-25 display without overflow
638
+ (arithmetic from the extreme cells (0,7) and (7,0)).
639
+
640
+ **Painter's order.** Iterate diagonal `s = x + y` from 0 to 14. For each
641
+ diagonal, iterate x from `max(0, s-7)` to `min(7, s)` with `y = s - x`. Draw
642
+ that cell last-wins: a cell at a higher diagonal (closer to the viewer) is
643
+ drawn after any cell at a lower diagonal whose character region overlaps it.
644
+ Clear the screen rows to space before drawing so removed tiles do not leave
645
+ stale characters.
646
+
647
+ **Sprite depth scan.** After each player move, scan all 64 cells. For each cell
648
+ with `bx + by > px + py` (in front of the player), check whether its character
649
+ box overlaps the sprite's character box:
650
+
651
+ - Sprite box: cols `[player_col+2, player_col+4]`, rows `[player_row-1, player_row+1]`.
652
+ Formula: `sprite_x = 24 + 8*(player_col + 2)`, `sprite_y = 45 + 8*player_row`.
653
+ - Block box: cols `[block_col, block_col+3]`, rows `[block_row-2, block_row+1]`.
654
+ - Tall block box: cols `[block_col, block_col+3]`, rows `[block_row-4, block_row+1]`.
655
+
656
+ If any in-front cell is a block and its box overlaps the sprite box, set
657
+ `$D01B` bit 0 (sprite behind the playfield); otherwise clear bit 0.
658
+
659
+ **Timing.** Wrap a draw with CIA 1 timer A in one-shot mode from `$FFFF`
660
+ (`$DC0E = $19`). Stop with `$08`. Elapsed = `$FFFF` minus the timer value,
661
+ computed as `$FF - low_byte` and `$FF - high_byte`.
662
+
663
+ ### Why it works
664
+
665
+ The VIC-II reads character codes from screen RAM and fetches glyph bytes from
666
+ the charset on every raster line it draws. Writing a code to a screen cell
667
+ instantly changes what that cell shows on the next raster fetch. Painter's
668
+ order means the last write wins without a z-buffer. `$D01B` bit 0 swaps sprite
669
+ priority for sprite 0 between two modes without any extra CPU cycle cost per
670
+ frame: one OR or AND to one register.
671
+
672
+ ### Cycle budget
673
+
674
+ Measured in VICE x64sc 3.10 (PAL, CIA 1 timer A, one-shot from `$FFFF`):
675
+
676
+ - Full 8-by-8 room redraw (64 cells, mix of floors and blocks): 42,034 cycles --
677
+ about 2.1 PAL frames (19,656 cycles each). A full-screen 40-by-25 hires
678
+ redraw (1,000 cells) is comparably large; see the cycle budget under
679
+ `text_mode_overlay_render`.
680
+ - One block draw (four rows of four chars, 16 screen writes + 16 colour writes
681
+ via four `setup_row` calls): 527 cycles, under 3 % of a PAL frame.
682
+
683
+ The 42,034-cycle redraw budget is for a room redrawn on state changes only
684
+ (start and after the final player move). A per-frame redraw would need either
685
+ a smaller map or a dirty-cell approach -- see `full_field_redraw_exceeds_vblank`.
686
+
687
+ ### Variations
688
+
689
+ **Depth bit limitation.** `$D01B` has one bit per sprite. Setting it places the
690
+ sprite behind every playfield character, not just the block in front of it. A
691
+ player standing between a nearer block and a farther block will appear behind
692
+ the farther block too, which is incorrect. The fix is either a software sprite
693
+ (redraw the figure into the charset each move, eliminating `$D01B` entirely) or
694
+ a per-raster split that sets `$D01B` only for the rows the front block occupies.
695
+
696
+ **Scrolling camera.** Replace the fixed origin with a scrollable viewport and
697
+ double-buffer the screen with `$D018` to avoid mid-draw tearing. The `tile_map_render`
698
+ technique documents the double-buffer flip; the painter loop becomes a partial
699
+ redraw of the visible window.
700
+
701
+ **More tile shapes.** The three shapes here share the same 13 glyphs. An
702
+ animated water tile needs one more code per animation phase; a sloped ramp
703
+ tile needs its own top-face glyph set. Each distinct shape adds at most eight
704
+ bytes to the charset.
705
+
706
+ ### Pitfalls
707
+
708
+ - `dirty_cell_skip_leaves_overlay_trail` -- the room clear-and-redraw avoids
709
+ this, but a dirty-cell optimisation would reintroduce it.
710
+ - `full_field_redraw_exceeds_vblank` -- a 64-cell isometric room costs 42,034
711
+ cycles per redraw, well over the ~6,700-cycle PAL blank window. Redraw on
712
+ state changes only.
713
+
714
+ ### Sources
715
+
716
+ - `recipes/kickassembler/isometric-room.md` -- 8-by-8 room, scripted player,
717
+ two timed redraws, verdict byte, depth scan; measured in VICE x64sc 3.10