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

# LTX overview

> What LTX 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>;
};

**LTX** turns a photo and a script into a video-and-audio take of that person speaking. One
generation pass produces the speech and the lip-synced picture together; there is no separate
text-to-speech step.

LTX is a [Lightricks](https://www.lightricks.com) model. Reactor serves it as a live session your
app opens, drives, and watches over WebRTC, rather than a render job you queue and wait on.

The LTX reference is split across four pages: this overview, the complete
[command and event schema](/model-api-reference/ltx2/schema), the
[prompt guide](/model-api-reference/ltx2/prompt-guide) for writing scripts and scene prompts that
render well, and an end-to-end [tutorial](/model-api-reference/ltx2/tutorial).

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/ltx2`), send named commands,
receive events. LTX's surface adds commands for the avatar photo, the script, delivery style, and
take-level controls like speech rate and seed.

## At a glance

| Spec               | Value                                            |
| ------------------ | ------------------------------------------------ |
| **Model name**     | `reactor/ltx2`                                   |
| **Pricing**        | <ModelRate model="ltx2" />                       |
| **Resolution**     | 640×352 @ 24 fps, joint with 48 kHz stereo audio |
| **Maximum length** | 300s per take                                    |
| **Input**          | An avatar photo, a script, and a scene prompt    |

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

## Key features

<CardGroup cols={3}>
  <Card title="Identity lock" icon="user-round">
    One photo fixes the face for the whole take. Identity, framing, and background hold from the
    first frame to the last.
  </Card>

  <Card title="Joint video + audio" icon="audio-waveform">
    One generation pass produces the voice and the lip-synced picture together, on a single sample
    clock, and streams both as one take.
  </Card>

  <Card title="Scene-driven delivery" icon="drama">
    A separate scene prompt casts the voice and controls tone, energy, and setting, independent of
    the words being spoken.
  </Card>
</CardGroup>

## How a long take holds together

A take is not one continuous render. The model generates it in 20-second windows and opens a new
window every 10 seconds, so each window overlaps the one before it by half its length.

That overlap is what holds a long take together: each window is generated against the second half of
the previous one under the same conditioning, so the face, the voice, and the background carry
forward from window to window instead of drifting the way a chain of separate clips would.

Frames arrive at 24 fps in wall-clock time, whatever lead generation has built up. Play the stream
as it arrives; there is nothing to buffer or poll.

<Note>
  Take length defaults to the script length divided by the speech rate you set with `set_wpm`. A
  duration outside the 4 to 300 second range clamps into it. If your script is shorter than the
  requested duration, the avatar holds an idle presence for the remainder instead of looping or
  repeating the script.
</Note>

## Install

<Tabs>
  <Tab title="npm">
    ```shell theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
    npm install @reactor-models/ltx2
    ```
  </Tab>

  <Tab title="pnpm">
    ```shell theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
    pnpm add @reactor-models/ltx2
    ```
  </Tab>
</Tabs>

<Tip>
  `npx create-reactor-app my-avatar-app --model=ltx2` scaffolds a running app around the package,
  with a server-side token route and a video element already wired.
</Tip>

## Quick start

`Ltx2Model` is the typed client: one named method per command, one subscription per message.

```typescript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
import { Ltx2Model } from "@reactor-models/ltx2";

const model = new Ltx2Model();
const videoEl = document.querySelector("video")!;

// Both tracks are generated on one sample clock, so play them from ONE
// MediaStream on ONE element, or video and audio drift apart.
const stream = new MediaStream();
const attach = (track: MediaStreamTrack) => {
  stream.addTrack(track);
  videoEl.srcObject = stream;
};
model.onMainVideo(attach);
model.onMainAudio(attach);

await model.connect(jwt); // minted server-side, see Authentication

const avatarImage = await model.uploadFile(imageFile);
await model.setAvatarImage({ avatar_image: avatarImage });
await model.setScript({ script: "Hello from LTX." });
await model.start();
```

The same package ships React bindings, `<Ltx2Provider>` and `useLtx2()`, which the
[tutorial](/model-api-reference/ltx2/tutorial) builds a full app on. If you would rather send raw
commands, the base [`Reactor`](/sdk-reference/reactor-class) class speaks the same wire protocol;
see [Typed Model SDKs](/sdk-reference/typed-model-sdk).

## How it works

1. **Connect** to the model.
2. **Set the avatar image** with
   [`set_avatar_image`](/model-api-reference/ltx2/schema#set_avatar_image). Required before `start`.
3. **Set the script** with [`set_script`](/model-api-reference/ltx2/schema#set_script). Required
   before `start`.
4. **Set optional conditions**: a scene/delivery prompt, speech rate, duration, or seed.
5. **Start** the take.
6. **Control** playback with pause / resume / stop.
7. **Reset** to clear the avatar image and start over. `reset` is the only way to clear it.

The [schema](/model-api-reference/ltx2/schema) documents every command, message, and state field;
the [prompt guide](/model-api-reference/ltx2/prompt-guide) covers writing scripts and scene prompts;
the [tutorial](/model-api-reference/ltx2/tutorial) walks the whole flow in a working app.
