You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I went through all of our docs pages to check for things that seemed to
be out of date with changes from 4.0 -> now and which will have changed
by 5.0. Mainly changing a few examples where methods have changed, but
also fixes a few example code blocks that caused errors
### Change type
- [ ] `bugfix`
- [ ] `improvement`
- [ ] `feature`
- [ ] `api`
- [x] `other`
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
`tablePrefix` option to avoid conflicts if you're sharing a database with other data.
182
182
</Callout>
183
183
184
+
### WebSocket hibernation
185
+
186
+
Some serverless platforms let WebSocket connections survive while the surrounding object hibernates. [Cloudflare Durable Objects](https://developers.cloudflare.com/durable-objects/best-practices/websockets/) is the most common example. The platform keeps the sockets open, but your in-memory state (including the `TLSocketRoom`) is gone when the object wakes back up. Every wake would force every client to reconnect from scratch.
187
+
188
+
`TLSocketRoom` exposes three APIs for hibernation. The `onSessionSnapshot` callback fires when a session has had no message activity for about 5 seconds, so you can persist its state. [TLSocketRoom#getSessionSnapshot](?) returns that snapshot on demand. [TLSocketRoom#handleSocketResume](?) restores a session straight into `Connected` state when the object wakes back up.
189
+
190
+
Here's the pattern in a Cloudflare Durable Object that uses the WebSocket Hibernation API:
Three pieces make this work. The `onSessionSnapshot` callback persists each session's state to its WebSocket's attachment so the snapshot is still around after hibernation. When the object wakes up with sockets still open, `handleSocketResume` replays each saved snapshot and the session lands straight in `Connected` state without the client noticing. Setting `clientTimeout: Infinity` disables the room's idle timer; hibernating platforms handle keep-alive themselves and would otherwise see the room disconnect perfectly fine clients.
245
+
246
+
For non-hibernating environments (Node servers, long-lived processes), you don't need any of this. The in-memory `TLSocketRoom` outlives individual sockets, and the default `clientTimeout` keeps idle sessions tidy.
247
+
184
248
### Asset storage
185
249
186
250
Tldraw also needs a way to store and retrieve large binary assets like images and videos.
You can define custom asset types by extending [TLBaseAsset](?). Create a validator with[createAssetValidator](?), then implement shapes that reference your custom assets.
291
+
Custom asset types let you store domain-specific media alongside images, videos, and bookmarks. Each asset type has a corresponding [AssetUtil](?) that defines type-specific behavior: which MIME types it accepts, how to derive an asset record from a dropped file, and what default props new instances start with. The built-in `ImageAssetUtil`, `VideoAssetUtil`, and `BookmarkAssetUtil` follow this pattern and live in `defaultAssetUtils`.
292
292
293
-
Custom asset types follow the same storage lifecycle as built-in types. Your upload, resolve, and remove handlers need to support them, and your custom shapes handle the rendering.
293
+
`AssetUtil` is the asset-side counterpart to `ShapeUtil`. You register one util per type on the editor at startup, and the editor calls its methods whenever a file enters the system.
294
+
295
+
Register your asset's props on `TLGlobalAssetPropsMap` via TypeScript module augmentation, then implement an `AssetUtil` for it:
When a file is dropped or pasted, the editor finds the first registered util whose `getSupportedMimeTypes()` includes the file's MIME type and calls its `getAssetFromFile()`. The returned asset record then flows through your `TLAssetStore.upload` handler, which assigns the final `src`. Custom shape utils that render audio (or whatever else you registered) read the resolved URL through `editor.resolveAssetUrl()` like the built-in shapes do.
354
+
355
+
### Configuring built-in asset utils
356
+
357
+
Use [AssetUtil#configure](?) to tweak options on a built-in util without subclassing it. For example, lock image uploads down to PNG:
Copy file name to clipboardExpand all lines: apps/docs/content/sdk-features/clipboard.mdx
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -81,6 +81,12 @@ This embeds images and videos directly in the clipboard data rather than relying
81
81
82
82
Cut combines copy and delete. The editor first copies the selected shapes to the clipboard, then deletes the originals. This order ensures the clipboard has the data before shapes disappear, preventing data loss if the copy fails.
83
83
84
+
### Plain text paste
85
+
86
+
`Cmd+Shift+V` (or `Ctrl+Shift+V` on Windows and Linux) pastes the clipboard as plain text. HTML and rich formatting are stripped. This is the standard "paste without formatting" shortcut. It's handy when styled text from a browser or word processor would otherwise bring its fonts and colors onto the canvas with it.
87
+
88
+
To extend or override this behavior, use the `onClipboardPasteRaw` hook on [TldrawOptions](?). It fires before tldraw parses the clipboard, so you can read the raw `ClipboardEvent` data yourself. Return `false` to short-circuit the default pipeline, or `void` to let it continue.
89
+
84
90
## Content structure
85
91
86
92
The [TLContent](?) type defines the clipboard payload:
Copy file name to clipboardExpand all lines: apps/docs/content/sdk-features/deep-links.mdx
+4-4Lines changed: 4 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -19,7 +19,7 @@ notes: ''
19
19
20
20
Deep links serialize editor state into URL-safe strings. They let users share links that open the editor at specific locations: individual shapes, viewport positions, or entire pages.
21
21
22
-
The simplest way to enable deep links is with the `deepLinks`prop:
22
+
The simplest way to enable deep links is with the `deepLinks`option:
You can also enable this via the `deepLinks`prop on the Tldraw component instead of calling this method directly.
120
+
You can also enable this via the `deepLinks`option on the Tldraw component instead of calling this method directly.
121
121
122
122
## Related examples
123
123
124
-
-**[Deep links](https://github.com/tldraw/tldraw/tree/main/apps/examples/src/examples/configuration/deep-links)** - Demonstrates how to use the `deepLinks`prop to enable URL-based navigation and how to create, parse, and handle deep links manually using the editor methods.
124
+
-**[Deep links](https://github.com/tldraw/tldraw/tree/main/apps/examples/src/examples/configuration/deep-links)** - Demonstrates how to use the `deepLinks`option to enable URL-based navigation and how to create, parse, and handle deep links manually using the editor methods.
|`maxPointsPerShape`|`number`|`600`| Maximum points before starting a new shape. Same behavior as draw shapes. |
227
227
228
-
The highlight's `underlayOpacity` (default `0.82`) and `overlayOpacity` (default `0.35`) are display values that can be overridden via `getCustomDisplayValues`.
228
+
The highlight's `underlayOpacity` (default `0.82`) and `overlayOpacity` (default `0.35`) are display values that can be overridden via `getCustomDisplayValues`:
To build your own container shape that behaves like a frame, extend `BaseFrameLikeShapeUtil` rather than re-implementing every behavior on `FrameShapeUtil`. The base class provides defaults for clipping children, full-brush selection, blocking erasure from inside, and drag-and-drop reparenting — see [Shapes](/sdk-features/shapes#frames) for details and the [portal shapes example](/examples/shapes/tools/portal-shapes) for a working implementation.
429
+
427
430
### Group
428
431
429
432
The group shape logically combines multiple shapes without visual representation. Groups let you move and transform shapes together while preserving their relative positions. The group's geometry is computed as the union of all child shapes' geometries. Groups are created through the editor API rather than directly, and they delete themselves automatically when their last child is removed or ungrouped.
Draw shapes store their path data in an efficient delta-encoded base64 format. The first point uses full Float32 precision (12 bytes), with subsequent points stored as Float16 deltas (6 bytes each).
Copy file name to clipboardExpand all lines: apps/docs/content/sdk-features/embed-shape.mdx
+10-4Lines changed: 10 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -37,6 +37,12 @@ editor.createShape({
37
37
38
38
The embed system recognizes URLs from supported services and converts them to their embeddable equivalents. A YouTube watch URL becomes an embed URL automatically.
39
39
40
+
### Pasting iframe code
41
+
42
+
You can also paste raw `<iframe>` HTML directly onto the canvas to create an embed shape, even when the source URL doesn't match a known provider. tldraw extracts the iframe's `src` attribute and creates an embed pointing at it. If the iframe element is missing `width` and `height`, the embed uses default dimensions instead.
43
+
44
+
This covers services tldraw doesn't know about — OpenStreetMap, SoundCloud, Loom, internal tools — without a custom embed definition. Iframes pasted this way receive a stricter sandbox than the built-in providers (no `allow-same-origin`, no top navigation), since tldraw can't make any safety guarantees about the source.
45
+
40
46
## Supported services
41
47
42
48
| Service | Hostnames | Resizable | Aspect ratio locked |
@@ -58,6 +64,7 @@ The embed system recognizes URLs from supported services and converts them to th
0 commit comments