@robinandeer/rtc-session-components 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICES +41 -0
- package/README.md +241 -125
- package/dist/index.cjs +254 -106
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +46 -88
- package/dist/index.d.ts +46 -88
- package/dist/index.js +254 -104
- package/dist/index.js.map +1 -1
- package/dist/styles.css +193 -0
- package/package.json +8 -4
package/NOTICES
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
This project includes the following third-party dependencies:
|
|
2
|
+
|
|
3
|
+
================================================================================
|
|
4
|
+
livekit-client
|
|
5
|
+
https://github.com/livekit/client-sdk-js
|
|
6
|
+
--------------------------------------------------------------------------------
|
|
7
|
+
Licensed under the Apache License, Version 2.0
|
|
8
|
+
|
|
9
|
+
Copyright 2023 LiveKit, Inc.
|
|
10
|
+
|
|
11
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
12
|
+
you may not use this file except in compliance with the License.
|
|
13
|
+
You may obtain a copy of the License at
|
|
14
|
+
|
|
15
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
16
|
+
|
|
17
|
+
Unless required by applicable law or agreed to in writing, software
|
|
18
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
19
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
20
|
+
See the License for the specific language governing permissions and
|
|
21
|
+
limitations under the License.
|
|
22
|
+
|
|
23
|
+
================================================================================
|
|
24
|
+
@livekit/components-react
|
|
25
|
+
https://github.com/livekit/components-js
|
|
26
|
+
--------------------------------------------------------------------------------
|
|
27
|
+
Licensed under the Apache License, Version 2.0
|
|
28
|
+
|
|
29
|
+
Copyright 2023 LiveKit, Inc.
|
|
30
|
+
|
|
31
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
32
|
+
you may not use this file except in compliance with the License.
|
|
33
|
+
You may obtain a copy of the License at
|
|
34
|
+
|
|
35
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
36
|
+
|
|
37
|
+
Unless required by applicable law or agreed to in writing, software
|
|
38
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
39
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
40
|
+
See the License for the specific language governing permissions and
|
|
41
|
+
limitations under the License.
|
package/README.md
CHANGED
|
@@ -2,201 +2,317 @@
|
|
|
2
2
|
|
|
3
3
|
React SDK for real-time AI avatar interactions with GWM-1.
|
|
4
4
|
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- React 18+
|
|
8
|
+
- A Runway API secret ([get one here](https://dev.runwayml.com/))
|
|
9
|
+
- A server-side endpoint to create sessions (API secrets must not be exposed to the client)
|
|
10
|
+
|
|
5
11
|
## Installation
|
|
6
12
|
|
|
7
13
|
```bash
|
|
8
14
|
npm install @runwayml/avatar-react
|
|
9
|
-
# or
|
|
10
|
-
bun add @runwayml/avatar-react
|
|
11
15
|
```
|
|
12
16
|
|
|
13
17
|
## Quick Start
|
|
14
18
|
|
|
19
|
+
Add an avatar call to your app with just a few lines:
|
|
20
|
+
|
|
15
21
|
```tsx
|
|
16
|
-
import {
|
|
22
|
+
import { AvatarCall } from '@runwayml/avatar-react';
|
|
17
23
|
|
|
18
24
|
function App() {
|
|
19
25
|
return (
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
<AvatarCall
|
|
27
|
+
avatarId="game-host"
|
|
28
|
+
connectUrl="/api/avatar/connect"
|
|
29
|
+
/>
|
|
23
30
|
);
|
|
24
31
|
}
|
|
32
|
+
```
|
|
25
33
|
|
|
26
|
-
|
|
27
|
-
const { connect, disconnect, speak, isConnected, isConnecting } = useAvatar();
|
|
34
|
+
That's it! The component handles session creation, WebRTC connection, and renders a default UI with the avatar video and controls.
|
|
28
35
|
|
|
29
|
-
|
|
30
|
-
await connect({ modelId: 'gwm-1' });
|
|
31
|
-
};
|
|
36
|
+
You can use preset avatars like `game-host`, `coding-teacher`, `language-tutor`, and more. See the [Runway Developer Portal](https://dev.runwayml.com/) for the full list and creating custom avatars.
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
38
|
+
### Optional: Add Default Styles
|
|
39
|
+
|
|
40
|
+
Import the optional stylesheet for a polished look out of the box:
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import '@runwayml/avatar-react/styles.css';
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The styles use CSS custom properties for easy customization:
|
|
47
|
+
|
|
48
|
+
```css
|
|
49
|
+
:root {
|
|
50
|
+
--avatar-bg: #a78bfa; /* Video background color */
|
|
51
|
+
--avatar-radius: 16px; /* Container border radius */
|
|
52
|
+
--avatar-control-size: 48px; /* Control button size */
|
|
53
|
+
--avatar-end-call-bg: #ef4444; /* End call button color */
|
|
49
54
|
}
|
|
50
55
|
```
|
|
51
56
|
|
|
52
|
-
|
|
57
|
+
See [`examples/`](./examples) for complete working examples:
|
|
58
|
+
- [`nextjs`](./examples/nextjs) - Next.js App Router
|
|
59
|
+
- [`react-router`](./examples/react-router) - React Router v7 framework mode
|
|
60
|
+
- [`express`](./examples/express) - Express + Vite
|
|
53
61
|
|
|
54
|
-
|
|
62
|
+
## How It Works
|
|
55
63
|
|
|
56
|
-
|
|
64
|
+
1. **Client** calls your server endpoint with the `avatarId`
|
|
65
|
+
2. **Server** uses your Runway API secret to create a session via `@runwayml/sdk`
|
|
66
|
+
3. **Server** returns connection credentials (token, URL) to the client
|
|
67
|
+
4. **Client** establishes a WebRTC connection for real-time video/audio
|
|
57
68
|
|
|
58
|
-
|
|
69
|
+
This flow keeps your API secret secure on the server while enabling low-latency communication.
|
|
59
70
|
|
|
60
|
-
|
|
61
|
-
<AvatarProvider config={{ apiKey: 'your-api-key', debug: true }}>{children}</AvatarProvider>
|
|
62
|
-
```
|
|
71
|
+
## Server Setup
|
|
63
72
|
|
|
64
|
-
|
|
73
|
+
Your server endpoint receives the `avatarId` and returns session credentials. Use `@runwayml/sdk` to create the session:
|
|
65
74
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
- `config.timeout` - Request timeout in ms (default: 30000)
|
|
70
|
-
- `config.maxRetries` - Max retry attempts (default: 2)
|
|
71
|
-
- `config.debug` - Enable debug logging (default: false)
|
|
75
|
+
```ts
|
|
76
|
+
// /api/avatar/connect (Next.js App Router example)
|
|
77
|
+
import Runway from '@runwayml/sdk';
|
|
72
78
|
|
|
73
|
-
|
|
79
|
+
const runway = new Runway(); // Uses RUNWAYML_API_SECRET env var
|
|
74
80
|
|
|
75
|
-
|
|
81
|
+
export async function POST(req: Request) {
|
|
82
|
+
const { avatarId } = await req.json();
|
|
76
83
|
|
|
77
|
-
|
|
78
|
-
|
|
84
|
+
const session = await runway.realtime.sessions.create({
|
|
85
|
+
model: 'calliope',
|
|
86
|
+
options: { avatar: avatarId },
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return Response.json({
|
|
90
|
+
sessionId: session.id,
|
|
91
|
+
serverUrl: session.url,
|
|
92
|
+
token: session.token,
|
|
93
|
+
roomName: session.room_name,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
79
96
|
```
|
|
80
97
|
|
|
81
|
-
|
|
98
|
+
## Customization
|
|
82
99
|
|
|
83
|
-
|
|
100
|
+
### Custom Connect Function
|
|
84
101
|
|
|
85
|
-
|
|
102
|
+
For more control over the connection flow:
|
|
86
103
|
|
|
87
104
|
```tsx
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
});
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
#### `useAvatarVideo(options?)`
|
|
111
|
-
|
|
112
|
-
Hook for handling avatar video frames.
|
|
105
|
+
<AvatarCall
|
|
106
|
+
avatarId="game-host"
|
|
107
|
+
connect={async (avatarId) => {
|
|
108
|
+
const res = await fetch('/api/avatar/connect', {
|
|
109
|
+
method: 'POST',
|
|
110
|
+
headers: {
|
|
111
|
+
'Authorization': `Bearer ${token}`,
|
|
112
|
+
'Content-Type': 'application/json',
|
|
113
|
+
},
|
|
114
|
+
body: JSON.stringify({ avatarId }),
|
|
115
|
+
});
|
|
116
|
+
return res.json();
|
|
117
|
+
}}
|
|
118
|
+
/>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Custom UI with Child Components
|
|
122
|
+
|
|
123
|
+
Use the built-in components for custom layouts:
|
|
113
124
|
|
|
114
125
|
```tsx
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
126
|
+
import { AvatarCall, AvatarVideo, ControlBar, UserVideo } from '@runwayml/avatar-react';
|
|
127
|
+
|
|
128
|
+
<AvatarCall avatarId="game-host" connectUrl="/api/avatar/connect">
|
|
129
|
+
<div className="call-layout">
|
|
130
|
+
<AvatarVideo className="avatar" />
|
|
131
|
+
<UserVideo className="self-view" />
|
|
132
|
+
<ControlBar className="controls" />
|
|
133
|
+
</div>
|
|
134
|
+
</AvatarCall>
|
|
120
135
|
```
|
|
121
136
|
|
|
122
|
-
|
|
137
|
+
### Render Props
|
|
123
138
|
|
|
124
|
-
|
|
139
|
+
All components support render props for complete control:
|
|
125
140
|
|
|
126
141
|
```tsx
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
142
|
+
<AvatarVideo>
|
|
143
|
+
{({ hasVideo, isConnecting, isSpeaking, trackRef }) => (
|
|
144
|
+
<div className={isSpeaking ? 'speaking' : ''}>
|
|
145
|
+
{isConnecting && <Spinner />}
|
|
146
|
+
{hasVideo && <VideoTrack trackRef={trackRef} />}
|
|
147
|
+
</div>
|
|
148
|
+
)}
|
|
149
|
+
</AvatarVideo>
|
|
131
150
|
```
|
|
132
151
|
|
|
133
|
-
|
|
152
|
+
### CSS Styling with Data Attributes
|
|
134
153
|
|
|
135
|
-
|
|
154
|
+
Style connection states with CSS:
|
|
136
155
|
|
|
137
156
|
```tsx
|
|
138
|
-
|
|
139
|
-
sampleRate: 48000,
|
|
140
|
-
echoCancellation: true,
|
|
141
|
-
noiseSuppression: true,
|
|
142
|
-
});
|
|
157
|
+
<AvatarCall avatarId="game-host" connectUrl="/api/avatar/connect" className="my-avatar" />
|
|
143
158
|
```
|
|
144
159
|
|
|
145
|
-
|
|
160
|
+
```css
|
|
161
|
+
.my-avatar[data-state="connecting"] {
|
|
162
|
+
opacity: 0.5;
|
|
163
|
+
}
|
|
146
164
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
modelId: string;
|
|
150
|
-
resolution?: { width: number; height: number };
|
|
151
|
-
audio?: AudioConfig;
|
|
152
|
-
initialState?: Partial<AvatarState>;
|
|
165
|
+
.my-avatar[data-state="error"] {
|
|
166
|
+
border: 2px solid red;
|
|
153
167
|
}
|
|
154
168
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
isSpeaking: boolean;
|
|
158
|
-
isListening: boolean;
|
|
159
|
-
gazeDirection: { x: number; y: number };
|
|
169
|
+
.my-avatar[data-state="connected"] {
|
|
170
|
+
border: 2px solid green;
|
|
160
171
|
}
|
|
172
|
+
```
|
|
161
173
|
|
|
162
|
-
|
|
174
|
+
## Callbacks
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
<AvatarCall
|
|
178
|
+
avatarId="game-host"
|
|
179
|
+
connectUrl="/api/avatar/connect"
|
|
180
|
+
onEnd={() => console.log('Call ended')}
|
|
181
|
+
onError={(error) => console.error('Error:', error)}
|
|
182
|
+
/>
|
|
163
183
|
```
|
|
164
184
|
|
|
165
|
-
##
|
|
185
|
+
## Hooks
|
|
166
186
|
|
|
167
|
-
|
|
187
|
+
Use hooks for custom components within an `AvatarCall` or `AvatarSession`:
|
|
168
188
|
|
|
169
|
-
|
|
170
|
-
import { createAvatarClient } from '@runwayml/avatar-react';
|
|
189
|
+
### useAvatarSession
|
|
171
190
|
|
|
172
|
-
|
|
191
|
+
Access session state and controls:
|
|
173
192
|
|
|
174
|
-
|
|
193
|
+
```tsx
|
|
194
|
+
function MyComponent() {
|
|
195
|
+
const { state, sessionId, error, end } = useAvatarSession();
|
|
175
196
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
});
|
|
197
|
+
if (state === 'connecting') return <Loading />;
|
|
198
|
+
if (state === 'error') return <Error message={error.message} />;
|
|
179
199
|
|
|
180
|
-
|
|
181
|
-
|
|
200
|
+
return <button onClick={end}>End Call</button>;
|
|
201
|
+
}
|
|
182
202
|
```
|
|
183
203
|
|
|
184
|
-
|
|
204
|
+
### useAvatar
|
|
185
205
|
|
|
186
|
-
|
|
187
|
-
# Install dependencies
|
|
188
|
-
bun install
|
|
206
|
+
Access the remote avatar's video/audio:
|
|
189
207
|
|
|
190
|
-
|
|
191
|
-
|
|
208
|
+
```tsx
|
|
209
|
+
function CustomAvatar() {
|
|
210
|
+
const { videoTrackRef, isSpeaking, hasVideo, hasAudio } = useAvatar();
|
|
192
211
|
|
|
193
|
-
|
|
194
|
-
|
|
212
|
+
return (
|
|
213
|
+
<div data-speaking={isSpeaking}>
|
|
214
|
+
{hasVideo && <VideoTrack trackRef={videoTrackRef} />}
|
|
215
|
+
</div>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### useLocalMedia
|
|
221
|
+
|
|
222
|
+
Control local camera and microphone:
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
function MediaControls() {
|
|
226
|
+
const {
|
|
227
|
+
isMicEnabled,
|
|
228
|
+
isCameraEnabled,
|
|
229
|
+
toggleMic,
|
|
230
|
+
toggleCamera,
|
|
231
|
+
toggleScreenShare,
|
|
232
|
+
} = useLocalMedia();
|
|
233
|
+
|
|
234
|
+
return (
|
|
235
|
+
<div>
|
|
236
|
+
<button onClick={toggleMic}>{isMicEnabled ? 'Mute' : 'Unmute'}</button>
|
|
237
|
+
<button onClick={toggleCamera}>{isCameraEnabled ? 'Hide' : 'Show'}</button>
|
|
238
|
+
</div>
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Advanced: AvatarSession
|
|
244
|
+
|
|
245
|
+
For full control over session management, use `AvatarSession` directly with pre-fetched credentials:
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
import { AvatarSession, AvatarVideo, ControlBar } from '@runwayml/avatar-react';
|
|
249
|
+
|
|
250
|
+
function AdvancedUsage({ credentials }) {
|
|
251
|
+
return (
|
|
252
|
+
<AvatarSession
|
|
253
|
+
credentials={credentials}
|
|
254
|
+
audio={true}
|
|
255
|
+
video={true}
|
|
256
|
+
onEnd={() => console.log('Ended')}
|
|
257
|
+
onError={(err) => console.error(err)}
|
|
258
|
+
>
|
|
259
|
+
<AvatarVideo />
|
|
260
|
+
<ControlBar />
|
|
261
|
+
</AvatarSession>
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Components Reference
|
|
195
267
|
|
|
196
|
-
|
|
197
|
-
|
|
268
|
+
| Component | Description |
|
|
269
|
+
|-----------|-------------|
|
|
270
|
+
| `AvatarCall` | High-level component that handles session creation |
|
|
271
|
+
| `AvatarSession` | Low-level wrapper that requires credentials |
|
|
272
|
+
| `AvatarVideo` | Renders the remote avatar video |
|
|
273
|
+
| `UserVideo` | Renders the local user's camera |
|
|
274
|
+
| `ControlBar` | Media control buttons (mic, camera, end call) |
|
|
275
|
+
| `ScreenShareVideo` | Renders screen share content |
|
|
276
|
+
| `AudioRenderer` | Handles avatar audio playback |
|
|
277
|
+
|
|
278
|
+
## TypeScript
|
|
279
|
+
|
|
280
|
+
All components and hooks are fully typed:
|
|
281
|
+
|
|
282
|
+
```tsx
|
|
283
|
+
import type {
|
|
284
|
+
AvatarCallProps,
|
|
285
|
+
SessionCredentials,
|
|
286
|
+
SessionState,
|
|
287
|
+
} from '@runwayml/avatar-react';
|
|
198
288
|
```
|
|
199
289
|
|
|
290
|
+
## Browser Support
|
|
291
|
+
|
|
292
|
+
This SDK uses WebRTC for real-time communication. Supported browsers:
|
|
293
|
+
|
|
294
|
+
- Chrome 74+
|
|
295
|
+
- Firefox 78+
|
|
296
|
+
- Safari 14.1+
|
|
297
|
+
- Edge 79+
|
|
298
|
+
|
|
299
|
+
Users must grant camera and microphone permissions when prompted.
|
|
300
|
+
|
|
301
|
+
## Troubleshooting
|
|
302
|
+
|
|
303
|
+
**"Failed to connect" or timeout errors**
|
|
304
|
+
- Verify your server endpoint is returning the correct credential format
|
|
305
|
+
- Check that `RUNWAYML_API_SECRET` is set correctly on your server
|
|
306
|
+
|
|
307
|
+
**No video/audio**
|
|
308
|
+
- Ensure the user has granted camera/microphone permissions
|
|
309
|
+
- Check browser console for WebRTC errors
|
|
310
|
+
- Verify the device has a working camera/microphone
|
|
311
|
+
|
|
312
|
+
**CORS errors**
|
|
313
|
+
- Your server endpoint must accept requests from your client's origin
|
|
314
|
+
- For local development, ensure both client and server are on compatible origins
|
|
315
|
+
|
|
200
316
|
## License
|
|
201
317
|
|
|
202
318
|
MIT
|