Pick a task

Every tool takes a disc image you supply (the project ships no game data); most read the extracted/ tree the extraction pipeline produces. The groups are in arrival order: get the assets off the disc, then either patch the game or dig into how it works.

  • Extract assets - turn the disc into PNGs, meshes and audio; the starting point for everything else.
  • Patch a disc - randomizer, ROM patcher, language packs. Shipped deliverables, not side effects.
  • Dig in Ghidra - the static path: disassemble the executable, recover the RAM overlays, answer "who calls this?".
  • Capture the emulator - the dynamic path: watch the retail game run and record what the code actually does.
  • Measure the port - how much of the game is understood, how much is ported, and whether the port matches retail.
  • More tooling docs - CI gates and triage ledgers, on GitHub only.

Extract assets

Almost everything on the disc lives inside one archive, PROT.DAT, as containers within containers. One command unpacks the whole chain.

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

Patch a disc

The patcher edits a copy of your disc in place - same-size edits, sector checksums re-encoded - so the result boots on real hardware and every emulator. Nothing Sony-owned is ever committed; you bring the disc.

Dig in Ghidra

The static path. Ghidra runs headlessly in Docker, driven by scripts; every FUN_80xxxxxx on this site is a function it labelled. One fact shapes all four pages: most of Legaia's game logic lives in overlays - code the game pages into RAM on demand - not in the executable, so "no static caller" is a question, not an answer.

Capture the emulator

The dynamic path: load a save state, arm a watch or breakpoint, run a few frames, read back what happened. PCSX-Redux brings a scriptable breakpoint debugger; mednafen brings cheap save states whose RAM can be diffed.

Measure the port

Four questions, four instruments: how much of the game is understood and reimplemented (port catalog, disc coverage), how much of one entry's bytes a parser really consumes (byte accounting), whether the port matches retail frame for frame (differential oracle), and whether it matches itself run twice (determinism).

More tooling docs (on GitHub)

These live in docs/tooling/ only: the CI gates that keep a measurement honest and the per-row triage ledgers behind the port catalog.

Worklist classification
Whether a missing-port row is a portable function entry at all (REAL / INTERIOR / SHARED_TAIL / DUPLICATE / VA_ALIASED / ...), so the worklist reads as work rather than addresses.
Live-audit triage
Per-anchor verdicts for the "undisclosed inert ports" the catalog's live audit flags, keyed by address + call site.
Stale NOT-WIRED triage
The sibling ledger: rows tagged NOT WIRED that the audit finds live, and the three call-graph shapes that put them there.
Reach triage
Verdicts for ports that are statically live but never entered by a replayed playthrough - the runtime gap the static audits are silent about.
Call-target integrity
Why a decoded jal target is a property of the bytes, not the load base - and the one dump window whose targets are therefore untrustworthy.
Dump-corpus integrity
A dump's printed addresses depend on its load base; only the header tag is evidence. Census of mis-based and truncated dumps plus the checker.
Port provenance
A // PORT: address can name the wrong routine and no gate catches it; the ranked worklist for checking that by hand.
Phantom print index
Address by address in the 0x801C**** / 0x801D**** band: which image and VA a printed address's bytes really occupy, and whether that VA is a function entry.
Host drift
The port ships three hosts on one engine (native window, browser play page, browser minigames), so a feature wired into one is invisible in a diff. The ladder of gates that catches it.
Shipped-bundle freshness
The site's WASM bundle is uncommitted build output whose source closure is most of the workspace; a content-addressed stamp says when a local bundle is stale.
Site shell
The static site's app shell across breakpoints, the two silent CSS / JS shadowing traps, and the page layer's delivery rules.
Shell observer traps
Three shell defects where the observer sits inside what it observes: pipe exit status off the wrong stage, pkill -f matching itself, grep's no-match exit 1 read as failure.
Doc density + link gates
The two pre-commit doc checks: over-long lines and table cells, and relative links + #anchors that must resolve.
Tagged-release pipeline
Pushing a v* tag builds the workspace binaries and attaches per-target archives + SHA256SUMS to the GitHub release. Binaries and licenses only - never game data.

Disc-gated tests

Tests that touch a real .bin run only when LEGAIA_DISC_BIN is set; without it they skip and pass, which is how CI runs. Source builds put the binaries under target/release/.

LEGAIA_DISC_BIN="/path/to/Legend of Legaia (USA).bin" cargo test --workspace