ui module gives your script its own settings window inside the menu. You
declare controls once; the menu builds real widgets from that declaration and
keeps them alive. There is no render callback — the menu draws on the render
thread, your script runs on its own, and the two only exchange declarations and
events.
Values live in the same store the rest of the cheat uses, so a script’s controls
save into configs, come back when one is applied, and carry hotkeys exactly like
native controls do. You write none of that.
Overview
Pages and groups
Tabs down the left, panels in up to two columns.
Controls
Switches, sliders, combos, colours, inputs, buttons.
Reactivity
Assign a function to
visible, disabled, or label and forget about it.Persistence
How values are keyed, saved, and restored.
Quick start
The window
Your script gets one window, laid out like the menu itself:- a header with the script’s name and a close button
- a rail of icon-only tabs down the left, one per page — it scrolls when a script declares more tabs than fit
- up to two columns of panels, 240px each
Pages and groups
ui.page
string
required
Names the tab and derives the page’s id.
string
Tabler icon name, as used by the native tabs:
"target", "eye", "code",
"keyboard". Defaults to "adjustments".string
Pins the path values save under. See Persistence.
number
Position among your other tabs. Lower comes first.
container.group
boolean
Puts a switch in the panel header. The group then behaves as a control too:
group.value, group.label, group.on("change").boolean
Starting state of the header switch. Only with
toggle.boolean
Gives the header a hotkey chip. Only with
toggle."left" | "right"
Forces the column. Left alone, groups are split down the middle in declaration
order — so one group stays one column and the window stays narrow.
container.row
Controls can also be declared straight on a page. They land in the column with no
panel around them — useful for a caption or a single button above the panels.
Controls
Every factory below exists on pages, groups, and rows alike.Slider options
number
required
number
required
number
Values snap to this.
0 (default) means no snapping.number
Decimals shown.
0 (default) makes it an integer slider, which also decides how
the value is stored.string
Appended to the printed value:
"°", " ms".Combo and multi
The value is the item, not its index. Replacing the list keeps the selection by value: an item that survived stays picked wherever it moved to, one that is gone falls back to the first entry — delivered as a normalchange.
Control handle
Buttons
style is "normal", "accent", "danger", or "dashed".
Reactivity
Assign a function tovisible, disabled, or label and it re-runs whenever
anything it read changes. No diffing, no re-render — only the property you fed is
updated.
key.active is tracked too, so a bind’s state can drive a label or a visibility
rule: label = () => (ctl.key.active ? "ON" : "OFF").Hotkeys
Passkey to any control to give it a bind chip.
Persistence
Every control’s value is stored under a path built from where it sits:"Double tap" becomes
double_tap). Renaming a label is free. Renaming a group or page moves
every id below it, and changing an explicit id orphans what configs already hold
— so pass id for anything you expect to rename.
Values under a path nothing claims are kept, not dropped: unloading a script
and saving a config does not strip its settings, and declaring the old path again
recovers them.
text() is never saved, whatever persist says — a caption belongs to the script,
not to a config.
Window and config events
change, and finally config fires once.
That ordering is the point: a change handler reading a neighbouring control sees
the config’s world, and logic that must run once per config goes in config.
Lifecycle
Callbacks are delivered on the script thread, in order. Nothing here is ever called
from the render thread, so a handler can do real work without stuttering the menu.
Not supported yet
Tooltips
Tooltips
Controls carry no hover text. Use
text() for a line of explanation instead.Changing a slider's range after creation
Changing a slider's range after creation
min, max, step, precision, and unit are fixed when the control is
created. Only label, visible, disabled, items, and the value can change.Binding a key from code
Binding a key from code
key.mode is yours, key.key is the user’s.