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

# Build your own model

> Write a Python model with the Reactor Runtime and stream it to any client.

The rest of these docs describe the client side of Reactor: the app you write with the JavaScript or Python SDK to drive a model and render what it sends back. This section describes the other side, where that model comes from.

A model is a Python class built on the [Reactor Runtime](https://github.com/reactor-team/reactor-runtime), an open-source framework that turns an inference pipeline into a live, interactive video stream. You write two methods. The runtime handles WebRTC, the session lifecycle, media encoding, and every client that connects.

## How it works

<Steps>
  <Step title="Write the model">
    Subclass `ReactorModel`. Declare the tracks it sends, load your weights in `load()`, and emit frames from `run()`.

    ```python model.py theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
    from pathlib import Path

    from reactor_runtime import Output, ReactorModel, Video


    class MyOutput(Output):
        main_video: Video


    class MyModel(ReactorModel):
        def load(self, config_path: Path | None) -> None:
            self.pipe = load_my_model()
            self.prompt = "a sunny meadow"

        async def run(self) -> None:
            while True:
                await self.connected.wait()
                while self.connected.is_set():
                    frame = self.pipe.forward(prompt=self.prompt)
                    await self.emit(MyOutput(main_video=frame))
    ```
  </Step>

  <Step title="Declare what clients can change">
    An `@event` handler is a command a client can call. Its signature is the payload, and the runtime validates every field before the handler runs.

    ```python theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
    @event(name="set_prompt", description="Scene the model renders")
    async def set_prompt(self, prompt: str = InputField(default="a sunny meadow")) -> None:
        self.prompt = prompt
    ```
  </Step>

  <Step title="Run it locally">
    The `reactor` CLI builds a container with the runtime already inside it and serves your model on port 8080. The CLI and Docker are the only things that install on your machine — see [Install the CLI](/deploy/platform/installation).

    ```sh theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
    reactor init my-model
    cd my-model
    reactor run
    ```

    `reactor init` scaffolds a workspace with a working model, a `Dockerfile`, and the runtime already pinned, so there is something to run before you write anything.
  </Step>

  <Step title="Connect a client">
    Point the SDK at the model running on your machine. The same code drives a deployed model once you drop `local`.

    ```tsx theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
    <ReactorProvider modelName="my-model" local={true} connectOptions={{ autoConnect: true }}>
      <ReactorView className="w-full aspect-video" />
    </ReactorProvider>
    ```

    See [Using the SDK](/sdk-reference/using-the-sdk) for the full client API.
  </Step>

  <Step title="Deploy it">
    `reactor model register` once, then `reactor model publish` and `reactor model deploy` for each release, all from the same workspace. It runs on Reactor's GPUs, in every region the platform serves.
  </Step>
</Steps>

## What the runtime handles

<CardGroup cols={2}>
  <Card title="Real-time streaming" icon="signal">
    Frames reach clients over WebRTC as you generate them, not after the video is finished.
  </Card>

  <Card title="Live interaction" icon="sliders-horizontal">
    Clients change inputs mid-generation. Nothing restarts, and nothing is re-queued.
  </Card>

  <Card title="No transport code" icon="plug">
    You never import a WebRTC library, hold a WebSocket open, or encode video.
  </Card>

  <Card title="Validated inputs" icon="shield-check">
    Declare each command with types and constraints. The runtime checks every payload first.
  </Card>
</CardGroup>

## Next

<CardGroup cols={2}>
  <Card title="Runtime Overview" icon="compass" href="/deploy/development/overview">
    Tracks, the run loop, commands, and messages.
  </Card>

  <Card title="Model Anatomy" icon="microscope" href="/deploy/development/reactor-model/model-anatomy">
    A working model read line by line.
  </Card>
</CardGroup>
