> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reactor.inc/llms.txt
> Use this file to discover all available pages before exploring further.

# LingBot overview

> What LingBot is, its key features, and a quick start.

export const ModelRate = ({model}) => {
  const [data, setData] = useState(null);
  const [error, setError] = useState(false);
  const [loading, setLoading] = useState(true);
  useEffect(() => {
    const ctrl = new AbortController();
    fetch("https://api.reactor.inc/pricing", {
      signal: ctrl.signal
    }).then(r => {
      if (!r.ok) throw new Error(`HTTP ${r.status}`);
      return r.json();
    }).then(json => {
      setData(json);
      setLoading(false);
    }).catch(err => {
      if (err.name === "AbortError") return;
      setError(true);
      setLoading(false);
    });
    return () => ctrl.abort();
  }, []);
  if (loading) {
    return <span aria-label="loading pricing" className="inline-block h-4 w-28 rounded bg-zinc-950/10 dark:bg-white/10 animate-pulse align-middle" />;
  }
  const creditsPerDollar = data?.settings?.credits_per_dollar;
  const amountPerSec = data?.models?.find(m => m.name === model)?.rate?.amount_per_sec;
  const canRender = !error && creditsPerDollar && typeof amountPerSec === "number";
  if (!canRender) {
    return <span className="text-zinc-950/60 dark:text-white/60">see current rate below</span>;
  }
  const perHour = Math.round(amountPerSec / creditsPerDollar * 3600);
  const perSec = (amountPerSec / creditsPerDollar).toFixed(4);
  return <span>
      <strong>${perHour}/hr</strong> (${perSec}/sec)
    </span>;
};

**LingBot** is a real-time, navigable video model. It takes a seed image plus a text prompt as
visual and stylistic anchors, then continuously generates a video stream you walk through with WASD
and look around with arrow keys. LingBot produces an **infinite, interactive stream** that responds
to commands frame-to-frame.

The LingBot reference is split across four pages: this overview, the complete
[command and event schema](/model-api-reference/lingbot/schema), the
[prompt guide](/model-api-reference/lingbot/prompt-guide) for writing prompts that steer the world
without leaking camera instructions, and an end-to-end
[tutorial](/model-api-reference/lingbot/tutorial) against the open-source reference frontend.

The base wire protocol is the same as every other Reactor model: open a session with the
[`Reactor`](/sdk-reference/reactor-class) class (model name `lingbot`), send named commands, receive
events. LingBot's surface adds commands for the prompt, the seed image, WASD movement, the look axes,
the seed, and playback control.

## At a glance

| Spec           | Value                         |
| -------------- | ----------------------------- |
| **Model name** | `lingbot`                     |
| **Pricing**    | <ModelRate model="lingbot" /> |
| **Frame rate** | 16 fps                        |
| **Latency**    | \< 1 second                   |
| **Resolution** | 1664 × 960                    |

The **model name** is the string you pass when you open a session, e.g.
`new Reactor({ modelName: "lingbot" })`. See
[Pricing & Billing](/resources/billing) for how billing works.

## Key features

<CardGroup cols={3}>
  <Card title="Interactive WASD navigation" icon="gamepad-2">
    Drive the camera through a generated world with movement and look commands that apply at the
    next chunk boundary.
  </Card>

  <Card title="Image-anchored generation" icon="image">
    A seed image fixes the visual identity of the world; the prompt steers the rest.
  </Card>

  <Card title="Live prompt swapping" icon="wand-sparkles">
    Re-fire `set_prompt` at any time mid-generation to swap atmosphere, lighting, or events
    without restarting the session.
  </Card>
</CardGroup>

## Quick Start

The fastest path to a working LingBot app is the `create-reactor-app` CLI, which scaffolds a runnable
project for you. You can also clone the
[open-source reference frontend](https://github.com/reactor-team/js-sdk/tree/main/examples/lingbot)
directly, or follow the [tutorial](/model-api-reference/lingbot/tutorial) for a guided walkthrough.

<Tabs>
  <Tab title="npm">
    ```shell theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
    npx create-reactor-app my-lingbot-app --model=lingbot
    ```
  </Tab>

  <Tab title="pnpm">
    ```shell theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
    pnpm create reactor-app my-lingbot-app --model=lingbot
    ```
  </Tab>
</Tabs>

Working in Python instead? The CLI is JavaScript-only, so install the SDK with
`pip install reactor-sdk` and follow the Python tab below (see the
[quickstart](/quickstart) for the full walkthrough).

A minimal connect-and-generate flow looks like:

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  import { Reactor } from "@reactor-team/js-sdk";

  const video = document.querySelector("video")!;
  const reactor = new Reactor({ modelName: "lingbot" });

  // Render frames as soon as they arrive.
  reactor.on("trackReceived", (name, track, stream) => {
    if (name !== "main_video") return;
    video.srcObject = stream;
    void video.play();
  });

  // Once the session is ready, set a seed image and prompt, then start.
  reactor.on("statusChanged", async (status) => {
    if (status !== "ready") return;
    const ref = await reactor.uploadFile(seedImageFile);
    await reactor.sendCommand("set_image", { image: ref });
    await reactor.sendCommand("set_prompt", {
      prompt: "A misty old-growth forest, soft morning light filtering through the canopy.",
    });
    await reactor.sendCommand("start", {});
  });

  const jwt = await getToken(); // token minted on your server
  await reactor.connect(jwt);
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  import asyncio
  import os
  from reactor_sdk import Reactor, ReactorStatus

  async def main():
      reactor = Reactor(model_name="lingbot", api_key=os.environ["REACTOR_API_KEY"])

      # Frames arrive as (H, W, 3) uint8 RGB NumPy arrays.
      @reactor.on_frame
      def on_frame(frame):
          print(f"Frame: {frame.shape}")

      # Once the session is ready, set a seed image and prompt, then start.
      @reactor.on_status(ReactorStatus.READY)
      async def on_ready(status):
          ref = await reactor.upload_file("seed.jpg")
          await reactor.send_command("set_image", {"image": ref})
          await reactor.send_command("set_prompt", {
              "prompt": "A misty old-growth forest, soft morning light filtering through the canopy.",
          })
          await reactor.send_command("start", {})

      await reactor.connect()
      await asyncio.Event().wait()  # run until interrupted

  asyncio.run(main())
  ```
</CodeGroup>

That uses the base SDK. LingBot also has a typed SDK, `@reactor-models/lingbot`, with named methods
(`setImage`, `setPrompt`, `start`, …) and React hooks; the
[tutorial](/model-api-reference/lingbot/tutorial) uses it. See
[Typed Model SDKs](/sdk-reference/typed-model-sdk).

<Note>
  For a clean first frame, wait for the `image_accepted` event between `set_image` and `start`;
  otherwise the first chunk renders before the seed image lands and the scene corrects itself one
  chunk later. The [tutorial](/model-api-reference/lingbot/tutorial#starting-a-scene-from-an-image)
  shows the pattern.
</Note>

## How it works

On connect the model is live but idle; it won't produce frames until it has both a seed image and a
prompt and you call `start`. The workflow:

1. **Connect** to the model.
2. **Upload and set a seed image** with [`set_image`](/model-api-reference/lingbot/schema#commands);
   it anchors the visual identity of the world (required).
3. **Set a prompt** with [`set_prompt`](/model-api-reference/lingbot/schema#commands) to steer
   atmosphere and content (required).
4. **Start** generation. `start` fails with a `command_error` until both an image and a prompt are set.
5. **Drive the camera** with the movement and look setters (WASD + arrow keys).
6. **Pause / resume** between chunks, or **reset** to clear state and re-stage with new conditions.

<Note>
  LingBot generates video one **chunk** at a time, and movement and look are **persistent state**, not
  pulses: `set_movement: "forward"` keeps walking until you send `"idle"`. Commands take effect at the
  next chunk boundary, so a quick key tap released before the boundary may never visibly land. See the
  [schema](/model-api-reference/lingbot/schema) for the full command and event surface.
</Note>
