npm.io
0.2.42 • Published 2d ago

@reactor-models/lingbot

Licence
MIT
Version
0.2.42
Deps
1
Size
270 kB
Vulns
0
Weekly
82

@reactor-models/lingbot

Typed JavaScript + React SDK for the Lingbot model on Reactor. Version v0.2.42.


Get started

Scaffold a starter app for Lingbot with create-reactor-app:

npx create-reactor-app my-app --model=lingbot
pnpm dlx create-reactor-app my-app --model=lingbot

Install

npm install @reactor-models/lingbot
pnpm add @reactor-models/lingbot

The package exports a plain-JavaScript client and a set of React bindings. Import whichever you need from @reactor-models/lingbot:

import { LingbotModel } from "@reactor-models/lingbot";
import { LingbotProvider, useLingbot } from "@reactor-models/lingbot";

React 18 or later is required when using the provider and hooks. The token-loading examples below use React 19's use(); on React 18, fetch the JWT in a useEffect and pass it to the provider once it resolves.


Authenticate

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.

Mint a JWT with POST https://api.reactor.inc/tokens and the Reactor-API-Key header; the response JSON is { "jwt": "..." }.

JavaScript (Next.js route handler)
// app/api/reactor/token/route.ts
import { NextResponse } from "next/server";

export async function POST() {
  const res = await fetch("https://api.reactor.inc/tokens", {
    method: "POST",
    headers: { "Reactor-API-Key": process.env.REACTOR_API_KEY! },
  });
  const { jwt } = await res.json();
  return NextResponse.json({ jwt });
}
React (provider)

Call the /api/reactor/token route above from a client component and pass the result to the provider:

"use client";

import { use } from "react";
import { LingbotProvider } from "@reactor-models/lingbot";
import { ReactorView } from "@reactor-team/js-sdk";

async function getToken() {
  const r = await fetch("/api/reactor/token", { method: "POST" });
  const { jwt } = await r.json();
  return jwt;
}

const tokenPromise = getToken();

export default function App() {
  const token = use(tokenPromise);
  return (
    <LingbotProvider jwtToken={token} connectOptions={{ autoConnect: true }}>
      <ReactorView className="w-full aspect-video" />
    </LingbotProvider>
  );
}

Connect

JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
await lingbot.connect(jwt);
React

The provider takes the JWT as a prop; fetch it from the same /api/reactor/token route the Authenticate example mints:

"use client";

import { use } from "react";
import { LingbotProvider, useLingbot } from "@reactor-models/lingbot";

async function getToken() {
  const r = await fetch("/api/reactor/token", { method: "POST" });
  const { jwt } = await r.json();
  return jwt;
}

const tokenPromise = getToken();

function Controller() {
  const { status } = useLingbot();
  return <span>Status: {status}</span>;
}

export default function App() {
  const token = use(tokenPromise);
  return (
    <LingbotProvider jwtToken={token}>
      <Controller />
    </LingbotProvider>
  );
}

Events

Client-to-model commands. The typed surface is LingbotModel (one method per event) in plain JS, and useLingbot() in React — every field name below matches the parameter name the method accepts.

pause

Pause generation after the current chunk finishes. Frames stop streaming on main_video until resume is called. Requires generation to be active. Emits generation_paused and state on success, or command_error if not generating or already paused.

Emits: generation_paused, state, command_error

No parameters.

JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
await lingbot.connect(jwt);

await lingbot.pause();
React
"use client";
import { useLingbot } from "@reactor-models/lingbot";

function Example() {
  const { pause } = useLingbot();

  return <button onClick={() => pause()}>pause</button>;
}
reset

Abort the current run, clear the active prompt and reference image, and return to the waiting state. Valid at any time. After reset, call set_prompt and set_image again before start to begin a new session. Emits generation_reset and state.

Emits: generation_reset, state

No parameters.

JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
await lingbot.connect(jwt);

await lingbot.reset();
React
"use client";
import { useLingbot } from "@reactor-models/lingbot";

function Example() {
  const { reset } = useLingbot();

  return <button onClick={() => reset()}>reset</button>;
}
start

Begin generating video on main_video. Requires both a prompt (via set_prompt) and a reference image (via set_image). Emits generation_started and state on success, or command_error if a precondition is missing. Has no effect while already generating.

Emits: generation_started, state, command_error

No parameters.

JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
await lingbot.connect(jwt);

await lingbot.start();
React
"use client";
import { useLingbot } from "@reactor-models/lingbot";

function Example() {
  const { start } = useLingbot();

  return <button onClick={() => start()}>start</button>;
}
resume

Resume generation from a previous pause. Requires the session to be paused. Emits generation_resumed and state on success, or command_error if not paused.

Emits: generation_resumed, state, command_error

No parameters.

JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
await lingbot.connect(jwt);

await lingbot.resume();
React
"use client";
import { useLingbot } from "@reactor-models/lingbot";

function Example() {
  const { resume } = useLingbot();

  return <button onClick={() => resume()}>resume</button>;
}
setSeed

Set seed

Parameter Type Required Description
seed number Seed for the random generator used to sample the initial noise. Must be a non-negative integer; the model never draws its own random seed — pick one explicitly (or keep the default) for reproducible runs. Read once when start fires; later changes take effect only after reset followed by a new start. (min 0, default 42)
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
await lingbot.connect(jwt);

await lingbot.setSeed({ seed: 42 });
React
"use client";
import { useLingbot } from "@reactor-models/lingbot";

function Example() {
  const { setSeed } = useLingbot();

  return <button onClick={() => setSeed({ seed: 42 })}>setSeed</button>;
}
setImage

Provide a reference image that anchors generation (image-to-video). Call before start; the image is required for generation to begin. Changes during generation have no effect until reset is issued and start is called again. Emits image_accepted, conditions_ready, and state on success, or command_error if the file is missing, not an image, or cannot be decoded.

Emits: image_accepted, conditions_ready, state, command_error

Parameter Type Required Description
image FileRef Reference to a file uploaded via the Reactor presigned-URL protocol. (default null)
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
await lingbot.connect(jwt);

const fileRef = await lingbot.uploadFile(blob);
await lingbot.setImage({ image: fileRef });
React
"use client";
import { useLingbot } from "@reactor-models/lingbot";

function Example() {
  const { setImage, uploadFile } = useLingbot();

  async function handlePick(file: File) {
    const ref = await uploadFile(file);
    await setImage({ image: ref });
  }

  return <input type="file" onChange={(e) => handlePick(e.target.files![0])} />;
}
setPrompt

Set the scene prompt. Valid at any time — call before start to arm generation, or hot-swap during generation to steer the next chunk. Emits prompt_accepted, conditions_ready, and state on success.

Emits: prompt_accepted, conditions_ready, state

Parameter Type Required Description
prompt string Natural-language description of the scene to generate. Replaces the previously active prompt. Applied on the next chunk when generating; otherwise takes effect when start fires. (default "")
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
await lingbot.connect(jwt);

await lingbot.setPrompt({ prompt: "A sunset over the ocean" });
React
"use client";
import { useLingbot } from "@reactor-models/lingbot";

function Example() {
  const { setPrompt } = useLingbot();

  return <button onClick={() => setPrompt({ prompt: "A sunset over the ocean" })}>setPrompt</button>;
}
setMovement

Set movement

Parameter Type Required Description
movement "idle" | "forward" | "back" | "strafe_left" | "strafe_right" Character movement in the generated scene. idle holds the character stationary; forward / back translate along the look axis; strafe_left / strafe_right translate sideways. Can be changed at any time; the new value applies to the next chunk. (default "idle")
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
await lingbot.connect(jwt);

await lingbot.setMovement({ movement: "idle" });
React
"use client";
import { useLingbot } from "@reactor-models/lingbot";

function Example() {
  const { setMovement } = useLingbot();

  return <button onClick={() => setMovement({ movement: "idle" })}>setMovement</button>;
}
setLookVertical

Set look_vertical

Parameter Type Required Description
look_vertical "idle" | "up" | "down" Vertical (pitch) camera rotation. idle holds pitch steady; up / down rotate the camera at the rate given by rotation_speed_deg. Can be changed at any time; the new value applies to the next chunk. (default "idle")
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
await lingbot.connect(jwt);

await lingbot.setLookVertical({ look_vertical: "idle" });
React
"use client";
import { useLingbot } from "@reactor-models/lingbot";

function Example() {
  const { setLookVertical } = useLingbot();

  return <button onClick={() => setLookVertical({ look_vertical: "idle" })}>setLookVertical</button>;
}
setLookHorizontal

Set look_horizontal

Parameter Type Required Description
look_horizontal "idle" | "left" | "right" Horizontal (yaw) camera rotation. idle holds yaw steady; left / right rotate the camera at the rate given by rotation_speed_deg. Can be changed at any time; the new value applies to the next chunk. (default "idle")
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
await lingbot.connect(jwt);

await lingbot.setLookHorizontal({ look_horizontal: "idle" });
React
"use client";
import { useLingbot } from "@reactor-models/lingbot";

function Example() {
  const { setLookHorizontal } = useLingbot();

  return <button onClick={() => setLookHorizontal({ look_horizontal: "idle" })}>setLookHorizontal</button>;
}
setRotationSpeedDeg

Set rotation_speed_deg

Parameter Type Required Description
rotation_speed_deg number Camera rotation speed in degrees per latent frame, applied when look_horizontal or look_vertical is not idle. Range 0.0 – 30.0. Ignored when both look axes are idle. Can be changed at any time; the new value applies to the next chunk. (min 0, max 30, default 5)
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
await lingbot.connect(jwt);

await lingbot.setRotationSpeedDeg({ rotation_speed_deg: 5 });
React
"use client";
import { useLingbot } from "@reactor-models/lingbot";

function Example() {
  const { setRotationSpeedDeg } = useLingbot();

  return <button onClick={() => setRotationSpeedDeg({ rotation_speed_deg: 5 })}>setRotationSpeedDeg</button>;
}

Messages

Model-to-client messages. Register a typed listener with on… on LingbotModel, or a useLingbot… hook in React, to receive only the messages you care about.

state

Snapshot of the session's observable state.

Emitted on connect, after every command that mutates session state (set_prompt, set_image, start, pause, resume, reset, and the auto-generated set_<field> setters), and after each chunk_complete. Clients can treat this as the single source of truth for driving UI, without having to track every individual command and message themselves.

Listener: onState · React hook: useLingbotState

Field Type Description
seed number Current value of the seed input field. The seed that was actually used by the running generation was captured when start fired — later changes to seed only take effect after reset and a new start.
paused boolean True while generation is paused via pause.
running boolean True while the chunk loop is actively producing frames — equivalent to started and not paused. False both before start and while paused; read started to disambiguate.
started boolean True once start has been accepted. Remains true while paused; reset to false by reset or after generation_complete when the session is not auto-restarting.
movement string Current value of the movement input field.
has_image boolean True once a reference image has been set for the session.
has_prompt boolean True once a prompt has been set for the session.
current_chunk number Zero-based index of the last completed chunk. 0 before the first chunk has completed, and resets to 0 on reset.
look_vertical string Current value of the look_vertical input field.
current_action string Composite action string derived from movement, look_horizontal, and look_vertical — a +-joined combination of w/s/a/d and left/right/up/down, or still when idle.
current_prompt unknown The prompt currently driving generation, or null if no prompt has been set for the session.
look_horizontal string Current value of the look_horizontal input field.
rotation_speed_deg number Current value of the rotation_speed_deg input field (0.0 – 30.0).
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
lingbot.onState((msg) => {
  console.log(
    "state",
    msg.seed,
    msg.paused,
    msg.running,
    msg.started,
    msg.movement,
    msg.has_image,
    msg.has_prompt,
    msg.current_chunk,
    msg.look_vertical,
    msg.current_action,
    msg.current_prompt,
    msg.look_horizontal,
    msg.rotation_speed_deg,
  );
});
await lingbot.connect(jwt);
React
import { useLingbotState } from "@reactor-models/lingbot";

// Inside a React component wrapped by <LingbotProvider>:
useLingbotState((msg) => {
  console.log(
    "state",
    msg.seed,
    msg.paused,
    msg.running,
    msg.started,
    msg.movement,
    msg.has_image,
    msg.has_prompt,
    msg.current_chunk,
    msg.look_vertical,
    msg.current_action,
    msg.current_prompt,
    msg.look_horizontal,
    msg.rotation_speed_deg,
  );
});
command_error

Emitted when a command is rejected because preconditions are not met or its arguments could not be processed.

Listener: onCommandError · React hook: useLingbotCommandError

Field Type Description
reason string Human-readable explanation of why the command was rejected.
command string Name of the command that was rejected.
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
lingbot.onCommandError((msg) => {
  console.log("command_error", msg.reason, msg.command);
});
await lingbot.connect(jwt);
React
import { useLingbotCommandError } from "@reactor-models/lingbot";

// Inside a React component wrapped by <LingbotProvider>:
useLingbotCommandError((msg) => {
  console.log("command_error", msg.reason, msg.command);
});
chunk_complete

Emitted once per completed chunk of main_video.

Listener: onChunkComplete · React hook: useLingbotChunkComplete

Field Type Description
chunk_index number Zero-based index of the chunk that just completed.
active_action string The composite action string used to drive this chunk — a +-joined combination of movement (w/s/a/d) and look directions (left/right/up/down), or still when the character is idle with no camera rotation.
active_prompt string The prompt that was active while this chunk was generated.
frames_emitted number Number of pixel frames emitted by this chunk.
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
lingbot.onChunkComplete((msg) => {
  console.log(
    "chunk_complete",
    msg.chunk_index,
    msg.active_action,
    msg.active_prompt,
    msg.frames_emitted,
  );
});
await lingbot.connect(jwt);
React
import { useLingbotChunkComplete } from "@reactor-models/lingbot";

// Inside a React component wrapped by <LingbotProvider>:
useLingbotChunkComplete((msg) => {
  console.log(
    "chunk_complete",
    msg.chunk_index,
    msg.active_action,
    msg.active_prompt,
    msg.frames_emitted,
  );
});
image_accepted

Emitted after set_image successfully decodes the uploaded file.

Listener: onImageAccepted · React hook: useLingbotImageAccepted

Field Type Description
width number Width in pixels of the decoded reference image.
height number Height in pixels of the decoded reference image.
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
lingbot.onImageAccepted((msg) => {
  console.log("image_accepted", msg.width, msg.height);
});
await lingbot.connect(jwt);
React
import { useLingbotImageAccepted } from "@reactor-models/lingbot";

// Inside a React component wrapped by <LingbotProvider>:
useLingbotImageAccepted((msg) => {
  console.log("image_accepted", msg.width, msg.height);
});
prompt_accepted

Emitted after set_prompt is accepted.

Listener: onPromptAccepted · React hook: useLingbotPromptAccepted

Field Type Description
prompt string The prompt text that was accepted.
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
lingbot.onPromptAccepted((msg) => {
  console.log("prompt_accepted", msg.prompt);
});
await lingbot.connect(jwt);
React
import { useLingbotPromptAccepted } from "@reactor-models/lingbot";

// Inside a React component wrapped by <LingbotProvider>:
useLingbotPromptAccepted((msg) => {
  console.log("prompt_accepted", msg.prompt);
});
conditions_ready

Emitted after set_prompt or set_image so the client can tell at a glance whether start will succeed.

Listener: onConditionsReady · React hook: useLingbotConditionsReady

Field Type Description
has_image boolean True once a reference image has been set for the session.
has_prompt boolean True once a prompt has been set for the session.
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
lingbot.onConditionsReady((msg) => {
  console.log("conditions_ready", msg.has_image, msg.has_prompt);
});
await lingbot.connect(jwt);
React
import { useLingbotConditionsReady } from "@reactor-models/lingbot";

// Inside a React component wrapped by <LingbotProvider>:
useLingbotConditionsReady((msg) => {
  console.log("conditions_ready", msg.has_image, msg.has_prompt);
});
generation_reset

Emitted after reset clears session state and returns to the waiting state.

Listener: onGenerationReset · React hook: useLingbotGenerationReset

Field Type Description
reason string Short human-readable reason the reset was issued.
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
lingbot.onGenerationReset((msg) => {
  console.log("generation_reset", msg.reason);
});
await lingbot.connect(jwt);
React
import { useLingbotGenerationReset } from "@reactor-models/lingbot";

// Inside a React component wrapped by <LingbotProvider>:
useLingbotGenerationReset((msg) => {
  console.log("generation_reset", msg.reason);
});
generation_paused

Emitted in response to pause, once the current chunk finishes.

Listener: onGenerationPaused · React hook: useLingbotGenerationPaused

Field Type Description
chunk_index number Index of the last completed chunk before pausing.
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
lingbot.onGenerationPaused((msg) => {
  console.log("generation_paused", msg.chunk_index);
});
await lingbot.connect(jwt);
React
import { useLingbotGenerationPaused } from "@reactor-models/lingbot";

// Inside a React component wrapped by <LingbotProvider>:
useLingbotGenerationPaused((msg) => {
  console.log("generation_paused", msg.chunk_index);
});
generation_resumed

Emitted in response to resume when leaving the paused state.

Listener: onGenerationResumed · React hook: useLingbotGenerationResumed

Field Type Description
chunk_index number Index of the last completed chunk before resuming.
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
lingbot.onGenerationResumed((msg) => {
  console.log("generation_resumed", msg.chunk_index);
});
await lingbot.connect(jwt);
React
import { useLingbotGenerationResumed } from "@reactor-models/lingbot";

// Inside a React component wrapped by <LingbotProvider>:
useLingbotGenerationResumed((msg) => {
  console.log("generation_resumed", msg.chunk_index);
});
generation_started

Emitted once when start succeeds and frames begin streaming.

Listener: onGenerationStarted · React hook: useLingbotGenerationStarted

Field Type Description
prompt string The prompt active at the start of generation.
chunk_num number Total number of chunks the run will produce before generation_complete fires.
frame_num number Total number of pixel frames the run will emit on main_video before generation_complete.
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
lingbot.onGenerationStarted((msg) => {
  console.log(
    "generation_started",
    msg.prompt,
    msg.chunk_num,
    msg.frame_num,
  );
});
await lingbot.connect(jwt);
React
import { useLingbotGenerationStarted } from "@reactor-models/lingbot";

// Inside a React component wrapped by <LingbotProvider>:
useLingbotGenerationStarted((msg) => {
  console.log(
    "generation_started",
    msg.prompt,
    msg.chunk_num,
    msg.frame_num,
  );
});
generation_complete

Emitted when all chunk_num chunks of a run have streamed. If the session is still started, a new run kicks off immediately with the same prompt and image; call reset to stop.

Listener: onGenerationComplete · React hook: useLingbotGenerationComplete

Field Type Description
total_chunks number Total number of chunks produced by the run.
JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
lingbot.onGenerationComplete((msg) => {
  console.log("generation_complete", msg.total_chunks);
});
await lingbot.connect(jwt);
React
import { useLingbotGenerationComplete } from "@reactor-models/lingbot";

// Inside a React component wrapped by <LingbotProvider>:
useLingbotGenerationComplete((msg) => {
  console.log("generation_complete", msg.total_chunks);
});

Tracks

Named media channels between your app and the Lingbot model. Use the typed helpers below — LingbotModel.publish<Track> / on<Track> in plain JS, and useLingbotTrack or the per-track <Lingbot<Track>View> components in React — so track names are checked at compile time.

main_video

A video channel you subscribe to — the model publishes this for your app to render.

JavaScript
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();
lingbot.onMainVideo((track, stream) => {
  // attach to a <video> element, pipe to a canvas, etc.
  videoEl.srcObject = stream;
});
await lingbot.connect(jwt);
React
"use client";
import { LingbotMainVideoView } from "@reactor-models/lingbot";

// Inside a component wrapped by <LingbotProvider>:
export function Example() {
  return <LingbotMainVideoView className="w-full aspect-video" />;
}

Keywords