> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rebind.gg/llms.txt
> Use this file to discover all available pages before exploring further.

# rb.macro

> Play, stream and record timed lists of key, button, mouse and text actions.

A macro is a list of actions, each with a delay in milliseconds before it.
`rb.macro` plays that list on the output with its timing kept, records the
user's input into one, and turns a take into the text of a macro file. A script reaches for it
when a fixed sequence of keys, clicks and moves has to repeat with the same
timing every time.

This script plays a short combo on F6 and stops it on F7:

```luau theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
-- rebind: min_sdk=3.9.0 name=example version=1.0.0
local combo = {
  { action = "press", code = "Q", delay = 0 },
  { action = "press", code = "E", hold_ms = 80, delay = 120 },
  { action = "move", dx = 40, dy = 0, delay = 50 },
  { action = "press", code = "Mouse1", delay = 30 },
}

rb.bind("F6", function()
  rb.macro.play(combo, { mode = "replace" })
end)
rb.bind("F7", function()
  rb.macro.stop_all()
end)
```

| Signature | Effect |
| - | - |
| `rb.macro.play(macro: { MacroAction }, options: RbPlayOptions?) -> MacroHandle` | plays a macro on a background thread |
| `rb.macro.stop_all() -> ()` | stops every macro the script plays |
| `rb.macro.record(options: RecordOpts?) -> ()` | starts recording input |
| `rb.macro.finish() -> { MacroAction }` | stops recording and returns the take |
| `rb.macro.to_script(macro: { MacroAction }, name: string) -> string` | the take as a macro file |
| `rb.macro.stream(macro: { MacroAction }) -> ()` | plays on Rebind Link's clock |
| `rb.macro.abort() -> ()` | stops the script's streamed playback |

## Playback

`options.speed` divides every delay (default `1.0`; `2.0` is twice as fast).
`options.mode` is `"parallel"` (default), which plays alongside the script's other
macros, or `"replace"`, which stops them first. Timing is kept on an absolute
timeline, so a late step does not delay the steps after it. Keys and buttons a
macro still holds when it ends or stops are released. The
[MacroHandle](https://docs.rebind.gg/reference/sdk/handles.md) pauses, resumes, stops, reports progress, and waits.

In hardware mode, on Link firmware that plays macros, `rb.macro.play` plays on
the Link's clock when no other macro of the script is playing (always with
`"replace"`), and falls back to host playback otherwise. It also plays on the
host when the macro has `"type"` actions, media keys or controller buttons, or
a value outside the
[streaming ranges](https://docs.rebind.gg/reference/sdk/limits.md).

## Streaming

`rb.macro.stream` plays only on the Link. It replaces the script's earlier
streamed macro and raises instead of falling back to the host:

* `rb.macro.stream: the Link cannot play type actions; use rb.macro.play` (or
  `media keys`, or `controller buttons`)
* `rb.macro.stream: needs Rebind Link in hardware mode, on firmware that plays macros`
* `rb.macro.stream: the Link is playing another macro`
* `rb.macro.stream: a delay, hold, move or scroll is not a finite number within range`

`rb.macro.abort` raises `rb.macro.abort: no device connected` when the script
has no output.

## Recording

`rb.macro.record` takes `{ ignore_mouse = false, ignore_keyboard = false, precision = "normal" }`.
Calling it again restarts the script's own take. It raises
`Macro.Record: another recording is running` while the app's recorder or another
script records. `rb.macro.finish` appends a release for every key and button
still held at the end, releases them on the output, and returns the take; it
returns an empty table when the script is not recording.

## Macro files

`rb.macro.to_script` returns the format the app's recorder saves: a modeline with
`macro=true` and `permissions=none`, then `return` of the actions. A long take
also gets a larger `memory_limit_mb`. Run directly, a macro file adds **Play
hotkey**, **Playback speed** and **Mouse movement scale** to its Options tab,
then plays once and stops, or waits for its hotkey. `require("macros/<name>")`
returns its actions and runs nothing.

## Action format

| `action` | Fields | Effect |
| - | - | - |
| (omitted) | `x, y, delay` | relative mouse move by `x`, `y` |
| `"move"` | `dx, dy, delay` | relative mouse move |
| `"down"` | `code, delay` | press a key or button |
| `"up"` | `code, delay` | release it |
| `"press"` | `code, hold_ms, delay` | tap; `hold_ms` defaults to 50 |
| `"type"` | `text, char_delay, delay` | types `text`; host playback sends it in one call |
| `"scroll"` | `amount, delay` | vertical scroll; host playback clamps to -127 to 127 |
| `"sleep"` | `delay` | wait |

`delay` is milliseconds before the action, fractions allowed; a negative delay
counts as 0. Fractional moves carry their remainder to the next move. `hold_ms`
and `char_delay` are also read as `holdMs` and `charDelay`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.