tldraw/tldraw
Shapes and tools
Active contributors: Steve Ruiz, Mime Čuvalo, Mitja Bezenšek
Purpose
How a user-visible "shape" actually exists in the codebase: as a record in the store, plus a ShapeUtil that defines how it renders and behaves, plus optionally a StateNode tool that creates and edits it.
The shape pipeline
graph LR
Schema["TLShape record types"] -->|registered| Store
Store -->|provides records| Editor
ShapeUtils["ShapeUtil subclasses"] -->|registered| Editor
Editor -->|render| Component[Shape component]
Editor -->|geometry| Hit[hit-testing, snapping, selection]
Editor -->|export| SVG[SVG export]
User -->|drag| Tool[StateNode tool]
Tool -->|editor.createShape| Editor- Record type — declared in
packages/tlschema/src/shapes/TL<Kind>Shape.ts. Defines props, validators, and migrations. - Shape util —
packages/tldraw/src/lib/shapes/<kind>/<Kind>ShapeUtil.tsxextendsShapeUtil<TLKindShape>frompackages/editor/src/lib/editor/shapes/ShapeUtil.ts. Implementscomponent(),indicator(),getGeometry(), plus optionalonResize,onTranslate,onHandleDrag,toSvg, etc. - Tool —
packages/tldraw/src/lib/tools/<Tool>/<Tool>.tsextendsStateNode. The tool listens for pointer/keyboard, transitions through child states, and callseditor.createShape(...)andeditor.updateShape(...).
Default set
The default shapes (packages/tldraw/src/lib/shapes/):
| Shape | Kind id | Notes |
|---|---|---|
| Arrow | arrow |
Curved/straight lines with binding endpoints. |
| Bookmark | bookmark |
URL preview. |
| Draw | draw |
Pressure-sensitive freehand. |
| Embed | embed |
iframe embeds. |
| Frame | frame |
Container with title and clipping. |
| Geo | geo |
Rect/ellipse/triangle/diamond/star/etc. |
| Highlight | highlight |
Highlighter strokes. |
| Image | image |
Image with crop. |
| Line | line |
Multi-point line. |
| Note | note |
Sticky note. |
| Text | text |
Text label. |
| Video | video |
Video player. |
| Group | group |
(Geometry-only; not a default tool.) |
The default tools (packages/tldraw/src/lib/tools/):
SelectTool— the biggest. Manages selection, translation, resizing, rotation, cropping, brush selection, edit mode, label editing.HandTool— pan camera.EraserTool— erase shapes.LaserTool— temporary laser pointer.ZoomTool— zoom to box / +/-.- Per-shape tools wired in
defaultShapeTools.ts: Draw, Arrow, Note, Text, Highlight, Frame, Geo, Line.
Shared selection logic — translating with snap, brushing, cropping, resizing — lives in packages/tldraw/src/lib/tools/selection-logic/.
Geometry
Every shape returns a Geometry2d from getGeometry(). The geometry library lives in packages/editor/src/lib/primitives/geometry/. It supports point-in-shape tests, segment intersection, bounds, padding, and SVG path output. The SpatialIndexManager indexes shape bounds with rbush so hit-testing is fast even with thousands of shapes.
Bindings
Some shapes have relationships with others. Arrow endpoints can be bound to shapes — when a shape moves, its bound arrows update. Binding records and the BindingUtil API live in packages/tlschema/src/bindings/ and packages/editor/src/lib/editor/bindings/. The default arrow uses a TLArrowBinding.
Custom shapes and tools
Templates demonstrate the pattern:
templates/agent/— AI-driven shapes.templates/shader/— WebGL shaders inside shapes.templates/workflow/— node-based shape graph.
To add a custom shape to your app, define a RecordType (or use customRecordType), implement a ShapeUtil, and pass it via <Tldraw shapeUtils={[MyShapeUtil]} />.
Related
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.