Skip to content

Script Settings ​

You can add user-configurable options to your script in two ways:

  1. settings = { ... } declaration (recommended for most scripts): a table that is read when the script loads. It shows inline under your script in the menu, is saved automatically to a per-script JSON config, and is restored on the next launch.
  2. ui.* widget API (for advanced or dynamic UIs): you create widgets in code, with custom tabs, buttons with callbacks, and layouts you can change at runtime. See UI.

settings declaration ​

lua
name = "My Script"
id = hero_id.any

settings = {
    { key = "enabled", type = "bool",  default = true,  label = "Enabled" },
    { key = "speed",   type = "float", default = 1.0,   min = 0.1, max = 10.0, label = "Speed" },
    { key = "count",   type = "int",   default = 5,     min = 1,   max = 20,   label = "Count" },
    { key = "mode",    type = "combo", default = 0,     label = "Mode",
      options = { "Off", "Conservative", "Aggressive" } },
    { key = "hotkey",  type = "keybind",   default = 0, label = "Hotkey" },
    { key = "slot",    type = "item_slot", default = 0, label = "Item Slot" },
    { key = "font",    type = "font",      default = "", label = "Draw Font" },
    { key = "tint",    type = "color",     default = {r=255, g=80, b=80, a=255}, label = "Tint" },
}

Each entry is a table with these keys:

KeyRequiredDescription
keyyesKey the value is saved under. Must be unique within the script
typeyesOne of: bool, int, float, combo, keybind, item_slot, font, color
defaultyesDefault value when the user hasn't set one. For int, combo, keybind and item_slot it must be a whole number: 5 and 5.0 both work, 2.5 is an error (the script does not load and the console says why)
labelyesDisplay label in the menu
min, maxfor int/floatSlider bounds. Default 0 and 100
optionsfor comboArray of strings shown in the dropdown
depends_onoptionalKey of another setting that controls this one's visibility
depends_valueoptionalValue the controlling setting must have for this one to show
tooltipoptionalHelp text shown when you hover the setting in the menu. Example: { key = "speed", type = "float", default = 1.0, min = 0.1, max = 10.0, label = "Speed", tooltip = "Controls how fast the script reacts" }

Setting types ​

TypeBacking typeNotes
boolbooleanRenders as a checkbox
intintegerRenders as a slider; needs min and max
floatnumberSame as int but for fractional values
combointegerDropdown index (0-based); needs options array
keybindintegerVK code; renders as a "click to bind" picker
item_slotintegerItem slot 0-3; renders as a dropdown of Slot 1 to Slot 4. Pass it to item_slot_to_key, or add 4 to get slot.item1 to slot.item4
fontstringFont name; renders as a font picker with system font search
colorRGBA table{r, g, b, a} with components 0-255; renders as an inline swatch that opens a full RGBA picker on click. default must be a four-key table. A fraction is rounded and anything outside 0-255 is clamped

Conditional visibility ​

Hide a setting unless another one has a specific value:

lua
settings = {
    { key = "auto_dispel", type = "bool", default = false, label = "Auto Dispel" },
    { key = "dispel_threshold", type = "float", default = 2.0,
      min = 0.5, max = 5.0, label = "Threshold (seconds)",
      depends_on = "auto_dispel", depends_value = 1 },
}

For booleans, depends_value = 1 (or true) means the controlling setting must be on, and 0 (or false) means it must be off. For combo, it's the option index (0-based). The value must be a whole number or a boolean.

config namespace ​

Read and write your script's persisted setting values at runtime.

FunctionReturnsDescription
config.get_bool(key, default)booleanRead a bool setting
config.get_int(key, default)integerRead an int, combo, keybind, or item_slot
config.get_float(key, default)numberRead a float setting
config.get_string(key, default)stringRead a font (or any other string-typed) setting
config.get_color(key, default?)RGBA tableRead a color setting; returns {r, g, b, a} with components 0-255. Defaults to white ({r=255,g=255,b=255,a=255}) when the key is absent and no default is provided
config.set_bool(key, value)-Write a boolean. Saved to disk automatically (see below)
config.set_int(key, value)-Write an integer. Saved to disk automatically (see below)
config.set_float(key, value)-Write a float. Saved to disk automatically (see below)
config.set_string(key, value)-Write a string. Saved to disk automatically (see below)
config.set_color(key, {r,g,b,a})-Write a color. Saved to disk automatically (see below)

Each script's values are saved in its own JSON file. All setting types (bool, int, float, combo, keybind, item_slot, font, color) are saved. A change the user makes in the menu is written right away.

After a config.set_* call, config.get_* returns the new value immediately. The file is written at most once every 5 seconds, so you can set a value every tick. It is also written when the script is switched off, stops on an error, is reloaded, or TSUKI closes. The _of variants below work the same way.

Reading settings ​

lua
function on_tick()
    if not config.get_bool("enabled", true) then return end

    local speed = config.get_float("speed", 1.0)
    local mode  = config.get_int("mode", 0)
    local font  = config.get_string("font", "")
    -- ...
end

The default is returned when the key isn't in the config yet. Match it to the value in your settings declaration.

Read settings inside on_tick or a callback, not at the top level of the script. Every time a script loads, its top-level code runs before its saved config is loaded, so config.get_* there returns the default you pass, and a config.set_* there can be lost.

Writing settings ​

Use this when your script needs to change its own settings in response to events:

lua
function on_tick()
    if input.is_key_pressed(0x70) then  -- F1
        local was = config.get_bool("enabled", true)
        config.set_bool("enabled", not was)
        toast(not was and "ON" or "OFF")
    end
end

Each script has its own JSON file, so writing enabled in Script A doesn't touch Script B's enabled.

Cross-script config ​

Use the _of variants to read or write the saved settings of another loaded script. The first argument is the target script's display name: its script_info.name, else its top-level name, else its file name without .lua.

FunctionReturnsDescription
config.get_bool_of(script, key, default?)booleanRead a boolean from another script's config
config.set_bool_of(script, key, value)-Write a boolean to another script's config and persist it
config.get_int_of(script, key, default?)integerRead an integer from another script's config
config.set_int_of(script, key, value)-Write an integer to another script's config and persist it
config.get_float_of(script, key, default?)numberRead a float from another script's config
config.set_float_of(script, key, value)-Write a float to another script's config and persist it
config.get_string_of(script, key, default?)stringRead a string from another script's config
config.set_string_of(script, key, value)-Write a string to another script's config and persist it

There is no color_of variant.

  • If the target script is not loaded, get_*_of returns the default value (or the type's zero value when no default is given). It does not raise an error.
  • Writes only take effect when the target script is loaded. If it is not loaded, the write does nothing, so load the script first.
  • Passing your own script's name is the same as calling plain config.get_* / config.set_*.
lua
-- A "coordinator" script that reads another script's toggle
function on_tick()
    local hook_enabled = config.get_bool_of("Hook", "enabled", false)
    if hook_enabled then
        -- do something in response to the Hook script being active
    end
end
lua
-- Disable the Dagger script's aim from a keybind in this script
function on_tick()
    if input.is_key_pressed(0x70) then  -- F1
        local cur = config.get_bool_of("Dagger", "aim_enabled", true)
        config.set_bool_of("Dagger", "aim_enabled", not cur)
    end
end

Color picker ​

The color type shows a swatch in the menu. Click it to open an RGBA picker with an alpha slider and hex and RGB entry. The value is saved like every other setting.

The default value is a table with r, g, b and a fields, each 0-255. A missing field reads as 255, so a list such as {255, 0, 0, 255} gives white. Name the fields:

lua
settings = {
    { key = "alert_color", label = "Alert Color", type = "color",
      default = {r = 255, g = 0, b = 0, a = 255} },
}

Read the current value with config.get_color. Write a new one with config.set_color:

lua
local c = config.get_color("alert_color")
-- c.r, c.g, c.b, c.a, all 0-255

config.set_color("alert_color", {r = 0, g = 255, b = 0, a = 255})

You can pass the returned values straight to draw.color(c.r, c.g, c.b, c.a) from the Draw namespace. This complete script uses a color picker to draw 3D boxes around enemies:

lua
-- Color Picker Test
-- Draws 3D boxes on enemies using color picker
script_info = {
    name        = "Color Picker Test",
    description = "3D box ESP with color picker",
}

settings = {
    { key = "box_color", label = "Box Color", type = "color", default = {r=255, g=50, b=50, a=255} },
}

function on_tick()
    local c = config.get_color("box_color")
    local col = draw.color(c.r, c.g, c.b, c.a)
    for _, p in ipairs(get_players()) do
        if p:is_enemy() and p:is_alive() then
            local pos = p:get_position()
            local head = p:get_head_world()
            local height = head.z - pos.z + 14
            local width = 30
            draw.box3d(vec3(pos.x, pos.y, pos.z + height * 0.5), width, width, height, col, 1.5)
        end
    end
end

Changing the swatch in the menu updates the box color on the next tick.

Top-level globals ​

The globals TSUKI reads from the top level of a script:

GlobalTypeDescription
namestringDisplay name shown in the scripts list. It can also go inside script_info
idintegerWhich hero the script runs on. Use hero_id.any to run on any hero
settingstableSetting declarations as above
script_infotableName, description, flags and icon

Everything else, such as description, needs_all_particles and needs_internal, is only read from inside script_info. At the top level it is ignored. See Script Structure.

You can also define these callbacks: on_tick, is_enabled, on_kill, on_modifier_added, on_modifier_removed, on_ability_start, on_ability_channel, on_ability_cast, on_item_used, on_shot, on_particle_create, on_particle_destroy, on_sound_event, on_entity_added, on_entity_removed, on_disable and on_unload. See Events.