From godot-prompter
Builds Godot 4.3+ user interfaces with Control nodes, themes, anchors, containers, and layout patterns using GDScript and C# examples.
How this skill is triggered — by the user, by Claude, or both
Slash command
/godot-prompter:godot-uiThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
All examples target Godot 4.3+ with no deprecated APIs. GDScript is shown first, then C#.
All examples target Godot 4.3+ with no deprecated APIs. GDScript is shown first, then C#.
Related skills: responsive-ui for multi-resolution scaling, hud-system for in-game HUD patterns, dialogue-system for dialogue UI presentation, tween-animation for UI transition and animation effects.
Control is the base class for all UI nodes. It lives in a separate branch of the scene tree from Node2D/Node3D and has a fundamentally different layout model.
| Feature | Node2D | Control |
|---|---|---|
| Position model | World-space position (pixels from parent) | Anchor + offset relative to parent rect |
| Size | No intrinsic size | Has size, minimum_size, custom_minimum_size |
| Theme | None | Inherits and overrides Theme resources |
| Focus | Not applicable | Built-in focus system (focus_mode, grab_focus()) |
| Mouse events | Manual via _input | gui_input, mouse_entered, mouse_exited |
| Layout helpers | None | Container subclasses auto-arrange children |
Every UI widget (Button, Label, LineEdit, etc.) extends Control. The key properties defined on Control itself are:
anchor_left, anchor_top, anchor_right, anchor_bottom — fractional values (0.0–1.0) relative to the parent's rectoffset_left, offset_top, offset_right, offset_bottom — pixel offsets applied after the anchor is resolvedsize_flags_horizontal, size_flags_vertical — how the node participates in Container layouttheme — a Theme resource; if null the node walks up the tree to find the nearest ancestor with onefocus_mode — controls whether the node can receive keyboard/gamepad focusPlace UI nodes inside a CanvasLayer (or directly under the scene root's built-in canvas) so they always render on top of the 3D/2D world and are not affected by Camera transforms.
| Container | Purpose | When to Use |
|---|---|---|
VBoxContainer | Stacks children vertically, top to bottom | Lists, option rows, vertical menus |
HBoxContainer | Stacks children horizontally, left to right | Toolbars, stat rows, horizontal nav |
GridContainer | Arranges children in a fixed-column grid | Inventory grids, key-binding tables |
MarginContainer | Adds padding around a single child | Wrapping any node to give it breathing room |
PanelContainer | Draws a StyleBox background, then lays out children | Card UI, dialog boxes, HUD panels |
ScrollContainer | Makes its single child scrollable; clips overflow | Long lists, logs, scrollable settings |
TabContainer | Stacks children as named tabs; shows one at a time | Settings screens, multi-section panels |
Sizing tips:
size_flags_horizontal = SIZE_EXPAND_FILL on children that should fill available space.custom_minimum_size to prevent a child from collapsing to zero.MarginContainer reads margin from the theme property margin_*; override at runtime with add_theme_constant_override("margin_left", 16).An anchor is a point on the parent rect expressed as a fraction (0 = top/left edge, 1 = bottom/right edge). Godot resolves the final pixel position of each edge as:
final_left = parent_width * anchor_left + offset_left
final_top = parent_height * anchor_top + offset_top
final_right = parent_width * anchor_right + offset_right
final_bottom = parent_height * anchor_bottom + offset_bottom
The editor exposes built-in presets:
| Preset | Anchor values | Use case |
|---|---|---|
| Full Rect | L=0, T=0, R=1, B=1 | Overlay / fill parent — most common for root UI |
| Center | L=0.5, T=0.5, R=0.5, B=0.5 | Fixed-size widget centred in parent |
| Top Left | L=0, T=0, R=0, B=0 | Fixed-size widget pinned to top-left corner |
| Top Right | L=1, T=0, R=1, B=0 | Fixed-size widget pinned to top-right corner |
| Bottom Center | L=0.5, T=1, R=0.5, B=1 | HUD element anchored to bottom centre |
GDScript:
# Fill parent completely (equivalent to "Full Rect" preset)
$Panel.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
# Anchor to top-right corner, fixed 200x60 size
$HUDLabel.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT)
$HUDLabel.size = Vector2(200.0, 60.0)
# Fine-tune with a 16 px margin from the right and top edges
$HUDLabel.offset_right = -16.0
$HUDLabel.offset_top = 16.0
# Custom responsive anchor: right half of screen, full height
$SidePanel.anchor_left = 0.5
$SidePanel.anchor_top = 0.0
$SidePanel.anchor_right = 1.0
$SidePanel.anchor_bottom = 1.0
$SidePanel.offset_left = 0.0
$SidePanel.offset_top = 0.0
$SidePanel.offset_right = 0.0
$SidePanel.offset_bottom = 0.0
C#:
// Fill parent completely
GetNode<Control>("Panel").SetAnchorsAndOffsetsPreset(Control.LayoutPreset.FullRect);
// Anchor to top-right corner
var label = GetNode<Control>("HUDLabel");
label.SetAnchorsAndOffsetsPreset(Control.LayoutPreset.TopRight);
label.Size = new Vector2(200f, 60f);
label.OffsetRight = -16f;
label.OffsetTop = 16f;
// Custom anchor: right half of screen
var panel = GetNode<Control>("SidePanel");
panel.AnchorLeft = 0.5f;
panel.AnchorTop = 0.0f;
panel.AnchorRight = 1.0f;
panel.AnchorBottom = 1.0f;
panel.OffsetLeft = 0f;
panel.OffsetTop = 0f;
panel.OffsetRight = 0f;
panel.OffsetBottom = 0f;
For fully responsive layout, keep offsets at 0 and let anchors do the work. Add small fixed offsets only for cosmetic margins (e.g., a 16 px gutter from an edge).
A Theme resource centralizes fonts, colors, and StyleBoxes. Apply at the root and let inheritance do the work; use theme_override_* only for one-off tweaks. StyleBoxFlat covers most flat-design needs (bg_color, border_color, corner_radius, border_width); StyleBoxTexture for textured backgrounds.
See references/theme-system.md for the full Theme resource creation walk-through, StyleBoxFlat properties, font overrides, theme inheritance rules, and per-node
theme_override_*methods.
Focus modes (FOCUS_NONE, FOCUS_CLICK, FOCUS_ALL) gate keyboard/gamepad navigation. Use focus_neighbor_top / _bottom / _left / _right to wire navigation chains, or rely on automatic spatial detection. Call grab_focus() on the first interactive element when a menu opens.
See references/focus-and-navigation.md for focus mode details,
focus_neighborchain examples, gamepad/keyboard input handling, and grab_focus patterns.
Three canonical scenes: a main menu (centered VBoxContainer with title + button list), a settings screen with tabs (TabContainer + child panels per category), and a pause menu overlay (full-rect ColorRect background + centered options panel, paused via get_tree().paused = true).
See references/ui-patterns.md for the full scene-tree fragments and GDScript wiring for each pattern.
Button.pressed for clicks, Control.gui_input for raw events on a node, Control.mouse_entered / mouse_exited for hover. Connect in _ready() or via the Inspector's Node panel.
See references/signals.md for the complete signal catalog and signal-driven UI update patterns.
FoldableContainer is a new built-in Container node introduced in Godot 4.5. It provides accordion-style collapsible sections with a toggle header, eliminating the boilerplate of manually wiring a Button to show/hide a child VBoxContainer.
# In a script that builds UI dynamically:
func _ready() -> void:
var foldable := FoldableContainer.new()
foldable.title = "Advanced Settings"
foldable.folded = false # start expanded
var label := Label.new()
label.text = "This content can be collapsed."
foldable.add_child(label)
var slider := HSlider.new()
slider.min_value = 0.0
slider.max_value = 1.0
slider.value = 0.5
foldable.add_child(slider)
add_child(foldable)
# Listen for toggle events:
func _ready() -> void:
var foldable := $FoldableContainer
foldable.folding_changed.connect(_on_section_toggled)
func _on_section_toggled(is_folded: bool) -> void:
print("Section is now: ", "folded" if is_folded else "expanded")
public override void _Ready()
{
var foldable = new FoldableContainer
{
Title = "Advanced Settings",
Folded = false
};
var label = new Label { Text = "This content can be collapsed." };
foldable.AddChild(label);
var slider = new HSlider { MinValue = 0.0, MaxValue = 1.0, Value = 0.5 };
foldable.AddChild(slider);
AddChild(foldable);
// Listen for toggle:
foldable.FoldingChanged += OnSectionToggled;
}
private void OnSectionToggled(bool isFolded)
{
GD.Print("Section is now: ", isFolded ? "folded" : "expanded");
}
| Property | Type | Purpose |
|---|---|---|
title | String | Text shown in the toggle header |
folded | bool | true = content hidden, false = content visible |
title_alignment | HorizontalAlignment | Align the title text within the header |
| Signal | Signature | When emitted |
|---|---|---|
folding_changed | (folded: bool) | Emitted whenever the fold state toggles |
Replaces boilerplate: Prior to Godot 4.5, accordion sections required a
Button+VBoxContainer+ signal connection.FoldableContainerhandles all of this in one node.
In Godot 4.5, Label and RichTextLabel support multiple layered text effects simultaneously — for example, stacking two outline effects at different widths and colors, or combining a shadow with a glow. Previously, achieving multiple outline layers required duplicating Label nodes and layering them manually.
# In the inspector: Label → Theme Overrides → Constants
# Add multiple outline layers by stacking VisualShaderNodeTextureParameter entries
# in the Theme, or configure via add_theme_* overrides at runtime.
# Example: thick outer outline + thin inner outline via theme overrides
func apply_stacked_outlines(label: Label) -> void:
# Outer outline — wide, dark
label.add_theme_constant_override("outline_size", 6)
label.add_theme_color_override("font_outline_color", Color(0.0, 0.0, 0.0, 0.9))
# Shadow (counts as a second layered effect)
label.add_theme_constant_override("shadow_offset_x", 2)
label.add_theme_constant_override("shadow_offset_y", 2)
label.add_theme_color_override("font_shadow_color", Color(0.0, 0.0, 0.0, 0.5))
public void ApplyStackedOutlines(Label label)
{
// Outer outline — wide, dark
label.AddThemeConstantOverride("outline_size", 6);
label.AddThemeColorOverride("font_outline_color", new Color(0f, 0f, 0f, 0.9f));
// Shadow (second layered effect)
label.AddThemeConstantOverride("shadow_offset_x", 2);
label.AddThemeConstantOverride("shadow_offset_y", 2);
label.AddThemeColorOverride("font_shadow_color", new Color(0f, 0f, 0f, 0.5f));
}
For RichTextLabel, stacked effects can also be applied using BBCode in combination with theme overrides:
# RichTextLabel with multiple outline-style effects via BBCode + theme
$RichTextLabel.text = "[outline size=4 color=#000000]Level Up![/outline]"
# Additional layers are set via theme overrides on the node as above.
Editor workflow: Stacked effects are most easily configured via Theme Editor → Label → Constants or by adding multiple
FontFile-style outline passes in the Font resource. The runtime API (add_theme_*_override) above works for dynamic scenarios.
Control has anchor preset Full Rect (or appropriate preset for the layout)Button, LineEdit, Slider) have focus_mode = FOCUS_ALLLabel, TextureRect) have focus_mode = FOCUS_NONEgrab_focus() called on the first interactive widget in _ready() for each screenControl has process_mode = PROCESS_MODE_ALWAYSTheme resource assigned at the screen root — not duplicated on every childStyleBoxFlat used instead of image assets for simple solid-colour panelsadd_theme_*_override() used for per-node overrides rather than assigning a whole new ThemeVBoxContainer, HBoxContainer, etc.) used for layout instead of manual position valuescustom_minimum_size set on widgets that must not collapse to zerolinear_to_db / db_to_linear — not raw linear values mapped to audio bus_ready() (or via the editor); no polling of UI state in _processTabContainer matches logical reading / navigation orderFoldableContainer instead of manual Button + VBoxContainer wiring (Godot 4.5+)Label/RichTextLabel use stacked theme overrides instead of duplicated nodes (Godot 4.5+)npx claudepluginhub jame581/godotprompter --plugin godot-prompterProvides expert guidance on Godot UI using Control nodes, themes, styling, responsive layouts, and patterns for menus, HUDs, inventories, dialogues. Use for UI/menu creation or styling.
Builds Godot UI — menus, HUDs, health bars, dialogs — using Control nodes, containers, anchors, and theme styling via Summer Engine commands.
Constructs Godot scenes from patterns like platformer characters, top-down chars, UI screens, projectiles, pickups, tilemaps with required companion nodes (e.g., CollisionShape2D).