Unofficial technical notes and a browser experiment around the MSX cartridge ROM of The Castle.
The project extracts the original ROM data, documents the game systems, converts the assets into readable formats, and explores how much of the game can be rebuilt as straightforward JavaScript from decoded data. A separate ROM execution harness is kept only as a reference for behavior comparison.
- 32 KiB MSX ROM mapped and documented.
- Full-address Z80 disassembly with 32 KiB byte-exact reassembly, curated symbols, routines, xrefs, and call graph.
- 464 SCREEN 2 tiles extracted.
- 64 16x16 sprite groups, their 64-byte color table, and 14 layered player frames extracted losslessly.
- All 100 rooms decoded into 30x20 logical grids with exact fresh-state primary/secondary collision planes and command-
0x06lock links. - Room graphics reconstructed through the ROM's dynamic VRAM tile-loading routines; all 100 backgrounds match original execution pixel-for-pixel.
- A lossless SCREEN 2 atlas covers all 479 reachable
(logical_code, variant)pairs: 224 final-room pairs plus 255 construction/runtime/scene-only variants, each with byte-level provenance. - A deterministic openMSX oracle captures RAM, VRAM, registers, sprites, and all 100 fresh-state rooms.
- Every one of the 1,159 generated room records and all 120,000 collision bytes are checked against captured original RAM with zero mismatches.
- Tiled
.worldand.tmjexports generated for inspection. - Complete
0x20..0x3Bobject catalog plus terrain-mechanism, lock-macro, collision, and movement catalogs generated. - Four Japanese message scripts decoded to positioned Unicode operations and editorial English translations.
- Seven title-credit strings, the exact three-pass title scheduler/wipe/abort choreography, title/captive/final-scene paths and effects, both scene player-motion programs, and all 128 active scripted-demo input records extracted as reversible contracts.
- The exact nine-entry pickup score/popup table, packed-BCD score/high-score rules, HUD crop, and raw source ranges are exported as modern assets.
- The 100-bit castle-map renderer and game-over presentation are portable contracts, including ordered VRAM/name writes, overlay precedence, sprites, text selectors, and exact delay-call counts.
- Five PSG scores and three procedural effects exported as events, VGM, WAV, MIDI, and raw bytes.
- Exact player predictor/commit contract with 34 branch vectors, seven more lock-opening/consumption vectors, probe order, parities, exits, and a 10-state sprite matrix, plus branch-level specifications and reference vectors for every dynamic object and terrain mechanism.
- Pickup, packed-BCD score, death, room-transition, input/pacing, popup, and power-up timer contracts include 67 additional executable reference vectors.
- Seven program-flow, four room-entry/audio-lifecycle, and five interrupt-arbitration vectors preserve title/session dispatch, scene-versus-life priority, the input gate, mute freeze, effect priority, and divider phase across rebuilds.
- Reset, F3 load, cassette parser, save transaction/failure, and ending-save branches exported as an executable persistence contract.
- Seven deterministic frame traces cover boot/demo/start, the no-input room-entry gate, walking, two jump forms, F1 rollback, and F2 game over.
- Three additional byte-exact dynamic traces cover the
0x34/0x1Bcoupling, room-91 elevators/high objects, and a complete 72-tick conveyor/barrier cycle; two independent capture trees match exactly. - A recapturable openMSX timing oracle pins the hashed NTSC C-BIOS baseline: 59,736 Z80 cycles/frame (59.922743404 Hz), exact neutral
0x50E8/0x5128costs, all three CTRL/GRAPH pacing modes, and four complete live room-70 loop intervals. - A consolidated remake data bundle is available at
assets/remake/remake_bundle.json. - A browser gameplay prototype lives at
/. - A separate original-ROM reference harness lives at
/remake/reference.html.
The browser prototype is an inspection aid, not yet the faithful remake. It still uses simplified movement, persistence, and object behavior. The reverse-engineered data/specification is substantially more complete than that prototype: the static background reconstruction now matches the openMSX oracle in all 100 rooms, with zero differing pixels, while the browser deliberately displays the oracle images until its runtime logic is ported from the generated state-machine contract.
The natural gameplay traces and timing oracle pin the C-BIOS_MSX1_JP NTSC
baseline at 59,736 Z80 cycles per VDP period (59.922743404 Hz, only nominally
60 Hz). The controlled object traces deliberately call
selected routines directly and therefore prove state transitions, not every
wall-clock timing path. Scene exports are reconstruction contracts and lossless
ingredients; captive/map/ending frame sequences are not presented as
independently captured finished cinematics, and Japanese BIOS glyph bitmaps
remain an external dependency.
Requirements:
- Node.js 20+
- pnpm
- Python 3
- the tools listed in
docs/toolchain.md
Install dependencies:
pnpm install
python3 -m venv .venv
.venv/bin/pip install -r requirements-dev.txtStart the development server:
pnpm devOpen the printed Vite URL. The playable browser experiment is served at:
//remake/reference.htmlfor the original-ROM reference harness.
Build the browser app:
pnpm build- Arrow keys or WASD: move.
- The reference harness also accepts Space, Enter, Z, and X as MSX trigger/key input.
Run the full reverse-engineering pipeline:
.venv/bin/python tools/build_all.pyManual stages:
.venv/bin/python tools/build_disassembly.py rom.MX1 -o analysis/disassembly --docs docs/disassembly.md
.venv/bin/python tools/build_gameplay_state_machines.py
.venv/bin/python tools/build_persistence_contract.py
.venv/bin/python tools/build_timing_oracle.py
.venv/bin/python tools/extract_assets.py rom.MX1 -o assets
.venv/bin/python tools/extract_scenes.py --rom rom.MX1 -o assets/scenes
.venv/bin/python tools/extract_audio.py rom.MX1 -o assets/audio --asset-manifest assets/manifest.json
.venv/bin/python tools/extract_ui.py
.venv/bin/python tools/decode_maps.py rom.MX1 -o assets/maps/decoded
.venv/bin/python tools/render_room_vram.py rom.MX1 -o assets/maps/vram_reconstruction --scale 2
.venv/bin/python tools/extract_logical_tile_atlas.py
.venv/bin/python tools/export_tiled_maps.py rom.MX1 -d assets/maps/decoded/decoded_rooms.json -o assets/maps/tiled
.venv/bin/python tools/build_object_catalog.py -d assets/maps/decoded/decoded_rooms.json -o assets/objects --docs docs/object_catalog.md
.venv/bin/python tools/build_collision_catalog.py rom.MX1 -d assets/maps/decoded/decoded_rooms.json -o assets/collision --docs docs/collision_and_movement.md
.venv/bin/python tools/build_remake_bundle.py -o assets/remake --docs docs/remake_data_bundle.md
.venv/bin/python tools/validate_decoded_runtime.py --require-all-rooms
.venv/bin/python tools/validate_openmsx_oracle.py --require-all-rooms
.venv/bin/python tools/validate_gameplay_traces.py
.venv/bin/python tools/validate_dynamic_traces.py
.venv/bin/python tools/check_toolchain.py --requirerom.MX1: source MSX cartridge ROM used by the extraction tools.index.html: browser experiment entry point.remake/: browser runtime source and reference harness.remake/src/gameState.js: readable game state, movement, transitions, pickups, score, lives, and inventory.remake/src/modernRenderer.js: canvas renderer using reconstructed room art.remake/src/msxMachine.js: Z80/MSX reference harness, not the main remake.analysis/disassembly/: round-trippable Z80 assembly, symbols, routine/xref indexes, ROM layout, and call graph.analysis/gameplay_state_machines.json: machine-readable player/core-gameplay contracts and branch-level dynamic-object/terrain specifications with executable helpers and vectors.analysis/persistence_contract.json: executable reset/load/save transaction and cassette-format contract.assets/tiles/: raw tile sheets plus the complete reachable logical SCREEN 2 atlas and provenance.assets/sprites/: extracted sprite sheets and sprite metadata.assets/audio/: decoded PSG events, VGM/WAV/MIDI, and lossless source ranges.assets/scenes/: title, captive/final-scene, player-motion, and scripted-demo contracts plus lossless source ranges.assets/ui/: pixel-exact HUD, score/popup tables, castle-map/game-over contracts, provenance, and lossless raw ranges.assets/maps/decoded/: decoded logical room grids and previews.assets/maps/vram_reconstruction/: reconstructed room images derived from ROM routines.assets/maps/tiled/: Tiled editor export.assets/objects/: object, terrain-mechanism, and exact lock-macro catalog.assets/collision/: collision mask catalog and movement notes.assets/remake/: consolidated data bundle for the browser experiment.assets/reference/openmsx/: deterministic original-ROM RAM/VRAM/register oracle.assets/reference/gameplay_traces/: per-frame original-execution traces and snapshots.assets/reference/dynamic_traces/: controlled per-logic-tick original-ROM traces for dynamic objects and mechanisms.assets/reference/timing/: exact baseline clock, input-delay measurements, live-loop samples, and ROM evidence.docs/: reverse-engineering notes and implementation roadmap.tools/: extraction, decoding, reconstruction, export, and bundle scripts.
Start here:
docs/faithful_remake_guide.md: implementation guide and canonical-file map for a faithful remake.docs/reverse_engineering.md: ROM layout, game loop, RAM state, room logic, objects, movement, UI, and audio notes.docs/assets.md: extracted asset formats and regeneration details.docs/logical_tile_atlas.md: lossless reachable tile atlas, source routes, provenance, and static oracle proof.docs/remake_runtime.md: browser runtime architecture and reference harness boundary.docs/fidelity_roadmap.md: remaining remake work and intentional-improvement policy.docs/gameplay_spec.md: implementation notes for the browser experiment.docs/ram_and_save.md: byte-exact RAM layout, persistence transactions, death rollback, and cassette format.docs/audio.md: complete PSG bytecode, tracks, effects, timing, and porting pseudocode.docs/dynamic_objects.md: branch-complete player physics plus frame-order/state-machine specifications for every dynamic object and terrain mechanism.docs/disassembly.md: reproducible disassembly, symbols, xrefs, graph, and exact round-trip instructions.docs/gameplay_traces.md: captured input scenarios, frame columns, observed timings, and validation.docs/dynamic_traces.md: exact original-ROM object/mechanism traces, declared injections, and determinism protocol.docs/timing.md: measured scheduler/input costs, exact NTSC clock, IRQ phase boundary, and remake timing contract.docs/scenes_and_demo.md: title/scene routes, scene-motion bytecode, and the complete scripted-demo timeline.docs/ui_and_score.md: HUD, score/popup table, packed-BCD arithmetic, visited-room map, and game-over behavior.docs/original_manual.md: manual-derived rules separated from code-derived findings.docs/toolchain.md: installed emulators, Z80 analysis tools, media tools, and reproducible setup.tools/openmsx_oracle.md: capture/validation method for original behavior and room VRAM.
