# How to Customize Camera Paths in the YAML Configuration for Rendered Output

> Customize camera paths in YAML config for rendered output. Edit camera blocks using presets like follow, birdeye, static, or pivot for smooth, interpolated paths with lingbot-map.

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

---

**You customize camera paths by editing the `camera` block in YAML configuration files (e.g., [`demo_render/config/indoor.yaml`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/config/indoor.yaml)) to define segments using presets like `follow`, `birdeye`, `static`, or `pivot`, which the `build_camera_path` function in [`demo_render/rgbd_render/camera.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/rgbd_render/camera.py) then interpolates into a smooth, key-frame-based trajectory.**

The lingbot-map rendering pipeline generates cinematic output by following camera trajectories defined entirely in human-readable YAML files. By modifying the `camera` section in configuration files such as [`demo_render/config/indoor.yaml`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/config/indoor.yaml), you control field-of-view, transition blending, and complex multi-segment camera movements without modifying Python source code.

## Understanding the Camera Path Architecture

The rendering system centers on the **`CameraPath`** class defined in [`demo_render/rgbd_render/camera.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/rgbd_render/camera.py) (lines 47-73), which stores a list of camera poses and interpolates between them to generate per-frame viewpoints. Rather than manually specifying thousands of coordinates, the pipeline provides **segment presets**—factory functions that generate `CameraPath` objects for specific motion styles:

- **`make_follow_path`** (lines 28-57): Generates a camera that trails the scanner trajectory with configurable spatial offsets and smoothing.
- **`make_birdeye_path`** (lines 61-73): Creates a static top-down view positioned above the scene center.
- **`make_static_path`** (lines 78-85): Produces a fixed viewpoint with constant eye and look-at positions.
- **`make_pivot_path`** (lines 88-96): Maintains a fixed eye position while dynamically updating the look-at target to follow the scan direction.

The **`build_camera_path`** function (lines 31-73) serves as the orchestrator. It reads the parsed YAML configuration, resolves frame boundaries, invokes the appropriate preset generators, and blends adjacent segments using a `_smoothstep` curve to eliminate jarring cuts.

## The YAML Configuration Schema

Camera behavior is controlled through a top-level `camera` block in your YAML file (e.g., [`demo_render/config/indoor.yaml`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/config/indoor.yaml)):

```yaml
camera:
  fov: 60.0               # vertical field-of-view in degrees

  transition: 30          # frames allocated for blending between segments

  segments:
    - mode: birdeye       # preset name: follow | birdeye | static | pivot

      frames: [0, -1]     # start-frame, end-frame (-1 means last frame)

      reveal_height_mult: 2.5   # birdeye-specific: height above scene

```

- **`fov`** sets the vertical field-of-view applied to all segments in the render.
- **`transition`** specifies the number of frames used to cross-fade between consecutive segments, creating smooth cinematic transitions.
- **`segments`** defines an ordered list of camera behaviors. Each entry requires a **`mode`** (selecting the preset function) and **`frames`** (an inclusive range where `-1` resolves to the final frame index). Additional parameters depend on the selected mode.

## Available Camera Path Presets and Parameters

Each preset in the YAML configuration maps directly to a specific generator function in [`demo_render/rgbd_render/camera.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/rgbd_render/camera.py), accepting distinct parameters:

**`mode: follow`**
- `back_offset`: Distance behind the scanner trajectory (0.0-1.0 scale).
- `up_offset`: Vertical elevation above the trajectory.
- `look_offset`: Forward displacement of the look-at target.
- `smooth_window`: Size of the averaging window for trajectory smoothing.

**`mode: birdeye`**
- `reveal_height_mult`: Multiplier determining camera height above the scene centroid.

**`mode: static`**
- `eye`: World-space coordinates `[x, y, z]` for the camera position.
- `lookat`: World-space coordinates `[x, y, z]` for the focal point.

**`mode: pivot`**
- `eye`: Fixed camera position `[x, y, z]`.
- The look-at target automatically follows the scanner trajectory.

## How the YAML Configuration is Processed into a Path

When the demo launches, the entry point loads the YAML file via `yaml.safe_load` and instantiates a **`CameraConfig`** object (defined in [`demo_render/config/__init__.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/config/__init__.py)). The `build_camera_path(cam_config, scene)` function then executes the following pipeline:

1. **Resolves frame indices**: Converts negative indices (like `-1`) to actual frame counts.
2. **Instantiates presets**: Calls the appropriate `make_*_path` function based on each segment's `mode`, passing YAML-supplied parameters.
3. **Blends transitions**: Overlaps consecutive segments by the specified `transition` frame count, applying the `_smoothstep` interpolation curve to smoothly blend position and rotation.
4. **Returns trajectory**: Produces a finalized `CameraPath` object queryable by frame index via `CameraPath[frame]`.

This architecture allows the YAML file to dictate the entire trajectory without requiring code changes.

## Practical YAML Configuration Examples

### Adding a Custom Follow Segment

This configuration captures the first 1500 frames with a trailing camera before switching to a bird's-eye overview:

```yaml
camera:
  fov: 70.0
  transition: 20
  segments:
    - mode: follow
      frames: [0, 1500]
      back_offset: 0.4
      up_offset: 0.12
      look_offset: 0.5
      smooth_window: 40
    - mode: birdeye
      frames: [1500, -1]
      reveal_height_mult: 3.0

```

As implemented in [`demo_render/rgbd_render/camera.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/rgbd_render/camera.py), frames 0-1499 use `make_follow_path` with the specified offsets, while frames 1500-end switch to `make_birdeye_path`. A 20-frame cross-fade blends the two motions.

### Configuring a Static Camera

For a completely fixed viewpoint throughout the entire render:

```yaml
camera:
  fov: 55.0
  transition: 10
  segments:
    - mode: static
      frames: [0, -1]
      eye: [1.0, 2.0, 3.0]
      lookat: [0.0, 0.0, 0.0]

```

The `make_static_path` function generates a `CameraPath` containing identical start and end keyframes, creating no motion.

### Using a Pivot Segment with Custom Eye Position

To keep the camera stationary while rotating to follow the scanner:

```yaml
camera:
  fov: 60.0
  transition: 15
  segments:
    - mode: pivot
      frames: [0, -1]
      eye: [0.5, 0.5, 0.5]

```

The `make_pivot_path` preset maintains the eye at `[0.5, 0.5, 0.5]` while dynamically updating the look-at vector to track the scanner trajectory.

## Summary

- **Camera paths** in lingbot-map are defined via YAML configuration files in `demo_render/config/` rather than hardcoded Python.
- The **`CameraPath`** class and **`build_camera_path`** function in [`demo_render/rgbd_render/camera.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/rgbd_render/camera.py) handle interpolation and segment blending.
- Four presets are available: **`follow`**, **`birdeye`**, **`static`**, and **`pivot`**, each with mode-specific parameters.
- The **`transition`** parameter controls cross-fade duration between segments using smoothstep interpolation.
- Frame ranges use standard indexing where **`-1`** resolves to the final frame of the sequence.

## Frequently Asked Questions

### What is the difference between the `follow` and `pivot` camera modes?

**`follow`** generates a camera that physically trails behind the scanner trajectory with configurable back, up, and look offsets, creating a third-person perspective. **`pivot`** keeps the camera eye at a fixed world position (specified by the `eye` parameter) and only rotates the view direction to track the scan, creating a stationary observational viewpoint.

### How do I create a smooth transition between two different camera angles?

Set the **`transition`** parameter in the YAML root `camera` block to the number of frames you want for the cross-fade (e.g., `transition: 30`). The `build_camera_path` function automatically blends the end of the previous segment with the start of the next using a smoothstep curve, ensuring cinematic continuity without manual keyframe editing.

### Can I chain multiple different camera presets in a single rendered video?

Yes. The **`segments`** field accepts an ordered list, allowing you to sequence any combination of `follow`, `birdeye`, `static`, and `pivot` modes. Define non-overlapping frame ranges for each segment (e.g., `[0, 500]`, `[501, 1000]`), and the pipeline will concatenate them into a single continuous `CameraPath` with automatic blending at the boundaries.

### What file contains the logic that parses the YAML camera configuration?

The **`CameraConfig`** object that holds the parsed YAML values is defined in [`demo_render/config/__init__.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo_render/config/__init__.py), while the trajectory generation logic resides 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 acts as the bridge between the configuration object and the executable camera trajectory used by the renderer.