agentsclimarketplace

Uw ui toolkit binder

Skill IdoCohen560/claude-unity-game-studio/examples/my-first-game/.claude/skills/uw-ui-toolkit-binder

Generate Unity 6+ UI Toolkit Runtime Data Binding code using MVVM pattern with [CreateProperty], DataBinding, and PropertyPath. Use when creating UI screens, HUDs, menus, inventories, settings panels, or any data-bound UI elements with UI Toolkit. Triggers on requests like "create a health bar", "build the HUD", "make a settings screen", "bind data to UI", "create an inventory UI", "add a pause menu", "show player stats on screen", "build a shop UI", "create a dialogue box", or any task involving runtime UI layout, styling, or data display. Also use when the user mentions UXML, USS, ViewModel, or UI bindings. Only activates when ProjectConfig.yaml -> ui_system is "UIToolkit" or "Mixed". Requires Unity 6.0+.From its SKILL.md

Install
npx -y skills add IdoCohen560/claude-unity-game-studio --skill uw-ui-toolkit-binder

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

13.3 KB, ~3.0k tokens by cl100k_base, as published. Nobody here has run it

UI Toolkit Binder

Generate MVVM UI code using Unity 6's Runtime Data Binding.

Before You Start

  1. Read docs/ProjectConfig.yaml for:
    • ui_system — must be "UIToolkit" or "Mixed". If "UGUI", this skill does not apply.
    • architecture_pattern"so-first" or "di-first" (affects how ViewModels get their data).
    • mcp.unity_mcp — if true, call refresh_unity after creating files.
  2. Read docs/NAMING_CONVENTIONS.md — UXML files use PascalCase (e.g., PlayerHUD.uxml), USS files match (e.g., PlayerHUD.uss).
  3. Read docs/CODING_STANDARDS.md — class structure order, serialization rules, async patterns apply to ViewModels.
  4. If UI motion/animation is needed, check docs/GFD_Template.md for guidelines and use uw-game-feel-integrator for tween integration.

When to Use UI Toolkit vs uGUI

Use CaseRecommendedWhy
Menus, settings, inventories, data-heavy UIUI ToolkitBatched rendering, no GameObject overhead, CSS-like styling
Animated in-game HUD, world-space UIuGUIEasier world-space Canvas, mature animation workflow
Complex project with bothHybridUI Toolkit for menus, uGUI for in-game HUD

If ProjectConfig.yaml -> ui_system is "UGUI", stop here — use uGUI patterns instead.

Architecture

Model (Data/SO) --> ViewModel ([CreateProperty] MonoBehaviour) --> View (UXML + USS)
  • Model: Game data — ScriptableObjects, runtime state, network state. The ViewModel reads from these.
  • ViewModel: A MonoBehaviour with [CreateProperty] on properties. This is the binding source. It bridges game data to UI elements without the View knowing about game logic.
  • View: UXML defines layout, USS defines styling. Bound to ViewModel properties via DataBinding in a controller script.

File Structure

For a feature called PlayerHUD inside a feature module:

Features/PlayerHUD/
├── Scripts/
│   ├── {RootNamespace}.PlayerHUD.asmdef
│   ├── PlayerHUDViewModel.cs
│   └── PlayerHUDController.cs
├── UI/
│   ├── PlayerHUD.uxml
│   └── PlayerHUD.uss
└── Tests/
    └── {RootNamespace}.PlayerHUD.Tests.asmdef

Use uw-unity-feature-scaffold to generate the module structure first, then add the UI-specific files.

ViewModel Pattern

The ViewModel exposes bindable properties using [CreateProperty] from Unity.Properties. Properties must have public getters for the binding system to read them.

using Unity.Properties;
using UnityEngine;

namespace {RootNamespace}.PlayerHUD
{
    public class PlayerHUDViewModel : MonoBehaviour
    {
        [SerializeField] private int _maxHealth = 100;

        private int _currentHealth;

        [CreateProperty]
        public int Health
        {
            get => _currentHealth;
            set
            {
                if (_currentHealth == value) return;
                _currentHealth = value;
            }
        }

        [CreateProperty]
        public float HealthPercent => _maxHealth > 0 ? (float)Health / _maxHealth : 0f;

        [CreateProperty]
        public string HealthText => $"{Health} / {_maxHealth}";

        [CreateProperty]
        public int CoinCount { get; private set; }

        /// <summary>
        /// Called by game systems to update health display.
        /// </summary>
        public void SetHealth(int current, int max)
        {
            _maxHealth = max;
            Health = current;
        }

        public void AddCoins(int amount)
        {
            CoinCount += amount;
        }
    }
}

When a [CreateProperty] value changes, the binding system detects it automatically on the next frame. No manual "notify" call is needed — Unity polls [CreateProperty] values each frame.

UXML Template

UXML defines the layout structure. Think of it like HTML for Unity UI.

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
    <ui:VisualElement name="hud-root" class="hud-container">
        <!-- Health bar -->
        <ui:VisualElement name="health-section" class="stat-section">
            <ui:Label name="health-label" text="100 / 100" class="stat-text" />
            <ui:VisualElement name="health-bar-bg" class="bar-background">
                <ui:VisualElement name="health-bar-fill" class="bar-fill health-fill" />
            </ui:VisualElement>
        </ui:VisualElement>

        <!-- Coin counter -->
        <ui:VisualElement name="coin-section" class="stat-section">
            <ui:Label name="coin-label" text="0" class="stat-text" />
        </ui:VisualElement>
    </ui:VisualElement>
</ui:UXML>

Naming: Use kebab-case for UXML element name attributes (e.g., health-label, coin-section). This follows USS selector conventions and avoids conflicts with C# naming.

USS Stylesheet

USS is Unity's CSS-like styling language. Define visual appearance here, not in C#.

.hud-container {
    position: absolute;
    top: 16px;
    left: 16px;
    padding: 8px;
    flex-direction: column;
}

.stat-section {
    flex-direction: row;
    align-items: center;
    margin-bottom: 4px;
}

.stat-text {
    font-size: 18px;
    color: white;
    -unity-font-style: bold;
    min-width: 80px;
}

.bar-background {
    width: 200px;
    height: 16px;
    background-color: rgba(0, 0, 0, 0.5);
    border-radius: 4px;
    overflow: hidden;
}

.bar-fill {
    height: 100%;
    border-radius: 4px;
    transition-property: width;
    transition-duration: 0.3s;
}

.health-fill {
    background-color: rgb(76, 175, 80);
    width: 100%;
}

Transitions: USS supports transition-property, transition-duration, transition-timing-function, and transition-delay for smooth animated changes. Use these for bar fills, opacity fades, and position shifts instead of C# tweens where possible.

Controller: Binding + Events

The controller loads the UXML, applies the USS, wires up data bindings, and handles UI events like button clicks.

using UnityEngine;
using UnityEngine.UIElements;

namespace {RootNamespace}.PlayerHUD
{
    [RequireComponent(typeof(UIDocument))]
    public class PlayerHUDController : MonoBehaviour
    {
        [SerializeField] private PlayerHUDViewModel _viewModel;

        private UIDocument _document;
        private Label _healthLabel;
        private VisualElement _healthBarFill;
        private Label _coinLabel;

        private void Awake()
        {
            _document = GetComponent<UIDocument>();
        }

        private void OnEnable()
        {
            var root = _document.rootVisualElement;

            // Cache element references (equivalent of GetComponent caching)
            _healthLabel = root.Q<Label>("health-label");
            _healthBarFill = root.Q<VisualElement>("health-bar-fill");
            _coinLabel = root.Q<Label>("coin-label");

            // Data bindings
            _healthLabel.SetBinding("text", new DataBinding
            {
                dataSource = _viewModel,
                dataSourcePath = new PropertyPath(nameof(PlayerHUDViewModel.HealthText))
            });

            _coinLabel.SetBinding("text", new DataBinding
            {
                dataSource = _viewModel,
                dataSourcePath = new PropertyPath(nameof(PlayerHUDViewModel.CoinCount))
            });
        }

        private void Update()
        {
            // Update bar width from ViewModel — binding handles labels,
            // but bar width needs manual style update since it's a style property
            _healthBarFill.style.width = Length.Percent(_viewModel.HealthPercent * 100f);
        }
    }
}

Why cache in OnEnable, not Awake? The UIDocument.rootVisualElement may not be available in Awake. OnEnable is the earliest reliable point to query the visual tree.

Event Binding (Buttons, Clicks)

For interactive elements like buttons, register callbacks in OnEnable and unregister in OnDisable to prevent memory leaks.

private Button _pauseButton;
private Button _settingsButton;

private void OnEnable()
{
    var root = _document.rootVisualElement;

    _pauseButton = root.Q<Button>("pause-button");
    _settingsButton = root.Q<Button>("settings-button");

    _pauseButton.clicked += OnPauseClicked;
    _settingsButton.clicked += OnSettingsClicked;
}

private void OnDisable()
{
    _pauseButton.clicked -= OnPauseClicked;
    _settingsButton.clicked -= OnSettingsClicked;
}

private void OnPauseClicked()
{
    // Raise event or call game system
}

private void OnSettingsClicked()
{
    // Navigate to settings screen
}

For more complex interactions (hover, drag, custom input), use RegisterCallback<T>:

// Pointer events
element.RegisterCallback<PointerEnterEvent>(OnHover);
element.RegisterCallback<PointerLeaveEvent>(OnHoverExit);

// Always unregister in OnDisable
element.UnregisterCallback<PointerEnterEvent>(OnHover);

Dynamic Lists (Runtime-Generated Items)

For inventories, leaderboards, or any list populated at runtime, create items from a template UXML and add them to a parent container.

[SerializeField] private VisualTreeAsset _itemTemplate;

private void PopulateInventory(List<ItemData> items)
{
    var container = _document.rootVisualElement.Q<VisualElement>("inventory-list");
    container.Clear();

    foreach (var item in items)
    {
        var element = _itemTemplate.Instantiate();
        element.Q<Label>("item-name").text = item.DisplayName;
        element.Q<Label>("item-count").text = item.Count.ToString();
        container.Add(element);
    }
}

For large lists (100+ items), use ListView with virtualization — it only renders visible items:

var listView = root.Q<ListView>("inventory-list");
listView.itemsSource = _inventoryItems;
listView.makeItem = () => _itemTemplate.Instantiate();
listView.bindItem = (element, index) =>
{
    var item = _inventoryItems[index];
    element.Q<Label>("item-name").text = item.DisplayName;
};

Value Formatting

When binding numeric data that needs formatting (percentages, currency, time), handle it in the ViewModel as a computed [CreateProperty] string:

[CreateProperty]
public string DamageText => $"{Damage:F0}";

[CreateProperty]
public string TimerText
{
    get
    {
        int minutes = Mathf.FloorToInt(_remainingTime / 60f);
        int seconds = Mathf.FloorToInt(_remainingTime % 60f);
        return $"{minutes:D2}:{seconds:D2}";
    }
}

[CreateProperty]
public string PriceText => $"{Price:N0} G";

Keep formatting logic in the ViewModel, not the View layer. The View should only display strings.

Performance Notes

  • Query once, cache always. Call root.Q<T>() in OnEnable and store references. Never query inside Update.
  • USS transitions over C# tweens for simple property changes (opacity, width, position). USS transitions are GPU-accelerated.
  • ListView for large lists. Virtualization avoids creating hundreds of VisualElements. Use ListView.RefreshItems() to update, not Clear() + re-add.
  • Minimize style changes in Update. Each style.* assignment can trigger layout recalculation. Batch changes or use USS class toggling (AddToClassList/RemoveFromClassList) instead.
  • Class toggling over direct style. Prefer element.EnableInClassList("low-health", healthPercent < 0.25f) over setting individual style properties in C#.

After Setup

  • Add game feel: Use uw-game-feel-integrator for screen shake, flash effects, or tween-based UI animations that go beyond USS transitions.
  • Custom editor tools: Use uw-unity-editor-tools if you need custom Inspector UI or Editor Windows built with UI Toolkit.
  • Write tests: Use uw-unity-test-runner — test ViewModel logic (property calculations, state changes) in EditMode tests without needing UI rendering.

Rules

  • [CreateProperty] requires Unity.Properties namespace — always include the using.
  • DataBinding and related types are in UnityEngine.UIElements.
  • Always generate matching .uxml and .uss files alongside ViewModel C# scripts.
  • UXML/USS file names use PascalCase (per NAMING_CONVENTIONS.md): PlayerHUD.uxml, PlayerHUD.uss.
  • Cache all root.Q<T>() calls in OnEnable — never query the visual tree in Update.
  • Register event callbacks in OnEnable, unregister in OnDisable.
  • [SerializeField] private for Inspector-exposed fields on ViewModels and Controllers — never public fields.
  • Keep formatting/conversion logic in the ViewModel. The View only displays strings and reacts to events.
  • If ProjectConfig.yaml -> mcp.unity_mcp is true, call refresh_unity after creating files.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Gives 0 of the 12 instructions most design frontend skills give in ~3.0k tokens

Counted across 1,169 of the 1,878 authors here whose files we hold, read 2026-08-07

  • Use CSS variables for color consistencyin 72 of 1169, across 23 files
  • Commit to one bold aesthetic direction before codingin 72 of 1169, across 27 files
  • Match implementation complexity to the aesthetic visionin 70 of 1169, across 20 files
  • Add atmospheric background effects and texturesin 57 of 1169, across 9 files
  • Use unexpected spatial compositions and layoutsin 56 of 1169, across 8 files
  • Implement real working codein 55 of 1169, across 7 files
  • Vary themes and aesthetics across different designsin 48 of 1169, across 7 files
  • Launch chromium in headless modein 47 of 1169, across 4 files
  • Close the browser when donein 47 of 1169, across 4 files
  • Run provided scripts with help flag firstin 47 of 1169, across 4 files
  • Wait for network idle statein 47 of 1169, across 4 files
  • Use descriptive selectors for elementsin 47 of 1169, across 4 files

Said here and by no other author read

  • create MonoBehaviour ViewModels using the CreateProperty attribute
  • define UXML layout files and USS styling files
  • load UXML and apply USS inside controller scripts
  • wire DataBinding objects to ViewModel properties using PropertyPath
  • cache VisualElement references inside OnEnable
  • register UI event callbacks in OnEnable

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 326,790. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.