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 file 0x16260..0x16740, VA 0x801E4A78..0x801E4F58
Stride
4 bytes per instruction; programs are 2 to 7 instructions long on disc
Retail reader
FUN_801D6628(&program), 13-entry jump table at 0x801CED70
Parser
legaia_game_tables::widget_script (parser + jal-site scanner)
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.

+0opcodeu8
+1window idu8
+2operandu16 LE
+4next opcode, 00 = endu8
FieldMeaning
opcode0x01..=0x0D selects one of 13 handlers; 0x00 terminates the program
window idIndex into the 52-record window descriptor table (16 bytes per record); the record's x / y are the instruction's default coordinates
operandPacked 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 on the actor VM page.

OpcodeSeen on disc as
0x01Open a window at its home position
0x02Open at a packed position (operand)
0x04Close
0x05Global tick
0x06Motion-flag clear
0x0AClose / 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_game_tables::widget_script::scan recovers 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.

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_code_hooks::seru_overlay::consts, shop flow).

VAFile offsetProgramCaller
0x801E4E380x16620[05][01 21][01 2A][01 20][01 28][01 22][00] - tick, then open vendor plate, picker, gold box and two panelsshop picker open, FUN_801DAFD4
0x801E4E540x1663C[04 28][04 2A][04 22][00] - close the picker windows, keep gold + vendor plateshop Sell transition, FUN_801DAFD4
0x801E4A780x16260[05][00] - global tick onlymenu-open staging (multiple callers)
0x801E4D50 / 0x801E4D780x16538 / 0x16560[01 07][00] - open window 7spell level-up notice, FUN_801D9280 / FUN_801D9594
0x801E4EA8 / 0x801E4EDC0x16690 / 0x166C4[01 1F][00] - open window 31Point Card toast, FUN_801DB7F4 / FUN_801DB380

How we know

Disassembly anchors
Function / siteAddressWhat it provesEvidence
Interpreter entryFUN_801D6628Takes a program pointer; 4-byte strideDisassembly of PROT 0899 at slot-A base 0x801CE818
Opcode range check0x801D6680sltiu v0, opcode-1, 0xd - 13 handlers, 0x00 falls outDisassembly
Jump table0x801CED70The 13 handler addressesDisassembly
Terminator re-read0x801D6854lbu v0,0x0(s4) after each dispatch - a zero byte ends the programDisassembly
Window-table index0x801E4738 + id*0x10Byte 1 is a window id, not an actor or animation idDisassembly of the base materialisation
Program bytesfile 0x16260..0x16740The pinned programs above exist on the disc as listedRead off the disc image

In the port, legaia_engine_menus::menu_widget resolves the same programs from the user's disc at boot and runs them through the interpreter in legaia_engine_vm.

Source of record: docs/formats/window-script.md.

See also