Remote Control
Rebind exposes a JSON-RPC WebSocket protocol that lets external programs send HID commands, read screen and input state, and subscribe to live event streams — without writing a single line of Lua.
The protocol is served by the Remote Access script that ships with Rebind. Install it once and any conforming client can connect.
Setup
- Download remote_access.lua and copy it to your Rebind
scripts directory:
- Windows:
%APPDATA%\Rebind\save_data\scripts\
- Windows:
- Open Rebind → Scripts → start Remote Access.
- The script binds a WebSocket server on
ws://0.0.0.0:19561(port is configurable in the script’s settings panel). - Install a client library for your language and connect.
Command surface
| Category | Commands |
|---|---|
| HID writes | hid.down, hid.up, hid.press, hid.type, hid.move, hid.move_to, hid.scroll |
| Screen | screen.pixel, screen.resolution |
| System | system.mouse, system.window, system.time |
| Input | input.keys, input.is_down, input.modifiers |
| Clipboard | clipboard.get, clipboard.set |
| Window | window.list, window.find, window.activate, window.move |
| Events | subscribe, unsubscribe (push: mouse, window, input) |
| Meta | ping, lua.exec |
Authentication
Disabled by default. To require a token, edit AUTH_TOKEN at the top of
remote_access.lua before installing, then pass the same value to your client.
Performance
Measured on localhost (Windows host, release build):
| Metric | Value |
|---|---|
| RPC round-trip p50 | ~1 ms |
| RPC round-trip p99 | ~2 ms |
| Sustained RPC throughput (16 in-flight) | ~10,000 req/s |
| Fire-and-forget wire throughput | ~100,000 msg/s |
JavaScript / TypeScript
npm install @rebind.gg/client-ts
import { RebindRemote } from "@rebind.gg/client-ts";
const r = new RebindRemote("ws://127.0.0.1:19561");
await r.connect();
r.hidMove(30, -5);
r.hidPress("Mouse1", 20);
r.hidType("hello\n");
const { x, y } = await r.systemMouse();
const pixel = await r.screenPixel(x, y);
for await (const pos of r.mouseEvents()) {
console.log(pos.x, pos.y);
if (pos.x > 500) break;
}
r.close();
Works in Node 22+, Bun, Deno, and browsers. Full TypeScript types. Zero runtime dependencies.
- npm:
@rebind.gg/client-ts - GitHub:
usinput/rebind-client-ts
Python
pip install git+https://github.com/usinput/rebind-client-py.git
from rebind import RebindRemote
with RebindRemote("ws://127.0.0.1:19561") as r:
r.hid_move(30, -5)
r.hid_press("Mouse1", hold_ms=20)
r.hid_type("hello\n")
x, y = r.system_mouse()
pixel = r.screen_pixel(x, y)
# sample a color and react
if pixel.r > 200 and pixel.g < 50:
r.hid_press("Mouse1")
# stream mouse position
for pos in r.mouse_events():
print(pos.x, pos.y)
if pos.x > 500:
break
Blocking and asyncio APIs. Pure Python, works on Windows, macOS, and Linux.
- GitHub:
usinput/rebind-client-py
Rust
cargo add rebind-client
use rebind_client::RebindClient;
#[tokio::main]
async fn main() -> rebind_client::Result<()> {
let client = RebindClient::connect("ws://127.0.0.1:19561").await?;
client.hid_move(30, -5);
client.hid_press("Mouse1", 20);
client.hid_type("hello\n");
let (x, y) = client.system_mouse().await?;
let pixel = client.screen_pixel(x, y).await?;
// sample a color and react
if pixel.r > 200 && pixel.g < 50 {
client.hid_press("Mouse1", 20);
}
// stream mouse position
let mut events = client.mouse_events().await?;
while let Some(pos) = events.recv().await {
println!("{} {}", pos.x, pos.y);
}
client.close().await;
Ok(())
}
Async, typed, built on tokio.
- crates.io:
rebind-client - GitHub:
usinput/rebind-client-rs