Unity Editor IMGUI Design Skill

SkillMedia

Unity IMGUI (Immediate Mode GUI) for editor tools and custom inspectors. Use for EditorWindow, Custom Inspector, Property Drawer development. NOT for game UI - use unity-game-ugui-design or unity-game-ui-toolkit-design instead.

Use Unity Editor IMGUI Design Skill in Claude, ChatGPT or Ahel Desktop

Free. Sign in, add Unity Editor IMGUI Design Skill and connect your AI. About a minute.

Also: Claude Code · Cursor · Codex

Then ask your AI: use the Unity Editor IMGUI Design Skill

Details

Instructions available. Your AI can read the instructions. Execution depends on the setup they require.

Add Ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Unity Editor IMGUI Design SkillStart free

What this skill tells your AI

The instructions your AI receives, as published by akiojin/unity-mcp-server in .claude-plugin/plugins/unity-mcp-server/skills/unity-editor-imgui-design/SKILL.md and read by Ahel’s review.

WARNING: IMGUI is for Unity Editor extensions ONLY. For game UI, use unity-game-ugui-design or unity-game-ui-toolkit-design.

IMGUI vs Game UI

AspectIMGUI (Editor)uGUI / UI Toolkit (Game)
PurposeEditor tools, inspectorsIn-game UI, HUD
Build inclusionEditor onlyIncluded in builds
RenderingImmediate modeRetained mode
PerformanceOK for editorOptimized for runtime
StylingLimited (GUISkin)Rich (USS, materials)

Quick Start

Create EditorWindow

// Create editor window script
mcp__unity-mcp-server__create_class({
  path: "Assets/Editor/MyToolWindow.cs",
  className: "MyToolWindow",
  namespace: "MyProject.Editor",
  baseType: "EditorWindow",
  usings: "UnityEditor"
})

// Add window content
mcp__unity-mcp-server__edit_structured({
  path: "Assets/Editor/MyToolWindow.cs",
  symbolName: "MyToolWindow",
  operation: "insert_after",
  newText: `
    [MenuItem("Tools/My Tool Window")]
    public static void ShowWindow()
    {
        GetWindow<MyToolWindow>("My Tool");
    }

    private void OnGUI()
    {
        GUILayout.Label("My Tool", EditorStyles.boldLabel);

        if (GUILayout.Button("Do Something"))
        {
            Debug.Log("Button clicked!");
        }
    }
`
})

Create Custom Inspector

// Create custom inspector script
mcp__unity-mcp-server__create_class({
  path: "Assets/Editor/MyComponentEditor.cs",
  className: "MyComponentEditor",
  namespace: "MyProject.Editor",
  baseType: "Editor",
  usings: "UnityEditor"
})

// Add CustomEditor attribute and OnInspectorGUI
mcp__unity-mcp-server__edit_structured({
  path: "Assets/Editor/MyComponentEditor.cs",
  symbolName: "MyComponentEditor",
  operation: "insert_before",
  newText: "[CustomEditor(typeof(MyComponent))]\n"
})

mcp__unity-mcp-server__edit_structured({
  path: "Assets/Editor/MyComponentEditor.cs",
  symbolName: "MyComponentEditor",
  operation: "insert_after",
  newText: `
    public override void OnInspectorGUI()
    {
        serializedObject.Update();

        EditorGUILayout.PropertyField(serializedObject.FindProperty("myField"));

        if (GUILayout.Button("Custom Button"))
        {
            ((MyComponent)target).DoSomething();
        }

        serializedObject.ApplyModifiedProperties();
    }
`
})

Core Concepts

IMGUI Lifecycle

OnGUI() called every frame (or on repaint/input)
    ├── Layout Event: Calculate sizes
    ├── Repaint Event: Draw controls
    └── Input Events: Handle mouse/keyboard

Event Types

void OnGUI()
{
    Event e = Event.current;

    switch (e.type)
    {
        case EventType.Layout:
            // Calculate layout
            break;
        case EventType.Repaint:
            // Draw visuals
            break;
        case EventType.MouseDown:
            // Handle click
            break;
        case EventType.KeyDown:
            // Handle keyboard
            break;
    }
}

GUILayout vs EditorGUILayout

GUILayoutEditorGUILayout
Works everywhereEditor only
Basic controlsRich editor controls
GUILayout.ButtonEditorGUILayout.PropertyField
GUILayout.TextFieldEditorGUILayout.ObjectField
GUILayout.LabelEditorGUILayout.HelpBox

EditorWindow Patterns

Basic Window Structure

using UnityEngine;
using UnityEditor;

public class MyToolWindow : EditorWindow
{
    // Serialized state (survives recompile)
    [SerializeField] private string searchText = "";
    [SerializeField] private Vector2 scrollPosition;

    // Non-serialized state
    private GUIStyle headerStyle;

    [MenuItem("Tools/My Tool %#t")] // Ctrl+Shift+T
    public static void ShowWindow()
    {
        var window = GetWindow<MyToolWindow>();
        window.titleContent = new GUIContent("My Tool", EditorGUIUtility.IconContent("d_Settings").image);
        window.minSize = new Vector2(300, 200);
        window.Show();
    }

    private void OnEnable()
    {
        // Initialize when window opens
    }

    private void OnDisable()
    {
        // Cleanup when window closes
    }

    private void OnGUI()
    {
        InitStyles();
        DrawToolbar();
        DrawContent();
    }

    private void InitStyles()
    {
        headerStyle ??= new GUIStyle(EditorStyles.boldLabel)
        {
            fontSize = 14,
            alignment = TextAnchor.MiddleCenter
        };
    }

    private void DrawToolbar()
    {
        using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
        {
            if (GUILayout.Button("Refresh", EditorStyles.toolbarButton, GUILayout.Width(60)))
            {
                Refresh();
            }

            GUILayout.FlexibleSpace();

            searchText = EditorGUILayout.TextField(searchText, EditorStyles.toolbarSearchField, GUILayout.Width(200));
        }
    }

    private void DrawContent()
    {
        scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
        {
            GUILayout.Label("Content Here", headerStyle);
        }
        EditorGUILayout.EndScrollView();
    }

    private void Refresh()
    {
        Repaint();
    }
}

MCP Implementation

// Create the window class
mcp__unity-mcp-server__create_class({
  path: "Assets/Editor/Tools/AssetBrowserWindow.cs",
  className: "AssetBrowserWindow",
  namespace: "MyProject.Editor.Tools",
  baseType: "EditorWindow",
  usings: "UnityEditor,System.Collections.Generic,System.Linq"
})

// Add complete implementation
mcp__unity-mcp-server__edit_structured({
  path: "Assets/Editor/Tools/AssetBrowserWindow.cs",
  symbolName: "AssetBrowserWindow",
  operation: "insert_after",
  newText: `
    [SerializeField] private string searchFilter = "";
    [SerializeField] private Vector2 scrollPos;
    private List<string> assetPaths = new List<string>();

    [MenuItem("Tools/Asset Browser")]
    public static void ShowWindow()
    {
        GetWindow<AssetBrowserWindow>("Asset Browser");
    }

    private void OnEnable()
    {
        RefreshAssets();
    }

    private void OnGUI()
    {
        DrawSearchBar();
        DrawAssetList();
    }

    private void DrawSearchBar()
    {
        using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
        {
            EditorGUI.BeginChangeCheck();
            searchFilter = EditorGUILayout.TextField(searchFilter, EditorStyles.toolbarSearchField);
            if (EditorGUI.EndChangeCheck())
            {
                RefreshAssets();
            }

            if (GUILayout.Button("Refresh", EditorStyles.toolbarButton, GUILayout.Width(60)))
            {
                RefreshAssets();
            }
        }
    }

    private void DrawAssetList()
    {
        scrollPos = EditorGUILayout.BeginScrollView(scrollPos);

        foreach (var path in assetPaths)
        {
            using (new EditorGUILayout.HorizontalScope())
            {
                var icon = AssetDatabase.GetCachedIcon(path);
                GUILayout.Label(icon, GUILayout.Width(20), GUILayout.Height(20));

                if (GUILayout.Button(System.IO.Path.GetFileName(path), EditorStyles.linkLabel))
                {
                    Selection.activeObject = AssetDatabase.LoadAssetAtPath<Object>(path);
                    EditorGUIUtility.PingObject(Selection.activeObject);
                }
            }
        }

        EditorGUILayout.EndScrollView();
    }

    private void RefreshAssets()
    {
        var filter = string.IsNullOrEmpty(searchFilter) ? "t:Object" : searchFilter;
        assetPaths = AssetDatabase.FindAssets(filter)
            .Select(AssetDatabase.GUIDToAssetPath)
            .Take(100)
            .ToList();
        Repaint();
    }
`
})

Custom Inspector Patterns

Basic Inspector

using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(EnemySpawner))]
public class EnemySpawnerEditor : Editor
{
    private SerializedProperty spawnPrefab;
    private SerializedProperty spawnInterval;
    private SerializedProperty maxEnemies;

    private void OnEnable()
    {
        spawnPrefab = serializedObject.FindProperty("spawnPrefab");
        spawnInterval = serializedObject.FindProperty("spawnInterval");
        maxEnemies = serializedObject.FindProperty("maxEnemies");
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();

        EditorGUILayout.PropertyField(spawnPrefab);

        EditorGUILayout.Space();
        EditorGUILayout.LabelField("Spawn Settings", EditorStyles.boldLabel);

        EditorGUILayout.PropertyField(spawnInterval);
        EditorGUILayout.PropertyField(maxEnemies);

        EditorGUILayout.Space();

        // Custom button
        if (GUILayout.Button("Spawn Test Enemy"))
        {
            var spawner = (EnemySpawner)target;
            spawner.SpawnEnemy();
        }

        serializedObject.ApplyModifiedProperties();
    }
}

MCP Implementation

// Create inspector class
mcp__unity-mcp-server__create_class({
  path: "Assets/Editor/Inspectors/WeaponDataEditor.cs",
  className: "WeaponDataEditor",
  namespace: "MyProject.Editor",
  baseType: "Editor",
  usings: "UnityEditor"
})

// Add CustomEditor attribute
mcp__unity-mcp-server__edit_structured({
  path: "Assets/Editor/Inspectors/WeaponDataEditor.cs",
  symbolName: "WeaponDataEditor",
  operation: "insert_before",
  newText: "[CustomEditor(typeof(WeaponData))]\n"
})

// Add inspector implementation
mcp__unity-mcp-server__edit_structured({
  path: "Assets/Editor/Inspectors/WeaponDataEditor.cs",
  symbolName: "WeaponDataEditor",
  operation: "insert_after",
  newText: `
    private SerializedProperty weaponName;
    private SerializedProperty damage;
    private SerializedProperty attackSpeed;
    private SerializedProperty weaponType;

    private bool showStats = true;

    private void OnEnable()
    {
        weaponName = serializedObject.FindProperty("weaponName");
        damage = serializedObject.FindProperty("damage");
        attackSpeed = serializedObject.FindProperty("attackSpeed");
        weaponType = serializedObject.FindProperty("weaponType");
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();

        // Header
        EditorGUILayout.LabelField("Weapon Configuration", EditorStyles.boldLabel);
        EditorGUILayout.Space();

        EditorGUILayout.PropertyField(weaponName);
        EditorGUILayout.PropertyField(weaponType);

        EditorGUILayout.Space();

        // Foldout section
        showStats = EditorGUILayout.Foldout(showStats, "Combat Stats", true);
        if (showStats)
        {
            EditorGUI.indentLevel++;
            EditorGUILayout.PropertyField(damage);
            EditorGUILayout.PropertyField(attackSpeed);

            // Calculated DPS
            float dps = damage.floatValue * attackSpeed.floatValue;
            EditorGUILayout.HelpBox($"DPS: {dps:F1}", MessageType.Info);
            EditorGUI.indentLevel--;
        }

        serializedObject.ApplyModifiedProperties();
    }
`
})

Foldout Groups

private bool showAdvanced = false;

public override void OnInspectorGUI()
{
    serializedObject.Update();

    // Basic properties
    EditorGUILayout.PropertyField(serializedObject.FindProperty("basicField"));

    // Foldout group
    showAdvanced = EditorGUILayout.Foldout(showAdvanced, "Advanced Settings", true);
    if (showAdvanced)
    {
        EditorGUI.indentLevel++;
        EditorGUILayout.PropertyField(serializedObject.FindProperty("advancedField1"));
        EditorGUILayout.PropertyField(serializedObject.FindProperty("advancedField2"));
        EditorGUI.indentLevel--;
    }

    serializedObject.ApplyModifiedProperties();
}

Conditional Display

public override void OnInspectorGUI()
{
    serializedObject.Update();

    var enableFeature = serializedObject.FindProperty("enableFeature");
    EditorGUILayout.PropertyField(enableFeature);

    // Show only when enabled
    if (enableFeature.boolValue)
    {
        EditorGUI.indentLevel++;
        EditorGUILayout.PropertyField(serializedObject.FindProperty("featureValue"));
        EditorGUILayout.PropertyField(serializedObject.FindProperty("featureMode"));
        EditorGUI.indentLevel--;
    }

    serializedObject.ApplyModifiedProperties();
}

Property Drawer Patterns

Basic Property Drawer

using UnityEngine;
using UnityEditor;

[CustomPropertyDrawer(typeof(MinMaxRange))]
public class MinMaxRangeDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        EditorGUI.BeginProperty(position, label, property);

        position = EditorGUI.PrefixLabel(position, label);

        var minProp = property.FindPropertyRelative("min");
        var maxProp = property.FindPropertyRelative("max");

        float min = minProp.floatValue;
        float max = maxProp.floatValue;

        // MinMax slider
        var sliderRect = new Rect(position.x, position.y, position.width - 100, position.height);
        var minRect = new Rect(position.x + position.width - 95, position.y, 45, position.height);
        var maxRect = new Rect(position.x + position.width - 45, position.y, 45, position.height);

        EditorGUI.MinMaxSlider(sliderRect, ref min, ref max, 0f, 100f);
        min = EditorGUI.FloatField(minRect, min);
        max = EditorGUI.FloatField(maxRect, max);

        minProp.floatValue = min;
        maxProp.floatValue = max;

        EditorGUI.EndProperty();
    }
}

MCP Implementation

// Create property drawer
mcp__unity-mcp-server__create_class({
  path: "Assets/Editor/PropertyDrawers/ColorRangeDrawer.cs",
  className: "ColorRangeDrawer",
  namespace: "MyProject.Editor",
  baseType: "PropertyDrawer",
  usings: "UnityEditor"
})

// Add attribute and implementation
mcp__unity-mcp-server__edit_structured({
  path: "Assets/Editor/PropertyDrawers/ColorRangeDrawer.cs",
  symbolName: "ColorRangeDrawer",
  operation: "insert_before",
  newText: "[CustomPropertyDrawer(typeof(ColorRange))]\n"
})

mcp__unity-mcp-server__edit_structured({
  path: "Assets/Editor/PropertyDrawers/ColorRangeDrawer.cs",
  symbolName: "ColorRangeDrawer",
  operation: "insert_after",
  newText: `
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        EditorGUI.BeginProperty(position, label, property);

        position = EditorGUI.PrefixLabel(position, label);

        var startColor = property.FindPropertyRelative("startColor");
        var endColor = property.FindPropertyRelative("endColor");

        float halfWidth = position.width / 2 - 2;
        var startRect = new Rect(position.x, position.y, halfWidth, position.height);
        var endRect = new Rect(position.x + halfWidth + 4, position.y, halfWidth, position.height);

        EditorGUI.PropertyField(startRect, startColor, GUIContent.none);
        EditorGUI.PropertyField(endRect, endColor, GUIContent.none);

        EditorGUI.EndProperty();
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        return EditorGUIUtility.singleLineHeight;
    }
`
})

Multi-Line Property Drawer

[CustomPropertyDrawer(typeof(DialogLine))]
public class DialogLineDrawer : PropertyDrawer
{
    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        // 3 lines + spacing
        return EditorGUIUtility.singleLineHeight * 3 + 4;
    }

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        EditorGUI.BeginProperty(position, label, property);

        float lineHeight = EditorGUIUtility.singleLineHeight;

        var speakerRect = new Rect(position.x, position.y, position.width, lineHeight);
        var textRect = new Rect(position.x, position.y + lineHeight + 2, position.width, lineHeight * 2);

        EditorGUI.PropertyField(speakerRect, property.FindPropertyRelative("speaker"));
        EditorGUI.PropertyField(textRect, property.FindPropertyRelative("text"));

        EditorGUI.EndProperty();
    }
}

Attribute-Based Drawers

ReadOnly Attribute

// Runtime attribute
public class ReadOnlyAttribute : PropertyAttribute { }

// Editor drawer
[CustomPropertyDrawer(typeof(ReadOnlyAttribute))]
public class ReadOnlyDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        GUI.enabled = false;
        EditorGUI.PropertyField(position, property, label);
        GUI.enabled = true;
    }
}

Range with Label Attribute

// Runtime attribute
public class LabeledRangeAttribute : PropertyAttribute
{
    public float Min { get; }
    public float Max { get; }
    public string MinLabel { get; }
    public string MaxLabel { get; }

    public LabeledRangeAttribute(float min, float max, string minLabel, string maxLabel)
    {
        Min = min;
        Max = max;
        MinLabel = minLabel;
        MaxLabel = maxLabel;
    }
}

// Editor drawer
[CustomPropertyDrawer(typeof(LabeledRangeAttribute))]
public class LabeledRangeDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        var attr = (LabeledRangeAttribute)attribute;

        EditorGUI.BeginProperty(position, label, property);
        position = EditorGUI.PrefixLabel(position, label);

        // Min label
        var minLabelRect = new Rect(position.x, position.y, 30, position.height);
        GUI.Label(minLabelRect, attr.MinLabel);

        // Slider
        var sliderRect = new Rect(position.x + 35, position.y, position.width - 70, position.height);
        property.floatValue = GUI.HorizontalSlider(sliderRect, property.floatValue, attr.Min, attr.Max);

        // Max label
        var maxLabelRect = new Rect(position.x + position.width - 30, position.y, 30, position.height);
        GUI.Label(maxLabelRect, attr.MaxLabel);

        EditorGUI.EndProperty();
    }
}

SceneView GUI (Handles)

Gizmo Drawing

[CustomEditor(typeof(SpawnArea))]
public class SpawnAreaEditor : Editor
{
    private void OnSceneGUI()
    {
        var spawner = (SpawnArea)target;

        // Draw spawn area bounds
        Handles.color = new Color(0, 1, 0, 0.3f);
        Handles.DrawSolidDisc(spawner.transform.position, Vector3.up, spawner.radius);

        // Draw editable radius handle
        Handles.color = Color.green;
        EditorGUI.BeginChangeCheck();
        float newRadius = Handles.RadiusHandle(Quaternion.identity, spawner.transform.position, spawner.radius);
        if (EditorGUI.EndChangeCheck())
        {
            Undo.RecordObject(spawner, "Change Spawn Radius");
            spawner.radius = newRadius;
        }

        // Draw label
        Handles.Label(spawner.transform.position + Vector3.up * 2, $"Spawn Area\nRadius: {spawner.radius:F1}");
    }
}

Position Handle

private void OnSceneGUI()
{
    var waypoint = (WaypointPath)target;

    for (int i = 0; i < waypoint.points.Count; i++)
    {
        EditorGUI.BeginChangeCheck();
        Vector3 newPos = Handles.PositionHandle(waypoint.points[i], Quaternion.identity);
        if (EditorGUI.EndChangeCheck())
        {
            Undo.RecordObject(waypoint, "Move Waypoint");
            waypoint.points[i] = newPos;
        }

        // Draw connection lines
        if (i > 0)
        {
            Handles.DrawLine(waypoint.points[i - 1], waypoint.points[i]);
        }

        // Draw index label
        Handles.Label(waypoint.points[i], $"Point {i}");
    }
}

Common UI Patterns

Horizontal Layout

using (new EditorGUILayout.HorizontalScope())
{
    GUILayout.Label("Name:", GUILayout.Width(60));
    value = EditorGUILayout.TextField(value);
    if (GUILayout.Button("Clear", GUILayout.Width(50)))
    {
        value = "";
    }
}

Vertical Layout with Box

using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
{
    GUILayout.Label("Section Title", EditorStyles.boldLabel);
    EditorGUILayout.PropertyField(prop1);
    EditorGUILayout.PropertyField(prop2);
}

Toolbar

private int selectedTab = 0;
private string[] tabs = { "General", "Advanced", "Debug" };

private void OnGUI()
{
    selectedTab = GUILayout.Toolbar(selectedTab, tabs);

    switch (selectedTab)
    {
        case 0: DrawGeneralTab(); break;
        case 1: DrawAdvancedTab(); break;
        case 2: DrawDebugTab(); break;
    }
}

Progress Bar

// Simple progress bar
EditorGUI.ProgressBar(rect, progress, $"{progress * 100:F0}%");

// Progress bar in inspector
public override void OnInspectorGUI()
{
    var healthProp = serializedObject.FindProperty("health");
    var maxHealthProp = serializedObject.FindProperty("maxHealth");

    float ratio = healthProp.floatValue / maxHealthProp.floatValue;

    Rect rect = GUILayoutUtility.GetRect(18, 18, "TextField");
    EditorGUI.ProgressBar(rect, ratio, $"Health: {healthProp.floatValue}/{maxHealthProp.floatValue}");
}

Drag and Drop

private void OnGUI()
{
    var dropArea = GUILayoutUtility.GetRect(100, 100);
    GUI.Box(dropArea, "Drop Asset Here");

    Event evt = Event.current;

    switch (evt.type)
    {
        case EventType.DragUpdated:
        case EventType.DragPerform:
            if (!dropArea.Contains(evt.mousePosition))
                break;

            DragAndDrop.visualMode = DragAndDropVisualMode.Copy;

            if (evt.type == EventType.DragPerform)
            {
                DragAndDrop.AcceptDrag();

                foreach (var obj in DragAndDrop.objectReferences)
                {
                    Debug.Log($"Dropped: {obj.name}");
                }
            }
            break;
    }
}

Undo Support

Recording Changes

// Single object
Undo.RecordObject(target, "Change Value");
myComponent.value = newValue;

// Multiple objects
Undo.RecordObjects(targets, "Change Values");
foreach (var t in targets)
{
    ((MyComponent)t).value = newValue;
}

// Create object with undo
var newObj = new GameObject("New Object");
Undo.RegisterCreatedObjectUndo(newObj, "Create Object");

// Destroy with undo
Undo.DestroyObjectImmediate(obj);

Property Change Callback

private void OnEnable()
{
    Undo.undoRedoPerformed += OnUndoRedo;
}

private void OnDisable()
{
    Undo.undoRedoPerformed -= OnUndoRedo;
}

private void OnUndoRedo()
{
    Repaint();
}

EditorPrefs (Persistent Settings)

public class MyToolWindow : EditorWindow
{
    private const string PREF_KEY = "MyTool_";

    private bool showAdvanced;
    private int selectedMode;

    private void OnEnable()
    {
        // Load settings
        showAdvanced = EditorPrefs.GetBool(PREF_KEY + "ShowAdvanced", false);
        selectedMode = EditorPrefs.GetInt(PREF_KEY + "SelectedMode", 0);
    }

    private void OnDisable()
    {
        // Save settings
        EditorPrefs.SetBool(PREF_KEY + "ShowAdvanced", showAdvanced);
        EditorPrefs.SetInt(PREF_KEY + "SelectedMode", selectedMode);
    }
}

Message Types

// Help boxes
EditorGUILayout.HelpBox("Info message", MessageType.Info);
EditorGUILayout.HelpBox("Warning message", MessageType.Warning);
EditorGUILayout.HelpBox("Error message", MessageType.Error);
EditorGUILayout.HelpBox("No icon message", MessageType.None);

// Dialog boxes
if (EditorUtility.DisplayDialog("Confirm", "Are you sure?", "Yes", "No"))
{
    // User clicked Yes
}

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
34
Forks
7
Last commit
Sep 2026
Advanced
Item type
skill
Key
unity-editor-imgui-design
Source
github.com/akiojin/unity-mcp-server