Config and script UI
| API | Description |
|---|---|
aqua.config.get(key) |
bool / int / float / {r,g,b,a} / string (auto-creates) |
aqua.config.set(key, value) |
true if accepted; false for incompatible types or failure to create an editable profile |
aqua.config.list([prefix]) |
{ {key=, value=, displayName?}, ... } |
aqua.config.save() |
SaveIfDirty |
aqua.config.override(key, value [, priority=75]) |
Set this script’s temporary layer for a registered key; returns false for unknown keys or incompatible values |
aqua.config.clear_override([key]) |
Release this script’s layer for one key, or all its layers when omitted |
Prefer keys under Scripts.<yourName>.*.
default is a clean-slate profile. The first actual setting change automatically creates and selects an editable new config profile (numbered when that name is taken). New keys written through aqua.config.set use their type’s zero/empty value as the default; register a UI control first when a different default is needed. Reading or registering a key without changing its value does not create a profile. Registering a control can replace the implicit zero default created by an earlier read; saved values and actual edits are preserved.
Moving the menu (Window.X/Y) while default is selected only changes its position for the current session; it does not create a profile or save changes into default. Menu position continues to save normally in editable profiles.
Temporary overrides last until released, or until the script stops, errors or unloads.
Higher priority wins (integer 0..200); the latest update wins ties. Releasing a winning
layer reveals the next script layer or the latest user value. get/list read effective
values, while set, user edits, save and profile duplication operate on saved values
underneath. Overrides survive profile switches while the owning script keeps running;
they never enter profile JSON or create a profile. Register a UI control first for a
script setting that needs an explicit default/type.
Config-override priorities are separate from aim/action priorities. The default is 75, but anti-aim’s 50 and ragebot’s 100 do not participate in config arbitration. Each key retains one layer per script. A lower-priority layer stays stored beneath the winner; updating a layer replaces that script’s value/priority and its tie order. Clearing the winner reveals the next layer, unlike command requests that already lost.
For example, script A overrides a key at 75 and script B at 100: B’s value is read. Clearing B reveals A’s value; clearing A reveals the current user/profile value.
Menu UI from scripts (aqua.ui)
Section titled “Menu UI from scripts (aqua.ui)”Register controls once while the script runs (typically at top-level). They are
cleared on Stop/Run and appear in the selected script’s OPTIONS view. Registration
copies descriptions to the menu; it does not draw immediately or invoke Lua from the
render thread. Repeated registration appends repeated rows, so use aqua.ui.clear()
when rebuilding the options.
aqua.ui.card(title, key?) starts a new titled card. Following controls belong to it
until the next card call; no closing call is needed. An optional bool config key
adds a feature switch to the header, defaults to true if newly declared, and dims
the card body when off. The script must check that key to disable its own behavior.
Saved preferences survive registration. Controls before the first explicit card go
in a card titled with the script’s display title. Cards flow through two columns
when there is room and one column in a narrow workspace.
label remains wrapped display text, and separator() remains a hairline inside
the current card. Neither starts a card. Existing scripts can adopt titled cards
without changing the config keys used by their controls.
Every control except label, value and separator stores its value in the config
key you pass, so it is saved per profile and readable with aqua.config.get(key).
value rows are the exception: their second argument is a row id, the text lives only
in the menu, and aqua.ui.set_value updates it. Use them for live readouts (hit counts,
the current target) - writing those through aqua.config.set would mark the profile
dirty and rewrite it every save.
Tooltips, subtitles and conditions are modifiers: call them right after the
control or card they belong to (see the second table). Controls with config keys
appear in menu search under <script title> > <card>, including their tooltips.
| API | Description |
|---|---|
aqua.ui.card(title [, key]) |
Start a titled card; optional bool key adds a header feature switch |
aqua.ui.checkbox(label, key [, default=false]) |
Toggle; registers config key |
aqua.ui.switch(label, key [, default=false]) |
Same bool key as checkbox, drawn as a label with a switch on the right |
aqua.ui.slider(label, key, default, min, max [, opts]) |
Slider. opts = { int = true, step = 5, format = "%d ms" }: int stores an int key, step snaps drag and typed values, format is a printf format with exactly one %d/%i (int) or %f/%e/%g (float) conversion; %% is a literal percent. A bad format raises an error |
aqua.ui.color(label, key [, {r,g,b,a} [, presets]]) |
Color swatch (config float[4]). presets = { {r,g,b,a}, ... } (max 8) adds one-click swatches; pass nil as the default to keep white |
aqua.ui.dropdown(label, key, items [, defaultIndex=0]) |
Combo; items = {"A","B",...}; config stores 0-based int |
aqua.ui.segmented(label, key, items [, defaultIndex=0]) |
Side-by-side choice buttons for 2-5 short items; same storage as dropdown |
aqua.ui.multiselect(label, key, items [, defaults]) |
Wrapping chips, any number selected (max 31 items). Config stores an int bitmask: item i (0-based) is on when bit.band(v, bit.lshift(1, i)) ~= 0. defaults is a bitmask or a table of 0-based indices |
aqua.ui.text(label, key [, default="" [, maxLength=64]]) |
Single-line text field (config string, max 256). Saved while typing |
aqua.ui.keybind(label, key [, defaultCode=UNBOUND]) |
Key capture button; config stores KeyState int (aqua.keys.*) |
aqua.ui.button(label, key [, icon="play"]) |
Momentary press. Sets the bool config key true; the script polls it and sets it back to false (no cross-thread Lua callback). icon is a name from aqua.ui.icons, or "none"; an unknown name raises an error |
aqua.ui.label(text) |
Display-only text row |
aqua.ui.value(label, id [, text]) |
Read-only label + value row for live stats. id is NOT a config key: nothing is saved |
aqua.ui.set_value(id, text) -> bool |
Update a value row (string or number). Cheap enough for every frame; false when no row has that id |
aqua.ui.separator() |
Thin horizontal rule |
aqua.ui.clear() |
Drop fields for this script (re-register after) |
aqua.ui.icons |
Array of the icon names button accepts |
Modifiers apply to the control or card declared just before them. They raise an
error when nothing was declared yet or the last call was separator().
| API | Description |
|---|---|
aqua.ui.tooltip(text [, meta]) |
Hover tooltip; meta is an optional small mono line ("default on"). On a card it sits on the title. Script tooltips also show in menu search |
aqua.ui.description(text) |
Grey subtitle: under the label for checkbox / switch, a caption under every other row, the first line of a card body |
aqua.ui.visible_if(key [, value]) |
Hide the row (or the whole card) unless config key equals value; without value, unless it is truthy (true, non-zero, non-empty). Hidden rows also leave menu search |
aqua.ui.enabled_if(key [, value]) |
Same test, but the row (or card) stays visible, greyed out and locked |
Conditions compare exactly: a float key equals a number only when it is that exact value, so condition on bools, dropdown indices or strings.
aqua.ui.card("Demo options", "Scripts.demo.Enabled")aqua.ui.slider("Scale", "Scripts.demo.Scale", 1.0, 0.25, 3.0)aqua.ui.color("Tint", "Scripts.demo.Tint", {0.3, 0.7, 1, 1})aqua.ui.switch("Outline", "Scripts.demo.Outline", true)aqua.ui.tooltip("Draws a dark edge so the text stays readable on bright maps.", "default on")aqua.ui.card("Controls")aqua.ui.dropdown("Mode", "Scripts.demo.Mode", { "Off", "Enemies", "All" }, 1)aqua.ui.tooltip("Which players the overlay follows.")aqua.ui.keybind("Toggle", "Scripts.demo.Key", aqua.keys.F6)aqua.ui.slider("Delay", "Scripts.demo.Delay", 100, 0, 500, { int = true, step = 10, format = "%d ms" })aqua.ui.enabled_if("Scripts.demo.Mode", 2)aqua.ui.button("Do the thing", "Scripts.demo.Go", "bolt")aqua.ui.value("Hits", "hits", "0")
aqua.ui.card("Filters")aqua.ui.multiselect("Show on", "Scripts.demo.Parts", { "Head", "Chest", "Legs" }, { 0 })aqua.ui.segmented("Size", "Scripts.demo.Size", { "S", "M", "L" }, 1)aqua.ui.text("Prefix", "Scripts.demo.Prefix", "[demo]", 16)aqua.ui.visible_if("Scripts.demo.Mode", 2) -- only while Mode = "All"aqua.ui.color("Accent", "Scripts.demo.Accent", nil, { {1, 0.3, 0.3, 1}, {0.3, 0.7, 1, 1} })
local hits = 0
local function selected(mask, index) -- 0-based, like dropdown indices return bit.band(mask, bit.lshift(1, index)) ~= 0end
function on_draw() if not aqua.config.get("Scripts.demo.Enabled") then return end local mode = aqua.config.get("Scripts.demo.Mode") or 0 if aqua.input.key_pressed(aqua.config.get("Scripts.demo.Key") or 0) then print("toggle key") end if aqua.config.get("Scripts.demo.Go") == true then aqua.config.set("Scripts.demo.Go", false) -- consume the press hits = hits + 1 aqua.ui.set_value("hits", hits) -- numbers are accepted too end local parts = aqua.config.get("Scripts.demo.Parts") or 0 if selected(parts, 0) then -- "Head" is ticked end -- ...end