# Primary objective — the menu shell, running in Godot **Status:** active, set 2026-08-28. Build a Godot 4 project that boots the player's own disc through the sequence the real game uses, and let a person move through it: ``` developer logo splash → intro video → title / PRESS Ⓐ → main menu → submenus ``` No gameplay. No 3D. No HUD. No emulator. Done means a human presses a d-pad and Ⓐ and moves through those screens with the right art, animation, music and transitions. ## 1. You are one of two agents A **container agent** does the reverse engineering, in the [Syplheed-Reborn][reborn] repository. It runs the emulator; you do not. You build the port from what it publishes. The contract is `docs/port/HANDOFF.md` in that repository. **Read it before assuming any value is on the disc.** Every answer there is one of three things, and the distinction decides what you do: | | meaning | what you do | |---|---|---| | **decoded** | a field on the disc, with a disc-wide check | read it in the exporter | | **measured** | not on the disc, but the running game does *this* | put it in `authored/`, cite the finding | | **undecodable** | looked for, provably not there | put it in `authored/`, say it is a decision | If HANDOFF.md does not answer something you need, **say so and move to another milestone**. Do not guess and do not reverse engineer it yourself — you have no emulator and no oracle, so a guess here is indistinguishable from a fact and will be believed later. [reborn]: https://git.mc02.dev/fabi/Syplheed-Reborn ## 2. The wall The Godot project **never reads a disc format**. No IPFB, no RATC, no T8aD, no XMA, no WMV. If Godot cannot read something, the exporter's job is to emit it differently — not to bridge the gap at runtime. * **No GDExtension. No Rust in `port/`.** * The decoders come from `sylpheed-formats`, **pinned by revision**. Do not vendor them, do not reimplement them, and do not float the pin — a decoder change landing mid-milestone is exactly the confusion this pin prevents. * Bump the pin deliberately, as its own commit, saying what you wanted from it. **In particular, do not reimplement media assembly.** `sylpheed_formats::media` already handles the cases where one playable thing is not one archive entry: a `.pak` entry that spans segment files, a bank with several sub-waves, and the cutscene voices — which are one continuous XMA stream chunked into `VOICE_*.slb` entries whose boundaries do **not** match the cues, so *a `.slb` need not hold the track its name claims*. That last one is the single easiest thing in this project to get subtly wrong. Use `resolve_movie_voice_region`. ## 3. Derived vs authored | | `export/` | `authored/` | |---|---|---| | produced by | the exporter | you, by hand | | contains | what the disc says | what we decided | | hand-edited | **never** | always | | in git | **no** — gitignored | yes | | on re-export | overwritten wholesale | untouched | Tempted to hand-fix a file under `export/`? The fix belongs in the exporter or in `authored/`. Every `authored/` entry carries a `why`. When the RE agent later decodes something you had authored, **delete the authored entry** and let the exporter emit it. That deletion is the measure of progress. ## 4. Never commit game assets `export/` is generated from the user's own disc and is gitignored. Code, schemas, `authored/` mappings and docs only. If you are about to commit a sprite PNG or a transcoded video, stop. ## 5. Milestones A milestone is done when its **artifact** exists, not when the code compiles. | | Milestone | Gate | |---|---|---| | **P0** | Exporter skeleton; one screen and its sprites to `export/` | `export/screens/title/main_menu.json` validates against FORMAT.md and the PNGs open | | **P1** | Godot renders that screen statically at 1280×720 | A Godot screenshot beside `sylpheed-cli screen render` of the same build — they should agree, and where they do not, say which is wrong | | **P2** | Keyframe animation | Buttons slide in. **Blocked on HANDOFF Q1** (the time unit). Do not invent it | | **P3** | Splash → title, with the transition | Both screens back to back, unattended | | **P4** | Intro video | `ADV.wmv` plays with audio (§6) | | **P5** | Main menu: navigation, focus states, Ⓐ into a submenu, B back | A human clicks through it | | **P6** | Audio — menu BGM and move/confirm SFX | Sound on the P5 gate. **Looping is blocked on HANDOFF Q10** | | **P7** | New-game intro video after NEW GAME | Plays, then returns to a defined state | Work the lowest unfinished milestone. When one is blocked on an RE answer, say so in `docs/BLOCKED.md`, and take the next milestone that is not. ## 6. The video problem `ADV.wmv` is **WMV3 video with WMA Pro audio**, 1280×720 at 30 fps, 137 s. Godot 4 plays only **Ogg Theora** natively. Transcode with ffmpeg, and **record the exact command in the export manifest** so a modder who dislikes the quality can re-run it rather than reverse-engineer what you did. Theora at 720p is not great; if the result is visibly poor, **say so and propose** the FFmpeg-GDExtension fallback — do not adopt a runtime dependency on your own authority. Only the boot intro and the one new-game intro are in scope. The disc holds 3.3 GB of video; transcoding all of it is not this milestone. ## 7. Out of scope 3D, gameplay, HUD, missions, save/load, localisation beyond English, the Ready Room, and any reverse engineering. If you want an answer the disc has not given you, that is a request to the container agent, not a task for you.