# Interface theme as data (ui.theme) Part of the [menus and screens guide](guide:ui-screens). ## 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 ```text 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 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: ```json { "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)` (`logo` or `background`, null if none). - `ui.theme.changed` (event): after `apply`, `reset` or `applyPreset`, 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.menu` `theme` is 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: `fontFile` is 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.