# Google Timeline Visualizer Camera Tracking Modes: Fixed, Steady, and Dynamic Explained

> Explore Google Timeline Visualizer camera tracking modes: Fixed, Steady, and Dynamic. Understand their unique zoom behaviors and responsiveness to enhance your journey visualization.

- Repository: [mahlernim/google-timeline-visualizer](https://github.com/mahlernim/google-timeline-visualizer)
- Tags: deep-dive
- Published: 2026-08-23

---

**Google Timeline Visualizer offers three camera tracking modes—Fixed zoom, Steady following, and Dynamic following—each controlling how the virtual camera follows your journey with different zoom behaviors and responsiveness levels.**

The **camera tracking modes** in Google Timeline Visualizer give users fine-grained control over how their location history is presented. These modes are defined in [`web/src/types.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/types.ts) and implemented in [`web/src/camera.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/camera.ts), then surfaced through a dropdown UI in [`web/index.html`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/index.html). This article breaks down each mode's technical implementation and when to use it.

---

## Camera Movement Type Definitions

The foundation of all **camera tracking modes** is the `CameraMovement` type in **[`web/src/types.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/types.ts)**:

```typescript
// web/src/types.ts (line 32)
export type CameraMovement = 'fixed' | 'steady' | 'dynamic';

```

This type is used throughout the codebase to ensure type safety when selecting or switching modes.

---

## The Three Camera Tracking Modes

Each mode is implemented as a **movement profile** in the `MOVEMENT_PROFILES` object within [`web/src/camera.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/camera.ts). The profiles configure zoom aggression, context window size, and leg-aware behavior.

### Fixed Zoom Mode

**Fixed zoom** maintains a constant zoom level throughout the entire animation.

The zoom level is computed once from the `FIXED_ZOOM_PERCENTILE` of raw samples, then locked. The viewport pans to keep the journey centered, but the scale never changes regardless of speed or direction changes.

```typescript
// web/src/camera.ts (lines 36-47)
fixed: {
  // Constant zoom based on percentile of all samples
  contextFraction: 4,        // Large context window
  zoomOutAlpha: 1,           // Immediate zoom out (but zoom is fixed)
  zoomInAlpha: 1,            // Immediate zoom in (but zoom is fixed)
  legAware: false,           // No special handling for transport legs
  // Zoom computed once from FIXED_ZOOM_PERCENTILE
}

```

**Best for:** Getting a consistent overview of your entire journey without distracting zoom changes.

### Steady Following Mode

**Steady following** provides a smooth, stable camera that gently adapts to the journey's scale.

This mode uses a full context window (`contextFraction: 1`) and applies heavy damping to zoom changes. The `zoomOutAlpha` of 0.14 and `zoomInAlpha` of 0.035 create a deliberate, unhurried feel.

```typescript
// web/src/camera.ts (lines 48-58)
steady: {
  contextFraction: 1,        // Full journey context
  zoomOutAlpha: 0.14,        // Slow zoom out
  zoomInAlpha: 0.035,        // Very slow zoom in
  legAware: false,           // Uniform treatment of all segments
  // Smooth, cinematic pacing
}

```

**Best for:** Relaxed, movie-like playback where you want to appreciate the overall flow without jarring transitions.

### Dynamic Following Mode

**Dynamic following** reacts aggressively to rapid changes in your journey.

This mode uses a tight context window (`contextFraction: 0.10`) and enables **leg-aware behavior**, which treats different transport types (flights, drives, walks) distinctly. Zoom changes are roughly twice as fast as Steady mode.

```typescript
// web/src/camera.ts (lines 59-69)
dynamic: {
  contextFraction: 0.10,     // Tight local context
  zoomOutAlpha: 0.24,        // Fast zoom out
  zoomInAlpha: 0.06,         // Moderate zoom in
  legAware: true,            // Different behavior per transport type
  // Responsive to speed and direction changes
}

```

**Best for:** Complex, multi-modal journeys where you want the camera to emphasize transitions between flights, drives, and walking segments.

| Mode | Context Fraction | Zoom Speed | Leg Aware | Feel |
|------|-----------------|------------|-----------|------|
| **Fixed** | 4× (large) | N/A | No | Static, map-like |
| **Steady** | 1× (full) | Slow | No | Cinematic, relaxed |
| **Dynamic** | 0.1× (tight) | Fast | Yes | Responsive, energetic |

---

## How Camera Tracking Modes Are Wired Into the Application

The **camera tracking mode** selection flows through four key files:

1. **UI selection** — [`web/index.html`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/index.html) provides a `<select id="camera-movement">` element with options `fixed`, `steady`, and `dynamic`.

2. **Value reading** — [`web/src/main.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/main.ts) captures the selection: `cameraMovementSelect.value as CameraMovement`.

3. **Track building** — [`web/src/renderer.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/renderer.ts) receives the mode in `buildCameraTrack(journey, size, cameraMovement)`.

4. **Profile application** — Inside `buildCameraTrack`, the corresponding `MOVEMENT_PROFILES[cameraMovement]` configures how viewport frames are computed and smoothed.

This architecture lets users swap **camera tracking modes** at runtime without reprocessing the underlying journey data.

---

## Programmatically Switching Camera Tracking Modes

You can preview different **camera tracking modes** programmatically using the `buildCameraTrack` function from [`web/src/renderer.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/renderer.ts):

```typescript
import { buildCameraTrack } from './renderer';
import type { CameraMovement } from './types';

// Preview a specific camera mode
function previewWithMode(mode: CameraMovement) {
  const track = buildCameraTrack(journey, size, mode);
  const viewport = cameraViewportAt(track, 0);
  console.log(`Mode: ${mode}`, viewport);
}

// Compare all three modes
previewWithMode('fixed');    // Constant zoom
previewWithMode('steady');   // Smooth, full-context following
previewWithMode('dynamic');  // Tight, responsive following

```

The returned `track` contains precomputed viewport frames that obey the selected movement profile's constraints.

---

## Summary

- **Fixed zoom** locks the zoom level using `FIXED_ZOOM_PERCENTILE`, panning only to center the path—ideal for consistent overviews.
- **Steady following** uses `contextFraction: 1` with heavy damping (`zoomOutAlpha: 0.14`, `zoomInAlpha: 0.035`) for smooth, cinematic playback.
- **Dynamic following** employs `contextFraction: 0.10`, **leg-aware behavior**, and faster zoom rates for responsive, detail-focused presentation.
- Mode selection is type-safe via `CameraMovement` in [`web/src/types.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/types.ts) and configurable at runtime through `MOVEMENT_PROFILES` in [`web/src/camera.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/camera.ts).

---

## Frequently Asked Questions

### What is the default camera tracking mode in Google Timeline Visualizer?

The default mode is **Steady following**. In [`web/index.html`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/index.html), the `<option value="steady">` element has the `selected` attribute, and the UI labels it "Steady following" (or localized equivalent via `data-i18n="cameraSteady"`).

### How does Dynamic following handle different transport types differently?

Dynamic following enables **leg-aware behavior** through `legAware: true` in its profile. When enabled, the camera logic in `buildCameraTrack` treats transport-type legs—such as flights versus ground travel—differently, potentially zooming out further for longer flight segments or adjusting framing based on expected speed.

### Can I implement a custom camera tracking mode?

Yes, though it requires modifying the source. You would: (1) extend `CameraMovement` in [`web/src/types.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/types.ts) with a new literal type, (2) add a corresponding profile to `MOVEMENT_PROFILES` in [`web/src/camera.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/camera.ts) with your desired `contextFraction`, `zoomOutAlpha`, `zoomInAlpha`, and `legAware` values, and (3) add the option to the `<select>` in [`web/index.html`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/index.html).

### Why does Fixed zoom still have contextFraction and alpha values in its profile?

The `contextFraction`, `zoomOutAlpha`, and `zoomInAlpha` fields exist for API consistency across all profiles, but **Fixed zoom** ignores them during playback. The zoom level is computed once from `FIXED_ZOOM_PERCENTILE` and never updated, making these values inert for that mode.