Virtual Tours
Build multi-scene 360° virtual tours with scene-switch hotspots and live camera state
Overview
A tour is a dictionary of scenes plus a default block that picks the first scene. Each scene is a Pannellum scene configuration: an equirectangular panorama URL, an initial camera (pitch, yaw, hfov), and optional hotSpots.
Hotspots with "type": "scene" switch to another scene when clicked — that's what turns a set of panoramas into a guided tour. sceneFadeDuration crossfades the transition.
Live example
Click the hotspot on the horizon to jump between scenes — and watch currentScene, pitch and yaw stream into the Dash callback below the viewer.
Scene jumps here are a clean crossfade with no "Loading…" flash: since 0.2.0 the component prefetches every other scene's panorama once the viewer is up (preloadScenes, on by default), and this example also sets hideLoadingSpinner=True so the load box never appears even on a cold cache:
# File: docs/tours/tour_example.py
import dash_mantine_components as dmc
from dash import Input, Output, callback, html
from dash_pannellum import DashPannellum
tour = {
"default": {
"firstScene": "observatory",
"sceneFadeDuration": 1000,
"author": "Pip Install Python",
},
"scenes": {
"observatory": {
"title": "ALMA Observatory",
"hfov": 110,
"pitch": -3,
"yaw": 117,
"type": "equirectangular",
"panorama": "https://pannellum.org/images/alma.jpg",
"autoLoad": True,
"hotSpots": [
{
"pitch": -2.1,
"yaw": 132.9,
"type": "scene",
"text": "Travel to Cerro Toco",
"sceneId": "desert",
}
],
},
"desert": {
"title": "Cerro Toco",
"hfov": 110,
"yaw": 5,
"type": "equirectangular",
"panorama": "https://pannellum.org/images/cerro-toco-0.jpg",
"hotSpots": [
{
"pitch": -0.6,
"yaw": 37.1,
"type": "scene",
"text": "Back to the observatory",
"sceneId": "observatory",
"targetYaw": -23,
"targetPitch": 2,
}
],
},
},
}
component = html.Div(
[
DashPannellum(
id="tour-demo",
tour=tour,
autoLoad=True,
compass=True,
# 0.2.0: scenes are prefetched (preloadScenes defaults True) and
# the load box is suppressed, so hotspot jumps are a clean fade.
hideLoadingSpinner=True,
width="100%",
height="450px",
),
dmc.Group(
[
dmc.Badge("—", id="tour-demo-scene", size="lg", variant="light"),
dmc.Code("waiting for camera…", id="tour-demo-view"),
],
mt="md",
gap="md",
),
]
)
@callback(
Output("tour-demo-scene", "children"),
Output("tour-demo-view", "children"),
Input("tour-demo", "currentScene"),
Input("tour-demo", "pitch"),
Input("tour-demo", "yaw"),
)
def show_camera_state(scene, pitch, yaw):
view = f"pitch {pitch or 0:+.1f}° · yaw {yaw or 0:+.1f}°"
return scene or "—", view
:defaultExpanded: false :withExpandedButton: true
Scene configuration
The most useful per-scene keys (all standard Pannellum options):
| Key | Type | Description |
|---|---|---|
panorama | str | URL of the equirectangular image |
title | str | Shown in the viewer's title bar |
hfov | number | Initial horizontal field of view, degrees |
pitch / yaw | number | Initial camera orientation |
autoLoad | bool | Load this scene without a click |
hotSpots | list | Scene-switch and info hotspots |
A scene-switch hotspot:
{
"pitch": -2.1, # where the hotspot sits in the panorama
"yaw": 132.9,
"type": "scene", # makes it a navigation hotspot
"text": "Next room", # tooltip
"sceneId": "kitchen", # scene to load on click
"targetYaw": -23, # optional: camera orientation after the jump
"targetPitch": 2,
}
Set showCenterDot=True and read pitch/yaw from a callback while aiming the dot at your target — the Callback Hotspots page demonstrates this workflow.
Tracking the active scene
currentScene updates whenever the user navigates, so you can drive any output from tour progress — breadcrumbs, maps, info panels:
@callback(
Output("scene-info", "children"),
Input("tour-demo", "currentScene"),
)
def describe(scene):
return SCENE_DESCRIPTIONS.get(scene, "")
Source: /components/tours
Note for AI agents: This is the static, prerendered view of an interactive Dash application served because we detected a non-JS user agent. Full prose docs:
- /components/tours/llms.txt — LLM-friendly documentation
- /sitemap.xml
- /robots.txt