API Reference

MacroAI API Reference

Image Recognition

image_find(tmpl, region?, threshold?, match_mode?, transform_policy?) -> ImageMatchResult | nil
image_wait(tmpl, timeout?, region?, threshold?, interval?, match_mode?, transform_policy?) -> ImageMatchResult | nil
image_find_all(tmpl, region?, threshold?, match_mode?, transform_policy?) -> table | nil
image_wait_all(tmpl, timeout?, region?, threshold?, interval?, match_mode?, transform_policy?) -> table | nil

Parameters: - tmpl (string | table) — template image. Accepts: - Single template string: "button.png" or "button" (auto-resolved in resources/images/) - Relative path: "resources/images/icon.png" (resolved relative to project dir) - Absolute path: "D:/images/icon.png" (used as-is) - Multi-template Lua table {"a.png", "b.png"} — screenshots once, iterates all, returns best match - Variable/parameter/user config reference: var_get('name'), u|var_id - 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 (image_wait / image_wait_all only) - interval (number, optional) — poll interval in seconds, default 0.2 (image_wait / image_wait_all only) - match_mode (string, optional) — match mode: "grayscale" (default), "luminance", "oklab" - transform_policy (string, optional) — coordinate transform policy: "default" (follow project setting, default) - 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 (basename only, no path. 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 (single screenshot, iterate all, return best match):

local r = image_find({"btn_ok.png", "btn_cancel.png"})
if r and r.success then
    if r.template_name == "btn_ok.png" then
        log("OK button found")
    end
end

Multi-template mixed with user_config_list:

-- Node editor template list: icon.png, u|uc_avatar
-- Generated code builds a mixed list automatically:
local _tmpls = {}
table.insert(_tmpls, 'icon.png')
for _, _v in ipairs(user_config_list('uc_avatar')) do
    table.insert(_tmpls, _v)
end
local r = image_find(_tmpls)
if r and r.success then
    log("Matched: " .. r.template_name)
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
key_stroke(vk, scan, is_down?) -> 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" - vk (number) — Virtual-Key Code - scan (number) — scan code - is_down (boolean, optional) — true = press, false = release, omit for press+release

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)
key_stroke(0x70, 0x3B)            -- press F1 (virtual key code 0x70)

Screen

screen_size() -> width, height

Example:

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

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_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:

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)
templates table[] required template configurations (see below)

templates 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 label = "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,
    templates = {
        {
            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.label .. " 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},
    templates = {
        { label="full", template_path="resources/bar_templates/full.png" },
        { label="half", template_path="resources/bar_templates/half.png" },
    }
})

Color Detection

color_get_pixel(x, y) -> table
color_get_dominant(region?, kwargs?) -> table
color_find(kwargs?) -> table
color_is(detected, target, threshold?) -> boolean
color_distance(c1, c2) -> number

Parameters: - x, y (number) — screen coordinates - region (table, optional) — detection area {left, top, width, height}, defaults to full screen - kwargs (table, optional) — parameters dictionary: - region — search area - color — target color {r, g, b} (used by color_find) - detected (table) — detected color {r, g, b} - target (table) — target color {r, g, b} - threshold (number, optional) — color distance threshold, default 30 - c1, c2 (table) — two color values {r, g, b}

color_get_pixel returns: {r, g, b} with values 0~255

color_get_dominant returns: {r, g, b} dominant color

color_find returns: {x, y} if found, nil otherwise

color_is returns: true / false

color_distance returns: distance value (lower = closer)

Example:

local pixel = color_get_pixel(500, 300)
log("Pixel color: " .. pixel.r .. "," .. pixel.g .. "," .. pixel.b)

local dominant = color_get_dominant({100, 100, 200, 200})
log("Dominant: " .. dominant.r .. "," .. dominant.g .. "," .. dominant.b)

local found = color_find({region={0, 0, 1920, 1080}, color={255, 0, 0}})
if found then
    log("Found red at: " .. found.x .. "," .. found.y)
end

if color_is({255, 50, 50}, {255, 0, 0}, 60) then
    log("Color approximately matches")
end

local dist = color_distance({255, 0, 0}, {200, 0, 0})
log("Color distance: " .. dist)

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
trace_log(msg) -> void
print(...) -> void

Example:

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

Notifications

show_dialog(text, image?, btn_text?) -> void
show_toast(text, image?, duration?) -> void

Parameters: - text (string) — notification text - image (string, optional) — image file path to display - btn_text (string, optional) — dialog button text (default "OK") - duration (number, optional) — toast display duration in seconds, default 3

Notes: - show_dialog shows a modal dialog, pauses until user confirms - show_toast shows a system toast notification that auto-dismisses

Example:

show_dialog("Operation complete!")
show_toast("Task completed successfully", 5)
show_dialog("Please confirm", "C:\\image.png", "OK")

User Config Variables

user_config(var_id) -> string
user_config_list(var_id) -> table

Parameters: - var_id (string) — user config variable ID (auto-prefixed with uc_ when defined, referenced with u| prefix)

Notes: - user_config returns the user config variable value (text string or absolute image path) - user_config_list returns a list of absolute file paths for image-type user config variables (for multi-image expansion in templates) - Images are stored in resources/user_config/ directory; name_ids are automatically resolved to absolute paths by the engine - Single-image variables referenced as u|var_id in the node editor are expanded at code generation time

Example:

local nickname = user_config("uc_nickname")
log("Nickname: " .. nickname)

local images = user_config_list("uc_avatar")
for _, path in ipairs(images) do
    log("Image absolute path: " .. path)
end

-- Used directly in image_find (handled by generated code):
-- image_find({"fixed.png", user_config("uc_avatar")})

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