← Home Splash Map animation techniques

Two production-proven ways to put real geography in motion for video. Both are deterministic — every frame is computed, gated on fully-loaded map tiles, and rendered headlessly through Remotion — so a render is exactly repeatable, at any resolution, with no screen recording involved. Pick the treatment; the toggle above switches the full spec.

Technique 01 — Cesium Flyover

A helicopter glide through real terrain

Google-Earth-grade 3D mountains — quantized-mesh terrain draped in satellite imagery — with a camera that flows along a river, banks into the bends, and never jitters. For the beat where the viewer needs to feel the landscape: a canyon, a gorge, a coastline, a route.

Engine CesiumJS Terrain + imagery MapTiler Render harness Remotion Output MP4, any resolution
Actual output — Yarlung Tsangpo Great Bend, 24-second glide Compressed preview · full render is 1080p+

/ Fit

What it's for

Reach for it when

  • The story needs a cinematic reveal of a real place — fly through a canyon, over a mountain range, along a border or supply route.
  • You want true 3D geometry with sharp ridgelines, not a flat map tilted back.
  • The shot must be reproducible: re-render after a script change and get the identical move.

Not the tool for

  • Flat "where is this?" maps, choropleths, or data overlays — switch to the 2D Map Animation.
  • Street-level or city photorealism (that's a 3D-tiles job, a paid tier above this stack).

/ Architecture

Three parts, one job each

Neither engine can do this alone — Cesium won't render reliably headless by itself, and Remotion has no 3D globe. Stacked, they cover each other exactly.

Draws the world

CesiumJS

A true free camera in a 3D globe that renders to the horizon. Loaded from CDN at runtime, driven one frame at a time — its default render loop is switched off.

Feeds the world

MapTiler

Quantized-mesh terrain (real 3D geometry, crisp silhouettes) plus satellite imagery draped on top. One API key covers both — no separate Cesium ion account.

Runs the clock

Remotion

Steps the timeline frame by frame and holds each frame until every terrain tile is loaded before capturing it. Deterministic in, deterministic out.

/ Pipeline

From a line on a map to a finished shot

Prepare the camera path

Start from a river or route centerline (OpenStreetMap). The prep script clips a window, resamples it to even spacing, smooths it into continuously flowing curves, and dampens the swerve toward a straight chord — one knob controls how much the camera weaves.

Fly the path

Each frame, the camera walks the path by distance and aims at a real point further along it. That far aim is what makes the heading turn gently with the terrain — and the rate of turn drives a subtle roll, so the camera banks into bends like a helicopter.

Render

One headless Chrome, one frame at a time: npx remotion render … --gl=angle. Every frame waits for tilesLoaded before capture, so there are no half-loaded tiles in the final video — ever.

/ Live demo

The camera path, interactive

This is the actual path algorithm running in your browser, top-down. The thin cyan line is the raw river; the amber line is the smoothed, dampened camera path; the marker aims at a point ahead of itself and banks with the turn. Drag the sliders.

45%
2.0 km
1.0×

Swerve at 0% flies dead straight; 100% follows every meander. The proven water-wars values: swerve 45%, look-ahead 1.5 km, 13 km travelled over 24 s (≈0.54 km/s — slower reads calmer, and renders faster because tiles stay cached).

/ Tuning

Every feel decision is one number

You wantTurn thisProven value
Slower, more peacefulComposition duration (speed = distance ÷ seconds)24 s for 13 km
More / less swerveDAMP in the path script0.45
Higher / lower cameraALT_START / ALT_END (absolute, in metres)4600 → 4300 m
More horizon in framePITCH_FROM_NADIR76°
Stronger / gentler bankMAX_BANK / BANK_GAIN±7.5° / 0.6
More dramatic reliefverticalExaggeration1.1

The gotcha this skill exists to spare you

Cesium's globe silently refuses to draw in a plain headless browser — WebGL works, the sky renders, but the terrain produces zero draw commands. The fix that works: render through Remotion, disable Cesium's own render loop, drive every frame with viewer.render() (never scene.render()), and gate each frame on tilesLoaded. The skill's troubleshooting file maps every failure symptom to its fix.

/ Contents

What ships in the skill

SKILL.mdthe entry point — when to use it, architecture, quick start
assets/CesiumFlythrough.tsxthe runnable Remotion component
assets/example-Root.tsxminimal composition scaffold (duration = speed knob)
assets/sample-river.geojsonan OSM gorge centerline — works out of the box
assets/cesium-path.jsonthe pre-generated camera path for the sample
scripts/prep-cesium-path.mjscamera-path generator (dependency-free Node)
references/architecture.mdfull camera math + proven feel values
references/troubleshooting.mdevery symptom → its fix

/ Quick start

Four steps to a first render

# 1 — copy the component + scaffold into a Remotion project
cp assets/CesiumFlythrough.tsx  your-project/src/components/
cp assets/example-Root.tsx      your-project/src/Root.tsx

# 2 — generate a camera path (runs against the shipped sample as-is)
node scripts/prep-cesium-path.mjs                # or: … my-river.geojson src/geo/cesium-path.json

# 3 — set the key (must be an UNRESTRICTED MapTiler key; domain-locked keys 403 headless)
echo "REMOTION_MAPTILER_KEY=…" > .env

# 4 — validate one still, then render
npx remotion still  src/index.ts CesiumFlyover out.png --frame=360 --gl=angle --timeout=180000
npx remotion render src/index.ts CesiumFlyover out.mp4 --gl=angle --concurrency=1 --timeout=180000