Legend of Legaia
About the project
Legend of Legaia es un videojuego para la consola PlayStation (PSOne) que en España salió en junio del 2000. El juego llegó a España con dos años de retraso. En Japón salió a la venta el juego a finales de 1998. Legend of Legaia es un juego con gráficos parecidos a Final Fantasy VII y compartía similitudes con esta saga. Tuvo una secuela en 2001 titulado Legaia 2: Duel Saga para la consola PlayStation 2.
2 versions of Legend of Legaia
You're viewing: Legend of Legaia
Official project information
legend-of-legaia-re
Legend of Legaia (PlayStation, 1998, NA SCUS-94254), running as a from-scratch Rust port you can play today - in a native window or in your browser - from your own disc image. Around the port sit a full asset extractor, a disc patcher (randomizer, translation packs, content mods), interactive viewers, and byte-level documentation of every format on the disc.
Project site: andrewaltimit.github.io/legend-of-legaia-re - play, browse and patch in the browser, nothing to install.
This repository is code and documentation only. You bring the disc: nothing Sony owns is committed or distributed, and everything browser-side reads your image locally in the tab - it is never uploaded. See You bring the disc.
What you can do with it
| You want to | What ships | Where |
|---|---|---|
| Play the game | The port: title screen, New Game, towns, dungeons, world map, battles, menus, saves | Browser play page, or legaia-engine natively |
| Play the minigames on their own | Slot machine, Noa's dance, Baka Fighter, fishing, Muscle Dome | Minigames page |
| Get the assets out | Textures, models, music, sound banks, dialog, FMVs, data tables | legaia-extract and a CLI per format; the asset viewer and media browser in the browser |
| Randomize or mod your disc | Shuffles, tuning sliders, MIPS code hooks, custom models and textures | legaia-patcher, or the ROM patcher page |
| Translate the game | Export all text to YAML, edit, reimport in place | legaia-patcher translate, or the translation workbench |
| Look things up | Enemies, characters, NPCs, magic, arts, shops, every town and kingdom in 3D | The site's data pages, starting at enemies and the world |
| Export to Blender / Unity / VRChat | Scenes, NPCs, props, equipment and the party as .glb | legaia-engine export-glb (guide) |
| Understand how the game works | Format specs, subsystem docs, traced functions, RAM map | docs/ |
What it is, and is not
A port, in the ScummVM / OpenRCT2 / OpenMW / OpenLara sense: fresh Rust written from the project's own reverse-engineering record (Ghidra-traced function dumps and live emulator probes), reading the original game data at runtime. It is not a decompilation, not a byte-matching rebuild, and not a static recompilation of the executable. The -re in the name is both reverse-engineering and re-implementation.
Retail is the ground truth, not a cage. The traced disassembly and the parity oracles pin the original's arithmetic, RNG, script pacing and save layout, and a retail-faithful mode stays testable. On top of it the port adds things the original never had - enhanced lighting, volumetric ground fog, see-through walls around the player, free-angle movement, an orbit camera, VR - as toggles, on by default where they are clearly better, with retail one switch away. Per-knob defaults: docs/subsystems/engine.md.
One engine runs behind every host. The simulation crates carry no GPU, windowing or audio-device dependency, so the same code ticks in a native window and as WebAssembly in the browser; How it fits together draws the whole stack.
What works
The whole game plays, New Game to the ending credits:
- Boot and story. Launcher, title screen, New Game through the opening (prologue, narration crawl, FMVs), Continue from a save. An automated full-game ladder plays one New Game through every story milestone to the credits on pad input alone, reloading only its own saves, and also clears each story segment from the retail save at its milestone.
- Field. Every scene on the disc loads and runs its own scripts through the ported field VM: retail movement and collision, NPCs and branching dialogue, doors, chests, cutscene choreography, the world map.
- Battle. Random and story encounters into player-driven battles: the command ring, Tactical Arts with Super and Miracle Arts, Seru magic and summons, items, Spirit, running away, then spoils, level-ups and Seru capture.
- Menus and towns. The pause menu and the screens behind it (status, items, magic, equipment, options), shops, inns, the save screen.
- Minigames. Fishing, the casino slot machine, Noa's dance, Baka Fighter and the Muscle Dome, driven by the tables on your disc.
- Audio and video. Music through a from-scratch SPU and sequencer against each scene's own sound bank, sound effects, the CD-XA arts shouts, battle stings and Seru cast voices, and MDEC cutscenes with synced audio.
- Saves. The engine's own save files, plus real PSX memory-card images an emulator still accepts.
- Tooling. One-command extraction of the whole disc, the randomizer and content mods, language packs, and reproducible static analysis.
Known gaps:
- Bug reports help. If you hit a visual glitch, a mistimed animation or a stuck script, an issue naming the scene and what you did is the fastest way to a fix.
- Frame-for-frame parity is still closing. The retail comparison corpus scores the port against retail save states - RAM, camera, and the frame on screen - and ranks where it still differs.
- Some sounds are the port's pick. Where retail's sound-effect id for an event is untraced, the port plays the closest cue and labels it as its own choice (details).
- USA disc only for the port. Other regions' discs extract, and an official PAL translation can be lifted into a USA language pack, but the engine and the patcher target
SCUS-94254. - Open questions remain in the reverse engineering itself: open threads.
Quick start
Play in the browser
Open the play page, pick your disc image, play - flat, or in VR over WebXR.
Play natively
Download the archive for your platform from the Releases page and double-click Legend of Legaia in the unpacked folder (Legend of Legaia.exe on Windows, Legend of Legaia.app on macOS). The launcher opens: choose your disc image once (it is checked and remembered), set the display options, and press Play for the title screen.
| Platform | Archive |
|---|---|
| Linux x86_64 (glibc 2.28+) | legaia-tools-<version>-x86_64-unknown-linux-gnu.tar.gz |
| Linux arm64 | legaia-tools-<version>-aarch64-unknown-linux-gnu.tar.gz |
| Windows x86_64 | legaia-tools-<version>-x86_64-pc-windows-gnu.zip |
| macOS 11+ (Apple silicon + Intel) | legaia-tools-<version>-universal-apple-darwin.tar.gz |
sha256sum -c SHA256SUMS --ignore-missing # optional: verify the download
tar -xzf legaia-tools-<version>-x86_64-unknown-linux-gnu.tar.gz
cd legaia-tools-<version>-x86_64-unknown-linux-gnu
./"Legend of Legaia" # launcher, then the title screen
The archive's top folder holds only the two programs to double-click - the game and Legaia Explorer - plus README-PLAY.txt and the licenses; every command-line program, the engine legaia-engine among them, is in its command-line-tools/ folder. README-PLAY.txt covers first launch, including the macOS Gatekeeper prompt; docs/tooling/releases.md covers what is in an archive and how it is built. The engine and asset-viewer want a GPU and, on Linux, ALSA.
Every archive also carries Legaia Explorer, a desktop app for the asset side: open your disc image, browse the archive by scene, preview textures, models, characters, monsters, audio, dialog and movies, and export them, or run the full extraction with a progress bar (crates/explorer). The site's desktop apps guide walks through downloading, the first start on each system, Explorer and the native port, with screenshots.

Build from source
Needs a Rust toolchain (edition 2024).
cargo build --release # every binary lands in target/release/
The commands worth knowing
Paths below are for a source build; from a release archive run them in its command-line-tools folder, without the target/release/ prefix.
DISC="/path/to/Legend of Legaia (USA).bin" # a .cue works anywhere a .bin does
# Check the dump against the known fingerprint.
./target/release/disc-extract verify "$DISC"
# Play: the launcher, straight into a scene, or from the title screen.
./target/release/legaia-engine
./target/release/legaia-engine play-window --disc "$DISC" --scene town01
./target/release/legaia-engine play-window --disc "$DISC" --boot-ui
./target/release/legaia-engine list-scenes --disc "$DISC"
# Watch an FMV with its audio.
./target/release/legaia-engine play-str MOV/MV1.STR --disc "$DISC"
# Extract everything: disc files, PROT entries, sub-assets, PNGs, XA WAVs, font.
./target/release/legaia-extract "$DISC" --out extracted
# Browse what was extracted.
./target/release/asset-viewer prot extracted/PROT.DAT --cdname extracted/CDNAME.TXT
# Bake a scene (world, NPCs, animated props) to .glb.
./target/release/legaia-engine export-glb --scene town01 --out glb-export
# Randomizer and translation: each lists its feature flags under --help.
./target/release/legaia-patcher randomize --help
./target/release/legaia-patcher translate --help
Every binary answers --help, and legaia-engine --help groups its subcommands into playing, exploring and development diagnostics. The guides take each task end to end:
- Getting started - from a release archive to an extracted disc, and every tool at a glance.
- Playing and viewing - controls, enhancement toggles, cheats, minigames, saves, the browser build.
- Extracting assets - textures, models, audio, movies, data tables.
- Modding and translation - randomizer, manual edits, texture replacement, saves.
- Translating - a language pack, step by step.
You bring the disc
This project ships no Sony-owned bytes, ever. There is no game executable, no asset data, and no ROM content in this repository or in any release archive. Everything here is code and documentation that operates on a disc image you already own and supply yourself.
Concretely, and non-negotiably:
- You supply the disc image. Every tool takes a path to your own
.bin. Nothing is bundled and nothing is downloaded for you. extracted/andghidra/projects/are gitignored. Extraction output is Sony-derived, so it stays on your machine. The same applies to per-function Ghidra dumps underghidra/scripts/funcs/and to exported translation packs.- Disc-gated tests skip when
LEGAIA_DISC_BINis unset. Tests that need real disc bytes skip and pass without it, so CI runs green with no disc data present. This gating is deliberate - don't remove it. - The licenses below cover this repository's code and docs only. They do not, and cannot, grant you any rights to Sony's IP.
If you are adding code here, treat "no Sony bytes get committed" as the one hard constraint that outranks everything else - including decompiled C that carries literal asset data or text strings.
The reference dump:
| Disc | SHA-256 (Mode2/2352 .bin) |
|---|---|
| Legend of Legaia (USA), SCUS-94254 | e6120a5d70716dd2f026a2da32d0171d52651971b52c4347a68541299f75258c |
This hash is a sanity check against the project author's dump; different dumping tools can produce a different whole-image hash for the same disc. For canonical per-track verification, cross-check against Redump.
Documentation
Start at docs/overview.md: how the layers stack from disc to sub-asset, and where to read next for any task. docs/porting-by-reimplementation.md explains the general approach: why an engine reimplementation rather than a decompilation or a static recompilation, and the method from documenting the disc to measuring against retail.
| Section | Holds |
|---|---|
docs/guides/ | Task-oriented walkthroughs for the shipped tools. |
docs/formats/ | Byte-level specs for every format on the disc, each with a confidence level and Ghidra provenance. |
docs/subsystems/ | How the runtime works - the VMs, battle, renderer, audio, field, menus, minigames - and the port's own architecture. |
docs/tooling/ | Extraction CLIs, the randomizer, translation, Ghidra and emulator automation, and the parity instruments. |
docs/reference/ | Traced functions, the RAM map, builds, curated game data, and the open / settled / falsified research threads. |
How it fits together
The repository is one Cargo workspace of small crates, each with a one-page README.md. They stack in bands: a crate depends only on crates in its own band or a band below it, so the stack reads from the programs people run at the top down to the disc parsers at the bottom. Colour marks the track a crate belongs to.
Explore it interactively on the crate map: hover a crate to light what it uses and what uses it, open its scope, binaries and modules, filter by track, and follow a scene from the disc to the screen. The page, this diagram and the layer list below are generated from the workspace itself (every Cargo.toml, the crate tables in CLAUDE.md and the layering table) by scripts/ci/gen-crate-map.py, and a gate fails a commit that leaves them stale.
Four tracks
| Track | What it is | Start at |
|---|---|---|
| Preservation | Reading the disc: the sector reader, the PROT archive, one parser per format, the Legaia-specific format families over them, and the tools that extract and document every asset. | legaia-extract, asset, docs/formats/ |
| Engine | The from-scratch port: the ported script VMs and rules engines as World-free kernels, the simulation in engine-core, the session both play hosts tick, the wgpu renderer and the from-scratch SPU. | docs/subsystems/engine.md |
| Patcher | Writing the disc: same-size PROT edits with EDC/ECC re-encode, MAN relocation, translation packs, MIPS code hooks, model and texture replacement - all behind legaia-patcher. | docs/tooling/randomizer.md |
| Research tooling | Measuring the port against retail: emulator save-state readers, the parity oracles and retail comparison corpus, and the curated reference labels. | docs/tooling/retail-compare.md |
The layers
Top of the stack first. Every crate name links its README.
<!-- crate-map:layers:begin (generated by scripts/ci/gen-crate-map.py; edit crate-map-layout.toml) -->- Hosts and front ends. The programs people run. Each one is a thin shell over the crates below.
engine-shell,web-viewer,web-play-bundle,web-play,web-minigames,web-patcher,web-expansion,asset-viewer,explorer,patcher,extract,asset - Session, presentation, tools. What both play hosts share above the simulation: the game session, the screens, the renderer, the audio stack and netplay; plus the tools that step a World from outside.
engine-session,engine-screens,engine-render,engine-audio,engine-export,parity,retail-exec,engine-capture,netplay,engine-netplay - World drivers. Layers that hold a running World from outside: scene entry and tick, the pause menu, the battle HUD's and the field screens' reads, the cheats, the LGSF saves.
engine-scene-host,engine-menu-runtime,engine-battle-hud,engine-world-views,engine-cheats,engine-save-state - Simulation. engine-core owns World and its tick, and implements each VM's Host trait. Everything below it names no World.
engine-core - World-free kernels. The ported VMs and rules engines, ranked by the committed layering table: a kernel depends only on kernels of a lower rank.
Rank 6:engine-battle-loop,engine-minigame-scenes
Rank 5:engine-battle-menus,engine-menus,engine-ui
Rank 4:engine-expansion,engine-fishing,engine-minigames,engine-scene
Rank 3:engine-battle,engine-cast,engine-effects,engine-field
Rank 2:engine-battle-vm,render-kernels
Rank 1:engine-camera,engine-dev-menu,engine-mode,engine-modes,engine-motion-vm,engine-title
Rank 0:engine-dialog,engine-run-rules,engine-system,engine-vm - Patcher and capture libraries. The disc-writing layers under legaia-patcher, and the emulator save-state readers under the parity oracles.
disc-patch,randomizer,translate,code-hooks,arts-patch,texture-replace,party-swap,delilas-party,delilas-challenge,ram-image,mednafen,pcsx-redux - Format families. The Legaia-specific layer over the parsers: containers, scenes, actors, minigames, the 2D interface, the static tables, code overlays.
container-formats,scene-formats,actor-formats,minigame-formats,ui-formats,game-tables,overlay-images,disc-audit,expansion-format - Disc and per-format parsers. The foundation: sector reader, the PROT archive, LZS, and one small crate per file format.
iso,prot,lzs,bytes,tim,tmd,vab,seq,xa,mdec,mes,anm,mdt,art,font,save,gamedata,cheats,app-theme
Three hosts, one engine
| Host | Crate | Draws through |
|---|---|---|
Native play-window | engine-shell (the legaia-engine binary) | winit + wgpu (engine-render) + cpal (engine-audio) |
| Browser play page | web-play, compiled to WebAssembly in web-play-bundle | WebGL + WebAudio, from site/js/play-app.js |
| Browser minigames page | the same web-play crate and bundle | one JS module per minigame |
Both play hosts tick the same engine-session BootSession over the same World; the minigames page drives the World-free minigame rules engines directly. What differs is only the shell. Host drift covers the gates that keep a feature from reaching one host only.
A scene takes one path through the stack on every host: iso reads the sectors, prot finds the entry, lzs decompresses it, container-formats and scene-formats split the bundle, engine-scene loads its resources, engine-core's World ticks the ported VMs over it, engine-scene-host and engine-session order the frame, render-kernels and engine-ui build the draws, and wgpu or WebGL puts them on screen.
Around the crates
| Path | Holds |
|---|---|
docs/ | The technical reference: formats, subsystems, tooling, reference tables (start here). |
site/ | The project site's sources: page fragments, the browser hosts' JS, the generator site/_gen.py. |
data/ | Curated, non-Sony reference tables (game data mined from public walkthroughs, music and scene names). |
ghidra/, scripts/ | Analysis scripts (dumps are gitignored), CI gates, capture automation (map). |
extracted/ | Your disc's assets. Sony bytes, gitignored, never committed. |
CLAUDE.md is the full map of the repository - every doc page and every crate, one line each - and crate layering explains the rules the stack keeps and the gate that holds the engine's kernel ranks.
Reusable for other PS1 games
Part of the stack describes the PlayStation rather than Legaia, and works on another game's disc. Take a crate as a git dependency with default-features = false (the default cli feature adds the command-line binary and its dependencies). Reusing this repo for other PS1 games has the per-crate detail, every Legaia assumption by name, and the transferable method (the retail-compare oracle, evidence grading, the falsified-hypotheses register, disc-denominated coverage, determinism replay), which the retail-oracle method writes up engine-neutral. A worked example runs the generic crates on a made-up game built in code: cargo run -p legaia-pcsx-redux --example bring_your_own_game.
| Crate | What it does | Generic? | Entry point |
|---|---|---|---|
iso | Mode 2/2352 reader, ISO9660 walk, EDC/ECC re-encode, in-place file patch | Generic | RawDisc::open, iso9660::walk_files, write::patch_file_logical |
xa | CD-XA ADPCM demux and decode to WAV | Generic | demux::demux_raw_sectors, decode |
tim | TIM parse, PNG export, PNG-to-TIM encode, software VRAM | Quirk: Vram::upload_tim lands CLUTs as Legaia's loader does | parse, decode_rgba8, encode::encode_replacement |
vab | VAB bank parse and VAG decode | Standalone VABs via parse; Legaia's two-chunk carriage has its own helpers | parse, decode_vag |
seq | libsnd SEQ parser | u32 version header, meta events with no length byte | Seq::parse |
lzs | LZSS (4 KB ring at 0xFEE) decode and re-pack | Zero-filled ring, no size header, Legaia container | decompress, compress |
mdec | STR sector assembly, A/V demux, MDEC decode | Decoder is the Iki bitstream; STRv2 needs Legaia's VLC table | str_av::demux_str_av, MdecDecoder |
mednafen | Mednafen state: RAM, VRAM, SPU | Library generic; several CLI subcommands are Legaia's | SaveState::from_path |
pcsx-redux | PCSX-Redux state: VRAM, scratchpad, RAM | Generic (all located structurally); the scene / mode accessors are Legaia's | SaveState::from_path_structural, gpu::PcsxGpu |
ram-image | RAM diff, write bisection, GPU primitive-pool decode | Generic; game knowledge is a GameProfile parameter | diff::diff_ram, prim_pool::decode, GameProfile |
engine-audio | From-scratch SPU and libsnd-shaped sequencer | No pitch modulation / noise / FM; Legaia battle-audio modules beside it | spu::Spu, Sequencer::new |
render-kernels | gte: register-level GTE with every command and the UNR divide | Module generic, crate Legaia-bound: vendor src/gte/ | gte::Gte |
tmd | Legaia's TMD variant | Legaia-only: rejects stock 0x41 TMDs | parse |
Contributing
CONTRIBUTING.md has the rules of engagement and the gates. The short form:
cargo fmt --all -- --check
cargo clippy --all-targets --workspace -- -D warnings
cargo test --workspace --profile release-test
LEGAIA_DISC_BIN="/path/to/Legend of Legaia (USA).bin" cargo test --workspace --profile release-test
The last line turns on the disc-gated tests; without the variable they skip and pass. Reverse-engineering work additionally wants Docker for headless Ghidra (setup) and, for runtime capture, mednafen or PCSX-Redux.
Status and license
Status: playable from New Game to the credits, natively and in the browser; What works lists the known gaps. Prebuilt releases are on the Releases page.
License: dual-licensed at your option under either the Unlicense (public-domain dedication) or the MIT License. Apache-2.0 is intentionally not offered - this project is meant to be as close to public domain as the law in your jurisdiction allows, with no patent-retaliation strings attached: copy it, fork it, sell it, patent improvements on it, just don't stop anyone else from doing the same.
These licenses apply only to the code and documentation in this repository. Sony's IP - game executable, asset data, ROM contents - is not redistributed here and is not covered by them. See You bring the disc above.
Acknowledgments
- Public community research on unused content and builds - developer attribution (Prokion / Contrail), debug-flag addresses, the catalog of 14 known builds.
- Sam Ste's PROT.DAT unpacker - early Python proof-of-concept that pointed at the right TOC slots and the TIM-pack heuristic.
- PSXRecomp (mstan / SamSteProjects) - a PlayStation 1 static recompiler (MIPS R3000A -> C -> native, recompiled SCPH1001 BIOS as the kernel, no HLE), and its Legaia-specific fork whose runtime work carries the game from boot through field, battle, and the CD/XA cutscene path. We run it as a live cross-reference oracle - a second, independent execution of the retail code to validate the from-scratch port against (GTE registers, overlay identity, render-dispatch and sound-driver behaviour) - never as a source of Sony bytes. Built on the N64Recomp static-recompilation model (RT64 team).
- ZetaPhoenix's "Legaia Arts Data" spreadsheet - public Google Sheets catalog of the Tactical Arts / Miracle Arts / Super Arts trigger strings and finisher replacements. The
legaia-artMiracleMatcher/SuperMatchertables (crates/art/src/miracle.rs,super_art.rs) cross-reference and validate against it. His damage-formula analysis - the Offense Value / Defense Value shape, the per-command equipment selection and halving, and the Vahn vs Evil Fly worked example - organisesdocs/subsystems/battle-formulas.md, where each claim is checked against the disassembly. - Meth962's "Legend of Legaia 100% Walkthrough" (GameFAQs) and his damage-formula threads on the old legendoflegaia.net forums (archived thread 800, thread 941) - the original community damage analysis, and the v1.10 "all Enemy stats section" + Seru-magic + magic-leveling tables ground three layers of
legaia-gamedata:enemies.tomlcarries Meth's per-enemy HP / MP / EXP / Gold / ATK / SPD / UDF / LDF / INT / AGL / element columns for every entry (extracted from in-RAM memory, so fan-recorded values rather than retail-binary-extracted constants - useful as labels for the binary monster recordscrates/actor-formats/src/monster_archive.rsdecodes from PROT 0867).bosses.tomlis rewritten around the per-fight layer (named attacks + MP cost, XP / gold / item rewards, recommended party level) for all 18 main-story B-code bosses plus the Lapis superboss.magic.tomlgrowsabsorb_lv1/absorb_lv2/absorb_lv3integer-percent fields per Seru spell (Gimard 55/60/80, Gilium 1/1/1, the full 21-spell table); the per-cast XP curve and damage-scaling multipliers live inlegaia_gamedata::magic_leveling.
- ZetaPhoenix - the Super Arts Pack, a mod adding five Super Arts per character with their own names, hit counts and animations, contributed as a 3764-byte RAM block. The disc patcher installs those bytes unmodified behind
--super-arts-pack(crates/patcher/data, randomizer.md). Same author as the "Legaia Arts Data" spreadsheet above. - Henrique Stanke Scandelari (Stann0x) - a music-track disambiguation that cross-references every BGM cue across its four naming spaces (the internal debug sound-test ID + working title, the in-game context it plays in, the official OST title, and a proposed relocalization title). Incorporated as
docs/reference/music-tracks.md- the human-readable label layer for the extracted SEQ/BGM tracks, in the same curated-reference spirit as the game-data tables above.- Also a RAM / debug-code survey of the retail executable, verified against the disc before it went in. It found why the debug menu's
TMD TESTcrashes on a retail console (its draw buffers are hard-coded at0x80400040/0x80419040, which only the 8 MB development console has), thatTESThangs andREADjumps into an overlay that is no longer loaded (boot.md), and where unused RAM sits above the overlay slots, under the interrupt stack and in uncalled code (memory map).
- Also a RAM / debug-code survey of the retail executable, verified against the disc before it went in. It found why the debug menu's
- the_rabidsquirel - community research on how the battle AP gauge fills, measured with save states on retail: the
+8every character gains at the end of its own action (Spirit's+32replacing it), the AP a party member gains when an enemy's hit lands on them, the 9 AP a Miracle Art leaves, and that a level-9 Vera / Orb / Spoon heal doubles the target's AP. Checked against the disassembly inbattle-formulas.md, which also led the port to apply the doubling. - The PSX scene generally - Sony PsyQ docs, Martin Korth's PSX-SPX, and decades of accumulated TIM/TMD/SPU documentation.
- Reference projects whose legal pattern this repo follows: ScummVM, OpenRCT2, OpenMW, OpenLara.
This project does not redistribute Sony's IP. You bring your own disc image. Tooling co-authored with AI agents under human direction.

