Menus and screens
Usage guide of ui.menu, ui.theme, ui.prompts, ui.endscreen and ui.cursor: screens, settings and defaults, theme groups and presets, key prompts that follow the bindings, end conditions, recap and credits, the game cursor.
Menus, theme, prompts and end screen (ui.* kits) #
The screens around your game: title and pause menus, options, the interface theme, key prompts, the end screen with credits and the game cursor. Readable offline: gripforge docs ui-screens, or the MCP tool gripforge_docs (topic ui-screens). To draw your own interface as a web page, see gripforge docs ui-webui.
What it is for #
Each kit builds one model that every engine draws (the web and native players, Godot, Unity, Unreal), so the same buttons, texts, tabs and behaviour come out everywhere.
| Kit | Role | In a new game |
|---|---|---|
ui.menu | title screen, pause menu, Options, Load / Save screen, loading line | yes (with input.remap, settings.graphics, save.persistence) |
ui.theme | one interface theme per game, as data | yes, with every value unset |
ui.prompts | key hints drawn from the live bindings | yes, with the help bar off |
ui.endscreen | victory, defeat and game over screen, recap, credits | yes (needs ui.menu) |
ui.cursor | a game cursor and the marker where an order is given | no |
gripforge_gamekit_configure { project_id: "gkp_…", id: "ui.menu",
config: { "title": "My game", "titleButtons": ["play", "continue", "options", "quit"] } }
gripforge_gamekit_configure { project_id: "gkp_…", id: "ui.theme", config: { "preset": "fantasy-medieval" } }
gripforge_gamekit_remove { project_id: "gkp_…", id: "ui.menu" } # the game then starts straight into play
Remove a default kit only when you mean to. The full reference of each is gripforge kit api <id>.
ui.menu #
- Title (
titleScreen, on): the game waits, paused. Buttons Play, Continue (only whensave.persistenceholds a save, the most recent one is loaded), Load, Options, Quit. Withgame.engine'ssceneFlow.menu: "scene"(every new game) the title is a scene of its own; seegripforge docs scenes. - Pause (
pauseKeyEscape, or the gamepad Start buttonpausePad): Resume, Save, Load, Options, Restart, Quit to title. - Load / Save: one row per slot with picture, date, play time, location and version; overwriting and deleting ask first.
- Options: tabs
general(language),controls(input.remap),graphics(settings.graphics), then tabs other kits register. A tab whose kit is absent is hidden.
| Key | Default | Meaning |
|---|---|---|
title, subtitle | project name, "" | texts of the title screen |
logo, background | "" | image paths (a web URL, res:// on Godot, a Resources path on Unity, an asset path on Unreal) |
titleMode | artwork | web: artwork, scene (the paused game behind), character (the bound model and its idle animation) |
characterSlot | player_character | model used by the character mode |
titleLayout, titleText, playLabel, titleHelp, pageBar | side, "", "", [], true | layout and texts of the title |
theme | accent #ff6b2c, panel #161a22, text #f4f1ea, background #0d1016, scale 1 | colours and size |
language | auto | auto, en, fr; the player can change it (kept in the player settings, outside saves) |
titleButtons | play, continue, load, options, quit | buttons and order |
pauseButtons | resume, save, load, options, restart, quit_to_title | buttons and order (quit can be added) |
tabs | general, controls, graphics | Options tabs; add saves to manage saves from Options |
pauseKey, pausePad | Escape, 9 | pause controls (not moddable) |
pauseGame | true | pause while a menu is open (not moddable) |
loadingLine | title | where the loading progress of asset.preload shows: title, menus, off |
waitFirstReady | false | Play stays disabled until the start scene is loaded (Continue and Load stay usable) |
keyHints | false | key hints under the buttons |
Loading line: while asset.preload loads, the title shows one line with a bar (Loading 42% - 12.3 / 29.0 MB - 14/30 files - from the cache), and nothing once it is done.
Add an Options tab: expose on your kit's service optionsTab() ({ id, order, label }), optionFields(lang) (fields of kind choice, toggle, slider, binding, button, actions) and setOption(id, value), then call ui.menu.registerTab("<your capability>").
Service: view(lang?), open(screen), back(), navigate(delta), focus(id), activate(id?), pause(), resume(), togglePause(), perform(action), press(control), tabs(), selectTab(id), nextTab(delta), fields(tab?), setOption(tab, id, value), registerTab(capability), canContinue(), setLanguage(lang), text(key), loading(lang?). Events: menu.screen, menu.action { action, slot } (play, continue, load, save, options, resume, restart, quit_to_title, quit), menu.tab, menu.language. The menu declares no hook: the player decides, and the kit that carries an action out owns the decision (a save goes through save.write of save.persistence). A mod can change texts, theme, staging, buttons and tabs, not images, the character slot, pause controls or pauseGame.
ui.theme #
Every default is unset, and unset means each kit keeps its built-in look: a game that does not configure the theme looks as before.
| Group | Keys | Values |
|---|---|---|
colors | accent, accentText, panel, text, muted, background, danger, success, focus | #rrggbb or #rrggbbaa |
typography | font, fontFile, scale, size, titleSize, weight, letterCase | family, font file, scale 0.5 to 2, body 10 to 32, title 20 to 96, regular/medium/bold, none/upper |
shapes | radius, borderWidth, buttonShape, padding | 0 to 32, 0 to 8, square/rounded/pill, 0 to 64 |
glyphs | style, set | outlined/filled/text; letters/shapes/positions for the gamepad face buttons |
images | logo, background | same path rules as fontFile |
preset picks a complete look in one value; any explicit value of the config wins over it. Presets: scifi-lowpoly, military, fantasy-medieval, cyberpunk-neon, cartoon-bright, horror-dark, minimal-clean, retro-pixel. A preset never sets a file (fontFile, images).
{ "preset": "scifi-lowpoly", "colors": { "accent": "#f2c14e" } }
Run time: presets(), preset(), applyPreset(id), apply(...), reset(); ui.theme.changed { revision, theme } makes interfaces redraw. Fonts: the web page loads the first family of the stack from a bundled open-licence file; Godot and Unity try the families in order; Unreal uses its own font unless fontFile is set. A mod can change colors, shapes and glyphs.
ui.prompts #
Key hints such as [E] Open door, or [A] Continue with a gamepad. No key is written in the kit: every label comes from input.actions (labelFor, promptFor), so it follows the player's remapping and the device used last. No key is shown on screen by default: the help bar (bar) and the context row (context) are off, and the controls live in Options, Controls. Turn one on for a tutorial or a game that lives on contextual prompts; a tutorial step pushes a prompt with show().
Keys: bar (false), context (false), barActions ([], the automatic bar), exclude, maxItems (6), interaction (true), contexts, position (bottom), device (auto), language (auto), hideInMenus (true); all moddable. Event prompts.changed.
ui.endscreen #
Opens once, pausing the game (pauseGame), when:
- a kit, script or code calls
show(result, stats?)withvictory,defeatorend; - an event of
victoryEvents(game.won) ordefeatEvents(game.lost) is emitted (patterns*andfamily.*work); - a mission listed in
missionscompletes (victory) or fails (defeat),*for any; - the player dies (
onDeath), or the game enters thefinishedphase (onFinished, on).
| Key | Default | Meaning |
|---|---|---|
template | classic | screen layout |
victoryEvents, defeatEvents | ["game.won"], ["game.lost"] | events that end the game |
missions | [] | missions that end the game |
onFinished, onDeath | true, false | |
showTime | true | play time in the recap |
stats | score, money, room | { id, var, label, format } lines read from variables (int, number, time, money, percent, text) |
buttons | retry, menu, credits | order; quit can be added. retry and menu go through ui.menu.perform |
victoryTitle, defeatTitle, victoryText, defeatText | built-in | { en, fr } texts |
creditsTitle, credits, creditsSpeed, poweredBy | project name, [], 1.5, true | credits is [{ title, names }], scrolled in order |
loadingLine | next | progress of the next scenes' preload by the buttons: next, all, off |
A kit adds recap lines by exposing endStats(lang) on its service and calling ui.endscreen.registerStats("<capability>"); a kit may set the variables endscreen.title and endscreen.text to replace the heading (game.endings does). Hook endscreen.show { result, trigger, mission, time }: mutable result (a defeat that is the true ending), cancellable (the screen stays closed and show() answers false). The credits are the authors' and not moddable.
ui.cursor #
Replaces the system pointer with a game cursor and marks the ground where the player gives an order. Any kit that turns a click into an order emits pointer.command { point, kind: "move" | "attack", target? }; this kit answers with the event fx.ground_marker (green arrows closing on the point for a move, red for an attack) and the host draws it.
| Key | Default | Meaning |
|---|---|---|
cursor | gauntlet | gauntlet, arrow, crosshair, system |
cursorColor, cursorSize | #d8dde6, 32 | |
marker | arrows | arrows, ring, none |
moveColor, attackColor | #3ee06a, #ff4d4d | the cursor turns attackColor over an enemy |
markerSeconds, markerSize | 0.55, 1.8 | life in seconds, radius in metres |
When it does not do what you expect #
| Symptom | Cause and fix |
|---|---|
| The game starts without a title | ui.menu was removed, or titleScreen: false |
| Continue is missing | save.persistence holds no save |
| A key hint is missing | ui.prompts bar and context are off on purpose: turn one on for a tutorial |
| The end screen never opens | no victoryEvents, defeatEvents, mission or show() call reaches it, or a tap of endscreen.show cancelled it |
| The theme looks unchanged | the value is unset in ui.theme (each kit keeps its look) or the ui.menu theme is used instead |