Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
206 lines
15 KiB
Plaintext
206 lines
15 KiB
Plaintext
---
|
|
title: v4.4.0
|
|
description: Consolidated options prop, quick zoom, fill styles dropdown, canvas indicators, R-tree indexing, and more
|
|
author: tldraw
|
|
date: 02/18/2026
|
|
order: 0
|
|
status: published
|
|
keywords:
|
|
- changelog
|
|
- release
|
|
- v4.4
|
|
- v4.4.0
|
|
- v4.4.1
|
|
- options-prop
|
|
- quick-zoom
|
|
- canvas-indicators
|
|
- r-tree
|
|
- spatial-index
|
|
- performance
|
|
- laser-pointer
|
|
- fill-styles
|
|
- select-component
|
|
- image-pipeline
|
|
- agent-template
|
|
- invert-zoom
|
|
---
|
|
|
|
[View on GitHub](https://github.com/tldraw/tldraw/releases/tag/v4.4.0)
|
|
|
|
This release adds a consolidated `options` prop, quick zoom navigation, a fill styles dropdown, a new `TldrawUiSelect` component, and shape-aware binding checks. It also includes 2D canvas rendering for shape indicators, R-tree spatial indexing, telestrator-style laser behavior, significant performance improvements for large canvases, and various bug fixes.
|
|
|
|
## What's new
|
|
|
|
### 2D canvas rendering for shape indicators ([#7708](https://github.com/tldraw/tldraw/pull/7708))
|
|
|
|
Shape indicators (selection outlines, hover states) now render using a 2D canvas instead of SVG elements. This significantly improves performance when selecting or hovering over many shapes, with up to 25x faster rendering in some scenarios.
|
|
|
|
Custom shapes can opt into canvas indicators by implementing the new `getIndicatorPath()` method on their ShapeUtil, and marking `useLegactIndicator` to return false:
|
|
|
|
```tsx
|
|
class MyShapeUtil extends ShapeUtil<MyShape> {
|
|
getIndicatorPath(shape: MyShape): TLIndicatorPath | undefined {
|
|
return {
|
|
path: new Path2D(),
|
|
// optional clip path for complex shapes like arrows with labels
|
|
}
|
|
}
|
|
|
|
// Return false to use the new canvas indicators (default is true for backwards compatibility)
|
|
useLegacyIndicator(): boolean {
|
|
return false
|
|
}
|
|
}
|
|
```
|
|
|
|
### Quick zoom navigation ([#7801](https://github.com/tldraw/tldraw/pull/7801), [#7836](https://github.com/tldraw/tldraw/pull/7836))
|
|
|
|
Press `z` then hold Shift to zoom out and see the whole canvas ("eagle eye" view). A viewport brush appears showing where you'll zoom to. Move the cursor to pick a location and release Shift to zoom there. Press Escape to cancel and return to the original view.
|
|
|
|
### Fill styles dropdown ([#7885](https://github.com/tldraw/tldraw/pull/7885))
|
|
|
|
The style panel now exposes additional fill styles (pattern, fill, lined-fill) through a dropdown picker after the solid button. The first three fill options (none, semi, solid) remain as inline buttons.
|
|
|
|
### User preference: Invert mouse wheel zoom direction ([#7732](https://github.com/tldraw/tldraw/pull/7732))
|
|
|
|
Added a new user preference to invert mouse wheel zoom direction. Some users prefer "natural" scrolling behavior where scrolling down zooms out, which this option now enables.
|
|
|
|
Access it via Menu → Preferences → Input device → Invert mouse zoom.
|
|
|
|
### Performance improvements ([#7676](https://github.com/tldraw/tldraw/pull/7676), [#7826](https://github.com/tldraw/tldraw/pull/7826), [#7840](https://github.com/tldraw/tldraw/pull/7840), [#7657](https://github.com/tldraw/tldraw/pull/7657))
|
|
|
|
This release includes several performance improvements for large canvases:
|
|
|
|
- **R-tree spatial indexing**: Shape queries now use an R-tree (RBush) for O(log n) lookups instead of O(n) iteration, significantly improving brushing, scribble selection, and erasing with many shapes on the canvas. The spatial index is maintained internally and accessed through existing methods like `editor.getShapesAtPoint()` and `editor.getShapeAtPoint()`.
|
|
- **Faster panning**: Hover hit-testing is now skipped during camera movement, reducing work while panning through large documents.
|
|
- **Reduced allocations**: Optimized Set comparisons, reduced memory allocations, and added string hash caching for better performance in large canvases and multiplayer rooms.
|
|
- **Smarter network scheduling**: Solo-mode network traffic is reduced by throttling to 1 FPS when no collaborators are present.
|
|
|
|
### Re-designed laser pointer ([#7681](https://github.com/tldraw/tldraw/pull/7681))
|
|
|
|
The laser pointer now behaves like a telestrator: all strokes remain visible while you're drawing and fade together when you stop. Previously, each stroke segment would fade independently, creating a trailing effect.
|
|
|
|
This is powered by a new generic session system on `ScribbleManager`. Sessions group multiple scribbles together and control how they fade:
|
|
|
|
```tsx
|
|
// Start a grouped session (used internally by the laser tool)
|
|
const sessionId = editor.scribbles.startSession({
|
|
fadeMode: 'grouped',
|
|
idleTimeoutMs: 1200,
|
|
fadeDurationMs: 500,
|
|
})
|
|
|
|
// Add scribbles and points to a session
|
|
editor.scribbles.addScribbleToSession(sessionId, { color: 'laser' })
|
|
editor.scribbles.addPointToSession(sessionId, scribbleId, x, y)
|
|
|
|
// Stop or clear a session
|
|
editor.scribbles.stopSession(sessionId)
|
|
editor.scribbles.clearSession(sessionId)
|
|
```
|
|
|
|
New option in `TldrawOptions`:
|
|
|
|
- `laserFadeoutMs` (default: 500ms) - How long to fade all laser scribbles after the session ends
|
|
|
|
### Image pipeline starter template ([#7863](https://github.com/tldraw/tldraw/pull/7863))
|
|
|
|
A new "Image pipeline" starter template is available via `npx create-tldraw`. It provides a visual node-based canvas for building AI image generation workflows, with custom node shapes, typed port connections, pipeline regions with play/stop controls, and a DAG-based execution engine backed by a Cloudflare Worker API.
|
|
|
|
### Agent starter template improvements ([#7640](https://github.com/tldraw/tldraw/pull/7640))
|
|
|
|
The agent starter template has been restructured around a manager-based architecture for better modularity and extensibility. It now includes a mode system for controlling agent capabilities per mode, action schema registries, prompt part definitions, canvas linting, and user action tracking. The template also renames "SimpleShape" to "FocusedShape" for clarity.
|
|
|
|
### TldrawUiSelect component ([#7566](https://github.com/tldraw/tldraw/pull/7566))
|
|
|
|
New select dropdown primitive wrapping Radix UI's Select, following existing tldraw UI patterns.
|
|
|
|
### 🔜 Consolidated options prop ([#7888](https://github.com/tldraw/tldraw/pull/7888))
|
|
|
|
The `cameraOptions`, `textOptions`, and `deepLinks` props on `Tldraw`, `TldrawEditor`, and `TldrawImage` are now consolidated into the `options` prop. The standalone props are deprecated but still work for backward compatibility.
|
|
|
|
```tsx
|
|
// Before
|
|
<Tldraw cameraOptions={{ isLocked: true }} deepLinks textOptions={{ ... }} />
|
|
|
|
// After
|
|
<Tldraw options={{ camera: { isLocked: true }, deepLinks: true, text: { ... } }} />
|
|
```
|
|
|
|
<details>
|
|
<summary>Migration guide</summary>
|
|
|
|
Replace standalone props with equivalent `options` fields:
|
|
|
|
- `cameraOptions={...}` → `options={{ camera: { ... } }}`
|
|
- `textOptions={...}` → `options={{ text: { ... } }}`
|
|
- `deepLinks` or `deepLinks={...}` → `options={{ deepLinks: true }}` or `options={{ deepLinks: { ... } }}`
|
|
|
|
The deprecated props still work. When both the deprecated prop and the `options` field are provided, the `options` value takes precedence.
|
|
|
|
</details>
|
|
|
|
## API changes
|
|
|
|
- 🔜 **`TldrawEditorBaseProps.cameraOptions`**, **`TldrawEditorBaseProps.textOptions`**, **`TldrawEditorBaseProps.deepLinks`** deprecated in favor of `options.camera`, `options.text`, `options.deepLinks`. ([#7888](https://github.com/tldraw/tldraw/pull/7888))
|
|
- 🔜 **`TLShapeUtilCanBindOpts.fromShapeType`** and **`toShapeType`** replaced with `fromShape` and `toShape` accepting `TLShape | { type }`. ([#7821](https://github.com/tldraw/tldraw/pull/7821))
|
|
- Remove `editor.spatialIndex` from public API. The spatial index is now internal; use `editor.getShapesAtPoint()` and `editor.getShapeAtPoint()` for shape queries. ([#7699](https://github.com/tldraw/tldraw/pull/7699))
|
|
- Add `TldrawOptions.camera`, `TldrawOptions.text`, and `TldrawOptions.deepLinks` fields to the `options` prop. ([#7888](https://github.com/tldraw/tldraw/pull/7888))
|
|
- Add `TldrawUiSelect`, `TldrawUiSelectTrigger`, `TldrawUiSelectValue`, `TldrawUiSelectContent`, `TldrawUiSelectItem` components and associated prop types. Add `iconTypes` export for enumerating available icons. ([#7566](https://github.com/tldraw/tldraw/pull/7566))
|
|
- Add `useCanApplySelectionAction()` hook for checking if selection actions should be enabled. ([#7811](https://github.com/tldraw/tldraw/pull/7811))
|
|
- Add `TLInstance.cameraState: 'idle' | 'moving'` for tracking camera movement state. ([#7826](https://github.com/tldraw/tldraw/pull/7826))
|
|
- Add `quickZoomPreservesScreenBounds` to `TldrawOptions`. ([#7836](https://github.com/tldraw/tldraw/pull/7836))
|
|
- Add `fillExtra` to `STYLES` object for additional fill style options. ([#7885](https://github.com/tldraw/tldraw/pull/7885))
|
|
- Make `Editor.getShapeIdsInsideBounds()` public. ([#7863](https://github.com/tldraw/tldraw/pull/7863))
|
|
- Add `ShapeUtil.getIndicatorPath()` method and `TLIndicatorPath` type for canvas-based indicator rendering. Add `ShapeUtil.useLegacyIndicator()` to control whether shapes use SVG or canvas indicators. ([#7708](https://github.com/tldraw/tldraw/pull/7708))
|
|
- Add `isZoomDirectionInverted` to `TLUserPreferences` interface and `UserPreferencesManager.getIsZoomDirectionInverted()` method. Add `ToggleInvertZoomItem` component export and `toggle-invert-zoom` action. ([#7732](https://github.com/tldraw/tldraw/pull/7732))
|
|
- Add `complete` to `TL_SCRIBBLE_STATES` enum and `ScribbleManager.complete(id)` method for marking scribbles as complete before fading. ([#7760](https://github.com/tldraw/tldraw/pull/7760))
|
|
- Add scribble session system: `ScribbleManager.startSession()`, `stopSession()`, `clearSession()`, `extendSession()`, `isSessionActive()`, `addScribbleToSession()`, `addPointToSession()`, and `ScribbleSessionOptions` type. Add `LaserTool.getSessionId()`. Add `laserFadeoutMs` to `TldrawOptions`. ([#7681](https://github.com/tldraw/tldraw/pull/7681))
|
|
- Add `FpsScheduler` class to create FPS-throttled function queues with configurable target rates. ([#7418](https://github.com/tldraw/tldraw/pull/7418))
|
|
|
|
## Improvements
|
|
|
|
- Improve performance in large canvases and multiplayer rooms by optimizing Set comparisons, reducing memory allocations, and caching string hashes. ([#7840](https://github.com/tldraw/tldraw/pull/7840))
|
|
- Improve panning performance in large documents by skipping hover hit-testing during camera movement. ([#7826](https://github.com/tldraw/tldraw/pull/7826))
|
|
- Improve performance when translating arrows together with bound shapes by skipping unnecessary reparenting. ([#7733](https://github.com/tldraw/tldraw/pull/7733))
|
|
- Add R-tree spatial indexing for O(log n) shape queries, improving performance of brushing, selection, and erasing with many shapes. ([#7676](https://github.com/tldraw/tldraw/pull/7676))
|
|
- Improve laser pointer to keep all strokes visible during a session (telestrator pattern), with strokes fading together when drawing stops. ([#7681](https://github.com/tldraw/tldraw/pull/7681))
|
|
- Improve laser pointer strokes with proper taper when lifting the pointer by adding a 'complete' state to the scribble lifecycle. ([#7760](https://github.com/tldraw/tldraw/pull/7760))
|
|
- Improve quick zoom to use zoom-to-fit instead of fixed 5%, add "quick peek" behavior, and add edge scrolling. ([#7836](https://github.com/tldraw/tldraw/pull/7836))
|
|
- Remove `core-js` polyfill dependency from `@tldraw/editor`. ([#7769](https://github.com/tldraw/tldraw/pull/7769))
|
|
- Reduce network traffic by squashing pending push requests before sending, so rapid edits result in fewer network calls. ([#7724](https://github.com/tldraw/tldraw/pull/7724))
|
|
- Reduce solo-mode network traffic by using a dedicated FPS-based scheduler that throttles to 1 FPS when no collaborators are present. ([#7657](https://github.com/tldraw/tldraw/pull/7657))
|
|
- Improve performance by separating UI and network scheduling into independent queues with configurable target FPS. ([#7418](https://github.com/tldraw/tldraw/pull/7418))
|
|
- Improve frame label sizing on smaller viewports and when zoomed out. ([#7746](https://github.com/tldraw/tldraw/pull/7746))
|
|
- Add image pipeline starter template with visual node-based AI image generation workflows. ([#7863](https://github.com/tldraw/tldraw/pull/7863))
|
|
- Restructure agent starter template with manager-based architecture and mode system. ([#7640](https://github.com/tldraw/tldraw/pull/7640))
|
|
|
|
## Bug fixes
|
|
|
|
- Fix geo shapes with text not being resizable to a smaller size. ([#7878](https://github.com/tldraw/tldraw/pull/7878))
|
|
- Fix shapes exploding when resizing unaligned arrows. ([#7855](https://github.com/tldraw/tldraw/pull/7855))
|
|
- Fix Safari pinch zoom resetting selection to previous shapes. ([#7777](https://github.com/tldraw/tldraw/pull/7777))
|
|
- Fix toggle-lock action firing when no shapes are selected. ([#7815](https://github.com/tldraw/tldraw/pull/7815))
|
|
- Fix menu items (zoom to selection, cut, copy, delete) being enabled when not in select tool. ([#7811](https://github.com/tldraw/tldraw/pull/7811))
|
|
- Fix excessive tab indentation in text shapes (now 2 spaces instead of 8). ([#7796](https://github.com/tldraw/tldraw/pull/7796))
|
|
- Fix canvas-in-front elements (cursors, following indicators) appearing in front of UI panels instead of behind them. ([#7865](https://github.com/tldraw/tldraw/pull/7865))
|
|
- Fix license console message colors for warnings and errors. ([#7850](https://github.com/tldraw/tldraw/pull/7850))
|
|
- Fix asset resolution being delayed by 500ms when updating an image shape's asset. ([#7612](https://github.com/tldraw/tldraw/pull/7612))
|
|
- Fix Durable Object SQLite migration in the multiplayer Cloudflare template. ([#7829](https://github.com/tldraw/tldraw/pull/7829), [#7832](https://github.com/tldraw/tldraw/pull/7832), [#7834](https://github.com/tldraw/tldraw/pull/7834), [#7835](https://github.com/tldraw/tldraw/pull/7835))
|
|
- Fix `zoomToFit` and `getCurrentPageBounds` to ignore hidden shapes when computing bounds. ([#7770](https://github.com/tldraw/tldraw/pull/7770))
|
|
- Fix collaborator shape indicators not rendering after the canvas indicator change. ([#7759](https://github.com/tldraw/tldraw/pull/7759))
|
|
- Fix rich text content not updating correctly with message squashing due to reference comparison. ([#7758](https://github.com/tldraw/tldraw/pull/7758))
|
|
- Fix keyboard shortcut menu item labels to use consistent ellipsis formatting. ([#7757](https://github.com/tldraw/tldraw/pull/7757))
|
|
- Fix spatial index not removing shapes when moved to a different page. ([#7700](https://github.com/tldraw/tldraw/pull/7700))
|
|
- Fix tldraw failing to load in CJS environments (tsx, ts-node, Jest) due to ESM-only rbush dependency. ([#7905](https://github.com/tldraw/tldraw/pull/7905))
|
|
|
|
---
|
|
|
|
## Patch releases
|
|
|
|
### v4.4.1
|
|
|
|
- Fix tooltip positioning when tldraw is rendered inside a container with CSS transforms. ([#8171](https://github.com/tldraw/tldraw/pull/8171))
|
|
|
|
[View release on GitHub](https://github.com/tldraw/tldraw/releases/tag/v4.4.1)
|