npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@reactor-models/lingbot

v0.2.40

Published

Strongly-typed SDK for the Lingbot model on Reactor

Readme

@reactor-models/lingbot

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


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" />;
}