Interface theme
Give the whole game interface one look: colour roles, typography, shapes, key glyphs and images, a complete preset in one value, and a theme you can change while the game runs.
Interface theme as data (ui.theme) #
Part of the menus and screens guide.
What it is for #
ui.theme keeps one theme per game, as data: colour roles, typography, shapes, key glyphs and images. Every interface kit (menu, prompts, end screen, HUD) reads it through the ui.theme service, so one change restyles all of them on every engine. The kit draws nothing itself. Every default is unset, and unset means each kit keeps its built-in look: a game that does not configure the theme looks as it did before.
Turn it on #
gripforge_gamekit_install { project_id: "gkp_…", id: "ui.theme" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "ui.theme",
config: { "preset": "scifi-lowpoly", "colors": { "accent": "#f2c14e" } } }
First example #
<!-- test: kits/game_engine/host/tests/ui_theme.rs::a_change_counts_a_revision_and_an_invalid_value_changes_nothing --> At run time a script applies a patch. A colour that is not #rrggbb or #rrggbbaa, or a number out of range, changes nothing and does not count a revision. A valid patch is normalised (colours lower case, numbers rounded) and counts one revision:
{ "op": "call", "service": "ui.theme", "method": "apply",
"args": [{ "colors": { "accent": "#FF8800" }, "shapes": { "radius": 8.4 } }] }
The answer holds colors.accent as #ff8800 and shapes.radius as 8. Applying null for a key puts it back to unset.
Settings and defaults #
| Group | Keys | Values |
|---|---|---|
colors | accent, accentText, panel, text, muted, background, danger, success, focus | #rrggbb or #rrggbbaa; empty = built-in |
typography | font, fontFile, scale, size, titleSize, weight, letterCase | family; font file; scale 0.5 to 2 (0 = built-in); size 10 to 32; titleSize 20 to 96; weight regular, medium, bold; letterCase none, upper; auto = built-in |
shapes | radius, borderWidth, buttonShape, padding | radius 0 to 32, borderWidth 0 to 8, padding 0 to 64 (-1 = built-in); buttonShape square, rounded, pill |
glyphs | style, set | style: outlined, filled or text for keys; set: letters, shapes or positions for the gamepad face buttons |
images | logo, background | file paths, same rules as fontFile |
preset picks a complete look in one value (default empty: none). Presets: scifi-lowpoly, military, fantasy-medieval, cyberpunk-neon, cartoon-bright, horror-dark, minimal-clean, retro-pixel. Any explicit value of the config wins over the preset, and a preset never sets a file (fontFile, images).
fontFile is a URL on the web, a res:// path in Godot, a Resources path in Unity, an asset path in Unreal; the file ships with the game. The slots logo and background of the project, when bound, win over images.logo and images.background.
The stored config of ui.menu seeds what the theme leaves unset (its colours, scale and logo), so an older game keeps its look.
Services, events, variables #
ui.theme(service):theme()(the resolved theme),own()(only what this kit sets),apply(patch),reset(),revision(),presets(),preset(),applyPreset(id),fontUrl(),imageUrl(name)(logoorbackground, null if none).ui.theme.changed(event): afterapply,resetorapplyPreset, payload{ revision, theme }; interfaces redraw.- Variable:
ui.theme.revision, the number of theme changes since the start.
Hooks and modding #
The kit declares no hook: apply and reset are calls the game makes itself. A mod may change colors, shapes and glyphs; typography and images carry files the game fetches and stay with the game.
Engines #
Web, native, Godot, Unity and Unreal share the same model. Godot has a GfUiTheme node with a theme_changed signal, Unity a GfUiTheme component with a ThemeChanged event, Unreal a component with Blueprint-callable Theme, Apply Theme and Reset Theme. On the web, the first family of the font stack is loaded from a bundled open-licence file; Godot and Unity try the families in order; Unreal uses its own font unless fontFile is set.
When it does not do what you expect #
- The theme looks unchanged: the value is unset (each kit keeps its look), or the
ui.menuthemeis used instead. - A value is ignored: it is invalid (a colour without the
#, a number out of range); an invalid value changes nothing. - The font does not load:
fontFileis not reachable on that engine.
Limits #
The theme sets looks, not layout: where a screen puts its parts stays with the kit that draws it.
Versions #
Kit 1.3.0 (adds presets). Service ui.theme 1.0.0.