A HUD defines its control panels in wwwroot/panel.json. sOU generates the panel editor from this. Texts, counters, media and references are stored as settings; action buttons, on the other hand, send one-time messages. The HUD itself determines how a field affects its presentation.
This chapter is aimed at HUD authors. The operation of finished panels is under Use HUD panels. The package rules are described under HUD package format.
Your first control panel
The SDK templates already contain the text field “Heading”. First try this field: Create, package and import your own project after Development guidelines, open a panel, change text and save it. The output takes over the stored text. Then you can add your own field.
- Create a section and field in
wwwroot/panel.json. In the following complete example, thedisplaysection is the text fieldcaption. - Subscribe to the panel stream in the HUD. In the web template, the text from
message.state.values.display?.captionis read; in C#,state.Text("display", "caption")provides the value. The Web template and the Blazor template already contain the connection. - Bind the text to an HTML element or a Razor output. As long as no text has been saved, display your own standard heading. For HTML, use
textContent. - Build and import a new package version, reload output, open a panel and save the text. Only the interplay of definition, reception and presentation makes the field usable.
For permanent settings, use normal fields. For “Start Animation Now” an action button is suitable: it triggers a one-time process and is not caught up after a reconnection. The following sections fully describe all field types and messages.
Definition and limits
The root is a JSON array of sections. One section has name, label and inputs. A field has type, name, label and optionally values. A non-existent panel file does not produce a panel; an invalid existing file prevents installation.
| Element | Type | Border |
|---|---|---|
| Entire file | UTF-8-JSON array | At most 64 KiB. |
| Sections | Array | Not more than 16. |
name of a section/field | String | 1–64 ASCII characters; starts with letters, then letters, numbers, underscores or hyphens. Model ^[a-zA-Z][a-zA-Z0-9_-]{0,63}$. |
label | String | 1–160 characters; visible intelligible inscription. |
inputs | Array | Required, maximum 64 fields per section. |
type | String enum | A supported field type; numeric values or unknown types are invalid. |
values | Array or null | Maximum 64 selection values. For select, at least one is required. |
values[].name | String | 1–160 signs without control signs. A data value, not a field identifier: for example, 2.5em is allowed. |
values[].label | String | 1–160 characters; caption of the selection or action button. |
Section names must be unique in the file, field names within its section, and selection values within its field. These identifiers are ordinally distinguished. Use permanently stable, consistently written names: They are keys of stored values and update adoption. A modified label changes the visible label; a modified name generates a different field from the point of view of adoption.
Complete example
[
{
"name": "display",
"label": "Darstellung",
"inputs": [
{ "type": "text", "name": "caption", "label": "Überschrift" },
{ "type": "checkbox", "name": "show_caption", "label": "Überschrift anzeigen" },
{
"type": "select", "name": "scale", "label": "Schriftgröße",
"values": [
{ "name": "2em", "label": "Normal" },
{ "name": "2.5em", "label": "Groß" }
]
},
{ "type": "player", "name": "featured_player", "label": "Spieler" },
{ "type": "team", "name": "featured_team", "label": "Team" },
{ "type": "match", "name": "featured_match", "label": "Match" },
{ "type": "image", "name": "logo", "label": "Logo" },
{ "type": "images", "name": "sponsors", "label": "Sponsorenbilder" },
{
"type": "action", "name": "cue", "label": "Einblendung",
"values": [
{ "name": "show", "label": "Einblenden" },
{ "name": "hide", "label": "Ausblenden" }
]
},
{ "type": "action", "name": "restart_animation", "label": "Animation neu starten" }
]
}
]
The example only describes the control elements. Without appropriate evaluation in the HUD, a button does not fade in and a size field does not change any font. Only link the fields that your application actually supports.
Field types and stored values
| Type | Value in condition | Standard and validation |
|---|---|---|
text | String | Standard ""; maximum 4.096 characters. |
checkbox | Boolean | Standard false. Strings such as "true" and numbers are not valid substitute values. |
select | String | Standard ""; then empty or exactly one of the declared values[].name values. |
player | String | Steam ID of the selected managed player; empty on no selection. Resolved metadata is separate in references. |
team | String | Managed Team ID or blank; no CT/T page. |
match | String | Managed match ID or empty; the selection does not activate a match itself. |
image | String | Empty string or soluble local path under /cast-media/. No free external image URL. |
images | Array of strings | Standard []; maximum 16 entries. Each entry must be valid as a local image reference. |
action | No stored cell value | With values one button per declared action; without selection values one button with value: null. |
There is no separate number, color, slider, mandatory field or freely configurable default value type in the current scheme. For example, if your HUD needs a color as text, it must validate this text itself and use a suitable fallback if entered invalidly. An additional default field in the JSON does not establish an agreed default value.
sOU supplements all defined checkboxes with the actual value false on the first loading. The HUD therefore receives complete values even without stored settings. For example, if you want an area to be visible by default, you can define hideRosters with the caption “Hide player lists” and hide it only for true. Thus, the panel and output match even after storing other fields. Check initialization with the ready-installed package, not just an empty test message.
Player selection refers to the local library. A special schema attribute for “currently living players only” or “current live players only” is not part of the contract. References and texts are limited to a maximum of 4.096 characters; the actual identity must nevertheless come from the offered administrative data.
Images and media
The panel editor imports PNG and JPEG images up to 4 MiB per file into the shared media storage. The state contains the local path, not the full image bytes. Use hud.media(path) or hud.Media(path) in the native SDK to resolve this path against the host. The images are loaded with the HUD browser session.
Removing an image reference from the panel does not automatically delete a media file that may be used elsewhere. A file directly from the package, on the other hand, is a static asset and loads relative to the package base. Do not confuse these two types of images.
The media stock can also contain files from other management areas; the possibilities of an editor there are not an extension of the panel file dialog. For the LHM output, the host translates the required image values and additionally offers the corresponding legacy image routes.
Panel transport
Native HUDs subscribe to SignalR under /hud-live/panels and call the stream method Watch(hudId, version). The SDK client takes over the arguments from the loaded packet address. The local browsing session, loopback and origin checking apply as with the livestream. Browsers can neither store values nor trigger actions here.
| Message/field | Type | Meaning |
|---|---|---|
hudId | String | HUD message identifier. |
version | String | Packet version of the message. |
state | HudPanelState or null | Complete repeatable setup. |
action | HudPanelAction or null | One-time order for now related outputs. |
state.revision | 64-bit integer | Revision of the stored status; 0 stands for still unstored standards. |
state.values | Object by section and field | Typed JSON values of the defined setting fields. No action values. |
state.references | Object by section and field | Separately resolved player/team/match references. |
action.id | UUID string | Unique identifier of this release. |
action.section, action.name | Strings | Section and field identifier of the action field. |
action.value | String or null | Selected declared action value; without selection values null. |
Example of a state
{
"hudId": "mein-cast-hud",
"version": "1.2.0",
"state": {
"revision": 3,
"values": {
"display": {
"caption": "Finale",
"show_caption": true,
"scale": "2em",
"featured_player": "",
"featured_team": "team-a",
"featured_match": "",
"logo": "",
"sponsors": []
}
},
"references": {
"display": {
"featured_team": {
"id": "team-a",
"name": "Team A",
"image": null,
"teamId": null,
"missing": false
}
}
}
},
"action": null
}
For a player reference, teamId can contain their managed team; for Team and Match, this field remains null. image is the existing avatar or logo image, otherwise null. If the referenced object is later removed, its id remains and missing becomes true; name and image may then be missing. Do not invent a substitute data set.
Library changes can trigger updated references without a new GSI message and without a new memory revision of the panel values. Therefore, do not discard messages with the same state.revision: The resolved names or pictures may have changed.
Example of an action
{
"hudId": "mein-cast-hud",
"version": "1.2.0",
"state": null,
"action": {
"id": "00000000-0000-4000-8000-000000000001",
"section": "display",
"name": "cue",
"value": "show"
}
}
This UUID is exclusively an example. Each actual trigger shall be given a new identifier. Check the section, name and value before your HUD responds. Do not reconstruct the “Hide” action from a saved state and do not repeat it yourself after Reconnect.
Saving, Conflicts and Reconnection
Changes in the panel editor are only transferred to the HUD with Save and apply. The action checks and saves all sections together, increases the revision and distributes the new state to the associated outputs of the same package version. In the case of intermediate changes, the older status is not stored over the newer one. A tab change is not storage.
Action buttons work immediately and independently of unstored form values. If an action is to use the just changed settings, they must be saved first. An action without connected recipients is not earmarked for later. A shipping confirmation is not a feedback from the HUD that the visible animation is complete.
Each new subscription gets the full current state and then new messages. Previous actions are not delivered. Process messages quickly: For more than 64 waiting messages, the subscription will be terminated. The SDK client then reconnects and receives the current state. There is no Exactly-once guarantee for actions; treat each action ID at most once and count on a broken connection with missed actions.
All browser, OBS and overlay outputs of the same HUD ID and package version share the panel stand. A targeted selection of a single issuer is not part of the contract. Other HUD IDs and other versions do not receive the message; this is a professional assignment within the same local origin, not a sandbox.
Panel values for HUD updates
- If a stored configuration already exists for the new package version, it is retained, even if it deliberately contains empty values.
- Otherwise, sOU searches for the numerically latest older installed version of the same ID with stored values on the first panel access.
- Only fields with identical section identifier, field identifier and identical type are accepted.
- Each value is checked against the new scheme. No longer allowed selection values, removed images or changed types fall back to the valid standard for this field.
- The transferred target status is stored with revision 1 and is then independent of the older version. Actions are neither adopted nor triggered.
New fields start with empty strings, false or empty image list. Distant fields only disappear in the new state. No renamings are advised, no values are transferred from other HUD IDs and no newer configuration is copied back to a downgrade. The source must still be installed because its scheme is needed for type comparison. Corrupted source configurations are an error and are not overwritten unnoticed.
Checks for authors
- Evaluate or remove any visible field in the HUD from the definition.
- Empty default values and
revision: 0are explicitly treated. - Check reference resolution with missing objects and images.
- Save and test instant action separately, including unstored input.
- After browser reloading, get the same state without performing a past action again.
- Check update with unchanged and changed field types as well as current older output.
The specific client methods and examples can be found under JavaScript client and C# client.