Appearance
Placed views
Read and edit the layout of the views already placed on the Present canvas. A placed view is a saved view that has been dropped onto a layout sheet (or the open canvas) — the live linked view shape sheets.place and the Present views panel's drag-drop create. Accessed via snaptrude.presentation.placedViews.
These methods change where a placed view sits, how big it is, its architectural scale, its rotation, and its crop. To refresh a placed view's content from the current model, use sheets.updatePlacedView — content refresh lives on sheets, layout lives here.
All methods are host API calls that return Promises. list never throws when Present mode is closed (it returns []); get and every write require Present mode to be open.
At a glance
| Method | What it does | Mutates? |
|---|---|---|
list(sheetId?) | List the placed views (optionally only those on one sheet) | — |
get(shapeId) | Read one placed view by its shape id | — |
move(shapeId, position, options?) | Reposition a placed view, optionally moving it to another sheet | ✓ |
scale(shapeId, factor) | Uniformly resize a placed view (2D and 3D) | ✓ |
setScale(shapeId, scale) | Set a standard architectural scale (the Scale dropdown; 2D only) | ✓ |
setCrop(shapeId, crop) | Crop a placed view to a window of itself, or clear the crop | ✓ |
setRotation(shapeId, rotation) | Set a placed view's absolute rotation (radians; 3D views only) | ✓ |
getStyles(shapeId) | Read the per-category presentation styles (resolved) | — |
updateStyles(shapeId, category, patch) | Restyle one category (line weights, dash styles, fills, …) | ✓ |
resetStyles(shapeId) | Reset all styling to defaults (the sidebar Reset) | ✓ |
updateFontStyles(shapeId, category, patch) | Label typography for one category (the Text tab) | ✓ |
listLabels(shapeId) | List a view's labels (text, category, position, hidden) | — |
moveLabel(labelId, position) | Reposition one label (view-relative coordinates) | ✓ |
setLabelHidden(labelId, hidden) | Hide/show one label individually | ✓ |
listShapes(sheetId?) | List ALL top-level canvas shapes with an origin classification | — |
getShape(shapeId) | Read any canvas shape (AI outputs, diagram images, …) | — |
moveShape(shapeId, position, options?) | Move any canvas shape, optionally onto a sheet | ✓ |
resizeShape(shapeId, factor) | Uniformly resize any canvas shape | ✓ |
rotateShape(shapeId, rotation) | Set any canvas shape's absolute rotation (radians) | ✓ |
deleteShapes(shapeIds) | Delete canvas shapes (atomic; annotations + sheets protected) | ✓ |
setOpacity(shapeId, opacity) | Whole-shape opacity, 0–1 (the sidebar slider) | ✓ |
setMask(shapeId, enabled) | Toggle "mask context buildings" on a view | ✓ |
Present mode required
get and every write throw "Present mode is not open" when Present mode (the documentation editor) is closed. list does not throw — it returns [], so a plugin cannot distinguish "Present mode is closed" from "nothing is placed".
Undo lives on the Present canvas
"Undoable" / "one undo step" here means the Present canvas's own history — the user's Ctrl+Z while Present mode is open. core.history.undo steps the design-side command stack and does not revert Present-canvas edits.
Types
PluginPlacedView
A view placed on the Present canvas. shapeId is the id sheets.place returned. For a grouped placed view (e.g. a sustainability 3D view grouped with its legend), position/size/rotation describe the whole group — the unit the user sees — while shapeId stays the view shape's id.
| Property | Type | Description |
|---|---|---|
shapeId | string | Id of the placed view shape (the id sheets.place returns) |
sheetId | string | null | The sheet it sits on (null when placed loose on the canvas) |
title | string | The saved view's title |
viewId | string | Id of the saved view it was placed from |
position | { x: number, y: number } | Top-left position — sheet-local when on a sheet, page coordinates otherwise |
size | { width: number, height: number } | Displayed size on the canvas |
scale | number | null | Architectural scale (e.g. 100 = 1:100); null for 3D views |
is3d | boolean | Whether it is a 3D view (no architectural scale) |
rotation | number | Rotation in radians, [0, 2π) (nonzero only for 3D views — 2D views cannot rotate on their own; set with setRotation. Exception: a 2D view grouped with other shapes rotates with its group — the record's root resolves to the group, matching the interactive group rotate handle) |
crop | PluginPlacedViewCrop | null | Crop window (null when uncropped) |
isUnlinked | boolean | Whether the source proposal was removed (an unlinked view no longer refreshes) |
PluginPlacedViewCrop
A crop window, as fractions (0–1) of the uncropped view. topLeft must be strictly less than bottomRight on both axes.
| Property | Type | Description |
|---|---|---|
topLeft | { x: number, y: number } | Top-left of the visible window (fractions 0–1) |
bottomRight | { x: number, y: number } | Bottom-right of the visible window (fractions 0–1) |
Functions
list(sheetId?)
List the placed views in the presentation — those nested on a layout sheet (with that sheet's id) and those sitting loose on the canvas (sheetId: null). Pass sheetId to list only the views placed on that sheet.
- Parameters:
sheetId:string | undefined— optional sheet id to filter by
- Returns:
{ placedViews: PluginPlacedView[] }— empty when Present mode is closed or nothing is placed. - Throws: If
sheetIdis given but is not a sheet (with Present mode open).
ts
const { placedViews } = await snaptrude.presentation.placedViews.list("sheet_1");
for (const p of placedViews) console.log(p.title, p.position, p.scale);get(shapeId)
Read a single placed view by its shape id — the id sheets.place returned (also reported by list).
- Parameters:
shapeId:string— the placed view shape to read
- Returns:
PluginPlacedView. - Throws: If Present mode is not open, or
shapeIdis unknown or is not a placed view.
ts
const placed = await snaptrude.presentation.placedViews.get(shapeId);
console.log(placed.sheetId, placed.size, placed.crop);move(shapeId, position, options?)
Reposition a placed view. position is the new top-left in sheet coordinates (page coordinates when the view is off-sheet). Pass options.sheetId to move the view onto another sheet — it is reparented to that sheet first, then positioned at position in the new sheet's coordinates. A grouped placed view moves as one unit. Undoable.
- Parameters:
shapeId:string— the placed view shape to moveposition:{ x: number, y: number }— new top-left position (sheet-local; page coordinates when off-sheet)options.sheetId:string | undefined— move the view onto this sheet
- Returns:
PluginPlacedView— the updated placed view. - Throws: If Present mode is not open,
shapeIdis unknown or is not a placed view, oroptions.sheetIdis given but is not a sheet.
ts
await snaptrude.presentation.placedViews.move(shapeId, { x: 50, y: 50 }, { sheetId: "sheet_2" });scale(shapeId, factor)
Uniformly resize a placed view about its top-left corner — the same resize as dragging a corner handle, aspect ratio held. Works for 2D and 3D views; labels and grouped legends resize with it. For a 2D view the printed architectural scale changes proportionally — doubling the size of a 1:100 plan makes it a 1:50 plan. Use setScale to land on an exact standard scale instead. Undoable.
- Parameters:
shapeId:string— the placed view shape to resizefactor:number— uniform scale factor, between0.01and100(2doubles the size,0.5halves it)
- Returns:
PluginPlacedView— the updated placed view. - Throws: If Present mode is not open,
shapeIdis unknown or is not a placed view, orfactoris not a finite number between 0.01 and 100.
ts
const scaled = await snaptrude.presentation.placedViews.scale(shapeId, 2);
console.log(scaled.size, scaled.scale); // twice the size; a 2D view's scale halvedsetScale(shapeId, scale)
Set a placed view's architectural scale — the same write the placed view's Scale dropdown performs. The view (and its labels) is resized about its top-left corner so it prints at the given scale. scale must be one of the standard values for the project's unit system — the same table as sheets.place (metric 10, 20, 50, 100, 150, 200, 250, 500, 1000; imperial e.g. 48 = 1/4″ = 1′). 3D views have no architectural scale — calling this on one throws. Undoable.
- Parameters:
shapeId:string— the placed view shape to set the scale ofscale:number— a standard scale value for the project's unit system
- Returns:
PluginPlacedView— the updated placed view. - Throws: If Present mode is not open,
shapeIdis unknown or is not a placed view,scaleis not a standard value for the project's unit system, or the placed view is a 3D view.
ts
await snaptrude.presentation.placedViews.setScale(shapeId, 100); // 1:100setCrop(shapeId, crop)
Crop a placed view, or clear its crop. crop selects the visible window as fractions (0–1) of the uncropped view — topLeft strictly less than bottomRight on both axes. The visible region stays anchored on the page (the same behavior as the interactive crop), labels that fall outside the crop are hidden, and the view's architectural scale is untouched. Pass null to clear the crop and restore the full view in its uncropped footprint (the interactive double-click-edge reset). Undoable.
The crop survives a content refresh: sheets.updatePlacedView recomputes the crop against the refreshed content and only clears it when the refreshed view no longer overlaps the cropped region.
- Parameters:
shapeId:string— the placed view shape to cropcrop:PluginPlacedViewCrop | null— the crop window, ornullto clear
- Returns:
PluginPlacedView— the updated placed view. - Throws: If Present mode is not open,
shapeIdis unknown or is not a placed view, orcropis not a valid 0–1 rectangle withtopLeft < bottomRighton both axes.
ts
// keep the left half of the view
await snaptrude.presentation.placedViews.setCrop(shapeId, {
topLeft: { x: 0, y: 0 },
bottomRight: { x: 0.5, y: 1 }
});
await snaptrude.presentation.placedViews.setCrop(shapeId, null); // clearsetRotation(shapeId, rotation)
Set a placed view's absolute rotation — radians, tldraw convention, the same value rotation reads back: setRotation(x) then get returns exactly x (values are canonicalized into [0, 2π), so pass values in that range for an exact round-trip). The view rotates about its page-space bounds center — the same pivot the interactive rotation handle uses — so the center stays put. A grouped placed view rotates as one unit. One undo step.
3D placed views only. 2D and site-plan views cannot rotate on their own — the canvas hides their rotate handle and reverts any rotation applied to them — so calling this on one throws instead of silently no-opping. One exception: a 2D view grouped with other shapes rotates with its group (the rotation targets the outermost non-frame root, which resolves to the group — the same unit the interactive group rotate handle turns), so setRotation on a grouped 2D view rotates the whole group.
- Parameters:
shapeId:string— the placed view shape to rotaterotation:number— the absolute rotation in radians (a finite number;0is unrotated)
- Returns:
PluginPlacedView— the updated placed view. - Throws: If Present mode is not open,
shapeIdis unknown or is not a placed view,rotationis not finite, or the placed view is a 2D/site-plan view.
ts
const rotated = await snaptrude.presentation.placedViews.setRotation(shapeId, Math.PI / 4);
console.log(rotated.rotation); // 0.7853981633974483 — exactly what was set
await snaptrude.presentation.placedViews.setRotation(shapeId, 0); // back uprightgetStyles(shapeId) / updateStyles(shapeId, category, patch) / resetStyles(shapeId)
The Present sidebar's per-category styling, per placed instance (the same saved view placed twice can be styled differently). Works on placed views and auto-diagram sheets (sheet writes fan out across the sheet's diagram set).
Ten categories: Site, Topography, Space, Department, Envelope, Facade/Mass, Dimension, Reference Line, Adjacency Line, Landscape elements. A patch may set any subset the category supports: lineStyle (solid/dashed/dashdot/hidden/center/phantom/propertyLine), lineColor (hex), dashLength (multiplier), line weights in mm — cutWidth + projectionWidth (Revit-style cut/projection split; lineWidth where a category has one weight; treeLineWidth/parkingLineWidth on Landscape) — colorMode (department/texture/monochrome/tag:<tagCategoryId>), opacity (0–100), hide (cascades to that category's labels), viewStyle (NONE/FILLET/BUBBLE) with radius/inset, and Topography's mapOpacity/buildingOpacity/mapHide/buildingHide/noBuilding.
getStyles returns fully-resolved values plus each category's supported setting ids and a disabled flag (category not visible in the view). updateStyles validates everything up front (typed VALIDATION with the supported list — nothing is written on a bad patch), lands as one undo step per call, and re-renders immediately. resetStyles is the sidebar Reset: clears all overrides, view styles, font styles, and styling-hidden labels.
ts
await snaptrude.presentation.placedViews.updateStyles(shapeId, "Space", {
cutWidth: 0.5,
projectionWidth: 0.18,
lineStyle: "dashed",
colorMode: "department"
});updateFontStyles(shapeId, category, patch)
The configure panel's Text tab: label typography per label type — objectLabels (the name), department, areas — each with fontFamily (system or any Google Font, loaded automatically), fontWeight (numeric string, e.g. "700"), fontStyle (normal/italic), fontSize (px number). visibleTypes controls which label types render ([] hides all). Topography, Facade/Mass, Reference Line and Adjacency Line have no Text tab and reject font writes.
listLabels(shapeId) / moveLabel(labelId, position) / setLabelHidden(labelId, hidden)
A placed view's labels (space names, departments, areas, dimension texts) as addressable shapes: { labelId, category, text, position, scale, hidden } with positions relative to the view. moveLabel repositions one (undoable, survives style changes); setLabelHidden hides/shows one individually — independent of the category-level hide and the Text-tab visibleTypes.
listShapes(sheetId?) / getShape(shapeId)
The generic canvas surface: every top-level Present shape, not just placed views — { shapeId, type, origin, sheetId, position, size, rotation, opacity } with origin ∈ view / aiOutput / pluginShape / annotation / image / other. This is how a plugin acts on the shape ids aiInspiration.generate and diagrams.place return. listShapes returns [] when Present mode is closed.
moveShape(shapeId, position, options?) / resizeShape(shapeId, factor) / rotateShape(shapeId, rotation)
move/scale/setRotation counterparts that accept ANY canvas shape (AI outputs, diagram images, plugin shapes, annotations — views too). Same coordinate semantics as move; options.sheetId reparents onto a sheet. rotateShape sets the absolute rotation in radians about the shape's page-space bounds center (the same semantics as setRotation, exact round-trip via getShape); a view passed to it falls under the same 3D-only rule as setRotation. All undoable (one undo step each).
deleteShapes(shapeIds)
Delete canvas shapes — one undo step, atomic (any rejected id deletes nothing). Deletable: placed views, AI outputs, diagram/plain images, plugin shapes. Protected: sheets (use sheets.delete) and user-drawn annotations (typed VALIDATION). → { deleted: string[] }.
setOpacity(shapeId, opacity) / setMask(shapeId, enabled)
setOpacity is the sidebar's whole-shape opacity slider (0–1, any canvas shape) — distinct from the per-category fill opacity in updateStyles. setMask toggles "mask context buildings" on a placed view (views only).
Errors
Failed calls reject with a typed PluginError — see Error Handling. Conditions specific to this namespace:
| Code | Thrown by | When | details |
|---|---|---|---|
PRECONDITION_FAILED | get and every write | Present mode is not open | — |
HANDLE_INVALID | every method | shapeId is unknown or is not a placed view, or a given sheetId is not a sheet | kind |
PRECONDITION_FAILED | setScale | The placed view is a 3D view (3D views have no architectural scale) | handles — the shape id |
PRECONDITION_FAILED | setRotation, rotateShape | The target is a 2D/site-plan placed view (only 3D placed views rotate) | handles — the shape id |
VALIDATION | setScale | scale is not one of the standard scale values for the project's unit system | scale, unitSystem, standardScales |
VALIDATION | scale, setCrop | factor out of range, or crop is not a valid 0–1 rectangle | — |
VALIDATION | setRotation, rotateShape | rotation is not a finite number | — |
HANDLE_INVALID | styling methods | shapeId is not a placed view or auto-diagram sheet (styleableShape) | kind |
VALIDATION | updateStyles | Category not applicable, setting unsupported by the category, or bad value | category, setting, supported |
VALIDATION | updateFontStyles | The category has no Text tab | category |
HANDLE_INVALID | label methods | labelId is not a view label (viewLabel) | kind |
HANDLE_INVALID | canvas-shape methods | shapeId is unknown or a sheet (canvasShape) | kind |
VALIDATION | deleteShapes | Any id is a protected user annotation — the whole batch is refused | shapeId, type, origin |
list and listShapes never throw when Present mode is closed — they return [].