Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Examples

Complete, ready-to-use scripts organized by complexity. Copy any of these into a new script in the Rebind UI to get started.

Beginner

Logger

Logs all input events without modifying them. Great for understanding what key names Rebind uses and debugging your own scripts.

-- rebind: name=Input Logger

function OnDown(key)
    Log.Info("DOWN: " .. key)
    return true
end

function OnUp(key, duration)
    Log.Info("UP: " .. key .. " (held " .. duration .. "ms)")
    return true
end

function OnScroll(delta)
    Log.Info("SCROLL: " .. delta)
    return true
end

Key Remap

Simple global key remap. Block the original key, send a different one. Useful for Vim users or anyone who never uses CapsLock.

-- rebind: name=CapsLock to Escape

function OnDown(key)
    if key == "CapsLock" then
        HID.Down("Escape")
        return false
    end
    return true
end

function OnUp(key)
    if key == "CapsLock" then
        HID.Up("Escape")
        return false
    end
    return true
end

Scroll Zoom

Hold a modifier key and scroll to zoom. Works in browsers, editors, image viewers, and most desktop apps.

-- rebind: name=Scroll Zoom

local cfg = UI.Schema({
    modifier = UI.Keybind("RAlt", { label = "Modifier Key" }),
})

function OnScroll(delta)
    if Input.IsDown(cfg.modifier) then
        HID.Down("LCtrl")
        HID.Scroll(delta)
        HID.Up("LCtrl")
        return false
    end
    return true
end

Clipboard Paste

Paste multi-line text with a single hotkey. Demonstrates Clipboard.Set with combo syntax for reliable bulk text input.

-- rebind: name=Quick Paste
local cfg = UI.Schema({
    hotkey = UI.Keybind("F8", { label = "Paste Key" }),
    text = UI.Text("Hello World", { label = "Text to Paste", maxLength = 500 }),
})

Bind(cfg.hotkey, Async(function()
    Clipboard.Set(cfg.text)
    HID.Press("LCtrl+V")
end))

Media Keys

Remap Mouse4/Mouse5 to media controls. Only active on the desktop – passes through normally inside other apps.

-- rebind: name=Mouse Media Keys

local cfg = UI.Schema({
    enabled = UI.Toggle(true, { label = "Enable" }),
})

function OnDown(key)
    if not cfg.enabled then
        return true
    end

    if key == "Mouse4" then
        HID.Down("MediaPrev")
        return false
    end
    if key == "Mouse5" then
        HID.Down("MediaNext")
        return false
    end
    return true
end

function OnUp(key)
    if key == "Mouse4" then
        HID.Up("MediaPrev")
        return false
    end
    if key == "Mouse5" then
        HID.Up("MediaNext")
        return false
    end
    return true
end

Intermediate

Expander

Type abbreviations and have them expanded into full text. Triggered by a hotkey after typing the shortcut.

-- rebind: name=Text Expander
local cfg = UI.Schema({
    trigger = UI.Keybind("F8", { label = "Expand Key" }),
    email = UI.Text("user@example.com", { label = "Email Address", maxLength = 60 }),
    sig = UI.Text("Best regards,", { label = "Signature", maxLength = 100 }),
})

local snippets = {}

function OnStart()
    snippets = {
        ["@@"] = cfg.email,
        ["##"] = cfg.sig,
        ["/date"] = os.date("%Y-%m-%d"),
        ["/time"] = os.date("%H:%M"),
    }
end

local buffer = ""

function OnDown(key)
    if key == cfg.trigger then
        for abbr, expansion in pairs(snippets) do
            if buffer:sub(-#abbr) == abbr then
                -- erase the abbreviation
                Run(function()
                    for i = 1, #abbr do
                        HID.Press("Backspace")
                        Sleep(20)
                    end
                    HID.Type(expansion, 15)
                end)
                buffer = ""
                return false
            end
        end
        return false
    end

    -- track typed characters
    if #key == 1 then
        buffer = buffer .. key
        if #buffer > 20 then
            buffer = buffer:sub(-20)
        end
    elseif key == "Backspace" and #buffer > 0 then
        buffer = buffer:sub(1, -2)
    elseif key == "Space" or key == "Enter" then
        buffer = ""
    end

    return true
end

Audio Feedback

Play sound effects on key events. Useful for toggle confirmations, cooldown timers, or just making your macros feel responsive.

-- rebind: name=Audio Feedback

local cfg = UI.Schema({
    toggle = UI.Keybind("F8", { label = "Toggle Key" }),
    volume = UI.Slider(0.5, { min = 0, max = 1, label = "Volume" }),
})

local active = false

Bind(cfg.toggle, function()
    active = not active
    if active then
        Audio.Play("on.wav", { volume = cfg.volume })
    else
        Audio.Play("off.wav", { volume = cfg.volume })
    end
end)

function OnBlur()
    Audio.StopAll()
end

function OnStop()
    Audio.StopAll()
end

Chat Filter

Use Regex to detect patterns in window titles or process names. This example applies different behavior depending on which chat app is active.

-- rebind: name=Chat Filter

local chat_apps = [[discord|slack|teams|telegram]]

local cfg = UI.Schema({
    paste_key = UI.Keybind("F9", { label = "Quick Paste" }),
    message = UI.Text("", { label = "Message", maxLength = 200 }),
})

Bind(cfg.paste_key, Async(function()
    local win = System.Window()
    if not Regex.IsMatch(win.process, chat_apps) then
        return true
    end
    Clipboard.Set(cfg.message)
    HID.Press("LCtrl+V")
end))

Config-Driven Script

Load settings from a TOML file instead of hardcoding them. Users can edit the config file with any text editor without touching the script.

-- rebind: name=Config Demo

-- default config written on first run
local defaults = {
    sensitivity = 0.8,
    enabled = true,
    weapon = "ak47",
    keybinds = { toggle = "F8", reload = "F5" },
}

-- load or create config
local cfg
if File.Exists("settings.toml") then
    cfg = Config.ReadTOML("settings.toml")
else
    Config.WriteTOML("settings.toml", defaults)
    cfg = defaults
end

Log.Info("Loaded config: weapon=" .. cfg.weapon .. " sensitivity=" .. tostring(cfg.sensitivity))

Bind(cfg.keybinds.toggle, function()
    cfg.enabled = not cfg.enabled
    Config.WriteTOML("settings.toml", cfg)
    Log.Info("Enabled: " .. tostring(cfg.enabled))
end)

Photoshop

Custom brush size shortcuts that only activate when Photoshop is in the foreground. Completely inert otherwise – zero overhead.

-- rebind: name=Photoshop Shortcuts
-- rebind: process=Photoshop.exe

local cfg = UI.Schema({
    brush_step = UI.Slider(5, { min = 1, max = 20, label = "Brush Size Step" }),
})

function OnFocus()
    Log.Info("Photoshop detected -- shortcuts active")
end

function OnScroll(delta)
    -- alt+scroll to change brush size
    if Input.IsDown("LAlt") then
        local steps = cfg.brush_step
        Run(function()
            for i = 1, steps do
                if delta > 0 then
                    HID.Press("RightBrace")
                else
                    HID.Press("LeftBrace")
                end
                Sleep(10)
            end
        end)
        return false
    end
    return true
end

function OnDown(key)
    -- mouse4 = undo, mouse5 = redo
    if key == "Mouse4" then
        Run(function() HID.Press("LCtrl+Z") end)
        return false
    end
    if key == "Mouse5" then
        Run(function() HID.Press("LCtrl+LShift+Z") end)
        return false
    end
    return true
end

Browser Tabs

Navigate browser tabs with mouse side buttons. Works with Chrome, Firefox, Edge, and most Chromium-based browsers.

-- rebind: name=Browser Tab Nav
-- rebind: process=chrome.exe
-- rebind: process=firefox.exe
-- rebind: process=msedge.exe
-- rebind: process=brave.exe

function OnDown(key)
    -- mouse4 = previous tab, mouse5 = next tab
    if key == "Mouse4" then
        Run(function() HID.Press("LCtrl+PageUp") end)
        return false
    end
    if key == "Mouse5" then
        Run(function() HID.Press("LCtrl+PageDown") end)
        return false
    end

    -- middle-click scroll wheel = close tab
    if key == "Mouse3" and Input.IsDown("LAlt") then
        Run(function() HID.Press("LCtrl+W") end)
        return false
    end

    return true
end

Sticky Mod

Turn any key into a toggle instead of a hold. Tap Shift once and it stays “held” until you tap it again. Useful for accessibility or one-handed workflows.

-- rebind: name=Sticky Modifier
local cfg = UI.Schema({
    target = UI.Keybind("LShift", { label = "Modifier to Toggle" }),
})

local held = false

function OnDown(key)
    if key == cfg.target then
        held = not held
        if held then
            HID.Down(cfg.target)
            UI.Notify("Modifier locked", "info")
        else
            HID.Up(cfg.target)
            UI.Notify("Modifier released", "info")
        end
        return false
    end
    return true
end

function OnUp(key)
    if key == cfg.target then
        return false
    end
    return true
end

function OnBlur()
    if held then
        held = false
        HID.Up(cfg.target)
    end
end

Precision

Hold a key to temporarily slow down mouse movement for fine positioning. Great for image editing, CAD, or any precision work.

-- rebind: name=Precision Mouse
local cfg = UI.Schema({
    hold_key = UI.Keybind("Mouse3", { label = "Precision Key" }),
    slowdown = UI.Slider(25, { min = 5, max = 75, suffix = "%", label = "Speed" }),
})

function OnMove(dx, dy)
    if Input.IsDown(cfg.hold_key) then
        local factor = cfg.slowdown / 100
        HID.Move(dx * factor, dy * factor)
        return false
    end
    return true
end

Mouse Inversion

Invert mouse axes. Swallows the original input and sends the negated version. Remove one negation to invert only horizontal or vertical.

-- rebind: name=Mouse Invert
-- rebind: mouse_block=true

function OnMove(dx, dy)
    HID.Move(-dx, -dy)
    return false
end

Sequence

Demonstrates sequential actions with Run() and Sleep(), plus cancellation. A general pattern for multi-step automation.

-- rebind: name=Sequence Demo

local cfg = UI.Schema({
    start_key = UI.Keybind("F9", { label = "Start Sequence" }),
})

local task = nil

function OnDown(key)
    if key == cfg.start_key then
        task = Run(function()
            Log.Info("Starting sequence...")

            HID.Press("LCtrl+A") -- select all
            Sleep(200)

            HID.Press("LCtrl+C") -- copy
            Sleep(200)

            HID.Press("End") -- move to end
            Sleep(100)
            HID.Press("Enter")
            HID.Press("Enter")
            Sleep(100)

            HID.Press("LCtrl+V") -- paste

            Log.Info("Sequence complete!")
        end)
        return false
    end

    if key == "F10" and task and task:IsRunning() then
        task:Cancel()
        UI.Notify("Cancelled", "info")
        return false
    end

    return true
end

function OnStop()
    if task and task:IsRunning() then
        task:Cancel()
    end
end

Advanced

UI Widgets

Demonstrates all available UI widgets and layout options.

-- rebind: name=UI Showcase

local cfg = UI.Schema({
    enabled = UI.Toggle(true, { label = "Enable Feature" }),

    strength = UI.Slider(100, {
        min = 0,
        max = 200,
        suffix = "%",
        step = 5,
        tooltip = "Adjust the strength",
        group = "Settings",
    }),

    hotkey = UI.Keybind("F6", { label = "Toggle Key" }),

    mode = UI.Select("Normal", { "Normal", "Fast", "Precise", "Custom" }, {
        label = "Operating Mode",
    }),

    tag = UI.Text("", {
        label = "Username",
        placeholder = "Enter your name",
        maxLength = 20,
    }),

    sensitivity = UI.Slider(50, {
        min = 1,
        max = 100,
        suffix = "%",
        group = "Advanced",
        tab = "Controls",
    }),
})

function OnStart()
    Log.Info("Enabled: " .. tostring(cfg.enabled))
    Log.Info("Strength: " .. cfg.strength .. "%")
    Log.Info("Mode: " .. cfg.mode)
end

Workflow Hub

A single script that provides different shortcuts for different applications. Demonstrates the power of System.Window() for runtime routing without needing separate scripts for each app.

-- rebind: name=Workflow Hub
local cfg = UI.Schema({
    enabled = UI.Toggle(true, { label = "Enable" }),
})

local function isProcess(name)
    local win = System.Window()
    return win.process:lower():find(name:lower()) ~= nil
end

function OnDown(key)
    if not cfg.enabled then
        return true
    end

    -- mouse4/mouse5 do different things per app
    if key == "Mouse4" then
        if isProcess("Photoshop") then
            Run(function() HID.Press("LCtrl+Z") end)
        elseif isProcess("chrome") or isProcess("firefox") or isProcess("msedge") then
            Run(function() HID.Press("LCtrl+PageUp") end)
        elseif isProcess("explorer") then
            Run(function() HID.Press("LAlt+Left") end)
        else
            return true
        end
        return false
    end

    if key == "Mouse5" then
        if isProcess("Photoshop") then
            Run(function() HID.Press("LCtrl+LShift+Z") end)
        elseif isProcess("chrome") or isProcess("firefox") or isProcess("msedge") then
            Run(function() HID.Press("LCtrl+PageDown") end)
        elseif isProcess("explorer") then
            Run(function() HID.Press("LAlt+Right") end)
        else
            return true
        end
        return false
    end

    return true
end

Auto-Clicker

A simple auto-clicker that uses Timer.Every instead of a Run/Sleep loop. Demonstrates the timer API and toggle pattern.

-- rebind: name=Auto Clicker
local cfg = UI.Schema({
    cps = UI.Slider(5, { min = 1, max = 20, label = "Clicks Per Second" }),
    toggle_key = UI.Keybind("F7", { label = "Toggle Key" }),
})

local active = false
local clickTimer = nil

function OnDown(key)
    if key == cfg.toggle_key then
        active = not active

        if active then
            local interval = 1000 / cfg.cps
            clickTimer = Timer.Every(interval, function()
                Run(function() HID.Press("Mouse1", 20) end)
            end)
            UI.Notify("Auto-clicker ON", "info")
        else
            if clickTimer then
                clickTimer:Cancel()
                clickTimer = nil
            end
            UI.Notify("Auto-clicker OFF", "info")
        end

        return false
    end
    return true
end

function OnStop()
    if clickTimer then
        clickTimer:Cancel()
    end
end

function OnBlur()
    if active then
        active = false
        if clickTimer then
            clickTimer:Cancel()
            clickTimer = nil
        end
    end
end

Macros

Play pre-defined input sequences with configurable speed. Useful for automating repetitive tasks, form filling, or testing.

-- rebind: name=Macro Demo

local cfg = UI.Schema({
    speed = UI.Slider(100, { min = 25, max = 400, suffix = "%", label = "Speed" }),
    play_key = UI.Keybind("F9", { label = "Play" }),
    stop_key = UI.Keybind("F10", { label = "Stop All" }),
})

-- a keyboard combo macro (explicit format)
local formFill = {
    { action = "press", code = "Tab", holdMs = 30, delay = 100 },
    { action = "type", text = "John Doe", charDelay = 30, delay = 100 },
    { action = "press", code = "Tab", holdMs = 30, delay = 100 },
    { action = "type", text = "john@example.com", charDelay = 30, delay = 100 },
    { action = "press", code = "Tab", holdMs = 30, delay = 100 },
    { action = "press", code = "Tab", holdMs = 30, delay = 100 },
    { action = "press", code = "Enter", holdMs = 50, delay = 0 },
}

function OnDown(key)
    if key == cfg.play_key then
        local speed = cfg.speed / 100
        Macro.Play(formFill, speed, "replace")
        UI.Notify("Playing", "info")
        return false
    end

    if key == cfg.stop_key then
        Macro.StopAll()
        UI.Notify("Stopped", "info")
        return false
    end

    return true
end

function OnStop()
    Macro.StopAll()
end

Sidecar Pipe

Communicate with an external Python/Node.js process using shared memory. This lets you bridge Rebind scripts with computer vision, AI models, or any other external tool.

-- rebind: name=Pipe Demo

local pipe = nil

function OnStart()
    pipe = Pipe.Open("myapp", { size = 65536 })
    Log.Info("Pipe opened: " .. pipe.name)

    Timer.Every(10, function()
        local msg = pipe:Read()
        if msg then
            local data = JSON.Parse(msg)
            Log.Info("Received command: " .. (data.action or "unknown"))

            if data.action == "type" and data.text then
                Run(function() HID.Type(data.text, 30) end)
            elseif data.action == "press" and data.key then
                Run(function() HID.Press(data.key) end)
            end
        end
    end)
end

function OnStop()
    if pipe then
        pipe:Close()
    end
end

The external process connects to the same shared memory region. For example, in Python:

import mmap
import struct
import json

shm = mmap.mmap(-1, 65536, tagname="Local\\Rebind_myapp")

# write to channel B (script's inbox) at offset size/2
offset = 65536 // 2
data = json.dumps({"action": "type", "text": "Hello from Python!"}).encode()

shm.seek(offset)
shm.write(struct.pack('<Q', 1))           # sequence number
shm.write(struct.pack('<I', len(data)))   # payload length
shm.write(data)

Macro Recorder

Full macro recording workflow: record input to a file, play it back with configurable speed and smoothing.

-- rebind: name=Macro Recorder
local cfg = UI.Schema({
    record = UI.Keybind("F9", { label = "Record / Save" }),
    play = UI.Keybind("F10", { label = "Play" }),
    stop = UI.Keybind("Escape", { label = "Stop" }),
    name = UI.Text("macro", { maxLength = 50 }),
    smooth = UI.Toggle(false, { label = "Smooth Playback" }),
    speed = UI.Slider(100, { min = 25, max = 400, suffix = "%" }),
})

local isRecording = false
local activeMacro = nil

function OnStart()
    File.MkDir("macros")
end

function OnStop()
    if isRecording then
        Macro.Finish()
    end
    if activeMacro then
        activeMacro:Stop()
    end
end

function OnDown(key)
    if key == cfg.record then
        if isRecording then
            local macro = Macro.Finish()
            if cfg.smooth then
                macro = Math.Spline(macro, 0.5)
            end
            File.WriteJSON("macros/" .. cfg.name .. ".json", macro)
            UI.Notify("Saved", "success")
            Audio.Beep()
            isRecording = false
        else
            Macro.Record({ precision = "high" })
            UI.Notify("Recording...", "info")
            Audio.Beep()
            isRecording = true
        end
        return false
    end

    if key == cfg.play then
        local path = "macros/" .. cfg.name .. ".json"
        if File.Exists(path) then
            activeMacro = Macro.Play(File.ReadJSON(path), cfg.speed / 100)
            UI.Notify("Playing", "info")
        else
            UI.Notify("Not found", "error")
        end
        return false
    end

    if key == cfg.stop and activeMacro then
        activeMacro:Stop()
        activeMacro = nil
        UI.Notify("Stopped", "info")
        return false
    end

    return true
end

function OnBlur()
    if activeMacro then
        activeMacro:Stop()
        activeMacro = nil
    end
end

Color Trigger

Click when a target color is detected at the center of the screen. Demonstrates pixel color sampling and polling.

-- rebind: name=Color Trigger
local cfg = UI.Schema({
    enabled = UI.Toggle(true),
    color = UI.Text("FF0000", { maxLength = 6, label = "Target Color (hex)" }),
    tolerance = UI.Slider(20, { min = 0, max = 100 }),
    trigger = UI.Keybind("Mouse2", { label = "Hold to Scan" }),
})

local function hexToRgb(hex)
    return tonumber(hex:sub(1, 2), 16), tonumber(hex:sub(3, 4), 16), tonumber(hex:sub(5, 6), 16)
end

local function colorDistance(hex1, hex2)
    local r1, g1, b1 = hexToRgb(hex1)
    local r2, g2, b2 = hexToRgb(hex2)
    return math.sqrt((r2 - r1) ^ 2 + (g2 - g1) ^ 2 + (b2 - b1) ^ 2)
end

function OnTick()
    if not cfg.enabled then
        return
    end
    if not Input.IsDown(cfg.trigger) then
        return
    end

    local w, h = System.Screen()
    local pixel = Screen.GetPixelColor(math.floor(w / 2), math.floor(h / 2))

    if colorDistance(pixel, cfg.color) <= cfg.tolerance then
        Run(function() HID.Press("Mouse1", 20) end)
    end
end

HTTP Remote

Control Rebind from external tools via HTTP. Any program that can send HTTP requests (curl, Python, browser) can trigger actions.

-- rebind: name=HTTP Remote
-- rebind: permission=net
local cfg = UI.Schema({
    enabled = UI.Toggle(true),
    port = UI.Slider(8080, { min = 1024, max = 65535 }),
})

local server = nil

function OnStart()
    server = Net.Listen(cfg.port, function(req)
        if req.path == "/click" then
            Run(function() HID.Press("Mouse1") end)
            return { status = 200, body = "clicked" }
        elseif req.path == "/type" and req.body then
            Run(function() HID.Type(req.body) end)
            return { status = 200, body = "typed" }
        elseif req.path == "/move" then
            local data = JSON.Parse(req.body)
            HID.Move(data.dx or 0, data.dy or 0)
            return { status = 200, body = "moved" }
        end
        return { status = 404, body = "not found" }
    end)
    Log.Info("Remote control on port " .. cfg.port)
end

function OnStop()
    if server then
        server:Stop()
    end
end

WebSocket Remote

Same idea as HTTP Remote but over a persistent WebSocket connection. The server handles multiple simultaneous clients, broadcasts to all of them, and reacts to messages within a single tick. Use this when you need push events (server → client) or a stable low-latency channel for high-frequency commands.

-- rebind: name=WebSocket Remote
-- rebind: permission=net

local cfg = UI.Schema({
    port = UI.Slider(9000, { min = 1024, max = 65535, label = "WS port" }),
})

local server = nil

function OnStart()
    server = Net.WSListen(cfg.port, {
        OnConnect = function(client)
            Log.Info(string.format("client %d connected (%d total)", client.id, server:ClientCount()))
            client:Send("welcome " .. client.id)
        end,

        OnMessage = function(client, payload, is_binary)
            local req = JSON.Decode(payload)
            if req.t == "click" then
                Run(function() HID.Press("Mouse1") end)
                client:Send(JSON.Encode({ id = req.id, ok = true }))
            elseif req.t == "type" then
                Run(function() HID.Type(req.text or "") end)
                client:Send(JSON.Encode({ id = req.id, ok = true }))
            elseif req.t == "move" then
                HID.Move(req.dx or 0, req.dy or 0)
            elseif req.t == "broadcast" then
                -- forward a message to every connected client
                server:Broadcast(payload)
            end
        end,

        OnClose = function(client)
            Log.Info(string.format("client %d disconnected", client.id))
        end,
    })
    Log.Info("WebSocket remote listening on ws://0.0.0.0:" .. cfg.port)
end

function OnStop()
    if server then
        server:Stop()
    end
end

Connect from Python with websocket-client:

import json
from websocket import create_connection

ws = create_connection("ws://127.0.0.1:9000")
print(ws.recv())  # "welcome 1"
ws.send(json.dumps({"t": "type", "text": "hello from python"}))
ws.send(json.dumps({"t": "move", "dx": 50, "dy": 0}))

Net.WSListen can expose arbitrary JSON-RPC surfaces — reads (screen pixels, window state, clipboard, input state), writes (HID commands), and push subscriptions (mouse position, window changes, input events) all compose naturally with the same handler pattern shown above. See the WebSocket performance characteristics in the SDK reference for throughput and latency bounds.

Twitch Clip Creator

Create Twitch clips on demand with a hotkey. Demonstrates Net.Post for external API calls, Bind with Async for non-blocking execution, and File.Append for logging results.

-- rebind: min_sdk=0.1.0
-- rebind: name=Twitch Clip Creator
-- rebind: permission=net

local cfg = UI.Schema({
    trigger = UI.Keybind("F9", { label = "Clip Hotkey" }),
    client_id = UI.Text("", { label = "Twitch Client ID", placeholder = "Your Twitch API Client ID" }),
    oauth_token = UI.Text("", { label = "OAuth Token", placeholder = "Bearer your_oauth_token" }),
    broadcaster_id = UI.Text("", { label = "Broadcaster ID", placeholder = "Your Twitch numeric user ID" }),
    clip_cooldown = UI.Slider(5, { min = 1, max = 30, label = "Clip Cooldown", suffix = "sec" }),
})

local lastClipTime = 0

Bind(
    cfg.trigger,
    Async(function()
        local now = System.Time()
        local cooldownMs = cfg.clip_cooldown * 1000

        if now - lastClipTime < cooldownMs then
            UI.Notify("Clip on cooldown", "warning")
            return false
        end

        if not cfg.client_id or not cfg.oauth_token or not cfg.broadcaster_id then
            UI.Notify("Missing Twitch credentials", "error")
            return false
        end

        local response =
            Net.Post("https://api.twitch.tv/helix/clips", JSON.Stringify({ broadcaster_id = cfg.broadcaster_id }), {
                ["Client-ID"] = cfg.client_id,
                ["Authorization"] = cfg.oauth_token,
                ["Content-Type"] = "application/json",
            })

        if response.status == 200 then
            local clipData = JSON.Parse(response.body)
            local clipUrl = clipData.data[1].edit_url:gsub("/edit", "")

            UI.Notify("Clip created!", "success")
            Log.Info("Clip URL: " .. clipUrl)

            File.Append("clips.txt", clipUrl .. "\n")

            lastClipTime = now
        else
            UI.Notify("Clip creation failed", "error")
            Log.Error("Clip API Error: " .. response.status)
        end

        return false
    end)
)

Twitch Streamer Toolkit

A comprehensive streaming control panel combining clips, ad breaks, slow mode, and stream markers into a single script. Demonstrates multiple Bind/Async handlers, Net.Patch, shared helper functions, UI groups, and session logging via File.Append.

-- rebind: min_sdk=0.1.0
-- rebind: name=Twitch Streamer Toolkit
-- rebind: permission=net

local cfg = UI.Schema({
    -- Credentials
    client_id = UI.Text("", {
        label = "Twitch Client ID",
        placeholder = "Your Twitch API Client ID",
        group = "Credentials",
    }),
    oauth_token = UI.Text("", {
        label = "OAuth Token",
        placeholder = "Bearer your_oauth_token",
        group = "Credentials",
    }),
    broadcaster_id = UI.Text("", {
        label = "Broadcaster ID",
        placeholder = "Your Twitch numeric user ID",
        group = "Credentials",
    }),
    moderator_id = UI.Text("", {
        label = "Moderator ID",
        placeholder = "Moderator's Twitch numeric user ID",
        group = "Credentials",
    }),

    -- Hotkeys
    clip_key = UI.Keybind("F9", { label = "Clip Hotkey", group = "Hotkeys" }),
    ad_key = UI.Keybind("F10", { label = "Ad Break Hotkey", group = "Hotkeys" }),
    slowmode_key = UI.Keybind("F11", { label = "Slow Mode Hotkey", group = "Hotkeys" }),
    marker_key = UI.Keybind("F12", { label = "Stream Marker Hotkey", group = "Hotkeys" }),

    -- Ad Configuration
    ad_length = UI.Select(30, {
        30,
        60,
        90,
        120,
        150,
        180,
        label = "Ad Length",
        suffix = "sec",
        group = "Ad Break",
    }),

    -- Slow Mode Configuration
    slowmode_delay = UI.Slider(5, {
        min = 1,
        max = 120,
        label = "Slow Mode Delay",
        suffix = "sec",
        group = "Slow Mode",
    }),
    slowmode_active = UI.Toggle(false, {
        label = "Slow Mode Enabled",
        group = "Slow Mode",
    }),

    -- Marker Configuration
    marker_desc = UI.Text("", {
        label = "Marker Description",
        placeholder = "Optional marker description",
        group = "Stream Marker",
    }),

    -- Global Settings
    global_cooldown = UI.Slider(5, {
        min = 1,
        max = 30,
        label = "Global Action Cooldown",
        suffix = "sec",
        group = "General",
    }),
})

local lastActionTime = 0

local function isOnCooldown()
    local now = System.Time()
    local cooldownMs = cfg.global_cooldown * 1000

    if now - lastActionTime < cooldownMs then
        UI.Notify("Action on cooldown", "warning")
        return true
    end

    lastActionTime = now
    return false
end

local function logAction(action, details)
    local timestamp = os.date("%Y-%m-%d %H:%M:%S")
    local logEntry = string.format("[%s] %s - %s\n", timestamp, action, details or "")
    File.Append("stream-session.txt", logEntry)
end

local function checkCredentials()
    if not cfg.client_id or not cfg.oauth_token or not cfg.broadcaster_id or not cfg.moderator_id then
        UI.Notify("Missing Twitch credentials", "error")
        return false
    end
    return true
end

Bind(
    cfg.clip_key,
    Async(function()
        if isOnCooldown() or not checkCredentials() then
            return false
        end

        local response =
            Net.Post("https://api.twitch.tv/helix/clips", JSON.Stringify({ broadcaster_id = cfg.broadcaster_id }), {
                ["Client-ID"] = cfg.client_id,
                ["Authorization"] = cfg.oauth_token,
                ["Content-Type"] = "application/json",
            })

        if response.status == 200 then
            local clipData = JSON.Parse(response.body)
            local clipUrl = clipData.data[1].edit_url:gsub("/edit", "")

            UI.Notify("Clip created successfully!", "success")
            logAction("CLIP_CREATED", clipUrl)
        else
            UI.Notify("Clip creation failed", "error")
            logAction("CLIP_FAILED", "Status: " .. response.status)
        end

        return false
    end)
)

Bind(
    cfg.ad_key,
    Async(function()
        if isOnCooldown() or not checkCredentials() then
            return false
        end

        local response = Net.Post(
            "https://api.twitch.tv/helix/channels/commercial",
            JSON.Stringify({
                broadcaster_id = cfg.broadcaster_id,
                length = cfg.ad_length,
            }),
            {
                ["Client-ID"] = cfg.client_id,
                ["Authorization"] = cfg.oauth_token,
                ["Content-Type"] = "application/json",
            }
        )

        if response.status == 200 then
            UI.Notify(cfg.ad_length .. "s Ad Break Started", "success")
            logAction("AD_BREAK", tostring(cfg.ad_length) .. " seconds")
        else
            UI.Notify("Ad Break Failed", "error")
            logAction("AD_BREAK_FAILED", "Status: " .. response.status)
        end

        return false
    end)
)

Bind(
    cfg.slowmode_key,
    Async(function()
        if isOnCooldown() or not checkCredentials() then
            return false
        end

        cfg.slowmode_active = not cfg.slowmode_active

        local response = Net.Patch(
            "https://api.twitch.tv/helix/chat/settings",
            JSON.Stringify({
                broadcaster_id = cfg.broadcaster_id,
                moderator_id = cfg.moderator_id,
                slow_mode = cfg.slowmode_active,
                slow_mode_wait_time = cfg.slowmode_active and cfg.slowmode_delay or 0,
            }),
            {
                ["Client-ID"] = cfg.client_id,
                ["Authorization"] = cfg.oauth_token,
                ["Content-Type"] = "application/json",
            }
        )

        if response.status == 200 then
            local status = cfg.slowmode_active and "ENABLED" or "DISABLED"
            UI.Notify("Slow Mode " .. status, cfg.slowmode_active and "warning" or "info")
            logAction("SLOWMODE_" .. status, tostring(cfg.slowmode_delay) .. " seconds")
        else
            UI.Notify("Slow Mode Toggle Failed", "error")
            logAction("SLOWMODE_FAILED", "Status: " .. response.status)
            cfg.slowmode_active = not cfg.slowmode_active
        end

        return false
    end)
)

Bind(
    cfg.marker_key,
    Async(function()
        if isOnCooldown() or not checkCredentials() then
            return false
        end

        local response = Net.Post(
            "https://api.twitch.tv/helix/streams/markers",
            JSON.Stringify({
                user_id = cfg.broadcaster_id,
                description = cfg.marker_desc or "Stream Marker",
            }),
            {
                ["Client-ID"] = cfg.client_id,
                ["Authorization"] = cfg.oauth_token,
                ["Content-Type"] = "application/json",
            }
        )

        if response.status == 200 then
            UI.Notify("Stream Marker Created", "success")
            logAction("STREAM_MARKER", cfg.marker_desc or "Unnamed Marker")
        else
            UI.Notify("Stream Marker Failed", "error")
            logAction("MARKER_FAILED", "Status: " .. response.status)
        end

        return false
    end)
)

Accessibility

Tremor Smoothing

Smooths mouse movement for users with hand tremors. Filters small jittery movements and applies exponential smoothing to larger ones.

-- rebind: name=Steady Hand
local cfg = UI.Schema({
    enabled = UI.Toggle(true),
    smoothing = UI.Slider(50, {
        min = 0,
        max = 90,
        suffix = "%",
        tooltip = "Higher = smoother but more latency",
    }),
    threshold = UI.Slider(5, {
        min = 1,
        max = 20,
        suffix = "px",
        tooltip = "Filter movements smaller than this",
    }),
})

local buffer = { x = 0, y = 0 }

function OnMove(dx, dy)
    if not cfg.enabled then
        return true
    end

    local magnitude = math.sqrt(dx * dx + dy * dy)
    if magnitude < cfg.threshold then
        return false
    end

    local s = cfg.smoothing / 100
    buffer.x = buffer.x * s + dx * (1 - s)
    buffer.y = buffer.y * s + dy * (1 - s)

    HID.Move(buffer.x, buffer.y)
    return false
end

function OnBlur()
    buffer.x = 0
    buffer.y = 0
end

Click Assist

Multiple click modes for users with difficulty clicking or holding. Hold Assist auto-releases after a timer, Toggle Click makes single clicks act as hold toggles, Double Click fires two clicks from one.

-- rebind: name=Click Assist
local cfg = UI.Schema({
    enabled = UI.Toggle(true),
    mode = UI.Select("Hold Assist", { "Hold Assist", "Toggle Click", "Double Click" }),
    hold_time = UI.Slider(500, {
        min = 100,
        max = 3000,
        suffix = "ms",
        showIf = "mode:Hold Assist",
    }),
    double_delay = UI.Slider(50, {
        min = 20,
        max = 200,
        suffix = "ms",
        showIf = "mode:Double Click",
    }),
})

local toggleState = false

function OnStop()
    if toggleState then
        HID.Up("Mouse1")
    end
end

function OnDown(key)
    if key ~= "Mouse1" or not cfg.enabled then
        return true
    end

    if cfg.mode == "Hold Assist" then
        Run(function()
            HID.Down("Mouse1")
            Audio.Beep()
            Sleep(cfg.hold_time)
            HID.Up("Mouse1")
        end)
        return false
    elseif cfg.mode == "Toggle Click" then
        toggleState = not toggleState
        if toggleState then
            HID.Down("Mouse1")
            Audio.Beep()
        else
            HID.Up("Mouse1")
        end
        return false
    elseif cfg.mode == "Double Click" then
        Run(function()
            HID.Press("Mouse1", 30)
            Sleep(cfg.double_delay)
            HID.Press("Mouse1", 30)
        end)
        return false
    end

    return true
end

function OnBlur()
    if toggleState then
        HID.Up("Mouse1")
        toggleState = false
    end
end

Dwell Click

Click by hovering the cursor in one spot. For users who cannot physically click a mouse button.

-- rebind: name=Dwell Click
local cfg = UI.Schema({
    enabled = UI.Toggle(true),
    dwell_time = UI.Slider(1000, { min = 300, max = 3000, suffix = "ms" }),
    tolerance = UI.Slider(10, { min = 5, max = 50, suffix = "px" }),
    click_type = UI.Select("Left Click", { "Left Click", "Right Click", "Double Click" }),
    sound = UI.Toggle(true, { label = "Audio Feedback" }),
})

local dwellStart = nil
local dwellPos = { x = 0, y = 0 }

function OnTick()
    if not cfg.enabled then
        dwellStart = nil
        return
    end

    local pos = Input.GetMousePos()
    local dx = pos.x - dwellPos.x
    local dy = pos.y - dwellPos.y
    local distance = math.sqrt(dx * dx + dy * dy)

    if distance > cfg.tolerance then
        dwellPos = pos
        dwellStart = System.Time()
        return
    end

    if not dwellStart then
        dwellStart = System.Time()
        return
    end

    if System.Time() - dwellStart >= cfg.dwell_time then
        if cfg.click_type == "Left Click" then
            Run(function() HID.Press("Mouse1") end)
        elseif cfg.click_type == "Right Click" then
            Run(function() HID.Press("Mouse2") end)
        elseif cfg.click_type == "Double Click" then
            Run(function()
                HID.Press("Mouse1", 30)
                Sleep(50)
                HID.Press("Mouse1", 30)
            end)
        end

        if cfg.sound then
            Audio.Beep()
        end
        dwellStart = nil
    end
end

function OnBlur()
    dwellStart = nil
end