Hotspots
Hotspots
Hotspots turn a static 360° object into an interactive product experience. Click a marker in the viewer and your visitor sees a description, jumps to another scene, opens a video, or downloads a PDF. Hotspots are authored in the desktop editor, stored with the project, and exported with the viewer package.
This guide covers what hotspots are, when to use them, how to create them in the editor, and the best practices that keep them useful for your visitors and fast for your site.
What is a hotspot?
A hotspot is a clickable marker pinned to a normalized coordinate on
a frame of your object. The marker is rendered as part of the
<rotavue-viewer> component; clicking it triggers a typed action (info
popup, link, scene navigation, image, video, PDF, YouTube, or Vimeo).
Each hotspot has:
- A type — what the marker does when clicked.
- A position — a
(x, y)pair in the range0..100(percent of canvas width and height). - A visibility range — the inclusive
start_frameandend_frameduring which the marker is shown. - A title and optional description — the human-readable label shown in the popup header.
- A content — the URL, scene target, or text payload for the action.
- A style — icon, color, size, and a pulse animation flag.
The full TypeScript shape is defined in
app/ui/src/types/hotspot.ts:
export type HotspotType =
| "info" | "url" | "navigation" | "image"
| "video" | "pdf" | "youtube" | "vimeo";
export interface Hotspot {
id: string;
project_id: string;
position: { x: number; y: number }; // 0..100
visibility: { start_frame: number; end_frame: number };
type: HotspotType;
title: string;
content: string;
description?: string;
style: { icon: string; color: string; size: number; pulse: boolean };
enabled: boolean;
}
When to use hotspots
Hotspots shine when the marker adds information that the photograph itself cannot convey. Common use cases:
| Use case | Recommended hotspot type |
|---|---|
| Callout a feature (stitching, materials, hardware ports) | info |
| Send visitors to a product detail page or a buy button | url |
| Connect a multi-object set so the visitor can hop from one turntable to another | navigation |
| Show a flat lay or alternate angle of the same product | image |
| Demo the product in motion | video |
| Embed a how-to or unboxing video | youtube / vimeo |
| Ship a spec sheet, manual, or warranty document | pdf |
A 360° object without hotspots is still useful. Add hotspots when the additional interactivity justifies the visual weight on the canvas.
Hotspot type reference
info
A modal popup with rich text. content is rendered as a text block;
basic HTML is allowed. The popup traps focus and closes on Esc or
on backdrop click.
url
Opens content in a new browser tab. The viewer validates that
content parses as an http:// or https:// URL. Anything else
(javascript:, data:, missing scheme) is rejected and the popup
shows “Invalid URL”.
navigation
Jumps to another frame within the same project. content is a
"col,row" pair (zero indexed, comma-separated, no spaces) matching
a frame in the current project’s grid. For example, "3,2" jumps to
column 3, row 2.
image
Loads and displays an image inline in the popup. content is an
absolute or relative URL to a JPEG, PNG, or WebP asset. Same URL
safety check as url.
video
Loads a self-hosted MP4 or WebM asset. The popup mounts a <video>
element with native controls. Prefer H.264 MP4 for the broadest
compatibility.
youtube
Embeds a YouTube player. content accepts a watch URL
(https://www.youtube.com/watch?v=…) or a short URL
(https://youtu.be/…). The viewer extracts the video ID and
constructs the embed URL with the standard
https://www.youtube.com/embed/<id> form, including the
accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture permissions.
vimeo
Embeds a Vimeo player. content accepts a Vimeo URL of the form
https://vimeo.com/<id>. The viewer extracts the numeric ID and
embeds https://player.vimeo.com/video/<id>.
pdf
Opens a PDF link in a new tab. content is an absolute or relative
URL to a .pdf file. Same URL safety check as url. Keep files
under ~10 MB for the fastest open experience.
Creating a hotspot in the editor
- Open the project, build it, and switch to the Hotspots tab. The preview becomes an editing surface.
- Turn the object (drag, arrow keys or the on-screen controls) to a view where the spot is visible.
- Click Add hotspot, then click the spot on the object. (Dragging an existing marker moves it; the new position is saved when you let go.)
- Fill in the dialog:
- Title (up to 200 characters) and Type (one of the eight above).
- The content field (labelled for the type: text, link address, target view, image, video, PDF) — what the marker shows or opens.
- Start and end frame — the range of turn steps where the marker is shown, numbered from 1 like the “Frame N / M” badge in the preview.
- Under Position and appearance: exact position in percent, icon, colour, size, pulse animation and an optional description.
- Click Add Hotspot (or Update Hotspot when editing).
A marker keeps its place on the screen, not on the object. Something that turns with the object will drift, so keep the frame range short for such markers.
Configuring scene navigation
The navigation type expects a content value of "col,row" that
matches a frame in the current project. If you target a scene in a
different project, the viewer falls back to opening that project’s
URL. To keep navigation offline-friendly and fast, use scenes inside
the same project.
Examples:
| Content value | Target |
|---|---|
0,0 | First frame (top-left) |
3,2 | Column 3, row 2 of a 4×3 grid |
0,0 (last column, last row) | Bottom-right of the grid |
Configuring link safety
URLs entered into url, image, video, and pdf hotspots are
validated by the viewer at render time. Only http:// and https://
URLs are accepted; everything else is rejected and the popup shows
“Invalid URL”. You do not need to escape URLs in the JSON manifest
— the viewer runs them through the URL parser before assigning to
href.
When a link opens, it does so in a new tab with
rel="noopener noreferrer" so the destination page cannot reach
back into the viewer’s window.
Best practices
- Anchor to features, not faces. A marker on a USB-C port is more useful than one on a generic surface. Visitors scan for the marker to learn something.
- Keep the title short. “USB-C port” beats “USB Type-C charging port with Power Delivery 3.0 support”. The full name belongs in the description.
- Use 1–3 hotspots per frame, max. Beyond three, the canvas looks busy and visitors stop clicking.
- Set a sensible visibility range. If a feature is only visible from frames 18–24, set the visibility range to exactly that segment; the marker will appear and disappear naturally as the visitor rotates.
- Use a consistent color per hotspot type. Pick a single accent
color for
infomarkers and stick with it across the project. Visitors will start to recognize the affordance. - Disable the pulse on dense markers. Pulse draws the eye; with more than two markers, the canvas becomes visually noisy.
- Reuse the same icon set. The editor default glyphs are a good starting point. If you swap to emoji or unicode characters, do so consistently across the project.
- Test every hotspot before export. Open the Internal Player, scrub through the full rotation, and click each marker. A misconfigured URL silently fails with “Invalid URL” in the popup.
Performance considerations
- Hotspots are stored in the project JSON and serialized into the exported viewer package. Each hotspot adds roughly 200 bytes to the manifest. 100 hotspots is well under 25 KB and does not affect load time.
- The viewer renders markers with CSS, not as canvas elements, so
they remain crisp at any zoom level. The pulse animation uses
transformandopacityonly and does not trigger layout. - Filtering visible markers per frame is constant-time: the viewer reads the current frame index and pre-computes the visible set on frame change. Switching from one frame to another is therefore O(visible) regardless of project size.
- Avoid embedding very large images in the popup. The
imagetype loads the asset on click; an 8 MB JPEG will block the main thread when the visitor opens it. Use a thumbnail plus link for high-res assets. - For
videoandpdftypes, prefer pre-encoded H.264 MP4 (≤ 1080p) and ≤ 10 MB PDFs. The viewer lazy-loads the asset on first click.
Examples
1. E-commerce callout
A shoe retailer wants to highlight the sole construction on a turntable of a sneaker.
| Field | Value |
|---|---|
| Type | info |
| Title | ”Carbon plate” |
| Description | ”Full-length carbon plate for energy return” |
| Content | ”Visible from the medial side, runs from heel to toe.” |
| Position | x=42, y=68 (mid-shoe, lower) |
| Visibility | frames 12–30 |
| Style | icon=“light bulb”, color=“#6366f1”, size=32, pulse=true |
2. Multi-product navigation
A museum’s online exhibit has a glass case with three artifacts on three turntables. The hotspot on artifact A jumps to the turntable for artifact B.
| Field | Value |
|---|---|
| Type | navigation |
| Title | ”See also: Bronze figurine” |
| Content | ”0,0” (the target frame) |
| Position | x=80, y=50 (right side of the frame) |
| Visibility | frames 0–35 (always visible) |
| Style | icon=“walking”, color=“#22c55e”, size=36, pulse=false |
3. Embedded demo
A kitchen appliance brand embeds an unboxing video from their channel.
| Field | Value |
|---|---|
| Type | youtube |
| Title | ”Watch the unboxing” |
| Content | https://www.youtube.com/watch?v=dQw4w9WgXcQ |
| Position | x=15, y=85 (lower-left) |
| Visibility | frames 0–71 (full rotation) |
| Style | icon=“play”, color=“#ef4444”, size=40, pulse=true |
Reference
- Viewer embed reference:
/api/viewer - Getting started:
/first-project