Locomo is a minimal Steam Remote Play client designed for ARM64 Linux handhelds. It implements the Steam In-Home Streaming protocol via ihslib and is built in Zig.
- Host discovery and PIN-based pairing
- H.264 and HEVC video streaming
- Hardware-accelerated decoding via V4L2 M2M, V4L2 Request API, and Rockchip MPP
- AAC and Opus audio
- Gamepad input passthrough via SDL HID
- Software mouse mode for cursor control from an analog stick
- In-app settings screen (no config file editing required)
- ARM64 Linux (aarch64)
- VPU hardware for video decoding (software decoding also available)
- EGL and OpenGL ES 2.0 for zero-copy DRM frame rendering
libSDL2andlibrockchip_mppavailable on the system (Provided by build if needed)- A Steam host on the same local network with Remote Play enabled
- Docker
bash
- Zig 0.16.0
python3,wayland-scanner++- ARM64 sysroot with:
libdbus,libibus,libdrm,libegl,libgles,libgbm,libasound2,libpulse,libwayland,libwayland-egl,libxkbcommon,libX11,libxext,libxrandr,libxcursor,libxi
git clone https://github.com/beebono/locomo.git
cd locomo./docker-build.shThis builds a Docker image with the full cross-compilation toolchain, then uses zig to build all dependencies and locomo itself. The output binary and libraries are placed at:
./zig-out/bin/locomo
./zig-out/lib/libSDL2-2.0.so.0
./zig-out/lib/librockchip_mpp.so.1
To target a different architecture, set TARGET before running:
TARGET=aarch64-linux-gnu ./docker-build.shPlease note this is unlikely to work for targets other than aarch64 at the moment!
zig build -Doptimize=ReleaseFastCopy locomo to your device and run it. On first launch it generates a device identity in a config/ directory next to the binary.
Locomo is fully controller-driven. Use D-pad to move, A to confirm, B to go back.
Host scan screen:
- D-pad up/down - move cursor
- A - connect to selected host (pairs if not yet paired, otherwise streams directly)
- Start - open settings
- B - confirm quit prompt
Pairing:
A 4-digit PIN is displayed. Enter it in Steam on the host when prompted, or under Settings → Remote Play → Pair Steam Link.
During streaming:
| Chord | Action |
|---|---|
| Start + Select, then X × 2 | Disconnect and return to menu |
| Start + Select + L3 | Toggle mouse mode |
In mouse mode the left stick moves the cursor and the right trigger acts as a click. You can also use the right stick to scroll content.
Open the settings screen from the host scan with Start. Navigate rows with D-pad up/down, change values with D-pad left/right or A. Press B or Start to save and return.
| Setting | Options |
|---|---|
| Quality | Fast / Balanced / Beautiful |
| Resolution | Native (screen size), or fixed 16:9: 852×480 up to 3840×2160 |
| Bandwidth | Automatic, or fixed: 5–100 Mbps / Unlimited |
| Audio | No Audio / Mono / Stereo |
| Framerate | Automatic / 30 / 60 / 120 / 240 FPS |
| HEVC | Off / On |
| HW Decode | Off / On (requires V4L2 or Rockchip MPP) |
| Button Swap | None / Swap A-B / Swap X-Y / Swap All |
Settings are saved to config/settings.json next to the binary.
All state is stored in a config/ directory alongside the binary:
| File | Contents |
|---|---|
device.json |
Device identity (ID, secret key, name), auto-generated |
paired.json |
Paired host info, written after successful pairing |
settings.json |
User settings, written when leaving the settings screen |
Delete paired.json to unpair from the current host.
| Library | Purpose |
|---|---|
| ihslib | Steam IHS protocol implementation |
| SDL2 | Window, renderer, gamepad input |
| SDL2_ttf | Font rendering for the UI |
| FFmpeg | Video/audio demuxing and decoding |
| Rockchip MPP | Hardware video decoding on Rockchip SoCs |
| mbedTLS | Cryptography (stream encryption) |
| protobuf-c | Protobuf serialization for the IHS protocol |
| libudev-zero | Minimal udev stub (static, no systemd dependency) |
See LICENSES directory for applicable licensing details
This project uses the work from following developers/projects. Without them, this wouldn't be here!
LibreELEC for the ffmpeg patches to enable additional V4L2 features

