Skip to content

Repository files navigation

Mobilerun

@mobilerun/react

React components for embedding Mobilerun's native streaming.
Live WebRTC video + full scrcpy remote control of a cloud device, in any React app.

@mobilerun/react dev playground

✨ What you get

Drop a live, controllable cloud device (iOS/ Android) into any React app:

  • 📺 <DeviceStream /> — WebRTC video with touch, swipe and keyboard control, plus automatic reconnects with exponential backoff and a retry UI once attempts are exhausted.
  • 🪝 useDeviceStream() — resolves a device's stream credentials from @mobilerun/sdk, polling while it boots.
  • 🧭 <NavigationBar />, <StreamStatusPill />, <RemoteControl /> — the surrounding chrome and a lower-level escape hatch.
  • 🎨 Prebuilt stylesheet — no Tailwind setup required, themeable via CSS variables.
  • 📦 Typed — ships its own .d.ts; React and the SDK are peer dependencies.

📦 Install

npm install @mobilerun/react @mobilerun/sdk react react-dom

react, react-dom and @mobilerun/sdk are peer dependencies.

🚀 Quick start

The SDK's Device already carries everything the stream needs (streamUrl + streamToken). useDeviceStream fetches them and refreshes them when the stream reconnects:

⚠️MOBILERUN_API_KEY is a secret API key — never ship it to the browser. It grants full account access, so the snippet below assumes a server-only context (RSC, route handler, SSR). In a client component, resolve streamUrl + streamToken on your backend instead and pass only those to <DeviceStream /> — they're short-lived and scoped to a single device. See Without the hook.

importMobilerunfrom'@mobilerun/sdk';import{DeviceStream,useDeviceStream}from'@mobilerun/react';import'@mobilerun/react/styles.css';constclient=newMobilerun({apiKey: process.env.MOBILERUN_API_KEY});exportfunctionDevicePanel({ deviceId }: {deviceId: string}){const{ streamUrl, streamToken, state, refetch }=useDeviceStream({ client, deviceId });return(<divstyle={{width: 360,height: 780}}><DeviceStreamstreamUrl={streamUrl}streamToken={streamToken}hasControlplaceholderLabel={state}onStreamHealed={refetch}/></div>);}

Without the hook

Already have the device? Feed its fields straight in — no hook required:

constdevice=awaitclient.devices.retrieve(deviceId);<DeviceStreamstreamUrl={device.streamUrl}streamToken={device.streamToken}hasControl/>;

🧪 Try it locally

The repo ships the playground shown above — paste an API key + device id, or a raw streamUrl + streamToken, and stream a real device:

bun install
bun run example # serves the playground at http://localhost:3000

In SDK mode the example server exposes one narrow helper endpoint backed by @mobilerun/sdk so the API key can stay server-side while retrieving streamUrl and streamToken. The stream WebSocket itself is opened directly by the browser against streamUrl; the component appends streamToken as ?token=.

🎨 Styling & theming

Import the prebuilt stylesheet once, anywhere:

import'@mobilerun/react/styles.css';

It bundles the design tokens, only the Tailwind utilities the components use, the animations, and the structural CSS. It does not include Tailwind's preflight/reset, so it won't touch your base styles — and you don't need Tailwind installed.

Retheme by overriding the CSS variables on an ancestor (e.g. --background, --card, --muted-foreground, --border, --primary), or add a .dark ancestor for the bundled dark palette:

:root {
--primary:oklch(0.550.18268);
--background:oklch(0.9850.00485);
}

🛠 Building locally

bun install
bun run build # tsup (JS + d.ts) + Tailwind (styles.css) → dist/
bun run typecheck

📄 License

Apache-2.0

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages