2 ui layout
forgejo-actions edited this page 2026-07-11 10:33:50 +00:00

UI Layout

What This System Is

UI layout is Aether's authored UI document system. Authors edit .aetherui source files, the editor validates them against slot contracts and skin references, and runtime consumes the authored documents through shared layout and binding descriptors.

The built-in layout source files live under assets/ui/layouts/*.aetherui. They are JSON documents with the current UI layout format version, design size, and a rooted UiLayoutNode tree.

How Authors Use It

The schema-owned asset manifest lists the built-in layout assets and their authored surface. There are two surfaces:

  • gameplay: in-world and player HUD layouts.
  • standalone: title, login, realm, character, loading, and death screens.

Current gameplay layouts are system_menu, chat_hud, hotbar_hud, emote_panel, keybind_menu, inventory_panel, armoury_panel, character_panel, journal_panel, and npc_service_panel.

Current standalone layouts are standalone_title, standalone_login, standalone_realm_select, standalone_character_create, standalone_character_select, standalone_loading, and standalone_death.

The asset manifest in src/ui_layout/schema.rs owns the stable asset id, label, asset path, surface, export policy, and bundled fallback bytes for each built-in document.

Document Model

A layout document has a root node and stable runtime dimensions. The root node size is the runtime width and height, with a safe minimum of one pixel.

Each UiLayoutNode records its id, authored slot string, display name, node kind, rectangle, min/max size, text, skin key, font, stack layout mode, anchors, auto-size flag, and children. Supported node kinds are container, panel, button, label, text input, and image.

Layout versions migrate in memory when possible. Future versions are rejected so an older runtime does not silently reinterpret new layout data.

Rules And Invariants

Slot contracts are table-driven in src/ui_layout/slots/manifest.rs and exposed through UiLayoutSlotDescriptor. A slot descriptor owns:

  • Stable UiLayoutSlotId
  • Owning layout asset
  • Authored slot string
  • Required flag
  • Default label
  • Optional gameplay binding
  • Optional runtime action
  • Optional dynamic text role
  • Optional text input role
  • Optional runtime-owned region role

Slot strings are the authored handshake between a .aetherui node and runtime behavior. Treat them as stable API. Renaming a slot requires updating the slot manifest, default/bundled documents, runtime adapters, validation expectations, and any localization or template references that mention the old slot.

Validation reports missing required slots and duplicate resolved slots for both gameplay and standalone layouts. Optional slots may be absent, but if they appear more than once they still violate the contract.

Skin References

Node skin values are semantic keys, not texture paths. Node kinds declare whether they support frame/button skins, button-only skins, image-only skins, or no skin.

Validation resolves authored skin keys through the UI skin manifest. It reports unknown skin names, missing skin textures, and node-kind/skin-family mismatches. Labels ignore skins, so a label with a non-empty skin is reported as a warning.

When a layout references a skin, layout dependency extraction includes the relevant skin key catalog and resolved skin texture dependencies. That is what makes skin changes participate in stale-cache and bake decisions.

Generated Manifests

assets/ui/layouts/manifest.json is generated from UiLayoutAssetDescriptor rows. Do not hand-edit it. Update the descriptor rows in src/ui_layout/schema.rs, then run the generated-artifact workflow so the checked-in manifest matches the schema.

The editor also loads ui/layout_templates.json through the UI layout authoring manifest. Templates are insert-time authoring helpers; they do not replace the required slot manifest.

Validation And Debugging

The authoring bake product is ui.layout.runtime_cache. It writes runtime/ui/ui_layout_runtime_cache.json with schema version 1.

The runtime cache contains a validation summary and one record per included layout: id, asset path, label, surface, export policy, required slots, and the full authored document. The baker includes every UiLayoutAssetId::ALL document whose export policy is included in runtime cache output.

Default bake inputs load the current .aetherui source document for each built-in asset and capture a dependency signature for that path. The product invalidation key is ui/layouts/*.aetherui; changes to layout source files invalidate the runtime cache. The broader authored asset dependency graph also tracks templates, fonts, skin key catalogs, and skin textures used by a layout.

After changing a layout source or manifest descriptor, run:

cargo run --bin aether-bake -- --fail-on-diagnostics

Use the generated-artifact gate when changing assets/ui/layouts/manifest.json or descriptor rows.

Editor And Runtime Consumption

The editor consumes source documents and the UI layout authoring manifest so authors can browse assets, slots, and insert templates. Preview uses the shared resolver and binding descriptors, which keeps editor feedback close to runtime behavior.

Runtime consumes authored documents through shared resolution and renderer paths. Gameplay UI registers the gameplay layout surfaces and dispatches gameplay slot actions into gameplay UI commands. Standalone screens load their standalone layout assets and map standalone actions, dynamic text roles, and text-input roles through the slot manifest.

Editor code may rewrite or save .aetherui source files. Runtime code should not mutate source documents; it should consume baked cache records or bundled fallbacks and report diagnostics when required contracts are not satisfied.

Examples

  1. Edit the .aetherui source file under assets/ui/layouts.
  2. Keep required slot strings present and unique.
  3. Use skin keys supported by the node kind.
  4. If adding a runtime behavior, add a slot manifest descriptor and runtime action or role.
  5. If adding a new built-in layout, add an asset descriptor and regenerate assets/ui/layouts/manifest.json.
  6. Bake with diagnostics before runtime testing.