> ## 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 World 2 overview

> What LingBot World 2 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 World 2** is a real-time navigable world model, and the next generation of
[LingBot](/model-api-reference/lingbot/overview). It takes a reference image plus a text prompt as
visual and stylistic anchors, then generates an infinite video stream that you can explore in real
time. Drive the camera with WASD, look around with the arrow keys, direct the camera with native
pose moves, and restyle the world on the fly by hot-swapping the prompt.

Coming from the first LingBot, three things are new:

* Movement is now possible along two independent axes (longitudinal and lateral)
* A native `set_camera_pose` layer drives directed camera moves to create new types of camera
  control
* A broader prompt-steering surface handles mid-stream scene changes.

The LingBot World 2 reference is split across four pages: this overview, the complete
[command and event schema](/model-api-reference/lingbot-world-2/schema), the
[prompt guide](/model-api-reference/lingbot-world-2/prompt-guide) for writing prompts that steer the
world, and an end-to-end [tutorial](/model-api-reference/lingbot-world-2/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 `reactor/lingbot-world-2`), send named
commands, receive events. LingBot World 2 also has a typed SDK, `@reactor-models/lingbot-world-2`,
that wraps the base class with named methods (`setImage`, `setPrompt`, `start`, …) and React hooks;
the [tutorial](/model-api-reference/lingbot-world-2/tutorial) uses it. See
[Typed Model SDKs](/sdk-reference/typed-model-sdk).

## At a glance

| Spec           | Value                                 |
| -------------- | ------------------------------------- |
| **Model name** | `reactor/lingbot-world-2`             |
| **Pricing**    | <ModelRate model="lingbot-world-2" /> |
| **Frame rate** | 48 fps                                |
| **Resolution** | 1664 × 960                            |
| **Input**      | Reference image + text prompt         |

The **model name** is the string you pass when you open a session, e.g.
`new Reactor({ modelName: "reactor/lingbot-world-2" })`; the `create-reactor-app` CLI and the
pricing catalog use the short slug `lingbot-world-2`. See [Pricing & Billing](/resources/billing)
for how billing works.

## Key features

<CardGroup cols={3}>
  <Card title="Two-axis WASD navigation" icon="gamepad-2">
    Drive the camera with independent longitudinal (W/S) and lateral (A/D) movement, plus
    arrow-key look. Commands apply at the next chunk boundary.
  </Card>

  <Card title="Image-anchored generation" icon="image">
    A reference image fixes the visual identity of the world; the prompt steers atmosphere and
    content. An image is required before generation starts.
  </Card>

  <Card title="Directed camera moves" icon="video">
    The native `set_camera_pose` layer drives arbitrary camera movements with per-frame
    motion deltas that can either augment or fully replace the look axes.
  </Card>
</CardGroup>

Beyond these, you can **hot-swap the prompt mid-stream** with `set_prompt` to change weather,
lighting, or events without restarting the session or losing the reference image. The
[prompt guide](/model-api-reference/lingbot-world-2/prompt-guide) covers how to write effective
prompts.

## Quick start

The fastest path to a working LingBot World 2 app is the `create-reactor-app` CLI, which scaffolds
the reference frontend into a runnable project. You can also clone the
[open-source reference frontend](https://github.com/reactor-team/js-sdk/tree/main/examples/lingbot-world-2)
itself, or follow the [tutorial](/model-api-reference/lingbot-world-2/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-world-2-app --model=lingbot-world-2
    ```
  </Tab>

  <Tab title="pnpm">
    ```shell theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
    pnpm create reactor-app my-lingbot-world-2-app --model=lingbot-world-2
    ```
  </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: "reactor/lingbot-world-2" });

  // 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 reference 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 reddish-brown ant on a dirt path between tall green grass blades, macro nature.",
    });
    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="reactor/lingbot-world-2", 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 reference 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 reddish-brown ant on a dirt path between tall green grass blades, macro nature.",
          })
          await reactor.send_command("start", {})

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

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

That uses the base SDK. The typed SDK, `@reactor-models/lingbot-world-2`, gives you
`new LingbotWorld2Model()` with named methods and React hooks (`useLingbotWorld2`,
`<LingbotWorld2MainVideoView />`); the [tutorial](/model-api-reference/lingbot-world-2/tutorial)
builds on it. See [Typed Model SDKs](/sdk-reference/typed-model-sdk).

## How it works

On connect the model is live but idle; it won't produce frames until it has both a reference image
and a prompt and you call `start`. In order to get your first generated video stream, you must:

1. **Connect** to the model.
2. **Upload and set a reference image** with
   [`set_image`](/model-api-reference/lingbot-world-2/schema#commands); it anchors the visual
   identity of the world.
3. **Set a prompt** with [`set_prompt`](/model-api-reference/lingbot-world-2/schema#commands) to
   describe the scene and how the camera and subject may move.
4. **Start** generation. `start` fails with a `command_error` until both an image and a prompt are
   set.
5. **Drive the camera** with the two movement axes (W/S + A/D) and the look axes (arrow keys), or
   direct it with [`set_camera_pose`](/model-api-reference/lingbot-world-2/schema#commands).
6. **Restyle live** by hot-swapping the prompt with `set_prompt`; the change lands on the next
   chunk.
7. **Pause / resume** between chunks, or **reset** to clear state and re-stage with new conditions.

<Note>
  LingBot World 2 generates video one **chunk** at a time. Movement and look are **persistent
  state**, not pulses: `set_move_longitudinal: "forward"` keeps driving until you send `"idle"`.
  Commands take effect at the next chunk boundary, so a quick key tap released before the boundary
  may never land on screen. When a run finishes, the server auto-restarts it with the same prompt
  and image until you `reset`. See the [schema](/model-api-reference/lingbot-world-2/schema) for the
  full surface.
</Note>
