Dev.to WebDev 🛠 Dev 👁 0 📖 4 min read

Plan an animated travel-map video with JavaScript

Disclosure: Album Map is the product associated with this account. This tutorial was prepared with an AI agent, and the JavaScript example was executed before publication. A travel video needs a clear relationship betwe

Disclosure: Album Map is the product associated with this account. This tutorial was prepared with an AI agent, and the JavaScript example was executed before publication.

A travel video needs a clear relationship between the places on the map and the memories shown at each stop. Before choosing camera movements or music, it helps to write a small storyboard: where the viewer goes, what appears there, and how long it stays on screen.

Here is a JavaScript recipe for planning that sequence. The output is a list of timed scenes you can use as a reference in a video editor or map builder.

Define the stops in story order

Keep the coordinates, place name, and caption together. This makes it easier to catch a caption attached to the wrong stop.

The example below uses five Canadian cities with approximate city coordinates and illustrative captions. It is a demonstration, not a customer trip.

const stops = [
  { place: "Toronto", coordinates: [-79.3832, 43.6532], note: "The starting point" },
  { place: "Kingston", coordinates: [-76.4860, 44.2312], note: "A waterfront stop" },
  { place: "Ottawa", coordinates: [-75.6972, 45.4215], note: "An afternoon in the capital" },
  { place: "Montreal", coordinates: [-73.5673, 45.5017], note: "City streets and shared photos" },
  { place: "Quebec City", coordinates: [-71.2080, 46.8139], note: "The final chapter" },
];

The coordinate pairs use longitude, latitude, the order used for GeoJSON positions in RFC 7946. Check the convention expected by your map library: some APIs accept named lat and lng fields instead.

Preserve the story order explicitly. Sorting photos by file name or upload time can put a travel route in the wrong sequence, especially when several people contribute.

Build a timing plan

For each location, reserve time for its photo, clip, or caption. Between locations, reserve time for the map transition. Keeping these durations separate lets you adjust the pace without changing the route.

function makeStoryboard(stops, {
  introSeconds = 2,
  travelSeconds = 1.5,
  holdSeconds = 3,
  outroSeconds = 2,
} = {}) {
  if (!Array.isArray(stops) || stops.length < 2) {
    throw new Error("Use at least two stops.");
  }

  for (const value of [introSeconds, outroSeconds]) {
    if (!Number.isFinite(value) || value < 0) {
      throw new Error("Intro and outro durations must be non-negative numbers.");
    }
  }
  for (const value of [travelSeconds, holdSeconds]) {
    if (!Number.isFinite(value) || value <= 0) {
      throw new Error("Travel and memory durations must be positive numbers.");
    }
  }

  const cleanStops = stops.map((stop, index) => {
    if (!stop || typeof stop.place !== "string" || !stop.place.trim()) {
      throw new Error(`Stop ${index + 1} needs a place name.`);
    }
    const coordinates = stop.coordinates;
    if (!Array.isArray(coordinates) || coordinates.length !== 2) {
      throw new Error(`Stop ${index + 1} needs [longitude, latitude].`);
    }
    const [lng, lat] = coordinates;
    if (!Number.isFinite(lng) || !Number.isFinite(lat)
      || Math.abs(lng) > 180 || Math.abs(lat) > 90) {
      throw new Error(`Stop ${index + 1} has invalid coordinates.`);
    }
    return { ...stop, place: stop.place.trim(), coordinates: [lng, lat] };
  });

  const scenes = [];
  let cursor = 0;
  function addScene(type, seconds, details = {}) {
    if (seconds === 0) return;
    scenes.push({ type, start: cursor, end: cursor + seconds, ...details });
    cursor += seconds;
  }

  addScene("intro", introSeconds);
  cleanStops.forEach((stop, index) => {
    if (index > 0) {
      addScene("travel", travelSeconds, {
        from: cleanStops[index - 1].coordinates,
        to: stop.coordinates,
        destination: stop.place,
      });
    }
    addScene("memory", holdSeconds, {
      place: stop.place,
      coordinates: stop.coordinates,
      note: stop.note || "",
    });
  });
  addScene("outro", outroSeconds);
  return { durationSeconds: cursor, scenes };
}

const storyboard = makeStoryboard(stops);
console.table(storyboard.scenes.map(scene => ({
  type: scene.type,
  place: scene.place || scene.destination || "",
  start: scene.start,
  end: scene.end,
})));
console.log("Total seconds:", storyboard.durationSeconds);

Run both code blocks in the same JavaScript file. With these settings, the plan lasts 25 seconds: two seconds for the opening, fifteen seconds across five memories, six seconds across four transitions, and two seconds for the ending.

The timing values are a planning example. Use the controls available in your chosen editor to approximate or refine them. This JSON is an independent planning format, not an Album Map import format or API contract.

Check the route before adding effects

The validation catches missing coordinates and values outside the longitude or latitude ranges. It cannot reliably detect a swapped pair when both numbers fall within valid ranges. Check that each pin appears in the intended city.

A connection between two pins also needs a clear meaning. It may represent the sequence of your trip, a flight, or a change of scene. For a driving route, use road geometry when you want the line to follow the roads; a line connecting city coordinates only represents the connection between them.

Then preview the route at the size people will watch. Keep labels readable, give captions enough time, and check that a photo stays associated with the correct location during a transition. For several contributors, agree on a short place name and one or two favorite memories for each stop before assembling the final edit.

Use the plan in a map-video workflow

In Album Map's creator workflows, the guided map builder combines photos, clips, and locations. The separate Map Animator is currently in beta and provides more detailed route and camera control. Choose the workflow based on whether your story centers on the memories at each stop or the map animation itself.

You can watch map-video examples and compare the workflows before starting. Use the storyboard as a checklist: the same location order, the right media at each stop, and a pace that lets the viewer follow the journey.

What do you use as the source of truth for a location-based video: the route, the media timeline, or a shared storyboard?

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.