Files
Syplheed-Reborn/docs/re/structures/ui-rat-layout.md
Claude (auto-RE) 621b9dd6e9 re: crack the UI layout record — the retail UI rebuilds from the disc
Each UI sprite <name>.t32 ships with a <name>.rat companion, and that companion
is the layout record: big-endian u32, a 1280x720 design space at 0x18, and a
placement block of scaleX/scaleY/tint/X/Y. Animated elements repeat the block
with a trailing time field (keyframes); an 'opt ' tag carries a length-prefixed
link to the focused-state record.

Verified in that order, records first: across the four pause buttons exactly one
field varies, stepping 268/338/408/478 at a constant 70px pitch with X fixed at
226; the three items visible in a screenshot of the running game measure
346.0/415.5/485.5, mapping onto those numbers under one constant offset to
within 0.5px. The tutorial build's records are outright framebuffer coordinates,
and compositing its sprites there reproduces the screenshot pixel-accurately.

Also records two mistakes the A/B caught, since a static-only reading would have
shipped both: texture width does not identify a language (Japanese fits English
widths), and the in-mission and tutorial pause menus are separate sprite sets
rather than one set re-packed into slots.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 19:05:21 +00:00

5.4 KiB
Raw Blame History

.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

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 screenGP_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 bundle is one (context × language) build of that screen, and its children come in pairs:

child what it is
<name>.t32 the sprite (T8aD)
<name>.rat that sprite's layout record (this document)
<screen>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

  • <screen>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 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).