At a glance

  • Almost everything is in one file. PROT.DAT is the game's archive: 1233 numbered entries holding every scene, monster, tune and menu. The executable only carries the tables that tie them together.
  • Each layer has one owner. One Rust crate reads the disc, one splits the archive, one sorts entries by format, and one small crate per format decodes it. That is what lets the browser pages and the native tools share code.
  • The game runs on scripts. Towns, cutscenes, battle moves, menus and NPC pathing are bytecode interpreted by a family of small virtual machines. The engine port reimplements those VMs rather than emulating the CPU.
  • Two tracks, one repo. Preservation (extract and document every asset) and reimplementation (a from-scratch engine) feed each other: the docs are the spec the engine is built from, and the engine is the test that the docs are right.

The pipeline

Going top to bottom: a PSX disc image, then the ISO filesystem, then the archive (PROT.DAT), then per-entry containers, then individual sub-assets, and finally the engine that brings them to life. Click any layer to read its format page or the crate that handles it.

1 PSX disc image (.bin Mode2/2352)
crates/iso → disc-extract
A CD is a run of 2352-byte sectors, each with 2048 bytes of real data wrapped in sync, header and error-correction bytes. This layer strips the wrapper. The same crate can re-encode sectors, which is what lets the patcher write a modified disc back.
↓
2 ISO9660 filesystem
crates/iso
The disc's directory: PROT.DAT (the archive), SCUS_942.54 (the executable), DMY.DAT (dev fixture data), the MOV/ movies, the XA/ voice streams, CDNAME.TXT (the archive's name list) and SYSTEM.CNF.
↓
3 PROT.DAT - the archive
↓
4 Asset dispatch + categorize
crates/asset → asset
Entries carry no type label, so detectors classify each one by its bytes: LZS-compressed, TIM-pack, streaming container, scene bundle, effect bundle, sound-driver output, sound bank, or a code overlay. Three different "pack" layouts coexist here - the format pages keep their header math apart.
↓
↓
5 Engine reimplementation

Two tracks, one repo

The -re in the project name means both reverse engineering and reimplementation. The tracks are separate crates with a clear boundary between them.

TrackWhat it producesWhere it lives
Preservation Every asset off the disc as PNG / WAV / OBJ / glTF / JSON, a format spec per file type with the game function that reads it named as evidence, and round-trip parsers that can write assets back. The container crates (iso, prot, lzs, asset), one crate per format, the extract driver, and the patcher.
Reimplementation A playable engine built from those specs plus logic traced in Ghidra and rewritten fresh - never a decompilation or static recompile of Sony's executable. Retail behaviour is the measured ground truth; enhancements (dynamic lighting, see-through walls, free-angle movement, VR) are toggles that leave the faithful mode bit-identical when off. engine-core, engine-vm, engine-ui, engine-render, engine-audio, engine-shell, and the asset-viewer / web-viewer front ends.

What keeps the two honest is a set of parity oracles: the engine's video memory, sound output and game-mode trace are compared against emulator captures of the real game, so a doc that is wrong shows up as a pixel or a sample that differs. The engine page has the boundaries and the current list of enhancement toggles.

The runtime VMs

When you talk to a villager, watch a cutscene, throw a Tactical Art or open the shop, no hand-written code for that moment is running. Instead the game's engine interprets small programs stored with the data: the villager's dialogue is a script, the art is a move record, the shop window is a widget program. The five interpreters below share one actor model - the same records describe your character, an NPC, a monster and a spark of a spell - and each has its own page. Four are classic bytecode dispatchers; the effect VM is a per-slot state machine that plays the same role with a different shape.

"Five VMs" is the orientation, not the census: the field VM's menu sub-dispatcher, the move VM's overlay extension, and the battle, world-map and tile-board state machines are separate dispatchers with their own tables. The VM inventory lists every one.

How they wire together

The field VM drives the scene. When it needs an actor to perform something, it stages a move record into that actor, and the per-frame actor tick steps the move VM through it. One move-VM opcode escapes into an overlay-resident extension dispatcher that exists only while the town overlay is loaded, so battle-side move records can never reach it. The motion VMs run independently per actor for pathing and camera follow. The effect VM is battle-only, but every effect is bound to a master-slot actor that the script VM and the battle state machine can reference - the same actor model throughout. Driver addresses and traces are on the linked subsystem pages.

Runtime VM call graph Per-frame scene tick Field / event VM 43 opcodes - town / field overlay NPC movement, dialog, story flags EXEC_MOVE stages a move record into the actor Per-actor frame tick Actor tick physics + animation, once per actor steps the move VM each frame step the active actor's move VM Per-actor opcode dispatch Move-table VM 71 opcodes - executable Tactical Arts, summons, props Move VM extension 61 sub-ops - town overlay only reached via the escape opcode Independent drivers - same actor records Actor / sprite VM 13 opcodes - menu overlay window widgets: shop, pause Motion VMs 22 + 32 opcodes - executable NPC pathing, camera, cutscenes Effect VM per-slot walker - battle overlay 32 master + 128 child slots all three read and write the same actor records as the chain above
The field VM drives the scene; per-actor ticks step the move VM; the move VM can jump into an overlay extension. Actor, motion and effect VMs run independently but bind to the same actor records.

Where to go next

You want to…Read
See it running before reading anythingPlay the port, asset viewer, media browser
Install the tools or build from sourceQuick start, getting started
Understand one file formatFormats index - each page has a confidence badge
Understand one part of the running gameSubsystems index
Mod or translate your own copyModding and translation, then randomizer / translation
Look up a function or RAM addressKey functions, memory map
Find an open question to work on, or check one already answeredOpen threads, settled threads, do not re-walk