Skip to main content
This page documents the complete LingBot wire surface: the media tracks it produces, the session lifecycle, every command you can send, and the messages the model emits back. For what LingBot is and a quick start, see the overview.

Tracks

DirectionNameTypeFormatRate
Outboundmain_videoVideo(N, H, W, 3) uint8 RGBAdaptive, paced to model throughput
Default resolution is 1664 x 960. There are no inbound tracks; all client → model communication is through commands.

Session lifecycle

LingBot runtime states: WAITING, GENERATING, PAUSED, with start/pause/resume/reset transitions and the set_* commands that take effect in each state
Once the connection reaches ready, the session begins in WAITING. start transitions to GENERATING (provided a prompt and seed image are set); pause moves to PAUSED; resume returns to GENERATING; reset clears state and returns to WAITING from any state. The Commands table below lists each command’s preconditions and effects. See Sessions for the separate connection-level lifecycle (disconnected → connecting → waiting → ready) the session passes through before reaching the runtime states above. When all chunks of a run complete and the session is still started, the server automatically kicks off the next run with the same prompt and image. Call reset to stop the loop and re-stage with new conditions.

Commands

Send commands to the model using reactor.sendCommand(). Setter commands (set_*) take effect at the next chunk boundary. Below are all available commands:
CommandDescription
set_promptSet or swap the text prompt (works before and during generation)
set_imageSet the seed image that anchors the world (required before start)
set_movementSet WASD movement direction
set_look_horizontalSet yaw (look left/right) direction
set_look_verticalSet pitch (look up/down) direction
set_rotation_speed_degSet how fast the camera rotates when a look axis is active
set_seedSet the RNG seed for the next generation
startBegin generation (requires a prompt and a seed image)
pausePause after the current chunk
resumeResume from a pause
resetClear all session state and return to WAITING

set_prompt

Stores the prompt and re-applies it on the next chunk boundary. Works before start and mid-generation for live prompt swaps. Emits prompt_accepted then conditions_ready.Parameters:
ParameterTypeRequiredDescription
promptstringYesPrompt text, ≤ 1000 chars
await reactor.sendCommand("set_prompt", {
  prompt: "A misty old-growth forest, soft morning light filtering through the canopy.",
});
const { setPrompt } = useLingbot();
await setPrompt({
  prompt: "A misty old-growth forest, soft morning light filtering through the canopy.",
});
await reactor.send_command("set_prompt", {
    "prompt": "A misty old-growth forest, soft morning light filtering through the canopy.",
})

Messages

LingBot emits the following messages. Every message is delivered as JSON { "type": "<name>", "data": { … } }.
EventWhenPayload
prompt_acceptedAfter set_prompt{ prompt: string }
image_acceptedAfter set_image decodes{ width: int, height: int }
conditions_readyAfter set_prompt or set_image{ has_prompt: bool, has_image: bool }
generation_startedAfter start{ prompt: string, chunk_num: int, frame_num: int }
chunk_completeAfter each chunk emits{ chunk_index: int, frames_emitted: int, active_prompt: string, active_action: string }
generation_pausedAfter pause{ chunk_index: int }
generation_resumedAfter resume{ chunk_index: int }
generation_completeAfter all chunks of a run finish{ total_chunks: int }
generation_resetAfter reset{ reason: string }
command_errorWhen a command is rejected{ command: string, reason: string }
stateOn connect, after every command, and after every chunk_completeFull session snapshot

state payload

state is the single source of truth for driving UI. Subscribe once and treat it as the authoritative session snapshot; you generally do not need to track individual set_* and chunk_complete events yourself.
FieldTypeMeaning
runningboolstarted && !paused. Equivalent to “frames are actively streaming”
startedboolTrue once start has been accepted; remains true through pauses and across auto-restarts. Flips back to false on reset
pausedboolTrue while in the PAUSED state
current_chunkintZero-based index of the last completed chunk; 0 before the first chunk and after reset
current_promptstring | nullThe prompt currently driving generation, or null if none set
has_promptboolWhether a prompt has been set this session
has_imageboolWhether a seed image has been set this session
current_actionstring+-joined composite of movement and look. E.g. "w+left", or "still" when idle
movementstringCurrent value of the movement input field
look_horizontalstringCurrent value of the look_horizontal input field
look_verticalstringCurrent value of the look_vertical input field
rotation_speed_degfloatCurrent rotation speed (0.0 – 30.0)
seedintCurrent seed value (effective only on the next start)

Complete example

Stage a seed image and prompt, wait for the image to decode, start, then drive the camera.
import { LingbotModel } from "@reactor-models/lingbot";

const lingbot = new LingbotModel();

lingbot.onChunkComplete(({ chunk_index, active_action }) => {
  console.log(`chunk ${chunk_index}: ${active_action}`);
});
lingbot.onCommandError(({ command, reason }) => {
  console.error(`${command} rejected: ${reason}`);
});

await lingbot.connect(jwt);

// Wait for the seed image to decode so the first chunk renders from it.
const imageAccepted = new Promise<void>((resolve) => lingbot.onImageAccepted(() => resolve()));
const ref = await lingbot.uploadFile(seedImageFile);
await lingbot.setImage({ image: ref });
await imageAccepted;

await lingbot.setPrompt({
  prompt: "A misty old-growth forest, soft morning light filtering through the canopy.",
});
await lingbot.start();

// Drive the camera (persistent state, holds until you change it).
await lingbot.setMovement({ movement: "forward" });
await lingbot.setLookHorizontal({ look_horizontal: "left" });
import asyncio, os
from reactor_sdk import Reactor

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

    image_accepted = asyncio.Event()

    @reactor.on_message("image_accepted")
    def _(msg):
        image_accepted.set()

    await reactor.connect()

    ref = await reactor.upload_file("seed.png")
    await reactor.send_command("set_image", {"image": ref})
    await image_accepted.wait()

    await reactor.send_command("set_prompt", {
        "prompt": "A misty old-growth forest, soft morning light filtering through the canopy.",
    })
    await reactor.send_command("start", {})

    # Drive the camera.
    await reactor.send_command("set_movement", {"movement": "forward"})
    await asyncio.Event().wait()

asyncio.run(main())