Concept: Policy & Layout Architecture

CrimsonUI follows the Lyra/CommonGame three-tier pattern: a manager subsystem owns a policy, the policy owns one root layout per local player, and everything you ever see is a widget pushed onto a tag-keyed layer inside a root layout. The base types live in CrimsonCommon so any plugin can push UI; CrimsonUI supplies the concrete manager and settings that boot them.

The chain, start to pixel

StageType (plugin)What happens
1. Game instance initUCrimsonUIManagerSubsystem (CrimsonUI)Initialize loads UCrimsonUISettings::DefaultUIPolicyClass and creates the policy. It also subscribes to the game instance's player-added/removed events - which only exist on UCrimsonCommonGameInstance.
2. Player joinsUCrimsonGameUIManagerSubsystem (CrimsonCommon)NotifyPlayerAdded fires per local player - but only for UCrimsonCommonLocalPlayer subclasses - and forwards to the policy.
3. Layout creationUCrimsonGameUIPolicy (CrimsonCommon)Instantiates LayoutClass for the player and adds it to the viewport, honoring LocalMultiplayerInteractionMode.
4. Layer registrationUCrimsonPrimaryGameLayout (CrimsonCommon)Your subclass registers a UCommonActivatableWidgetContainerBase (usually a stack) per UI.Layer.* tag.
5. ScreensUCrimsonUIExtensions / PushWidgetToLayerStackEverything else is a push onto a registered layer.

Layers are a convention, not a fixed set

A layer is any tag under UI.Layer you register a stack for. The recommended set and their contracts:

LayerContractDefined by
UI.Layer.GameThe HUD layout; exactly one widget, pushed at startup, never popped.Your project (tag ini)
UI.Layer.GameMenuIn-game screens that coexist with gameplay (inventory, map).Your project (tag ini)
UI.Layer.MenuPause/system menus. The escape handler pushes here.CrimsonUI (native tag)
UI.Layer.ModalDialogs and errors. The messaging subsystem pushes here.CrimsonUI (native tag)
UI.Layer.ContextMenuContext menus. The context-menu subsystem pushes here.CrimsonCommon (native tag)

Because layers are separate stacks, pushing a menu does not disturb the HUD below it, and each stack restores its previous top widget when the current one deactivates. Stacking order on screen is simply the order of the stacks in your root layout's widget tree.

Local multiplayer

ECrimsonLocalMultiplayerInteractionMode on the policy: PrimaryOnly gives only the first local player a layout; SingleToggle keeps one interactive layout that can be handed between players (RequestPrimaryControl); Simultaneous gives every local player a full layout (split-screen co-op). Each layout is added to that player's own viewport slot.

Odds and ends worth knowing

  • The manager runs a ticker mirroring AHUD::bShowHUD onto the root layout's visibility - the console command ShowHUD therefore hides the whole CommonUI stack too.
  • The policy class is loaded once at game-instance init; editing DefaultUIPolicyClass requires a PIE restart.
  • GetPrimaryGameLayout and GetCurrentUIPolicy are C++-only; Blueprint goes through UCrimsonUIExtensions.
  • Dedicated servers create no layouts - every entry point above is local-player driven.