diff --git a/apps/docs/content/getting-started/releases.mdx b/apps/docs/content/getting-started/releases.mdx
index 894e7b6a745d..6b7583f3898c 100644
--- a/apps/docs/content/getting-started/releases.mdx
+++ b/apps/docs/content/getting-started/releases.mdx
@@ -17,6 +17,12 @@ Unlike many JavaScript packages distributed on [NPM](https://www.npmjs.com/), th
- Minor version bumps are released on a regular cadence, approximately monthly. **They may contain breaking changes**. We aim to make breaking changes as minimally disruptive as possible, but tldraw is actively evolving as we add new features. We recommend updating at a similar pace and checking the release notes.
- Patch version bumps are for bugfixes and hotfixes that can't wait for the next cadence release.
+## Latest tldraw versions
+
+- Run `npm install tldraw` to get the latest minor version of tldraw
+- Use `npm install tldraw@next` to get the latest version of tldraw that is used on [tldraw.com](https://www.tldraw.com)
+- The latest changes to the `main` branch of tldraw are available to test through our [pre-release canary builds](https://www.npmjs.com/package/tldraw?activeTab=versions).
+
## Next
- [next](/releases/next) - Changes for the upcoming release.
diff --git a/apps/docs/content/releases/next.mdx b/apps/docs/content/releases/next.mdx
index 60cfba39498e..ef32d4847eaa 100644
--- a/apps/docs/content/releases/next.mdx
+++ b/apps/docs/content/releases/next.mdx
@@ -2,19 +2,19 @@
title: Next release
description: Changes coming in the next release
author: tldraw
-date: 03/18/2026
+date: 05/01/2026
order: 0
status: published
last_version: v4.5.10
---
-This release adds a first-class theme system with display values for customizing default shapes, a new canvas overlay system that replaces React component overrides with Canvas 2D rendering, extensible asset types via a new `AssetUtil` system, shape attribution with a new `TLUserStore` provider and extensible user records, clipboard hooks for intercepting copy, cut, and paste, custom record types to the store, a new `@tldraw/mermaid` package for converting Mermaid diagrams to native shapes, WebSocket hibernation support for tlsync, a new `@tldraw/editor-controller` package for scripting and automation, RTL language support in the UI, cross-window embedding support, arbitrary iframe embed pasting, a paste-as-plain-text keyboard shortcut, smarter export trimming, frame-like behavior for custom shapes, custom geo shape types, right-click panning, and editor performance measurement hooks. It also includes various other improvements and bug fixes.
+This major release introduces a first-class theme system with display values, a new `OverlayUtil` system for canvas overlays, and extensibility APIs for custom record types, asset types, geo shapes, and frame-like shapes. Two new packages ship alongside it: `@tldraw/driver` for imperative editor control and `@tldraw/mermaid` for converting Mermaid diagrams into native shapes. It also adds a shape attribution system with the `TLUserStore` provider, clipboard and performance-measurement hooks, WebSocket hibernation in tlsync, RTL support, cross-window embedding, and various other improvements and bug fixes.
## What's new
-### 💥 Theme system with display values ([#8410](https://github.com/tldraw/tldraw/pull/8410))
+### 💥 Custom themes with display values ([#8410](https://github.com/tldraw/tldraw/pull/8410))
-A new first-class theme system replaces the previous approach where colors were hardcoded and resolved inline. Themes are now named, registered objects that shape utils consume via a structured display values pipeline.
+A new first-class theme system replaces the previous approach where colors were hardcoded and resolved inline. Themes are named, registered objects that shape utils consume via a structured display values pipeline.
Register custom themes via `TLThemes` module augmentation for type-safe IDs, add or remove palette colors via `TLThemeDefaultColors` and `TLRemovedDefaultThemeColors`, and pass themes to the editor via the `themes` and `initialTheme` props:
@@ -32,8 +32,6 @@ const MyDrawShapeUtil = DrawShapeUtil.configure({
})
```
-New editor methods include `getCurrentTheme()`, `setCurrentTheme()`, `getThemes()`, `updateTheme()`, `updateThemes()`, and `getColorMode()`.
-
Migration guide
@@ -70,123 +68,127 @@ const colors = theme.colors[editor.getColorMode()]
-### Custom record types ([#8213](https://github.com/tldraw/tldraw/pull/8213))
+### 💥 Custom overlays ([#8469](https://github.com/tldraw/tldraw/pull/8469))
-You can now register custom record types in the tldraw store for persisting and synchronizing domain-specific data that doesn't fit into shapes, bindings, or assets. Custom records support scoping (document/session/presence), validation, migrations, and default properties.
+A new `OverlayUtil` system unifies canvas overlays. Built-in brushes, handles, scribbles, snap indicators, selection foreground, collaborator cursors, and arrow hints are now implemented as overlay utils and can be customized or extended via the `overlayUtils` prop.
-```tsx
-import { createTLSchema, createCustomRecordId } from 'tldraw'
-
-const schema = createTLSchema({
- records: [
- {
- typeName: 'marker',
- scope: 'document',
- validator: markerValidator,
- },
- ],
-})
-```
+Overlays now render in front of indicators in a unified `CanvasOverlays` layer, and the legacy default component implementations and their CSS have been removed.
-TypeScript module augmentation via `TLGlobalRecordPropsMap` lets custom record types participate in the `TLRecord` union.
+
+Migration guide
-### WebSocket hibernation in tlsync ([#8070](https://github.com/tldraw/tldraw/pull/8070))
+The legacy overlay components have been removed from `TLEditorComponents`. Canvas overlays are now rendered directly to a 2D canvas context by `OverlayUtil` classes, and customization happens by subclassing the default util rather than swapping a React component.
-`TLSocketRoom` now supports session resume and snapshot APIs for WebSocket hibernation environments like Cloudflare Durable Objects. Sessions can be suspended and restored without losing state, and the `sync-cloudflare` template has been updated to use the WebSocket Hibernation API.
+**Customizing a built-in overlay:** extend the default util and give it the same `static type`; it replaces the built-in when passed via `overlayUtils`:
-New APIs include `handleSocketResume()` for restoring sessions from snapshots, `getSessionSnapshot()` for capturing session state, and an `onSessionSnapshot` callback for persisting snapshots to WebSocket attachments.
+```tsx
+// Before
+const components: TLEditorComponents = {
+ Brush: MyBrushComponent,
+}
-### @tldraw/editor-controller ([#7952](https://github.com/tldraw/tldraw/pull/7952))
+
-A new `@tldraw/editor-controller` package provides an imperative API for driving the tldraw editor programmatically. `EditorController` wraps an `Editor` instance and exposes event dispatch, selection transforms, clipboard operations, and shape queries with fluent chaining.
+// After
+import { Tldraw, BrushOverlayUtil, type TLBrushOverlay } from 'tldraw'
-```tsx
-import { EditorController } from '@tldraw/editor-controller'
+class MyBrushOverlayUtil extends BrushOverlayUtil {
+ override render(ctx: CanvasRenderingContext2D, overlays: TLBrushOverlay[]) {
+ const overlay = overlays[0]
+ if (!overlay) return
+ const { x, y, w, h } = overlay.props
+ const zoom = this.editor.getEfficientZoomLevel()
+ ctx.fillStyle = 'rgba(0, 0, 255, 0.1)'
+ ctx.strokeStyle = 'blue'
+ ctx.lineWidth = 1 / zoom
+ ctx.beginPath()
+ ctx.rect(x, y, w, h)
+ ctx.fill()
+ ctx.stroke()
+ }
+}
-const controller = new EditorController(editor)
-controller.pointerMove(100, 100).pointerDown().pointerMove(200, 200).pointerUp()
+
```
-This is useful for scripting, automation, agent workflows, and REPL-style interaction. The release includes a Scripter example demonstrating the package.
+The following slots have been removed from `TLEditorComponents`. Subclass the matching default overlay util instead:
-### RTL support ([#8033](https://github.com/tldraw/tldraw/pull/8033))
+- `Brush`, `ZoomBrush` → `BrushOverlayUtil`, `ZoomBrushOverlayUtil`
+- `Scribble` → `ScribbleOverlayUtil`
+- `SnapIndicator` → `SnapIndicatorOverlayUtil`
+- `Handle`, `Handles` → `ShapeHandleOverlayUtil`
+- `SelectionForeground`, `SelectionBackground` → `SelectionForegroundOverlayUtil`
+- `CollaboratorHint` → `CollaboratorHintOverlayUtil` (collaborator cursors/brushes/scribbles have their own utils too)
-The tldraw UI now supports right-to-left languages like Arabic. A new `useDirection()` hook returns `'ltr'` or `'rtl'` from the current translation context, and all Radix UI components and CSS have been updated to respect text direction. The `dir` attribute is set on `.tl-container`, and CSS uses logical properties (`margin-inline-start`, `inset-inline-end`, etc.) instead of physical ones.
+The corresponding `Default*` exports and `LiveCollaborators` have also been removed.
-### @tldraw/mermaid ([#8194](https://github.com/tldraw/tldraw/pull/8194), [#8285](https://github.com/tldraw/tldraw/pull/8285), [#8322](https://github.com/tldraw/tldraw/pull/8322))
+Customizing shape indicators — `ShapeIndicator`, `ShapeIndicators`, and `ShapeIndicatorErrorFallback` are gone. Indicators now render through each shape util's `getIndicatorPath()`. Override it to change how a shape's indicator is drawn.
-A new `@tldraw/mermaid` package converts Mermaid diagram syntax into native tldraw shapes. Paste Mermaid text to create flowcharts, sequence diagrams, state diagrams, and mind maps as editable shapes on the canvas.
+Overlays cannot render React; they draw into a 2D canvas context. For React-based overlays, render an HTML layer above the canvas via a regular `TLEditorComponents` slot like `InFrontOfTheCanvas`.
-```tsx
-import { createMermaidDiagram } from '@tldraw/mermaid'
+Overlay colors come from `TLTheme`, not CSS variables. Read them inside `render()` via `this.editor.getCurrentTheme().colors[this.editor.getColorMode()]` so overlays follow light/dark mode automatically.
-await createMermaidDiagram(
- editor,
- `
- graph TD
- A[Start] --> B{Decision}
- B -->|Yes| C[Action]
- B -->|No| D[End]
-`
-)
-```
+These CSS variables have been removed: `--tl-color-snap`, `--tl-color-brush-fill`, `--tl-color-brush-stroke`, `--tl-color-laser`, `--tl-layer-overlays-custom`.
-The package parses Mermaid syntax, extracts layout from the rendered SVG, and produces a diagram-agnostic blueprint that gets rendered into geo shapes, arrows, and groups.
+Overriding them (or the removed selectors `.tl-brush`, `.tl-scribble`, `.tl-snap-indicator`, `.tl-handle*`, `.tl-selection__fg__outline`, `.tl-corner-handle`, `.tl-text-handle`, `.tl-corner-crop-handle`, `.tl-mobile-rotate__*`) no longer has any effect. Port these to `TLTheme` entries or to the overlay util's `render()`.
-Node creation is extensible: pass `mapNodeToRenderSpec` per diagram type to map diagram nodes to different shapes, or use `createShape` in `BlueprintRenderingOptions` to take full control of how nodes are created on the canvas.
+
-### Clipboard hooks ([#8290](https://github.com/tldraw/tldraw/pull/8290))
+### Custom record types ([#8213](https://github.com/tldraw/tldraw/pull/8213))
-New `TldrawOptions` hooks let you intercept and customize clipboard copy, cut, and paste. `onBeforeCopyToClipboard` filters or transforms serialized content before it hits the clipboard, `onBeforePasteFromClipboard` filters parsed paste payloads before shapes are created, and `onClipboardPasteRaw` handles raw clipboard data before tldraw's default paste pipeline.
+You can now register custom record types in the tldraw store for persisting and synchronizing domain-specific data that doesn't fit into shapes, bindings, or assets. Custom records support scoping (document/session/presence), validation, migrations, and default properties.
```tsx
-const options: Partial = {
- onBeforeCopyToClipboard(info, content) {
- // filter shapes or transform content before copy/cut
- return content
- },
- onBeforePasteFromClipboard(info, content) {
- // filter or transform parsed paste content
- return content
- },
- onClipboardPasteRaw(info) {
- // handle raw clipboard data yourself; return false to cancel tldraw handling
- return false
- },
-}
-```
+import { createTLSchema, createCustomRecordId } from 'tldraw'
-### Shape attribution and TLUserStore ([#8147](https://github.com/tldraw/tldraw/pull/8147))
+const schema = createTLSchema({
+ records: [
+ {
+ typeName: 'marker',
+ scope: 'document',
+ validator: markerValidator,
+ },
+ ],
+})
+```
-A new shape attribution system tracks who created and last edited shapes. The `TLUserStore` provider interface connects tldraw to your auth system with reactive `Signal`-based methods: `getCurrentUser()` returns the active user for presence and attribution, while `resolve(userId)` resolves any user ID to display info.
+TypeScript module augmentation via `TLGlobalRecordPropsMap` lets custom record types participate in the `TLRecord` union.
-```tsx
- currentUserSignal,
- resolve: (userId) => resolvedUserSignal(userId),
- }}
-/>
-```
+### Extensible geo shapes ([#8543](https://github.com/tldraw/tldraw/pull/8543))
-User records are now document-scoped via the unified `TLUser` record type. SDK users can extend user records with custom validated metadata through `createTLSchema`:
+`GeoShapeUtil` now supports custom geo types via a `customGeoTypes` option on `configure()`. Previously, adding a new geo type required forking or monkey-patching `GeoShapeUtil`; now custom types plug into the existing system and inherit labels, resizing, fill/dash/color styling, SVG export, and hyperlink support — while supplying their own path geometry, snap behavior, creation size, and style panel icon.
```tsx
-const schema = createTLSchema({
- user: {
- meta: {
- isAdmin: T.boolean,
- department: T.string,
+import { GeoShapeUtil, PathBuilder } from 'tldraw'
+
+const MyGeoShapeUtil = GeoShapeUtil.configure({
+ customGeoTypes: {
+ 'rounded-rect': {
+ getPath: (w, h, shape) => {
+ const r = Math.min(w, h) * 0.2
+ return new PathBuilder()
+ .moveTo(r, 0, { geometry: { isFilled: shape.props.fill !== 'none' } })
+ .lineTo(w - r, 0)
+ .circularArcTo(r, false, true, w, r)
+ .lineTo(w, h - r)
+ .circularArcTo(r, false, true, w - r, h)
+ .lineTo(r, h)
+ .circularArcTo(r, false, true, 0, h - r)
+ .lineTo(0, r)
+ .circularArcTo(r, false, true, r, 0)
+ .close()
+ },
+ snapType: 'polygon',
+ icon: 'geo-rectangle',
+ defaultSize: { w: 200, h: 150 },
},
},
})
-```
-Note shapes now track and display a "first edited by" attribution label in the bottom-right corner, showing who first added text to the note.
-
-### Arbitrary iframe embeds ([#8306](https://github.com/tldraw/tldraw/pull/8306))
+
+```
-Paste any `