Where to start

Tools you can run today - each takes a user-supplied disc image (the project ships no game data) and does something with it:

  • Get the assets off your disc. The extraction CLIs - one command turns a disc image into browsable PNGs, 3D meshes, and audio files.
  • Change the game. The randomizer re-rolls a disc from a seed - loot, encounters, shops, doors, and more - in the browser or on the CLI. The translation toolchain turns a disc's text into an editable language pack. Both are shipped deliverables in their own right.
  • Record and replay a session. Determinism + replay captures your inputs to a small text file and plays them back frame-perfectly in the engine.

Reverse-engineering infrastructure - the instruments the format docs and the engine port are built with. You only need these if you are extending the reverse-engineering itself:

  • Ghidra in Docker is the static path: disassemble the game's executable and trace its functions.
  • Most of Legaia's game logic is not in the executable - it lives in overlays, chunks of code the game loads into RAM on demand. Overlay capture, the static overlay pipeline, and the PCSX-Redux / mednafen probe harnesses recover and observe that code at runtime; the spine flag-writers runbook is a worked example of one such hunt.
  • The port catalog is the bookkeeping: per-function status across the whole decompilation + engine-port effort.
  • Disc coverage is the same question with the denominator taken from the disc instead of from our own citations — the only measure that can say how much of the game is left.
  • The address-reference scan settles the question that stalls individual threads: who reaches this routine, and — when the honest answer is nobody — how that is told apart from work not yet done.

Pages

Extraction CLIs
Turn your disc image into PNGs, meshes, and audio in one command. Per-stage extraction binaries plus the top-level legaia-extract orchestrator: disc → ISO9660 → PROT.DAT (the disc's main archive) → categorize → sub-asset extract → PNG.
Ghidra in Docker
Headless Ghidra runs in a single Docker service. Setup, per-query invocations, the script catalogue, the LUI+ADDIU workaround.
Overlay capture
Static analysis hits a wall when code lives in RAM overlays at 0x801C0000+. Capture from mednafen save states, PCSX-Redux Lua dumps, or Duckstation .sav files.
Static overlay pipeline
The static complement to overlay capture: extract each runtime overlay straight from PROT.DAT at its recovered load address, so an overlay's identity comes from the disc rather than a guess. Solves the "several overlays share one address" ambiguity; reproducible from any copy of the disc.
Mednafen automation
Scriptable substitute for mednafen's interactive memory-watchpoint debugger. Pairwise diffs, sequence bisection, declarative scenarios for blocked decompilation work.
PCSX-Redux automation
Closed-loop Lua probes layered on PCSX-Redux's breakpoint debugger. Save-state load → arm probes → capture N VSyncs → CSV / snapshot. Catalogue of committed probes.
Recomp differential oracle
Frame-tagged parity measurement between the clean-room engine and a static recomp of the retail game: both sides emit the same JSONL state trace in retail units, and trace_diff.py reports the first frame each channel diverges. A note-level variant does the same for BGM key-ons.
Spine flag-writers capture
A worked example of a live writer hunt: one PCSX-Redux session watches the chapter-1 story-progression flags (Zeto battle-id + flags 0x142/0x482) and logs which code writes each one. Save-slot-to-story-beat mapping + derived watch addresses.
Port catalog
Per-function status: dumped × documented × ported × ignored. // PORT: and // REF: tags, BFS-from-roots feature views, ignore-list of statically-linked PsyQ infra, drift checker wired into the pre-commit hook, regenerable open-work dashboard.
Address-reference scan
"Who calls this?" answered from the disc's own bytes rather than from one tool's blind spot: every way the game can reach an address — pointer table, split-address pair, call, jump, branch — swept across the executable, all 31 overlay images and every archive entry at once. Also settles the opposite question, which is how a routine the game never runs gets told apart from unfinished work.
Determinism + replay
j-replay-v1 TOML format + legaia-engine record / replay subcommands + disc-free determinism cargo-test. Same input file run twice → bit-identical state-trace bytes; pad transitions captured from play-window's keyboard handler.
Randomizer / disc patcher
Re-rolls a user-supplied .bin from a seed: loot, encounters, monster stats, shops, doors, arts, and the starting party - plus code-hook features retail has no table for. Built on an LZS encoder, Mode 2/2352 sector write-back (EDC/ECC re-encode), and a PROT-entry disc bridge. Same-size in-place edits; no Sony bytes committed.
ROM patcher (in browser)
Run the randomizer client-side: supply your own disc image, toggle the drop / encounter / chest settings, and download a patched image. Nothing is uploaded - the patch runs in WASM in your browser.
Translation / language packs
legaia-patcher translate exports a disc's user-facing text as an editable YAML language pack and applies a filled pack back as a same-size in-place patch. Built for community translations; packs carry disc coordinates, not the original script.
Official PAL localizations
How the official French / German / Italian discs align to the USA coordinate space, and how their text is lifted onto it. Container-identical to USA; accents are single high bytes on a CP437 layout.
Tagged-release pipeline
Pushing a v* tag builds the workspace binaries and attaches per-target archives + SHA256SUMS to the GitHub release. Archives carry binaries and licenses only - never game data.

Full extraction pipeline at a glance

The recommended end-to-end run:

./legaia-extract "/path/to/Legend of Legaia (USA).bin" --out extracted

--skip-verify / --skip-xa / --skip-font skip individual stages (a .cue path also works). Release-archive users run ./legaia-extract; source builds live under target/release/. Disc-gated tests (everything that touches a real .bin) run when LEGAIA_DISC_BIN is set; CI runs without disc data and the tests skip cleanly.