# How to Configure Camera Paths in YAML for LingBot-Map's Offline Rendering

> Configure LingBot-Map camera paths in YAML files to define custom offline rendering sequences. Learn how to set up segments, transitions, and camera modes for dynamic scene generation.

- Repository: [Robbyant/lingbot-map](https://github.com/Robbyant/lingbot-map)
- Tags: how-to-guide
- Published: 2026-07-08

---

**You define camera motion in LingBot-Map by creating a YAML file with a `camera` block containing `fov`, `transition`, and an ordered list of `segments` that specify modes like `follow`, `birdeye`, or `flyby`, which the `OfflinePipeline` loads via `build_camera_path()` in [`demo_render/rgbd_render/camera.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/rgbd_render/camera.py) to generate interpolated keyframes for each rendered frame.**

LingBot-Map's offline rendering system generates high-quality videos by following programmatic camera trajectories defined in configuration files. The rendering pipeline parses these YAML presets to construct smooth camera paths that follow reconstructions, execute flybys, or transition to bird's-eye views. Understanding how to structure these configuration files allows you to create cinematic visualizations without modifying the underlying Python source code.

## Architecture of the Camera Path System

The camera path system consists of four tightly integrated components that transform YAML declarations into rendered frames.

### Core Components

**`PipelineConfig`** ([`demo_render/rgbd_render/config.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/rgbd_render/config.py)) parses the entire YAML file and stores the camera configuration in `cfg.camera`. This dataclass handles merging base configurations with user overrides passed via command-line arguments.

**`CameraPath`** ([`demo_render/rgbd_render/camera.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/rgbd_render/camera.py)) implements the actual trajectory logic. It stores a list of keyframes (position and orientation quaternions) and provides `__getitem__` access so the renderer can query the interpolated camera pose for any frame index.

**`build_camera_path`** (in [`demo_render/rgbd_render/camera.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/rgbd_render/camera.py)) acts as the factory function that iterates over `cfg.camera.segments` and dispatches to preset generators (`follow`, `birdeye`, `flyby`, `keyframes`) based on the `mode` field.

**`OfflinePipeline`** ([`demo_render/rgbd_render/pipeline/offline.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/rgbd_render/pipeline/offline.py)) orchestrates the rendering process. It instantiates the `CameraPath` using `build_camera_path(cfg.camera, scene)` and calls `renderer.render_frame(scene, camera_path[i], ...)` for each frame index.

## YAML Configuration Structure

The `camera` block in your YAML file controls global optical parameters and defines the sequence of motions through segments.

### Global Camera Settings

Every camera configuration starts with two global fields:

- **`fov`** (float): The horizontal field of view in degrees applied to all frames. Example: `fov: 70.0`
- **`transition`** (int): The number of frames used for smooth interpolation between consecutive segments. Example: `transition: 20`

### The Segments List

The `segments` field contains an ordered list of motion presets. Each segment must specify a `mode` and mode-specific parameters. Frame ranges use inclusive indices, where `-1` represents the final frame of the animation.

## Supported Camera Modes

LingBot-Map implements four distinct camera modes in [`demo_render/rgbd_render/camera.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/rgbd_render/camera.py), each designed for specific visualization scenarios.

### Follow Mode

**`follow`** generates a camera trajectory that tracks alongside the reconstructed scene path, maintaining a fixed offset from the actual camera positions.

Required parameters:
- **`frames`**: `[start, end]` frame range
- **`back_offset`**: Distance behind the tracked camera (world units)
- **`up_offset`**: Vertical elevation above the tracked camera
- **`look_offset`**: Forward offset for the look-at target
- **`smooth_window`**: Rolling average window size for smoothing the trajectory

### Birdeye Mode

**`birdeye`** creates a static top-down view positioned high above the scene center, useful for revealing the full reconstruction layout.

Required parameters:
- **`frames`**: `[start, end]` frame range
- **`reveal_height_mult`**: Multiplier applied to the scene's bounding box height to determine camera altitude (e.g., `3.0` places the camera three times the scene height above the center)

### Flyby Mode

**`flyby`** moves the camera linearly between two world-space coordinates while maintaining focus on a specific target point.

Required parameters:
- **`frames`**: `[start, end]` frame range
- **`start`**: `[x, y, z]` world coordinates for the starting position
- **`end`**: `[x, y, z]` world coordinates for the ending position
- **`look_at`**: `[x, y, z]` world coordinates to maintain focus on
- **`smooth_window`**: Smoothing window for the camera motion

### Keyframes Mode

**`keyframes`** allows direct specification of absolute camera poses, bypassing the automatic generators for precise manual control.

Required parameters:
- **`frames`**: `[start, end]` frame range
- **`keyframes`**: List of dictionaries containing:
  - **`pos`**: `[x, y, z]` position array
  - **`wxyz`**: `[w, x, y, z]` quaternion rotation (scalar-first)

## Creating a Custom YAML Preset

Below is a production-ready configuration that demonstrates combining multiple modes with smooth transitions:

```yaml
camera:
  fov: 65.0
  transition: 15

  segments:
    # Track the reconstruction from a side view

    - mode: follow
      frames: [0, 2000]
      back_offset: 0.4
      up_offset: 0.1
      look_offset: 0.5
      smooth_window: 30

    # Transition to an overhead view

    - mode: birdeye
      frames: [2000, -1]
      reveal_height_mult: 3.0

    # Optional: scripted fly-through

    - mode: flyby
      frames: [3500, 4000]
      start: [5.0, 1.0, 2.0]
      end: [5.0, 1.0, -2.0]
      look_at: [0.0, 0.0, 0.0]
      smooth_window: 20

```

When processed, the `transition: 15` value inserts 15 interpolated frames between the last `follow` pose and the first `birdeye` pose to prevent jarring cuts.

## Running the Offline Pipeline with Your Config

Save your YAML configuration to a file (e.g., [`my_camera.yaml`](https://github.com/Robbyant/lingbot-map/blob/main/my_camera.yaml)) and execute the rendering pipeline using the `--camera_config` override flag:

```bash
python demo_render/rgbd_scan_render.py \
    --config demo_render/config/indoor.yaml \
    --camera_config my_camera.yaml \
    --input_folder example/university \
    --output out.mp4

```

The `--camera_config` argument merges your camera-specific YAML with the base configuration, overriding only the `camera` section while preserving scene, preprocessing, and rendering settings from the base file.

## Inspecting and Reusing Generated Camera Paths

After rendering completes, LingBot-Map writes a snapshot of the interpolated camera path to `<output>_config.yaml` (e.g., [`out_config.yaml`](https://github.com/Robbyant/lingbot-map/blob/main/out_config.yaml)). This file contains the flattened, frame-by-frame camera data:

```yaml
camera_path:
  total_frames: 4200
  interpolation: linear
  keyframes:
    - pos: [4.8, 0.9, 2.1]
      wxyz: [0.0, 0.0, 0.0, 1.0]
    - pos: [4.5, 0.9, 2.0]
      wxyz: [0.1, -0.2, 0.0, 0.98]

```

You can reload this exact path for deterministic replay using the Python API:

```python
from demo_render.rgbd_render.camera import CameraPath

camera_path = CameraPath.load('out_config.yaml')

```

## Summary

- **Camera paths in LingBot-Map are YAML-driven** through the `camera` block containing `fov`, `transition`, and `segments`.
- **Four preset modes** (`follow`, `birdeye`, `flyby`, `keyframes`) in [`demo_render/rgbd_render/camera.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/rgbd_render/camera.py) generate keyframes automatically from high-level descriptions.
- **`build_camera_path()`** processes the YAML segments and handles interpolation between modes using the `transition` frame count.
- **Command-line overrides** via `--camera_config` allow experimentation without modifying base configuration files.
- **Output snapshots** in `<video>_config.yaml` enable reproducible rendering and debugging of complex camera motions.

## Frequently Asked Questions

### How do I smoothly transition between different camera modes?

Set the `transition` field in your YAML `camera` block to the number of frames you want for interpolation. According to the implementation in [`demo_render/rgbd_render/camera.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/rgbd_render/camera.py), the `build_camera_path` function automatically inserts linearly interpolated keyframes between the last pose of the previous segment and the first pose of the next segment using this frame count.

### Can I combine automatic presets with manually specified keyframes?

Yes. You can mix `follow`, `birdeye`, or `flyby` segments with `keyframes` segments in the same `segments` list. The `keyframes` mode accepts a list of absolute poses (`pos` and `wxyz`) that the system interpolates between, allowing you to script precise camera movements where automatic generation is insufficient.

### What does the `-1` value mean in the `frames` parameter?

In the YAML configuration, `-1` is a sentinel value that resolves to the last frame of the animation sequence. For example, `frames: [2000, -1]` creates a segment that starts at frame 2000 and continues until the end of the video, regardless of the total frame count.

### Where is the final camera path data stored after rendering?

The `OfflinePipeline` in [`demo_render/rgbd_render/pipeline/offline.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/rgbd_render/pipeline/offline.py) writes a complete snapshot to `<output>_config.yaml` alongside your video file. This file contains the `CameraPath` object with all interpolated keyframes, allowing you to inspect exact per-frame poses or reload the exact path using `CameraPath.load()` for identical reproduction.