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
| Where | What | How |
|---|---|---|
from | the parent theme | dark · light · scifi_dark · medieval_dark · … or another JSON theme. Omitted keys inherit its values; an inheritance cycle fails |
palette | background · three surfaces · border · three text tones · accent · four status colours · scrim · shadow · bar track | "#RRGGBB", alpha as "#RRGGBB@0.35" |
fill-only vivid colours *_vivid | keep bars saturated even when the text colour has to darken — leave one out and the builder says so | |
| readability | not 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 | |
shape | kind | flat (rounded) · cut (chamfered corners) · medieval (forged frames) |
| sizes | radius · 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 only | cut_ratio · cut_max · corners (diagonal|all) · glow · edge | |
medieval only | material (0 iron · 1 leather · 2 parchment) · grain_alpha · ornament_scale · bevel_strength · fonts — title, subtitle, caption, body, button mapped to addon-local res:// font files | |
skin | base — 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 bracket | Every parent value is spelled out in the JSON. The builder writes them into themes/skins/gohud_skin_<id>.tres — no skin code is touched. Only to change the drawings themselves do you run --new-skin, which scaffolds a GoSkin subclass | |
icons | the icon set | a res:// path to a GoIconSet resource — kept from a JSON parent when omitted |
dark · title | how the picker shows it | boolean · 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
GoSkin — 17| Dial | Default | What it sets |
|---|---|---|
chip_fill_alpha | 0.16 | Fill opacity of a chip's panel. |
chip_edge_alpha | 0.45 | Edge opacity of a chip's panel. |
alert_tint | 0.1 | How far an alert box's panel is tinted toward its status colour. |
slot_tint_lit | 0.24 | Accent tint of a quick-slot panel while its cooldown runs. |
slot_tint_idle | 0.08 | Accent tint of a quick-slot panel at rest. |
slot_border_lit | 2 | Quick-slot border width (dp) while its cooldown runs. |
slot_border_idle | 1 | Quick-slot border width (dp) at rest. |
badge_pad_x | 5 | Horizontal inner padding (dp) of a badge (quantity, time left). |
badge_pad_y | 1 | Vertical inner padding (dp) of a badge. |
badge_edge_alpha | 0.6 | Edge opacity of a badge's panel. |
float_shadow_alpha | 0.45 | Shadow opacity of floating cards (coach mark, prompt card). |
float_shadow_size | 14 | Shadow blur (dp) of floating cards. |
float_shadow_lift | 4 | Downward offset (dp) of a floating card's shadow. |
float_glow_size | 10.0 | Glow distance (dp) of a floating panel that glows instead of casting a shadow, like the sci-fi chamfered panel. |
joystick_base_alpha | 0.42 | Opacity of the joystick's base disc. |
joystick_ring_alpha | 0.45 | Opacity of the joystick's ring. |
joystick_ring_width | 2.0 | Width (dp) of the joystick's ring. |
Sci-fi skin GoSkinSciFi — 10
GoSkinSciFi — 10| Dial | Default | What it sets |
|---|---|---|
cut_chip | 7.0 | Chamfer size (dp) of a chip's panel. |
cut_skeleton | 5.0 | Chamfer size (dp) of a skeleton panel. |
cut_alert | 8.0 | Chamfer size (dp) of an alert box. |
cut_segment | 8.0 | Chamfer size (dp) of a segmented control. |
cut_slot | 6.0 | Chamfer size (dp) of a quick-slot panel. |
cut_disc_ratio | 0.24 | Chamfer of avatars and discs = diameter × this ratio. |
slot_glow_alpha | 0.45 | Glow opacity of a slot whose cooldown is running. |
slot_glow_size | 6.0 | Glow distance (dp) of a slot whose cooldown is running. |
bracket_arm | 12.0 | Arm length (dp) of the coach mark's targeting bracket. |
bracket_thickness | 2.0 | Line thickness (dp) of the coach mark's targeting bracket. |
Medieval skin GoSkinMedieval — 5
GoSkinMedieval — 5| Dial | Default | What it sets |
|---|---|---|
slot_radius | 4.0 | Corner radius (dp) of the medieval quick-slot frame. |
leather_grain_alpha | 0.035 | Opacity of the subtle leather marks inside quick slots. |
ornament_scale | 1.0 | Scale of the metal decorations at quick-slot corners. Menu frames use shape.ornament_scale. |
bevel_strength | 0.18 | Strength of the metal highlight along quick-slot edges. |
slot_rivets | 1 | Show 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.
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.