UI ​
Add custom widgets to the menu. Tabs and sections are created implicitly: every widget call takes (tab, section, name, ...) as its first three arguments, and the engine creates the tab and section on first reference.
Every widget call returns a ref string. You don't get the value back directly. To read or write a widget's value, use ui.get(ref) and ui.set(ref, value) against the ref. State is persisted between sessions automatically.
Quick example ​
local on = ui.checkbox("My ESP", "Boxes", "Enabled", true)
local thickness = ui.slider_int("My ESP", "Boxes", "Thickness", 1, 5, 2)
local color = ui.color_picker("My ESP", "Boxes", "Color")
ui.button("My ESP", "Boxes", "Reset", function()
print("reset clicked")
end)
function on_tick()
if not ui.get(on) then return end
for _, p in ipairs(get_players()) do
if p:is_enemy() and p:is_alive() then
local b = p:screen_box()
if b then
draw.rect(b.x, b.y, b.x + b.w, b.y + b.h,
ui.get(color), ui.get(thickness))
end
end
end
endThe first three arguments ("My ESP", "Boxes", the widget name) determine where the widget appears in the menu. Reuse the same tab+section across calls to group widgets together.
Custom tab labels ​
By default, the tab name you pass to widget calls doubles as both the internal ID (used to group widgets) and the display label shown in the menu's tab bar. If you want them to differ, typically so the on-screen label can have spaces or fancy characters while the ID stays clean for code, declare the tab explicitly with ui.new_tab:
ui.new_tab("toast_demo", "Toast Demo")
ui.button("toast_demo", "styles", "Default", function()
toast("Hi", 2)
end)| Function | Returns | Description |
|---|---|---|
ui.new_tab(id, label) | - | Register a tab where the internal id (used by every widget call's first argument) differs from the display label shown in the menu. Calling this is optional, if you skip it, the first widget call referencing a tab implicitly creates one with id = label |
Widgets ​
| Function | Returns | Description |
|---|---|---|
ui.checkbox(tab, section, name, [default]) | ref | Toggle. default is a bool |
ui.slider_int(tab, section, name, min, max, [default]) | ref | Integer slider |
ui.slider_float(tab, section, name, min, max, [default]) | ref | Float slider |
ui.dropdown(tab, section, name, options, [default_index]) | ref | Dropdown. options is an array of strings; selection returned as 1-based index |
ui.multiselect(tab, section, name, options) | ref | Multi-select. Returns an array of selected indexes |
ui.color_picker(tab, section, name) | ref | Color picker. Stored as ABGR uint32 |
ui.input_text(tab, section, name, [default]) | ref | Text input |
ui.keybind(tab, section, name, [default_vk]) | ref | "Click to bind" keybind picker. Stored as VK code |
ui.font_picker(tab, section, name, [default_font]) | ref | Font picker with system font search. Stored as font name string. See Draw > Fonts |
ui.button(tab, section, name, callback) | ref | Button. callback runs when pressed |
ui.label(tab, section, text) | ref | Static wrapped text label. Useful for headings, instructions, or status readouts |
Each widget also has a ui.new_* alias (ui.new_checkbox, ui.new_slider_int, etc.) for consistency with older script styles. The aliases are identical to the unprefixed versions.
Reading and writing values ​
| Function | Returns | Description |
|---|---|---|
ui.get(ref) | varies | Current value of the widget. Type depends on the widget |
ui.set(ref, value) | - | Override the widget's current value |
ui.set_visibility(ref, bool) | - | Show or hide the widget |
local mode = ui.dropdown("Misc", "General", "Mode", {"Off", "Casual", "Tryhard"}, 1)
function on_tick()
if ui.get(mode) == 3 then
-- Tryhard mode
end
end
-- Set programmatically:
ui.set(mode, 2)Use ui.set_visibility for conditional UI without re-creating widgets:
local advanced = ui.checkbox("Misc", "General", "Advanced mode")
local detail = ui.slider_int("Misc", "General", "Detail level", 1, 10, 5)
function on_tick()
ui.set_visibility(detail, ui.get(advanced))
endReturn value types ​
| Widget | ui.get returns |
|---|---|
checkbox | boolean |
slider_int, keybind | integer |
slider_float | number |
dropdown | integer (1-based index) |
multiselect | table of integers |
color_picker | integer (ABGR uint32) |
input_text, font_picker | string |
button | nothing meaningful (use the callback) |
label | nothing meaningful (display-only) |
settings vs ui ​
For most scripts, declare config in the settings = { ... } table instead. It's simpler, auto-renders below your script in the menu, and uses the config.* namespace for reading/writing.
Use ui.* when you need:
- Custom tabs and sections (settings render only inline under the script)
- Buttons with callbacks
- Runtime-mutable visibility via
ui.set_visibility - Widgets created or destroyed during script execution
Both styles can coexist within the same script.