This repository has been archived on 2026-09-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Sylpheed RE agent 6f23f4d113 re(ui): the keyframe-time shift is favoured 26x by timing, rejected by a render
Follow-up on last iteration's unadopted candidate (+36 holds the NEXT
pose's time, not its own). Two new results, pointing opposite ways, and
both are reported.

FOR, and calibration-free: the observed full-alpha hold : fade-out ratio
on palogo_gamearts is 83 : 13 frames = 6.38. The shifted reading predicts
8.00. The current reading predicts 0.25 -- off by 26x. With the glow's 2
units/frame fixed and nothing else free, the current reading says the
logo holds full alpha for 2.0 frames; the capture holds it for 83. This
is no longer the shape argument the candidate rested on.

Also for: rest()'s plain max-dwell fallback picks a=0 -- a transparent
pose, for a publisher logo -- under the current reading, and the visible
a=255 hold under the shift. Only the rest_plateau special case rescues
the render today, and that is the case the port agent reported a bug in.

AGAINST: rendering every build of six UI paks under both readings, 10 of
11 compared are byte-identical and one changes -- GP_TITLE build 7, the
Japanese twin of build 4, by 13.1% of pixels. Build 4, the one verified
against a live capture, is unchanged either way, so the single build the
shift moves is the one with no capture to adjudicate it. The proxy goes
against the shift: language twins are the same artwork, and build 7 reads
70.94 mean luminance as decoded against build 4's 71.41, but 76.32
shifted. Correlation does not separate them (0.6206 vs 0.6201).

These constrain different things -- timing versus pose selection -- and
rest() is a heuristic layered on the times, so moving the times moves its
tie-breaks. Adopting the shift means revisiting that heuristic in the
same change, with no build-7 capture to verify against.

Default UNCHANGED. Experiment reachable via SYLPHEED_KF_TIME_SHIFT=1.
Shifted-mode suite: 122 passed, 0 failed across 3 suites at commit time.
2026-08-28 23:03:55 +00:00

Project Sylpheed: Arc of Deception — Reborn

A clean-room, open-source reimplementation of Project Sylpheed: Arc of Deception (Xbox 360, 2006).

Built with Rust and the Bevy game engine. Runs natively on Windows, macOS, and Linux, and in the browser via WebAssembly.

Legal note: This project contains no original game code or assets. You must own a legitimate copy of Project Sylpheed to use this engine. Assets remain the intellectual property of SETA Corporation / Square Enix.


Current Status: Milestone 1 — Asset Explorer

  • XISO disc image reading via xdvdfs
  • Xbox 360 texture de-tiling (Morton / Z-order)
  • XPR2 texture container parsing
  • Bevy custom AssetLoader for .xpr textures
  • Orbit camera viewer
  • CLI tools: extract, list, sniff, texture info, texture export
  • GitHub Actions CI (Windows + macOS + Linux + WASM)
  • WASM / web build target
  • Mesh format (reverse engineering in progress)
  • Audio format (XMA → PCM pipeline)
  • Mission data format

Repository Structure

sylpheed-reborn/
└── sylpheed-viewer/        ← Milestone 1: asset explorer (Rust/Bevy workspace)
    ├── Cargo.toml          ← Workspace root
    ├── crates/
    │   ├── sylpheed-formats/   # Format parsers — no Bevy dependency
    │   │   ├── xiso.rs         # XISO / XDVDFS disc image reader
    │   │   ├── texture.rs      # XPR2 container + DXT de-tiling (Morton)
    │   │   ├── vfs.rs          # Virtual filesystem + magic-byte sniffer
    │   │   ├── mesh.rs         # Mesh parser (stub — RE in progress)
    │   │   └── audio.rs        # Audio parser (stub — XMA TODO)
    │   │
    │   ├── sylpheed-viewer/    # Bevy application
    │   │   ├── lib.rs          # App setup + WASM entry point
    │   │   ├── main.rs         # Native binary entry point
    │   │   ├── asset_loader.rs # Custom Bevy AssetLoaders
    │   │   ├── camera.rs       # Orbit camera (LMB orbit, RMB pan, scroll zoom)
    │   │   └── ui.rs           # egui file browser + RE notes panel
    │   │
    │   └── sylpheed-cli/       # Command-line tools
    │       └── main.rs         # extract / list / sniff / texture info commands
    │
    ├── assets/             ← Extracted game files (gitignored)
    ├── .github/workflows/
    │   └── ci.yml          # CI: Windows + macOS + Linux + WASM
    ├── Trunk.toml          # WASM build configuration
    └── justfile            # All build recipes

Getting Started

Prerequisites

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Install just (task runner)
cargo install just

# For web builds only
cargo install trunk
rustup target add wasm32-unknown-unknown

Linux — Bevy system dependencies

sudo apt-get install -y \
  libasound2-dev libudev-dev libwayland-dev \
  libxkbcommon-dev libx11-dev libxi-dev pkg-config

Step 1 — Extract your disc

cd sylpheed-viewer

# Extract using the CLI tool
just extract /path/to/project_sylpheed.iso

# Or manually with xdvdfs
cargo install xdvdfs-cli
xdvdfs unpack project_sylpheed.iso ./assets/

Step 2 — Run the viewer

cd sylpheed-viewer

just run          # Native viewer
just web          # WASM dev server → http://localhost:8080

The asset viewer opens an orbit camera scene. Use the left panel to browse extracted game files. Click a .xpr file to preview it as a texture.


Build Commands

All commands run from the sylpheed-viewer/ directory.

just run              # Run the native viewer (debug)
just run-dev          # Run with hot-reloading
just build-native     # Build native release binary
just web              # WASM dev server at localhost:8080
just build-web        # WASM release build → ./dist/

just extract game.iso # Extract an ISO to ./assets/
just sniff            # Identify file formats in ./assets/
just sniff-unknown    # Show only unrecognised formats (RE focus)

just test             # Run all tests
just ci               # Full CI: fmt + lint + test + WASM check

Technology Stack

Layer Choice Reason
Language Rust Memory safety, performance, cross-platform
Game engine Bevy 0.15 ECS-first, WASM-native, data-driven
XISO reading xdvdfs Pure Rust, reads Xbox 360 disc images
Binary parsing binrw Derive-macro based, ideal for RE work
Web bundler Trunk Bevy's standard WASM build tool
CLI clap Asset extraction and inspection tools
Debug UI bevy_egui In-viewer asset browser and RE notes panel

Key Architectural Decisions

sylpheed-formats has zero Bevy dependency. All binary format parsers live here and are testable with plain cargo test. Bevy integration is a thin layer on top in sylpheed-viewer.

WASM is a first-class target. XISO reading is gated behind #[cfg(not(target_arch = "wasm32"))] since the browser can't read local files. On the web, assets must be pre-extracted and served over HTTP.

Modding is designed in from the start. The virtual filesystem (vfs.rs) is the single choke point for all asset reads — a mod loader only needs to intercept that one layer to override any file.


Reverse Engineering Notes

Known file formats

Path pattern Format Status Notes
*.XPR, *.XPR2 XPR2 texture Parsing DXT1/3/5, DXN, Morton de-tiling done
DEFAULT.XEX Xbox EXE 2 🔬 Study Main executable — load in Ghidra (PPC BE)
*.XWB, *.XSB XACT audio TODO Wave/sound banks; audio is XMA codec
*.pak, *.p00 SETA archive Unknown Paired header/data format
mesh files Unknown TODO Run just sniff-unknown to find candidates

RE workflow

# 1. Extract and map the disc
just extract game.iso
just sniff-unknown   # shows hex magic bytes of unknown files

# 2. Hex-inspect candidates
#    Groups of 12 bytes at offsets: likely f32 XYZ vertices
#    Groups of 6 bytes:             likely u16 triangle indices

# 3. Cross-reference in Ghidra
#    Load DEFAULT.XEX with PowerPC Big-Endian processor
#    Search string refs to file extensions → find load functions

# 4. Implement parser
#    Add binrw #[derive(BinRead)] struct in sylpheed-formats/src/mesh.rs
#    cargo test -p sylpheed-formats

Next steps (Milestone 2)

  1. Mesh format — fingerprint with sniff-unknown, implement mesh.rs
  2. Audio — parse XWB headers, batch-convert XMA to WAV via ffmpeg
  3. Mission data — format unknown; starts after mesh/texture loading works
  4. Flight model — document by playing the original; implement as Bevy system

Constraints

  1. Never copy decompiled or disassembled game code — reimplement behavior through observation only.
  2. Assets stay gitignoredassets/ and *.iso are excluded. Never commit game files.
  3. Keep sylpheed-formats Bevy-free — parsers must be testable without a GPU.
  4. WASM must always compile — CI enforces cargo check --target wasm32-unknown-unknown.
  5. justfile is the source of truth for build commands — add new recipes there.

Milestone Roadmap

Milestone Goal Status
1 Asset Explorer 🚧 In Progress
2 Flying Tech Demo Planned
3 Combat Prototype Planned
4 Mission 1 Playable Planned
5 Full Game (all 16 missions) Planned
6 Mod SDK Planned

Useful References

Description
No description provided
Readme 103 MiB
Languages
Rust 97.6%
Python 1.1%
HTML 0.8%
Just 0.5%