@reactor-models/fast-h3 1.0.2
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/README.md +1433 -0
- package/dist/chunk-4DZUZYZH.mjs +301 -0
- package/dist/chunk-4DZUZYZH.mjs.map +1 -0
- package/dist/chunk-NMQA7NIH.mjs +343 -0
- package/dist/chunk-NMQA7NIH.mjs.map +1 -0
- package/dist/core.d.mts +653 -0
- package/dist/core.d.ts +653 -0
- package/dist/core.js +371 -0
- package/dist/core.js.map +1 -0
- package/dist/core.mjs +15 -0
- package/dist/core.mjs.map +1 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +683 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +61 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react.d.mts +185 -0
- package/dist/react.d.ts +185 -0
- package/dist/react.js +347 -0
- package/dist/react.js.map +1 -0
- package/dist/react.mjs +51 -0
- package/dist/react.mjs.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,1433 @@
|
|
|
1
|
+
# @reactor-models/fast-h3
|
|
2
|
+
|
|
3
|
+
> Typed JavaScript + React SDK for the **FastH3** model on [Reactor](https://reactor.inc). Version **v1.0.2**.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Get started
|
|
8
|
+
|
|
9
|
+
Scaffold a starter app for **FastH3** with [`create-reactor-app`](https://www.npmjs.com/package/create-reactor-app):
|
|
10
|
+
|
|
11
|
+
```shell
|
|
12
|
+
npx create-reactor-app my-app --model=fast-h3
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```shell
|
|
16
|
+
pnpm dlx create-reactor-app my-app --model=fast-h3
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```shell
|
|
24
|
+
npm install @reactor-models/fast-h3
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```shell
|
|
28
|
+
pnpm add @reactor-models/fast-h3
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The package exports a plain-JavaScript client and a set of React bindings. Import whichever you need from `@reactor-models/fast-h3`:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { FastH3Provider, useFastH3 } from "@reactor-models/fast-h3";
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
React 18 or later is required when using the provider and hooks. The token-loading examples below use [React 19's `use()`](https://react.dev/reference/react/use); on React 18, fetch the JWT in a `useEffect` and pass it to the provider once it resolves.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Authenticate
|
|
46
|
+
|
|
47
|
+
Reactor uses short-lived JWTs for session auth. You hold your API key on your server, mint a token on demand, and the client never sees the raw key. Tokens are valid for **6 hours** — if one leaks, it expires on its own.
|
|
48
|
+
|
|
49
|
+
Mint a JWT with **`POST https://api.reactor.inc/tokens`** and the **`Reactor-API-Key`** header; the response JSON is `{ "jwt": "..." }`.
|
|
50
|
+
|
|
51
|
+
### JavaScript (Next.js route handler)
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// app/api/reactor/token/route.ts
|
|
55
|
+
import { NextResponse } from "next/server";
|
|
56
|
+
|
|
57
|
+
export async function POST() {
|
|
58
|
+
const res = await fetch("https://api.reactor.inc/tokens", {
|
|
59
|
+
method: "POST",
|
|
60
|
+
headers: { "Reactor-API-Key": process.env.REACTOR_API_KEY! },
|
|
61
|
+
});
|
|
62
|
+
const { jwt } = await res.json();
|
|
63
|
+
return NextResponse.json({ jwt });
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### React (provider)
|
|
68
|
+
|
|
69
|
+
Call the `/api/reactor/token` route above from a client component and pass the result to the provider:
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
"use client";
|
|
73
|
+
|
|
74
|
+
import { use } from "react";
|
|
75
|
+
import { FastH3Provider } from "@reactor-models/fast-h3";
|
|
76
|
+
import { ReactorView } from "@reactor-team/js-sdk";
|
|
77
|
+
|
|
78
|
+
async function getToken() {
|
|
79
|
+
const r = await fetch("/api/reactor/token", { method: "POST" });
|
|
80
|
+
const { jwt } = await r.json();
|
|
81
|
+
return jwt;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const tokenPromise = getToken();
|
|
85
|
+
|
|
86
|
+
export default function App() {
|
|
87
|
+
const token = use(tokenPromise);
|
|
88
|
+
return (
|
|
89
|
+
<FastH3Provider jwtToken={token} connectOptions={{ autoConnect: true }}>
|
|
90
|
+
<ReactorView className="w-full aspect-video" />
|
|
91
|
+
</FastH3Provider>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Connect
|
|
99
|
+
|
|
100
|
+
### JavaScript
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
104
|
+
|
|
105
|
+
const fastH3 = new FastH3Model();
|
|
106
|
+
await fastH3.connect(jwt);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### React
|
|
110
|
+
|
|
111
|
+
The provider takes the JWT as a prop; fetch it from the same `/api/reactor/token` route the Authenticate example mints:
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
"use client";
|
|
115
|
+
|
|
116
|
+
import { use } from "react";
|
|
117
|
+
import { FastH3Provider, useFastH3 } from "@reactor-models/fast-h3";
|
|
118
|
+
|
|
119
|
+
async function getToken() {
|
|
120
|
+
const r = await fetch("/api/reactor/token", { method: "POST" });
|
|
121
|
+
const { jwt } = await r.json();
|
|
122
|
+
return jwt;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const tokenPromise = getToken();
|
|
126
|
+
|
|
127
|
+
function Controller() {
|
|
128
|
+
const { status } = useFastH3();
|
|
129
|
+
return <span>Status: {status}</span>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export default function App() {
|
|
133
|
+
const token = use(tokenPromise);
|
|
134
|
+
return (
|
|
135
|
+
<FastH3Provider jwtToken={token}>
|
|
136
|
+
<Controller />
|
|
137
|
+
</FastH3Provider>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Events
|
|
145
|
+
|
|
146
|
+
Client-to-model commands. The typed surface is `FastH3Model` (one method per event) in plain JS, and `useFastH3()` in React — every field name below matches the parameter name the method accepts. Every awaited call resolves once the model's handler has completed; a command whose handler returns a message resolves with that reply (see each event's "Returns" line).
|
|
147
|
+
|
|
148
|
+
### `pop`
|
|
149
|
+
|
|
150
|
+
Remove one clip by its UUID from whichever queue holds it, freeing its slot. Works on generating and built clips alike; a build already running for it is discarded when it completes. The clip that is playing is in neither queue — [`stop`](#stop) is the command that cuts it. A built clip stays in `queue_update.history` after popping, so clips continued from it are unaffected; an unbuilt clip that queued clips continue from is refused, since popping it would leave them nothing to open from — pop those first. Emits [`clip_popped`](#clip_popped), [`queue_update`](#queue_update) and [`state_update`](#state_update), or [`command_error`](#command_error) when no queued clip has that id or queued clips still continue from it.
|
|
151
|
+
|
|
152
|
+
Returns: [`clip_popped`](#clip_popped) — `{ type: "clip_popped", clip: null }` (or `undefined` when the send fails).
|
|
153
|
+
|
|
154
|
+
| Parameter | Type | Description |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| `clip_id` | `string` | UUID of the queued clip to remove, from [`clip_queued`](#clip_queued) or [`queue_update`](#queue_update). _(default `""`)_ |
|
|
157
|
+
|
|
158
|
+
#### JavaScript
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
162
|
+
|
|
163
|
+
const fastH3 = new FastH3Model();
|
|
164
|
+
await fastH3.connect(jwt);
|
|
165
|
+
|
|
166
|
+
const reply = await fastH3.pop({ clip_id: "" });
|
|
167
|
+
|
|
168
|
+
if (reply) {
|
|
169
|
+
console.log("clip_popped", reply.clip);
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### React
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
"use client";
|
|
177
|
+
import { useFastH3 } from "@reactor-models/fast-h3";
|
|
178
|
+
|
|
179
|
+
function Example() {
|
|
180
|
+
const { pop } = useFastH3();
|
|
181
|
+
|
|
182
|
+
return <button onClick={() => pop({ clip_id: "" })}>pop</button>;
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### `move`
|
|
187
|
+
|
|
188
|
+
Reposition one clip within the queue that holds it — the generation queue for a clip still to build, the playout queue for a built one; clips never move between queues except by building. `position` 0 is the front: the next build, or what bare [`play`](#play) and autoplay take next. Values past the end mean the back. Replies [`clip_moved`](#clip_moved) with the queue and the resulting position, and emits [`queue_update`](#queue_update); [`command_error`](#command_error) when no queued clip has that id.
|
|
189
|
+
|
|
190
|
+
Returns: [`clip_moved`](#clip_moved) — `{ type: "clip_moved", clip: null, queue: "", position: 0 }` (or `undefined` when the send fails).
|
|
191
|
+
|
|
192
|
+
| Parameter | Type | Description |
|
|
193
|
+
|---|---|---|
|
|
194
|
+
| `clip_id` | `string` | UUID of the queued clip to move, from any clip-referencing message. _(default `""`)_ |
|
|
195
|
+
| `position` | `number` | Target position in the clip's queue, 0 = front; clamped to the end. _(min 0, default `0`)_ |
|
|
196
|
+
|
|
197
|
+
#### JavaScript
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
201
|
+
|
|
202
|
+
const fastH3 = new FastH3Model();
|
|
203
|
+
await fastH3.connect(jwt);
|
|
204
|
+
|
|
205
|
+
const reply = await fastH3.move({ clip_id: "", position: 0 });
|
|
206
|
+
|
|
207
|
+
if (reply) {
|
|
208
|
+
console.log(
|
|
209
|
+
"clip_moved",
|
|
210
|
+
reply.clip,
|
|
211
|
+
reply.queue,
|
|
212
|
+
reply.position,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
#### React
|
|
218
|
+
|
|
219
|
+
```tsx
|
|
220
|
+
"use client";
|
|
221
|
+
import { useFastH3 } from "@reactor-models/fast-h3";
|
|
222
|
+
|
|
223
|
+
function Example() {
|
|
224
|
+
const { move } = useFastH3();
|
|
225
|
+
|
|
226
|
+
return <button onClick={() => move({ clip_id: "", position: 0 })}>move</button>;
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### `play`
|
|
231
|
+
|
|
232
|
+
Play one clip from the playout queue. Blank `clip_id` plays the front clip; a UUID plays that specific one. Playing consumes the entry: it leaves the queue, [`clip_started`](#clip_started) marks its first frames, and when it ends the stream holds on black until the next [`play`](#play). Emits [`queue_update`](#queue_update) and [`state_update`](#state_update), or [`command_error`](#command_error) when a clip is already playing, the id is unknown, or the clip is still generating.
|
|
233
|
+
|
|
234
|
+
Returns: nothing — the awaited call resolves `undefined` once the model's handler has run.
|
|
235
|
+
|
|
236
|
+
| Parameter | Type | Description |
|
|
237
|
+
|---|---|---|
|
|
238
|
+
| `clip_id` | `string` | UUID of the clip to play, from [`clip_generated`](#clip_generated) or [`queue_update`](#queue_update). Blank plays the playout queue's front clip. _(default `""`)_ |
|
|
239
|
+
|
|
240
|
+
#### JavaScript
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
244
|
+
|
|
245
|
+
const fastH3 = new FastH3Model();
|
|
246
|
+
await fastH3.connect(jwt);
|
|
247
|
+
|
|
248
|
+
await fastH3.play({ clip_id: "" });
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
#### React
|
|
252
|
+
|
|
253
|
+
```tsx
|
|
254
|
+
"use client";
|
|
255
|
+
import { useFastH3 } from "@reactor-models/fast-h3";
|
|
256
|
+
|
|
257
|
+
function Example() {
|
|
258
|
+
const { play } = useFastH3();
|
|
259
|
+
|
|
260
|
+
return <button onClick={() => play({ clip_id: "" })}>play</button>;
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### `stop`
|
|
265
|
+
|
|
266
|
+
Cut the clip that is playing. Whatever is queued on the output tracks is dropped and the picture goes to black within a fraction of a second (with [`set_flush_on_clip_end`](#setflushonclipend) off, the transport drains what it holds and freezes on the last frame instead), and the session is back where a finished clip leaves it — the queue is untouched and the next [`play`](#play) starts clean. With autoplay on this acts as a skip: the next ready clip starts on its own, so send [`set_autoplay`](#setautoplay) off first to hold the stream. Emits [`clip_stopped`](#clip_stopped) and [`state_update`](#state_update), or [`command_error`](#command_error) when no clip is playing.
|
|
267
|
+
|
|
268
|
+
Returns: nothing — the awaited call resolves `undefined` once the model's handler has run.
|
|
269
|
+
|
|
270
|
+
_No parameters._
|
|
271
|
+
|
|
272
|
+
#### JavaScript
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
276
|
+
|
|
277
|
+
const fastH3 = new FastH3Model();
|
|
278
|
+
await fastH3.connect(jwt);
|
|
279
|
+
|
|
280
|
+
await fastH3.stop();
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
#### React
|
|
284
|
+
|
|
285
|
+
```tsx
|
|
286
|
+
"use client";
|
|
287
|
+
import { useFastH3 } from "@reactor-models/fast-h3";
|
|
288
|
+
|
|
289
|
+
function Example() {
|
|
290
|
+
const { stop } = useFastH3();
|
|
291
|
+
|
|
292
|
+
return <button onClick={() => stop()}>stop</button>;
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### `reset`
|
|
297
|
+
|
|
298
|
+
Return every condition to its default, drop both queues' clips and the retained history, and clear the output tracks. A clip that is playing is cut, with a [`clip_stopped`](#clip_stopped) to mark it. Valid at any time. Replies [`session_reset`](#session_reset) and emits [`queue_update`](#queue_update) and [`state_update`](#state_update).
|
|
299
|
+
|
|
300
|
+
Returns: [`session_reset`](#session_reset) — `{ type: "session_reset", was_playing: true, cleared_clips: 0 }` (or `undefined` when the send fails).
|
|
301
|
+
|
|
302
|
+
_No parameters._
|
|
303
|
+
|
|
304
|
+
#### JavaScript
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
308
|
+
|
|
309
|
+
const fastH3 = new FastH3Model();
|
|
310
|
+
await fastH3.connect(jwt);
|
|
311
|
+
|
|
312
|
+
const reply = await fastH3.reset();
|
|
313
|
+
|
|
314
|
+
if (reply) {
|
|
315
|
+
console.log("session_reset", reply.was_playing, reply.cleared_clips);
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### React
|
|
320
|
+
|
|
321
|
+
```tsx
|
|
322
|
+
"use client";
|
|
323
|
+
import { useFastH3 } from "@reactor-models/fast-h3";
|
|
324
|
+
|
|
325
|
+
function Example() {
|
|
326
|
+
const { reset } = useFastH3();
|
|
327
|
+
|
|
328
|
+
return <button onClick={() => reset()}>reset</button>;
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### `enqueue`
|
|
333
|
+
|
|
334
|
+
Queue one clip generation. The clip enters the generation queue (at `position`, or the back), builds when its turn comes, and then joins the back of the playout queue, announced by [`clip_generated`](#clip_generated). The prompt is what the clip will show; the metadata is an opaque string echoed back on every message that references the clip, for frontends to carry their own tracking data. The clip opens from text alone, from an uploaded still (`starting_frame` — the image animates forward), or from an existing clip's last frame (`continue_from_clip_id` — any clip in the queues or in `queue_update.history`); a continued clip simply waits its turn until its source is built, wherever the two sit in the queue. The clip's canvas is the session's; its length is the `seconds` passed here (snapped to what the model can produce) or the session default, and its seed is the one passed here or the session's advancing default. Builds run through the queue in order; watch [`queue_update`](#queue_update) for the clip turning ready. Replies [`clip_queued`](#clip_queued) with the clip's UUID and emits [`queue_update`](#queue_update) and [`state_update`](#state_update), or [`command_error`](#command_error) when the queue is full, the prompt is empty, both a starting frame and a source clip are given, the source clip is unknown or no longer retained, or the upload is not a decodable image.
|
|
335
|
+
|
|
336
|
+
Returns: [`clip_queued`](#clip_queued) — `{ type: "clip_queued", clip: null }` (or `undefined` when the send fails).
|
|
337
|
+
|
|
338
|
+
| Parameter | Type | Description |
|
|
339
|
+
|---|---|---|
|
|
340
|
+
| `seed` | `number \| null` | Seed for this clip. Omitted or null, the session's default is used and advances by one; passing a seed leaves the default untouched, so explicit and automatic seeding do not interfere. _(min 0, default `null`)_ |
|
|
341
|
+
| `prompt` | `string` | What the clip should show, up to 800 characters. Fixed once enqueued; a different scene is a new [`enqueue`](#enqueue). _(maxLength 800, default `""`)_ |
|
|
342
|
+
| `seconds` | `number \| null` | Length of this clip in seconds, between 5.167 and 14.375, snapped to the nearest length the model can produce; the clip's structure reports the effective value. Omitted or null, the session default applies. A length the deployment has not built before pays a one-off compile cost on its first build. _(min 5.167, max 14.375, default `null`)_ |
|
|
343
|
+
| `metadata` | `string` | Free-form string stored with the clip and echoed back on every message that references it. The model never reads it; use it to correlate clips with your own records — who asked for it, which group it belongs to, display text. _(maxLength 2000, default `""`)_ |
|
|
344
|
+
| `position` | `number \| null` | Where the clip enters the generation queue: 0 is the front (the next build), larger values count back from there, and anything past the end — or omitted — appends. The clip already building is unaffected either way. [`queue_update`](#queue_update) reports the resulting order. _(min 0, default `null`)_ |
|
|
345
|
+
| `starting_frame` | `FileRef \| null` | A still image the clip opens from and animates forward — image-to-video. Common formats decode; the frame is fitted to the session canvas. To continue from a video, extract the frame you want and send it here. Omit for a clip opening from text or from another clip; at most one of this and `continue_from_clip_id`. _(default `null`)_ |
|
|
346
|
+
| `continue_from_clip_id` | `string` | UUID of the clip whose last frame this one opens from and animates forward — how clips chain into a continuing scene. Any clip in either queue or in `queue_update.history` qualifies, including one that has not built yet: this clip then waits for it. Blank for a clip opening from text or from an uploaded frame; at most one of this and `starting_frame`. _(default `""`)_ |
|
|
347
|
+
|
|
348
|
+
#### JavaScript
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
352
|
+
|
|
353
|
+
const fastH3 = new FastH3Model();
|
|
354
|
+
await fastH3.connect(jwt);
|
|
355
|
+
|
|
356
|
+
const fileRef = await fastH3.uploadFile(blob);
|
|
357
|
+
const reply = await fastH3.enqueue({ starting_frame: fileRef, seed: null, prompt: "A sunset over the ocean", seconds: null, metadata: "", position: null, continue_from_clip_id: "" });
|
|
358
|
+
|
|
359
|
+
if (reply) {
|
|
360
|
+
console.log("clip_queued", reply.clip);
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
#### React
|
|
365
|
+
|
|
366
|
+
```tsx
|
|
367
|
+
"use client";
|
|
368
|
+
import { useFastH3 } from "@reactor-models/fast-h3";
|
|
369
|
+
|
|
370
|
+
function Example() {
|
|
371
|
+
const { enqueue, uploadFile } = useFastH3();
|
|
372
|
+
|
|
373
|
+
async function handlePick(file: File) {
|
|
374
|
+
const ref = await uploadFile(file);
|
|
375
|
+
await enqueue({ starting_frame: ref, seed: null, prompt: "A sunset over the ocean", seconds: null, metadata: "", position: null, continue_from_clip_id: "" });
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return <input type="file" onChange={(e) => handlePick(e.target.files![0])} />;
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### `setSeed`
|
|
383
|
+
|
|
384
|
+
Set the default seed — the one an [`enqueue`](#enqueue) without a seed of its own uses, advancing it by one, so re-enqueuing the same prompts in the same order reproduces the same clips. Clips already in the queue keep the seed they were enqueued with. Valid at any time. Emits [`seed_accepted`](#seed_accepted) and [`state_update`](#state_update).
|
|
385
|
+
|
|
386
|
+
Returns: [`seed_accepted`](#seed_accepted) — `{ type: "seed_accepted", seed: 0 }` (or `undefined` when the send fails).
|
|
387
|
+
|
|
388
|
+
| Parameter | Type | Description |
|
|
389
|
+
|---|---|---|
|
|
390
|
+
| `seed` | `number` | Default seed for enqueues that carry none. Reproduction is close rather than exact: the deployment runs fused kernels that can reorder arithmetic. _(min 0, default `1000`)_ |
|
|
391
|
+
|
|
392
|
+
#### JavaScript
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
396
|
+
|
|
397
|
+
const fastH3 = new FastH3Model();
|
|
398
|
+
await fastH3.connect(jwt);
|
|
399
|
+
|
|
400
|
+
const reply = await fastH3.setSeed({ seed: 1000 });
|
|
401
|
+
|
|
402
|
+
if (reply) {
|
|
403
|
+
console.log("seed_accepted", reply.seed);
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
#### React
|
|
408
|
+
|
|
409
|
+
```tsx
|
|
410
|
+
"use client";
|
|
411
|
+
import { useFastH3 } from "@reactor-models/fast-h3";
|
|
412
|
+
|
|
413
|
+
function Example() {
|
|
414
|
+
const { setSeed } = useFastH3();
|
|
415
|
+
|
|
416
|
+
return <button onClick={() => setSeed({ seed: 1000 })}>setSeed</button>;
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### `getQueue`
|
|
421
|
+
|
|
422
|
+
Return both queues' contents — `generation` (waiting to build) and `playout` (built, playable) — plus `history`, the built clips no longer queued that `continue_from_clip_id` can still name, every clip as its full structure. The same payload the model broadcasts as [`queue_update`](#queue_update). Valid at any time.
|
|
423
|
+
|
|
424
|
+
Returns: [`queue_update`](#queue_update) — `{ type: "queue_update", history: null, playout: null, generation: null }` (or `undefined` when the send fails).
|
|
425
|
+
|
|
426
|
+
_No parameters._
|
|
427
|
+
|
|
428
|
+
#### JavaScript
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
432
|
+
|
|
433
|
+
const fastH3 = new FastH3Model();
|
|
434
|
+
await fastH3.connect(jwt);
|
|
435
|
+
|
|
436
|
+
const reply = await fastH3.getQueue();
|
|
437
|
+
|
|
438
|
+
if (reply) {
|
|
439
|
+
console.log(
|
|
440
|
+
"queue_update",
|
|
441
|
+
reply.history,
|
|
442
|
+
reply.playout,
|
|
443
|
+
reply.generation,
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
#### React
|
|
449
|
+
|
|
450
|
+
```tsx
|
|
451
|
+
"use client";
|
|
452
|
+
import { useFastH3 } from "@reactor-models/fast-h3";
|
|
453
|
+
|
|
454
|
+
function Example() {
|
|
455
|
+
const { getQueue } = useFastH3();
|
|
456
|
+
|
|
457
|
+
return <button onClick={() => getQueue()}>getQueue</button>;
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### `getState`
|
|
462
|
+
|
|
463
|
+
Return a snapshot of everything the session exposes except the queue's contents ([`get_queue`](#getqueue) carries those): the conditions in force, what is playing, progress counters, and the commands that are valid right now. The same payload the model broadcasts as [`state_update`](#state_update). Valid at any time.
|
|
464
|
+
|
|
465
|
+
Returns: [`state_update`](#state_update) — `{ type: "state_update", seed: 0, width: 0, aspect: "", height: 0, playing: true, autoplay: true, clip_seconds: 0, clips_played: 0, seconds_sent: 0, playout_queued: 0, valid_commands: null, playing_clip_id: null, clip_seconds_max: 0, clip_seconds_min: 0, playout_capacity: 0, flush_on_clip_end: true, generation_queued: 0, generation_capacity: 0 }` (or `undefined` when the send fails).
|
|
466
|
+
|
|
467
|
+
_No parameters._
|
|
468
|
+
|
|
469
|
+
#### JavaScript
|
|
470
|
+
|
|
471
|
+
```typescript
|
|
472
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
473
|
+
|
|
474
|
+
const fastH3 = new FastH3Model();
|
|
475
|
+
await fastH3.connect(jwt);
|
|
476
|
+
|
|
477
|
+
const reply = await fastH3.getState();
|
|
478
|
+
|
|
479
|
+
if (reply) {
|
|
480
|
+
console.log(
|
|
481
|
+
"state_update",
|
|
482
|
+
reply.seed,
|
|
483
|
+
reply.width,
|
|
484
|
+
reply.aspect,
|
|
485
|
+
reply.height,
|
|
486
|
+
reply.playing,
|
|
487
|
+
reply.autoplay,
|
|
488
|
+
reply.clip_seconds,
|
|
489
|
+
reply.clips_played,
|
|
490
|
+
reply.seconds_sent,
|
|
491
|
+
reply.playout_queued,
|
|
492
|
+
reply.valid_commands,
|
|
493
|
+
reply.playing_clip_id,
|
|
494
|
+
reply.clip_seconds_max,
|
|
495
|
+
reply.clip_seconds_min,
|
|
496
|
+
reply.playout_capacity,
|
|
497
|
+
reply.flush_on_clip_end,
|
|
498
|
+
reply.generation_queued,
|
|
499
|
+
reply.generation_capacity,
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
#### React
|
|
505
|
+
|
|
506
|
+
```tsx
|
|
507
|
+
"use client";
|
|
508
|
+
import { useFastH3 } from "@reactor-models/fast-h3";
|
|
509
|
+
|
|
510
|
+
function Example() {
|
|
511
|
+
const { getState } = useFastH3();
|
|
512
|
+
|
|
513
|
+
return <button onClick={() => getState()}>getState</button>;
|
|
514
|
+
}
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### `setCanvas`
|
|
518
|
+
|
|
519
|
+
Choose the aspect ratio of `main_video`. The video track keeps one size and queued clips are built at it, so this is only valid while the queue is empty and nothing is playing. Emits [`canvas_accepted`](#canvas_accepted), carrying the exact pixel size, and [`state_update`](#state_update), or [`command_error`](#command_error) while clips are queued or playing, or when the ratio is not one this model offers.
|
|
520
|
+
|
|
521
|
+
Returns: [`canvas_accepted`](#canvas_accepted) — `{ type: "canvas_accepted", width: 0, aspect: "", height: 0 }` (or `undefined` when the send fails).
|
|
522
|
+
|
|
523
|
+
| Parameter | Type | Description |
|
|
524
|
+
|---|---|---|
|
|
525
|
+
| `aspect` | `"16:9" \| "1:1" \| "9:16" \| "4:3"` | Aspect ratio of `main_video`. [`canvas_accepted`](#canvas_accepted) and [`state_update`](#state_update) report the width and height in pixels it resolves to. _(default `"16:9"`)_ |
|
|
526
|
+
|
|
527
|
+
#### JavaScript
|
|
528
|
+
|
|
529
|
+
```typescript
|
|
530
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
531
|
+
|
|
532
|
+
const fastH3 = new FastH3Model();
|
|
533
|
+
await fastH3.connect(jwt);
|
|
534
|
+
|
|
535
|
+
const reply = await fastH3.setCanvas({ aspect: "16:9" });
|
|
536
|
+
|
|
537
|
+
if (reply) {
|
|
538
|
+
console.log(
|
|
539
|
+
"canvas_accepted",
|
|
540
|
+
reply.width,
|
|
541
|
+
reply.aspect,
|
|
542
|
+
reply.height,
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
#### React
|
|
548
|
+
|
|
549
|
+
```tsx
|
|
550
|
+
"use client";
|
|
551
|
+
import { useFastH3 } from "@reactor-models/fast-h3";
|
|
552
|
+
|
|
553
|
+
function Example() {
|
|
554
|
+
const { setCanvas } = useFastH3();
|
|
555
|
+
|
|
556
|
+
return <button onClick={() => setCanvas({ aspect: "16:9" })}>setCanvas</button>;
|
|
557
|
+
}
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### `setAutoplay`
|
|
561
|
+
|
|
562
|
+
Turn autoplay on or off. On, the playout queue's front clip starts on its own whenever nothing is playing — right after a clip finishes, or the moment a build completes while the stream is idle — so a steadily fed queue plays through without a [`play`](#play) per clip. Off (the default), the stream holds on black until an explicit [`play`](#play). Takes effect immediately and lasts for the session. Emits [`autoplay_accepted`](#autoplay_accepted) and [`state_update`](#state_update).
|
|
563
|
+
|
|
564
|
+
Returns: [`autoplay_accepted`](#autoplay_accepted) — `{ type: "autoplay_accepted", enabled: true }` (or `undefined` when the send fails).
|
|
565
|
+
|
|
566
|
+
| Parameter | Type | Description |
|
|
567
|
+
|---|---|---|
|
|
568
|
+
| `enabled` | `boolean` | True plays the playout queue front-first on its own; false holds the stream after each clip until [`play`](#play). _(default `false`)_ |
|
|
569
|
+
|
|
570
|
+
#### JavaScript
|
|
571
|
+
|
|
572
|
+
```typescript
|
|
573
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
574
|
+
|
|
575
|
+
const fastH3 = new FastH3Model();
|
|
576
|
+
await fastH3.connect(jwt);
|
|
577
|
+
|
|
578
|
+
const reply = await fastH3.setAutoplay({ enabled: false });
|
|
579
|
+
|
|
580
|
+
if (reply) {
|
|
581
|
+
console.log("autoplay_accepted", reply.enabled);
|
|
582
|
+
}
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
#### React
|
|
586
|
+
|
|
587
|
+
```tsx
|
|
588
|
+
"use client";
|
|
589
|
+
import { useFastH3 } from "@reactor-models/fast-h3";
|
|
590
|
+
|
|
591
|
+
function Example() {
|
|
592
|
+
const { setAutoplay } = useFastH3();
|
|
593
|
+
|
|
594
|
+
return <button onClick={() => setAutoplay({ enabled: false })}>setAutoplay</button>;
|
|
595
|
+
}
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
### `setClipSeconds`
|
|
599
|
+
|
|
600
|
+
Set the default length for enqueues that carry no `seconds` of their own. The value is snapped to the nearest length the model can produce, so read the effective one back from [`clip_length_accepted`](#clip_length_accepted). Clips already in the queue keep the length they were enqueued with. Longer clips carry a scene further; shorter ones build faster. Valid at any time. Emits [`clip_length_accepted`](#clip_length_accepted) and [`state_update`](#state_update).
|
|
601
|
+
|
|
602
|
+
Returns: [`clip_length_accepted`](#clip_length_accepted) — `{ type: "clip_length_accepted", frames: 0, clip_seconds: 0 }` (or `undefined` when the send fails).
|
|
603
|
+
|
|
604
|
+
| Parameter | Type | Description |
|
|
605
|
+
|---|---|---|
|
|
606
|
+
| `seconds` | `number` | Clip length in seconds, between 5.167 and 14.375. Snapped to the nearest length the model can produce, so the value that takes effect can differ slightly; `state_update.clip_seconds` always carries the one in force. _(min 5.167, max 14.375, default `14.375`)_ |
|
|
607
|
+
|
|
608
|
+
#### JavaScript
|
|
609
|
+
|
|
610
|
+
```typescript
|
|
611
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
612
|
+
|
|
613
|
+
const fastH3 = new FastH3Model();
|
|
614
|
+
await fastH3.connect(jwt);
|
|
615
|
+
|
|
616
|
+
const reply = await fastH3.setClipSeconds({ seconds: 14.375 });
|
|
617
|
+
|
|
618
|
+
if (reply) {
|
|
619
|
+
console.log("clip_length_accepted", reply.frames, reply.clip_seconds);
|
|
620
|
+
}
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
#### React
|
|
624
|
+
|
|
625
|
+
```tsx
|
|
626
|
+
"use client";
|
|
627
|
+
import { useFastH3 } from "@reactor-models/fast-h3";
|
|
628
|
+
|
|
629
|
+
function Example() {
|
|
630
|
+
const { setClipSeconds } = useFastH3();
|
|
631
|
+
|
|
632
|
+
return <button onClick={() => setClipSeconds({ seconds: 14.375 })}>setClipSeconds</button>;
|
|
633
|
+
}
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### `setFlushOnClipEnd`
|
|
637
|
+
|
|
638
|
+
Set whether the stream cuts to black when a clip ends, is stopped, or a non-continuing clip follows it. On (the default) those boundaries flush to black at once. Off, the stream holds the last frame instead — [`stop`](#stop) then drains what the transport already holds (up to a couple of seconds) before the picture freezes, rather than snapping to black. Either way, autoplay chains a clip whose `continue_from_clip_id` names the clip just finished with no cut at all, and [`reset`](#reset) always clears the tracks. Takes effect at the next boundary and lasts for the session. Emits [`flush_accepted`](#flush_accepted) and [`state_update`](#state_update).
|
|
639
|
+
|
|
640
|
+
Returns: [`flush_accepted`](#flush_accepted) — `{ type: "flush_accepted", enabled: true }` (or `undefined` when the send fails).
|
|
641
|
+
|
|
642
|
+
| Parameter | Type | Description |
|
|
643
|
+
|---|---|---|
|
|
644
|
+
| `enabled` | `boolean` | True cuts to black at every non-continuing clip boundary; false holds the last frame there instead. _(default `true`)_ |
|
|
645
|
+
|
|
646
|
+
#### JavaScript
|
|
647
|
+
|
|
648
|
+
```typescript
|
|
649
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
650
|
+
|
|
651
|
+
const fastH3 = new FastH3Model();
|
|
652
|
+
await fastH3.connect(jwt);
|
|
653
|
+
|
|
654
|
+
const reply = await fastH3.setFlushOnClipEnd({ enabled: true });
|
|
655
|
+
|
|
656
|
+
if (reply) {
|
|
657
|
+
console.log("flush_accepted", reply.enabled);
|
|
658
|
+
}
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
#### React
|
|
662
|
+
|
|
663
|
+
```tsx
|
|
664
|
+
"use client";
|
|
665
|
+
import { useFastH3 } from "@reactor-models/fast-h3";
|
|
666
|
+
|
|
667
|
+
function Example() {
|
|
668
|
+
const { setFlushOnClipEnd } = useFastH3();
|
|
669
|
+
|
|
670
|
+
return <button onClick={() => setFlushOnClipEnd({ enabled: true })}>setFlushOnClipEnd</button>;
|
|
671
|
+
}
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
## Messages
|
|
675
|
+
|
|
676
|
+
Model-to-client messages. Register a typed listener with `on…` on `FastH3Model`, or a `useFastH3…` hook in React, to receive only the messages you care about.
|
|
677
|
+
|
|
678
|
+
### `clip_moved`
|
|
679
|
+
|
|
680
|
+
Emitted when [`move`](#move) repositions a clip within its queue.
|
|
681
|
+
|
|
682
|
+
Listener: `onClipMoved` · React hook: `useFastH3ClipMoved`
|
|
683
|
+
|
|
684
|
+
| Field | Type | Description |
|
|
685
|
+
|---|---|---|
|
|
686
|
+
| `clip` | `{ "seed": number; "ready": boolean; "frames": number; "prompt": string; "clip_id": string; "seconds": number; "metadata": string; "has_starting_frame": boolean; "continue_from_clip_id": string \| null }` | The clip that moved. |
|
|
687
|
+
| `queue` | `string` | Which queue it moved within: `generation` or `playout`. |
|
|
688
|
+
| `position` | `number` | The clip's resulting position in that queue, 0 = front. |
|
|
689
|
+
|
|
690
|
+
#### JavaScript
|
|
691
|
+
|
|
692
|
+
```typescript
|
|
693
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
694
|
+
|
|
695
|
+
const fastH3 = new FastH3Model();
|
|
696
|
+
fastH3.onClipMoved((msg) => {
|
|
697
|
+
console.log(
|
|
698
|
+
"clip_moved",
|
|
699
|
+
msg.clip,
|
|
700
|
+
msg.queue,
|
|
701
|
+
msg.position,
|
|
702
|
+
);
|
|
703
|
+
});
|
|
704
|
+
await fastH3.connect(jwt);
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
#### React
|
|
708
|
+
|
|
709
|
+
```tsx
|
|
710
|
+
import { useFastH3ClipMoved } from "@reactor-models/fast-h3";
|
|
711
|
+
|
|
712
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
713
|
+
useFastH3ClipMoved((msg) => {
|
|
714
|
+
console.log(
|
|
715
|
+
"clip_moved",
|
|
716
|
+
msg.clip,
|
|
717
|
+
msg.queue,
|
|
718
|
+
msg.position,
|
|
719
|
+
);
|
|
720
|
+
});
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
### `clip_failed`
|
|
724
|
+
|
|
725
|
+
Emitted when a clip's generation fails.
|
|
726
|
+
|
|
727
|
+
The clip leaves the queue and the queue moves on; nothing else is
|
|
728
|
+
affected.
|
|
729
|
+
|
|
730
|
+
Listener: `onClipFailed` · React hook: `useFastH3ClipFailed`
|
|
731
|
+
|
|
732
|
+
| Field | Type | Description |
|
|
733
|
+
|---|---|---|
|
|
734
|
+
| `clip` | `{ "seed": number; "ready": boolean; "frames": number; "prompt": string; "clip_id": string; "seconds": number; "metadata": string; "has_starting_frame": boolean; "continue_from_clip_id": string \| null }` | The clip whose build failed. |
|
|
735
|
+
| `reason` | `string` | What went wrong. |
|
|
736
|
+
|
|
737
|
+
#### JavaScript
|
|
738
|
+
|
|
739
|
+
```typescript
|
|
740
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
741
|
+
|
|
742
|
+
const fastH3 = new FastH3Model();
|
|
743
|
+
fastH3.onClipFailed((msg) => {
|
|
744
|
+
console.log("clip_failed", msg.clip, msg.reason);
|
|
745
|
+
});
|
|
746
|
+
await fastH3.connect(jwt);
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
#### React
|
|
750
|
+
|
|
751
|
+
```tsx
|
|
752
|
+
import { useFastH3ClipFailed } from "@reactor-models/fast-h3";
|
|
753
|
+
|
|
754
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
755
|
+
useFastH3ClipFailed((msg) => {
|
|
756
|
+
console.log("clip_failed", msg.clip, msg.reason);
|
|
757
|
+
});
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
### `clip_popped`
|
|
761
|
+
|
|
762
|
+
Emitted when [`pop`](#pop) removes a clip from either queue.
|
|
763
|
+
|
|
764
|
+
The clip's slot is free again immediately. A build already running for it
|
|
765
|
+
is discarded when it completes; the GPUs cannot abandon it mid-build.
|
|
766
|
+
|
|
767
|
+
Listener: `onClipPopped` · React hook: `useFastH3ClipPopped`
|
|
768
|
+
|
|
769
|
+
| Field | Type | Description |
|
|
770
|
+
|---|---|---|
|
|
771
|
+
| `clip` | `{ "seed": number; "ready": boolean; "frames": number; "prompt": string; "clip_id": string; "seconds": number; "metadata": string; "has_starting_frame": boolean; "continue_from_clip_id": string \| null }` | The clip that left its queue. |
|
|
772
|
+
|
|
773
|
+
#### JavaScript
|
|
774
|
+
|
|
775
|
+
```typescript
|
|
776
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
777
|
+
|
|
778
|
+
const fastH3 = new FastH3Model();
|
|
779
|
+
fastH3.onClipPopped((msg) => {
|
|
780
|
+
console.log("clip_popped", msg.clip);
|
|
781
|
+
});
|
|
782
|
+
await fastH3.connect(jwt);
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
#### React
|
|
786
|
+
|
|
787
|
+
```tsx
|
|
788
|
+
import { useFastH3ClipPopped } from "@reactor-models/fast-h3";
|
|
789
|
+
|
|
790
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
791
|
+
useFastH3ClipPopped((msg) => {
|
|
792
|
+
console.log("clip_popped", msg.clip);
|
|
793
|
+
});
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
### `clip_queued`
|
|
797
|
+
|
|
798
|
+
Emitted when [`enqueue`](#enqueue) accepts a generation request.
|
|
799
|
+
|
|
800
|
+
Listener: `onClipQueued` · React hook: `useFastH3ClipQueued`
|
|
801
|
+
|
|
802
|
+
| Field | Type | Description |
|
|
803
|
+
|---|---|---|
|
|
804
|
+
| `clip` | `{ "seed": number; "ready": boolean; "frames": number; "prompt": string; "clip_id": string; "seconds": number; "metadata": string; "has_starting_frame": boolean; "continue_from_clip_id": string \| null }` | The queued clip, UUID included. `ready` is false here; [`clip_generated`](#clip_generated) announces it crossing into the playout queue. |
|
|
805
|
+
|
|
806
|
+
#### JavaScript
|
|
807
|
+
|
|
808
|
+
```typescript
|
|
809
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
810
|
+
|
|
811
|
+
const fastH3 = new FastH3Model();
|
|
812
|
+
fastH3.onClipQueued((msg) => {
|
|
813
|
+
console.log("clip_queued", msg.clip);
|
|
814
|
+
});
|
|
815
|
+
await fastH3.connect(jwt);
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
#### React
|
|
819
|
+
|
|
820
|
+
```tsx
|
|
821
|
+
import { useFastH3ClipQueued } from "@reactor-models/fast-h3";
|
|
822
|
+
|
|
823
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
824
|
+
useFastH3ClipQueued((msg) => {
|
|
825
|
+
console.log("clip_queued", msg.clip);
|
|
826
|
+
});
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
### `clip_started`
|
|
830
|
+
|
|
831
|
+
Emitted as a clip begins streaming on the output tracks.
|
|
832
|
+
|
|
833
|
+
Listener: `onClipStarted` · React hook: `useFastH3ClipStarted`
|
|
834
|
+
|
|
835
|
+
| Field | Type | Description |
|
|
836
|
+
|---|---|---|
|
|
837
|
+
| `clip` | `{ "seed": number; "ready": boolean; "frames": number; "prompt": string; "clip_id": string; "seconds": number; "metadata": string; "has_starting_frame": boolean; "continue_from_clip_id": string \| null }` | The clip now playing. |
|
|
838
|
+
|
|
839
|
+
#### JavaScript
|
|
840
|
+
|
|
841
|
+
```typescript
|
|
842
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
843
|
+
|
|
844
|
+
const fastH3 = new FastH3Model();
|
|
845
|
+
fastH3.onClipStarted((msg) => {
|
|
846
|
+
console.log("clip_started", msg.clip);
|
|
847
|
+
});
|
|
848
|
+
await fastH3.connect(jwt);
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
#### React
|
|
852
|
+
|
|
853
|
+
```tsx
|
|
854
|
+
import { useFastH3ClipStarted } from "@reactor-models/fast-h3";
|
|
855
|
+
|
|
856
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
857
|
+
useFastH3ClipStarted((msg) => {
|
|
858
|
+
console.log("clip_started", msg.clip);
|
|
859
|
+
});
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
### `clip_stopped`
|
|
863
|
+
|
|
864
|
+
Emitted when [`stop`](#stop) cuts a playing clip.
|
|
865
|
+
|
|
866
|
+
The rest of the clip is discarded — a stopped clip cannot be resumed — and
|
|
867
|
+
the stream holds on black until the next [`play`](#play), exactly as after
|
|
868
|
+
[`clip_finished`](#clip_finished).
|
|
869
|
+
|
|
870
|
+
Listener: `onClipStopped` · React hook: `useFastH3ClipStopped`
|
|
871
|
+
|
|
872
|
+
| Field | Type | Description |
|
|
873
|
+
|---|---|---|
|
|
874
|
+
| `clip` | `{ "seed": number; "ready": boolean; "frames": number; "prompt": string; "clip_id": string; "seconds": number; "metadata": string; "has_starting_frame": boolean; "continue_from_clip_id": string \| null }` | The clip that was cut. |
|
|
875
|
+
| `seconds_sent` | `number` | Seconds of video and audio sent since the session began. |
|
|
876
|
+
|
|
877
|
+
#### JavaScript
|
|
878
|
+
|
|
879
|
+
```typescript
|
|
880
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
881
|
+
|
|
882
|
+
const fastH3 = new FastH3Model();
|
|
883
|
+
fastH3.onClipStopped((msg) => {
|
|
884
|
+
console.log("clip_stopped", msg.clip, msg.seconds_sent);
|
|
885
|
+
});
|
|
886
|
+
await fastH3.connect(jwt);
|
|
887
|
+
```
|
|
888
|
+
|
|
889
|
+
#### React
|
|
890
|
+
|
|
891
|
+
```tsx
|
|
892
|
+
import { useFastH3ClipStopped } from "@reactor-models/fast-h3";
|
|
893
|
+
|
|
894
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
895
|
+
useFastH3ClipStopped((msg) => {
|
|
896
|
+
console.log("clip_stopped", msg.clip, msg.seconds_sent);
|
|
897
|
+
});
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
### `queue_update`
|
|
901
|
+
|
|
902
|
+
Emitted on connect and whenever either queue changes, and answers [`get_queue`](#getqueue).
|
|
903
|
+
|
|
904
|
+
Both queues in full, front first, each entry a complete `ClipInfo`, plus
|
|
905
|
+
the retained history of built clips that can still seed a new one. A
|
|
906
|
+
change is any of: a clip enqueued or [`move`](#move)d, a build finishing (the clip
|
|
907
|
+
crosses from `generation` to `playout`), a clip leaving to play or by
|
|
908
|
+
[`pop`](#pop), or the queues being cleared by [`reset`](#reset).
|
|
909
|
+
|
|
910
|
+
Listener: `onQueueUpdate` · React hook: `useFastH3QueueUpdate`
|
|
911
|
+
|
|
912
|
+
| Field | Type | Description |
|
|
913
|
+
|---|---|---|
|
|
914
|
+
| `history` | `{ "seed": number; "ready": boolean; "frames": number; "prompt": string; "clip_id": string; "seconds": number; "metadata": string; "has_starting_frame": boolean; "continue_from_clip_id": string \| null }[]` | Built clips no longer queued — played, stopped, or popped — whose last frame is still retained, oldest first. No longer playable ([`play`](#play) refuses them), but any can be named in [`enqueue`](#enqueue)'s `continue_from_clip_id`; the oldest are evicted as new builds finish, so the front of this list is what expires next. |
|
|
915
|
+
| `playout` | `{ "seed": number; "ready": boolean; "frames": number; "prompt": string; "clip_id": string; "seconds": number; "metadata": string; "has_starting_frame": boolean; "continue_from_clip_id": string \| null }[]` | Built clips waiting to play, front first. A finished build joins at the back; bare [`play`](#play) (and autoplay) takes the front; [`move`](#move) reorders; playing or [`pop`](#pop) consumes. |
|
|
916
|
+
| `generation` | `{ "seed": number; "ready": boolean; "frames": number; "prompt": string; "clip_id": string; "seconds": number; "metadata": string; "has_starting_frame": boolean; "continue_from_clip_id": string \| null }[]` | Clips waiting to build, front first. Builds consume this queue from the front, one at a time, pausing only while `playout` is at capacity; a clip whose `continue_from_clip_id` source is not built yet is skipped until it is, without blocking the rest. [`enqueue`](#enqueue)'s `position` and [`move`](#move) control the order. |
|
|
917
|
+
|
|
918
|
+
#### JavaScript
|
|
919
|
+
|
|
920
|
+
```typescript
|
|
921
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
922
|
+
|
|
923
|
+
const fastH3 = new FastH3Model();
|
|
924
|
+
fastH3.onQueueUpdate((msg) => {
|
|
925
|
+
console.log(
|
|
926
|
+
"queue_update",
|
|
927
|
+
msg.history,
|
|
928
|
+
msg.playout,
|
|
929
|
+
msg.generation,
|
|
930
|
+
);
|
|
931
|
+
});
|
|
932
|
+
await fastH3.connect(jwt);
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
#### React
|
|
936
|
+
|
|
937
|
+
```tsx
|
|
938
|
+
import { useFastH3QueueUpdate } from "@reactor-models/fast-h3";
|
|
939
|
+
|
|
940
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
941
|
+
useFastH3QueueUpdate((msg) => {
|
|
942
|
+
console.log(
|
|
943
|
+
"queue_update",
|
|
944
|
+
msg.history,
|
|
945
|
+
msg.playout,
|
|
946
|
+
msg.generation,
|
|
947
|
+
);
|
|
948
|
+
});
|
|
949
|
+
```
|
|
950
|
+
|
|
951
|
+
### `state_update`
|
|
952
|
+
|
|
953
|
+
Emitted on connect and after every change to the session's state.
|
|
954
|
+
|
|
955
|
+
One snapshot of everything observable except the queue's contents (those
|
|
956
|
+
travel as [`queue_update`](#queue_update)), so a client can render its whole UI from this
|
|
957
|
+
alone instead of accumulating the individual messages below.
|
|
958
|
+
|
|
959
|
+
Listener: `onStateUpdate` · React hook: `useFastH3StateUpdate`
|
|
960
|
+
|
|
961
|
+
| Field | Type | Description |
|
|
962
|
+
|---|---|---|
|
|
963
|
+
| `seed` | `number` | Seed the next enqueued clip will use when [`enqueue`](#enqueue) carries none; each such enqueue advances it by one. |
|
|
964
|
+
| `width` | `number` | Width of every frame on `main_video`. |
|
|
965
|
+
| `aspect` | `string` | Aspect ratio in effect, e.g. `16:9`. |
|
|
966
|
+
| `height` | `number` | Height of every frame on `main_video`. |
|
|
967
|
+
| `playing` | `boolean` | A clip is streaming on the output tracks. |
|
|
968
|
+
| `autoplay` | `boolean` | The playout queue's front clip starts on its own whenever nothing is playing. Off by default: playback waits for an explicit [`play`](#play). |
|
|
969
|
+
| `clip_seconds` | `number` | Length a newly enqueued clip gets when [`enqueue`](#enqueue) carries no `seconds` of its own. |
|
|
970
|
+
| `clips_played` | `number` | Clips that finished playing or were stopped since the session began. |
|
|
971
|
+
| `seconds_sent` | `number` | Seconds of video and audio sent since the session began. |
|
|
972
|
+
| `playout_queued` | `number` | Built clips in the playout queue, each playable right now. |
|
|
973
|
+
| `valid_commands` | `string[]` | Names of the commands the session would accept right now. Use this to enable or grey out controls instead of re-deriving the state machine client-side; any command not listed would be rejected. |
|
|
974
|
+
| `playing_clip_id` | `string \| null` | UUID of the clip now playing, or null when the stream is idle. |
|
|
975
|
+
| `clip_seconds_max` | `number` | Longest clip length [`set_clip_seconds`](#setclipseconds) accepts. |
|
|
976
|
+
| `clip_seconds_min` | `number` | Shortest clip length [`set_clip_seconds`](#setclipseconds) accepts. |
|
|
977
|
+
| `playout_capacity` | `number` | Most built clips the playout queue holds. Generation pauses while it is full and resumes as playing or [`pop`](#pop) frees a slot. |
|
|
978
|
+
| `flush_on_clip_end` | `boolean` | The stream cuts to black when a clip ends, is stopped, or a non-continuing clip follows it (the default). Off, those transitions hold the last frame instead. Either way, autoplay chains a clip that continues the one just finished with no cut at all. |
|
|
979
|
+
| `generation_queued` | `number` | Clips in the generation queue: enqueued, not yet built. |
|
|
980
|
+
| `generation_capacity` | `number` | Most clips the generation queue holds; [`enqueue`](#enqueue) is refused beyond it. |
|
|
981
|
+
|
|
982
|
+
#### JavaScript
|
|
983
|
+
|
|
984
|
+
```typescript
|
|
985
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
986
|
+
|
|
987
|
+
const fastH3 = new FastH3Model();
|
|
988
|
+
fastH3.onStateUpdate((msg) => {
|
|
989
|
+
console.log(
|
|
990
|
+
"state_update",
|
|
991
|
+
msg.seed,
|
|
992
|
+
msg.width,
|
|
993
|
+
msg.aspect,
|
|
994
|
+
msg.height,
|
|
995
|
+
msg.playing,
|
|
996
|
+
msg.autoplay,
|
|
997
|
+
msg.clip_seconds,
|
|
998
|
+
msg.clips_played,
|
|
999
|
+
msg.seconds_sent,
|
|
1000
|
+
msg.playout_queued,
|
|
1001
|
+
msg.valid_commands,
|
|
1002
|
+
msg.playing_clip_id,
|
|
1003
|
+
msg.clip_seconds_max,
|
|
1004
|
+
msg.clip_seconds_min,
|
|
1005
|
+
msg.playout_capacity,
|
|
1006
|
+
msg.flush_on_clip_end,
|
|
1007
|
+
msg.generation_queued,
|
|
1008
|
+
msg.generation_capacity,
|
|
1009
|
+
);
|
|
1010
|
+
});
|
|
1011
|
+
await fastH3.connect(jwt);
|
|
1012
|
+
```
|
|
1013
|
+
|
|
1014
|
+
#### React
|
|
1015
|
+
|
|
1016
|
+
```tsx
|
|
1017
|
+
import { useFastH3StateUpdate } from "@reactor-models/fast-h3";
|
|
1018
|
+
|
|
1019
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
1020
|
+
useFastH3StateUpdate((msg) => {
|
|
1021
|
+
console.log(
|
|
1022
|
+
"state_update",
|
|
1023
|
+
msg.seed,
|
|
1024
|
+
msg.width,
|
|
1025
|
+
msg.aspect,
|
|
1026
|
+
msg.height,
|
|
1027
|
+
msg.playing,
|
|
1028
|
+
msg.autoplay,
|
|
1029
|
+
msg.clip_seconds,
|
|
1030
|
+
msg.clips_played,
|
|
1031
|
+
msg.seconds_sent,
|
|
1032
|
+
msg.playout_queued,
|
|
1033
|
+
msg.valid_commands,
|
|
1034
|
+
msg.playing_clip_id,
|
|
1035
|
+
msg.clip_seconds_max,
|
|
1036
|
+
msg.clip_seconds_min,
|
|
1037
|
+
msg.playout_capacity,
|
|
1038
|
+
msg.flush_on_clip_end,
|
|
1039
|
+
msg.generation_queued,
|
|
1040
|
+
msg.generation_capacity,
|
|
1041
|
+
);
|
|
1042
|
+
});
|
|
1043
|
+
```
|
|
1044
|
+
|
|
1045
|
+
### `clip_finished`
|
|
1046
|
+
|
|
1047
|
+
Emitted when a clip has been fully sent on the output tracks.
|
|
1048
|
+
|
|
1049
|
+
The stream then holds on black until the next [`play`](#play); nothing plays on its
|
|
1050
|
+
own.
|
|
1051
|
+
|
|
1052
|
+
Listener: `onClipFinished` · React hook: `useFastH3ClipFinished`
|
|
1053
|
+
|
|
1054
|
+
| Field | Type | Description |
|
|
1055
|
+
|---|---|---|
|
|
1056
|
+
| `clip` | `{ "seed": number; "ready": boolean; "frames": number; "prompt": string; "clip_id": string; "seconds": number; "metadata": string; "has_starting_frame": boolean; "continue_from_clip_id": string \| null }` | The clip that just finished. |
|
|
1057
|
+
| `seconds_sent` | `number` | Seconds of video and audio sent since the session began, this clip included. |
|
|
1058
|
+
|
|
1059
|
+
#### JavaScript
|
|
1060
|
+
|
|
1061
|
+
```typescript
|
|
1062
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
1063
|
+
|
|
1064
|
+
const fastH3 = new FastH3Model();
|
|
1065
|
+
fastH3.onClipFinished((msg) => {
|
|
1066
|
+
console.log("clip_finished", msg.clip, msg.seconds_sent);
|
|
1067
|
+
});
|
|
1068
|
+
await fastH3.connect(jwt);
|
|
1069
|
+
```
|
|
1070
|
+
|
|
1071
|
+
#### React
|
|
1072
|
+
|
|
1073
|
+
```tsx
|
|
1074
|
+
import { useFastH3ClipFinished } from "@reactor-models/fast-h3";
|
|
1075
|
+
|
|
1076
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
1077
|
+
useFastH3ClipFinished((msg) => {
|
|
1078
|
+
console.log("clip_finished", msg.clip, msg.seconds_sent);
|
|
1079
|
+
});
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
### `command_error`
|
|
1083
|
+
|
|
1084
|
+
Emitted when a command is rejected. The command had no effect.
|
|
1085
|
+
|
|
1086
|
+
Listener: `onCommandError` · React hook: `useFastH3CommandError`
|
|
1087
|
+
|
|
1088
|
+
| Field | Type | Description |
|
|
1089
|
+
|---|---|---|
|
|
1090
|
+
| `reason` | `string` | Why it was rejected. |
|
|
1091
|
+
| `command` | `string` | Name of the command that was rejected. |
|
|
1092
|
+
|
|
1093
|
+
#### JavaScript
|
|
1094
|
+
|
|
1095
|
+
```typescript
|
|
1096
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
1097
|
+
|
|
1098
|
+
const fastH3 = new FastH3Model();
|
|
1099
|
+
fastH3.onCommandError((msg) => {
|
|
1100
|
+
console.log("command_error", msg.reason, msg.command);
|
|
1101
|
+
});
|
|
1102
|
+
await fastH3.connect(jwt);
|
|
1103
|
+
```
|
|
1104
|
+
|
|
1105
|
+
#### React
|
|
1106
|
+
|
|
1107
|
+
```tsx
|
|
1108
|
+
import { useFastH3CommandError } from "@reactor-models/fast-h3";
|
|
1109
|
+
|
|
1110
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
1111
|
+
useFastH3CommandError((msg) => {
|
|
1112
|
+
console.log("command_error", msg.reason, msg.command);
|
|
1113
|
+
});
|
|
1114
|
+
```
|
|
1115
|
+
|
|
1116
|
+
### `seed_accepted`
|
|
1117
|
+
|
|
1118
|
+
Emitted when [`set_seed`](#setseed) is accepted.
|
|
1119
|
+
|
|
1120
|
+
Listener: `onSeedAccepted` · React hook: `useFastH3SeedAccepted`
|
|
1121
|
+
|
|
1122
|
+
| Field | Type | Description |
|
|
1123
|
+
|---|---|---|
|
|
1124
|
+
| `seed` | `number` | Seed the next enqueued clip will use when [`enqueue`](#enqueue) carries none. |
|
|
1125
|
+
|
|
1126
|
+
#### JavaScript
|
|
1127
|
+
|
|
1128
|
+
```typescript
|
|
1129
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
1130
|
+
|
|
1131
|
+
const fastH3 = new FastH3Model();
|
|
1132
|
+
fastH3.onSeedAccepted((msg) => {
|
|
1133
|
+
console.log("seed_accepted", msg.seed);
|
|
1134
|
+
});
|
|
1135
|
+
await fastH3.connect(jwt);
|
|
1136
|
+
```
|
|
1137
|
+
|
|
1138
|
+
#### React
|
|
1139
|
+
|
|
1140
|
+
```tsx
|
|
1141
|
+
import { useFastH3SeedAccepted } from "@reactor-models/fast-h3";
|
|
1142
|
+
|
|
1143
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
1144
|
+
useFastH3SeedAccepted((msg) => {
|
|
1145
|
+
console.log("seed_accepted", msg.seed);
|
|
1146
|
+
});
|
|
1147
|
+
```
|
|
1148
|
+
|
|
1149
|
+
### `session_reset`
|
|
1150
|
+
|
|
1151
|
+
Emitted when [`reset`](#reset) is accepted.
|
|
1152
|
+
|
|
1153
|
+
Every condition is back to its default, the queue is empty, and the output
|
|
1154
|
+
stream is cleared.
|
|
1155
|
+
|
|
1156
|
+
Listener: `onSessionReset` · React hook: `useFastH3SessionReset`
|
|
1157
|
+
|
|
1158
|
+
| Field | Type | Description |
|
|
1159
|
+
|---|---|---|
|
|
1160
|
+
| `was_playing` | `boolean` | A clip was playing and has been cut; a [`clip_stopped`](#clip_stopped) accompanies it. |
|
|
1161
|
+
| `cleared_clips` | `number` | Clips dropped from both queues, built and pending alike. |
|
|
1162
|
+
|
|
1163
|
+
#### JavaScript
|
|
1164
|
+
|
|
1165
|
+
```typescript
|
|
1166
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
1167
|
+
|
|
1168
|
+
const fastH3 = new FastH3Model();
|
|
1169
|
+
fastH3.onSessionReset((msg) => {
|
|
1170
|
+
console.log("session_reset", msg.was_playing, msg.cleared_clips);
|
|
1171
|
+
});
|
|
1172
|
+
await fastH3.connect(jwt);
|
|
1173
|
+
```
|
|
1174
|
+
|
|
1175
|
+
#### React
|
|
1176
|
+
|
|
1177
|
+
```tsx
|
|
1178
|
+
import { useFastH3SessionReset } from "@reactor-models/fast-h3";
|
|
1179
|
+
|
|
1180
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
1181
|
+
useFastH3SessionReset((msg) => {
|
|
1182
|
+
console.log("session_reset", msg.was_playing, msg.cleared_clips);
|
|
1183
|
+
});
|
|
1184
|
+
```
|
|
1185
|
+
|
|
1186
|
+
### `clip_generated`
|
|
1187
|
+
|
|
1188
|
+
Emitted when a clip's build completes.
|
|
1189
|
+
|
|
1190
|
+
The clip has left the generation queue and joined the back of the playout
|
|
1191
|
+
queue, playable immediately. [`queue_update`](#queue_update) accompanies it with both
|
|
1192
|
+
queues' new contents.
|
|
1193
|
+
|
|
1194
|
+
Listener: `onClipGenerated` · React hook: `useFastH3ClipGenerated`
|
|
1195
|
+
|
|
1196
|
+
| Field | Type | Description |
|
|
1197
|
+
|---|---|---|
|
|
1198
|
+
| `clip` | `{ "seed": number; "ready": boolean; "frames": number; "prompt": string; "clip_id": string; "seconds": number; "metadata": string; "has_starting_frame": boolean; "continue_from_clip_id": string \| null }` | The freshly built clip, now at the back of the playout queue. |
|
|
1199
|
+
|
|
1200
|
+
#### JavaScript
|
|
1201
|
+
|
|
1202
|
+
```typescript
|
|
1203
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
1204
|
+
|
|
1205
|
+
const fastH3 = new FastH3Model();
|
|
1206
|
+
fastH3.onClipGenerated((msg) => {
|
|
1207
|
+
console.log("clip_generated", msg.clip);
|
|
1208
|
+
});
|
|
1209
|
+
await fastH3.connect(jwt);
|
|
1210
|
+
```
|
|
1211
|
+
|
|
1212
|
+
#### React
|
|
1213
|
+
|
|
1214
|
+
```tsx
|
|
1215
|
+
import { useFastH3ClipGenerated } from "@reactor-models/fast-h3";
|
|
1216
|
+
|
|
1217
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
1218
|
+
useFastH3ClipGenerated((msg) => {
|
|
1219
|
+
console.log("clip_generated", msg.clip);
|
|
1220
|
+
});
|
|
1221
|
+
```
|
|
1222
|
+
|
|
1223
|
+
### `flush_accepted`
|
|
1224
|
+
|
|
1225
|
+
Emitted when [`set_flush_on_clip_end`](#setflushonclipend) is accepted.
|
|
1226
|
+
|
|
1227
|
+
Listener: `onFlushAccepted` · React hook: `useFastH3FlushAccepted`
|
|
1228
|
+
|
|
1229
|
+
| Field | Type | Description |
|
|
1230
|
+
|---|---|---|
|
|
1231
|
+
| `enabled` | `boolean` | Whether the stream now cuts to black when a clip ends, is stopped, or a non-continuing clip follows it. Off, those transitions hold the last frame instead. |
|
|
1232
|
+
|
|
1233
|
+
#### JavaScript
|
|
1234
|
+
|
|
1235
|
+
```typescript
|
|
1236
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
1237
|
+
|
|
1238
|
+
const fastH3 = new FastH3Model();
|
|
1239
|
+
fastH3.onFlushAccepted((msg) => {
|
|
1240
|
+
console.log("flush_accepted", msg.enabled);
|
|
1241
|
+
});
|
|
1242
|
+
await fastH3.connect(jwt);
|
|
1243
|
+
```
|
|
1244
|
+
|
|
1245
|
+
#### React
|
|
1246
|
+
|
|
1247
|
+
```tsx
|
|
1248
|
+
import { useFastH3FlushAccepted } from "@reactor-models/fast-h3";
|
|
1249
|
+
|
|
1250
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
1251
|
+
useFastH3FlushAccepted((msg) => {
|
|
1252
|
+
console.log("flush_accepted", msg.enabled);
|
|
1253
|
+
});
|
|
1254
|
+
```
|
|
1255
|
+
|
|
1256
|
+
### `canvas_accepted`
|
|
1257
|
+
|
|
1258
|
+
Emitted when [`set_canvas`](#setcanvas) is accepted.
|
|
1259
|
+
|
|
1260
|
+
Listener: `onCanvasAccepted` · React hook: `useFastH3CanvasAccepted`
|
|
1261
|
+
|
|
1262
|
+
| Field | Type | Description |
|
|
1263
|
+
|---|---|---|
|
|
1264
|
+
| `width` | `number` | Width of every frame on `main_video`. |
|
|
1265
|
+
| `aspect` | `string` | Aspect ratio now in effect. |
|
|
1266
|
+
| `height` | `number` | Height of every frame on `main_video`. |
|
|
1267
|
+
|
|
1268
|
+
#### JavaScript
|
|
1269
|
+
|
|
1270
|
+
```typescript
|
|
1271
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
1272
|
+
|
|
1273
|
+
const fastH3 = new FastH3Model();
|
|
1274
|
+
fastH3.onCanvasAccepted((msg) => {
|
|
1275
|
+
console.log(
|
|
1276
|
+
"canvas_accepted",
|
|
1277
|
+
msg.width,
|
|
1278
|
+
msg.aspect,
|
|
1279
|
+
msg.height,
|
|
1280
|
+
);
|
|
1281
|
+
});
|
|
1282
|
+
await fastH3.connect(jwt);
|
|
1283
|
+
```
|
|
1284
|
+
|
|
1285
|
+
#### React
|
|
1286
|
+
|
|
1287
|
+
```tsx
|
|
1288
|
+
import { useFastH3CanvasAccepted } from "@reactor-models/fast-h3";
|
|
1289
|
+
|
|
1290
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
1291
|
+
useFastH3CanvasAccepted((msg) => {
|
|
1292
|
+
console.log(
|
|
1293
|
+
"canvas_accepted",
|
|
1294
|
+
msg.width,
|
|
1295
|
+
msg.aspect,
|
|
1296
|
+
msg.height,
|
|
1297
|
+
);
|
|
1298
|
+
});
|
|
1299
|
+
```
|
|
1300
|
+
|
|
1301
|
+
### `autoplay_accepted`
|
|
1302
|
+
|
|
1303
|
+
Emitted when [`set_autoplay`](#setautoplay) is accepted.
|
|
1304
|
+
|
|
1305
|
+
Listener: `onAutoplayAccepted` · React hook: `useFastH3AutoplayAccepted`
|
|
1306
|
+
|
|
1307
|
+
| Field | Type | Description |
|
|
1308
|
+
|---|---|---|
|
|
1309
|
+
| `enabled` | `boolean` | Whether ready clips now start on their own when nothing is playing. |
|
|
1310
|
+
|
|
1311
|
+
#### JavaScript
|
|
1312
|
+
|
|
1313
|
+
```typescript
|
|
1314
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
1315
|
+
|
|
1316
|
+
const fastH3 = new FastH3Model();
|
|
1317
|
+
fastH3.onAutoplayAccepted((msg) => {
|
|
1318
|
+
console.log("autoplay_accepted", msg.enabled);
|
|
1319
|
+
});
|
|
1320
|
+
await fastH3.connect(jwt);
|
|
1321
|
+
```
|
|
1322
|
+
|
|
1323
|
+
#### React
|
|
1324
|
+
|
|
1325
|
+
```tsx
|
|
1326
|
+
import { useFastH3AutoplayAccepted } from "@reactor-models/fast-h3";
|
|
1327
|
+
|
|
1328
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
1329
|
+
useFastH3AutoplayAccepted((msg) => {
|
|
1330
|
+
console.log("autoplay_accepted", msg.enabled);
|
|
1331
|
+
});
|
|
1332
|
+
```
|
|
1333
|
+
|
|
1334
|
+
### `clip_length_accepted`
|
|
1335
|
+
|
|
1336
|
+
Emitted when [`set_clip_seconds`](#setclipseconds) is accepted.
|
|
1337
|
+
|
|
1338
|
+
The requested length is snapped to the nearest length the model can produce,
|
|
1339
|
+
so the value here may differ slightly from the one sent.
|
|
1340
|
+
|
|
1341
|
+
Listener: `onClipLengthAccepted` · React hook: `useFastH3ClipLengthAccepted`
|
|
1342
|
+
|
|
1343
|
+
| Field | Type | Description |
|
|
1344
|
+
|---|---|---|
|
|
1345
|
+
| `frames` | `number` | Frames each newly enqueued clip will carry. |
|
|
1346
|
+
| `clip_seconds` | `number` | Clip length now in effect, in seconds. |
|
|
1347
|
+
|
|
1348
|
+
#### JavaScript
|
|
1349
|
+
|
|
1350
|
+
```typescript
|
|
1351
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
1352
|
+
|
|
1353
|
+
const fastH3 = new FastH3Model();
|
|
1354
|
+
fastH3.onClipLengthAccepted((msg) => {
|
|
1355
|
+
console.log("clip_length_accepted", msg.frames, msg.clip_seconds);
|
|
1356
|
+
});
|
|
1357
|
+
await fastH3.connect(jwt);
|
|
1358
|
+
```
|
|
1359
|
+
|
|
1360
|
+
#### React
|
|
1361
|
+
|
|
1362
|
+
```tsx
|
|
1363
|
+
import { useFastH3ClipLengthAccepted } from "@reactor-models/fast-h3";
|
|
1364
|
+
|
|
1365
|
+
// Inside a React component wrapped by <FastH3Provider>:
|
|
1366
|
+
useFastH3ClipLengthAccepted((msg) => {
|
|
1367
|
+
console.log("clip_length_accepted", msg.frames, msg.clip_seconds);
|
|
1368
|
+
});
|
|
1369
|
+
```
|
|
1370
|
+
|
|
1371
|
+
## Tracks
|
|
1372
|
+
|
|
1373
|
+
Named media channels between your app and the FastH3 model. Use the typed helpers below — `FastH3Model.publish<Track>` / `on<Track>` in plain JS, and `useFastH3Track` or the per-track `<FastH3<Track>View>` components in React — so track names are checked at compile time.
|
|
1374
|
+
|
|
1375
|
+
### `main_video`
|
|
1376
|
+
|
|
1377
|
+
A video channel you subscribe to — the model publishes this for your app to render.
|
|
1378
|
+
|
|
1379
|
+
#### JavaScript
|
|
1380
|
+
|
|
1381
|
+
```typescript
|
|
1382
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
1383
|
+
|
|
1384
|
+
const fastH3 = new FastH3Model();
|
|
1385
|
+
fastH3.onMainVideo((track, stream) => {
|
|
1386
|
+
// attach to a <video> element, pipe to a canvas, etc.
|
|
1387
|
+
videoEl.srcObject = stream;
|
|
1388
|
+
});
|
|
1389
|
+
await fastH3.connect(jwt);
|
|
1390
|
+
```
|
|
1391
|
+
|
|
1392
|
+
#### React
|
|
1393
|
+
|
|
1394
|
+
```tsx
|
|
1395
|
+
"use client";
|
|
1396
|
+
import { FastH3MainVideoView } from "@reactor-models/fast-h3";
|
|
1397
|
+
|
|
1398
|
+
// Inside a component wrapped by <FastH3Provider>:
|
|
1399
|
+
export function Example() {
|
|
1400
|
+
return <FastH3MainVideoView className="w-full aspect-video" />;
|
|
1401
|
+
}
|
|
1402
|
+
```
|
|
1403
|
+
|
|
1404
|
+
### `main_audio`
|
|
1405
|
+
|
|
1406
|
+
A audio channel you subscribe to — the model publishes this for your app to render.
|
|
1407
|
+
|
|
1408
|
+
#### JavaScript
|
|
1409
|
+
|
|
1410
|
+
```typescript
|
|
1411
|
+
import { FastH3Model } from "@reactor-models/fast-h3";
|
|
1412
|
+
|
|
1413
|
+
const fastH3 = new FastH3Model();
|
|
1414
|
+
fastH3.onMainAudio((track, stream) => {
|
|
1415
|
+
// attach to a <audio> element, pipe to a canvas, etc.
|
|
1416
|
+
videoEl.srcObject = stream;
|
|
1417
|
+
});
|
|
1418
|
+
await fastH3.connect(jwt);
|
|
1419
|
+
```
|
|
1420
|
+
|
|
1421
|
+
#### React
|
|
1422
|
+
|
|
1423
|
+
```tsx
|
|
1424
|
+
"use client";
|
|
1425
|
+
import { useFastH3Track } from "@reactor-models/fast-h3";
|
|
1426
|
+
|
|
1427
|
+
// Inside a component wrapped by <FastH3Provider>:
|
|
1428
|
+
export function Example() {
|
|
1429
|
+
const track = useFastH3Track("main_audio");
|
|
1430
|
+
// attach `track` to an <audio> element via a ref + srcObject.
|
|
1431
|
+
return null;
|
|
1432
|
+
}
|
|
1433
|
+
```
|