Getting Started

1. Create a file and declare a module

Create my-module.lua in <config>/aesthetic/scripts/ — the game can be running:

local module = ui.category("scripts"):module("code", "My Module")
  • ui.category(name) — GUI category: "combat", "movement", "visuals", "player", "misc" or "scripts".
  • :module(icon, title[, description]) — icon name (e.g. "code", "bolt", "eye" — the editor autocompletes the full set) and the module title. The title must be unique across all modules.

2. Add settings

local delay = module:number("Delay", 20, 1, 100, 1, "t")
local text  = module:string("Text", "hello")
local on    = module:boolean("Enabled part", true)

Settings are read with :get() and show up in the module's GUI automatically. All types are listed in Modules & Settings.

3. Subscribe to events

local ticks = 0

module:callback("enable", function()
    ticks = 0
end)

module:event("tick", function()
    ticks = ticks + 1
    if on:get() and ticks % delay:get() == 0 then
        client.print_chat(text:get())
    end
end)

callback handles the lifecycle ("enable", "disable"), event handles game events (see Events). Event names ignore case and underscores: render_2d and render2d are the same.

4. Save and enable

Save the file — chat shows [lua] Loaded my-module.lua and the module appears in the GUI. Enable it and keep editing: every save reloads the script while keeping your setting values and the enabled state.

Editor support (autocomplete)

The mod generates language-server annotations for the whole API on every launch:

  • <config>/aesthetic/scripts/library/*.lua — LuaCATS stubs for all globals, events, settings and render canvases;
  • <config>/aesthetic/scripts/.luarc.json — configuration pointing lua-language-server at them.

Open the scripts folder in an editor with lua-language-server — the Lua extension in VS Code, the SumnekoLua plugin in IntelliJ, or lua_ls in Neovim — and you get completion, hovers, signature help and type checking out of the box, including event names with typed callback arguments (module:event("render_2d", function(render) ...), packet names and the full icon-name set.

The library/ folder is regenerated on every launch to match the installed mod version — don't edit it. .luarc.json is only written when missing, so your own tweaks survive.

Debugging

  • print("a", value) and client.print_chat(text) — output to chat ([lua] prefix);
  • aesthetic.log(msg) — output to the game log;
  • callback errors print to chat and disable the module — fix and re-enable.

Shared libraries

require resolves files relative to the scripts folder. Only top-level .lua files auto-load as scripts, so keep shared code in a subfolder:

local util = require "lib/util"   -- <scripts>/lib/util.lua