Join us online - 19th of November
Save your spot
For AI agents: a documentation index is available at /llms.txt. Markdown versions of all pages are available by appending .md to any URL.

Create a guided tour with annotations

This example demonstrates how to build a guided tour by controlling annotations programmatically with openPopup() and closePopup().

NPM module setup


npm install --save @maptiler/geosplats
import { SplatModel, Map, config } from "@maptiler/geosplats";
import "@maptiler/geosplats/dist/maptiler-geosplats.css";

config.apiKey = "YOUR_MAPTILER_API_KEY_HERE";

const map = new Map({
  apiKey: config.apiKey,
  container: "map",
  center: [-80.27822, 25.74077],
  zoom: 17.5,
  pitch: 50,
  bearing: -15,
});

let splatModel;
map.on("load", () => {
  splatModel = new SplatModel({
    model: "YOUR_MAPTILER_SPLAT_MODEL_ID_HERE",
    revealParams: { enabled: true },
  });
  map.addSplatModel(splatModel);
});

const tour = [];
let currentStep = 0;

function goTo(index) {
  if (!tour.length) return;
  currentStep = (index + tour.length) % tour.length;
  const indicator = document.getElementById("stepIndicator");
  if (indicator) {
    indicator.textContent = `Step ${currentStep + 1} of ${tour.length}`;
  }
  tour[currentStep].openPopup();
}

map.on("splatmodel:load", () => {
  const a1 = splatModel.addAnnotation({
    pos: { x: -0.06, z: -0.26 },
    icon: "🏢",
    label: "1. Main Lobby",
    popup: "<h3>1. Main Lobby</h3><p>Grand entrance hall and 24/7 concierge reception.</p>",
  });

  const a2 = splatModel.addAnnotation({
    pos: { x: -0.4, z: -0.2 },
    icon: "🏖️",
    label: "2. Sun Pool",
    popup: "<h3>2. Sun Pool</h3><p>Heated resort pool surrounded by palm groves and cabanas.</p>",
  });

  const a3 = splatModel.addAnnotation({
    pos: { x: 0.6, z: 0.46 },
    icon: "🎾",
    label: "3. Tennis Club",
    popup: "<h3>3. Tennis Club</h3><p>10 floodlit championship clay courts.</p>",
  });

  const a4 = splatModel.addAnnotation({
    pos: { x: -0.6, z: 0.5 },
    icon: "⛳",
    label: "4. Golf Course",
    popup:
      "<h3>4. Golf Course</h3><p>18-hole championship green surrounding the resort grounds.</p>",
  });

  tour.push(a1, a2, a3, a4);
  goTo(0);
});

document.getElementById("nextBtn")?.addEventListener("click", () => goTo(currentStep + 1));
document.getElementById("prevBtn")?.addEventListener("click", () => goTo(currentStep - 1));

document.addEventListener("keydown", (e) => {
  if (e.key === "ArrowRight") {
    goTo(currentStep + 1);
  } else if (e.key === "ArrowLeft") {
    goTo(currentStep - 1);
  } else if (e.key === "Escape") {
    tour[currentStep]?.closePopup();
  }
});

Opening popups programmatically

While popups typically open on user clicks, you can trigger them directly in JavaScript using the SplatAnnotation instance handle.

Calling annotation.openPopup() opens the annotation’s popup and automatically closes whichever popup was previously open:


const tour = []; // SplatAnnotation handles

function goTo(stepIndex) {
  tour[stepIndex].openPopup();
}

Unlike user clicks, openPopup() does not fire "annotation:click", but it fires "annotation:active" on the model and "splatmodel:annotation:active" on the map.

Store the returned SplatAnnotation handles in an array when adding annotations during splatmodel:load. You can then step forward or backward using external UI buttons:


let currentStep = 0;

document.getElementById("nextBtn").addEventListener("click", () => {
  currentStep = (currentStep + 1) % tour.length;
  tour[currentStep].openPopup();
});

When a popup opens, the active pin bounces and a pulse ring ripples across the model surface, directing the viewer’s attention to the active point of interest.

Keyboard shortcuts and escape handling

You can close any open popup programmatically with closePopup(). This makes it simple to bind keyboard shortcuts like Escape or the left and right arrow keys:


document.addEventListener("keydown", (event) => {
  if (event.key === "Escape") {
    tour[currentStep]?.closePopup();
  }
});

Learn more

Check out the MapTiler GeoSplats SDK reference to explore the SplatAnnotation interface.

How to add annotations to a splat model

Add annotations

Examples

Add interactive labelled pins and popups to a splat model.

Customize annotation pins and colors

Pin styles and categories

Examples

Style annotations with colors, icons, numbers, and custom popup placement.

Filter annotations by category at runtime

Filter annotations by category

Examples

Filter annotations by category using visibility toggle or color dimming.

Synchronize annotations with a sidebar list

Sync annotations with sidebar

Examples

Connect 3D model annotations bidirectionally with an external sidebar list.

Was this helpful?