Skip to content

Architecture

How Tick UI is put together internally and where each concern lives in the source tree. Read this once you understand the immediate-mode GUI model, the frame lifecycle, and the stacks Tick UI maintains per frame.

Frame lifecycle summary

A frame runs in three phases: BeginFrame(), then user draw code, then EndFrame(). BeginFrame updates input, resolves the hovered panel (blocking panels sorted to the end of the list, then a single walk in which the last matching panel wins), and seeds the rect stack with a full-screen rect. EndFrame flushes the visible user-scene panels' draw commands, then the debugger-scene panels, then asserts the stacks are balanced.

For the full breakdown, refer to Frame lifecycle.

The UI partial class

Tick UI's public API lives across many files in Source/Interface/, each carrying one concern: layout, panels, buttons, drawing, animation, and so on. They all extend the same UI partial class.

Panels

Persistent named containers identified by string.GetHashCode(). Each panel tracks visibility (Visible, Hiding, Hidden), its draw command list, and the index of the last frame it was used (LastUsedFrame). Use IsPanelFirstShown() to detect first-frame initialisation.

For the full panel workflow, refer to Panels and modals.

Layout stack

Layout is a Stack<LayoutRect>. Every PushRect, Pad, Center, and Inset call pushes; Pop() removes one. Layout schemas (PushSeries*, PushStack*, PushSized*) push a container plus a current-element rect; advance with Next(), terminate with Pop().

For the full breakdown of every stack Tick UI maintains, refer to Stacks.

Render integration

IDrawer abstracts the renderer. Three integration paths exist: URP (TickURPInjector plus TickRenderPass), Built-in (TickBIRPInjector), and a pipeline-agnostic RenderTexture path (TickRenderTextureInjector) for in-world UI. All three forward draw recording through an TickRecorder subclass, typically BaseGameUI.

Input

IInput abstracts input. InputSystemProvider (new Input System) or InputLegacy is selected at compile time via #if ENABLE_INPUT_SYSTEM.