godot-ui-theming

Expert blueprint for UI themes using Theme resources, StyleBoxes, custom fonts, and theme overrides for consistent visual styling. Covers StyleBoxFlat/Texture, theme inheritance, dynamic theme switching, and font variations. Use when implementing consistent UI styling OR supporting multiple themes.

By thedivergentai · 447 installs

npx skills add thedivergentai/gd-agentic-skills --skill godot-ui-theming

Source repository · Upstream listing

UI Theming Theme resources, StyleBox styling, font management, and override system define consistent UI visual identity. Available Scripts [global theme manager.gd](scripts/global theme manager.gd) Expert theme manager with dynamic switching, theme variants, and fallback handling. [ui scale manager.gd](scripts/ui scale manager.gd) Runtime theme switching and DPI/Resolution scale management. [theme swapper.gd](scripts/theme swapper.gd) Dynamic Dark/Light mode implementation using cascading theme root propagation. [danger button assignment.gd](scripts/danger button assignment.gd) Expert use of theme type variation for semantic UI styling without scene duplication. [dynamic stylebox color.gd](scripts/dynamic stylebox color.gd) Safe runtime StyleBox modification. Demonstrates the critical duplicate() pattern for isolated overrides. [procedural theme safe.gd](scripts/procedural theme safe.gd) Reliable theming for generated UI elements using NOTIFICATION THEME CHANGED . [custom chart drawing.gd](scripts/custom chart drawing.gd) Pattern for reading active Theme properties (colors, fonts) in custom draw() logic. [theme isolation.gd](scripts/theme isolation.gd) Ensuring HUD consistency by isolating nodes from parent themes and referencing Project Defaults. [pulsating ui theme.gd](scripts/pulsating ui theme.gd) Animating UI styles via Tweens. Targets StyleBox properties directly after duplication. [crisp ui scaler.gd](scripts/crisp ui scaler.gd) High quality resolution independent scaling using content scale factor to maintain font crispness. [memory safe custom drawing.gd](scripts/memory safe custom drawing.gd) Fixing the "disappearing stylebox" bug by caching resources at the class level for the RenderingServer. [rtl theme mirroring.gd](scripts/rtl theme mirroring.gd) Bi directional (RTL/LTR) UI support. Swaps theme variants dynamically based on layout direction. [focus prompt icon swapper.gd](scripts/focus prompt icon swapper.gd) Controller/keyboard prompt icon bank swap + focus highlight panel. MANDATORY for accessibility prompt chrome. NEVER Do in UI Theming NEVER create StyleBox in ready() for many nodes — Instantiating StyleBoxFlat.new() 100 times creates 100 unique objects. Use a Theme resource for shared heritage. NEVER forget theme inheritance — Parent themes are ignored if a child has its own theme. Apply themes at the root and use theme type variation for specific overrides. NEVER hardcode colors in StyleBox — Use theme.get color() to maintain a single source of truth for your palette. NEVER use add theme override for global styles — This is brittle. Define styles in a Theme resource for automatic propagation across the project. NEVER modify theme resources during draw() OR process() — Frequent layout recalculations will severely degrade performance. NEVER assign StyleBoxEmpty to focus styles without a fallback — This invisibly breaks controller/keyboard navigation [1]. Always provide a visible alternative (e.g. scale change). NEVER use standard set() for theme properties — Calling node.set("font color", red) fails. You MUST use the dedicated add theme color override() API [3]. NEVER use expand margin to increase clickable area — It only expands the VISUAL bounds. Use content margin on the StyleBox or adjust the Control's size to ensure input works [5]. NEVER define StyleBoxes as local variables inside draw() — They will be garbage collected before the RenderingServer can finish drawing them [7]. Store at class level. NEVER duplicate scenes/themes just to change one color — Use theme type variation to create lightweight derived styles (e.g. "DangerButton") within the same Theme [8]. NEVER skip corner radius all on StyleBoxFlat — shorthand for uniform rounding; prefer it over four separate radius fields when all corners match. NEVER confuse Theme items with Control overrides — add theme override beats Theme resource items on that node only; a child Control with its own theme still blocks parent cascade. Clear with remove theme override when swapping roots — do not leave stale overrides fighting the new Theme. Decision Tree — Theme Ownership Goal Choose Notes / script App wide look Project Settings → GUI → Theme Author in Theme editor — no per node StyleBox tutorials here One Control differs add theme override on that node Local only; never for global styles Button/panel subtype theme type variation See [danger button assignment.gd](scripts/danger button assignment.gd) Runtime color tweak without mutating shared Theme stylebox.duplicate() then override See [dynamic stylebox color.gd](scripts/dynamic stylebox color.gd) Fonts & StyleBoxes: edit via Theme editor / Project Theme. Runtime helpers: [global theme manager.gd](scripts/global theme manager.gd), [theme swapper.gd](scripts/theme swapper.gd), [procedural theme safe.gd](scripts/procedural theme safe.gd). Expert Theming Patterns 1. Shared Color Palette (The Static Pattern) Maintain a single source of truth for UI colors accessible to both the Theme Editor and GDScript. Theme Setup : In your .theme file, create a custom type called Palette and add Color items (e.g., primary , danger , accent ). Static Access : Use a SharedPalette class with static func get primary() Color that pulls from ThemeDB.get project theme() . This ensures UI scripts and the visual theme never drift. 2. Theme Type Variations Avoid duplicating button scenes or styleboxes for variants like "Danger" or "Ghost" styles. Implementation : In the Theme Editor, create a new Type Variation . Set its Base Type to Button . Inheritance : The variation inherits all properties from the base type. You only override what's different (e.g., set font color to red for DangerButton ). Usage : Assign via code node.theme type variation = &"DangerButton" or via the Inspector dropdown. MANDATORY : Read [danger button assignment.gd](scripts/danger button assignment.gd) — do not fork Button scenes for color variants. 3. Runtime StyleBox Color (duplicate first) When a single Control needs a runtime tint, duplicate the StyleBox before mutating — shared Theme StyleBoxes must stay immutable. MANDATORY : Read [dynamic stylebox color.gd](scripts/dynamic stylebox color.gd) — never mutate a Theme StyleBox in place. 4. Runtime Theme Swapping (Accessibility) Efficiently switch the visual style of the entire game for Light, Dark, or High Contrast modes. Cascading Updates : Assign a new Theme resource to the root Control node. Godot propagates this to every descendant. Accessibility : Use NOTIFICATION THEME CHANGED to update elements that don't support automatic theming (like custom draw() logic or RichText effects). High Contrast : Ensure High Contrast themes use pure black/white and thicker focus outlines for low vision accessibility. MANDATORY : Read [theme swapper.gd](scripts/theme swapper.gd) — swap at the theme root; do not walk every Control assigning themes. 5. RTL / LTR Theme Mirroring Bi directional layouts need mirrored StyleBox / type variation banks when direction flips — not hand flipped anchors alone. MANDATORY : Read [rtl theme mirroring.gd](scripts/rtl theme mirroring.gd) — swap theme variants from layout direction; do not hardcode LTR margins. 6. Themed Asset Loading (Seasonal Variants) Godot Themes support more than just colors and fonts—they can store textures. Setup : Define UI icons as Icon items within separate Theme resources (e.g., halloween.theme , christmas.theme ). Swapping : Swapping the root theme resource instantly cascades the new icon textures across all buttons and panels without manual logic. 7. UI Focus Manager (Dynamic Controller Icons) Standard focus styles are static. For accessibility UX, swap prompt icons by device and tween a highlight panel to get global rect() . MANDATORY : Read [focus prompt icon swapper.gd](scripts/focus prompt icon swapper.gd) — do not paste joypad icon paths into Control scripts. Pairs with Runtime Theme Swapping (Accessibility) above and [theme swapper.gd](scripts/theme swapper.gd) for High Contrast roots. 8. Asset Dependency Audit (Draw Call Reduction) Ensuring UI textures are optimized for rendering performance. Atlas Packing : Use AtlasTexture to crop small UI elements from a singular large sheet. This reduces VRAM state changes and minimizes draw calls [14]. Compression Policy : 2D/Pixel Art : Use Lossless compression to avoid blurry artifacts [15]. UI Backgrounds : Use Lossy or Basis Universal for large illustrations to save disk space without decreasing VRAM usage [15]. Audit : Use ResourceLoader.get dependencies(scene path) to ensure no uncompressed raw assets (e.g. .png ) are leaking into the final export [19]. Deep recipes (on demand) LLM ignorance rule: if a general agent would not know it before reading, it lives here or in scripts/ — never delete, only move. Topic Reference StyleBox / font setup [theme authoring recipes.md](references/theme authoring recipes.md) Reference Progressive disclosure: open Official Documentation links only when researching a specific API; load Related Skills when routing work to a peer domain — do not preload the whole lattice. Official Documentation [GUI skinning](https://docs.godotengine.org/en/stable/tutorials/ui/gui skinning.html) — Theme resources, StyleBoxes, and cascading skin ownership. [Using the theme editor](https://docs.godotengine.org/en/stable/tutorials/ui/gui using theme editor.html) — Authoring Theme assets without hand editing every Control override. [Theme type variations](https://docs.godotengine.org/en/stable/tutorials/ui/gui theme type variations.html) — Variants for button/panel subtypes without duplicating whole themes. [Using fonts](https://docs.godotengine.org/en/stable/tutorials/ui/gui using fonts.html) — DynamicFont / font size theming for UI readability. [Custom GUI controls](https://docs.godotengine.org/en/stable/tutorials/ui/custom gui controls.html) — When themed draw() needs theme item lookups. [Size and anchors](https://docs.godotengine.org/en/stable/tutorials/ui/size and anchors.html) — Layout that survives theme scale and DPI changes. [Theme](https://docs.godotengine.org/en/stable/classes/class theme.html) — Runtime get/set for colors, constants, icons, StyleBoxes. [ThemeDB](https://docs.godotengine.org/en/stable/classes/class themedb.html) — Project default theme and fallback resolution. [Control](https://docs.godotengine.org/en/stable/classes/class control.html) — Theme overrides and NOTIFICATION THEME CHANGED. [StyleBox](https://docs.godotengine.org/en/stable/classes/class stylebox.html) — Panel/button chrome used by most Theme skins. [AtlasTexture](https://docs.godotengine.org/en/stable/classes/class atlastexture.html) — Pack UI icons to cut draw call churn. [Input](https://docs.godotengine.org/en/stable/classes/class input.html) — Custom cursors and joypad driven prompt icon swaps. Related Skills Prerequisites [godot project foundations](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot project foundations/SKILL.md) — Project layout and default Control/Theme placement before skin systems. [godot resource data patterns](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot resource data patterns/SKILL.md) — Theme/StyleBox/icon banks as Resources instead of path string sprawl. [godot ui containers](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot ui containers/SKILL.md) — Containers must be correct before theme polish hides layout bugs. [godot signal architecture](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot signal archite