UI hint vocabulary
Why you’d want this
Section titled “Why you’d want this”The platform auto-generates the Reward-config UI from your JSON Schema, but a bare schema produces bland inputs (a text box where a dropdown belongs). UI hints let you upgrade that generated UI (a picker, a colour swatch, a slider) without writing any UI code. Reach for them when you want the broadcaster’s config experience to feel designed, not generic.
JSON Schema is fine for validation but says nothing about presentation. mobrule
defines a small vocabulary of x-mobrule-* keys that steer the auto-generated
UI. The validator ignores the whole x-mobrule-* namespace, so hints never
affect whether a value is accepted, only how it is asked for.
Recognised hint keywords
Section titled “Recognised hint keywords”| Key | Type | Effect |
|---|---|---|
x-mobrule-viewer-override | boolean | Surface this property as a viewer-controlled input. |
x-mobrule-widget | string | Force a specific widget (see Available widgets below). |
x-mobrule-label | string | Display name shown instead of the prettified key. Set it when the schema key isn’t the friendly name you want broadcasters to see. |
x-mobrule-options | array | Choice list: [{ "value": …, "label": "…", "color": "…"? }, …]. |
x-mobrule-source | string | Name of a pack-shipped option dataset to source choices from, instead of inlining x-mobrule-options. |
x-mobrule-unit | string | Unit suffix rendered inside number, text, and slider widgets (e.g. "s"). |
x-mobrule-unit-scale | number | For a number widget, how many stored units make one displayed unit (e.g. 1000 keeps milliseconds on the wire but shows and edits seconds). minimum / maximum are shown in the displayed unit too. |
x-mobrule-toggle-label | string | First line of a toggle widget’s label. |
x-mobrule-toggle-sub | string | Second, smaller line under a toggle widget’s label. |
x-mobrule-visible-when | object | { "field": "...", "equals": … }: show this field only while another field equals a value. A hidden field is also excluded from required-validation. |
Standard JSON Schema keywords are honoured alongside the hints: description
renders as help text, minimum / maximum bound and clamp numeric widgets,
and maxLength gives text widgets a live character counter plus validation.
The UI must degrade gracefully when an unknown hint appears, so Pack authors are free to ship forward-compatible hints.
Available widgets
Section titled “Available widgets”x-mobrule-widget accepts one of the following values. Each demo below is
interactive and renders exactly as the platform UI does.
| Widget | Value type | Requires |
|---|---|---|
chips | any option value | x-mobrule-options |
segmented | any option value | x-mobrule-options |
dropdown | any option value | x-mobrule-options or x-mobrule-source |
combobox | any option value | x-mobrule-options or x-mobrule-source |
multiselect | array of values | x-mobrule-options |
checkbox | boolean | none |
toggle | boolean | none |
number | number / integer | none |
stepper | number / integer | none |
slider | number / integer | minimum and maximum |
text | string | none |
One pill button per option; single-select, click again to deselect. An option
color shows as a swatch on the chip.
pack.toml
[events.example.params_schema.properties.mood]type = "string""x-mobrule-widget" = "chips""x-mobrule-options" = [ { value = "chaos", label = "Chaos", color = "#e8748a" }, { value = "calm", label = "Calm", color = "#74d2e0" }, { value = "gold", label = "Gold", color = "#e8b76a" }, { value = "plain", label = "Plain" },]segmented
Section titled “segmented”A joined segmented-button row; single-select, click again to deselect. Best for short ordered scales.
pack.toml
[events.example.params_schema.properties.intensity]type = "string""x-mobrule-widget" = "segmented""x-mobrule-options" = [ { value = "low", label = "Low" }, { value = "medium", label = "Medium" }, { value = "high", label = "High" },]dropdown
Section titled “dropdown”A picker popover; click the field to open, pick one option.
pack.toml
[events.example.params_schema.properties.monster]type = "string""x-mobrule-widget" = "dropdown""x-mobrule-options" = [ { value = "imp", label = "Imp" }, { value = "cacodemon", label = "Cacodemon" }, { value = "pinky", label = "Pinky" }, { value = "revenant", label = "Revenant" }, { value = "mancubus", label = "Mancubus" }, { value = "archvile", label = "Arch-vile" }, { value = "baron", label = "Baron of Hell" }, { value = "cyberdemon", label = "Cyberdemon" },]combobox
Section titled “combobox”The same picker, searchable: opens on focus and filters as you type. Use for long option lists. For a list long enough that you wouldn’t inline it, source it from an option dataset instead.
pack.toml
[events.example.params_schema.properties.monster]type = "string""x-mobrule-widget" = "combobox""x-mobrule-options" = [ { value = "imp", label = "Imp" }, { value = "cacodemon", label = "Cacodemon" }, { value = "pinky", label = "Pinky" }, { value = "revenant", label = "Revenant" }, { value = "mancubus", label = "Mancubus" }, { value = "archvile", label = "Arch-vile" }, { value = "baron", label = "Baron of Hell" }, { value = "cyberdemon", label = "Cyberdemon" },]multiselect
Section titled “multiselect”Chips that accumulate into an array; toggling every chip off yields unset.
pack.toml
[events.example.params_schema.properties.modifiers]"x-mobrule-widget" = "multiselect""x-mobrule-options" = [ { value = "chaos", label = "Chaos", color = "#e8748a" }, { value = "calm", label = "Calm", color = "#74d2e0" }, { value = "gold", label = "Gold", color = "#e8b76a" }, { value = "plain", label = "Plain" },]checkbox
Section titled “checkbox”A plain checkbox for booleans.
pack.toml
[events.example.params_schema.properties.announce]type = "boolean""x-mobrule-widget" = "checkbox"toggle
Section titled “toggle”A switch with a two-line label from x-mobrule-toggle-label /
x-mobrule-toggle-sub; without a label it reads “Enabled” / “Disabled”.
pack.toml
[events.example.params_schema.properties.friendly_fire]type = "boolean""x-mobrule-widget" = "toggle""x-mobrule-toggle-label" = "Friendly fire""x-mobrule-toggle-sub" = "Effects can hit the streamer's allies too."number
Section titled “number”A numeric input; clamped to minimum / maximum, with an optional
x-mobrule-unit suffix. Pair that suffix with x-mobrule-unit-scale to store
one unit while the broadcaster reads another: "x-mobrule-unit-scale" = 1000
with "x-mobrule-unit" = "s" keeps milliseconds on the wire but shows and edits
seconds.
pack.toml
[events.example.params_schema.properties.delay]type = "integer"minimum = 0maximum = 500"x-mobrule-widget" = "number""x-mobrule-unit" = "ms"stepper
Section titled “stepper”A −/+ stepper around a numeric input; steps by 1, clamps to
minimum / maximum, and disables the button at the bound.
pack.toml
[events.example.params_schema.properties.count]type = "integer"minimum = 1maximum = 10"x-mobrule-widget" = "stepper"slider
Section titled “slider”A range slider with a live readout (plus x-mobrule-unit) and min/max tick
labels. Requires both minimum and maximum.
pack.toml
[events.example.params_schema.properties.duration]type = "integer"minimum = 5maximum = 120"x-mobrule-widget" = "slider""x-mobrule-unit" = "s"A text input; maxLength adds a live counter, x-mobrule-unit a suffix.
This is also the fallback for unknown schemas.
pack.toml
[events.example.params_schema.properties.message]type = "string"maxLength = 40"x-mobrule-widget" = "text""x-mobrule-viewer-override" = trueDefaults when no widget is declared
Section titled “Defaults when no widget is declared”A property without x-mobrule-widget (or with an unrecognised value) is
inferred from its schema:
"type": "boolean"→checkbox- has
x-mobrule-options→chipsfor up to 6 options,dropdownbeyond - has
x-mobrule-source(and nox-mobrule-options) →combobox, since a sourced param typically backs a large dataset worth searching "type": "number"or"integer"→number- everything else (including nested /
$ref/anyOfschemas) →text
Example
Section titled “Example”A duration slider and a mode picker that reveals a dependent field:
{ "type": "object", "required": ["mode"], "properties": { "duration": { "type": "integer", "minimum": 5, "maximum": 120, "x-mobrule-widget": "slider", "x-mobrule-unit": "s" }, "mode": { "type": "string", "x-mobrule-widget": "segmented", "x-mobrule-options": [ { "value": "chaos", "label": "Chaos", "color": "#e0564b" }, { "value": "calm", "label": "Calm" } ] }, "chaos_level": { "type": "integer", "x-mobrule-widget": "stepper", "minimum": 1, "maximum": 10, "x-mobrule-visible-when": { "field": "mode", "equals": "chaos" } } }}See also
Section titled “See also”- Manifest reference: where hints live in the schema tree.
- Events: most viewer-facing hints attach to Event params.
- Option datasets: sourcing
x-mobrule-sourcechoices from a pack-shipped file.