Buckets:
| # 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 │ | |
| └─────────────────────────────────┘ | |
| ``` | |
| 1. **Your app** is a static HTML/JS page hosted on Hugging Face Spaces. | |
| 2. **reachy-mini.js** handles authentication, signaling, and WebRTC negotiation. | |
| 3. The **signaling server** relays SDP offers/answers and ICE candidates. It also validates Hugging Face OAuth tokens. | |
| 4. 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](https://huggingface.co/new-space) with `sdk: static`. | |
| Your `README.md` front matter should look like: | |
| ```yaml | |
| --- | |
| 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: | |
| ```html | |
| import { ReachyMini } from "./reachy-mini.js"; | |
| const robot = new ReachyMini(); | |
| ``` | |
| You can grab `reachy-mini.js` from the [reference example](https://huggingface.co/spaces/cduss/webrtc_example) or from the npm CDN: | |
| ```js | |
| import { ReachyMini } from "https://cdn.jsdelivr.net/npm/@anthropic-robotics/reachy-mini/+esm"; | |
| ``` | |
| ### 3. Connect to your robot | |
| ```js | |
| // 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 open | |
| ``` | |
| ### 4. Control the robot | |
| ```js | |
| // 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 | |
| ```js | |
| // 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 | |
| ```js | |
| // 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 | |
| ```js | |
| detach(); // remove video binding | |
| await robot.stopSession(); // back to 'connected' state | |
| robot.disconnect(); // close signaling (keeps auth) | |
| robot.logout(); // clear HF credentials | |
| ``` | |
| ## API Reference | |
| ### Constructor | |
| ```js | |
| 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` | 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 | |
| ```js | |
| 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 degrees | |
| ``` | |
| ## Security | |
| - 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](../platforms/reachy_mini/usage)). | |
| - Currently supported on **wireless versions** only. | |
| ## Example | |
| A full working example is available as a Hugging Face Space: | |
| [cduss/webrtc_example](https://huggingface.co/spaces/cduss/webrtc_example) | |
| It demonstrates video streaming, head/antenna control, bidirectional audio, and sound playback — all from a single static HTML page. | |
Xet Storage Details
- Size:
- 9.33 kB
- Xet hash:
- 4131d9fad4a406c607a0d78a16957f70d7d64f7c6faa5f37923812d9575fa5f9
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.