scenario-unity-ui
Unity UI (UI developer)
Expert UI work is a screen that keeps the same shape from a phone in portrait to a 4K monitor, answers mouse, touch, keyboard and gamepad alike, reads clearly, and costs almost nothing while it sits still. An agent gets there by building from code or text, then proving each screen with a capture at every device size, a layout assertion on the same frame, an audit, behavior tests and counters. Target: Unity 6000.3.21f1, uGUI 2.0 (TextMeshPro inside), UI Toolkit, Input System 1.20. If a sibling skill named here is missing from your available skills, ask the user to install it (npx skills add scenario-labs/skills --skill <name>); unattended, proceed from tool schemas and flag the gap.
REQUIRED BACKGROUND: scenario-unity-expert (channels, review loop, 6.3 traps). Toolkit: scripts/ut_ui.py (imports ut_env, ut_run, ut_review), jobs in scripts/AgentKit/UI/, runtime components in scripts/Runtime/UI/ (asmdef AgentUI.Runtime), UXML/USS/TSS templates in scripts/templates/uitk/.
Stance (the expert delta)
- uGUI is still the 6.3 runtime recommendation; the matrix decides. UI Toolkit only: data binding, USS transitions, flexible layout, global styles, dynamic atlas, RTL and emoji, SVG. uGUI only: Animation Clips and Timeline, serialized events, Scene-view authoring (6.3 Manual). Custom shaders (UI Shader Graph) and world space are in BOTH columns in 6.3: never a reason to pick uGUI. No blocker: keep the project's system; UI-heavy or designer-led projects lean UI Toolkit; split by screen when both columns are needed (
ut_ui.choose_system). - One reference resolution, anchored edges, Match chosen by orientation. 1920 x 1080, Scale With Screen Size, Match 0.5 when both orientations exist: with this landscape reference, Match 0 shrinks a portrait phone to 0.5625 (Match 1 inflates it 1.78x); the manual's "1.5x at Match 0" is its portrait reference shown in landscape. uGUI blends Match in log space, UI Toolkit linearly: 1.0 vs 1.17 at 1080 x 1920 (measured). Anchor each element to its corner while the Game view shows the design resolution, keep scale 1 (uGUI manual; Christina). Phones take a handheld multiplier set from a touch-target check (
CanvasDeviceScale, 1.35). - A uGUI Canvas is the rebuild and batch unit. Split static and per-frame content into sub-canvases, remove raycasters from display-only canvases, untick Raycast Target on labels. Canvases never batch with each other: 400 world-space name plates are 400 batches (Andy Touch). Hide with
Canvas.enabled(0 mesh regenerations vs 200 forSetActive, measured) plusCanvasGroup.interactable, or buttons stay navigable. - Layout resolves preferred, else min, else 0. A child with nothing to report collapses under Control Child Size; a Content Size Fitter goes only at the top; the pivot sets growth; no layout groups on per-frame UI. When a size surprises you, read min/preferred/flexible of parent AND children (
UIAudit.ExplainLayout), never toggle checkboxes (Christina, HTQV4mukZ2M). - One selection, one layer table, across both systems. Hover selects, the first selection lands one frame after a screen shows, the last selection is remembered for the gamepad (Sasquatch B Studios). Point a scripted
InputSystemUIInputModuleatInputSystem.actionsor rebinds never reach navigation (measured). Give every layer its own sort order from one table (ut_ui.UI_LAYERS: HUD 0, menus 10, modal 20):Canvas.sortingOrderandPanelSettings.sortingOrderrank against each other (drawing since 2021.2, Unity staff; input measured here); a tie leaves the top layer to Hierarchy order (Christina). Focus crosses systems through the EventSystem:element.Focus()selects the panel,SetSelectedGameObject(uguiButton)blurs it (measured). UI in its own additive scene holding the only EventSystem (Jason Weimann). - Text: effects in the material, one font chain per system. Shadow plus Outline turned 28 triangles into 280; TMP outline and underlay stayed at 30 (measured; Andy Touch). TMP fallbacks never reach UI Toolkit text, which resolves its own font and Panel Text Settings: with a CJK font in TMP Settings, the HUD still missed "設定" (measured). Gate every locale per system with tryAdd on; all fallback assets share one sampling size and padding (about a tenth); CJK split across assets; RTL means UI Toolkit (Imphenzia). Code-filled drop-downs refill on the locale event (
SettingsScreen.OnLocaleChanged). - UI Toolkit costs follow GPU state and time hidden. At most 8 textures per batch (measured ceil(N/8)); a static panel split across vertex buffers draws twice: raise Vertex Budget (12k vertices: 3 batches at 0, 1 at 20000, measured); stencil masks break batches, so pre-cut a round minimap frame; animate transforms with usage hints; no class toggles on big containers;
[GeneratePropertyBag]works only with the assembly attribute too (class alone gave a reflected bag, measured) (Nicolas Borromeo, Unity). Hide by duration: removal for long absences, display none in between (bindings keep running), opacity or off-screen for blinking (ut_ui.uitk_hide_method, costs in procedures P16). Find idle invalidations withPanelChangeLog; a stylesheet loads every asset it references. - Capture the UI the way it renders, then assert on the same frame. Overlay canvases never reach a camera target (0 UI pixels, measured): capture uGUI through Screen Space Camera on a hidden camera, UI Toolkit through a cloned PanelSettings with
targetTexture. Look at every sheet, including a 4K crop.