gohud

Readability is measured

← Theming

"Pretty" is taste; "legible" can be measured. Faint grey text looks fine on a good monitor and disappears on a phone in daylight — picking by eye guarantees that eventually.

python3 addons/gohud/tools/check_contrast.py
WhatRequired
Body text4.5 : 1
Large text (24px and up)3 : 1
Accent borders and icons3 : 1
Decorative borders2 : 1 — WCAG does not apply its 3:1 rule to decoration
Adjacent surfaces1.12 : 1 — enough that a card reads as separate from its background

Same-hue text on a same-hue tint

This trap appeared three times in this codebase — pressed buttons (accent panel, accent label), danger buttons, and chips. It looks good in a swatch and collapses the moment it is measured, because the two share a hue and so have no difference in lightness.

Label colours are therefore not chosen by hand. The theme builder and GoSkin each push lightness — and only lightness — until the threshold is cleared on the panel the text actually sits on. Hue and saturation survive, so the palette keeps its character and changing it keeps its contrast.

Colour read as text and colour painted as area want opposite things

On a light theme a warning colour has to darken to stay readable as text (#96500A). When the bar fill inherits that, the experience bar turns brown. Colour alone cannot fix it: yellow is intrinsically bright, so it clears 3:1 over no grey track at all, and darkening the track makes it worse (1.52 → 1.06).

So the two are separated. Colour stays vivid — the palette carries fill-only colours such as warning_vivid. The edge carries the contrastGoSkin draws a 1dp outline on any fill that cannot reach 3:1 against its track, so "how full is it" stays legible.

MY_LIGHT = dict(
    warning=hexc("9A5407"),         # read as text
    warning_vivid=hexc("F2A007"),   # painted on the bar
)
Leaving it out is reported. Without a *_vivid, a fill that comes out dark makes the builder print the bar looks drab — add warning_vivid to the palette. A place that used to degrade silently now says so.

A floating panel cannot know what is behind it

A HUD is drawn over the game — a snowfield, or a cave. If its panel is translucent, whatever is behind it bleeds through and changes the panel's colour, taking the text contrast down with it. At 82% opacity the dark themes' muted text fell to 3.74:1 over a bright backdrop — below the minimum.

So translucent panels are measured with pure white and pure black behind them; those are the worst a game scene can offer. The bundled themes' HUD panel is opaque enough to pass (92%) while keeping the glassy look.

For the same reason icon colours are not fixed either. The quick slot's glyph was hard-coded white and measured 1.11:1 on a light theme — it now follows the panel it sits on, exactly as the labels do.

Two checkers, two reaches. check_contrast.py reads the theme files; colours a skin mixes while running (chips, slots) are measured by the suite's skin contrast section inside Godot.