← Back to blog

Godot 4 HUD and Theme: Control Tree Handoff and Play Acceptance

Acceptance for Theme, StyleBox, container anchors, and minimum_size when Figma lands in Godot 4. Maps to Unity UGUI checklist bars—six Play steps and fix routing. Handoff guide, not a Theme editor tutorial.

Published
  • game-ui-design
  • game-dev-ai
  • ui-to-engine
  • godot
  • theme
  • hud
  • figma-to-godot
  • vberai
  • 2026
Godot 4 HUD and Theme: Control Tree Handoff and Play Acceptance

Godot 4 HUD is not done when PNGs sit on TextureRect nodes: StyleBox in Theme, default fonts, the container chain (MarginContainer → HBoxContainer / VBoxContainer), and anchors / offsets together decide whether layout holds across resolutions. Figma Auto Layout can look perfect while Play still shows drifting bottom bars, zero-min buttons, or long copy clipping—usually the Control tree or Theme resource did not match handoff spec.

Below focuses on Godot 4.x Control + Theme. Unity teams can apply the same bar via engine + MCP checklist. Full Figma → Godot flow: Figma to Godot (VberAI Studio exports the Control tree). This post covers HUD shell only: Theme, node naming, Play smoke—not MCP install steps.

Fail criteria (any one = not passed): primary HUD readable controls clipped at target aspect (including Safe Area equivalent DisplayServer.get_display_safe_area()); same button Editor vs exported build size mismatch with no written spec; Theme button states (normal / hover / pressed / disabled, etc.) missing states still shipped; Scene tree changed for one locale only (conflicts with same-structure i18n—see locale overflow); minimum_size unset so nine-slice panel bg looks fine but text hugs edges.


Theme and nodes: what handoff must align

Design deliveryGodot landing
Color / radius / bordered panelsStyleBoxFlat / StyleBoxTexture in Theme (patch margins per nine-slice)
Body / title sizesTheme default font_size + Label type variations if needed
Button statesFour StyleBox sets on Button: normal / hover / pressed / disabled
Icon + copyIcon TextureRect with fixed min; copy Label in expandable container
Full-screen HUD rootRoot Control anchor preset + MarginContainer for safe area

Naming: Scene node names match Figma component semantics (HUD_BottomBar, Btn_Shop) so MCP / script $ paths stay stable (engine + MCP checklist).


Play acceptance order (6 steps)

1. Lock viewport and safe area

  • Set target base width/height in Project Settings → Display (team portrait convention).
  • Inset HUD root with DisplayServer.get_display_safe_area() or Godot 4.2+ SafeArea node; smoke one tall phone (see Safe Area post).

2. Theme as single source of truth

  • HUD subtree inherits one Theme resource, not per-Button manual overrides.
  • Any override nodes must be listed in spec or reskin will miss them.

3. Container chain and size flags

CheckCommon mistake
size_flags_horizontal / verticalLabel that should grow lacks Fill/Expand → locale clip
custom_minimum_sizeButton height 0 → touch target too small
Nested MarginContainerDouble margins → extra blank ring

4. Locale smoke

  • In Localization, switch stress languages (DE/ES, etc.) and ship language; change only tr() text, not the node tree.
  • Overflow → locale overflow path (min width / copy / re-export).

5. States and focus

  • Keyboard/gamepad focus (if supported): focus StyleBox defined in Theme.
  • Disabled buttons still blocking clicks (mouse_filter, disabled state).

6. Exported build retest

  • Run main HUD 30s in Debug and Release; if font fallback changes width, retest on device (pre-ship item 5 Dev/Release; all locales item 2).

Rough Figma Auto Layout mapping

FigmaGodot 4
Vertical Auto LayoutVBoxContainer + separation
Horizontal Auto LayoutHBoxContainer
PaddingMarginContainer or StyleBox content margin
Fill containersize_flags Expand + Fill
Hug contentsChildren not Expand; parent hugs

If VberAI Studio (or your pipeline) already exported containers, accept in Play—do not eyeball static Editor frames only.


Fix routing

SymptomLikely causeActionOwner
Bottom bar under notchNo safe insetRoot margin + safe area APIEng
One locale overflowsMin width / font sizeTheme or container min; shorter loc copyDesign + eng
Styles wrong after reskinOverrides scatteredConsolidate Theme; re-exportEng + design
Nine-slice seam in StyleBoxWrong patch marginMatch design px; see nine-slice postEng + design
MCP cannot bind nodesNames ≠ exportUnify naming; re-export Scene/PackedSceneEng

FAQ

One Theme per screen or one for the whole game?
Common pattern: global Theme + rare theme_override; event skins via reskin Theme swap, not per-node tint edits.

Mix Control with raw CanvasItem layout?
Keep 2D HUD on one Control tree; do not blend with hand-placed CanvasLayer coords in the same HUD.

Need a separate focus style for keyboard/gamepad?
If the project supports keyboard/gamepad focus, define focus StyleBox on Button, LineEdit, etc. in Theme (or visible theme_override), and smoke Tab/d-pad in Play. Touch-only HUD can spec no focus styling required so QA and eng share one bar.

How is this different from Unity Prefab acceptance?
Same bar (clip, locales, states, Release); swap names to StyleBox / size_flags / PackedScene.

Must we use Figma?
No. Without Figma you still need Theme + container spec; with Figma, design handoff checklist then Godot.

More guides you might like