Game UI design using Unity's uGUI (Canvas/RectTransform/Anchors). Includes game UI elements like HUD, health bars, inventory, skill bars, mobile responsive design, and Safe Area support. Use when: game UI design, HUD creation, Canvas setup, mobile UI, Anchors configuration
/plugin marketplace add akiojin/unity-mcp-server/plugin install unity-mcp-server@unity-mcp-serverThis skill is limited to using the following tools:
A skill for game UI design using Unity's uGUI (Unity GUI) system. Provides a comprehensive game UI design guide including implementation patterns for game UI elements like HUD, health bars, inventory, dialogs, mobile responsive design, and Safe Area support.
// 1. Create Canvas
mcp__unity-mcp-server__create_gameobject({
name: "Canvas"
})
// 2. Add Canvas component
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Canvas",
componentType: "Canvas",
properties: {
renderMode: 0 // ScreenSpaceOverlay
}
})
// 3. Add CanvasScaler (responsive design)
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Canvas",
componentType: "CanvasScaler",
properties: {
uiScaleMode: 1, // ScaleWithScreenSize
referenceResolution: { x: 1080, y: 1920 }, // Reference resolution
screenMatchMode: 0, // MatchWidthOrHeight
matchWidthOrHeight: 0 // 0=Portrait priority, 1=Landscape priority
}
})
// 4. Add GraphicRaycaster (for interaction)
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Canvas",
componentType: "GraphicRaycaster"
})
Game UI is classified into 4 types based on placement and representation.
UI that exists within the game world. Characters can also perceive it.
// World Space Canvas (enemy HP bar above head)
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Enemy/HealthCanvas",
componentType: "Canvas",
properties: { renderMode: 2 } // WorldSpace
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Enemy/HealthCanvas",
componentType: "RectTransform",
fieldPath: "sizeDelta",
value: { x: 100, y: 20 }
})
Overlay UI visible only to the player.
// HUD overlay Canvas
mcp__unity-mcp-server__add_component({
gameObjectPath: "/HUDCanvas",
componentType: "Canvas",
properties: { renderMode: 0 } // ScreenSpaceOverlay
})
UI that exists in 3D space but is not part of the game world.
// Billboard marker
mcp__unity-mcp-server__add_component({
gameObjectPath: "/QuestMarker/Canvas",
componentType: "Canvas",
properties: { renderMode: 2 } // WorldSpace
})
// Add billboard script
mcp__unity-mcp-server__add_component({
gameObjectPath: "/QuestMarker/Canvas",
componentType: "BillboardUI"
})
Full-screen effect UI.
// Damage flash Canvas
mcp__unity-mcp-server__add_component({
gameObjectPath: "/EffectCanvas",
componentType: "Canvas",
properties: {
renderMode: 0,
sortingOrder: 100 // Frontmost
}
})
// Flash Image (full screen)
mcp__unity-mcp-server__create_gameobject({
name: "DamageFlash",
parentPath: "/EffectCanvas"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/EffectCanvas/DamageFlash",
componentType: "Image",
properties: {
color: { r: 1, g: 0, b: 0, a: 0 } // Transparent red
}
})
Game HUDs have industry-standard placement conventions.
┌─────────────────────────────────────────────────────┐
│ [HP/MP Bar] [Mini Map] [Settings] │ ← Top
│ ★ Top-Left: HP/MP/Stamina Top-Right: Minimap, Settings
│ │
│ │
│ [Quest] [Buff Icons] │ ← Upper-Middle
│ ★ Quest objectives Buff/Debuff icons │
│ │
│ [Center] │
│ Crosshair/Interact │
│ │
│ [Chat] [Inventory] │ ← Lower-Middle
│ │
│ │
│ [Skill Bar] [Action Buttons] │ ← Bottom
│ ★ Skills/Items Action buttons │
└─────────────────────────────────────────────────────┘
| Position | Anchor | UI Elements | Reason |
|---|---|---|---|
| Top-Left | (0,1) | HP/MP/Stamina | Critical info, minimal eye movement |
| Top-Right | (1,1) | Minimap, Settings | Auxiliary info, non-intrusive |
| Bottom-Left | (0,0) | Chat, Logs | Infrequently viewed info |
| Bottom-Right | (1,0) | Inventory, Buttons | Easy right-hand access |
| Bottom-Center | (0.5,0) | Skill bar | Two-hand access, high importance |
| Center | (0.5,0.5) | Crosshair, Interact | Center of vision |
// HP Bar (top-left placement)
mcp__unity-mcp-server__create_gameobject({
name: "HPBar",
parentPath: "/HUDCanvas/SafeArea"
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/HPBar",
componentType: "RectTransform",
fieldPath: "anchorMin",
value: { x: 0, y: 1 }
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/HPBar",
componentType: "RectTransform",
fieldPath: "anchorMax",
value: { x: 0, y: 1 }
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/HPBar",
componentType: "RectTransform",
fieldPath: "pivot",
value: { x: 0, y: 1 }
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/HPBar",
componentType: "RectTransform",
fieldPath: "anchoredPosition",
value: { x: 20, y: -20 } // 20px margin from top-left
})
// Minimap (top-right placement)
mcp__unity-mcp-server__create_gameobject({
name: "Minimap",
parentPath: "/HUDCanvas/SafeArea"
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/Minimap",
componentType: "RectTransform",
fieldPath: "anchorMin",
value: { x: 1, y: 1 }
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/Minimap",
componentType: "RectTransform",
fieldPath: "anchorMax",
value: { x: 1, y: 1 }
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/Minimap",
componentType: "RectTransform",
fieldPath: "pivot",
value: { x: 1, y: 1 }
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/Minimap",
componentType: "RectTransform",
fieldPath: "anchoredPosition",
value: { x: -20, y: -20 } // 20px margin from top-right
})
// Skill Bar (bottom-center placement)
mcp__unity-mcp-server__create_gameobject({
name: "SkillBar",
parentPath: "/HUDCanvas/SafeArea"
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/SkillBar",
componentType: "RectTransform",
fieldPath: "anchorMin",
value: { x: 0.5, y: 0 }
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/SkillBar",
componentType: "RectTransform",
fieldPath: "anchorMax",
value: { x: 0.5, y: 0 }
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/SkillBar",
componentType: "RectTransform",
fieldPath: "pivot",
value: { x: 0.5, y: 0 }
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/SkillBar",
componentType: "RectTransform",
fieldPath: "anchoredPosition",
value: { x: 0, y: 20 } // 20px margin from bottom
})
Implements delayed damage display (red gauge gradually decreases after taking damage).
HealthBar (RectTransform)
├── Background (Image) - Background
├── DelayedFill (Image) - Delayed gauge (red)
├── Fill (Image) - Current value gauge (green)
└── Text (TextMeshProUGUI) - "100/100"
// Create health bar
mcp__unity-mcp-server__create_gameobject({
name: "HealthBar",
parentPath: "/HUDCanvas/SafeArea"
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/HealthBar",
componentType: "RectTransform",
fieldPath: "sizeDelta",
value: { x: 200, y: 24 }
})
// Background
mcp__unity-mcp-server__create_gameobject({
name: "Background",
parentPath: "/HUDCanvas/SafeArea/HealthBar"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/HUDCanvas/SafeArea/HealthBar/Background",
componentType: "Image",
properties: {
color: { r: 0.1, g: 0.1, b: 0.1, a: 0.8 }
}
})
// Delayed gauge (Filled Image)
mcp__unity-mcp-server__create_gameobject({
name: "DelayedFill",
parentPath: "/HUDCanvas/SafeArea/HealthBar"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/HUDCanvas/SafeArea/HealthBar/DelayedFill",
componentType: "Image",
properties: {
color: { r: 0.8, g: 0.2, b: 0.2, a: 1 },
type: 3, // Filled
fillMethod: 0, // Horizontal
fillAmount: 1.0
}
})
// Current value gauge
mcp__unity-mcp-server__create_gameobject({
name: "Fill",
parentPath: "/HUDCanvas/SafeArea/HealthBar"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/HUDCanvas/SafeArea/HealthBar/Fill",
componentType: "Image",
properties: {
color: { r: 0.2, g: 0.8, b: 0.2, a: 1 },
type: 3, // Filled
fillMethod: 0, // Horizontal
fillAmount: 1.0
}
})
// Text
mcp__unity-mcp-server__create_gameobject({
name: "Text",
parentPath: "/HUDCanvas/SafeArea/HealthBar"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/HUDCanvas/SafeArea/HealthBar/Text",
componentType: "TextMeshProUGUI",
properties: {
text: "100/100",
fontSize: 14,
alignment: 514 // Center
}
})
// HealthBarController.cs
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class HealthBarController : MonoBehaviour
{
[SerializeField] private Image fillImage;
[SerializeField] private Image delayedFillImage;
[SerializeField] private TextMeshProUGUI text;
[SerializeField] private float delayedFillSpeed = 0.5f;
private float currentHealth = 100f;
private float maxHealth = 100f;
private float delayedHealth = 100f;
public void SetHealth(float health, float max)
{
currentHealth = Mathf.Clamp(health, 0, max);
maxHealth = max;
float ratio = currentHealth / maxHealth;
fillImage.fillAmount = ratio;
text.text = $"{(int)currentHealth}/{(int)maxHealth}";
// When taking damage, delayed gauge stays
// On healing, update immediately
if (delayedHealth < currentHealth)
{
delayedHealth = currentHealth;
delayedFillImage.fillAmount = ratio;
}
}
void Update()
{
// Gradually decrease delayed gauge
if (delayedHealth > currentHealth)
{
delayedHealth = Mathf.MoveTowards(
delayedHealth,
currentHealth,
maxHealth * delayedFillSpeed * Time.deltaTime
);
delayedFillImage.fillAmount = delayedHealth / maxHealth;
}
}
}
Displays remaining time with darkened overlay + rotating mask during cooldown.
SkillSlot (RectTransform)
├── Icon (Image) - Skill icon
├── CooldownOverlay (Image) - Darkened overlay (Radial Fill)
├── CooldownText (TextMeshProUGUI) - Remaining seconds
└── KeyHint (TextMeshProUGUI) - "Q"
// Create skill slot
mcp__unity-mcp-server__create_gameobject({
name: "SkillSlot",
parentPath: "/HUDCanvas/SafeArea/SkillBar"
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/SkillBar/SkillSlot",
componentType: "RectTransform",
fieldPath: "sizeDelta",
value: { x: 64, y: 64 }
})
// Icon
mcp__unity-mcp-server__create_gameobject({
name: "Icon",
parentPath: "/HUDCanvas/SafeArea/SkillBar/SkillSlot"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/HUDCanvas/SafeArea/SkillBar/SkillSlot/Icon",
componentType: "Image"
})
// Cooldown overlay (Radial Fill)
mcp__unity-mcp-server__create_gameobject({
name: "CooldownOverlay",
parentPath: "/HUDCanvas/SafeArea/SkillBar/SkillSlot"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/HUDCanvas/SafeArea/SkillBar/SkillSlot/CooldownOverlay",
componentType: "Image",
properties: {
color: { r: 0, g: 0, b: 0, a: 0.7 },
type: 3, // Filled
fillMethod: 4, // Radial360
fillOrigin: 2, // Top
fillClockwise: false,
fillAmount: 0
}
})
// Cooldown text
mcp__unity-mcp-server__create_gameobject({
name: "CooldownText",
parentPath: "/HUDCanvas/SafeArea/SkillBar/SkillSlot"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/HUDCanvas/SafeArea/SkillBar/SkillSlot/CooldownText",
componentType: "TextMeshProUGUI",
properties: {
text: "",
fontSize: 20,
alignment: 514, // Center
fontStyle: 1 // Bold
}
})
// Key hint
mcp__unity-mcp-server__create_gameobject({
name: "KeyHint",
parentPath: "/HUDCanvas/SafeArea/SkillBar/SkillSlot"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/HUDCanvas/SafeArea/SkillBar/SkillSlot/KeyHint",
componentType: "TextMeshProUGUI",
properties: {
text: "Q",
fontSize: 12,
alignment: 257 // BottomLeft
}
})
// SkillSlotController.cs
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class SkillSlotController : MonoBehaviour
{
[SerializeField] private Image icon;
[SerializeField] private Image cooldownOverlay;
[SerializeField] private TextMeshProUGUI cooldownText;
private float cooldownDuration;
private float cooldownRemaining;
public void SetIcon(Sprite sprite)
{
icon.sprite = sprite;
}
public void StartCooldown(float duration)
{
cooldownDuration = duration;
cooldownRemaining = duration;
}
public bool IsOnCooldown => cooldownRemaining > 0;
void Update()
{
if (cooldownRemaining > 0)
{
cooldownRemaining -= Time.deltaTime;
float ratio = cooldownRemaining / cooldownDuration;
cooldownOverlay.fillAmount = ratio;
if (cooldownRemaining > 1)
cooldownText.text = Mathf.CeilToInt(cooldownRemaining).ToString();
else if (cooldownRemaining > 0)
cooldownText.text = cooldownRemaining.ToString("F1");
else
{
cooldownText.text = "";
cooldownOverlay.fillAmount = 0;
}
}
}
}
Rarity-based border colors, stack count display, drag & drop support.
InventoryGrid (RectTransform + GridLayoutGroup)
└── ItemSlot (multiple)
├── Background (Image) - Rarity border
├── Icon (Image) - Item icon
├── StackCount (TextMeshProUGUI) - "x99"
└── SelectionHighlight (Image) - Selection highlight
// Create inventory grid
mcp__unity-mcp-server__create_gameobject({
name: "InventoryGrid",
parentPath: "/InventoryCanvas/Panel"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/InventoryCanvas/Panel/InventoryGrid",
componentType: "GridLayoutGroup",
properties: {
cellSize: { x: 64, y: 64 },
spacing: { x: 4, y: 4 },
startCorner: 0, // UpperLeft
startAxis: 0, // Horizontal
childAlignment: 0, // UpperLeft
constraint: 1, // FixedColumnCount
constraintCount: 6 // 6 columns
}
})
// Create item slot
mcp__unity-mcp-server__create_gameobject({
name: "ItemSlot",
parentPath: "/InventoryCanvas/Panel/InventoryGrid"
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/InventoryCanvas/Panel/InventoryGrid/ItemSlot",
componentType: "RectTransform",
fieldPath: "sizeDelta",
value: { x: 64, y: 64 }
})
// Background (rarity border)
mcp__unity-mcp-server__create_gameobject({
name: "Background",
parentPath: "/InventoryCanvas/Panel/InventoryGrid/ItemSlot"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/InventoryCanvas/Panel/InventoryGrid/ItemSlot/Background",
componentType: "Image",
properties: {
color: { r: 0.3, g: 0.3, b: 0.3, a: 1 } // Default (Common)
}
})
// Icon
mcp__unity-mcp-server__create_gameobject({
name: "Icon",
parentPath: "/InventoryCanvas/Panel/InventoryGrid/ItemSlot"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/InventoryCanvas/Panel/InventoryGrid/ItemSlot/Icon",
componentType: "Image"
})
// Stack count
mcp__unity-mcp-server__create_gameobject({
name: "StackCount",
parentPath: "/InventoryCanvas/Panel/InventoryGrid/ItemSlot"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/InventoryCanvas/Panel/InventoryGrid/ItemSlot/StackCount",
componentType: "TextMeshProUGUI",
properties: {
text: "",
fontSize: 12,
alignment: 260 // BottomRight
}
})
// Selection highlight
mcp__unity-mcp-server__create_gameobject({
name: "SelectionHighlight",
parentPath: "/InventoryCanvas/Panel/InventoryGrid/ItemSlot"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/InventoryCanvas/Panel/InventoryGrid/ItemSlot/SelectionHighlight",
componentType: "Image",
properties: {
color: { r: 1, g: 1, b: 1, a: 0.3 },
raycastTarget: false
}
})
// ItemRarity.cs
using UnityEngine;
public enum ItemRarity
{
Common, // Gray
Uncommon, // Green
Rare, // Blue
Epic, // Purple
Legendary // Orange
}
public static class RarityColors
{
public static Color GetColor(ItemRarity rarity) => rarity switch
{
ItemRarity.Common => new Color(0.6f, 0.6f, 0.6f),
ItemRarity.Uncommon => new Color(0.2f, 0.8f, 0.2f),
ItemRarity.Rare => new Color(0.2f, 0.4f, 0.9f),
ItemRarity.Epic => new Color(0.6f, 0.2f, 0.9f),
ItemRarity.Legendary => new Color(1.0f, 0.5f, 0.0f),
_ => Color.white
};
}
Effect where numbers float up and fade from the damage location.
DamageNumber (RectTransform)
└── Text (TextMeshProUGUI) - Damage value
// Create damage number prefab
mcp__unity-mcp-server__create_gameobject({
name: "DamageNumber",
parentPath: "/WorldCanvas"
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/WorldCanvas/DamageNumber",
componentType: "RectTransform",
fieldPath: "sizeDelta",
value: { x: 100, y: 40 }
})
// Text
mcp__unity-mcp-server__create_gameobject({
name: "Text",
parentPath: "/WorldCanvas/DamageNumber"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/WorldCanvas/DamageNumber/Text",
componentType: "TextMeshProUGUI",
properties: {
text: "999",
fontSize: 24,
alignment: 514, // Center
fontStyle: 1, // Bold
color: { r: 1, g: 0.2, b: 0.2, a: 1 }
}
})
// DamageNumberController.cs
using UnityEngine;
using TMPro;
public class DamageNumberController : MonoBehaviour
{
[SerializeField] private TextMeshProUGUI text;
[SerializeField] private float floatSpeed = 50f;
[SerializeField] private float fadeSpeed = 2f;
[SerializeField] private float lifetime = 1.5f;
private float elapsed;
private Color originalColor;
private Vector3 randomOffset;
public void Setup(int damage, bool isCritical = false)
{
text.text = damage.ToString();
if (isCritical)
{
text.fontSize *= 1.5f;
text.color = new Color(1f, 0.8f, 0f); // Yellow
}
originalColor = text.color;
randomOffset = new Vector3(Random.Range(-20f, 20f), 0, 0);
}
void Update()
{
elapsed += Time.deltaTime;
// Float upward
transform.localPosition += (Vector3.up * floatSpeed + randomOffset) * Time.deltaTime;
randomOffset *= 0.95f; // Dampen horizontal movement
// Fade out
if (elapsed > lifetime * 0.5f)
{
float alpha = Mathf.Lerp(originalColor.a, 0,
(elapsed - lifetime * 0.5f) / (lifetime * 0.5f));
text.color = new Color(originalColor.r, originalColor.g, originalColor.b, alpha);
}
if (elapsed >= lifetime)
{
Destroy(gameObject);
}
}
}
Top-down minimap using RawImage and RenderTexture.
MinimapContainer (RectTransform)
├── MapImage (RawImage + Mask) - Map display
├── PlayerIcon (Image) - Player icon
├── Border (Image) - Border
└── CompassText (TextMeshProUGUI) - "N"
// Minimap container
mcp__unity-mcp-server__create_gameobject({
name: "MinimapContainer",
parentPath: "/HUDCanvas/SafeArea"
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/MinimapContainer",
componentType: "RectTransform",
fieldPath: "sizeDelta",
value: { x: 150, y: 150 }
})
// Map display (RawImage)
mcp__unity-mcp-server__create_gameobject({
name: "MapImage",
parentPath: "/HUDCanvas/SafeArea/MinimapContainer"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/HUDCanvas/SafeArea/MinimapContainer/MapImage",
componentType: "RawImage"
})
// Circular mask
mcp__unity-mcp-server__add_component({
gameObjectPath: "/HUDCanvas/SafeArea/MinimapContainer/MapImage",
componentType: "Mask",
properties: {
showMaskGraphic: false
}
})
// Player icon (centered)
mcp__unity-mcp-server__create_gameobject({
name: "PlayerIcon",
parentPath: "/HUDCanvas/SafeArea/MinimapContainer"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/HUDCanvas/SafeArea/MinimapContainer/PlayerIcon",
componentType: "Image"
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/HUDCanvas/SafeArea/MinimapContainer/PlayerIcon",
componentType: "RectTransform",
fieldPath: "sizeDelta",
value: { x: 16, y: 16 }
})
// Border
mcp__unity-mcp-server__create_gameobject({
name: "Border",
parentPath: "/HUDCanvas/SafeArea/MinimapContainer"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/HUDCanvas/SafeArea/MinimapContainer/Border",
componentType: "Image",
properties: {
raycastTarget: false
}
})
RPG-style conversation window. Displays speaker name, text, and choices.
DialogPanel (RectTransform + CanvasGroup)
├── SpeakerName (TextMeshProUGUI)
├── Portrait (Image) - Speaker portrait
├── DialogText (TextMeshProUGUI) - Dialog text
├── ChoicesContainer (VerticalLayoutGroup)
│ └── ChoiceButton (Button + TextMeshProUGUI)
└── ContinueIndicator (Image) - Continue arrow
// Dialog panel
mcp__unity-mcp-server__create_gameobject({
name: "DialogPanel",
parentPath: "/DialogCanvas"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/DialogCanvas/DialogPanel",
componentType: "Image",
properties: {
color: { r: 0, g: 0, b: 0, a: 0.85 }
}
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/DialogCanvas/DialogPanel",
componentType: "CanvasGroup"
})
// Bottom stretch placement
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/DialogCanvas/DialogPanel",
componentType: "RectTransform",
fieldPath: "anchorMin",
value: { x: 0, y: 0 }
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/DialogCanvas/DialogPanel",
componentType: "RectTransform",
fieldPath: "anchorMax",
value: { x: 1, y: 0.3 }
})
// Speaker name
mcp__unity-mcp-server__create_gameobject({
name: "SpeakerName",
parentPath: "/DialogCanvas/DialogPanel"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/DialogCanvas/DialogPanel/SpeakerName",
componentType: "TextMeshProUGUI",
properties: {
text: "Villager A",
fontSize: 20,
fontStyle: 1, // Bold
color: { r: 1, g: 0.9, b: 0.4, a: 1 }
}
})
// Portrait
mcp__unity-mcp-server__create_gameobject({
name: "Portrait",
parentPath: "/DialogCanvas/DialogPanel"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/DialogCanvas/DialogPanel/Portrait",
componentType: "Image"
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/DialogCanvas/DialogPanel/Portrait",
componentType: "RectTransform",
fieldPath: "sizeDelta",
value: { x: 100, y: 100 }
})
// Dialog text
mcp__unity-mcp-server__create_gameobject({
name: "DialogText",
parentPath: "/DialogCanvas/DialogPanel"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/DialogCanvas/DialogPanel/DialogText",
componentType: "TextMeshProUGUI",
properties: {
text: "Hello, traveler.",
fontSize: 18,
alignment: 257 // TopLeft
}
})
// Choices container
mcp__unity-mcp-server__create_gameobject({
name: "ChoicesContainer",
parentPath: "/DialogCanvas/DialogPanel"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/DialogCanvas/DialogPanel/ChoicesContainer",
componentType: "VerticalLayoutGroup",
properties: {
spacing: 8,
childAlignment: 4 // MiddleCenter
}
})
// Continue indicator
mcp__unity-mcp-server__create_gameobject({
name: "ContinueIndicator",
parentPath: "/DialogCanvas/DialogPanel"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/DialogCanvas/DialogPanel/ContinueIndicator",
componentType: "Image"
})
// DialogController.cs
using System.Collections;
using UnityEngine;
using TMPro;
public class DialogController : MonoBehaviour
{
[SerializeField] private TextMeshProUGUI dialogText;
[SerializeField] private GameObject continueIndicator;
[SerializeField] private float charactersPerSecond = 30f;
private string fullText;
private bool isTyping;
private bool skipRequested;
public void ShowDialog(string text)
{
fullText = text;
StartCoroutine(TypeText());
}
IEnumerator TypeText()
{
isTyping = true;
continueIndicator.SetActive(false);
dialogText.text = "";
foreach (char c in fullText)
{
if (skipRequested)
{
dialogText.text = fullText;
break;
}
dialogText.text += c;
yield return new WaitForSeconds(1f / charactersPerSecond);
}
isTyping = false;
skipRequested = false;
continueIndicator.SetActive(true);
}
public void OnClick()
{
if (isTyping)
skipRequested = true;
else
// Proceed to next dialog
OnDialogComplete();
}
void OnDialogComplete()
{
// Implementation: Show next line or finish
}
}
| Mode | Use Case | Features |
|---|---|---|
| Screen Space - Overlay | General UI | Rendered in front, no camera needed |
| Screen Space - Camera | UI with 3D effects | Camera reference, depth sorting |
| World Space | In-world UI | VR/AR, in-game signboards |
RectTransform is the component that controls UI element position and size.
// Key RectTransform properties
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Canvas/Button",
componentType: "RectTransform",
fieldPath: "anchoredPosition",
value: { x: 0, y: 100 } // Position relative to anchor
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Canvas/Button",
componentType: "RectTransform",
fieldPath: "sizeDelta",
value: { x: 200, y: 60 } // Size
})
Anchors are the core of responsive design. They specify relative position to parent element using normalized values from 0 to 1.
| Preset | anchorMin | anchorMax | Use Case |
|---|---|---|---|
| Center | (0.5, 0.5) | (0.5, 0.5) | Popup, Dialog |
| Top-Left | (0, 1) | (0, 1) | Status display |
| Top-Right | (1, 1) | (1, 1) | Settings button |
| Bottom-Left | (0, 0) | (0, 0) | Chat input |
| Bottom-Right | (1, 0) | (1, 0) | Action buttons |
| Top Stretch | (0, 1) | (1, 1) | Header |
| Bottom Stretch | (0, 0) | (1, 0) | Footer |
| Left Stretch | (0, 0) | (0, 1) | Side menu |
| Full Stretch | (0, 0) | (1, 1) | Background |
// Full stretch example
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Canvas/Background",
componentType: "RectTransform",
fieldPath: "anchorMin",
value: { x: 0, y: 0 }
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Canvas/Background",
componentType: "RectTransform",
fieldPath: "anchorMax",
value: { x: 1, y: 1 }
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Canvas/Background",
componentType: "RectTransform",
fieldPath: "offsetMin",
value: { x: 0, y: 0 }
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Canvas/Background",
componentType: "RectTransform",
fieldPath: "offsetMax",
value: { x: 0, y: 0 }
})
The key to mobile responsive design is proper CanvasScaler configuration.
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Canvas",
componentType: "CanvasScaler",
fieldPath: "uiScaleMode",
value: 1 // ScaleWithScreenSize
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Canvas",
componentType: "CanvasScaler",
fieldPath: "referenceResolution",
value: { x: 1080, y: 1920 } // 9:16 portrait reference
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Canvas",
componentType: "CanvasScaler",
fieldPath: "matchWidthOrHeight",
value: 0 // 0 = Match width (optimal for portrait)
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Canvas",
componentType: "CanvasScaler",
fieldPath: "referenceResolution",
value: { x: 1920, y: 1080 } // 16:9 landscape reference
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Canvas",
componentType: "CanvasScaler",
fieldPath: "matchWidthOrHeight",
value: 1 // 1 = Match height (optimal for landscape)
})
For supporting both orientations, switch Match at runtime.
// OrientationHandler.cs
using UnityEngine;
using UnityEngine.UI;
public class OrientationHandler : MonoBehaviour
{
private CanvasScaler canvasScaler;
private ScreenOrientation lastOrientation;
void Start()
{
canvasScaler = GetComponent<CanvasScaler>();
UpdateMatch();
}
void Update()
{
if (Screen.orientation != lastOrientation)
{
UpdateMatch();
lastOrientation = Screen.orientation;
}
}
void UpdateMatch()
{
bool isPortrait = Screen.height > Screen.width;
canvasScaler.matchWidthOrHeight = isPortrait ? 0f : 1f;
}
}
Safe Area support for devices with notches or punch-hole cameras.
// SafeAreaHandler.cs
using UnityEngine;
public class SafeAreaHandler : MonoBehaviour
{
private RectTransform panelRectTransform;
private Rect lastSafeArea;
void Start()
{
panelRectTransform = GetComponent<RectTransform>();
ApplySafeArea();
}
void Update()
{
if (Screen.safeArea != lastSafeArea)
{
ApplySafeArea();
}
}
void ApplySafeArea()
{
Rect safeArea = Screen.safeArea;
lastSafeArea = safeArea;
// Convert to normalized coordinates
Vector2 anchorMin = safeArea.position;
Vector2 anchorMax = safeArea.position + safeArea.size;
anchorMin.x /= Screen.width;
anchorMin.y /= Screen.height;
anchorMax.x /= Screen.width;
anchorMax.y /= Screen.height;
panelRectTransform.anchorMin = anchorMin;
panelRectTransform.anchorMax = anchorMax;
}
}
// Create Safe Area panel
mcp__unity-mcp-server__create_gameobject({
name: "SafeAreaPanel",
parentPath: "/Canvas"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Canvas/SafeAreaPanel",
componentType: "RectTransform"
})
// Set to full stretch
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Canvas/SafeAreaPanel",
componentType: "RectTransform",
fieldPath: "anchorMin",
value: { x: 0, y: 0 }
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Canvas/SafeAreaPanel",
componentType: "RectTransform",
fieldPath: "anchorMax",
value: { x: 1, y: 1 }
})
// Add SafeAreaHandler script
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Canvas/SafeAreaPanel",
componentType: "SafeAreaHandler"
})
Layout Group components for automatic layouts.
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Canvas/ButtonContainer",
componentType: "HorizontalLayoutGroup",
properties: {
spacing: 10,
childAlignment: 4, // MiddleCenter
childControlWidth: true,
childControlHeight: true,
childForceExpandWidth: false,
childForceExpandHeight: false
}
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Canvas/MenuList",
componentType: "VerticalLayoutGroup",
properties: {
spacing: 5,
childAlignment: 1, // UpperCenter
padding: { left: 10, right: 10, top: 10, bottom: 10 }
}
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Canvas/ItemGrid",
componentType: "GridLayoutGroup",
properties: {
cellSize: { x: 100, y: 100 },
spacing: { x: 10, y: 10 },
startCorner: 0, // UpperLeft
startAxis: 0, // Horizontal
childAlignment: 4, // MiddleCenter
constraint: 1, // FixedColumnCount
constraintCount: 4
}
})
Automatically adjusts parent to fit child elements.
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Canvas/AutoSizePanel",
componentType: "ContentSizeFitter",
properties: {
horizontalFit: 2, // PreferredSize
verticalFit: 2 // PreferredSize
}
})
| Purpose | Recommended Tool |
|---|---|
| Create Canvas | create_gameobject + add_component |
| Add UI element | create_gameobject + add_component |
| Set anchors | set_component_field (RectTransform) |
| Configure Canvas Scaler | set_component_field (CanvasScaler) |
| Add Layout Group | add_component |
| Search UI elements | find_ui_elements |
| Test UI click | click_ui_element |
| Check UI state | get_ui_element_state |
| Create script | create_class |
// Step 1: Create Canvas
mcp__unity-mcp-server__create_gameobject({ name: "MobileCanvas" })
mcp__unity-mcp-server__add_component({
gameObjectPath: "/MobileCanvas",
componentType: "Canvas",
properties: { renderMode: 0 }
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/MobileCanvas",
componentType: "CanvasScaler",
properties: {
uiScaleMode: 1,
referenceResolution: { x: 1080, y: 1920 },
matchWidthOrHeight: 0
}
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/MobileCanvas",
componentType: "GraphicRaycaster"
})
// Step 2: Safe Area panel
mcp__unity-mcp-server__create_gameobject({
name: "SafeArea",
parentPath: "/MobileCanvas"
})
// Step 3: Header (top stretch)
mcp__unity-mcp-server__create_gameobject({
name: "Header",
parentPath: "/MobileCanvas/SafeArea"
})
// Set anchors to top stretch...
// Step 4: Content (center stretch)
mcp__unity-mcp-server__create_gameobject({
name: "Content",
parentPath: "/MobileCanvas/SafeArea"
})
// Step 5: Footer (bottom stretch)
mcp__unity-mcp-server__create_gameobject({
name: "Footer",
parentPath: "/MobileCanvas/SafeArea"
})
// Create ScrollView
mcp__unity-mcp-server__create_gameobject({
name: "ScrollView",
parentPath: "/Canvas"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Canvas/ScrollView",
componentType: "ScrollRect"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Canvas/ScrollView",
componentType: "Image"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Canvas/ScrollView",
componentType: "Mask"
})
// Create Content
mcp__unity-mcp-server__create_gameobject({
name: "Content",
parentPath: "/Canvas/ScrollView"
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Canvas/ScrollView/Content",
componentType: "VerticalLayoutGroup",
properties: {
childControlHeight: false,
childForceExpandHeight: false
}
})
mcp__unity-mcp-server__add_component({
gameObjectPath: "/Canvas/ScrollView/Content",
componentType: "ContentSizeFitter",
properties: {
verticalFit: 2 // PreferredSize
}
})
NG: Fixed position UI placement
// UI goes off-screen when screen size changes
anchoredPosition: { x: 500, y: 800 }
OK: Relative placement using anchors
// Fixed to parent's bottom-right
anchorMin: { x: 1, y: 0 }
anchorMax: { x: 1, y: 0 }
anchoredPosition: { x: -50, y: 50 } // Margin
NG: Left as Constant Pixel Size
uiScaleMode: 0 // UI size becomes inappropriate when resolution changes
OK: Scale With Screen Size
uiScaleMode: 1
referenceResolution: { x: 1080, y: 1920 }
matchWidthOrHeight: 0 // or 1
NG: Placing important UI directly under Canvas
OK: Place within Safe Area panel
NG: Applying Layout Groups to all UI
OK: Use only for dynamically changing lists
NG: Assuming only 16:9
referenceResolution: { x: 1920, y: 1080 }
// Breaks on 9:16, 18:9, 21:9, etc.
OK: Consider multiple aspect ratios
mcp__unity-mcp-server__find_ui_elements({
elementType: "Button", // UI component type
tagFilter: "MainMenu", // GameObject tag
namePattern: "Btn_*", // Name pattern
includeInactive: false, // Include inactive
canvasFilter: "MainCanvas" // Parent Canvas name
})
mcp__unity-mcp-server__click_ui_element({
elementPath: "/Canvas/Button",
clickType: "left", // left, right, middle
holdDuration: 0, // ms
position: { x: 0.5, y: 0.5 } // 0-1 normalized
})
mcp__unity-mcp-server__get_ui_element_state({
elementPath: "/Canvas/Button",
includeChildren: false,
includeInteractableInfo: true
})
mcp__unity-mcp-server__set_ui_element_value({
elementPath: "/Canvas/InputField",
value: "Hello World",
triggerEvents: true
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Canvas/Panel",
componentType: "RectTransform",
fieldPath: "anchorMin", // anchorMin, anchorMax, pivot, anchoredPosition, sizeDelta, offsetMin, offsetMax
value: { x: 0, y: 0 }
})
mcp__unity-mcp-server__set_component_field({
gameObjectPath: "/Canvas",
componentType: "CanvasScaler",
fieldPath: "matchWidthOrHeight", // uiScaleMode, referenceResolution, screenMatchMode, matchWidthOrHeight
value: 0.5
})
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.