API Reference

MacroAI API Reference

Image Recognition

image_find(tmpl, region?, threshold?) -> ImageMatchResult | nil
image_wait(tmpl, timeout?, region?, threshold?) -> ImageMatchResult | nil
image_find_all(tmpl, region?, threshold?) -> table | nil
image_wait_all(tmpl, timeout?, region?, threshold?) -> table | nil
image_save_template(img, path) -> void

Parameters: - tmpl (string) — template image filename (e.g. "button.png"), must be uploaded in Image Manager; also supports variable references (e.g. var_get('btn_name')) or function parameter names - region (table, optional) — search area {left, top, width, height}, defaults to full screen - threshold (number, optional) — match threshold 0~1, default 0.85, lower = more tolerant - timeout (number, optional) — timeout in seconds, default 10 - img — image data (numpy array)

Return Value (ImageMatchResult): - .success (boolean) — whether found - .x, .y (number) — top-left corner of match - .center_x, .center_y (number) — center of match - .width, .height (number) — match dimensions - .confidence (number) — confidence score - .rect (table) — {left, top, width, height} - .template_name (string) — the matched template filename (useful in multi-template search to identify which template matched)

Example:

local r = image_find("login_btn.png", {100, 200, 800, 600}, 0.8)
if r and r.success then
    mouse_click(r.center_x, r.center_y)
end

Returning all matches:

image_find_all(tmpl, region?, threshold?) -> table | nil
image_wait_all(tmpl, timeout?, region?, threshold?) -> table | nil
  • Returns a table (array) of all match results, or nil if no matches found
  • Each element has the same fields as ImageMatchResult
  • Useful when multiple instances of the same template exist on screen
  • image_wait_all polls until at least one match is found, then returns all matches

Example (find and click all matches):

local results = image_find_all("icon.png")
if results then
    for _, r in ipairs(results) do
        mouse_click(r.center_x, r.center_y)
        wait(500)  -- pause between clicks
    end
end

Multi-template example:

local r1 = image_find("btn_ok.png", nil, 0.85)
local r2 = image_find("btn_cancel.png", nil, 0.85)
local best = nil
local best_conf = 0
for _, r in ipairs({r1, r2}) do
    if r and r.success and r.confidence > best_conf then
        best = r
        best_conf = r.confidence
    end
end
if best then
    if best.template_name == "btn_ok.png" then
        -- OK button found
    else
        -- Cancel button found
    end
end

OCR

ocr_recognize(region?, lang?) -> string
ocr_compare(text, region?, threshold?, lang?) -> OcrCompareResult
ocr_find_text(text, region?, lang?) -> number, number
ocr_log(msg) -> void

Parameters: - region (table, optional) — recognition area {left, top, width, height}, defaults to full screen - lang (string, optional) — language code, e.g. "zh-CN", "en-US", defaults to system language - text (string) — text to match - threshold (number, optional) — similarity threshold, default 0.8 - msg (string) — log message

Return Value (OcrCompareResult): - .matched (boolean) — whether text matched - .found_text (string) — recognized text - .similarity (number) — similarity score - .confidence (number) — confidence score

ocr_find_text returns: - Success: center_x, center_y (number, number) - Failure: nil, nil

Example:

local text = ocr_recognize({100, 100, 500, 100}, "en-US")
ocr_log("Recognized: " .. text)

local r = ocr_compare("Submit", {100, 100, 500, 100})
if r and r.matched then
    log("Match found, similarity: " .. r.similarity)
end

local x, y = ocr_find_text("OK", {100, 100, 500, 100})
if x then mouse_click(x, y) end

Mouse

mouse_click(x?, y?, button?, clicks?) -> void
mouse_move(x?, y?) -> void
mouse_double_click(x?, y?) -> void
mouse_right_click(x?, y?) -> void
mouse_scroll(clicks, x?, y?) -> void
mouse_drag(sx, sy, ex, ey, button?, duration?) -> void

Parameters: - x, y (number, optional) — screen coordinates, uses current position if omitted - button (string, optional) — mouse button: "left" (default), "right", "middle" - clicks (number) — scroll wheel clicks, positive = up, negative = down - sx, sy (number) — drag start point - ex, ey (number) — drag end point - duration (number, optional) — drag duration (seconds), default 0.3

Example:

mouse_click(500, 300)                -- left click at (500,300)
mouse_click(500, 300, "right")       -- right click
mouse_double_click(500, 300)         -- double click
mouse_move(100, 200)                 -- move to (100,200)
mouse_drag(100, 100, 500, 300)       -- drag from (100,100) to (500,300)
mouse_scroll(3)                      -- scroll down 3 clicks

Keyboard

key_press(key) -> void
key_type(text) -> void
key_hotkey(key1, key2, ...) -> void
key_shortcut(combo) -> void

Parameters: - key (string) — key name, e.g. "enter", "tab", "escape", "a", "ctrl" - text (string) — text to type, newlines are converted to Enter - key1, key2, ... (string...) — sequential key combination, e.g. ("ctrl", "c") - combo (string) — shortcut notation, e.g. "ctrl+c", "alt+tab"

Example:

key_press("enter")                   -- press Enter
key_type("Hello, World!")            -- type text
key_hotkey("ctrl", "c")             -- Ctrl+C (sequential)
key_shortcut("ctrl+c")              -- Ctrl+C (chord)

Screen

screen_capture(region?) -> Image (numpy array)
screen_size() -> width, height

Parameters: - region (table, optional) — capture area {left, top, width, height}, defaults to full screen

Example:

local w, h = screen_size()
log("Screen resolution: " .. w .. "x" .. h)

local img = screen_capture({0, 0, 100, 100})  -- capture top-left 100x100
image_save_template(img, "screenshot.png")

Wait

wait(milliseconds) -> void
wait_seconds(seconds) -> void

Example:

wait(1000)         -- wait 1000 ms (1 second)
wait_seconds(2.5)  -- wait 2.5 seconds

Variables

var_set(name, value, scope?) -> void
var_get(name) -> any
var_has(name) -> boolean

Parameters: - name (string) — variable name - value (any) — variable value (string, number, boolean, table) - scope (string, optional) — variable scope: "local" (default, script-local), "global" (shared across scripts)

Example:

var_set("count", 10)
var_set("name", "MacroAI", "global")

local c = var_get("count")
log("count = " .. c)

if var_has("name") then
    log("name variable exists")
end

Regions

region_set(name, left, top, width, height) -> void
region_get(name) -> Region | nil
getRegion(name?) -> {left, top, width, height} | nil
to_runtime_region(region) -> {left, top, width, height}
to_runtime_point(x, y) -> number, number

Parameters: - name (string) — region name - left, top, width, height (number) — region rectangle (design-space coordinates) - region (table) — {left, top, width, height} format

Notes: - region_get returns a Region object with .left, .top, .width, .height properties - getRegion returns a Lua table; omit name or use "__effective__" for the default search area - to_runtime_region / to_runtime_point convert design-space coordinates to runtime (for multi-resolution support)

Example:

region_set("dialog", 100, 200, 500, 300)
local r = region_get("dialog")
if r then
    log("Region: " .. r.left .. "," .. r.top)
end

local rt = getRegion("dialog")            -- {left, top, width, height}
local eff = getRegion()                   -- default search area
local px, py = to_runtime_point(500, 300) -- convert to runtime coordinates

Change Detection

detect_change(kwargs?) -> table
wait_change(kwargs?) -> table
wait_bar_change(kwargs?) -> table

detect_change / wait_change Parameters

Parameter Type Default Description
region table full screen detection area {left, top, width, height}
block_size number 50 grid block size (pixels)
threshold number 30.0 change threshold (grayscale diff)
min_area number 900 minimum change area
timeout number 30 timeout in seconds (wait_change only)
interval number 1.0 poll interval in seconds (wait_change only)
track_frames number 10 tracking frames for cyclic filtering (wait_change only)
cyclic_ratio number 0.7 cyclic filter ratio (wait_change only)

wait_bar_change Parameters

Parameter Type Default Description
region table full screen detection area
timeout number 30 timeout in seconds
interval number 0.5 poll interval in seconds
min_change number 0.1 minimum change ratio
match_threshold number 0.85 template similarity threshold
orientation string "auto" bar orientation: "horizontal", "vertical", "auto"
reset boolean false reset all tracking (use when switching scenes)
colors table[] required template configurations (see below)

colors format:

{
    {
        label = "hp_full",             -- template name (also filename)
        template_path = "resources/bar_templates/hp_full.png",
        color_swatch = {255, 50, 50}   -- auto-computed, can omit
    },
    {
        label = "hp_half",
        template_path = "resources/bar_templates/hp_half.png",
        color_swatch = {50, 50, 255}
    }
}

Return Values: - detect_change / wait_change return an array of changed regions: lua { { center_x = 350, center_y = 250, rect = {340, 240, 20, 20} }, ... } - wait_bar_change returns an array of bar changes: lua { { rect = {100, 200, 300, 20}, -- bar bounding box center_x = 250, -- bar center X center_y = 210, -- bar center Y color = "hp_full", -- matched template label state = "changed", -- changed/resized/disappeared/appeared delta = 0.5, -- width ratio change (new label / old label) reference_value = 1.0, -- old label width ratio curr_value = 0.5, -- new label width ratio orientation = "horizontal" }, ... }

Example:

-- Detect bar value change (upload two templates with different widths)
local bar_changes = wait_bar_change({
    region = {100, 50, 300, 20},
    timeout = 15,
    colors = {
        {
            label = "full",
            template_path = "resources/bar_templates/full.png",
        },
        {
            label = "half",
            template_path = "resources/bar_templates/half.png",
        }
    }
})

-- Filter: only process real changes, ignore enter/leave
for _, bc in ipairs(bar_changes) do
    if bc.state == "changed" or bc.state == "resized" then
        log("bar changed: " .. bc.color .. " delta=" .. bc.delta)
    end
end
reset_bar_detector() -> void

Reset all bar tracking cache. Call before entering a new scene to prevent stale state from interfering.

Parameter Type Description
none - -

Example:

-- Reset tracking when entering a new scene
reset_bar_detector()

local bars = wait_bar_change({
    region = {100, 50, 300, 20},
    colors = {
        { label="full", template_path="resources/bar_templates/full.png" },
        { label="half", template_path="resources/bar_templates/half.png" },
    }
})


Audio

play_warning(sound_type, custom_file?) -> void
play_music(filepath) -> void
is_music_playing() -> boolean

Parameters: - sound_type (string) — sound type: - System sounds: "ding", "error", "warning", "question", "info" - Windows media: "startup", "shutdown", "chimes", "tada" - Musical notes: "do", "re", "mi", "fa", "sol", "la", "si" (PC speaker beeps) - Custom: "custom" - custom_file (string, optional) — custom WAV file path (when sound_type is "custom") - filepath (string) — music file path (supports MP3, WAV, etc.)

Example:

play_warning("ding")                         -- play ding sound
play_warning("custom", "C:\\alert.wav")      -- play custom WAV

play_music("C:\\bgm.mp3")                   -- play background music
if is_music_playing() then
    log("Music is playing")
end

Logging

log(message) -> void
ocr_log(msg) -> void
print(...) -> void

Example:

log("Script started")
ocr_log("OCR result: " .. text)
print("Values:", x, y, z)  -- output: Values: 100 200 300

Other

macro_call(macro_id) -> void

Notes: - macro_id (string) — recorded macro ID to replay - Replays all recorded events (mouse clicks, key presses, waits, etc.) - Coordinates are automatically scaled to fit the current run area

Example:

macro_call("macro_12345678")  -- replay a recorded macro

Check Stop

check_stop() -> void

Call during long loops or long-running operations to make the script responsive to pause and stop signals. If the user clicks pause or stop during execution, check_stop() will immediately interrupt the current operation.

The engine automatically injects this call in some long-running operations, but it's recommended to call it explicitly in custom loops.

Example:

for i = 1, 100 do
    check_stop()  -- allow the user to abort at any time
    -- perform operations...
    wait(500)
end

Common Conventions

Coordinate System

  • All coordinates are in pixels
  • Region format: {left, top, width, height}
  • Coordinates are automatically scaled between design area and run area (multi-resolution)

Return Value Convention

  • Success returns a valid value, failure returns nil
  • For ImageMatchResult, check if r and r.success to determine match status