> ## 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.

# LongLive-2.0 schema reference

> The complete LongLive-2.0 command and event schema, with end-to-end examples.

This page documents the complete LongLive-2.0 wire surface: every command you send with
`reactor.sendCommand()`, the events the model emits back, and an end-to-end example. For the
conceptual model and a quick start, see the [overview](/model-api-reference/longlive-v2/overview).

LongLive-2.0 outputs a single video track, **`main_video`**, in chunks of 29 frames (\~1.2s at
24fps). Transitions take effect on chunk boundaries. See
[Chunks, scenes, and length](/model-api-reference/longlive-v2/overview#chunks-scenes-and-length) for
how the per-scene 48-chunk budget and the cumulative `session_chunk` clock work.

## Commands

Send commands to the model using `reactor.sendCommand()`. Below are all available commands:

| Command              | Description                                                                |
| -------------------- | -------------------------------------------------------------------------- |
| `set_shot`           | Set the opening shot, or queue a **soft** transition (keeps the scene)     |
| `scene_cut`          | Queue a **hard** cut to a new scene (purges memory, fresh 48-chunk budget) |
| `schedule_shot`      | Plant a soft shot at a specific `session_chunk`                            |
| `schedule_scene_cut` | Plant a hard cut at a specific `session_chunk`                             |
| `start`              | Begin generating video on `main_video`                                     |
| `pause`              | Pause generation after the current chunk                                   |
| `resume`             | Resume generation from a pause                                             |
| `reset`              | Abort, clear the prompt and all scheduled beats, return to idle            |
| `set_seed`           | Set the noise seed (read once at `start`)                                  |

<Tabs>
  <Tab title="set_shot">
    ### set\_shot

    Set the opening shot before `start`, or queue a **soft** shot change mid-stream. A shot keeps the
    scene's attention memory (the "sink tokens") and continuity, swapping the prompt conditioning.
    Use it for a new beat within the same world (a camera move, an action, a time skip). Mid-stream it
    activates at the next chunk boundary and **spends from the current scene's 48-chunk budget**.

    Acknowledged by `shot_set`; rejected with `command_error` if the prompt is empty.

    **Parameters:**

    | Parameter | Type   | Required | Description            |
    | --------- | ------ | -------- | ---------------------- |
    | `prompt`  | string | Yes      | The shot's prompt text |

    **Example:**

    <CodeGroup>
      ```typescript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      // Opening shot (before start)
      await reactor.sendCommand("set_shot", {
        prompt: "A lone astronaut walks across a windswept red dune at golden hour",
      });

      // Soft transition mid-stream: same world, new beat
      await reactor.sendCommand("set_shot", {
        prompt: "The camera pulls back to reveal a vast crater on the horizon",
      });
      ```

      ```tsx React theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      const { setShot } = useLongliveV2();

      await setShot({ prompt: "A lone astronaut walks across a windswept red dune at golden hour" });
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      await reactor.send_command("set_shot", {
          "prompt": "A lone astronaut walks across a windswept red dune at golden hour",
      })
      ```
    </CodeGroup>
  </Tab>

  <Tab title="scene_cut">
    ### scene\_cut

    Queue a **hard** cut to an unrelated scene. A cut purges the model's memory and re-prefills from
    the new prompt (a clean break with no carry-over) and **resets the per-scene chunk counter to 0,
    giving a fresh 48-chunk budget** (this is how you extend total length). Costs a one-time
    \~150–300ms re-prefill. Activates at the next chunk boundary.

    Acknowledged by `scene_cut`; rejected with `command_error` if the prompt is empty.

    **Parameters:**

    | Parameter | Type   | Required | Description                 |
    | --------- | ------ | -------- | --------------------------- |
    | `prompt`  | string | Yes      | The new scene's prompt text |

    **Example:**

    <CodeGroup>
      ```typescript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      await reactor.sendCommand("scene_cut", {
        prompt: "A neon-lit Tokyo street at night, rain slicking the pavement",
      });
      ```

      ```tsx React theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      const { sceneCut } = useLongliveV2();
      await sceneCut({ prompt: "A neon-lit Tokyo street at night, rain slicking the pavement" });
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      await reactor.send_command("scene_cut", {
          "prompt": "A neon-lit Tokyo street at night, rain slicking the pavement",
      })
      ```
    </CodeGroup>
  </Tab>

  <Tab title="schedule_shot">
    ### schedule\_shot

    Plant a soft shot at a specific **cumulative** chunk index. The prompt is pre-encoded so it fires
    with zero activation latency when `session_chunk` reaches the target. Indices already passed never
    fire. Acknowledged by `shot_scheduled`.

    **Parameters:**

    | Parameter          | Type    | Required | Description                                          |
    | ------------------ | ------- | -------- | ---------------------------------------------------- |
    | `prompt`           | string  | Yes      | The shot's prompt text                               |
    | `at_session_chunk` | integer | Yes      | Cumulative chunk index (≥ 0) at which the shot fires |

    **Example:**

    <CodeGroup>
      ```typescript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      await reactor.sendCommand("schedule_shot", {
        prompt: "Sunrise breaks over the dunes",
        at_session_chunk: 12,
      });
      ```

      ```tsx React theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      const { scheduleShot } = useLongliveV2();
      await scheduleShot({ prompt: "Sunrise breaks over the dunes", at_session_chunk: 12 });
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      await reactor.send_command("schedule_shot", {
          "prompt": "Sunrise breaks over the dunes",
          "at_session_chunk": 12,
      })
      ```
    </CodeGroup>
  </Tab>

  <Tab title="schedule_scene_cut">
    ### schedule\_scene\_cut

    Plant a hard cut at a specific **cumulative** chunk index. Pre-encodes the prompt so the cut fires
    with no activation latency at the target. Use scheduled cuts to bound each scene within its
    48-chunk budget and compose a full sequence ahead of `start`. Acknowledged by
    `scene_cut_scheduled`.

    **Parameters:**

    | Parameter          | Type    | Required | Description                                         |
    | ------------------ | ------- | -------- | --------------------------------------------------- |
    | `prompt`           | string  | Yes      | The new scene's prompt text                         |
    | `at_session_chunk` | integer | Yes      | Cumulative chunk index (≥ 0) at which the cut fires |

    **Example:**

    <CodeGroup>
      ```typescript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      await reactor.sendCommand("schedule_scene_cut", {
        prompt: "Hard cut to an underwater coral reef, shafts of light cutting through blue water",
        at_session_chunk: 24,
      });
      ```

      ```tsx React theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      const { scheduleSceneCut } = useLongliveV2();
      await scheduleSceneCut({
        prompt: "Hard cut to an underwater coral reef",
        at_session_chunk: 24,
      });
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      await reactor.send_command("schedule_scene_cut", {
          "prompt": "Hard cut to an underwater coral reef, shafts of light cutting through blue water",
          "at_session_chunk": 24,
      })
      ```
    </CodeGroup>
  </Tab>

  <Tab title="start / pause / resume / reset">
    ### start

    Begin generating video on `main_video`. Requires an opening shot set via `set_shot`; zeros the
    cumulative counter. Rejected with `command_error` if no prompt is set, or after a run has
    completed (call `reset` first).

    ### pause / resume

    `pause` halts generation after the current chunk finishes (`generation_paused`); `resume`
    continues (`generation_resumed`). `pause` is only valid while generating; `resume` only while
    paused.

    ### reset

    Abort the current run, clear the active prompt and every scheduled shot/cut, and return to the
    idle waiting state (`generation_reset`). Always succeeds. After reset you must call `set_shot`
    again before `start`.

    <CodeGroup>
      ```typescript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      await reactor.sendCommand("start", {});
      await reactor.sendCommand("pause", {});
      await reactor.sendCommand("resume", {});
      await reactor.sendCommand("reset", {});
      ```

      ```tsx React theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      const { start, pause, resume, reset } = useLongliveV2();
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      await reactor.send_command("start", {})
      await reactor.send_command("pause", {})
      await reactor.send_command("resume", {})
      await reactor.send_command("reset", {})
      ```
    </CodeGroup>
  </Tab>

  <Tab title="set_seed">
    ### set\_seed

    Set the noise seed for sampling. The seed is read once when `start` fires; changes after that take
    effect on the next `reset` + `start`.

    **Parameters:**

    | Parameter | Type    | Required | Description                         |
    | --------- | ------- | -------- | ----------------------------------- |
    | `seed`    | integer | Yes      | Noise seed. Same seed → same output |

    <CodeGroup>
      ```typescript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      await reactor.sendCommand("set_seed", { seed: 42 });
      ```

      ```tsx React theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      const { setSeed } = useLongliveV2();
      await setSeed({ seed: 42 });
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
      await reactor.send_command("set_seed", {"seed": 42})
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Messages from model

The model emits these events. Subscribe with `reactor.on("message", ...)` (or the generated React
hooks). Every message is delivered as JSON `{ "type": "<name>", "data": { … } }`.

| Event                 | When                                              | Payload                                                                                |
| --------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `shot_set`            | A `set_shot` was accepted                         | `{ prompt: string }`                                                                   |
| `scene_cut`           | A `scene_cut` fired (immediate or scheduled)      | `{ prompt: string, at_session_chunk: int }`                                            |
| `shot_scheduled`      | A `schedule_shot` was accepted                    | `{ prompt: string, at_session_chunk: int }`                                            |
| `scene_cut_scheduled` | A `schedule_scene_cut` was accepted               | `{ prompt: string, at_session_chunk: int }`                                            |
| `generation_started`  | `start` succeeded, frames begin                   | `{ prompt: string, chunk_num: int, frame_num: int }`                                   |
| `chunk_complete`      | Once per completed chunk of `main_video`          | `{ chunk_index: int, session_chunk: int, frames_emitted: int, active_prompt: string }` |
| `generation_paused`   | In response to `pause`                            | `{ chunk_index: int }`                                                                 |
| `generation_resumed`  | In response to `resume`                           | `{ chunk_index: int }`                                                                 |
| `generation_reset`    | In response to `reset`                            | `{ reason: string }`                                                                   |
| `generation_complete` | A scene reached the chunk ceiling with no cut     | `{ total_chunks: int }`                                                                |
| `command_error`       | A command was rejected (bad precondition)         | `{ command: string, reason: string }`                                                  |
| `state`               | On connect, after every command, after each chunk | Full session snapshot (see below)                                                      |

### `state` payload

`state` is the single source of truth for the session's observable state. Subscribe once and treat
it as the authoritative session snapshot; you generally do not need to track individual command
acknowledgements and `chunk_complete` events yourself.

| Field                  | Type             | Meaning                                                                               |
| ---------------------- | ---------------- | ------------------------------------------------------------------------------------- |
| `running`              | `bool`           | `started && !paused`. Equivalent to "frames are actively streaming"                   |
| `started`              | `bool`           | True once `start` has been accepted; remains true through pauses. False on `reset`    |
| `paused`               | `bool`           | True while generation is paused                                                       |
| `current_chunk`        | `int`            | Chunks since the current scene began; resets to `0` on every `scene_cut`              |
| `session_chunk`        | `int`            | Cumulative chunks since `start`; never resets. The clock scheduled beats fire against |
| `current_frame`        | `int`            | Frames emitted on `main_video` so far                                                 |
| `current_prompt`       | `string \| null` | The prompt currently driving generation, or `null` if none set                        |
| `has_prompt`           | `bool`           | Whether an opening shot has been set this session                                     |
| `seed`                 | `int`            | Current seed value (effective only on the next `start`)                               |
| `scheduled_shots`      | `int[]`          | `session_chunk` indices of pending scheduled shots                                    |
| `scheduled_scene_cuts` | `int[]`          | `session_chunk` indices of pending scheduled cuts                                     |

## Complete example

<CodeGroup>
  ```typescript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  import { LongliveV2Model } from "@reactor-models/longlive-v2";

  const longlive = new LongliveV2Model();

  longlive.onChunkComplete(({ session_chunk, active_prompt }) => {
    console.log(`chunk ${session_chunk}: ${active_prompt}`);
  });
  longlive.onCommandError(({ command, reason }) => {
    console.error(`${command} rejected: ${reason}`);
  });

  await longlive.connect(jwt);

  // Compose the storyboard before starting:
  await longlive.setShot({ prompt: "A lone astronaut walks across a red dune at golden hour" });
  await longlive.scheduleShot({
    prompt: "The camera pulls back to reveal a vast crater",
    at_session_chunk: 20,
  });
  await longlive.scheduleSceneCut({
    prompt: "Hard cut: a neon-lit Tokyo street at night",
    at_session_chunk: 40,
  });

  await longlive.start();
  ```

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

  async def main():
      reactor = Reactor(model_name="reactor/longlive-v2", api_key=os.environ["REACTOR_API_KEY"])

      @reactor.on_message("chunk_complete")
      def _(msg):
          print(f"chunk {msg['session_chunk']}: {msg['active_prompt']}")

      await reactor.connect()
      await reactor.send_command("set_shot", {"prompt": "A lone astronaut on a red dune at golden hour"})
      await reactor.send_command("schedule_shot", {"prompt": "Camera pulls back to a vast crater", "at_session_chunk": 20})
      await reactor.send_command("schedule_scene_cut", {"prompt": "Hard cut: neon Tokyo street at night", "at_session_chunk": 40})
      await reactor.send_command("start", {})
      await asyncio.Event().wait()

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