A narrative combines media and actions; it is not just an array of camera coordinates. For an audible story, supply narration you can serve to the browser and its measured duration. For an intentional silent camera-and-caption story, use an empty media URL and an explicit timeline duration. In both cases use the current Work's panorama index.
import { Five } from '@realsee/five'
import { VreoKeyframeEnum, type VreoUnit, type VreoKeyframe, type CameraMovementData, type PrompterData } from '@realsee/vreo/typings'
// Use an accessible media asset, or an empty URL for Vreo's built-in silent timeline.
export function createNarrative(narrationUrl: string, durationMs: number, panoIndex: number, fov = 90): VreoUnit {
if (!Number.isFinite(durationMs) || durationMs < 4000) throw new Error('Use a timeline at least four seconds long')
const camera: CameraMovementData = { mode: Five.Mode.Panorama, panoIndex, longitude: 0, latitude: 0, fov }
const caption: PrompterData = { text: 'Welcome to this space.' }
const keyframes: VreoKeyframe[] = [
{ type: VreoKeyframeEnum.CameraMovement, start: 0, end: 2000, data: camera },
{ type: VreoKeyframeEnum.Prompter, start: 0, end: 4000, data: caption }
]
return { video: { url: narrationUrl, duration: durationMs, start: 0, end: durationMs }, keyframes }
}The function deliberately requires a timeline of at least four seconds so both example actions fit. Call it with a real media URL and pass the returned unit to the player quickstart.
Use the published model
| Field | Meaning |
|---|---|
video.url | Accessible narration audio/video asset, or an empty string for the built-in silent timeline |
video.duration, start, end | Timeline values in milliseconds |
keyframes[].start, end | The action's time window in milliseconds |
CameraMovementData.panoIndex | A panorama index in the currently loaded Work |
longitude, latitude | Camera angles in radians |
Import the enum and types from @realsee/vreo/typings. The package root exports Player; it does not re-export every script type. Because keyframe data is broadly typed, declaring the separate CameraMovementData and PrompterData values catches more mistakes than an untyped JSON object.
Other keyframe kinds need their own payloads and valid assets. In particular, a panorama update contains signed scene data; do not invent that data or embed your Developer app secret to obtain it.
Verify
Validate the media response, duration, timeline ordering, and panorama membership before loading. In the browser, verify the caption interval and camera target while narration runs, then replay and seek through your calling controls.
