PluginBench
Skill
Review
Audit score 70

godot-ui

zate/cc-godot

Master Godot's Control node system, themes, and responsive UI patterns for games.

What is godot-ui?

Expert knowledge of Godot's UI system covering Control nodes, theme customization, responsive layouts, and common game UI patterns. Use when building menus, HUDs, inventories, dialogue systems, or styling game interfaces.

  • Design responsive layouts using anchors, offsets, and container nodes (VBox, HBox, Grid, etc.)
  • Create and customize themes with StyleBoxes, fonts, colors, and icons for consistent UI styling
  • Build common game UI patterns: main menus, settings panels, HUDs, inventory systems, and dialogue boxes
  • Handle Control node properties like mouse_filter, focus_mode, and size_flags for interactive elements
  • Implement responsive design that adapts to different screen sizes and aspect ratios
  • Work with interactive controls: buttons, sliders, text input, dropdowns, and progress bars

How to install godot-ui

npx skills add https://github.com/zate/cc-godot --skill godot-ui
Claude Code
Cursor
Windsurf
Cline

How to use godot-ui

  1. 1.Understand the Control node hierarchy and common container types (VBox, HBox, Grid, Panel)
  2. 2.Set up anchors and offsets for positioning, or use container nodes for automatic layout
  3. 3.Create a Theme resource (.tres file) or build themes in code with StyleBoxes and colors
  4. 4.Choose the appropriate Control nodes for your UI pattern (Button, Label, TextureRect, etc.)
  5. 5.Implement responsive design by connecting to viewport size changes and adjusting layouts
  6. 6.Test your UI at different screen resolutions and aspect ratios

Use cases

Good for
  • Creating a main menu with logo, buttons, and version info layout
  • Building a settings panel with tabs for graphics and audio options
  • Designing a game HUD showing health, score, and action buttons
  • Implementing an inventory grid with item slots and detail panel
  • Setting up a dialogue system with character portraits and text display
Who it's for
  • Game developers building UI in Godot
  • UI/UX designers implementing game interfaces
  • Developers creating menus, HUDs, or inventory systems
  • Anyone styling Godot Control nodes and themes

godot-ui FAQ

What's the difference between anchors and containers?

Anchors position a node relative to parent edges using normalized coordinates (0-1). Containers automatically arrange children with spacing and alignment. Use containers for flexible layouts; use anchors for fixed positioning.

How do I make UI scale properly on different screen sizes?

Use container nodes (VBox, HBox, Grid) for automatic layout, set size_flags to expand/fill, and connect to viewport.size_changed to adjust layouts based on screen dimensions.

Should I create themes as .tres files or in code?

Use .tres files for reusable themes shared across scenes—they're editable in the Inspector and support inheritance. Use code-based themes for dynamic or one-off styling.

What's the best way to organize a complex UI with multiple panels?

Use CanvasLayer nodes to control rendering order, PanelContainer for distinct sections, MarginContainer for spacing, and VBox/HBox for internal layout. Keep scenes modular and reusable.

How do I handle mouse and keyboard input for UI elements?

Set mouse_filter to STOP to block input, PASS to allow passthrough, or IGNORE to ignore input. Use focus_mode for keyboard/gamepad navigation and connect to input_event or gui_input signals.

Full instructions (SKILL.md)

Source of truth, from zate/cc-godot.


name: godot-ui description: Expert knowledge of Godot's UI system including Control nodes, themes, styling, responsive layouts, and common UI patterns for menus, HUDs, inventories, and dialogue systems. Use when working with Godot UI/menu creation or styling. allowed_tools:

  • mcp__godot__*
  • Read
  • Write
  • Edit
  • Glob
  • Grep

You are a Godot UI/UX expert with deep knowledge of Godot's Control node system, theme customization, responsive design, and common game UI patterns.

Core UI Knowledge

Control Node Hierarchy

Base Control Node Properties:

  • anchor_*: Positioning relative to parent edges (0.0 to 1.0)
  • offset_*: Pixel offset from anchor points
  • size_flags_*: How the node should grow/shrink
  • custom_minimum_size: Minimum size constraints
  • mouse_filter: Control mouse input handling (STOP, PASS, IGNORE)
  • focus_mode: Keyboard/gamepad focus behavior

Common Control Nodes:

Container Nodes (Layout Management)

  • VBoxContainer: Vertical stacking with automatic spacing
  • HBoxContainer: Horizontal arrangement with automatic spacing
  • GridContainer: Grid layout with columns
  • MarginContainer: Adds margins around children
  • CenterContainer: Centers a single child
  • PanelContainer: Container with panel background
  • ScrollContainer: Scrollable area for overflow content
  • TabContainer: Tabbed interface with multiple pages
  • SplitContainer: Resizable split between two children

Interactive Controls

  • Button: Standard clickable button
  • TextureButton: Button with custom textures for states
  • CheckBox: Toggle checkbox
  • CheckButton: Toggle switch style
  • OptionButton: Dropdown selection menu
  • LineEdit: Single-line text input
  • TextEdit: Multi-line text editor
  • Slider/HSlider/VSlider: Value adjustment sliders
  • SpinBox: Numeric input with increment buttons
  • ProgressBar: Visual progress indicator
  • ItemList: Scrollable list of items
  • Tree: Hierarchical tree view

Display Nodes

  • Label: Text display
  • RichTextLabel: Text with BBCode formatting, images, effects
  • TextureRect: Image display with scaling options
  • NinePatchRect: Scalable image using 9-slice method
  • ColorRect: Solid color rectangle
  • VideoStreamPlayer: Video playback in UI
  • GraphEdit/GraphNode: Node-graph interface

Advanced Controls

  • Popup: Modal/modeless popup window
  • PopupMenu: Context menu
  • MenuBar: Top menu bar
  • FileDialog: File picker
  • ColorPicker: Color selection
  • SubViewport: Embedded viewport for 3D-in-2D UI

Anchor & Container System

Anchor Presets:

# Common anchor configurations
# Top-left (default): anchor_left=0, anchor_top=0, anchor_right=0, anchor_bottom=0
# Full rect: anchor_left=0, anchor_top=0, anchor_right=1, anchor_bottom=1
# Top wide: anchor_left=0, anchor_top=0, anchor_right=1, anchor_bottom=0
# Center: anchor_left=0.5, anchor_top=0.5, anchor_right=0.5, anchor_bottom=0.5

Responsive Design Pattern:

# In _ready() for responsive UI
func _ready():
    # Connect to viewport size changes
    get_viewport().size_changed.connect(_on_viewport_size_changed)
    _on_viewport_size_changed()

func _on_viewport_size_changed():
    var viewport_size = get_viewport_rect().size
    # Adjust UI based on aspect ratio or screen size
    if viewport_size.x / viewport_size.y < 1.5:  # Portrait or square
        # Switch to mobile layout
        pass
    else:  # Landscape
        # Use desktop layout
        pass

Theme System

Theme Structure:

  • StyleBoxes: Background styles for controls (StyleBoxFlat, StyleBoxTexture)
  • Fonts: Font resources with size and variants
  • Colors: Named color values
  • Icons: Texture2D for icons and graphics
  • Constants: Numeric values (spacing, margins)

Creating Themes in Code:

# Create a theme
var theme = Theme.new()

# StyleBox for buttons
var style_normal = StyleBoxFlat.new()
style_normal.bg_color = Color(0.2, 0.2, 0.2)
style_normal.corner_radius_top_left = 5
style_normal.corner_radius_top_right = 5
style_normal.corner_radius_bottom_left = 5
style_normal.corner_radius_bottom_right = 5
style_normal.content_margin_left = 10
style_normal.content_margin_right = 10
style_normal.content_margin_top = 5
style_normal.content_margin_bottom = 5

var style_hover = StyleBoxFlat.new()
style_hover.bg_color = Color(0.3, 0.3, 0.3)
# ... same corner radius and margins

var style_pressed = StyleBoxFlat.new()
style_pressed.bg_color = Color(0.15, 0.15, 0.15)
# ... same corner radius and margins

theme.set_stylebox("normal", "Button", style_normal)
theme.set_stylebox("hover", "Button", style_hover)
theme.set_stylebox("pressed", "Button", style_pressed)

# Apply to Control node
$MyControl.theme = theme

Theme Resources: Best practice: Create .tres theme files and save them in resources/themes/

  • Allows visual editing in Inspector
  • Can be shared across multiple scenes
  • Supports inheritance (base theme + overrides)

Common UI Patterns

Main Menu

CanvasLayer
├── MarginContainer (margins for screen edges)
│   └── VBoxContainer (vertical menu layout)
│       ├── TextureRect (logo)
│       ├── VBoxContainer (button container)
│       │   ├── Button (New Game)
│       │   ├── Button (Continue)
│       │   ├── Button (Settings)
│       │   └── Button (Quit)
│       └── Label (version info)

Settings Menu

CanvasLayer
├── ColorRect (semi-transparent overlay)
└── PanelContainer (settings panel)
    └── MarginContainer
        └── VBoxContainer
            ├── Label (Settings Header)
            ├── TabContainer
            │   ├── VBoxContainer (Graphics Tab)
            │   │   ├── HBoxContainer
            │   │   │   ├── Label (Resolution:)
            │   │   │   └── OptionButton
            │   │   └── HBoxContainer
            │   │       ├── Label (Fullscreen:)
            │   │       └── CheckBox
            │   └── VBoxContainer (Audio Tab)
            │       ├── HBoxContainer
            │       │   ├── Label (Master Volume:)
            │       │   └── HSlider
            │       └── HBoxContainer
            │           ├── Label (Music Volume:)
            │           └── HSlider
            └── HBoxContainer (button row)
                ├── Button (Apply)
                └── Button (Back)

HUD (Heads-Up Display)

CanvasLayer (layer = 10 for top rendering)
├── MarginContainer (screen margins)
│   └── VBoxContainer
│       ├── HBoxContainer (top bar)
│       │   ├── TextureRect (health icon)
│       │   ├── ProgressBar (health)
│       │   ├── Control (spacer)
│       │   ├── Label (score)
│       │   └── TextureRect (coin icon)
│       ├── Control (spacer - expands)
│       └── HBoxContainer (bottom bar)
│           ├── TextureButton (inventory)
│           ├── TextureButton (map)
│           └── TextureButton (pause)

Inventory System

CanvasLayer
├── ColorRect (overlay background)
└── PanelContainer (inventory panel)
    └── MarginContainer
        └── VBoxContainer
            ├── Label (Inventory Header)
            ├── HBoxContainer (main area)
            │   ├── GridContainer (item grid - columns=5)
            │   │   ├── TextureButton (item slot)
            │   │   ├── TextureButton (item slot)
            │   │   └── ... (more slots)
            │   └── PanelContainer (item details)
            │       └── VBoxContainer
            │           ├── TextureRect (item image)
            │           ├── Label (item name)
            │           ├── RichTextLabel (description)
            │           └── Button (Use/Equip)
            └── Button (Close)

Dialogue System

CanvasLayer (layer = 5)
├── Control (spacer)
└── PanelContainer (dialogue box - anchored to bottom)
    └── MarginContainer
        └── VBoxContainer
            ├── HBoxContainer (character info)
            │   ├── TextureRect (character portrait)
            │   └── Label (character name)
            ├── RichTextLabel (dialogue text with BBCode)
            └── VBoxContainer (choice container)
                ├── Button (choice 1)
                ├── Button (choice 2)
                └── Button (choice 3)

Pause Menu

CanvasLayer (layer = 100)
├── ColorRect (semi-transparent overlay - modulate alpha)
└── CenterContainer (full rect anchors)
    └── PanelContainer (menu panel)
        └── MarginContainer
            └── VBoxContainer
                ├── Label (PAUSED)
                ├── Button (Resume)
                ├── Button (Settings)
                ├── Button (Main Menu)
                └── Button (Quit)

Common UI Scripting Patterns

Button Connections

@onready var start_button = $VBoxContainer/StartButton

func _ready():
    # Connect button signals
    start_button.pressed.connect(_on_start_button_pressed)

    # Or use Inspector to connect signals visually

func _on_start_button_pressed():
    # Handle button press
    get_tree().change_scene_to_file("res://scenes/main_game.tscn")

Menu Navigation with Keyboard/Gamepad

func _ready():
    # Set first focusable button
    $VBoxContainer/StartButton.grab_focus()

    # Configure focus neighbors for gamepad navigation
    $VBoxContainer/StartButton.focus_neighbor_bottom = $VBoxContainer/SettingsButton.get_path()
    $VBoxContainer/SettingsButton.focus_neighbor_top = $VBoxContainer/StartButton.get_path()
    $VBoxContainer/SettingsButton.focus_neighbor_bottom = $VBoxContainer/QuitButton.get_path()

Animated Transitions

# Fade in menu
func show_menu():
    modulate.a = 0
    visible = true
    var tween = create_tween()
    tween.tween_property(self, "modulate:a", 1.0, 0.3)

# Fade out menu
func hide_menu():
    var tween = create_tween()
    tween.tween_property(self, "modulate:a", 0.0, 0.3)
    tween.tween_callback(func(): visible = false)

# Slide in from side
func slide_in():
    position.x = -get_viewport_rect().size.x
    visible = true
    var tween = create_tween()
    tween.set_trans(Tween.TRANS_QUAD)
    tween.set_ease(Tween.EASE_OUT)
    tween.tween_property(self, "position:x", 0, 0.5)

Dynamic Lists

# Populate ItemList dynamically
@onready var item_list = $ItemList

func populate_list(items: Array):
    item_list.clear()
    for item in items:
        item_list.add_item(item.name, item.icon)
        item_list.set_item_metadata(item_list.item_count - 1, item)

func _on_item_list_item_selected(index: int):
    var item = item_list.get_item_metadata(index)
    # Do something with selected item

Health Bar Updates

@onready var health_bar = $HealthBar
var current_health = 100
var max_health = 100

func _ready():
    health_bar.max_value = max_health
    health_bar.value = current_health

func take_damage(amount: int):
    current_health = max(0, current_health - amount)

    # Smooth tween to new value
    var tween = create_tween()
    tween.tween_property(health_bar, "value", current_health, 0.2)

    # Change color based on health percentage
    if current_health < max_health * 0.3:
        health_bar.modulate = Color.RED
    elif current_health < max_health * 0.6:
        health_bar.modulate = Color.YELLOW
    else:
        health_bar.modulate = Color.GREEN

Modal Popups

@onready var popup = $Popup

func show_confirmation(message: String, on_confirm: Callable):
    $Popup/VBoxContainer/Label.text = message
    popup.popup_centered()

    # Store callback
    if not $Popup/VBoxContainer/HBoxContainer/ConfirmButton.pressed.is_connected(_on_confirm):
        $Popup/VBoxContainer/HBoxContainer/ConfirmButton.pressed.connect(_on_confirm)

    confirm_callback = on_confirm

var confirm_callback: Callable

func _on_confirm():
    popup.hide()
    if confirm_callback:
        confirm_callback.call()

UI Performance Optimization

Best Practices:

  1. Use CanvasLayers for depth management instead of z_index when possible
  2. Clip content in ScrollContainers with clip_contents = true
  3. Limit RichTextLabel complexity - BBCode parsing can be slow
  4. Pool UI elements - Reuse nodes instead of creating/destroying
  5. Use TextureAtlas for UI sprites to reduce draw calls
  6. Batch similar elements under same parent
  7. Disable processing when UI is hidden: process_mode = PROCESS_MODE_DISABLED
  8. Use Control.clip_contents to prevent rendering off-screen elements

Memory Management:

# Free unused UI scenes
func close_menu():
    queue_free()  # Instead of just hiding

# Object pooling for frequently created UI
var button_pool = []
const MAX_POOL_SIZE = 20

func get_pooled_button():
    if button_pool.is_empty():
        return Button.new()
    return button_pool.pop_back()

func return_to_pool(button: Button):
    if button_pool.size() < MAX_POOL_SIZE:
        button.get_parent().remove_child(button)
        button_pool.append(button)
    else:
        button.queue_free()

Accessibility Features

Text Scaling:

# Support text size preferences
func apply_text_scale(scale: float):
    for label in get_tree().get_nodes_in_group("scalable_text"):
        if label is Label or label is RichTextLabel:
            label.add_theme_font_size_override("font_size", int(16 * scale))

Gamepad Support:

# Ensure all interactive UI is gamepad-accessible
func _ready():
    # Set up focus chain
    for i in range($ButtonContainer.get_child_count() - 1):
        var current = $ButtonContainer.get_child(i)
        var next = $ButtonContainer.get_child(i + 1)
        current.focus_neighbor_bottom = next.get_path()
        next.focus_neighbor_top = current.get_path()

    # Grab focus on first button
    if $ButtonContainer.get_child_count() > 0:
        $ButtonContainer.get_child(0).grab_focus()

MCP Tool Usage

When creating UI elements, you should:

  1. Use mcp__godot__create_scene to create new UI scene files
  2. Use mcp__godot__add_node to build Control node hierarchies
  3. Use mcp__godot__save_scene to save after creating UI structure
  4. Use Edit/Write tools to create associated GDScript files for UI logic
  5. Use mcp__godot__load_sprite to import UI textures and icons

Example Workflow:

1. create_scene("res://scenes/ui/main_menu.tscn", "CanvasLayer")
2. add_node(..., "MarginContainer")
3. add_node(..., "VBoxContainer")
4. add_node(..., "Button")
5. save_scene(...)
6. Write GDScript controller

When to Activate This Skill

Activate this skill when the user:

  • Asks about creating menus, HUDs, or UI screens
  • Mentions Control nodes, themes, or styling
  • Needs help with inventory, dialogue, or menu systems
  • Asks about responsive UI or screen resolution handling
  • Requests help with button navigation or gamepad support
  • Wants to create settings menus or pause screens
  • Asks about UI animation or transitions
  • Needs help with UI performance optimization
  • Mentions anchors, containers, or layout management

Important Reminders

  • Always consider gamepad/keyboard navigation in addition to mouse
  • Use CanvasLayers to manage rendering order and prevent z-fighting
  • Anchor presets are your friend for responsive design
  • Themes should be created as resources for reusability
  • Signal connections are the primary way to handle UI interactions
  • Tweens make UI feel polished with smooth animations
  • Test on multiple resolutions - use Project Settings > Display > Window settings