Show navigation
Interface layout
A screen's interface is laid out by the game's own tree. Unity places every piece of an interface with a RectTransform: two anchors as shares of its parent's box, a pivot as a share of its own, the pivot's offset from the anchors (the anchored position) and how far its size strays from the anchors' span (the size delta). A screen's markup follows that tree piece for piece, so a piece sits inside its game parent and inherits its anchoring, and a fix to a parent reaches everything in it. On the login screen the foot, Bottom, is anchored to the screen's bottom, and the loading row, the account, the build string and both button columns ride in it on any window.
How it works
flowchart LR EX["genshin:assets interface"] --> TREE["interface.json: the screen's RectTransform tree"] TREE --> FIT["fit: fitInterfaceRects"] FIT -->|"rects by path, a layout group's children left out"| DATA["data/<screen>/interfaceRects.json"] DATA --> RECT["GameRect: nested in the nearest GameRect, or on the canvas"] RECT --> CSS["toCanvasRectStyle: absolute + calc"] MEASURED["A prefab, a group's spacing, a text line: measured"] --> LEAF["Scoped CSS inside the GameRect holding it"] RECT --> LEAF
- The tree is data beside the screen.
genshin:assets interfaceexports the screen's RectTransforms from the game's block, outside the repository like every other reference. The screen'sfitturns it intointerfaceRects.jsonwithfitInterfaceRects: every piece's anchors, pivot, position and size in canvas units, and its scale where it is not one, keyed by its path under the interface's root. The root is the canvas itself, so it is left out. - One component nests the tree.
GameRecttakes a piece's rect and draws a box placed by it inside its game parent's box, or on the canvas when itsparentis the canvas's own rect, which is the default for a root. A nested piece takes its parent's resolved rect explicitly: the parent exposes it as a slot prop,<GameRect v-slot="{ rect: centerRect }" ...>, and the child passes it as:parent="centerRect". The markup reads as the game's tree:<GameRect :rect="interfaceRects['GrpLogin/Bottom']">holds theGameRectofGrpLogin/Bottom/CurrentAccount, which holds that of its build string. - The browser is the layout engine. A RectTransform's corners are its anchors' points in the parent plus
offsetMin = anchoredPosition − sizeDelta × pivotandoffsetMax = offsetMin + sizeDelta, which absolute positioning withcalc()expresses exactly (toCanvasRectStyle, overcomputeRectOffsets), at no cost per piece. A layout engine of its own (Yoga, Taffy) would lay out a different model and need Unity's rebuilt on top of it. - A layout group's children are left out. A
GridLayoutGroupplaces its children at run time, so their rects read zero; the fit keeps the group's own rect and drops everything under it, and the group's stacking and spacing are scoped CSS on itsGameRect, measured off a recording. - What the tree cannot hold is measured inside the piece holding it. A prefab the page loads at run time, such as the door's prompt in
BtnPressStart, has no rect in the page's block, and a script that resizes a piece at run time (the age rating's layout adaptor) makes its rect a container only. Each is measured on a recording and written as CSS inside theGameRectit loads into, so it still rides with its parent. A line of text is set by the game's text component at run time, so its place inside its rect is measured too. - The game's clips play on the same tree. Each
GameRecta clip moves carries its path under the clips' root as itsdata-clip-target, so a fade the game plays on a parent fades everything the markup nests in it, as the door's prompt fades withCenter/SwitchServer.
Notes
- A measured leaf is written from its parent's box, such as the prompt's
calc(var(--unit) * 38 - var(--canvas-unit) * 128)from a container standing 128 canvas units in. The measure stays the one taken off the recording, and the parent's term keeps it where the recording shows on any window. - A layout component has no image.
GameRectandGameScreendraw nothing of their own, so the interface library's suite exempts them from the fixture every other component owes.
Key files
| File | Role |
|---|---|
scripts/src/services/genshinAssets/interface/extractComponentInterface.ts | The screen's RectTransform tree, exported from its block |
scripts/src/services/genshinAssets/fit/fitInterfaceRects.ts | The tree as rects keyed by path, a group's children out |
packages/genshin-world/src/data/login/interfaceRects.json | The login page's fitted rects |
packages/genshin-interface/src/components/GameRect/Index.vue | A piece placed by its rect inside its parent's, or the canvas |
packages/genshin-interface/src/services/toCanvasRectStyle.ts | Unity's RectTransform as CSS, the one layout computation |
packages/genshin-world/src/components/Login/Interface/Index.vue | The login's interface, nested as the game's tree |
Scroll to top