Sylpheed port agent 9f740d8ced port: settle at the hold, not at the last timed keyframe
P2 shipped the wrong rule and the title is the counter-example. I had reasoned
that the exit is the final untimed keyframe, so anything timed was still the
entry. It is not: `pteff02` on the title holds at t=46 with the 25 % dim quad at
alpha 0x40 and then ramps to 0x00 by t=236. The exit can be a long run of TIMED
keyframes, and running to the end drops the dim and leaves the whole screen
~13/255 too bright -- exactly the luminance excess P2 recorded (oracle 64.1,
rest 62.8, timeline 80.0) and filed as an unexplained "glow slab".

A group is pre-roll -> ramp in -> hold -> ramp out -> post-roll, and a screen
that has arrived sits on the hold. `settle_units()` is now `rest.t`, the
decoders' own identification of that hold.

The check is that a disagreement vanishes: on ALL TWELVE screens the settled
timeline is now byte-identical to the `--pose=rest` render, where before this
four differed by up to 247/255. The timeline's endpoint should BE `rest` -- the
animation is what it adds, not a different destination -- so this is the
property to want, and it holds with no special case.

Credit where due: this came out of the RE agent measuring the title's dim quad
against a plate-free capture, in pursuit of a different question.
2026-08-28 21:44:08 +00:00

Sylpheed Godot

A clean-room Godot 4 port of Project Sylpheed: Arc of Deception, starting with the menu shell: developer splash → intro video → title → main menu → submenus.

You need your own copy of the game. Nothing in this repository is game content. An offline exporter reads the disc you supply and writes an open, moddable asset tree; the Godot project reads only that tree and never touches a disc format.

  your disc  ──▶  crates/sylpheed-export  ──▶  export/   ──▶  port/  (Godot 4)
                  (Rust; decoders come from      JSON + PNG        reads ONLY
                   sylpheed-formats)             + OGG + OGV       open formats

Why the wall

Two reasons, and the second is the interesting one:

  1. Godot cannot read IPFB archives, RATC bundles, T8aD textures, XMA banks or WMV video, and it should not learn to.
  2. Modding is a goal of this port. If the runtime reads the original formats, modding means reverse engineering. If it reads JSON and PNG, modding means opening a file.

Where the knowledge comes from

The decoders live in sylpheed-formats, pinned by revision — a separate project, where the reverse engineering happens. Its docs/port/HANDOFF.md is the contract: what has been decoded, what was measured off the running game, and what is known to be undecodable. Read it before assuming a value is on the disc.

Layout

crates/sylpheed-export/ disc → open formats. Regenerates export/ wholesale
port/ the Godot 4 project
authored/ decisions that are not on the disc, each with its reason
export/ generated, gitignored, never hand-edited
tools/ verification harnesses that hold the port to the reference renderer
docs/ the mission, the format spec, the agent's loop prompt

Verifying

sylpheed-cli screen render -- built from the same sylpheed-formats revision the exporter is pinned to -- is the reference renderer. tools/verify-screen draws every exported screen both ways and reports the largest per-channel difference in the frame:

tools/verify-screen              # every screen in the manifest
tools/verify-screen main_menu    # one of them

Where the two disagree, one of them is wrong; docs/DECISIONS.md says which and why, rather than tuning the port until the number goes down.

Status

P1. The exporter writes GP_TITLE's twelve screen builds and their sprites, and the Godot project draws any of them statically at 1280x720 from that tree alone. main_menu matches the reference renderer to within 3/255 on every channel of every pixel. Next: P2, keyframe animation.

Description
No description provided
Readme MIT 820 MiB
Languages
Rust 57.6%
Python 27.7%
Shell 10.6%
GDScript 3.5%
Dockerfile 0.4%
Other 0.1%