v2.4.0

View on GitHub

Welcome to the 2.4.0 release of the tldraw SDK. This month we’ve been working to bring our sync engine (the backend we developed for tldraw.com) into the SDK as a technology for general use. This release also includes new animation options for shapes, support for image flipping, and a long list of bug fixes and developer experience enhancements. Read on for the highlights and see the bottom of these notes for the list of significant fixes and changes.

Thank you also to our first-time contributors Albert Brand (@AlbertBrand) and Guillaume Grossetie (@ggrossetie)!

What's new

Sync

For the first time, we’re releasing our real-time collaboration engine—the one we developed for tldraw.com—as a general library that developers can use for their own projects. The SDK will of course still support any backend for collaboration, however we hope this will be the best and easiest for developers to use alongside the rest of the tldraw SDK. While we’re shipping the code in this release, we still have some work to do on our messaging and our documentation, so keep an eye out for an announcement in the coming weeks. For now, see the new sync package in the repository and the new multiplayer-demo example in the tldraw repository.

Interpolation

Did you know that tldraw has basic support for animation? You can use the Editor.animateShapes method to animate shapes on the canvas, but up to now only the position and rotation properties would be animated. In this release, we’ve given the ShapeUtil class a new getInterpolatedProps method. You can use this to describe how your custom shape’s other properties should be animated. We’ve only started to implement this feature for our own shapes, but check our BaseBoxShapeUtil as an example.

override getInterpolatedProps(startShape: Shape, endShape: Shape, t: number): Shape['props'] {
	return {
		...endShape.props,
		w: lerp(startShape.props.w, endShape.props.w, t),
		h: lerp(startShape.props.h, endShape.props.h, t),
	}
}
Editor.run

You can use the new Editor.run method to run a function within some additional context. By default, the function will be run inside of a transaction, meaning that all changes made during the transaction will be settled at once. This improves performance and avoids unnecessary renders in the user interface. You can also use Editor.run’s contextual options to ignore history or ignore locked shapes.

editor.run(
	() => {
		editor.createShapes(myShapes)
		editor.sendToBack(myShapes)
		editor.selectNone()
	},
	{ history: 'ignore' }
)
Assets

As part of our work on sync, we have a new system for handling large assets like images and videos. You can provide a TLAssetStore to control how assets are uploaded and retrieved.

In your own shapes & tools, these options are available through the new Editor.uploadAsset and Editor.resolveAssetURL methods.


Breaking changes

  • editor.history.ignore(cb) has been replaced with editor.run(cb, {history: ‘ignore’})
  • editor.batch is deprecated, replaced with editor.run
  • If you’re importing from @tldraw/state directly, the track function and all hooks (e.g. useValue) have moved to @tldraw/state-react.

Improvements

  • Images now support horizontal and vertical flipping. (#4113)
  • Custom tools can now decide whether or not they are affected by shape lock. #4208
  • We now serve our icons as a single SVG rather than many individual requests. (#4150)
  • Paste at point behavior is now based on a user preference. (#4104)
  • We now show a toast when uploading an unsupported file type or a file that is too large. (#4114)
  • We now show a toast when pasting failed due to missing clipboard permissions. (#4117)
  • You can use the new ShapeIndicators component to add custom logic about when to display indicators. (#4083)
  • A shape’s opacity will now also animate. (#4242)

API changes

  • The @tldraw/state library is now split into @tldraw/state and @tldraw/state-react. (#4170)
  • We now export the DefaultMenuPanel. (#4193)
  • The fileSize property of TLImageAsset and TLVideoAsset is now optional. (#4206)
  • You can now pass a partial TLEditorSnapshot to TldrawImage and useTLStore. (#4190)
  • We explicitly type our defaults for better documentation. (#4191)
  • EffectScheduler and useStateTracking are now public. (#4155)]
  • Add setDefaultValue to StyleProp. (#4044)
  • Add ShapeUtil.getInterpolatedProps. (#4162)
  • Add Editor.run, replacing Editor.batch (#4042)

Bug fixes

  • The font style is now correctly exported as SVG. (#4195)
  • The force flag is now taken into account for additional camera methods. (#4214)
  • The user's color scheme is shown in the menu by default. (#4184)
  • The padding for text shapes is now correct for dynamically scaled text shapes. (#4140)
  • Changing cameraOptions via react no longer causes the editor to re-mount. (#4089)
  • High-res images may now be uploaded. (#4198)
  • Locked shapes can no longer be updated, grouped, and ungrouped programmatically. (#4042)
  • The snapshots prop is now used by createTLStore. (#4233
  • Grid backgrounds work properly with multiple tldraw instances. (#4132)
  • The offline icon is back! (#4127)
  • Inputs stay in the right place while viewport-following. (#4108)
  • Bookmarks render correctly across devices. (#4118)
  • The InFrontOfTheCanvas component is displayed at the right stack-order. (#4024)
  • Frame headers stop editing correctly when they lose focus. (#4092)
  • The distance offset for duplicated shapes now matches other duplication distance offsets. (#4056)
  • Filled draw shapes work close with correct distance when dynamic sized. (#3974)
  • Remove an artificial delay in showing an image. (#4058)
  • The context menu no longer displays an empty edit menu. (#4037)
  • Right-clicking the selected shape no longer selects its children. (#4034)

Authors

Prev
v3.0.0
Next
v2.3.0