marketplace/macro

Record and Loop

v0.1.0

@rebindfree

Record your keys and clicks once, then replay them on a loop with the same timing.

Gallery

Record and Loop preview

Readme

Record any sequence of keys and clicks, such as a farming route, a crafting cycle, or a rotation, and replay it on a loop with the timing you recorded.

  • Press F6 to start recording.
  • Press F6 again to stop recording and start the loop.
  • Press F6 a third time to stop.

The presses of F6 itself are left out of the loop, and the pause before your last F6 press is kept between laps.

Needs Rebind 3.5.0 or newer on Windows, macOS, or Linux. No extra permissions.

Settings

  • Record, loop, stop: default F6. Key changes apply while the package runs on Rebind 3.9 or newer; on older versions, restart the package.

Before you use it

Games set their own rules about replayed input. Check the rules where you play.

Limits

  • Mouse movement is replayed as recorded, so the loop only lines up if the game view and window start in the same place each lap.
  • A recording lives in memory and is lost when the package stops.
  • Notices appear in Rebind. To see them on the desktop, turn on Desktop notifications in Rebind's settings. Linux shows them only inside Rebind.
  • Live use remains unverified on Windows, macOS, and Linux.

Stop

Press F6 while looping, stop the package from the editor toolbar, or press Left Ctrl + Left Alt + K to stop all scripts. Stopping releases anything the loop was holding.

Reviews

No reviews yet. Be the first, from the app.

Source

Version 0.1.0 (current)

main.luau

-- Record and Loop: the key starts recording, then starts the loop, then
-- stops everything.

local cfg = UI.Schema({
  key = UI.Keybind("F6", { label = "Record, loop, stop" }),
})

local mode, loop = "idle", nil

-- The take also holds the presses of the record key itself. Drop them and
-- carry their delays forward so the rest of the timing stays exact; the
-- returned tail is the pause before the final key press.
local function withoutKey(take, key)
  local kept, carry = {}, 0
  for _, action in take do
    if action.code == key then
      carry += action.delay or 0
    else
      local copy = table.clone(action)
      copy.delay = (copy.delay or 0) + carry
      carry = 0
      table.insert(kept, copy)
    end
  end
  return kept, carry
end

Bind(cfg.key, function()
  if mode == "idle" then
    Macro.Record()
    mode = "recording"
    UI.Notify("Recording", "info")
  elseif mode == "recording" then
    local route, tail = withoutKey(Macro.Finish(), cfg.key)
    if #route == 0 then
      mode = "idle"
      UI.Notify("Nothing was recorded", "warning")
      return
    end
    loop = Run(function()
      while true do
        Macro.Play(route):Wait()
        Sleep(tail)
      end
    end)
    mode = "looping"
    UI.Notify("Looping", "success")
  else
    if loop then
      loop:Cancel()
      loop = nil
    end
    Macro.StopAll()
    mode = "idle"
    UI.Notify("Stopped", "info")
  end
end)

function OnStop()
  if loop then
    loop:Cancel()
  end
  if mode == "recording" then
    Macro.Finish()
  end
  Macro.StopAll()
end