Appearance
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
| Method | What it does | Mutates? |
|---|---|---|
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 jobs | cancelJob ✓ |
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
| Property | Type | Description |
|---|---|---|
walkthroughId | string | The walkthrough's id |
name | string | Its name |
keyframes | PluginWalkthroughKeyframe[] | Its keyframes, in order |
isLoop | boolean | The path returns from the last keyframe to the first |
isRepeating | boolean | Playback starts again when it reaches the end |
speed | number | Travel speed, Snaptrude units per second |
durationInSeconds | number | How long playback takes, including easing and holds |
pathLength | number | Length of the path, in Snaptrude units |
eyeHeight | number | Eye height above the floor for floor-following keyframes |
preset | PluginWalkthroughPreset | null | The camera move it was made from, while it is still a preset |
PluginWalkthroughKeyframe
| Property | Type | Description |
|---|---|---|
keyframeId | string | The keyframe's id |
eye | { x, y, z } | Camera position |
look | PluginWalkthroughLook | How the camera looks here |
followsFloor | boolean | Stands at eye height above the floor; paths between two such keyframes follow the floor, stairs included |
holdInSeconds | number | Pause here before moving on |
PluginWalkthroughLook
| Shape | Meaning |
|---|---|
{ 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.
| Property | Type | Description |
|---|---|---|
eye | { x, y, z } | Camera position; with followsFloor, a point on or above the floor |
look | PluginWalkthroughLook | undefined | How the camera looks here (default { mode: "path" }) |
followsFloor | boolean | undefined | Stand at eye height above the floor at or below eye (default false: eye as given) |
holdInSeconds | number | undefined | Pause here, 0 to 60 (default 0) |
PluginWalkthroughPreset and PluginWalkthroughPresetKind
| Kind | The camera move |
|---|---|
orbit | Circles the subject, always facing its middle |
flyOver | Passes above it from the camera's side, looking ahead and down |
pushIn | Moves toward it |
pullBack | Moves away from it |
rise | Cranes up from eye level, tilting down to keep it in view |
| Property | Type | Description |
|---|---|---|
kind | PluginWalkthroughPresetKind | The move |
distance | number | Camera distance as a multiple of the distance at which the subject just fits in view (0.8 to 3) |
heightInDegrees | number | Camera height, degrees above level seen from the subject's middle (0 to 75) |
isClockwise | boolean | Orbits only: goes round clockwise seen from above |
PluginWalkthroughPlaybackState
| Property | Type | Description |
|---|---|---|
status | "stopped" | "playing" | "paused" | Playback status |
walkthroughId | string | null | The walkthrough playing or paused |
timeInSeconds | number | How far through it |
durationInSeconds | number | Its duration (0 when stopped) |
isRecording | boolean | Whether playback is being recorded by an export |
PluginWalkthroughExportJob
| Property | Type | Description |
|---|---|---|
jobId | string | The job's id |
walkthroughId | string | The walkthrough being exported |
status | "queued" | "running" | "completed" | "failed" | "cancelled" | Where the job is |
createdAt / updatedAt | number | Epoch milliseconds |
completedAt | number | undefined | When it completed, failed or was cancelled |
progress | number | undefined | 0 to 1 while running |
result | { shapeId, videoUrl, width, height, mimeType, durationInSeconds } | undefined | What it made, once completed |
error | string | undefined | Why 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—nullwhen 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.speedoroptions.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 ofcreate, pluslookAt?: { 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 (defaultfalse).options.durationInSeconds:number— default orbit 24, fly over 12, the others 8.options.name,options.isRepeating: as forcreate.- 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? } }—speedordurationInSeconds, 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—trueonce 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 atindex.
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, ornullwhen 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 ofcount.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'stimeInSeconds.
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.