# Scripted GUIs

Use `hoi4.gui_inspect`, `hoi4.gui_render`, and `hoi4.gui_rewrite` for `.gui`, `.gfx`, `common/scripted_guis`, localisation, sprites, fonts, and linked decision entry points.

## Start with a preview

> Render this window at 100% and 125% UI scale. Show its control regions and list the state inputs needed to establish visibility and availability.

The [interface examples](https://github.com/klimPaskov/hoi4-agent-tools/blob/main/docs/gui-comparisons.md) show real vanilla and mod windows.
Cyan click regions have confirmed availability under the supplied scenario.
Dashed amber regions are potential controls with unresolved visibility or enabling conditions; they do not count as confirmed branch coverage.
The scene retains the reason so the agent can supply the missing facts instead of guessing.
These are source-model results, not proof of native click execution.

## Preview immediate tooltip text

An explicit tooltip request uses a visible element's `pdx_tooltip` localisation key. Supply `tooltip.target` with its inspected instance ID or a unique element name, plus viewport `x`, `y`, `width` and `padding` values.

Position, width and padding are declared viewport pixels; height follows the measured text.
The preview uses the loaded `ToolTip` sprite and `cg_16b` font.
Missing or ambiguous targets, hidden or unresolved visibility, missing text/assets, and bounds errors produce diagnostics without a guessed popup.
A visibly disabled control can still have tooltip text.

Engine-generated `[!element_action]` and `[!element_action_enabled]` descriptions are not invented.
If their exact text is known, supply the exact bracketed token as a string key in `scenario.values` or `scenario.scriptedGui`; otherwise the tooltip remains unresolved.
The preview does not establish native automatic positioning, frame composition, delayed timing or `click_to_front` behavior.

## Create a GUI

`hoi4.gui_rewrite` can work from supported source, targeted patches, or structured helpers. Source and helper rewrites may include one bounded text package: the main `.gui` plus additional interface `.gui`/`.gfx`, configured GFX `.gfx`, `common/scripted_guis/*.txt`, and localisation `.yml` files. The package is path-checked, parsed, linked, rendered, validated, and applied together in one rewrite. Existing text encodings are retained, while localisation is always written as UTF-8 with BOM.

A package may contain at most 32 text files and 16 MiB of encoded source in total. Paths are compared portably, so aliases that differ only by letter case are rejected.

Helpers cover common layouts such as anchors, rows, columns, stacks, grids, cards, tabs, scroll lists, meters, status panels, modals, and overlays. They compile to ordinary HOI4 GUI source; the finished mod has no runtime dependency on this server. Binary textures, fonts, and other art are referenced from `.gfx`/GUI source and must already exist in the workspace; the rewrite input does not upload binary art.

Before writing:

- define the root window, parent/context, element IDs, and dimensions;
- register sprites, textures, fonts, and localisation used on screen;
- provide button triggers, effects, scripted-GUI properties, dynamic-list wiring, and AI behavior where required;
- render the important states and resolutions;
- keep click regions aligned with visible controls.

Rewrite once, then inspect and render the result.

## Clean an existing GUI

1. Inspect the root window and its linked GUI, GFX, scripted-GUI, and localisation source.
2. Render the normal state and the states relevant to the task, such as hover, selected, disabled, warning, empty list, full list, minimum value, maximum value, or long text.
3. Add `relatedScenarios` for every meaningful value-driven version of the window, such as open and closed panels, empty and populated lists, unlocked and locked actions, low and high values, and alternate scripted-GUI property results.
4. Check common resolutions and UI scales when positioning or clipping can change.
5. Fix the existing mod-owned file with targeted patches, a complete supported source replacement, or a structured helper replacement.
6. Rewrite once, then inspect and render the result.

Inspection checks missing assets and localisation, invalid sizes, overlap, clipping, overflow, button-label centering, content crossing a background boundary, conflicting click regions, invisible blockers, broken parents or contexts, list-row cuts, state conflicts, trigger/effect gaps, and resolution drift. `hoi4.gui_render` returns a scripted-scenario gallery and JSON delta report alongside the generic state and resolution galleries. The scenario matrix records shown and hidden branches, enabled and disabled branches, reasons for hidden or disabled controls, measured label boxes and text overflow, and rendered background boxes with sprite provenance. Use its branch coverage list to identify scenario conditions that still need evidence.

For source comparisons, pass `sourceBaseline: { "relativePath": "interface/example.gui", "source": "..." }` to `hoi4.gui_render`. The tool renders that mod-owned `.gui` text and the current source with the same requested scenario, and returns source-baseline and source-comparison PNGs plus a JSON report with source revisions and pixel deltas. `comparisonScenario` remains the separate comparison between two scenarios on the current source.

GUI scenarios accept `date` in `YYYY.M.D` or `YYYY-MM-DD` form and `controls` as a map from state IDs to controller tags, for example `{"date":"1944.10.1","country":{"tag":"GER"},"controls":{"87":"GER","88":"GER"}}`. Date and controller facts reach the shared condition evaluator, including `controls_state` and `is_controlled_by` in declared state scopes. An absent state-controller fact remains unresolved. These fields are explicit scenario assumptions; they do not prove a live campaign's state or engine execution.

A requested root window uses its source `show_position` when present. This is the settled visible endpoint, so native windows whose ordinary `position` is offscreen can be inspected as open panels. The static render does not claim to reproduce the engine's transition animation.

Explicit native list rows resolve their entry template in the owning GUI file before considering a shared template, so reused names in unrelated vanilla windows do not select the wrong layout. One-column native grids with a one-pixel slot height stack entries by their rendered heights. Scenario `.text` overrides can name installed localisation keys even when those keys do not appear literally in the selected GUI source. For dimensions normally supplied by engine code, provide `values["element.width"]` or `values["element.height"]` in native UI pixels and record the source or declared-state basis for those values.

The renderer resolves sprites and fonts through the complete mod, dependency, and installed-game load order. Mod windows therefore render ordinary vanilla sprites, tiled vanilla panels, progress bars, masked shields, button frames, country flags, and localisation icons such as `£command_power` without copying game assets into the mod. Case differences in GFX and font identifiers do not prevent a valid asset from resolving.

Bitmap text uses the language-appropriate HOI4 font definition and its real glyph atlas. Header, serif, compact, typewriter, black, inverted, and other declared faces keep their own glyph shapes, native metrics, face colour, border colour, language override, and font-specific `textcolors` palette. The renderer reads BMFont channel roles, separates face and outline coverage, and recognizes both vanilla black-on-white masks and conventional white-on-transparent custom masks. HOI4 localisation colour runs such as `§Y` and `§R` therefore colour the glyph face while retaining its sharp antialiasing and declared border instead of flattening the glyph into a blurred monochrome mask or switching to the tool font. The default language uses the base font rather than an unrelated language override, and the renderer recognizes installed-game atlases whose filename omits a page suffix declared by the matching `.fnt` file.

`uiScale` is the in-game UI scale, not an image zoom. Use `1` for native pixel geometry at any screen resolution. Bitmap-font glyphs come directly from the real atlas without a sharpening, threshold, opacity-gain, or reconstructed-edge pass. Native-size coverage is unchanged. Enlarged coverage uses restrained Lanczos2 interpolation to avoid blocky pixel replication without running a sharpening filter. Downscaling uses nearest-neighbour sampling. Bitmap placement is snapped to the output pixel grid, and bitmap colours use alpha masks, so native, fractional-scale, local, and VPS renders remain deterministic.

Layout follows Clausewitz orientation and element-origin anchors, including `CENTER_LEFT`, `CENTER_RIGHT`, `CENTER_UP`, `CENTER_DOWN`, `origo`, `centerposition`, inherited container coordinate origins, local scale, and both `%` and `%%` relative dimensions. Text boxes use native font metrics together with `maxWidth`, `maxHeight`, alignment, wrapping, and `fixedsize` clipping. Cornered tile sprites use fixed nine-slice borders and optional center tiling; progress bars composite their filled and background textures; masked shields composite their background and mask textures.

A single-percent dimension is a proportional extent; a double-percent dimension names the far edge in the parent and subtracts the element's resolved anchor position.
For example, a centered root at y=423 with `height=85%%` in a 1440-pixel viewport ends at y=1224 and has height 801, rather than height 1224.
GUI element type matching is case-insensitive while source spelling and bytes are preserved.
A zero horizontal or vertical corner border produces the corresponding three-slice composition rather than stretching the entire texture.
Colour-only progress sprites use their declared size, `color` and `colortwo` without requiring a texture.
The supported source-backed progress shader selects a colour or texture on each side of its progress threshold; semi-transparent primary pixels do not blend over a second complete texture layer.
The scene records the selected shader source, hash and entry point.
Additional shader operations, including animated end-cap sampling, remain explicit unsupported findings rather than accepted pixel-parity evidence.

Container scrollbars use referenced or inline `extendedScrollbarType` templates, including their backgrounds, inline track, thumb and end-button artwork.
The template's slider and end-button roles are engine-owned compound controls, so scripted click-effect checks apply to authored source buttons and explicitly referenced role names rather than requiring effects for the native scrollbar internals.
Each attachment has independent instance IDs and source provenance even when multiple containers reuse one template.
The renderer measures direct content bounds and populated grid/list rows, retaining declared list bounds as a minimum, clamps scroll offsets, and applies `autohide_scrollbars`.
A nested container contributes its declared bounds rather than the overflowing artwork of its descendants.
Margins inset the scrolling clip without adding layout padding; attached scrollbars anchor to the outer window, and children wholly inside a fixed border remain stationary.
Clipping is resolved after scroll positioning, so off-screen content can scroll into view and nested scrolling retains the correct ancestor boundaries.
Visible orthogonal scrollbars reserve their anchored gutters to avoid overlapping end controls.
Native corner-space behavior still needs matching in-game reference qualification; synthetic non-overlap checks alone do not establish engine parity.

Supply `values["container.scrollX"]` and `values["container.scrollY"]` in native UI pixels; these keys also work inside list rows.
The existing `scrollOffsets` map remains a vertical-offset shorthand, including names with row-instance suffixes.
`minimum-value` and `maximum-value` scenarios sample content endpoints.
The scene element's `scroll` record exposes its viewport, measured content dimensions, applied offsets and maximum offsets in output pixels after UI scaling.
Missing, wrong-axis, duplicate or privately scoped scrollbar references and unclipped/background-less containers produce explicit findings rather than invented templates.

Scripted-GUI composition follows `parent_scripted_gui` chains even when the linked child window is a top-level sibling in the `.gui` file. Literal `always = yes` and `always = no` visibility and click-enabled blocks are applied automatically. A scenario's `values` object supplies concrete runtime values in one place: variable names resolve numeric text, scripted-localisation names resolve dynamic labels, a progress-bar element name sets its fill value, and element keys ending in `.image`, `.frame`, `.x`, `.y`, `.visible`, or `.enabled` update that visual property. Scripted-GUI property expressions such as `image = "[GetMeterSprite]"` or `x = meter_fill_width` consume matching scenario values automatically. Dynamic text is parsed after scenario and scripted-localisation substitution, so a runtime string containing `£command_power` or `£[GetResourceIcon]` renders the resolved inline HOI4 text icon instead of literal marker text. Dynamic lists instantiate their declared `entry_container` or `country_scope_entry_container`; each scenario row can select the country template with `countryScope`, choose an explicit `entryContainer`, provide `countryTag` and `ideology` for `GetFlag`, and supply row-scoped text, image, frame, position, visibility, and enabled values. Masked country sprites use the actual mask and overlay dimensions, so custom flag sizes are discovered from GFX assets rather than assumed by the renderer.

Native lists can also use an explicit `entryContainer` without fabricated scripted-GUI wiring.
Each expanded row instance includes its owning list identity, so two lists using the same template cannot overwrite one another's clipping or geometry.
For native country-flag controls, bind `element_name.countryTag` and `element_name.ideology` in scenario or row values.
Only valid bounded tag tokens enter asset discovery; an invalid tag is reported, not converted into a different country's identifier or a filesystem path.
An unrelated global country value does not turn every native icon into a flag.

`hoi4.gui_inspect` and `hoi4.gui_render` generate a seeded exploratory preview by default. The generator follows the complete `parent_scripted_gui` surface, discovers numeric and text tokens, fills meters within their declared ranges, and populates dynamic lists with coherent rows. Scripted-localisation text and sprite branches use the same structured condition evaluator as probability analysis, including compound conditions, inclusive comparisons, constants, declared scopes, and scripted triggers. An unknown earlier condition leaves the token unresolved instead of guessing a branch. The scenario's `conditionResults` records checked choices and missing inputs. Explicit values remain authoritative; generated inputs are not verified campaign state. Normal controls and animation frames remain stable unless variation is requested. Every explicit `relatedScenarios` entry is rendered beside the generated view.

Declare scoped facts with `scopes`, for example `"scopes": { "FROM": { "id": "target", "actor": "FRA", "state": { "support": 10 } } }`. Existing flat values such as `FROM.support` remain usable. Seeded pane and active/idle selection is exploratory layout sampling, not proof that every visibility branch is reachable.

Generation is reproducible. Set `generatedScenarios.seed` to any stable string for an exact rerun, use `count` for several plausible versions, or configure numeric bounds, integer or decimal values, list row bounds, text samples, visibility probability, and state variation. Generated numeric values favour ordinary mid-range states, obey literal limits such as `[?capacity]/10`, keep displayed current/limit pairs coherent, and remain inside progress-bar ranges. The generated view is the default. Set `enabled` to `false` when only the supplied placeholder scenario should render, or set `preservePlaceholder` to `true` to include the placeholder beside generated scenarios.

```json
{
  "generatedScenarios": {
    "seed": "status-panel-review",
    "count": 3,
    "numericMinimum": 0,
    "numericMaximum": 100,
    "listRowsMinimum": 2,
    "listRowsMaximum": 8,
    "trueProbability": 0.75,
    "textSamples": ["Stable", "Escalating", "Critical"]
  }
}
```

Preview scenarios can include exact layout expectations:

```json
{
  "id": "populated-unlocked",
  "values": {
    "threat": 73,
    "GetThreatLabel": "High",
    "GetCostLine": "Cost £command_power 20",
    "threat_meter": 73,
    "confirm_button.enabled": true
  },
  "flags": { "panel_open": true },
  "lists": {
    "target_list": [
      {
        "id": 1,
        "label": "France",
        "countryScope": true,
        "countryTag": "FRA",
        "ideology": "democratic"
      }
    ]
  },
  "visibility": { "target_list": true, "confirm_button": true },
  "expectations": {
    "visible": ["target_list", "confirm_button"],
    "hidden": ["empty_message"],
    "containedBy": { "confirm_button": "main_panel" },
    "centeredOn": { "confirm_label": "confirm_button" }
  }
}
```

Selectors accept an element name, instance ID, or source ID. Visibility expectations diagnose elements that are missing or in the wrong scripted version. `containedBy` diagnoses text or controls that leave their intended background or panel. `centeredOn` uses rendered glyph bounds, so it catches labels that occupy the right text box but are visibly off-center on the button.

Broad inspection indexes localisation actually referenced by GUI source and returns a connected workspace projection when the complete source graph is very large. The resource records full and returned node and edge counts, so an agent can identify the relevant window without loading unrelated vanilla UI into its prompt. Rendering remains targeted to the selected root, state, and resolution.

GUI rewrites keep complete validation evidence in a linked JSON resource and retain the highest-priority findings in the transaction result. Large surrounding interface inventories therefore do not turn a small scalar patch into a transaction structure-limit error.

Large inspections, renders, and rewrites send periodic MCP progress heartbeats while a service stage is still running.
Clients that request progress can reset their idle request timer from these notifications, and cancellation follows the request signal.
A read-only `hoi4.gui_inspect` or `hoi4.gui_render` job still running after the configurable `jobDeadlineSeconds` (default 1,800) is stopped with `JOB_DEADLINE_EXCEEDED`; a `hoi4.gui_rewrite` job is not stopped by that deadline.
See [persistent jobs and MCP tasks](jobs.md#cancellation-and-recovery).

## Source-backed button shading

The renderer reads referenced shader source, including legacy `.lua` references whose implementation is a `.shader` file.
For supported native sprite transforms and straight-alpha blending, a bounded interpreter derives affine RGBA colour operations from the selected normal, hover, pressed or disabled pixel program.
It supports scalar/vector arithmetic, swizzles, constant interpolation, dot products and clock-dependent constant expressions without executing shader code or arbitrary functions.
The scene records source identity, effect and entry point; unresolved features, nonlinear sampled-colour operations, additional texture samples and unsupported geometry or blend states remain fidelity findings.
Supported primary samplers retain point or linear filtering for magnification and minification and use clamped, non-mipmapped texture sampling.

Button shading is independent of explicit atlas frames and checkbox checked state.
Use `values["element.checked"]` for a checkbox's Boolean state, `values["element.pressed"]` for a held button, and `values["element.stateTimeSeconds"]` for elapsed time in the current button state.
These keys also work in list rows.
Without a per-element state clock, `animationTimeSeconds` supplies elapsed time; `0` represents entry into the state, not a settled hover.
Source or scenario `enabled = false` selects disabled appearance and removes the control from click regions.

## Scenario fidelity

The renderer does not run the game engine. Each render includes a fidelity report that separates fields it models from fields it approximates, ignores, cannot resolve, or does not support. Treat that report as part of the review.

### Scenario fields

Every `scenario` needs an `id`, a short label such as `"usa_1936"`.
The other fields describe the game state the window is drawn under and how the preview is produced.
Unknown fields are rejected.
The complete schema is [gui-scenario.schema.json](../schemas/gui-scenario.schema.json); `relatedScenarios` entries and `comparisonScenario` use the same shape.

| Field                  | Type                                          | Default and limits                                                                                                                                                                                                           | Meaning                                                                                                                                                                                                            |
| ---------------------- | --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id`                   | string                                        | Required; 1–128 characters matching `^[A-Za-z0-9][A-Za-z0-9._-]*$`.                                                                                                                                                          | Scenario label used in artifact names and reports.                                                                                                                                                                 |
| `description`          | string                                        | Optional; at most 500 characters.                                                                                                                                                                                            | Free-text note about the scenario.                                                                                                                                                                                 |
| `date`                 | string                                        | Optional; a valid calendar date as `YYYY.M.D` or `YYYY-MM-DD`, at most 16 characters.                                                                                                                                        | Game date, `"1936.1.1"`, for date conditions.                                                                                                                                                                      |
| `country`              | map of name → string, number, or boolean      | Optional.                                                                                                                                                                                                                    | Viewing-country values for `[ROOT.GetName]`-style text; `tag`, `countryTag`, or `GetTag` names the actor country for conditions and for country flags, and `ideology` selects the flag variant.                    |
| `controls`             | map of state ID → country tag                 | Optional; state IDs are positive integers without leading zeros, tags are three `A-Z` or `0-9` characters, at most 2,048 entries.                                                                                            | State controllers, `{"64": "GER"}`, for `controls_state` and `is_controlled_by`.                                                                                                                                   |
| `flags`                | map of flag name → boolean                    | `{}`.                                                                                                                                                                                                                        | Flags on the viewing country, `{"show_settings_page": true}`.                                                                                                                                                      |
| `closedFlags`          | boolean                                       | Optional; absent means `false`.                                                                                                                                                                                              | `true` treats every flag not listed in `flags` as unset, as on a country that never received it. Without it, an undeclared flag is unknown and every condition that reads it stays unresolved.                     |
| `variables`            | map of name → number                          | `{}`.                                                                                                                                                                                                                        | Variables on the viewing country, `{"settings_page": 1}`.                                                                                                                                                          |
| `values`               | map of key → string, number, or boolean       | `{}`; strings at most 16,384 characters.                                                                                                                                                                                     | Exact runtime values for localisation tokens, scripted-GUI properties, and element keys such as `element.visible`, `element.enabled`, `element.frame`, `element.x`, `container.scrollY`, or `element.width`.       |
| `stateValues`          | map of key → string, number, or boolean       | Optional.                                                                                                                                                                                                                    | Additional condition state for the viewing country; `variables` and `values` override the same key.                                                                                                                |
| `conditionResults`     | array of condition records                    | Optional; at most 10,000 records of `{ token, sourcePath, state, localisationKey?, unresolved }`, where `state` is `true`, `false`, or `unresolved`.                                                                         | Written by the scenario generator to record checked scripted-localisation choices and missing inputs. It is accepted on input so a returned scenario can be sent back unchanged; it does not decide any condition. |
| `visibility`           | map of element or scripted-GUI name → boolean | `{}`.                                                                                                                                                                                                                        | Forced visibility, `{"settings_page_events": false}`; it overrides evaluated triggers.                                                                                                                             |
| `scopes`               | map of scope name → scope binding             | Optional; names at most 256 characters.                                                                                                                                                                                      | Named scope bindings such as `FROM`. A binding has `id` (1–256 characters) and optional `type`, `actor`, `state`, `flags` (an array of names), `eventTargets`, and `weight`.                                       |
| `lists`                | map of list name → array of row objects       | `{}`; at most 256 list names and 10,000 rows across all lists.                                                                                                                                                               | Dynamic and native list rows. Each row is a map of scalars, such as `id`, `label`, `countryScope`, `entryContainer`, `countryTag`, `ideology`, and row-scoped element values.                                      |
| `localisation`         | map of key → text                             | `{}`.                                                                                                                                                                                                                        | Per-scenario localisation overrides; a key here replaces the installed text for that key.                                                                                                                          |
| `scriptedGui`          | map of key → string, number, or boolean       | `{}`.                                                                                                                                                                                                                        | Scripted-GUI property and token values, including exact `[!element_action]`-style tooltip tokens; `values` takes precedence for the same key.                                                                      |
| `elementStates`        | map of element name → preview state           | `{}`; states as listed for `state`.                                                                                                                                                                                          | Per-element preview state that overrides `state` for that element.                                                                                                                                                 |
| `selectedFrames`       | map of element or sprite name → integer       | `{}`; integers of at least 0.                                                                                                                                                                                                | Zero-based frame index for a frame sprite, clamped to the last frame. It takes precedence over `.frame` values, which are one-based as in HOI4 source.                                                             |
| `scrollOffsets`        | map of container name → number                | `{}`; numbers of at least 0.                                                                                                                                                                                                 | Vertical scroll offset shorthand in native UI pixels, including names with row-instance suffixes.                                                                                                                  |
| `guiCosts`             | map of key → number                           | `{}`.                                                                                                                                                                                                                        | Cost shown by the GUI for a key.                                                                                                                                                                                   |
| `scriptCosts`          | map of key → number                           | `{}`.                                                                                                                                                                                                                        | Cost charged by script for the same key; a different `guiCosts` value for that key reports `GUI_COST_MISMATCH`.                                                                                                    |
| `expectations`         | object                                        | `{ "visible": [], "hidden": [], "containedBy": {}, "centeredOn": {} }`; each list holds at most 10,000 selectors.                                                                                                            | Layout assertions: `visible` and `hidden` list selectors, `containedBy` maps a selector to its intended background or panel, and `centeredOn` maps a label to the control it should be centred on.                 |
| `tooltip`              | object                                        | Optional; `target` (1–256 characters), `x`, `y`, `width`, and `padding` are all required. `x`, `y`, and `padding` are at least 0, `width` is greater than 0 and at most 16,384, and `padding * 2` must be less than `width`. | Immediate tooltip preview for one element, as described in [Preview immediate tooltip text](#preview-immediate-tooltip-text).                                                                                      |
| `resolution`           | `{ width, height }`                           | `{ "width": 1920, "height": 1080 }`; integers, width 320–16,384 and height 200–16,384, within the render pixel budget.                                                                                                       | Screen size in pixels.                                                                                                                                                                                             |
| `uiScale`              | number                                        | `1`; 0.25–4.                                                                                                                                                                                                                 | In-game UI scale. It changes layout geometry and is not an output-image zoom.                                                                                                                                      |
| `state`                | string                                        | `"normal"`; one of `normal`, `hover`, `selected`, `locked`, `disabled`, `warning`, `active`, `completed`, `empty-list`, `full-list`, `minimum-value`, `maximum-value`, `long-text`, `missing-localisation`.                  | Preview state applied to every element without an `elementStates` entry.                                                                                                                                           |
| `language`             | string                                        | `"l_english"`; matches `^l_[a-z_]+$`.                                                                                                                                                                                        | Localisation language, which also selects language-specific fonts.                                                                                                                                                 |
| `background`           | string                                        | Optional; `scene` or `transparent`. Absent means `scene`.                                                                                                                                                                    | `"transparent"` renders without the preview backdrop, so pixels the window does not cover are fully transparent in every PNG.                                                                                      |
| `animationTimeSeconds` | number                                        | `0`; 0–86,400.                                                                                                                                                                                                               | Elapsed time for frame animation and button-state shading; `0` represents entry into the state.                                                                                                                    |
| `visibleTimeSeconds`   | number                                        | Optional; 0–86,400.                                                                                                                                                                                                          | Elapsed time since the window became visible, used by frame animations that play on show; absent means `animationTimeSeconds`.                                                                                     |

A whole scenario may hold at most 100,000 object keys and 1,000,000 string characters in total.

GUI `flags` is a `{ "name": true }` map.
Decision scenarios (`hoi4.decision_inspect`) and probability scenarios take `flags` as an array of flag names, such as `["relief_open"]`, and so do scope bindings in every tool, including GUI `scopes`.

A scripted GUI `visible` or `<element>_visible` trigger that the scenario decides hides or shows its element exactly.
For compositing, each visible element is its own `<g>` group in the full SVG, with an `id` that matches the element in `layout.json`, which also records every element's box.
A trigger the scenario cannot decide leaves the element drawn and lists it in the fidelity report as unresolved, so pages that the game shows one at a time can overlap in the preview.
For tabbed windows, set the flags or variables of the page to show and `closedFlags: true`, then render each page as its own scenario through `relatedScenarios`.
`GUI_UNRESOLVED_VISIBILITY_OVERLAP` names each overlapping pair drawn together for that reason.
`GUI_NEAR_CENTRE_OFFSET` names an element whose horizontal centre is between half a pixel and 3 pixels from its parent's centre, which usually means it was meant to be centred.
Scripted localisation (`defined_text`) used by the window resolves to its first branch whose trigger the scenario decides as true, as long as every earlier branch is decided false; otherwise the token renders as `[dynamic_loc]`. A value in `values` always takes precedence.

The generated primary view replaces discovered numeric and text runtime tokens with plausible values. Set `generatedScenarios.preservePlaceholder` to `true`, or disable generation, when the same run should also show unresolved numeric values such as `[?variable|format]` as `[X]` and unresolved text-returning scripted or scoped localisation such as `[GetStatusText]`, `[FROM.GetName]`, and `[?leader_scope.GetName]` as `[dynamic_loc]`. Put `variable` or `GetStatusText` in the supplied scenario's `values` object when an exact value matters; explicit values always take precedence over generated ones and can drive the related meter or state-dependent controls. Supported HOI4 `§` localisation colour controls use the active font's palette and `§!` restores the face colour.

A rewrite stops if malformed or unsupported GUI script makes the requested change ambiguous. Frame-sheet animation, nine-slice tiling, progress composition, masking, and the primary and secondary textures referenced by vanilla GFX definitions render offline. Font selection follows mod/game load order and preview language, accepts Paradox hex and numeric color declarations, and uses the supplied HOI4 bitmap or outline font assets without requiring host font installation. Shader operations outside the supported colour subset, hardcoded controls, and dynamic values that are not supplied by a scenario remain fidelity-report entries; an unexecuted shader never hides its resolved base texture.

### Generated scenarios

`generatedScenarios` configures the seeded exploratory scenarios that `hoi4.gui_inspect` and `hoi4.gui_render` build from the supplied scenario.
It requires a window `scenario`, and unknown fields are rejected.

| Field                 | Default and limits                                                                                  | Meaning                                                                                                                                                                     |
| --------------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`             | `true`                                                                                              | `false` renders only the supplied scenario and its related scenarios.                                                                                                       |
| `count`               | `1`; 1–16.                                                                                          | Number of generated scenarios.                                                                                                                                              |
| `seed`                | `"auto"`; 1–256 characters.                                                                         | `"auto"` derives the seed from the window name, scenario `id`, and source-graph hash, so unchanged source reproduces the same output; any other string is used as the seed. |
| `idPrefix`            | `"generated"`; 1–64 characters matching `^[A-Za-z0-9][A-Za-z0-9._-]*$`.                             | Generated scenario IDs are `<scenario id>-<idPrefix>-<n>`.                                                                                                                  |
| `preservePlaceholder` | `false`                                                                                             | `true` also renders the supplied scenario, with unresolved tokens shown as `[X]` and `[dynamic_loc]`.                                                                       |
| `numericMinimum`      | `0`; −1,000,000,000 to 1,000,000,000.                                                               | Lower bound for generated numbers.                                                                                                                                          |
| `numericMaximum`      | `100`; −1,000,000,000 to 1,000,000,000, and at least `numericMinimum`.                              | Upper bound for generated numbers.                                                                                                                                          |
| `integerValues`       | `true`                                                                                              | `false` allows decimal values.                                                                                                                                              |
| `listRowsMinimum`     | `1`; 0–100.                                                                                         | Fewest generated rows per list.                                                                                                                                             |
| `listRowsMaximum`     | `5`; 0–100, and at least `listRowsMinimum`.                                                         | Most generated rows per list.                                                                                                                                               |
| `trueProbability`     | `0.7`; 0–1.                                                                                         | Probability that a generated Boolean is `true`.                                                                                                                             |
| `visibility`          | `"varied"`; `show-all` or `varied`.                                                                 | `show-all` shows every scripted GUI that has a visibility trigger; `varied` samples which of them are shown. Explicit `visibility` entries are kept in both modes.          |
| `elementStates`       | `"normal"`; `normal` or `varied`.                                                                   | `varied` samples per-element preview states; `normal` keeps controls in their normal state.                                                                                 |
| `textSamples`         | `["Operational", "Ready", "Stable", "Available", "In Progress"]`; 1–64 strings of 1–128 characters. | Strings used for generated text values.                                                                                                                                     |

### Request fields

Every request accepts `workspaceId`, which defaults to `"current"`.
`windowName` is 1–256 characters, and `scenario` follows the scenario fields above.

| Field                | Tools                    | Limits                                                                                                         | Meaning                                                                                                                                                                         |
| -------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `windowName`         | inspect, render, rewrite | Required for render and rewrite; inspect requires it exactly when `scenario` is present.                       | Root window to inspect, render, or validate. An inspect call without `windowName` and `scenario` inspects the workspace GUI graph.                                              |
| `scenario`           | inspect, render, rewrite | Required for render and rewrite.                                                                               | Primary scenario.                                                                                                                                                               |
| `relatedScenarios`   | inspect, render          | At most 32; requires `scenario`.                                                                               | Additional explicit scenarios rendered beside the primary and generated views.                                                                                                  |
| `generatedScenarios` | inspect, render          | Requires `scenario`.                                                                                           | Generator options from the table above.                                                                                                                                         |
| `states`             | render                   | At most 14 values of the `state` enumeration; defaults to all 14.                                              | Preview states in the state gallery.                                                                                                                                            |
| `resolutions`        | render                   | 1–16 entries of `{ width, height, uiScale? }`, with the same size limits as `resolution` and `uiScale` 0.25–4. | Resolution gallery. The default is 1280×720, 1920×1080, and 2560×1440 at UI scale 1, plus 1920×1080 at UI scale 1.25. An entry without `uiScale` uses the scenario's `uiScale`. |
| `comparisonScenario` | render                   | Same shape as `scenario`.                                                                                      | Second scenario compared against the primary scenario on the current source.                                                                                                    |
| `sourceBaseline`     | render                   | `{ relativePath, source }`; `source` at most 32 MiB.                                                           | Previous mod-owned `.gui` text rendered with the same scenario for a source comparison.                                                                                         |
| `mode`               | rewrite                  | Required; `source`, `helpers`, or `patches`.                                                                   | Rewrite input form.                                                                                                                                                             |
| `relativePath`       | rewrite                  | Required workspace-relative path.                                                                              | Main `.gui` file to write.                                                                                                                                                      |
| `source`             | rewrite                  | Required in `source` mode and rejected in the other modes; at most 32 MiB.                                     | Complete replacement `.gui` source.                                                                                                                                             |
| `helper`             | rewrite                  | Required in `helpers` mode and rejected in the other modes.                                                    | Structured helper document; see [gui-helper.schema.json](../schemas/gui-helper.schema.json).                                                                                    |
| `additionalFiles`    | rewrite                  | At most 31 entries of `{ relativePath, source }`, each `source` at most 32 MiB; rejected in `patches` mode.    | Other files in the same text package, as described in [Create a GUI](#create-a-gui).                                                                                            |
| `expectedSourceHash` | rewrite                  | Required in `patches` mode and rejected otherwise; 64 lowercase hexadecimal characters.                        | SHA-256 of the current file bytes; a different current file fails with `GUI_SOURCE_STALE`.                                                                                      |
| `patches`            | rewrite                  | Required in `patches` mode and rejected otherwise; 1–1,000 entries.                                            | Targeted replacements of `{ start, end, expectedText, text, description }`.                                                                                                     |
| `requestKey`         | rewrite                  | 1–256 characters.                                                                                              | Caller-stable key for native background rewrites and their retries; see [rewrite request keys](jobs.md#rewrite-request-keys).                                                   |

Each patch replaces the source text between offsets `start` and `end`, which are integers of at least 0.
The current text in that range must equal `expectedText`; otherwise the rewrite stops with `GUI_PATCH_PRECONDITION_FAILED`.
`expectedText` and `text` are at most 5,000,000 characters each, and `description` is 1–1,000 characters.
