Reachy Mini documentation
JavaScript SDK & Web Apps
JavaScript SDK & Web Apps
Reachy Mini supports full JavaScript web apps that run entirely in the browser. No install, no server, no Python β just open a URL and control your robot from any device, including your phone.
Why Web Apps?
The Python SDK is powerful but requires installation, GStreamer dependencies, and a capable machine. Web apps take a different approach:
- Zero install β open a link, youβre in. Save disk space and setup time.
- Cross-platform β works on any device with a browser: laptop, tablet, phone.
- Run from anywhere β control your robot from the other side of the world.
- Leverage device hardware β use your phoneβs microphone, speakers, and touchscreen.
- Instant sharing β send someone a link, they can use the app immediately.
Web apps are deployed as static Hugging Face Spaces (sdk: static). There is no server-side code β the browser connects directly to the robot over WebRTC via a central signaling server.
Python apps are not going away. Web apps are a complementary option, especially suited for lightweight control, remote access, and quick demos.
Architecture
βββββββββββββββββββββββββββββββββββ
β Browser β
β (your app + reachy-mini.js) β
βββββββββ¬βββββββββββββ¬βββββββββββββ
β SSE/HTTP β WebRTC (peer-to-peer)
β signaling β video + audio + data
βββββββββΌβββββββ β
β Signaling β β
β Server β β
β (HF Space) β β
βββββββββ¬βββββββ β
β β
βββββββββΌβββββββββββββΌβββββββββββββ
β Robot β
β GStreamer WebRTC daemon β
β camera Β· mic Β· motors β
βββββββββββββββββββββββββββββββββββ- Your app is a static HTML/JS page hosted on Hugging Face Spaces.
- reachy-mini.js handles authentication, signaling, and WebRTC negotiation.
- The signaling server relays SDP offers/answers and ICE candidates. It also validates Hugging Face OAuth tokens.
- Once the WebRTC connection is established, video, audio, and commands flow peer-to-peer β the signaling server is no longer in the path.
Quick Start
1. Create a Hugging Face Space
Create a new Space on huggingface.co with sdk: static.
Your README.md front matter should look like:
---
title: My Reachy Mini App
emoji: π€
sdk: static
pinned: false
hf_oauth: true
hf_oauth_expiration_minutes: 480
---hf_oauth: true is required β it enables the Hugging Face login button that the signaling server uses for authentication.
2. Add the SDK
In your index.html, import the SDK as an ES module:
<script type="module">
import { ReachyMini } from "./reachy-mini.js";
const robot = new ReachyMini();
</script>You can grab reachy-mini.js from the reference example or from the npm CDN:
import { ReachyMini } from "https://cdn.jsdelivr.net/npm/@anthropic-robotics/reachy-mini/+esm";3. Connect to your robot
// Authenticate with Hugging Face
if (!await robot.authenticate()) {
robot.login(); // redirects to HF login page
return;
}
// Connect to the signaling server
await robot.connect();
// Wait for robots to appear
robot.addEventListener("robotsChanged", (e) => {
const robots = e.detail.robots;
console.log("Available robots:", robots);
});
// Start a session with a specific robot
const detach = robot.attachVideo(document.querySelector("video"));
await robot.startSession(robotId);
// You're live β video is streaming, data channel is open4. Control the robot
// Move the head (roll, pitch, yaw in degrees)
robot.setHeadPose(0, 10, -5);
// Move the antennas (right, left in degrees)
robot.setAntennas(30, -30);
// Play a sound file on the robot
robot.playSound("wake_up.wav");
// Send any JSON command via the data channel
robot.sendRaw({ my_custom_command: "hello" });5. Receive robot state
// Emitted every ~500ms while streaming
robot.addEventListener("state", (e) => {
const { head, antennas } = e.detail;
// head: { roll, pitch, yaw } β degrees
// antennas: { right, left } β degrees
});6. Audio
// Unmute robot speaker (muted by default in browser)
robot.setAudioMuted(false);
// Unmute your microphone (bidirectional audio, if robot supports it)
robot.setMicMuted(false);
// Check if bidirectional audio is available
robot.addEventListener("micSupported", (e) => {
console.log("Mic supported:", e.detail.supported);
});7. Cleanup
detach(); // remove video binding
await robot.stopSession(); // back to 'connected' state
robot.disconnect(); // close signaling (keeps auth)
robot.logout(); // clear HF credentialsAPI Reference
Constructor
new ReachyMini({
signalingUrl: "https://cduss-reachy-mini-central.hf.space", // default
enableMicrophone: true, // default β request mic on startSession()
})State Machine
'disconnected' ββconnect()βββΈ 'connected' ββstartSession()βββΈ 'streaming'
β΄ disconnect() β΄ stopSession()
βββββββββββββββββββββββββββββββProperties (read-only)
| Property | Type | Description |
|---|---|---|
state | string | "disconnected", "connected", or "streaming" |
robots | Array | Available robots: [{ id, meta: { name } }] |
robotState | Object | { head: { roll, pitch, yaw }, antennas: { right, left } } (degrees) |
username | string\|null | HF username after authenticate() |
isAuthenticated | boolean | True if a valid HF token is available |
micSupported | boolean | True if robot offers bidirectional audio |
micMuted | boolean | Your microphone mute state |
audioMuted | boolean | Robot speaker mute state (local only) |
Methods
| Method | Returns | Description |
|---|---|---|
authenticate() | Promise<boolean> | Check for existing HF OAuth token |
login() | β | Redirect to HF login page |
connect() | Promise | Open SSE connection, receive robot list |
startSession(robotId) | Promise | Negotiate WebRTC, resolves when video + data ready |
stopSession() | Promise | End session, back to connected |
disconnect() | β | Close signaling (keeps auth) |
logout() | β | Clear HF credentials |
attachVideo(videoEl) | () => void | Bind video stream to element; returns cleanup function |
setHeadPose(roll, pitch, yaw) | boolean | Set head orientation in degrees |
setAntennas(right, left) | boolean | Set antenna positions in degrees |
playSound(filename) | boolean | Play a sound file on the robot |
sendRaw(data) | boolean | Send arbitrary JSON via data channel |
requestState() | boolean | Request a state snapshot |
setAudioMuted(muted) | β | Mute/unmute robot speaker (local) |
setMicMuted(muted) | β | Mute/unmute your microphone |
Events
Use robot.addEventListener(name, handler) β the SDK extends EventTarget.
| Event | Detail | Description |
|---|---|---|
connected | { peerId } | Signaling connection established |
disconnected | { reason } | Signaling connection lost |
robotsChanged | { robots } | Robot list updated |
streaming | { sessionId, robotId } | WebRTC session active |
sessionStopped | { reason } | Session ended |
state | { head, antennas } | Robot state update (~500ms) |
videoTrack | { track, stream } | Video track available |
micSupported | { supported } | Bidirectional audio availability |
error | { source, error } | Error from signaling, webrtc, or robot |
Math Utilities
import { rpyToMatrix, matrixToRpy, degToRad, radToDeg } from "./reachy-mini.js";
rpyToMatrix(roll, pitch, yaw) // degrees β 4Γ4 rotation matrix (ZYX)
matrixToRpy(matrix) // 4Γ4 matrix β { roll, pitch, yaw } in degreesSecurity
- Authentication goes through Hugging Face OAuth β only users logged in to HF can access the signaling server.
- By default, you can only connect to robots registered under your own HF account.
- WebRTC connections are encrypted (DTLS/SRTP).
Prerequisites
- Your robot must be running the wireless firmware and connected to the central signaling server.
- The robot must have a valid Hugging Face token configured (see Usage).
- Currently supported on wireless versions only.
Example
A full working example is available as a Hugging Face Space: cduss/webrtc_example
It demonstrates video streaming, head/antenna control, bidirectional audio, and sound playback β all from a single static HTML page.
Update on GitHub