Skip to content

UI ​

Add custom widgets to the menu. Every widget call takes (tab, section, name, ...) as its first three arguments. Tabs must be created explicitly with ui.new_tab() before any widget call targets them - if the tab does not exist, the engine calls luaL_error with a "tab does not exist" message. Sections auto-create within an already-existing tab on first widget 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 ​

lua
ui.new_tab("My ESP", "My ESP")

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.w, b.h,
                          ui.get(color), ui.get(thickness))
            end
        end
    end
end

The 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 ​

ui.new_tab(id, display) takes a separate group id and display label. The id (the first argument to every widget call) groups widgets and stays fixed in code; the display label is what shows in the menu's tab bar and can have spaces or special characters. Pass a distinct display label when you want the two to differ:

lua
ui.new_tab("toast_demo", "Toast Demo")

ui.button("toast_demo", "styles", "Default", function()
    toast("Hi", 2)
end)
FunctionReturnsDescription
ui.new_tab(id, label)-Register a tab. The internal id (used by every widget call's first argument) can differ from the display label shown in the menu. Must be called before any widget call that targets this tab. If you use the same string for both id and label, calling ui.new_tab(id, id) is still required

Widgets ​

FunctionReturnsDescription
ui.checkbox(tab, section, name, [default], [in_line])refToggle. default is a bool; in_line places the widget inline with the previous one
ui.slider_int(tab, section, name, min, max, [default])refInteger slider
ui.slider_float(tab, section, name, min, max, [default])refFloat slider
ui.dropdown(tab, section, name, options, [default_index])refDropdown. options is an array of strings; selection returned as 1-based index
ui.multiselect(tab, section, name, options)refMulti-select. ui.get returns a boolean array indexed by option position (1-based)
ui.color_picker(tab, section, name, [default], [in_line])refColor picker. default is an optional {r,g,b,a} Color table; ui.get returns a Color table {r,g,b,a} (0-255)
ui.input_text(tab, section, name, [default])refText input
ui.keybind(tab, section, name, [default_vk])ref"Click to bind" keybind picker. Stored as VK code. default_vk defaults to 0x06 (VK_XBUTTON2) when omitted
ui.font_picker(tab, section, name, [default_font])refFont picker with system font search. Stored as font name string. See Draw > Fonts
ui.button(tab, section, name, callback)refButton. callback runs when pressed
ui.label(tab, section, text)refStatic wrapped text label. No interactive value

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 ​

FunctionReturnsDescription
ui.get(ref)variesCurrent value of the widget. Also accepts (tab, sec, name) directly instead of a ref string. Type depends on the widget
ui.get_value(ref)variesAlias for ui.get
ui.set(ref, value)-Override the widget's current value. Also accepts (tab, sec, name, val) directly
ui.set_value(ref, value)-Alias for ui.set
ui.set_visibility(ref, bool)-Show or hide the widget. Also accepts (tab, sec, name, visible) directly
lua
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:

lua
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))
end

Sections ​

ui.new_section creates a named card (section) inside a tab, giving you control over layout options that are not available when sections are created implicitly by widget calls.

FunctionReturnsDescription
ui.new_section(tab, ref, display, [opts])-Create a section card. opts is an optional table: {autosize, next, halfsize, visible}. If tab does not exist, silently does nothing (returns without creating anything)
ui.new_container(tab, ref, display, [opts])-Alias for ui.new_section
lua
local sec = ui.new_section("My Tab", "main_sec", "Options", { halfsize = true })
local on  = ui.checkbox("My Tab", "main_sec", "Enable")

Tooltips ​

FunctionReturnsDescription
ui.set_tooltip(ref, text)-Attach hover tooltip text to a widget. Also accepts (tab, sec, name, text) directly
ui.tooltip(ref, text)-Alias for ui.set_tooltip
lua
local spd = ui.slider_float("Aim", "General", "Speed", 0.1, 1.0, 0.5)
ui.set_tooltip(spd, "Lower = smoother. 1.0 = instant snap.")

Theme and menu state ​

FunctionReturnsDescription
ui.accent()Color {r,g,b,a}Current menu accent color (matches the theme). a is always 255
ui.accent_color()Color {r,g,b,a}Alias for ui.accent
ui.is_menu_open()booleanTrue while the overlay menu is open. Use this to gate panel dragging so panels cannot be moved during gameplay
ui.menu_open()booleanAlias for ui.is_menu_open

Draggable and resizable panels ​

Call these each tick (inside on_tick) to let users reposition and resize script-drawn panels while the menu is open.

FunctionReturnsDescription
ui.draggable(id, x, y, w, h)nx, ny, draggingDrag a panel. id must be unique per panel. Returns the (possibly updated) top-left position and a dragging flag. Persist nx, ny yourself (e.g. via ui.set on release)
ui.resizable(id, x, y, w, h, value, [min], [max])new_value, resizing, factorProportional resize grip (bottom-right corner). value is the size parameter to scale; factor is the raw drag ratio, apply it to other size params for uniform scaling. Call before ui.draggable on the same panel so the grip grab takes priority. Inert while the menu is closed
lua
local px = ui.slider_int("Radar", "Panel", "X", 0, 3840, 100)
local py = ui.slider_int("Radar", "Panel", "Y", 0, 2160, 100)
local ps = ui.slider_int("Radar", "Panel", "Size", 50, 800, 300)

function on_render()
    if not ui.is_menu_open() then return end
    local x, y, s = ui.get(px), ui.get(py), ui.get(ps)

    -- resize grip first so it wins over the body drag
    local ns, resizing = ui.resizable("radar_panel", x, y, s, s, s, 50, 800)
    if resizing then ui.set(ps, ns) end

    local nx, ny, dragging = ui.draggable("radar_panel", x, y, s, s)
    if dragging then ui.set(px, nx); ui.set(py, ny) end
end

Return value types ​

Widgetui.get returns
checkboxboolean
slider_int, keybindinteger
slider_floatnumber
dropdowninteger (1-based index)
multiselecttable of booleans (indexed by option position; true = selected)
color_pickerColor table {r, g, b, a} (0-255 per channel)
input_text, font_pickerstring
buttonnothing meaningful (use the callback)
labelnothing 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, button callbacks, or runtime-mutable visibility via ui.set_visibility.

Not affiliated with Valve Corporation.