# `.rat` — the UI element layout / animation record **Status:** ✅ `CONFIRMED` for placement (2026-07-28). The retail UI can be **reassembled from the disc**: the tutorial PAUSE menu rebuilds pixel-accurately from its sprites placed at the coordinates in their `.rat` records — no fitting, no manual nudging. ![real vs rebuilt](captures/ui-layout/pause-tutorial-real-vs-rebuilt.png) *Left: the running game (Canary screenshot). Right: rebuilt from `GP_PAUSE_MENU.pak` alone. The remaining differences are the animated frame/glow sprites (`*eff*`) that were not placed, and the live 3D background.* ## Screen composition The UI is **one pak per screen** — `GP_TITLE`, `GP_PAUSE_MENU`, `GP_READY_ROOM`, `GP_SAVE_LOAD`, `GP_MISSION_SELECT`, `GP_OPTIONS`, `GP_SYSTEM`, `GP_TUTORIAL`, `GP_STAGE_CLEAR`, `GP_MOVIE_THEATER`, `GP_DEBRIEFING_PILOTLOG`, `GP_LEADERBOARD`, `GP_MISSION_LOG`, `GP_BUNK`, `GP_DIALOG`, `GP_GAMEOVER`, `GP_CHALLENGE`, `GP_HANGAR_ARSENAL`. Inside a screen pak, each top-level [RATC](../INDEX.md) bundle is **one (context × language) build of that screen**, and its children come in pairs: | child | what it is | |---|---| | `.t32` | the sprite ([T8aD](texture-color-k8888.md)) | | `.rat` | that sprite's **layout record** (this document) | | `loop1.rat` | a screen-level record (larger; not yet decoded) | `GP_PAUSE_MENU.pak`'s six bundles are `{in-mission, tutorial} × {English, Japanese}`, with the two in-mission builds each present twice at identical size. The purpose of that duplicate is **NEEDS-HUMAN** (resolution or aspect variant?), and where the other four shipped languages live is likewise unresolved — this pak holds only EN and JP. Naming is transparent: `pgp` = pause screen, `pgp_ttrl_` = its tutorial context, `btnNN` = menu item, `btnNNf` = that item's **focused** sprite, `eff*` = frame/glow decoration, `deli*` = the item divider, `title`, `msg`. ## Record layout Big-endian u32 throughout (Xbox 360). A minimal record (a static button) is 165 bytes: ``` 0x00 "RATC" magic — a RATC bundle reused as a data record 0x08 u32 payload size 0x18 u32 design width = 1280 0x1c u32 design height = 720 0x20 char[] the sprite this record places, e.g. "pgpbtn00.t32" ... ── placement block ── u32 scale X = 100 (percent) u32 scale Y = 100 u32 tint = 0xffffffff (RGBA, white = untinted) u32 X ← position u32 Y ← u32 time (keyframe records only) ... "opt " u32 len char[len] link to another record, e.g. "pgpbtn00f.rat" ``` - **Animated elements are a keyframe list.** `pgptitle.rat` (752 B) is the same placement block repeated with a varying trailing `time` field — the PAUSE title's fly-in. - **`opt `** carries a length-prefixed record name. On `pgpbtn00.rat` it points at `pgpbtn00f.rat`, i.e. *normal state → focused state*. - Two fields (at 0x50/0x54 in the button records) vary per button and are **not identified**. ## Evidence Positions were read out of the records and checked against a screenshot of the running game, twice, in that order — the records were never fitted to the picture. 1. **Differential.** Across `pgpbtn00/01/04/05.rat`, exactly one field varies and it steps `268 → 338 → 408 → 478` — a constant 70 px pitch — while the field before it is 226 in all four. A vertical menu: constant X, evenly spaced Y. 2. **Against the game.** The three visible items measured at screenshot y-centres 346.0 / 415.5 / 485.5 — spacing 70.0 and 70.0, and a *single* constant offset maps all three onto 268 / 338 / 408 to within 0.5 px. 3. **Absolute placement.** The tutorial build's records give 546/288, 546/358, 546/428 and 540/119, which are framebuffer coordinates directly: compositing the sprites there reproduces the screenshot (image above). ## Two traps this caught Both were mistakes made during this analysis, caught by comparing against the real game — recording them because a static-only reading would have shipped them: - **Texture width does not identify a language.** English `RESUME` (166 px) and Japanese `再開` (86 px) differ hugely, but Japanese `通信ログ` (148 px) is within a few px of an English label. The first language assignment made here was wrong; rendering the sprites is the only reliable check. - **The in-mission and tutorial pause menus are different sprite sets, not one set re-packed.** In-mission is `RESUME / RADIO LOG / OPTIONS / BACK TO TITLE` (4 items, `pgpbtnNN`); the tutorial is `RESUME / OPTIONS / BACK TO MENU` (3 items, `pgp_ttrl_btn1N`). Matching the 3-item screenshot against the 4-item set suggests a runtime slot-packing rule that does not exist. ## Next - `loop1.rat` (1320 B) is the screen-level record — decoding it should give the draw order and the `eff*`/`deli*` placements that are missing from the rebuild above. - The same method should now unroll the other screens directly; `GP_HANGAR_ARSENAL.pak` (789 T8aD + 510 RATC) is the big one, and the ARSENAL `DATA SHEET` panel documented in [weapon-datasheet-runtime.md](../weapon-datasheet-runtime.md) is a ready-made oracle for it. - Tooling: `crates/sylpheed-formats/examples/ui_screen.rs` (inventory a screen pak, carve a named RATC child), `sylpheed-cli pak textures` (decode every sprite).