gohud

Your own preset — one file

← Theming

Adding a theme used to mean editing four places by hand — the builder's palette, the shape, a skin, a preset resource. One command now puts all of them in place.

python3 addons/gohud/tools/new_theme.py neon --from scifi_dark --title "Neon"
python3 addons/gohud/tools/make_theme.py neon      # theme .tres + control artwork
godot --headless --path . --import                  # import the new artwork once
GoUi.use_preset(&"neon")                             # done — it shows up in the picker too

The first line writes themes/palettes/neon.json and themes/presets/neon.tres. The JSON carries every value of the theme it inherits from, fully spelled out, so it doubles as the list of what you can change: delete a key to keep the parent's value, write one to override it. Presets are found by scanning themes/presets/, so no registry code changes — the project setting's dropdown picks it up as well.

What you can change — on one page

WhereWhatHow
fromthe parent themedark · light · scifi_dark · medieval_dark · … or another JSON theme. Omitted keys inherit its values; an inheritance cycle fails
palettebackground · three surfaces · border · three text tones · accent · four status colours · scrim · shadow · bar track"#RRGGBB", alpha as "#RRGGBB@0.35"
fill-only vivid colours *_vividkeep bars saturated even when the text colour has to darken — leave one out and the builder says so
readabilitynot tuned by hand. Text, borders, the accent and the label on it are pushed by the builder until they clear the thresholds — change only the accent and the checks still pass
shapekindflat (rounded) · cut (chamfered corners) · medieval (forged frames)
sizesradius · radius_small · radius_large · gap · gap_small · gap_large · padding · button_height · button_padding[4] — the tokens follow, so panels and widget maths never disagree
cut onlycut_ratio · cut_max · corners (diagonal|all) · glow · edge
medieval onlymaterial (0 iron · 1 leather · 2 parchment) · grain_alpha · ornament_scale · bevel_strength · fontstitle, subtitle, caption, body, button mapped to addon-local res:// font files
skinbase — the family for the places code draws itself (joystick, slots, badges, coach-mark ring, chips, dividers)default · scifi · medieval
dials — the numbers of those places: slot border width and tint, badge padding, chip and alert opacity, joystick ring width and opacity, sci-fi chamfer sizes, glow and bracketEvery parent value is spelled out in the JSON. The builder writes them into themes/skins/gohud_skin_<id>.tresno skin code is touched. Only to change the drawings themselves do you run --new-skin, which scaffolds a GoSkin subclass
iconsthe icon seta res:// path to a GoIconSet resource — kept from a JSON parent when omitted
dark · titlehow the picker shows itboolean · string

Every dial

The table below is filled by tools/make_site.py straight from the skin scripts' @export lines — add a dial or change a default and the table follows. Use these names under skin.dials in the JSON. A dial whose default reads 14 is an integer, one that reads 10.0 a float — write either form in the JSON and the builder casts to the script's type.

Default skin GoSkin — 17

DialDefaultWhat it sets
chip_fill_alpha0.16Fill opacity of a chip's panel.
chip_edge_alpha0.45Edge opacity of a chip's panel.
alert_tint0.1How far an alert box's panel is tinted toward its status colour.
slot_tint_lit0.24Accent tint of a quick-slot panel while its cooldown runs.
slot_tint_idle0.08Accent tint of a quick-slot panel at rest.
slot_border_lit2Quick-slot border width (dp) while its cooldown runs.
slot_border_idle1Quick-slot border width (dp) at rest.
badge_pad_x5Horizontal inner padding (dp) of a badge (quantity, time left).
badge_pad_y1Vertical inner padding (dp) of a badge.
badge_edge_alpha0.6Edge opacity of a badge's panel.
float_shadow_alpha0.45Shadow opacity of floating cards (coach mark, prompt card).
float_shadow_size14Shadow blur (dp) of floating cards.
float_shadow_lift4Downward offset (dp) of a floating card's shadow.
float_glow_size10.0Glow distance (dp) of a floating panel that glows instead of casting a shadow, like the sci-fi chamfered panel.
joystick_base_alpha0.42Opacity of the joystick's base disc.
joystick_ring_alpha0.45Opacity of the joystick's ring.
joystick_ring_width2.0Width (dp) of the joystick's ring.

Sci-fi skin GoSkinSciFi — 10

DialDefaultWhat it sets
cut_chip7.0Chamfer size (dp) of a chip's panel.
cut_skeleton5.0Chamfer size (dp) of a skeleton panel.
cut_alert8.0Chamfer size (dp) of an alert box.
cut_segment8.0Chamfer size (dp) of a segmented control.
cut_slot6.0Chamfer size (dp) of a quick-slot panel.
cut_disc_ratio0.24Chamfer of avatars and discs = diameter × this ratio.
slot_glow_alpha0.45Glow opacity of a slot whose cooldown is running.
slot_glow_size6.0Glow distance (dp) of a slot whose cooldown is running.
bracket_arm12.0Arm length (dp) of the coach mark's targeting bracket.
bracket_thickness2.0Line thickness (dp) of the coach mark's targeting bracket.

Medieval skin GoSkinMedieval — 5

DialDefaultWhat it sets
slot_radius4.0Corner radius (dp) of the medieval quick-slot frame.
leather_grain_alpha0.035Opacity of the subtle leather marks inside quick slots.
ornament_scale1.0Scale of the metal decorations at quick-slot corners. Menu frames use shape.ornament_scale.
bevel_strength0.18Strength of the metal highlight along quick-slot edges.
slot_rivets1Show small metal rivets on quick slots: 0 hides them, 1 shows them.

Subclass the skin (optional)

Only what theme and shape cannot reach — the joystick's hexagon, slot badges, the coach mark's targeting bracket — lives in a skin. Subclass GoSkin, override just those methods, and point the JSON's skin at that resource. A colour-only theme skips this step.

A check keeps the promise. tools/check_scaffold.sh creates a throwaway theme every run — changes the accent, sets the radius to 4 — and verifies generation, token propagation and a clean contrast pass before removing it. The first run found a theme with only its accent changed failing 8 pairs: the builder pushed text colours but used the accent as written. It now pushes the accent and the label on it too.