Window widget scripts Confirmed
When a shop opens, five UI windows slide onto the screen in one coordinated motion - the vendor's name plate, the Buy/Sell picker, the gold box and two panels. That entrance is data: a tiny bytecode program of fixed 4-byte instructions, run by the menu overlay's window-script interpreter. The programs are not in a scene file or an asset bundle; they sit in a small table inside the menu overlay's own data segment - the code module that hosts the pause menu, shop and save UI. This page is the byte-level spec; the interpreter is on the actor VM page.
At a glance
- In the game
- The choreography of pause-menu, shop and save-UI windows opening, closing and sliding
- Magic / marker
- None - a zero opcode byte terminates a program
- Lives in
- Menu overlay, PROT extraction entry 0899 (slot-A base
0x801CE818): programs cluster at file0x16260..0x16740, VA0x801E4A78..0x801E4F58 - Stride
- 4 bytes per instruction; programs are 2 to 7 instructions long on disc
- Retail reader
FUN_801D6628(&program), 13-entry jump table at0x801CED70- Parser
legaia_asset::widget_script(parser +jal-site scanner); interpreter portlegaia_engine_vm::run; host wiringlegaia_engine_core::menu_widget- Confidence
- Confirmed - interpreter and caller disassembly, program bytes verified on the disc image
- Used by
- Shop flow, Level-up notice, Field menu
Instruction encoding
Each instruction is exactly 4 bytes. After every instruction the interpreter reads the opcode byte of the next slot and stops when it is zero.
0x00.| Offset | Size | Field | Meaning |
|---|---|---|---|
+0 | 1 | opcode | 0x01..=0x0D selects one of 13 handlers; 0x00 terminates the program |
+1 | 1 | window id | Index into the 52-record window descriptor table (16 bytes per record); the record's x / y are the instruction's default coordinates |
+2 | 2 (LE) | operand | Packed position for opcodes 0x02 / 0x09: x = (w >> 7) & 0x1FE, y = w & 0xFF. Style byte for 0x03. Zero elsewhere on disc |
Opcode semantics (create / snap / slide / close / global tick) belong to the interpreter and are documented with
its port in crates/engine-vm/src/lib.rs and on the actor VM page.
| Opcode | Seen on disc as |
|---|---|
0x01 | Open a window at its home position |
0x02 | Open at a packed position (operand) |
0x04 | Close |
0x05 | Global tick |
0x06 | Motion-flag clear |
0x0A | Close / re-open / slide-back composite |
Where the programs live
Each caller builds a pointer to a program and calls the interpreter with it. Because the table is overlay data at fixed addresses, the lookup is per boot, not per scene: the same programs are resident whenever the menu overlay is - pause menu, shop, save UI, every scene.
legaia_asset::widget_script::scanrecovers the programs structurally: find every call into the interpreter, resolve the argument each site materialises, keep the targets that parse as terminated programs with in-range opcodes and window ids.- Call sites that forward the pointer through a saved register (the shop pair among them) are not resolvable by that pass; those programs are pinned by reading the caller's disassembly.
- The from-scratch engine resolves the same programs out of the user's disc at boot and runs them through the ported interpreter on the same shop transitions (
legaia_engine_core::menu_widget).
Pinned programs
Byte-verified on the disc image. The shop pair is additionally pinned by the randomizer's Seru-trading vendor,
which reuses exactly these scripts (legaia_patcher::seru_overlay::consts, shop flow).
| VA | File offset | Program | Caller |
|---|---|---|---|
0x801E4E38 | 0x16620 | [05][01 21][01 2A][01 20][01 28][01 22][00] - tick, then open vendor plate, picker, gold box and two panels | shop picker open, FUN_801DAFD4 |
0x801E4E54 | 0x1663C | [04 28][04 2A][04 22][00] - close the picker windows, keep gold + vendor plate | shop Sell transition, FUN_801DAFD4 |
0x801E4A78 | 0x16260 | [05][00] - global tick only | menu-open staging (multiple callers) |
0x801E4D50 / 0x801E4D78 | 0x16538 / 0x16560 | [01 07][00] - open window 7 | spell level-up notice, FUN_801D9280 / FUN_801D9594 |
0x801E4EA8 / 0x801E4EDC | 0x16690 / 0x166C4 | [01 1F][00] - open window 31 | Point Card toast, FUN_801DB7F4 / FUN_801DB380 |
How we know
| Function / site | Address | What it proves | Evidence |
|---|---|---|---|
| Interpreter entry | FUN_801D6628 | Takes a program pointer; 4-byte stride | Disassembly of PROT 0899 at slot-A base 0x801CE818 |
| Opcode range check | 0x801D6680 | sltiu v0, opcode-1, 0xd - 13 handlers, 0x00 falls out | Disassembly |
| Jump table | 0x801CED70 | The 13 handler addresses | Disassembly |
| Terminator re-read | 0x801D6854 | lbu v0,0x0(s4) after each dispatch - a zero byte ends the program | Disassembly |
| Window-table index | 0x801E4738 + id*0x10 | Byte 1 is a window id, not an actor or animation id | Disassembly of the base materialisation |
| Program bytes | file 0x16260..0x16740 | The pinned programs above exist on the disc as listed | crates/asset/tests/widget_script_real.rs (disc-gated) |
Source of record: docs/formats/window-script.md.
History: the "sprite-walk interpreter" reading
The interpreter was once read as the title screen's sprite-walk interpreter with an ANM-trigger opcode, which led to a hunt for a per-scene program carrier. Its base materialisation indexes the window descriptor table, byte 1 is a window id, and no arm of the 13-way dispatch hands off an animation id - so it is the menu overlay's window-widget interpreter and the programs are overlay-resident data. Recorded in do-not-re-walk.