High-performance, low-latency remote desktop
QUIC transport · hardware encoding and decoding · up to 120 fps
Windows · macOS · Linux · Android · browser
English · 简体中文
Airhand is a high-performance, low-latency remote desktop: the screen is encoded on the GPU (AV1 / HEVC / H.264) at up to 120 fps and sent over QUIC; when the network slows down it skips to the latest frame instead of letting lag pile up; and the mouse pointer is drawn locally, so it moves without delay.
The same program is both the host (the device being controlled) and the controller (the device you control it from). The two sides meet through a relay server that you deploy yourself. It's small, and Docker Compose deploys it with one command. Enter the other side's 6-digit control code to connect.
Note
Work in progress (0.2.2). The protocol still changes between versions, so the clients and the server need to be the same version; a mismatch is detected and reported (see Protocol versions).
Every stage from capture to display is built for low latency:
- Hardware encoding and decoding: the host encodes on the GPU (NVENC / Quick Sync / AMF, VideoToolbox, MediaCodec) in low-latency mode without B-frames; the controller decodes on the GPU (WebCodecs / MediaCodec). Measured with a 4K screen streamed at 1080p, hardware AV1 encoding takes about 7 ms per frame (RTX graphics card)
- The best format: AV1 > HEVC > H.264, automatically picking the most efficient format both sides support; scaling and color conversion use SIMD, and all buffers are reused
- No lag build-up: the host limits frames in flight (≈ RTT × frame rate + 2) and skips to the latest frame on a slow network; adaptive bitrate backs off under congestion and recovers gradually
- QUIC + BBR: BBR congestion control is steadier than Cubic on lossy networks such as Wi-Fi or long-distance links; control messages, audio and video are queued separately, so mouse input and pings never wait behind a large frame; the relay only forwards bytes and never parses the video
- Decode and show: the decoder runs in low-latency mode, and each frame is drawn to a desynchronized canvas as soon as it's decoded, without waiting for vsync
- Local pointer: the remote cursor's shape is mirrored locally, and moving it happens locally
- Low bandwidth: no frames are sent while the screen is still, so an idle desktop uses almost nothing; sessions that aren't on screen drop to 5 fps
See How it works → Video for details.
- Windows system service: the lock screen, the sign-in screen and UAC prompts can be seen and controlled, and the computer can be reached after boot, before anyone signs in
- Fixed control codes: they survive restarts, upgrades and even server restarts until you change them yourself
- Console: browser-style tabs to control several computers at once, plus a multi-screen overview to watch them all. Computers you've connected to are saved and reconnect with one click; if one is offline, it connects as soon as it comes back
- Web console: the controller can also run in Docker and be used from a browser, with nothing to install on the computer you control from
- Android: control computers and phones from a phone as a trackpad or touchscreen, or share your own screen to get help (you approve each connection by default); watch on a TV with the remote
- Audio: the host's system audio plays on the controller (Opus + adaptive jitter buffer), with optional A/V sync for watching videos
- Handy tools: two-way clipboard sync, typing the clipboard as keystrokes, system shortcuts (Win, Alt+Tab, Ctrl+Shift+Esc…), multiple monitors, keyboard lock in fullscreen, quality presets
- Secure by default: TLS 1.3 with certificate pinning, brute-force protection for control codes; the host always sees who is connected and can disconnect them with one click
- Leaves nothing behind: the host is just a tray icon and doesn't start a WebView; everything worth keeping is in one
config.toml, other runtime files are deleted on exit, and nothing is left after uninstalling (Windows has an uninstaller, macOS has "Uninstall Airhand…" in the menu, Linux takes two commands) - English and Chinese: follows the system language; notices from the other computer and the server also appear in your language
| Platform | Host | Controller | Notes |
|---|---|---|---|
| Windows 10 / 11 | ✅ | ✅ | Installed; the host runs as a system service |
| macOS 13+ | ✅ | ✅ | The host needs the Screen & System Audio Recording and Accessibility permissions |
| Linux | ✅ | ✅ | The host supports X11 desktops only, with software encoding for now |
| Android 7+ phones / tablets | ✅ | ✅ | Can only be watched until the accessibility service is turned on; the controller connects to one device at a time |
| Android TV / Google TV | — | View only | Operated entirely with the remote |
| Browser (web console) | — | ✅ | Chrome / Edge, Safari 16.4+, Firefox 130+ |
See Known limitations for platform-specific caveats.
flowchart LR
host["Host<br>Windows / macOS / Linux / Android"]
relay["Relay server<br>airhand-server (Docker)"]
ctrl["Controller<br>desktop console / web console / Android"]
host <-->|"QUIC · UDP 4433"| relay
relay <-->|"QUIC · UDP 4433"| ctrl
The host connects to the relay server and gets a 6-digit control code; the controller uses that code to find it. The server only registers codes, pairs sessions and forwards bytes; it never parses the video. Both the host and the controller connect out to the server, so neither needs an open port or a public IP. See How it works for details.
You need:
- A machine both sides can reach, with Docker and UDP 4433 open
- Rust, Node.js 20+ and CMake to build the client (per-platform requirements in Building)
git clone https://github.com/sqlpxc/airhand.git
cd airhand
docker compose up -d
docker compose logs airhand | grep fingerprint # note the certificate's SHA-256 fingerprintThe certificate and the control-code database live in data/. Keep that directory: with a new certificate, clients you've already built can no longer connect. Server settings are in Deployment.
Compile in the server address and the fingerprint from step 1.
Windows (PowerShell):
cd client
npm install
$env:AIRHAND_SERVER = "relay.example.com:4433"
$env:AIRHAND_SERVER_FP = "<fingerprint from step 1>"
npm run tauri buildmacOS / Linux:
cd client
npm install
export AIRHAND_SERVER=relay.example.com:4433
export AIRHAND_SERVER_FP=<fingerprint from step 1>
npm run tauri buildThe packages are under client/src-tauri/target/release/bundle/:
| System | Package |
|---|---|
| Windows | nsis/Airhand_<version>_x64-setup.exe |
| macOS | macos/Airhand.app, dmg/Airhand_<version>_<arch>.dmg |
| Linux | deb/Airhand_<version>_amd64.deb |
The server address and fingerprint can also be changed later in config.toml. For the Android APK, see Building → Android.
- Install Airhand on both computers (on Windows run the installer, which needs administrator rights; on macOS grant the permissions it asks for the first time)
- On the computer to be controlled, right-click the tray icon (on macOS, click the menu bar icon) to see its 6-digit control code
- On your computer, choose Open console from the tray menu (Switch to controller on macOS / Linux) and enter the code
The full guide is in Usage.
Start the web console on any machine with Docker and use it from a browser:
cd web
AIRHAND_SERVER=relay.example.com:4433 AIRHAND_SERVER_FP=<fingerprint> docker compose up -dOpen http://localhost:8080 on that machine, or https://<its address>:8080 from other computers. For the access password, the HTTPS certificate and reverse proxies, see Deployment → Web console.
| Document | Contents |
|---|---|
| Usage | Host, Windows installation, configuration file, uninstalling, console, quality, language |
| Deployment | Relay server settings, web console, reverse proxies |
| Android | Controlling from a phone, sharing the phone, gestures, TVs |
| Building | Per-platform requirements and packages, signing, APK |
| How it works | Architecture, source layout, Windows service, video and audio pipelines, A/V sync, files on disk |
| Security | Encryption and pinning, brute-force protection, control codes and resume tokens |
| Known limitations | Known issues by platform |
| Development | Tests, debugging tools, project conventions |
- Everything runs over TLS 1.3 (QUIC), and clients verify the server by its certificate fingerprint. A client built without a fingerprint doesn't verify the server; use that for development only
- The relay server can see session contents (TLS terminates at the server), so run it on a machine you trust; the same goes for the web console
- A control code is a key: the Windows host runs as SYSTEM, so whoever has the code controls the computer with administrator rights. Give it only to people you trust; the host's tray always shows who is connected and lets you disconnect them or change the code
See Security for details.
| Directory | Contents |
|---|---|
crates/ |
The protocol (airhand-proto) and the client-to-relay link (airhand-link) |
server/ |
Relay server |
web/ |
Web console service |
client/ |
Desktop client: Tauri (Rust) + React UI, which the web console uses too |
android/ |
Android app (Kotlin + Jetpack Compose) and its Rust core |
How to run the tests, the debugging tools and the project conventions (protocol versions, UI strings…) are in Development.