Skip to content

Walkthroughs ​

Camera paths through the model, played in the viewport and exported as videos — the scriptable counterpart of the Walkthrough tool, its camera-move menu and the walkthrough dock. Accessed via snaptrude.presentation.walkthroughs.

A walkthrough is a list of keyframes (camera positions, and how the camera looks at each) joined by a smooth path that the camera travels at a steady speed, easing in at the start and out at the end. Make one from full keyframes (create), from points on the floor (createFromPoints) or from a camera move around what is selected (createFromPreset); inspect it (sample, listIssues, capture); play it (start / stop / getState); and export it as a video onto the Present canvas (export plus the job methods).

Positions are world coordinates in Snaptrude units (1 unit = 0.254 m, Y up; see snaptrude.core.units). Yaw is degrees clockwise from +z seen from above; pitch is degrees above level.

At a glance ​

MethodWhat it doesMutates?
list()Every walkthrough, oldest first—
get(walkthroughId)One walkthrough, or null—
create(keyframes, options?)A walkthrough from full keyframes✓
createFromPoints(points, options?)A walkthrough through points on the floor, at eye height✓
createFromPreset(kind, options?)A camera move (orbit, fly over, push in, pull back, rise) around a subject✓
update(walkthroughId, patch)Name, loop, repeat, speed or duration, preset settings✓
delete(walkthroughId)Delete a walkthrough✓
createKeyframe(walkthroughId, keyframe, index?)Add a keyframe✓
updateKeyframe(walkthroughId, keyframeId, patch)Change a keyframe✓
deleteKeyframe(walkthroughId, keyframeId)Remove a keyframe✓
reorderKeyframe(walkthroughId, keyframeId, index)Move a keyframe in the order✓
sample(walkthroughId, timesInSeconds)Camera poses at given moments—
listIssues(walkthroughId)Where the camera passes through the model—
capture(walkthroughId, options?)A contact-sheet image of frames—
start(walkthroughId, options?)Play it in the viewport—
stop()Stop playback and restore the camera—
getState()Playback state—
export(walkthroughId, options?)Record a video onto the Present canvas, as a job✓
getJob(jobId) · cancelJob(jobId) · listJobs()Follow or cancel export jobscancelJob ✓

Not saved with the project yet

Walkthroughs last until the project is closed or reloaded. An exported video stays on the Present canvas.

Undo

Every write is one step of the walkthrough undo history, which is separate from the model's: it is what the walkthrough dock's undo button and Ctrl+Z take back while a walkthrough is being worked on. Writes also open the walkthrough in the dock.

Types ​

PluginWalkthrough ​

PropertyTypeDescription
walkthroughIdstringThe walkthrough's id
namestringIts name
keyframesPluginWalkthroughKeyframe[]Its keyframes, in order
isLoopbooleanThe path returns from the last keyframe to the first
isRepeatingbooleanPlayback starts again when it reaches the end
speednumberTravel speed, Snaptrude units per second
durationInSecondsnumberHow long playback takes, including easing and holds
pathLengthnumberLength of the path, in Snaptrude units
eyeHeightnumberEye height above the floor for floor-following keyframes
presetPluginWalkthroughPreset | nullThe camera move it was made from, while it is still a preset

PluginWalkthroughKeyframe ​

PropertyTypeDescription
keyframeIdstringThe keyframe's id
eye{ x, y, z }Camera position
lookPluginWalkthroughLookHow the camera looks here
followsFloorbooleanStands at eye height above the floor; paths between two such keyframes follow the floor, stairs included
holdInSecondsnumberPause here before moving on

PluginWalkthroughLook ​

ShapeMeaning
{ mode: "path" }Ahead along the path, level
{ mode: "target", target }At a point in the model
{ mode: "fixed", yawInDegrees, pitchInDegrees }In a fixed direction (pitch within ±89°)

PluginWalkthroughKeyframeInput ​

A keyframe to add, for create and createKeyframe. updateKeyframe takes the same fields, all optional.

PropertyTypeDescription
eye{ x, y, z }Camera position; with followsFloor, a point on or above the floor
lookPluginWalkthroughLook | undefinedHow the camera looks here (default { mode: "path" })
followsFloorboolean | undefinedStand at eye height above the floor at or below eye (default false: eye as given)
holdInSecondsnumber | undefinedPause here, 0 to 60 (default 0)

PluginWalkthroughPreset and PluginWalkthroughPresetKind ​

KindThe camera move
orbitCircles the subject, always facing its middle
flyOverPasses above it from the camera's side, looking ahead and down
pushInMoves toward it
pullBackMoves away from it
riseCranes up from eye level, tilting down to keep it in view
PropertyTypeDescription
kindPluginWalkthroughPresetKindThe move
distancenumberCamera distance as a multiple of the distance at which the subject just fits in view (0.8 to 3)
heightInDegreesnumberCamera height, degrees above level seen from the subject's middle (0 to 75)
isClockwisebooleanOrbits only: goes round clockwise seen from above

PluginWalkthroughPlaybackState ​

PropertyTypeDescription
status"stopped" | "playing" | "paused"Playback status
walkthroughIdstring | nullThe walkthrough playing or paused
timeInSecondsnumberHow far through it
durationInSecondsnumberIts duration (0 when stopped)
isRecordingbooleanWhether playback is being recorded by an export

PluginWalkthroughExportJob ​

PropertyTypeDescription
jobIdstringThe job's id
walkthroughIdstringThe walkthrough being exported
status"queued" | "running" | "completed" | "failed" | "cancelled"Where the job is
createdAt / updatedAtnumberEpoch milliseconds
completedAtnumber | undefinedWhen it completed, failed or was cancelled
progressnumber | undefined0 to 1 while running
result{ shapeId, videoUrl, width, height, mimeType, durationInSeconds } | undefinedWhat it made, once completed
errorstring | undefinedWhy it failed

Functions ​

list() ​

Every walkthrough of the open project, oldest first.

  • Returns: { walkthroughs: PluginWalkthrough[] } ([] when there are none).
ts
const { walkthroughs } = await snaptrude.presentation.walkthroughs.list();

get(walkthroughId) ​

  • walkthroughId: string.
  • Returns: PluginWalkthrough | null — null when there is none with that id.
ts
const walkthrough = await snaptrude.presentation.walkthroughs.get(walkthroughId);
console.log(walkthrough?.durationInSeconds);

create(keyframes, options?) ​

Create a walkthrough from full keyframes. A keyframe that follows the floor stands at the walkthrough's eye height above the floor, stair, terrain or ground at or below its eye, and the path between two such keyframes climbs stairs and ramps. Write-gated; one undo step.

  • keyframes: PluginWalkthroughKeyframeInput[] — 1 to 200, in order.
  • options.name: string — default "Walkthrough N".
  • options.isLoop: boolean — return from the last keyframe to the first (needs 3 keyframes).
  • options.isRepeating: boolean — play again from the start at the end.
  • options.speed or options.durationInSeconds: travel speed in Snaptrude units per second, or how long it should take (holds included). Give one, not both. Default speed 1 m/s.
  • Returns: the new PluginWalkthrough.
ts
const walkthrough = await snaptrude.presentation.walkthroughs.create(
  [
    { eye: { x: 0, y: 30, z: 80 }, look: { mode: "target", target: { x: 0, y: 10, z: 0 } } },
    { eye: { x: 60, y: 30, z: 0 }, look: { mode: "target", target: { x: 0, y: 10, z: 0 } } }
  ],
  { name: "Approach", durationInSeconds: 10 }
);

createFromPoints(points, options?) ​

Walk through points on the floor, the way the Walkthrough tool draws a route: the camera stands at eye height above the floor, stair, terrain or ground at each point, climbs stairs and ramps between them, and looks ahead along the path — or at options.lookAt the whole way. Write-gated; one undo step.

  • points: { x, y, z }[] — 2 to 200, in order.
  • options: those of create, plus lookAt?: { x, y, z }.
  • Returns: the new PluginWalkthrough.
ts
await snaptrude.presentation.walkthroughs.createFromPoints(
  [
    { x: 0, y: 0, z: 0 },
    { x: 40, y: 0, z: 0 },
    { x: 40, y: 0, z: 30 }
  ],
  { name: "Ground floor tour" }
);

createFromPreset(kind, options?) ​

A camera move around a subject, as the Walkthrough button's menu makes: sized from the subject's bounding box so it fits in view, starting on the side the camera is on. The subject is options.subject, else the selection, else the visible model without its terrain. While it is still a preset, update can change its distance, height and direction; editing a keyframe makes it an ordinary walkthrough. Write-gated; one undo step.

  • kind: "orbit" | "flyOver" | "pushIn" | "pullBack" | "rise".
  • options.subject: ComponentHandle[] — what to frame.
  • options.distance: number — 0.8 to 3 (default per move).
  • options.heightInDegrees: number — 0 to 75 (default per move).
  • options.isClockwise: boolean — orbits only (default false).
  • options.durationInSeconds: number — default orbit 24, fly over 12, the others 8.
  • options.name, options.isRepeating: as for create.
  • Returns: the new PluginWalkthrough.
ts
await snaptrude.presentation.walkthroughs.createFromPreset("orbit", {
  subject: [towerId],
  heightInDegrees: 35,
  durationInSeconds: 20
});

update(walkthroughId, patch) ​

Change a walkthrough; only the fields given change. preset changes a preset walkthrough's move and makes its keyframes again, keeping its duration; changing isLoop of a preset makes it ordinary. Write-gated; one undo step.

  • patch: { name?, isLoop?, isRepeating?, speed?, durationInSeconds?, preset?: { distance?, heightInDegrees?, isClockwise? } } — speed or durationInSeconds, not both.
  • Returns: the updated PluginWalkthrough.
ts
await snaptrude.presentation.walkthroughs.update(walkthroughId, {
  durationInSeconds: 30,
  isRepeating: true
});

delete(walkthroughId) ​

Write-gated; one undo step.

  • Returns: boolean — true once deleted.

createKeyframe(walkthroughId, keyframe, index?) ​

Add a keyframe at index (0 to the keyframe count; default the end). A preset walkthrough becomes ordinary. Write-gated; one undo step.

  • Returns: the updated PluginWalkthrough; the new keyframe is at index.
ts
await snaptrude.presentation.walkthroughs.createKeyframe(
  walkthroughId,
  { eye: { x: 12, y: 0, z: 30 }, followsFloor: true, holdInSeconds: 2 },
  2
);

updateKeyframe(walkthroughId, keyframeId, patch) ​

Change a keyframe; only the fields given change. A preset walkthrough becomes ordinary. Write-gated; one undo step.

  • patch: { eye?, look?, followsFloor?, holdInSeconds? }.
  • Returns: the updated PluginWalkthrough.
ts
await snaptrude.presentation.walkthroughs.updateKeyframe(walkthroughId, keyframeId, {
  look: { mode: "target", target: { x: 5, y: 4, z: 10 } }
});

deleteKeyframe(walkthroughId, keyframeId) ​

Remove a keyframe; the path then runs straight from the keyframe before it to the one after. Removing the last keyframe deletes the walkthrough. Write-gated; one undo step.

  • Returns: the updated PluginWalkthrough, or null when removing the last keyframe deleted it.

reorderKeyframe(walkthroughId, keyframeId, index) ​

Move a keyframe to position index in the order (the presentation.sheets.reorder convention). Write-gated; one undo step.

  • Returns: the updated PluginWalkthrough.

sample(walkthroughId, timesInSeconds) ​

Where the camera is and which way it looks at given moments of playback, without moving the camera.

  • timesInSeconds: number[] — 1 to 500 moments, each clamped to the duration.
  • Returns: { samples: { timeInSeconds, eye, direction, yawInDegrees, pitchInDegrees }[] }.
ts
const walkthrough = await snaptrude.presentation.walkthroughs.get(walkthroughId);
const { samples } = await snaptrude.presentation.walkthroughs.sample(walkthroughId, [
  0,
  walkthrough!.durationInSeconds / 2
]);

listIssues(walkthroughId) ​

Places where the camera passes through the model — through anything the arrow keys will not walk through: walls, glazing, columns, slabs, roofs, ceilings, solid masses and terrain. Doors, furniture and room masses do not count. Each issue is one pass, reported where the camera enters.

  • Returns: { issues: { kind: "throughGeometry", timeInSeconds, point, componentId }[] } in playback order ([] when the path is clear).
ts
const { issues } = await snaptrude.presentation.walkthroughs.listIssues(walkthroughId);
for (const issue of issues) console.log(issue.timeInSeconds, issue.componentId);

capture(walkthroughId, options?) ​

Frames of a walkthrough as one contact-sheet image: a grid of views at evenly spaced moments (or at options.timesInSeconds), left to right and top to bottom. The camera goes back to where it was afterwards.

  • options.count: number — 1 to 12 frames (default 6).
  • options.timesInSeconds: number[] — 1 to 12 moments instead of count.
  • options.width: number — the whole image's width in pixels, 256 to 2048 (default 1536).
  • options.format: "png" | "jpeg" — default "jpeg".
  • Returns: { image, frames } — the sheet as a base64 data URL and each frame's timeInSeconds.
ts
const { image } = await snaptrude.presentation.walkthroughs.capture(walkthroughId, { count: 6 });

start(walkthroughId, options?) · stop() · getState() ​

Play a walkthrough in the viewport from the start (or options.fromTimeInSeconds); a walkthrough that is already playing keeps playing. Arrow-key navigation pauses while it plays. stop puts the camera back where it was before playback started; it is a no-op when nothing is playing.

  • Returns: PluginWalkthroughPlaybackState.
ts
await snaptrude.presentation.walkthroughs.start(walkthroughId);

export(walkthroughId, options?) ​

Record a walkthrough as a video and place it on the Present canvas, as an asynchronous job: this resolves at once with the queued job; poll getJob until it completes, fails or is cancelled. Recording plays the walkthrough in real time at the chosen size, so it takes about as long as the walkthrough plus the upload; the editor then switches to Present mode to place the video, which plays muted in a loop there. One export runs at a time. Write-gated.

  • options.quality: "720p" | "1080p" | "4k" — default "1080p".
  • options.framesPerSecond: 30 | 60 — default 30.
  • Returns: the queued PluginWalkthroughExportJob.
ts
const walkthroughs = snaptrude.presentation.walkthroughs;
let job = await walkthroughs.export(walkthroughId, { quality: "1080p" });
while (job.status === "queued" || job.status === "running") {
  await new Promise((resolve) => setTimeout(resolve, 2000));
  job = (await walkthroughs.getJob(job.jobId))!;
}
console.log(job.result?.shapeId);

getJob(jobId) · cancelJob(jobId) · listJobs() ​

getJob returns the job or null (finished jobs are forgotten after 30 minutes). cancelJob stops a recording and places nothing (write-gated); a finished job is returned unchanged. listJobs returns { jobs }, newest first.

Errors ​

Failed calls reject with a typed PluginError — see Error Handling. Writes and export / cancelJob reject with METHOD_NOT_PERMITTED when plugin writes are disabled. An unknown walkthrough, keyframe or job id rejects with HANDLE_INVALID (reads of an unknown walkthrough or job return null instead). VALIDATION covers bad arguments, an out-of-range index, a loop of fewer than three keyframes, and speed given with durationInSeconds. PRECONDITION_FAILED covers a point below the ground with nothing under it, nothing to frame for a preset, preset settings for an ordinary walkthrough, capture while a walkthrough plays, anything that moves the camera while an export records, another export already running, and a browser that cannot record video.