@mocanvas/editor · class

Editor

declare class Editor extends EventEmitter<EditorEvents>

This one ships without a description. The signature above is read from the package, and the guides cover the area it belongs to.

On this page

alignShapesanimateShapeanimateShapesassetUtilsbailbailToMarkbatchblurbringForwardbringToFrontcanBindShapescancelcancelDoubleClickcanCreateShapecanCreateShapescanCropShapecanEditShapecanRedocanUndocenterOnPointclearHistorycompleteconstructorcontainercreateAssetcreateAssetscreateBindingcreateBindingscreateDeepLinkcreatePagecreateShapecreateShapescreateTemporaryAssetPreviewdegToRaddeleteAssetdeleteAssetsdeleteBindingdeleteBindingsdeletePagedeleteShapedeleteShapesdeselectdispatchdisposedistributeShapesduplicatePageduplicateShapesfindCommonAncestorfindShapeAncestorflipShapesflushEnginefocusgetAncestorPageIdgetAssetgetAssetForExternalContentgetAssetsgetAssetUtilgetAssetUtilForMimeTypegetAttributionDisplayNamegetAttributionUsergetAttributionUserIdgetBaseZoomgetBindinggetBindingsFromShapegetBindingsInvolvingShapegetBindingsToShapegetBindingUtilgetCameragetCameraOptionsgetCameraStategetCanRedogetCanUndogetCollaboratorsgetCollaboratorsOnCurrentPagegetColorModegetContainerDocumentgetContainerWindowgetContentFromCurrentPagegetCroppingShapegetCroppingShapeIdgetCulledShapesgetCurrentPagegetCurrentPageBoundsgetCurrentPageIdgetCurrentPageRenderingShapesSortedgetCurrentPageShapeIdsgetCurrentPageShapesgetCurrentPageShapesInReadingOrdergetCurrentPageShapesSortedgetCurrentPageStategetCurrentThemegetCurrentThemeIdgetCurrentToolgetCurrentToolIdgetCursorgetDebouncedZoomLevelgetDocumentSettingsgetDraggingOverShapegetEditingShapegetEditingShapeIdgetEfficientZoomLevelgetErasingShapeIdsgetErasingShapesgetFocusedGroupgetFocusedGroupIdgetFollowingUserIdgetFrameEpochgetHasMeasuredViewportgetHighestIndexForParentgetHintingShapegetHintingShapeIdsgetHintingShapesgetHitTestMargingetHoveredShapegetHoveredShapeIdgetInitialMetaForShapegetInitialZoomgetInstancePresenceIdgetInstanceStategetIsDisposedgetIsFocusedgetIsMountedgetIsReadonlygetLastFrameStatsgetNearestAdjacentShapegetNotVisibleShapesgetOnlySelectedShapegetOnlySelectedShapeIdgetOutermostSelectableShapegetOverlayClipsgetOverlayShapeIdsgetPagegetPagesgetPageShapeIdsgetPageStatesgetPathgetPointInParentSpacegetPointInShapeSpacegetRenderingShapesgetResizeScaleFactorgetRichTextEditorgetSelectedShapeAtPointgetSelectedShapeIdsgetSelectedShapesgetSelectionPageBoundsgetSelectionRotatedPageBoundsgetSelectionRotatedScreenBoundsgetSelectionRotationgetSelectionScreenBoundsgetShapegetShapeAncestorsgetShapeAndDescendantIdsgetShapeAtPointgetShapeClipPathgetShapeGeometrygetShapeGeometryBoundsgetShapeHandlesgetShapeIdsInsideBoundsgetShapeLocalTransformgetShapeMaskgetShapeMaskedPageBoundsgetShapePageBoundsgetShapePageTransformgetShapeParentgetShapeParentAtPointgetShapeParentTransformgetShapesAtPointgetShapesInsideBoundsgetShapesIntersectingBoundsgetShapeSketchPathgetShapesPageBoundsgetShapeStyleIfExistsgetShapeUtilgetShapeUtilForAssetTypegetSharedOpacitygetSharedStylesgetSnapshotgetSortedChildIdsForParentgetStateDescendantgetStyleForNextShapegetStylePropsForTypegetSvgElementgetSvgStringgetTemporaryAssetPreviewgetTextOptionsgetTextureResolutiongetThemegetThemesgetViewportPageBoundsgetViewportPageCentergetViewportScreenBoundsgetViewportScreenCentergetVisibleCollaboratorsgetVisibleCollaboratorsOnCurrentPagegetZoomLevelgroupShapeshasAncestorhasAssetUtilhasBindingUtilhasExternalAssetHandlerhasExternalContentHandlerhasShapeUtilhasToolinterruptisAncestorSelectedisDisposedisEventHandledisInisInAnyisPointInShapeisShapeFrameLikeisShapeHiddenisShapeInPageisShapeOfTypeisShapeOrAncestorLockedloadSnapshotmarkmarkEventAsHandledmarkHistoryStoppingPointmoveShapesToPagenavigateToDeepLinknudgeShapespackShapespageToScreenpageToViewportpanpopFocusedGroupIdputContentOntoCurrentPageputExternalContentredoregisterDeepLinkListenerregisterExternalAssetHandlerregisterExternalContentHandlerremoveToolrenamePagerenderFramereparentShapesreplaceExternalContentresetZoomresizeShaperesizeShapesresizeToBoundsresolveAssetsInContentresolveAssetUrlrotateShapesByrunscreenToPageselectselectAdjacentShapeselectAllselectFirstChildShapeselectNoneselectParentShapesendBackwardsendToBacksetCamerasetCameraOptionssetColorModesetCroppingShapesetCurrentPagesetCurrentThemesetCurrentToolsetCursorsetEditingShapesetErasingShapessetFocusedGroupsetHintingShapessetHoveredShapesetOpacityForNextShapessetOpacityForSelectedShapessetRichTextEditorsetSelectedShapessetStyleForNextShapessetStyleForSelectedShapessetToolslideCamerasquashToMarkstackShapesstartFollowingUserstopCameraAnimationstopFollowingUserstretchShapesstylePropstextMeasuretoggleLocktoImagetoImageDataUrlundoungroupShapesupdateAssetupdateAssetsupdateBindingupdateBindingsupdateCurrentPageStateupdateDocumentSettingsupdateInstanceStateupdatePageupdateShapeupdateShapesupdateThemeupdateThemesupdateViewportScreenBoundsuploadAssetviewportToPagevisitDescendantswasEventAlreadyHandledzoomInzoomOutzoomToBoundszoomToFitzoomToPointAtzoomToSelectionzoomToSelectionIfOffscreenzoomToUserassetsbindingUtilsclickcollaboratorscontentElementscontextIdedgeScrollManagerenginefontsgetContainergetInitialMetaForShapeHandlergetShapeVisibilityhandleshistoryidinputsmenusoptionsoverlaysperformancerootscribblesshapeUtilssideEffectssnapsstoretexttextOptionstexturesthemetimersuser

Methods · 314

alignShapes(ids: readonly ShapeId[], operation: "left" | "center-horizontal" | "right" | "top" | "center-vertical" | "bottom" | "center"): this

Align shapes against their common bounds. "center" centres on both axes at once — the two center-* operations applied together.

animateShape(partial: ShapePartial<UnknownShape> | null | undefined, opts?: TLAnimationOptions): this

Move a shape to a new position/rotation/opacity over time.

animateShapes(partials: readonly (ShapePartial<UnknownShape> | null | undefined)[], opts?: TLAnimationOptions): this

animateShape for many shapes on one clock.

get assetUtils(): ReadonlyMap<string, TLAssetUtilLike>

Every registered asset util, keyed by asset type.

bail(): this
bailToMark(id: string): this
batch<T>(fn: () => T): T

@deprecated use run

blur(): this

Take keyboard focus off the canvas. The inverse of focus.

bringForward(ids?: readonly ShapeId[]): this
bringToFront(ids?: readonly ShapeId[]): this
canBindShapes(opts: {

Whether a binding may be created between two shapes. Both utils must agree.

cancel(): this
cancelDoubleClick(): this

Restart double-click detection, so the next press begins a fresh gesture.

A tool calls this after acting on a double click that changed what is under the pointer — opening a label editor, say — so the release that follows is not read as part of the same gesture.

canCreateShape(partial: ShapeCreate<UnknownShape>): boolean

Whether one more shape can be added to the current page.

canCreateShapes(partials: readonly ShapeCreate<UnknownShape>[]): boolean

Whether a whole batch can be added, as one decision.

canCropShape(shape: UnknownShape | ShapeId): boolean

Whether a shape can enter cropping. No readonly or locked exemption.

canEditShape(shape: UnknownShape | ShapeId, info?: TLEditStartInfo): boolean

Whether a shape can be put into its editing state right now.

canRedo(): boolean

Whether there is anything to redo. The documented spelling of getCanRedo.

canUndo(): boolean

Whether there is anything to undo. The documented spelling of getCanUndo.

centerOnPoint(point: VecLike, opts?: TLCameraMoveOptions): this
clearHistory(): this

Throw away the undo and redo stacks, keeping the document exactly as it is.

This is what a host calls once its own setup writes are done: loading a board, registering derived state or migrating shapes are all changes the user never made and must not be able to undo their way behind.

complete(): this
constructor(opts: EditorOptions)
get container(): HTMLElement

The element the canvas is mounted in.

createAsset<A extends Asset>(asset: AssetCreate<A>): this
createAssets<A extends Asset>(assets: readonly AssetCreate<A>[]): this
createBinding<B extends UnknownBinding>(partial: BindingCreate<B>): this
createBindings<B extends UnknownBinding>(partials: readonly BindingCreate<B>[]): this
createDeepLink(opts?: TLDeepLinkOptions & {

A URL pointing at where we are now — the selection when there is one, the viewport otherwise.

Returns a URL rather than a string so a caller can keep its own query parameters; the deep link occupies one parameter, d by default.

createPage(page?: Partial<Omit<Page, "id" | "typeName" | "index">> & {
createShape<T extends UnknownShape>(partial: ShapeCreate<T>): this
createShapes<T extends UnknownShape>(partials: readonly ShapeCreate<T>[]): this
createTemporaryAssetPreview(assetId: AssetId, url: string): this

Remember a URL to paint for an asset while its upload is in flight.

static degToRad(d: number): number

Degrees → radians.

deleteAsset(id: AssetId | Asset): this
deleteAssets(ids: readonly (AssetId | Asset)[]): this
deleteBinding(id: BindingId | UnknownBinding, opts?: {
deleteBindings(ids: readonly (BindingId | UnknownBinding)[], opts?: {
deletePage(id: PageId): this
deleteShape(id: ShapeId | UnknownShape): this
deleteShapes(ids: readonly (ShapeId | UnknownShape)[]): this
deselect(...ids: (ShapeId | UnknownShape)[]): this

Remove shapes from the selection, leaving the rest of it alone.

dispatch(info: EventInfo): this

Route an event to the tool tree, updating inputs first.

dispose(): void
distributeShapes(ids: readonly ShapeId[], operation: "horizontal" | "vertical"): this

Space shapes evenly between the first and last along an axis.

duplicatePage(id?: PageId, createId?: PageId): PageId | undefined

Copy a page and everything on it. Returns the new page's id.

duplicateShapes(ids?: readonly ShapeId[], offset?: VecLike): ShapeId[]

Duplicate shapes (and their descendants) with new ids, offset by offset in page space. Returns the new top-level ids.

findCommonAncestor(shapes: readonly (UnknownShape | ShapeId)[], predicate?: (shape: UnknownShape) => boolean): ShapeId | undefined

The innermost shape all of shapes sit inside, or undefined.

findShapeAncestor(shape: UnknownShape | ShapeId | undefined, predicate: (parent: UnknownShape) => boolean): UnknownShape | undefined

The nearest ancestor of shape that predicate accepts.

flipShapes(ids: readonly ShapeId[], operation: "horizontal" | "vertical"): this

Mirror shapes across the center of their common bounds. Positions flip; geometry is not mirrored.

flushEngine(): void

Apply pending engine commands. Cheap when nothing is pending.

focus(): this

Put keyboard focus on the canvas.

The one thing an app needs after its own DOM took a keystroke — closing a caption editor, dismissing a menu — so that the next key press reaches the editor's shortcuts instead of the body. preventScroll because focusing a canvas that is partly off-screen must not scroll the page under it.

A no-op with no container (a headless editor, or one already torn down).

getAncestorPageId(shape: UnknownShape | ShapeId | undefined): PageId | undefined
getAsset<A extends Asset = Asset>(id: AssetId | A): A | undefined
getAssetForExternalContent(info: ExternalAssetContent): Promise<Asset | undefined>

Produce (but do not store) an asset record for a file or url through the registered asset handler. undefined when there is no handler or the handler declines the content.

getAssets(): Asset[]

Every asset in the document (assets are not per page).

getAssetUtil(type: string | Asset): TLAssetUtilLike | undefined

The util for an asset type, or undefined.

getAssetUtilForMimeType(mimeType: string): TLAssetUtilLike | undefined

The util that claims a MIME type — what a drop handler asks first.

getAttributionDisplayName(userId: UserId): string

A name to show for a person: their display name, or a short form of their id when nothing is known about them.

Never returns an empty string. A blank byline reads as a bug; an id reads as "we do not know who this is", which is the truth.

getAttributionUser(userId: UserId): User | null | Promise<User | null>

Look a person up in the host's user store.

May return a promise, because a directory lookup usually is one — callers render a placeholder until it settles. null when there is no store or the id is unknown.

getAttributionUserId(record: {

Who made (or last touched) a record, when the record says.

SEMANTICS-ASSUMED: read from meta.userId, falling back to meta.createdBy. Attribution is carried in meta because that is the one field every record type already has and the only one a host can write without a schema change.

getBaseZoom(): number

The zoom level that counts as 1 for this editor: zoomSteps are multiples of it, so the same step list means the same thing whatever the viewport size. Without camera constraints it is simply 1.

getBinding<B extends UnknownBinding = UnknownBinding>(id: BindingId): B | undefined
getBindingsFromShape<B extends UnknownBinding = UnknownBinding>(shape: UnknownShape | ShapeId, type?: B["type"]): B[]
getBindingsInvolvingShape<B extends UnknownBinding = UnknownBinding>(shape: UnknownShape | ShapeId, type?: B["type"]): B[]
getBindingsToShape<B extends UnknownBinding = UnknownBinding>(shape: UnknownShape | ShapeId, type?: B["type"]): B[]
getBindingUtil<B extends UnknownBinding>(binding: B | B["type"]): BindingUtil<B>
getCamera(): Camera
getCameraOptions(): TLCameraOptions

The camera's current policy: lock, wheel behaviour, speeds, zoom steps.

getCameraState(): TLCameraState

"moving" while the camera is in flight, "idle" once it settles.

getCanRedo(): boolean
getCanUndo(): boolean
getCollaborators(): InstancePresence[]

Presence records of everyone else in the room, in arrival order.

"Else" means *another instance*, not another person: the filter is on the presence record id (getInstancePresenceId), so a second tab, a second window, or the same person on a phone and a laptop all show up as collaborators. Filtering by user id instead made two tabs of one browser invisible to each other while every message arrived correctly.

getCollaboratorsOnCurrentPage(): InstancePresence[]

The subset of getCollaborators() looking at the page we are on.

getColorMode(): TLColorMode

Which half of the theme's colours applies right now.

getContainerDocument(): ContainerDocument | undefined

The document the canvas is painted in. undefined when there is no DOM at all (server rendering, node tests) or the container is not attached yet.

getContainerWindow(): ContainerWindow | undefined

The window the canvas is painted in; undefined outside a DOM.

getContentFromCurrentPage(ids: readonly ShapeId[]): {

Serializable content for the clipboard: shapes (with descendants) and bindings between them.

getCroppingShape(): UnknownShape | undefined

The shape being cropped, as a record.

getCroppingShapeId(): ShapeId | null

The shape being cropped, or null.

getCulledShapes(): Set<ShapeId>

Shapes the renderer may skip: not visible, and willing to be skipped.

getCurrentPage(): Page
getCurrentPageBounds(): Box | undefined

Union of every shape's page bounds on the current page, or undefined when the page is empty.

Geometry, not ink: this is the union of getShapePageBounds() and excludes the half-stroke pad the engine keeps for culling. The pad is per-shape, so including it would both inflate the box and shift its centre whenever the outermost shapes carry different stroke widths.

getCurrentPageId(): PageId
getCurrentPageRenderingShapesSorted(): UnknownShape[]

The page's visible shapes in paint order, without the render metadata.

getCurrentPageShapeIds(): Set<ShapeId>
getCurrentPageShapes(): Shape[]
getCurrentPageShapesInReadingOrder(): UnknownShape[]

The page's shapes in reading order — for a11y and keyboard navigation.

getCurrentPageShapesSorted(): UnknownShape[]
getCurrentPageState(): InstancePageState
getCurrentTheme(): TLTheme

The live theme: ramps, roles and per-mode colour tables.

getCurrentThemeId(): TLThemeId

The id of the current theme.

getCurrentTool(): StateNode
getCurrentToolId(): string
getCursor(): Instance["cursor"]

The cursor currently shown over the canvas.

getDebouncedZoomLevel(): number

The zoom level as of the last time the camera settled.

getDocumentSettings(): Document$1
getDraggingOverShape(): UnknownShape | undefined

The frame-like shape a drag is currently over, or undefined.

SEMANTICS-ASSUMED: derived rather than stored. It is the topmost container under the pointer during a drag, excluding whatever is being dragged — which is the same rule the drop itself uses, so the highlight a tool draws from this can never disagree with where the shapes actually land. Outside a drag there is nothing to be over and the answer is undefined.

getEditingShape(): UnknownShape | undefined
getEditingShapeId(): ShapeId | null
getEfficientZoomLevel(): number

The camera zoom, quantised to a small step.

Geometry that has to stay a constant size on screen divides by the zoom — a heading band, a hit target, a hairline. Reading getZoomLevel there makes the shape's geometry a function of the exact zoom, so every frame of a pinch recomputes and re-uploads it. Rounding to a step means the geometry only changes when the zoom has moved enough to be visible.

SEMANTICS-ASSUMED: the step is 1/64 of a zoom unit, chosen so the error is under half a pixel on a 32px band — small enough not to be seen, coarse enough that a slow pinch recomputes tens of times rather than hundreds.

getErasingShapeIds(): ShapeId[]
getErasingShapes(): UnknownShape[]

The shape records behind getErasingShapeIds(), skipping any that are gone.

getFocusedGroup(): UnknownShape | undefined

The focused group's record, or undefined when the page is focused.

getFocusedGroupId(): ShapeId | PageId

The container gestures are scoped to: a drilled-into group, or the page.

getFollowingUserId(): UserId | null

The user id being followed, or null.

getFrameEpoch(): number

Increments whenever the GPU frame must be redrawn.

getHasMeasuredViewport(): boolean

Whether a host has ever told us how big the canvas is (updateViewportScreenBounds).

Until it has, getViewportScreenBounds answers with the instance record's default — a plausible-looking 1080x720 that is not this canvas — or with zeros once a container that has not been laid out yet has been measured. Both are wrong in the same way and neither announces itself, which is why anything that needs the viewport asks this first.

getHighestIndexForParent(parentId: ParentId): IndexKey

The index a new child of parentId should take: above every existing one.

An empty parent answers getIndexAbove(ZERO_INDEX_KEY), not ZERO_INDEX_KEY itself. Two reasons, and the first stands on its own: asking this package the same question two ways used to give two answers, because getIndexAbove(ZERO_INDEX_KEY) from @mocanvas/store sits one step above what this returned. The second is parity — a consumer whose headless fold mirrors the store helper matched a live tldraw editor for months on this and stopped matching ours.

Only newly created shapes move; an index already written into a document is data and is never recomputed. Order is relative, so a document built before this still sorts exactly as it did.

getHintingShape(): UnknownShape | undefined

The single hinted shape, when exactly one is hinted.

undefined when none or several are: the singular accessor exists for the common case of a drag with one drop target, and a caller handling several wants getHintingShapes.

getHintingShapeIds(): ShapeId[]

The shapes currently marked as drop targets.

getHintingShapes(): UnknownShape[]

The shape records behind getHintingShapeIds(), skipping any that are gone.

getHitTestMargin(): number

The hit-test tolerance for the pointer in use: a fingertip covers more of the canvas than a cursor and needs the larger target.

getHoveredShape(): UnknownShape | undefined
getHoveredShapeId(): ShapeId | null
getInitialMetaForShape(shape: UnknownShape): UnknownShape["meta"]

The meta a newly created shape starts with. See getInitialMetaForShape.

getInitialZoom(): number

The zoom the editor starts at: the base zoom implied by the camera constraints, or 1 when there are none.

Not the same as getBaseZoom() only in intent — this is what resetZoom() should return to, and a host with constraints wants that to be the constrained fit rather than a literal 100%.

getInstancePresenceId(): InstancePresenceId

This editor instance's presence record id — who *this tab* is, as opposed to user.getId(), which is who the person is.

The two are not interchangeable and conflating them was a bug: a user id is per browser (it is the same in every tab, and the same on a phone and a laptop signed in as one person), while a presence record is per editor instance. Two tabs of one browser are two presences of one user, and they must see each other.

@mocanvas/sync publishes this tab's presence record under this id, which is what lets getCollaborators drop our own record — and only our own record — should it ever come back to us.

getInstanceState(): Instance
getIsDisposed(): boolean
getIsFocused(): boolean

Whether the canvas currently holds keyboard focus.

getIsMounted(): boolean

Whether a host has told us the editor is on screen.

Reactive — reading it inside a signal re-runs when the editor mounts or unmounts. Derived from the mount / unmount events, so it is a first class state and not a guess made from the DOM.

This is what a global registry of live editors should be built on: @mocanvas/mocanvas's tleditors currently registers editors from the flagship component's effect, which means an editor mounted any other way never appears in it. Deriving that list from this flag would fix it — see the note in the workstream report.

getIsReadonly(): boolean

Whether the document may be changed.

Read-only blocks EDITING, not participating: commenting, selecting, moving the camera and following someone else all stay available, so tools must ask this rather than assuming a read-only viewer can do nothing.

getLastFrameStats(): {

Stats for the last rendered frame.

getNearestAdjacentShape(shape: UnknownShape | ShapeId, direction: TLAdjacentDirection): UnknownShape | undefined

The shape an arrow key press from shape should move to.

getNotVisibleShapes(): Set<ShapeId>

Shapes that are off screen or clipped away. Some must still be drawn.

getOnlySelectedShape(): UnknownShape | undefined
getOnlySelectedShapeId(): ShapeId | null

The id of the only selected shape, or null when zero or many are.

getOutermostSelectableShape(shape: UnknownShape | ShapeId): UnknownShape | undefined

The outermost group containing a shape, or undefined.

getOverlayClips(): readonly (ClipRect | undefined)[]

Page-space clip rects for the overlay shapes, parallel to getOverlayShapeIds(); undefined where the shape is unclipped.

getOverlayShapeIds(): readonly ShapeId[]

Shapes the DOM overlay must render this frame, in draw order.

getPage(id: PageId): Page | undefined
getPages(): Page[]
getPageShapeIds(pageId: PageId): ShapeId[]
getPageStates(): InstancePageState[]

The session state of every page: selection, hover, editing, cropping.

getPath(): string
getPointInParentSpace(shape: UnknownShape | ShapeId, point: VecLike): Vec
getPointInShapeSpace(shape: UnknownShape | ShapeId, point: VecLike): Vec

Transform a page point into the shape's local space.

getRenderingShapes(): TLRenderingShape[]

Every shape on the page in paint order, with its render metadata.

getResizeScaleFactor(): number

How much a newly placed shape should be scaled by so it looks the same size on screen at any zoom.

It is 1 normally; in the user's dynamic-size mode it is 1 / zoom, which is what makes a sticky dropped on a zoomed-out board come out big enough to read. Placement states multiply their default size by it and pass it on as the shape's scale prop.

getRichTextEditor(): unknown

The rich-text editor instance currently attached to a shape's label, or null.

Untyped on purpose: the editor package does not ship a text stack and must not depend on one. A host that installed a rich-text implementation casts this to whatever it installed.

getSelectedShapeAtPoint(point: VecLike): UnknownShape | undefined

The topmost SELECTED shape under a page point.

getSelectedShapeIds(): ShapeId[]
getSelectedShapes(): Shape[]
getSelectionPageBounds(): Box | null

The bounds of the current selection, or null when nothing is selected.

getSelectionRotatedPageBounds(): Box | null

The selection's bounds in the selection's own rotated frame.

getSelectionRotatedScreenBounds(): Box | undefined

The rotated selection bounds, in screen space.

getSelectionRotation(): number
getSelectionScreenBounds(): Box | undefined

The selection's bounds in screen space (window-relative pixels).

getShape<T extends UnknownShape = Shape>(id: ShapeId | UnknownShape): T | undefined

One shape by id.

Defaults to Shape, the union of registered types, so shape.type === "note" narrows its props at the call site. Pass a type argument for a specific one, or UnknownShape for a type that is not registered.

getShapeAncestors(shape: UnknownShape | ShapeId): UnknownShape[]

Every shape between this one and the page, OUTERMOST FIRST — so the last entry is the shape's direct parent and the first is its top-level ancestor. Empty when the shape sits directly on the page.

A parent chain that loops (a corrupt snapshot) stops at the repeat rather than spinning forever.

getShapeAndDescendantIds(ids: readonly ShapeId[]): Set<ShapeId>

Every id given, plus every descendant of each.

getShapeAtPoint(point: VecLike, opts?: HitTestOptions): UnknownShape | undefined
getShapeClipPath(shape: UnknownShape | ShapeId): string | undefined

A CSS clip-path, in the shape's own space, or undefined when unclipped.

getShapeGeometry<G extends Geometry2d = Geometry2d>(shape: UnknownShape | ShapeId): G
getShapeGeometryBounds(shape: UnknownShape | ShapeId): Box | undefined
getShapeHandles(shape: UnknownShape | ShapeId): ShapeHandle[] | undefined

A shape's drag handles in its own space, or undefined.

getShapeIdsInsideBounds(bounds: BoxLike): ShapeId[]

The ids of every shape completely inside a page-space box.

getShapeLocalTransform(shape: UnknownShape): Mat

Local → parent transform components.

getShapeMask(shape: UnknownShape | ShapeId): VecLike[] | undefined

The page-space polygon a shape is clipped to by its ancestors, or undefined when nothing clips it.

An ancestor contributes its ShapeUtil.getClipPath() — a polygon in the ancestor's own coordinates, put through its page transform here — and falls back to the ancestor's page-space bounds rectangle when it clips (isClipShape()) but names no path. A frame clips, a plain container or a group does not. Several clipping ancestors intersect into one polygon; an intersection that is empty (a shape scrolled entirely out of its frame) comes back as an empty array, which is not the same answer as "unclipped".

SEMANTICS-ASSUMED: the consumer only pins the undefined case (a section clips nothing). Empty-array-for-empty-intersection is chosen over undefined because collapsing them would make a fully clipped shape look unclipped, which is the more damaging of the two mistakes.

LIMITATION: the intersection is Sutherland–Hodgman, so a *concave* clip path is honoured only where it agrees with its convex hull. Rectangles, rounded-corner approximations and any convex path — every shape mocanvas ships and the only kind the consumer defines — are exact.

getShapeMaskedPageBounds(shape: UnknownShape | ShapeId): Box | undefined

The part of a shape's page bounds its clipping ancestors leave visible.

getShapePageBounds(shape: UnknownShape | ShapeId): Box | undefined
getShapePageTransform(shape: UnknownShape | ShapeId): Mat
getShapeParent(shape: UnknownShape | ShapeId): UnknownShape | undefined
getShapeParentAtPoint(_point: VecLike): UnknownShape | undefined
getShapeParentTransform(shape: UnknownShape | ShapeId): Mat

Parent → page transform. Identity for a shape parented to the page.

getShapesAtPoint(point: VecLike, opts?: HitTestOptions): UnknownShape[]

Shapes under a point, topmost first.

getShapesInsideBounds(box: BoxLike, opts?: HitTestOptions): UnknownShape[]

Shapes fully inside a page box, in draw order.

getShapesIntersectingBounds(box: BoxLike, opts?: HitTestOptions): UnknownShape[]

Shapes whose outline touches a page box, in draw order.

getShapeSketchPath(shape: UnknownShape | ShapeId): number[] | null

The outline a shape is *drawn* with when the hand-drawn style is on, as path words in shape space — or null for every other style.

The draw style does not stroke a shape's geometry. It strokes a perturbed, corner-rounded sketch of it, made in the renderer from the shape's own seed, and until now that curve existed only on the GPU. Anything here that wanted to trace what the user can see had nothing but the mathematical outline, and disagreed with the drawing wherever the two differ — most visibly at a corner, which the sketch rounds and the geometry does not.

null is the honest answer for a solid, dashed or dotted shape: those *are* stroked along their geometry, so there is no second curve to ask about.

getShapesPageBounds(ids: readonly (ShapeId | UnknownShape)[]): Box | null

The common masked page bounds of several shapes, or null.

getShapeStyleIfExists<T>(shape: UnknownShape | ShapeId, style: StyleProp<T>): T | undefined

A shape's value for one style prop, or undefined when it has no such style.

getShapeUtil<T extends UnknownShape | ShapeUtil = UnknownShape>(shape: UnknownShape | string): T extends ShapeUtil ? T : T extends UnknownShape ? ShapeUtil<T> : never

The util registered for a shape or shape type.

The type argument may be either the shape (getShapeUtil<NoteShape>(s), giving ShapeUtil<NoteShape>) or the util itself (getShapeUtil<NoteShapeUtil>("note"), giving NoteShapeUtil) — the second is what you want when reaching for methods a custom util adds.

getShapeUtilForAssetType(assetType: string): ShapeUtil | undefined

The ShapeUtil that should represent an asset of this type on the canvas, or undefined when nothing claims it.

Two lookups in one: the asset util names a shape type, and that shape type is resolved to its util here — so a caller placing a dropped file never has to know both registries exist.

getSharedOpacity(): TLSharedOpacity | undefined

The opacity of the selection: a value, "mixed", or undefined.

getSharedStyles(): SharedStyleMap

Styles of the selection (or of the next shape when nothing is selected).

getSnapshot(): TLEditorSnapshot

The document and this person's place in it, saved together.

getSortedChildIdsForParent(parentId: ParentId): ShapeId[]
getStateDescendant<T extends StateNode>(path: string): T | undefined
getStyleForNextShape<T>(style: StyleProp<T>): T
getStylePropsForType(type: string): Map<string, StyleProp<unknown>>

Style props declared by the ShapeUtil for a type, keyed by prop name.

getSvgElement(ids?: readonly ShapeId[], opts?: EditorSvgExportOptions): SVGSVGElement | undefined

The export as a live <svg> element rather than a string.

What a preview pane wants: an element can be measured, styled and inserted without a parse step. undefined when there is nothing to export, or when there is no DOM to build an element in.

getSvgString(ids?: readonly ShapeId[], opts?: EditorSvgExportOptions): EditorSvgExportResult | undefined

Serialize shapes to an SVG string; undefined when there is nothing to export. Defaults to the selection, or the whole page when nothing is selected. Throws until an export implementation is registered.

getTemporaryAssetPreview(assetId: AssetId): TLTemporaryAssetPreview | undefined

The in-flight preview for an asset, or undefined once it has expired.

getTextOptions(): TLTextOptions | undefined

Rich-text configuration, from textOptions or options.text.

getTextureResolution(): number

Device-pixel scale at which rasterized textures (text labels) should be drawn: the device pixel ratio times the zoom, bucketed to powers of two.

getTheme(id: TLThemeId): TLTheme | undefined

One registered theme by id, or undefined.

getThemes(): Record<TLThemeId, TLTheme>

Every registered theme.

getViewportPageBounds(): Box
getViewportPageCenter(): Vec
getViewportScreenBounds(): Box
getViewportScreenCenter(): Vec
getVisibleCollaborators(): InstancePresence[]

Everybody who counts as present, on any page: their presence record was refreshed within collaboratorInactiveTimeoutMs.

The list a people-menu shows. For the cursors to draw, which is a narrower question, use getVisibleCollaboratorsOnCurrentPage.

getVisibleCollaboratorsOnCurrentPage(): InstancePresence[]

Collaborators on this page who are actually THERE: the ones whose presence record was refreshed within COLLABORATOR_INACTIVE_TIMEOUT.

A tab left open overnight keeps writing presence but stops being a person to draw a cursor for, so anything that renders collaborators uses this and not getCollaboratorsOnCurrentPage(). The flip side is that a long-running participant (an agent working through a tool call) must keep its lastActivityTimestamp fresh or it will vanish mid-turn.

getZoomLevel(): number
groupShapes(ids?: readonly ShapeId[], groupId?: ShapeId): ShapeId | undefined

Wrap shapes in a new group shape (requires a registered "group" ShapeUtil). Returns the group id.

hasAncestor(shape: UnknownShape | ShapeId | undefined, ancestorId: ShapeId): boolean

Whether ancestorId is above shape in the tree. False for the shape itself.

hasAssetUtil(type: string): boolean

Whether an asset type has a util registered.

hasBindingUtil(type: string): boolean
hasExternalAssetHandler(type: ExternalAssetType): boolean
hasExternalContentHandler(type: ExternalContentType): boolean
hasShapeUtil(type: string): boolean
hasTool(id: string): boolean

Whether a tool id is still in service.

interrupt(): this
isAncestorSelected(shape: UnknownShape | ShapeId | undefined): boolean

Whether any ancestor of shape is selected.

get isDisposed(): boolean

Whether dispose() has run. Async work started before disposal checks this before touching the store again; reading it inside a signal re-runs the reader when the editor goes away.

isEventHandled(event: {

Whether markEventAsHandled was called for this event.

isIn(path: string): boolean
isInAny(...paths: string[]): boolean
isPointInShape(shape: UnknownShape | ShapeId, point: VecLike, opts?: TLPointInShapeOptions): boolean

Whether a page point falls on a shape, honouring what clips it.

isShapeFrameLike(shape: UnknownShape | ShapeId | undefined): boolean

Whether a shape's util declares it a frame-like container.

isShapeHidden(shape: UnknownShape | ShapeId | undefined): boolean

Whether the host's getShapeVisibility hides this shape.

isShapeInPage(shape: UnknownShape | ShapeId | undefined, pageId?: PageId): boolean

Whether shape lives on pageId (the current page by default).

isShapeOfType<T extends UnknownShape>(shape: UnknownShape | ShapeId | undefined, type: T["type"]): shape is T

Whether a shape is of a given type, narrowing it when so.

A type guard rather than a === because that is what makes it usable in a filter: shapes.filter((s) => editor.isShapeOfType<NoteShape>(s, "note")) comes back typed.

isShapeOrAncestorLocked(shape: UnknownShape | ShapeId): boolean
loadSnapshot(snapshot: Parameters<typeof loadSnapshot>[1], opts?: TLLoadSnapshotOptions): this

Restore a snapshot, or just its document half. Not undoable.

mark(name?: string): string

Alias of markHistoryStoppingPoint.

markEventAsHandled(event: {

Claim an event that a shape's own DOM has already dealt with, so the tool tree leaves it alone.

A shape rendered as real DOM (an editable label, an embedded input) handles its own double-click, pointer-down and Enter. Without claiming them they also bubble to the canvas, where the select tool reads them as gestures on the shape and, for instance, re-enters edit mode on the Enter that was meant to leave it.

React synthetic events and native events are both accepted; the underlying native event is what gets marked, so either wrapper of the same event is recognised afterwards.

SEMANTICS-ASSUMED: this is advisory, not a stopPropagation. The mark is only honoured where something checks isEventHandled before turning a DOM event into an editor event, which keeps the decision in the layer that owns the DOM rather than mutating the event itself.

markHistoryStoppingPoint(name?: string): string
moveShapesToPage(ids: readonly ShapeId[], pageId: PageId): this

Move shapes — and everything under them — to another page.

navigateToDeepLink(opts?: TLDeepLinkOptions & {

Move the camera to whatever a deep link points at.

A link naming shapes that are gone, or a page that is gone, moves nothing — a stale link should leave you where you were, not somewhere arbitrary.

nudgeShapes(ids: readonly ShapeId[], offset: VecLike): this

Move shapes by a page-space offset.

packShapes(ids?: readonly ShapeId[], gap?: number): this

Pack shapes into a tight block, in place, without resizing them.

pageToScreen(point: VecLike): Vec

Page -> screen (window-relative pixels, for position: fixed callers).

pageToViewport(point: VecLike): Vec

Page -> viewport (container-relative pixels).

pan(offsetScreen: VecLike, opts?: TLCameraMoveOptions): this

Pan by a VIEWPORT-space offset (container-relative pixels).

popFocusedGroupId(): this

Back out one level of drill-in, selecting the group being left.

putContentOntoCurrentPage(content: {

Insert clipboard content at a page point (centered), with fresh ids. Returns the new ids.

putExternalContent(info: ExternalContent): Promise<void>

Handle content dropped or pasted onto the canvas by dispatching to the registered handler for info.type. Resolves once the handler is done; resolves immediately when no handler is registered.

redo(): this
registerDeepLinkListener(opts?: TLDeepLinkOptions): () => void

Keep a URL in step with where the editor is, and return the unsubscribe.

Debounced, because the camera changes on every frame of a pan and a URL rewritten sixty times a second floods the browser's history.

registerExternalAssetHandler<T extends ExternalAssetType>(type: T, handler: ExternalAssetHandler<T> | null): () => void

Register how an asset record is produced from a file or url. Returns a function that removes it again.

registerExternalContentHandler<T extends ExternalContentType>(type: T, handler: ExternalContentHandler<T> | null): () => void

Register the handler for one kind of dropped/pasted content. Replaces any previous handler for that type; null removes it. Returns a function that removes the handler again (only if it is still the registered one).

removeTool(id: string): this

Take a tool out of service.

The tool's state node stays in the tree — removing it would strand any state a shape holds against it — but it stops being selectable, and an editor sitting in it is moved to the first remaining tool. This is how a host disables drawing in a review mode without rebuilding the editor.

renamePage(id: PageId, name: string): this
renderFrame(backend: RenderBackend): FrameBuffers

Build and draw one frame. Called by the canvas component inside rAF.

reparentShapes(shapes: readonly (ShapeId | UnknownShape)[], parentId: ParentId, insertIndex?: IndexKey): this

Move shapes under a new parent, keeping their page position and rotation.

Takes ids or records: a caller that already has the shape in hand should not have to reach for .id, and a caller that has only the id should not have to look the shape up.

replaceExternalContent(info: ExternalContent & {

Replace a shape's content with something dropped onto it, rather than creating a new shape beside it.

The "drop an image onto an image" gesture. Delegates to the registered external-content handler with the target shape attached, so an app that already customised drop handling customises this too; with no handler it does nothing rather than falling back to creating a shape, which is the behaviour the caller explicitly did not ask for.

resetZoom(point?: VecLike, opts?: TLCameraMoveOptions): this
resizeShape(id: ShapeId | UnknownShape, scale: VecLike, options?: ResizeShapeOptions): this

Scale one shape by scale about a point, letting its ShapeUtil.onResize produce the prop change — the same contract the select tool's resize state uses. The shape's origin is moved by the same scale about scaleOrigin (its page bounds center by default), measured in a frame rotated by scaleAxisRotation.

Locked shapes and shapes whose util says canResize is false are left alone. onResizeStart / onResizeEnd bracket the change; the util is told the resize came from the bottom_right handle.

resizeShapes(ids: readonly (ShapeId | UnknownShape)[], scale: VecLike, options?: Omit<ResizeShapeOptions, "initialBounds">): this

Scale several shapes by the same factor about one point — by default the center of their common page bounds, so the group scales as a unit.

resizeToBounds(ids: readonly ShapeId[], bounds: BoxLike): this

Scale and move shapes so their common bounds become bounds exactly.

resolveAssetsInContent(content: {

Resolve every asset referenced by a piece of content, so it can be rendered somewhere the store is not — an export, a thumbnail, a paste into another document.

Returns a map rather than mutating the content: the content may be frozen, and the caller usually wants both the original ids and the URLs.

resolveAssetUrl(asset: AssetId | Asset): string | null | Promise<string | null>

The URL to paint an asset from.

A temporary preview wins while one is current, so a just-dropped image appears immediately and is replaced by the uploaded one without the shape having to re-render against a null src in between.

rotateShapesBy(ids: readonly ShapeId[], delta: number, center?: VecLike): this

Rotate shapes by delta radians around the center of their common page bounds.

The resulting rotation is canonicalized into [0, 2π). Without that, an angle that only ever accumulates leaves two documents that look identical carrying different numbers — and rotation is persisted and sent over the wire, so a diff, a parity check and a sync merge all see a difference that is not on screen.

run<T>(fn: () => T, opts?: {

Run fn as one operation: one history entry, and one notification to the store's listeners however many writes it makes.

It has to open an operation on the *store*, not just a signal transaction. A transact alone batches recomputation and nothing else, so every write inside still opened and closed an operation of its own — two updateShapes calls in one run reached a listener as two notifications, the first of them carrying a half-applied state that was never an intended state of the document. A sync binding published that state to its peers.

screenToPage(point: VecLike): Vec

Screen (window-relative) -> page. The inverse of pageToScreen.

select(...ids: (ShapeId | UnknownShape)[]): this
selectAdjacentShape(direction: TLAdjacentDirection): this

Move the selection one shape in direction.

selectAll(): this
selectFirstChildShape(): this

Select the first child of the only selected shape.

selectNone(): this
selectParentShape(): this

Select the parents of the selected shapes.

sendBackward(ids?: readonly ShapeId[]): this
sendToBack(ids?: readonly ShapeId[]): this
setCamera(point: Partial<VecModel>, opts?: TLCameraMoveOptions): this

Move the camera. Omitted components keep their current value and the zoom is clamped to the editor's zoom range.

With animation.duration the camera eases to the target over that many milliseconds instead of jumping; any animation already in flight is abandoned first, so the newest instruction always wins. A locked camera (see setCameraOptions) ignores the move unless force is passed.

setCameraOptions(options: Partial<TLCameraOptions>): this

Change part of the camera policy; omitted keys keep their value.

setColorMode(scheme: TLColorScheme): this

Choose light, dark, or follow the host window.

Takes the full TLColorScheme and not only a resolved mode, because "system" is a legitimate thing to set and there would otherwise be no way back to it once a mode was pinned.

setCroppingShape(id: ShapeId | UnknownShape | null): this

Enter (or, with null, leave) cropping.

Refuses a shape that canCropShape rejects rather than entering a mode with nothing to do in it. Entering also selects the shape, since every crop handle is drawn against the selection.

setCurrentPage(pageId: PageId): this
setCurrentTheme(id: TLThemeId): this

Switch themes. Unknown ids are ignored.

setCurrentTool(id: string, info?: Record<string, unknown>): this

Switch tools. id may be a dotted path, e.g. "select.idle".

setCursor(cursor: Partial<Instance["cursor"]>): this

Set the cursor shown over the canvas. Tools set it on enter and put it back to default on exit; nothing resets it for them.

setEditingShape(id: ShapeId | UnknownShape | null): this
setErasingShapes(ids: readonly ShapeId[]): this
setFocusedGroup(id: ShapeId | UnknownShape | null): this

Drill into a group, or back out to the page with null.

setHintingShapes(ids: readonly (ShapeId | UnknownShape)[]): this

Mark shapes as hinted: the drop targets of the gesture in flight.

A hinted shape draws its indicator with a heavier stroke than a selected or hovered one, which is how "this is where it will land" reads. An empty array clears the hint, and every gesture that sets one is responsible for clearing it when it ends.

setHoveredShape(id: ShapeId | UnknownShape | null): this
setOpacityForNextShapes(opacity: number): this

Set the opacity newly created shapes will start with.

setOpacityForSelectedShapes(opacity: number): this

Set the opacity of the selected shapes.

setRichTextEditor(instance: unknown): this

Attach (or, with null, detach) the rich-text editor instance.

setSelectedShapes(ids: readonly (ShapeId | UnknownShape)[]): this
setStyleForNextShapes<T>(style: StyleProp<T>, value: T): this
setStyleForSelectedShapes<T>(style: StyleProp<T>, value: T): this

Set a style on every selected shape that declares it.

setTool(id: string, info?: Record<string, unknown>): this

Switch tools. The documented spelling of setCurrentTool.

slideCamera(opts: {

Fling the camera and let it coast to a stop.

direction is a screen-space velocity in pixels per frame; speed scales it; friction comes from cameraSlideFriction. The slide stops early on any other camera instruction, because the newest instruction always wins.

squashToMark(id: string): this
stackShapes(ids: readonly ShapeId[], operation: "horizontal" | "vertical", gap?: number): this

Stack shapes edge to edge with a fixed gap along an axis (order by current position).

startFollowingUser(userId: UserId): this

Follow another person's camera. Their viewport is mirrored into ours until stopFollowingUser or a camera move of our own.

The id is a USER id (InstancePresence.userId), not a presence record id: one person with several tabs is still one person to follow.

stopCameraAnimation(): this

End any camera animation where it currently is.

This is what a hand on the board mid-flight does: the camera stops at the frame the user interrupted it on rather than continuing to a destination they have already overruled.

stopFollowingUser(): this

Stop mirroring anyone's camera. A no-op when not following.

stretchShapes(ids: readonly ShapeId[], operation: "horizontal" | "vertical"): this

Resize shapes so each one spans the common bounds of all of them on one axis. Every shape given contributes to the common bounds, but only the unlocked, resizable ones are stretched.

get styleProps(): ReadonlyMap<string, ReadonlyMap<string, StyleProp<unknown>>>

Every style prop the registered shape utils declare, by shape type.

SEMANTICS-ASSUMED: keyed by shape type, then by prop name. The style panel needs both directions of this map and the type-first shape is the one that can be built without instantiating anything.

get textMeasure(): EditorTextMeasure

Measures runs of text the way the editor renders them. Installed through the same seam as the export functions; throws until something registers one.

toggleLock(ids?: readonly ShapeId[]): this

Toggle the locked state of shapes.

toImage(ids?: readonly ShapeId[], opts?: EditorImageExportOptions): Promise<EditorImageExportResult>

Render shapes to an image blob (png by default). Same shape selection rules as getSvgString. Throws until an export implementation is registered.

toImageDataUrl(ids?: readonly ShapeId[], opts?: EditorImageExportOptions): Promise<string>

The export as a data: URL.

The form that can go straight into an <img src> or a clipboard write without a blob URL to revoke afterwards — at the cost of about a third more bytes, which is why toImage and its blob remain the default.

undo(): this
ungroupShapes(ids?: readonly ShapeId[]): this

Dissolve groups, re-parenting their children to the group's parent.

updateAsset<A extends Asset>(partial: AssetPartial<A>): this
updateAssets<A extends Asset>(partials: readonly AssetPartial<A>[]): this
updateBinding<B extends UnknownBinding>(partial: BindingPartial<B>): this
updateBindings<B extends UnknownBinding>(partials: readonly BindingPartial<B>[]): this
updateCurrentPageState(partial: Partial<Omit<InstancePageState, "id" | "typeName" | "pageId">>): this
updateDocumentSettings(settings: Partial<Omit<Document$1, "id" | "typeName">>): this
updateInstanceState(partial: Partial<Omit<Instance, "id" | "typeName">>): this
updatePage(partial: Partial<Omit<Page, "typeName">> & {

Change a page's name, index or meta.

updateShape<T extends UnknownShape>(partial: ShapePartial<T> | null | undefined): this
updateShapes<T extends UnknownShape>(partials: readonly (ShapePartial<T> | null | undefined)[]): this
updateTheme(id: TLThemeId, patch: Parameters<ThemeManager["updateTheme"]>[1]): this

Patch one theme in place.

updateThemes(patch: Parameters<ThemeManager["updateThemes"]>[0]): this

Patch several themes at once.

updateViewportScreenBounds(bounds: Box | BoxLike | HTMLElement, center?: boolean): this

Tell the editor how big its viewport is on screen.

Takes the element as well as a box, because that is the call every host actually makes — it has the container to hand, not a measured rectangle — and because tldraw accepts one, so a drop-in host that passes its ref would otherwise fail on a getBoundingClientRect that was never there.

uploadAsset(file: File): Promise<Asset | undefined>

Turn a file into an asset record through the util that claims its type, and store it.

undefined when no util wants the file — the caller shows "unsupported file type" rather than silently dropping it.

viewportToPage(point: VecLike): Vec

Viewport (container-relative) -> page. The inverse of pageToViewport.

visitDescendants(parent: PageId | ShapeId, visitor: (id: ShapeId) => void | false): this

Depth-first walk of a parent's descendants; return false to prune a branch.

wasEventAlreadyHandled(event: {

Whether something has already claimed this event.

The documented spelling of isEventHandled; both read the same weakly-held set, so a shape's own DOM handler marking an event is visible to the canvas handler that sees it next.

zoomIn(point?: VecLike, opts?: TLCameraMoveOptions): this
zoomOut(point?: VecLike, opts?: TLCameraMoveOptions): this
zoomToBounds(bounds: BoxLike, opts?: TLCameraMoveOptions & {

Frame bounds in the viewport. inset is the screen-space margin left around it and targetZoom a CEILING on the resulting zoom, so a tiny target does not fill the screen.

zoomToFit(opts?: TLCameraMoveOptions & {
zoomToPointAt(viewportPoint: VecLike, nextZoom: number, opts?: TLCameraMoveOptions): this

Zoom keeping the given VIEWPORT point (container-relative) fixed.

zoomToSelection(opts?: TLCameraMoveOptions & {
zoomToSelectionIfOffscreen(padding?: number, opts?: TLCameraMoveOptions & {

Bring the selection into view, but only if it is not already there.

The camera does not move at all when the selection is fully on screen — which is what makes this safe to call after every operation that changes the selection, without yanking the view around when nothing needed to happen.

zoomToUser(userId: UserId, opts?: TLCameraMoveOptions & {

Move the camera to whatever userId has selected, or — when they have nothing selected — to their cursor.

A one-shot jump, unrelated to startFollowingUser: it does not keep mirroring their camera afterwards. Returns without moving when that person is not on this page, or is not here at all.

SEMANTICS-ASSUMED: framing their *selection* rather than replicating their viewport. Copying their camera would put a collaborator on a 27" display somewhere unusable on a laptop; "show me what they are working on" is the question this method is actually asked. With nothing selected there is no region to frame, so the cursor is centred at the current zoom instead.


Properties · 32

readonly assets: AssetStore

Where this editor's asset bytes live.

readonly bindingUtils: Readonly<Record<string, BindingUtil>>
readonly click: ClickManager

Double-click detection for the dispatch loop and for tools.

readonly collaborators: CollaboratorsManager

Who else is in the room, and which of them to draw.

readonly contentElements: ContentElementManager

DOM elements owned by shape utils rather than by the React tree — see ShapeUtil.getContentElement. They outlive a re-render and the editor's own unmount, and are released with the shape or with the editor.

contextId: string | undefined

The React context instance this editor belongs to, when a host set one.

Two editors rendered by two independent React trees on one page must not read each other's context; a host that mounts editors in isolated trees (a plugin host, a storybook page) sets this so context lookups can tell them apart. undefined in the ordinary single-tree case.

readonly edgeScrollManager: EdgeScrollManager

Panning the camera when a drag reaches the viewport edge.

readonly engine: EngineBridge
readonly fonts: FontManager

On-demand loading of the typefaces the canvas needs.

readonly getContainer: () => HTMLElement
readonly getInitialMetaForShapeHandler: ((shape: UnknownShape) => UnknownShape["meta"]) | undefined
readonly getShapeVisibility: TLGetShapeVisibility | undefined
readonly handles: HandleTable
readonly history: HistoryManager<EditorRecord>
readonly id: string

This editor's own id. Stable for its lifetime, unique within the process, and the thing to key per-editor caches and log lines by.

readonly inputs: EditorInputs
readonly menus: MenuManager

Which menus are open right now. Backed by the instance session record.

readonly options: EditorConfig
readonly overlays: OverlayManager

The registry of canvas overlay painters.

readonly performance: PerformanceManager

Timing events for profilers and dev overlays. Nothing depends on it.

readonly root: StateNode
readonly scribbles: ScribbleManager

The trails a laser, an eraser or a select brush leaves behind.

readonly shapeUtils: Readonly<Record<string, ShapeUtil>>
readonly sideEffects: EditorStore["sideEffects"]
readonly snaps: SnapManager
readonly store: EditorStore
readonly text: TextManager

Text measurement and span layout. See TextManager.

readonly textOptions: TLTextOptions | undefined

Rich-text configuration, from textOptions or options.text.

readonly textures: TextureManager

GPU textures referenced by shape styles (images, rasterized text).

readonly theme: ThemeManager

Colours and display values for the current theme and colour mode.

readonly timers: Timers

Timeouts, intervals and animation frames that die with the editor.

readonly user: UserPreferencesManager

The local person's preferences: identity (id, name, colour) plus the behaviour flags that change how the editor treats their input, such as dynamic-size mode. Session-only, never persisted with the document.

mocanvas is built by Symbio. Free for non-commercial, non-profit and development use; commercial use needs an agreement. Not affiliated with or endorsed by tldraw.