SUNRISE STUDIO

CUI layout internals

The CUI page reads the game’s native CUI resources and hierarchies and writes edits back as deltas. The steps are in Edit CUI screens.

Composition

A hierarchy view composes the default property profile through imports and supported anchors, in the native construction order. It marks unsupported branches instead of drawing guessed rectangles. A stored rectangle can still be replaced at run time by a binding or a container rule.

surfacesupport
stored rectanglesbase X, Y, width and height on verified layout node types
hierarchyconstruction order, import bases, default-profile overrides
local widgetscreate core types, duplicate, reparent, remove, with stable native IDs
container anchorsstored, start, center, end and stretch; margins and size limits
property unitsunscaled floats and screen-height-scaled floats
runtime sizingunresolved branches keep their node and source links
custom containersunresolved unless their children opt out of layout
textEnglish font and style lookup, size, ASCII case, alignment, palette, RGBA tint
bitmapsauthored group and frame selection, decoded textures
bindingslisted per widget; root comparisons editable; evaluated from page inputs

Layout and content edits

Layout values can share one pooled constant. An edit detaches the changed property inside its typed pool, then repairs the pool descriptor and every reference, so other widgets keep their values. Shared component and property arrays are detached before an edit. New fields create typed pools and an empty selector path when needed. An unchanged edit keeps the original bytes. The project stores copy ranges and XOR masks, never a copied resource.

The first hierarchy edit creates a private root resource as a delta of the installed root. It goes into an unused package among the top 256 new package IDs. The hierarchy reference, the resource and the widget name file are one transaction. Undo removes the private additions. Redo restores their tags. Other screens and imported resources keep the originals.

A widget that an authored animation track targets cannot be deleted. Every structural edit checks that each binding still reads the same afterwards, unless it belonged to a removed widget.

Bindings

A binding copies a value from one widget property to another, sometimes through a NOT or a comparison. A resource’s bindings use its own node IDs, so the page maps them through the resource’s placement. An edit points the binding at a new record, so a record shared with other bindings keeps its value.

Studio evaluates bindings only from the inputs set in the page. Comparisons never convert value kinds. A binding whose source kind does not match its transform stays unevaluated. Apply bindings hides a widget whose visibility, property 0x201 of a layout type, comes out false, together with its children.

Widget types

Type inheritance and constructor defaults come from the game’s widget registry. The installed executable is packed and does not expose it, so Studio carries a copy for this build: 390 types, each with its parent and whether its constructor applies the standard 360 x 240 defaults.

Text

DirectWrite validates and bakes the game’s fonts from memory through an isolated loader. Fonts are never installed in Windows. ImGui receives bounded alpha sprites and never parses font outlines.

Latin text uses the game’s break and spacing rules with legacy pair kerning, one UTF-16 character at a time. Modern ligatures and GPOS shaping are off, to match. Auto width and auto height measure the prepared text. Raster edges can differ from the game’s renderer.

Live game state

The game sends one row per CUI object of the watched screen, parent before child. Each row carries the object’s hierarchy tag, node id and name hash. A widget row also carries a widget flag, the state flags, the text key, four rectangle slots and slot 6. The live link owns the transfer.

Studio joins a row to the open hierarchy by two keys:

keygameStudio
hierarchy tagthe tag the widget was built fromthe open hierarchy’s tag
node idthe widget’s construction indexthe composed node’s id

A row with another hierarchy tag belongs to a nested hierarchy. It is counted, never joined. A row whose node id is missing here, or whose name hash differs from the node’s authored name, is counted as a mismatch. A node with no authored name, such as the screen root, joins on its id alone.

Studio treats a widget as shown when its state bit 0x2 is set and every parent row is shown. A row without the widget flag has no state word, so Studio counts it as shown. Visibility, property 0x201, sets bit 0x2. Whether that bit keeps a widget out of the draw is unverified.

A tree cut short at 8,192 rows or 256 levels marks the join partial. A node with no row is then unknown, not unbuilt.

Not shown:

  • nested hierarchies inside the screen
  • live rectangles on the canvas; the canvas keeps the composed layout
  • live binding values

Limits

  • CJK breaks, non-ASCII case maps, inline styles, text shrinking, ellipsis and parent reflow are not supported.