Skillsunity-game-ui-toolkit-design-skill
U

unity-game-ui-toolkit-design-skill

A skill for game UI design using Unity's UI Toolkit (USS/UXML/Flexbox). This comprehensive game UI design guide covers implementation patterns for game UI elements like HUD, health bars, inventory, dialogs, screen scaling with PanelSettings, and Safe Area support.

akiojin
9 stars
1.2k downloads
Updated 5d ago

Readme

unity-game-ui-toolkit-design-skill follows the SKILL.md standard. Use the install command to add it to your agent stack.

---
name: unity-game-ui-toolkit-design
description: Game UI design using Unity's UI Toolkit (USS/UXML/Flexbox). Includes game UI elements like HUD, health bars, inventory, skill bars, PanelSettings scaling, and Safe Area support. Use when: game UI design, HUD creation, USS/UXML styling, Flexbox layout, PanelSettings configuration
allowed-tools:
  - mcp__unity-mcp-server__find_ui_elements
  - mcp__unity-mcp-server__click_ui_element
  - mcp__unity-mcp-server__get_ui_element_state
  - mcp__unity-mcp-server__set_ui_element_value
  - mcp__unity-mcp-server__simulate_ui_input
  - mcp__unity-mcp-server__add_component
  - mcp__unity-mcp-server__modify_component
  - mcp__unity-mcp-server__set_component_field
  - mcp__unity-mcp-server__list_components
  - mcp__unity-mcp-server__create_gameobject
  - mcp__unity-mcp-server__modify_gameobject
  - mcp__unity-mcp-server__find_gameobject
  - mcp__unity-mcp-server__manage_asset_database
  - mcp__unity-mcp-server__edit_structured
  - mcp__unity-mcp-server__create_class
  - mcp__unity-mcp-server__read
  - mcp__unity-mcp-server__get_symbols
---

# Unity Game UI Toolkit Design Skill

A skill for game UI design using Unity's UI Toolkit (USS/UXML/Flexbox). This comprehensive game UI design guide covers implementation patterns for game UI elements like HUD, health bars, inventory, dialogs, screen scaling with PanelSettings, and Safe Area support.

## Overview

UI Toolkit is Unity's next-generation UI system that builds UIs with an approach similar to web technologies (HTML/CSS).

| Feature | Details |
|---------|---------|
| Layout Engine | Yoga (CSS Flexbox subset implementation) |
| Styling | USS (Unity Style Sheets, CSS-like) |
| Markup | UXML (HTML-like) |
| Supported Version | Unity 2021.2+ (Unity 6.0+ recommended) |
| Use Cases | Game UI, Editor extensions |

## Game UI Types

Game UIs are classified into 4 types based on purpose and presentation method. Before starting implementation, clarify which type your UI belongs to.

### 1. Diegetic

UI that physically exists within the game world. Characters can also perceive it.

| Example | Game |
|---------|------|
| HP bar on suit's back | Dead Space |
| Car dashboard | Racing Games |
| Ammo count on weapon | Metro Exodus |
| Handheld map | Far Cry 2 |

```xml
<!-- UXML - Diegetic UI (placed in 3D space) -->
<ui:VisualElement class="diegetic-display">
    <ui:VisualElement class="diegetic-display__screen">
        <ui:Label class="diegetic-display__value" text="87" />
        <ui:Label class="diegetic-display__unit" text="%" />
    </ui:VisualElement>
</ui:VisualElement>
```

### 2. Non-Diegetic

Screen overlay. Pure player-facing information that characters cannot perceive.

| Example | Placement |
|---------|-----------|
| HP bar | Top-left |
| Minimap | Top-right |
| Skill bar | Bottom-center |
| Quest objectives | Right side |

```xml
<!-- UXML - Non-Diegetic HUD structure -->
<ui:VisualElement class="hud">
    <!-- Top-left: Player status -->
    <ui:VisualElement class="hud__top-left">
        <ui:VisualElement class="health-bar" />
        <ui:VisualElement class="mana-bar" />
    </ui:VisualElement>

    <!-- Top-right: Minimap -->
    <ui:VisualElement class="hud__top-right">
        <ui:VisualElement class="minimap" />
    </ui:VisualElement>

    <!-- Bottom-center: Action bar -->
    <ui:VisualElement class="hud__bottom-center">
        <ui:VisualElement class="action-bar" />
    </ui:VisualElement>
</ui:VisualElement>
```

### 3. Spatial

UI that exists within the game world but characters cannot perceive.

| Example |
|---------|
| HP bar above enemy's head |
| NPC name display |
| Interactable object icons |
| Path guide lines |

### 4. Meta

Expresses game state through screen effects. Not direct UI elements.

| Example | Representation |
|---------|----------------|
| Damage | Red vignette at screen edges |
| Low HP | Red pulse across entire screen |
| Status effects | Screen distortion/color changes |
| Underwater | Blue overlay |

```css
/* USS - Meta effect */
.meta-overlay {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(255, 0, 0, 0);
    transition-duration: 0.3s;
}

.meta-overlay--damage {
    background-color: rgba(255, 0, 0, 0.3);
}

.meta-overlay--low-health {
    /* Pulse animation */
}
```

## HUD Screen Layout

Game HUDs have established placement conventions. Players unconsciously expect this layout.

```
┌─────────────────────────────────────────────────────┐
│ [HP/MP/Status]                    [Minimap/Compass] │
│ [Buff/Debuff icons]               [Quest Objectives]│
│                                                     │
│                     Game Screen                     │
│                    (Focus Area)                     │
│                                                     │
│ [Chat]                                              │
│ [Log/Notifications]  [Skill Bar/Items] [Quick Slots]│
└─────────────────────────────────────────────────────┘
```

### Placement Principles

| Area | Elements | Reason |
|------|----------|--------|
| **Top-left** | HP, MP, Stamina | Most important status, gaze naturally goes there |
| **Top-right** | Minimap, Compass | Navigation info, frequently checked |
| **Bottom-center** | Skill bar, Action bar | Feels close to hands, corresponds to keyboard layout |
| **Bottom-right** | Inventory, Quick slots | Secondary info, affinity with mouse operation |
| **Bottom-left** | Chat, Log | Text info, social elements |
| **Right side vertical** | Quest objectives, Notifications | Additional info, temporary display |
| **Screen center** | Avoid | Don't obstruct gameplay visibility |

```css
/* USS - HUD grid layout */
.hud {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
}

.hud__top-left {
    position: absolute;
    left: 16px;
    top: 16px;
}

.hud__top-right {
    position: absolute;
    right: 16px;
    top: 16px;
}

.hud__bottom-center {
    position: absolute;
    left: 50%;
    bottom: 16px;
    translate: -50% 0;
}

.hud__bottom-left {
    position: absolute;
    left: 16px;
    bottom: 16px;
}

.hud__bottom-right {
    position: absolute;
    right: 16px;
    bottom: 80px; /* Above action bar */
}

.hud__right-side {
    position: absolute;
    right: 16px;
    top: 200px;
    width: 250px;
}
```

## Quick Start

### Basic UIDocument Setup

```javascript
// 1. Create GameObject with UIDocument
mcp__unity-mcp-server__create_gameobject({
  name: "UIManager"
})

// 2. Add UIDocument component
mcp__unity-mcp-server__add_component({
  gameObjectPath: "/UIManager",
  componentType: "UIDocument"
})

// 3. Configure PanelSettings
mcp__unity-mcp-server__set_component_field({
  gameObjectPath: "/UIManager",
  componentType: "UIDocument",
  fieldPath: "panelSettings",
  valueType: "objectReference",
  objectReference: {
    assetPath: "Assets/UI/PanelSettings.asset"
  }
})
```

## Core Concepts

### 1. PanelSettings (Screen Scaling)

PanelSettings is equivalent to uGUI's Canvas Scaler and controls UI scaling based on screen size.

#### Scale Mode List

| Mode | Use Case | Features |
|------|----------|----------|
| Constant Pixel Size | Desktop | 1:1 pixel correspondence (default) |
| Constant Physical Size | Multi-DPI | DPI independent, constant physical size |
| Scale With Screen Size | Mobile | Scales relative to reference resolution |

#### Scale With Screen Size Settings

```csharp
// PanelSettings configuration example
[CreateAssetMenu(menuName = "UI/Panel Settings")]
public class ResponsivePanelSettings : ScriptableObject
{
    // Create PanelSettings asset and configure:
    // Scale Mode: Scale With Screen Size
    // Reference Resolution: 1080 x 1920 (Portrait) or 1920 x 1080 (Landscape)
    // Screen Match Mode: Match Width Or Height
    // Match: 0 (Width priority for Portrait) / 1 (Height priority for Landscape)
}
```

#### Runtime Match Switching

```csharp
// OrientationScaleHandler.cs
using UnityEngine;
using UnityEngine.UIElements;

public class OrientationScaleHandler : MonoBehaviour
{
    [SerializeField] private PanelSettings panelSettings;
    private ScreenOrientation lastOrientation;

    void Update()
    {
        if (Screen.orientation != lastOrientation)
        {
            bool isPortrait = Screen.height > Screen.width;
            panelSettings.match = isPortrait ? 0f : 1f;
            lastOrientation = Screen.orientation;
        }
    }
}
```

### 2. Flexbox Layout

UI Toolkit uses the Yoga (Flexbox) layout engine. Web developers will find this CSS layout model familiar.

#### flex-direction

```css
/* USS - Vertical layout (default) */
.vertical-container {
    flex-direction: column;
}

/* USS - Horizontal layout */
.horizontal-container {
    flex-direction: row;
}
```

#### flex-grow / flex-shrink / flex-basis

```css
/* USS - Equal distribution */
.equal-child {
    flex-grow: 1;
    flex-basis: 0;  /* Ignore content size for equal distribution */
}

/* USS - Fixed size + flexible */
.fixed-header {
    flex-grow: 0;
    flex-shrink: 0;
    height: 60px;
}

.flexible-content {
    flex-grow: 1;
    flex-shrink: 1;
}
```

#### Percentage-based Sizing

```css
/* USS - Responsive sizing */
.responsive-panel {
    width: 80%;
    height: 100%;
    max-width: 600px;
}

.half-width {
    width: 50%;
}
```

#### align-items / justify-content

```css
/* USS - Center alignment */
.center-container {
    align-items: center;      /* Cross-axis center */
    justify-content: center;  /* Main-axis center */
}

/* USS - Space between + equal spacing */
.space-between-container {
    justify-content: space-between;
}

/* USS - End alignment */
.end-aligned {
    align-items: flex-end;
    justify-content: flex-end;
}
```

### 3. USS (Unity Style Sheets)

Define styles with CSS-like syntax.

#### Basic Syntax

```css
/* USS - Selector types */
.class-selector { }      /* Class selector */
#name-selector { }       /* Name selector */
Button { }               /* Type selector */
.parent > .child { }     /* Direct child selector */
.parent .descendant { }  /* Descendant selector */
.element:hover { }       /* Pseudo-class */
```

#### BEM Naming Convention

```css
/* Block */
.menu { }

/* Element */
.menu__item { }
.menu__title { }

/* Modifier */
.menu--horizontal { }
.menu__item--active { }
.menu__item--disabled { }
```

### 4. UXML (UI Markup Language)

Define UI structure with HTML-like syntax.

```xml
<?xml version="1.0" encoding="utf-8"?>
<ui:UXML xmlns:ui="UnityEngine.UIElements">
    <ui:VisualElement class="root">
        <ui:VisualElement class="header">
            <ui:Label text="Title" class="header__title" />
        </ui:VisualElement>

        <ui:VisualElement class="content">
            <ui:ScrollView class="content__scroll">
                <ui:VisualElement class="content__list">
                    <!-- Dynamic items -->
                </ui:VisualElement>
            </ui:ScrollView>
        </ui:VisualElement>

        <ui:VisualElement class="footer">
            <ui:Button text="Action" class="footer__button" />
        </ui:VisualElement>
    </ui:VisualElement>
</ui:UXML>
```

## Mobile Responsive Design

### Responsive Layout Structure

```css
/* USS - Mobile responsive basic structure */
.root {
    flex-grow: 1;
    flex-direction: column;
}

.header {
    flex-shrink: 0;
    height: 60px;
    flex-direction: row;
    align-items: center;
    padding: 0 16px;
}

.content {
    flex-grow: 1;
    flex-shrink: 1;
}

.footer {
    flex-shrink: 0;
    height: 80px;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    padding: 0 16px;
}
```

### Safe Area Support

UI Toolkit requires coordinate system conversion (Screen.safeArea uses bottom-left origin, UI Toolkit uses top-left origin).

```csharp
// SafeAreaController.cs
using UnityEngine;
using UnityEngine.UIElements;

public class SafeAreaController : MonoBehaviour
{
    private UIDocument uiDocument;
    private VisualElement safeAreaContainer;
    private Rect lastSafeArea;

    void Start()
    {
        uiDocument = GetComponent<UIDocument>();
        safeAreaContainer = uiDocument.rootVisualElement.Q<VisualElement>("safe-area");
        ApplySafeArea();
    }

    void Update()
    {
        if (Screen.safeArea != lastSafeArea)
        {
            ApplySafeArea();
        }
    }

    void ApplySafeArea()
    {
        Rect safeArea = Screen.safeArea;
        lastSafeArea = safeArea;

        // Convert to UI Toolkit coordinate system (top-left origin)
        float left = safeArea.x;
        float right = Screen.width - (safeArea.x + safeArea.width);
        float top = Screen.height - (safeArea.y + safeArea.height);
        float bottom = safeArea.y;

        // Consider PanelSettings scale
        var panelSettings = uiDocument.panelSettings;
        float scale = GetCurrentScale(panelSettings);

        safeAreaContainer.style.paddingLeft = left / scale;
        safeAreaContainer.style.paddingRight = right / scale;
        safeAreaContainer.style.paddingTop = top / scale;
        safeAreaContainer.style.paddingBottom = bottom / scale;
    }

    float GetCurrentScale(PanelSettings settings)
    {
        // Calculate scale for Scale With Screen Size
        if (settings.scaleMode == PanelScaleMode.ScaleWithScreenSize)
        {
            var refRes = settings.referenceResolution;
            float widthRatio = Screen.width / refRes.x;
            float heightRatio = Screen.height / refRes.y;
            return Mathf.Lerp(widthRatio, heightRatio, settings.match);
        }
        return 1f;
    }
}
```

```css
/* USS - Safe Area container */
#safe-area {
    flex-grow: 1;
    /* padding is set dynamically from C# */
}
```

### Dynamic Layout Switching (Media Query Alternative)

UI Toolkit doesn't support CSS @media queries, so switch styles dynamically with C#.

```csharp
// ResponsiveLayoutController.cs
using UnityEngine;
using UnityEngine.UIElements;

public class ResponsiveLayoutController : MonoBehaviour
{
    private UIDocument uiDocument;
    private VisualElement root;
    private bool wasPortrait;

    void Start()
    {
        uiDocument = GetComponent<UIDocument>();
        root = uiDocument.rootVisualElement;
        ApplyOrientationLayout();
    }

    void Update()
    {
        bool isPortrait = Screen.height > Screen.width;
        if (isPortrait != wasPortrait)
        {
            ApplyOrientationLayout();
            wasPortrait = isPortrait;
        }
    }

    void ApplyOrientationLayout()
    {
        bool isPortrait = Screen.height > Screen.width;

        root.RemoveFromClassList("landscape");
        root.RemoveFromClassList("portrait");
        root.AddToClassList(isPortrait ? "portrait" : "landscape");

        // Layout based on screen width
        float screenWidth = Screen.width;
        root.RemoveFromClassList("narrow");
        root.RemoveFromClassList("wide");

        if (screenWidth < 600)
        {
            root.AddToClassList("narrow");
        }
        else
        {
            root.AddToClassList("wide");
        }
    }
}
```

```css
/* USS - Orientation-based styles */
.portrait .sidebar {
    display: none;
}

.landscape .sidebar {
    display: flex;
    width: 250px;
}

/* USS - Screen width-based styles */
.narrow .content__grid {
    flex-direction: column;
}

.wide .content__grid {
    flex-direction: row;
    flex-wrap: wrap;
}

.narrow .card {
    width: 100%;
}

.wide .card {
    width: 48%;
    margin: 1%;
}
```

## Game UI Elements Implementation

### 1. Health Bar / Resource Bar

```xml
<!-- UXML - Health bar -->
<ui:VisualElement class="resource-bar health-bar">
    <ui:VisualElement class="resource-bar__background">
        <ui:VisualElement class="resource-bar__fill" name="health-fill" />
        <ui:VisualElement class="resource-bar__delayed-fill" name="health-delayed" />
    </ui:VisualElement>
    <ui:Label class="resource-bar__text" name="health-text" text="100/100" />
</ui:VisualElement>
```

```css
/* USS - Resource bar */
.resource-bar {
    width: 200px;
    height: 24px;
    flex-direction: row;
    align-items: center;
}

.resource-bar__background {
    flex-grow: 1;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    border-radius: 4px;
    overflow: hidden;
}

.resource-bar__fill {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 100%;
    background-color: #e74c3c;
    transition-duration: 0.2s;
}

.resource-bar__delayed-fill {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 100%;
    background-color: #c0392b;
    transition-duration: 0.5s;
    transition-delay: 0.3s;
}

.resource-bar__text {
    position: absolute;
    left: 0;
    right: 0;
    -unity-text-align: middle-center;
    color: white;
    font-size: 12px;
    text-shadow: 1px 1px 2px black;
}

/* Variations */
.mana-bar .resource-bar__fill {
    background-color: #3498db;
}

.stamina-bar .resource-bar__fill {
    background-color: #2ecc71;
}

.xp-bar .resource-bar__fill {
    background-color: #9b59b6;
}
```

```csharp
// ResourceBarController.cs
public class ResourceBarController
{
    private VisualElement fill;
    private VisualElement delayedFill;
    private Label text;

    public void SetValue(float current, float max)
    {
        float percent = current / max;
        fill.style.width = Length.Percent(percent * 100);
        delayedFill.style.width = Length.Percent(percent * 100);
        text.text = $"{(int)current}/{(int)max}";
    }
}
```

### 2. Skill Cooldown

```xml
<!-- UXML - Skill slot -->
<ui:VisualElement class="skill-slot">
    <ui:VisualElement class="skill-slot__icon" />
    <ui:VisualElement class="skill-slot__cooldown-overlay" name="cooldown-overlay" />
    <ui:Label class="skill-slot__cooldown-text" name="cooldown-text" />
    <ui:Label class="skill-slot__keybind" text="Q" />
</ui:VisualElement>
```

```css
/* USS - Skill slot */
.skill-slot {
    width: 64px;
    height: 64px;
    margin: 4px;
    background-color: rgba(0, 0, 0, 0.6);
    border-width: 2px;
    border-color: #555;
    border-radius: 8px;
}

.skill-slot__icon {
    position: absolute;
    left: 4px;
    top: 4px;
    right: 4px;
    bottom: 4px;
    background-image: resource("Icons/skill_placeholder");
}

.skill-slot__cooldown-overlay {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.7);
    /* Circular mask implemented with shader */
}

.skill-slot__cooldown-text {
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    translate: 0 -50%;
    -unity-text-align: middle-center;
    font-size: 20px;
    color: white;
    -unity-font-style: bold;
}

.skill-slot__keybind {
    position: absolute;
    right: 2px;
    bottom: 2px;
    font-size: 12px;
    color: #aaa;
    background-color: rgba(0, 0, 0, 0.5);
    padding: 2px 4px;
    border-radius: 2px;
}

.skill-slot--ready {
    border-color: #f39c12;
}

.skill-slot--active {
    border-color: #2ecc71;
    border-width: 3px;
}
```

### 3. Inventory Grid

```xml
<!-- UXML - Inventory -->
<ui:VisualElement class="inventory-panel">
    <ui:VisualElement class="inventory-panel__header">
        <ui:Label text="Inventory" class="inventory-panel__title" />
        <ui:Button class="inventory-panel__close" text="×" />
    </ui:VisualElement>
    <ui:VisualElement class="inventory-panel__grid" name="inventory-grid">
        <!-- Dynamically generated -->
    </ui:VisualElement>
    <ui:VisualElement class="inventory-panel__footer">
        <ui:Label name="gold-label" text="Gold: 0" />
        <ui:Label name="weight-label" text="Weight: 0/100" />
    </ui:VisualElement>
</ui:VisualElement>
```

```css
/* USS - Inventory */
.inventory-panel {
    width: 400px;
    background-color: rgba(20, 20, 30, 0.95);
    border-width: 2px;
    border-color: #444;
    border-radius: 8px;
}

.inventory-panel__header {
    height: 40px;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    padding: 0 12px;
    background-color: rgba(0, 0, 0, 0.3);
    border-bottom-width: 1px;
    border-bottom-color: #333;
}

.inventory-panel__grid {
    flex-direction: row;
    flex-wrap: wrap;
    padding: 8px;
}

.inventory-slot {
    width: 48px;
    height: 48px;
    margin: 2px;
    background-color: rgba(0, 0, 0, 0.4);
    border-width: 1px;
    border-color: #333;
    border-radius: 4px;
}

.inventory-slot:hover {
    border-color: #666;
    background-color: rgba(255, 255, 255, 0.1);
}

.inventory-slot--selected {
    border-color: #f39c12;
    border-width: 2px;
}

.inventory-slot__icon {
    position: absolute;
    left: 4px;
    top: 4px;
    right: 4px;
    bottom: 12px;
}

.inventory-slot__count {
    position: absolute;
    right: 2px;
    bottom: 2px;
    font-size: 10px;
    color: white;
    background-color: rgba(0, 0, 0, 0.6);
    padding: 1px 3px;
    border-radius: 2px;
}

/* Item rarity */
.inventory-slot--common { border-color: #aaa; }
.inventory-slot--uncommon { border-color: #2ecc71; }
.inventory-slot--rare { border-color: #3498db; }
.inventory-slot--epic { border-color: #9b59b6; }
.inventory-slot--legendary { border-color: #f39c12; }
```

### 4. Damage Numbers (Floating Text)

```csharp
// DamageNumberController.cs
using UnityEngine;
using UnityEngine.UIElements;

public class DamageNumberController : MonoBehaviour
{
    [SerializeField] private UIDocument uiDocument;
    [SerializeField] private VisualTreeAsset damageNumberTemplate;

    public void SpawnDamageNumber(Vector3 worldPos, int damage, DamageType type)
    {
        var root = uiDocument.rootVisualElement;
        var damageLabel = damageNumberTemplate.Instantiate();

        var label = damageLabel.Q<Label>("damage-text");
        label.text = damage.ToString();

        // Style based on damage type
        switch (type)
        {
            case DamageType.Critical:
                label.AddToClassList("damage-number--critical");
                label.text = damage.ToString() + "!";
                break;
            case DamageType.Heal:
                label.AddToClassList("damage-number--heal");
                label.text = "+" + damage.ToString();
                break;
        }

        // Convert world coordinates to screen coordinates
        Vector2 screenPos = Camera.main.WorldToScreenPoint(worldPos);
        // Convert to UI Toolkit coordinate system (Y-axis inverted)
        float uiY = Screen.height - screenPos.y;

        damageLabel.style.position = Position.Absolute;
        damageLabel.style.left = screenPos.x;
        damageLabel.style.top = uiY;

        root.Add(damageLabel);

        // Remove after animation
        damageLabel.schedule.Execute(() => {
            damageLabel.RemoveFromHierarchy();
        }).ExecuteLater(1000);
    }
}
```

```css
/* USS - Damage numbers */
.damage-number {
    position: absolute;
    font-size: 24px;
    color: white;
    -unity-font-style: bold;
    text-shadow: 2px 2px 4px black;
    transition-property: translate, opacity;
    transition-duration: 1s;
    translate: 0 0;
    opacity: 1;
}

.damage-number--animate {
    translate: 0 -50px;
    opacity: 0;
}

.damage-number--critical {
    font-size: 36px;
    color: #e74c3c;
}

.damage-number--heal {
    color: #2ecc71;
}

.damage-number--miss {
    color: #888;
    font-size: 18px;
}
```

### 5. Minimap

```xml
<!-- UXML - Minimap -->
<ui:VisualElement class="minimap">
    <ui:VisualElement class="minimap__frame">
        <ui:VisualElement class="minimap__content" name="minimap-content">
            <!-- RenderTexture set as background -->
        </ui:VisualElement>
        <ui:VisualElement class="minimap__player-icon" />
        <ui:VisualElement class="minimap__markers" name="minimap-markers">
            <!-- Dynamic markers -->
        </ui:VisualElement>
    </ui:VisualElement>
    <ui:VisualElement class="minimap__compass">
        <ui:Label text="N" class="minimap__compass-label" />
    </ui:VisualElement>
</ui:VisualElement>
```

```css
/* USS - Minimap */
.minimap {
    width: 180px;
    height: 180px;
}

.minimap__frame {
    width: 100%;
    height: 100%;
    border-radius: 90px; /* Circular */
    border-width: 3px;
    border-color: rgba(0, 0, 0, 0.8);
    overflow: hidden;
}

.minimap__content {
    width: 100%;
    height: 100%;
    /* RenderTexture set from C# */
}

.minimap__player-icon {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 12px;
    height: 12px;
    translate: -50% -50%;
    background-color: #3498db;
    border-radius: 6px;
    border-width: 2px;
    border-color: white;
}

.minimap__marker {
    position: absolute;
    width: 8px;
    height: 8px;
    border-radius: 4px;
}

.minimap__marker--enemy {
    background-color: #e74c3c;
}

.minimap__marker--quest {
    background-color: #f39c12;
}

.minimap__marker--poi {
    background-color: #2ecc71;
}
```

### 6. Dialog System

```xml
<!-- UXML - Dialog box -->
<ui:VisualElement class="dialog-box">
    <ui:VisualElement class="dialog-box__portrait" name="portrait" />
    <ui:VisualElement class="dialog-box__content">
        <ui:Label class="dialog-box__speaker" name="speaker-name" />
        <ui:Label class="dialog-box__text" name="dialog-text" />
    </ui:VisualElement>
    <ui:VisualElement class="dialog-box__choices" name="choices-container">
        <!-- Dynamic choices -->
    </ui:VisualElement>
    <ui:VisualElement class="dialog-box__continue-indicator" />
</ui:VisualElement>
```

```css
/* USS - Dialog box */
.dialog-box {
    position: absolute;
    left: 10%;
    right: 10%;
    bottom: 10%;
    min-height: 150px;
    background-color: rgba(0, 0, 0, 0.85);
    border-width: 2px;
    border-color: #444;
    border-radius: 8px;
    flex-direction: row;
    padding: 16px;
}

.dialog-box__portrait {
    width: 120px;
    height: 120px;
    border-width: 2px;
    border-color: #666;
    border-radius: 4px;
    margin-right: 16px;
    flex-shrink: 0;
}

.dialog-box__content {
    flex-grow: 1;
    flex-direction: column;
}

.dialog-box__speaker {
    font-size: 18px;
    color: #f39c12;
    -unity-font-style: bold;
    margin-bottom: 8px;
}

.dialog-box__text {
    font-size: 16px;
    color: white;
    white-space: normal;
    flex-grow: 1;
}

.dialog-box__choices {
    flex-direction: column;
    margin-top: 12px;
}

.dialog-choice {
    padding: 8px 16px;
    margin: 4px 0;
    background-color: rgba(255, 255, 255, 0.1);
    border-radius: 4px;
    color: white;
}

.dialog-choice:hover {
    background-color: rgba(255, 255, 255, 0.2);
}

.dialog-choice--selected {
    background-color: rgba(243, 156, 18, 0.3);
    border-left-width: 3px;
    border-left-color: #f39c12;
}

.dialog-box__continue-indicator {
    position: absolute;
    right: 16px;
    bottom: 16px;
    width: 16px;
    height: 16px;
    /* For blink animation */
}
```

## Performance Best Practices

### 1. Avoid Inline Styles

```csharp
// NG - Performance degradation
element.style.backgroundColor = Color.red;
element.style.width = 100;
element.style.height = 50;

// OK - Use USS classes
element.AddToClassList("highlighted-button");
```

### 2. :hover Pseudo-class Optimization

```css
/* NG - :hover on all elements degrades performance */
.button:hover {
    background-color: #444;
}

/* OK - Use only when necessary, or combine with :focus */
.interactive-button:hover,
.interactive-button:focus {
    background-color: #444;
}
```

### 3. Avoid Deep Nesting

```xml
<!-- NG - Too deep nesting -->
<ui:VisualElement>
    <ui:VisualElement>
        <ui:VisualElement>
            <ui:VisualElement>
                <ui:Label text="Deep" />
            </ui:VisualElement>
        </ui:VisualElement>
    </ui:VisualElement>
</ui:VisualElement>

<!-- OK - Flat structure -->
<ui:VisualElement class="container">
    <ui:Label text="Flat" />
</ui:VisualElement>
```

### 4. VisualElement Pooling

```csharp
// Use pooling for large numbers of dynamic elements
private Queue<VisualElement> elementPool = new Queue<VisualElement>();

VisualElement GetPooledElement()
{
    if (elementPool.Count > 0)
    {
        return elementPool.Dequeue();
    }
    return new VisualElement();
}

void ReturnToPool(VisualElement element)
{
    element.RemoveFromHierarchy();
    element.ClearClassList();
    elementPool.Enqueue(element);
}
```

## Tool Selection Guide

| Purpose | Recommended Tool |
|---------|------------------|
| UIDocument GameObject creation | `create_gameobject` + `add_component` |
| PanelSettings configuration | `set_component_field` |
| C# controller creation | `create_class` |
| UXML/USS file creation | `manage_asset_database` |
| UI element search | `find_ui_elements` |
| UI testing | `click_ui_element`, `simulate_ui_input` |
| UI state check | `get_ui_element_state` |

## Common Workflows

### 1. Creating Mobile Responsive UI

```javascript
// Step 1: Create GameObject for UIDocument
mcp__unity-mcp-server__create_gameobject({
  name: "ResponsiveUI"
})

mcp__unity-mcp-server__add_component({
  gameObjectPath: "/ResponsiveUI",
  componentType: "UIDocument"
})

// Step 2: Add responsive controller
mcp__unity-mcp-server__create_class({
  path: "Assets/Scripts/UI/ResponsiveLayoutController.cs",
  className: "ResponsiveLayoutController",
  baseType: "MonoBehaviour",
  namespace: "Game.UI",
  apply: true
})

// Step 3: Add Safe Area controller
mcp__unity-mcp-server__create_class({
  path: "Assets/Scripts/UI/SafeAreaController.cs",
  className: "SafeAreaController",
  baseType: "MonoBehaviour",
  namespace: "Game.UI",
  apply: true
})
```

### 2. Creating a Scroll View

```xml
<!-- UXML -->
<ui:ScrollView class="scroll-view" mode="Vertical">
    <ui:VisualElement class="scroll-content">
        <!-- Content items -->
    </ui:VisualElement>
</ui:ScrollView>
```

```css
/* USS */
.scroll-view {
    flex-grow: 1;
}

.scroll-content {
    flex-direction: column;
    padding: 16px;
}
```

### 3. Data Binding

```csharp
// DataBindingController.cs
using UnityEngine;
using UnityEngine.UIElements;

public class DataBindingController : MonoBehaviour
{
    [SerializeField] private UIDocument uiDocument;

    void Start()
    {
        var root = uiDocument.rootVisualElement;

        // Label binding
        var scoreLabel = root.Q<Label>("score-label");
        scoreLabel.text = "Score: 0";

        // Button event
        var button = root.Q<Button>("action-button");
        button.clicked += OnButtonClicked;

        // ListView
        var listView = root.Q<ListView>("item-list");
        listView.makeItem = () => new Label();
        listView.bindItem = (element, index) =>
        {
            (element as Label).text = $"Item {index}";
        };
        listView.itemsSource = new List<string> { "A", "B", "C" };
    }
}
```

## Common Mistakes

### 1. PanelSettings Not Configured

**NG**: UIDocument's PanelSettings is not set
- UI doesn't display
- Scaling doesn't work

**OK**: Create and set PanelSettings asset
- Select Scale With Screen Size
- Set Reference Resolution

### 2. flex-grow: 0 Unchanged

**NG**: Child elements don't fill parent
```css
.container { }  /* flex-grow: 0 is default */
```

**OK**: Explicitly set flex-grow
```css
.container {
    flex-grow: 1;
}
```

### 3. Safe Area Coordinate System Confusion

**NG**: Using Screen.safeArea directly
```csharp
// Position is off due to different coordinate systems
element.style.top = Screen.safeArea.y;
```

**OK**: Convert to UI Toolkit coordinate system
```csharp
float top = Screen.height - (Screen.safeArea.y + Screen.safeArea.height);
element.style.paddingTop = top / scale;
```

### 4. Using @media Queries

**NG**: Writing CSS media queries
```css
/* Does not work in UI Toolkit */
@media screen and (max-width: 600px) { }
```

**OK**: Switch classes dynamically with C#
```csharp
root.AddToClassList(isNarrow ? "narrow" : "wide");
```

### 5. Performance-Unaware Styles

**NG**: Frequent inline style changes
```csharp
void Update()
{
    element.style.left = Mathf.Sin(Time.time) * 100;
}
```

**OK**: Use transform
```csharp
void Update()
{
    element.transform.position = new Vector3(Mathf.Sin(Time.time) * 100, 0, 0);
}
```

## Tool Reference

### PanelSettings Scale Modes

| Property | Type | Description |
|----------|------|-------------|
| scaleMode | PanelScaleMode | Constant Pixel Size / Constant Physical Size / Scale With Screen Size |
| referenceResolution | Vector2Int | Reference resolution (for Scale With Screen Size) |
| screenMatchMode | PanelScreenMatchMode | Match Width Or Height / Expand / Shrink |
| match | float | 0 = Width priority, 1 = Height priority |
| referenceDpi | float | Reference DPI (for Constant Physical Size) |

### USS Flexbox Properties

| Property | Values | Default |
|----------|--------|---------|
| display | flex, none | flex |
| flex-direction | row, column, row-reverse, column-reverse | column |
| flex-grow | number | 0 |
| flex-shrink | number | 1 |
| flex-basis | length, auto | auto |
| align-items | flex-start, flex-end, center, stretch | stretch |
| justify-content | flex-start, flex-end, center, space-between, space-around | flex-start |
| flex-wrap | nowrap, wrap, wrap-reverse | nowrap |

### USS Size Properties

| Property | Values |
|----------|--------|
| width | length, %, auto |
| height | length, %, auto |
| min-width | length, % |
| max-width | length, % |
| min-height | length, % |
| max-height | length, % |

### C# VisualElement API

```csharp
// Class operations
element.AddToClassList("class-name");
element.RemoveFromClassList("class-name");
element.ToggleInClassList("class-name");
element.EnableInClassList("class-name", enabled);

// Style operations
element.style.display = DisplayStyle.Flex;
element.style.flexGrow = 1;
element.style.width = Length.Percent(100);

// Queries
root.Q<Button>("button-name");
root.Q<VisualElement>(className: "class-name");
root.Query<Label>().ToList();
```

## References

- [Unity Manual: Panel Settings](https://docs.unity3d.com/Manual/UIE-Runtime-Panel-Settings.html)
- [Unity Manual: USS Properties](https://docs.unity3d.com/Manual/UIE-USS-SupportedProperties.html)
- [Unity Manual: Layout Engine](https://docs.unity3d.com/Manual/UIE-LayoutEngine.html)
- [CSS Tricks: Flexbox Guide](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)
- [2024 Guide to UI Toolkit](https://flexbuilder.ninja/2024/04/12/2024-guide-to-uitoolkit-for-unity-games/)

Install

Requires askill CLI v1.0+

Metadata

LicenseUnknown
Version-
Updated5d ago
Publisherakiojin

Tags

api