tldraw/tldraw
@tldraw/tlschema
Active contributors: Steve Ruiz, Mime Čuvalo, David Sheldrick, Mitja Bezenšek
Purpose
@tldraw/tlschema defines the record types that make up a tldraw document, plus their validators and migrations. Where @tldraw/store is the engine, @tldraw/tlschema is the data model. Every shape, binding, asset, page, and presence record originates here.
Directory layout
packages/tlschema/
├── package.json
└── src/
├── index.ts
├── createTLSchema.ts # the schema factory (15 KB)
├── createPresenceStateDerivation.ts
├── store-migrations.ts # store-level migrations
├── recordsWithProps.ts # union helper
├── util-types.ts
├── records/ # one file per top-level record kind
│ ├── TLShape.ts # 16 KB
│ ├── TLBinding.ts # 12 KB
│ ├── TLAsset.ts
│ ├── TLDocument.ts
│ ├── TLPage.ts
│ ├── TLPageState.ts
│ ├── TLInstance.ts # 17 KB
│ ├── TLPresence.ts
│ ├── TLPointer.ts
│ ├── TLCamera.ts
│ ├── TLUser.ts
│ ├── TLRecord.ts # union
│ └── TLCustomRecord.ts
├── shapes/ # per-shape shape records (TLArrowShape, TLDrawShape, …)
├── bindings/ # per-binding records
├── styles/ # StyleProp definitions (color, dash, fill, font, size)
├── translations/
├── assets/ # asset record types
├── misc/ # handles, geometry types
└── migrations.test.ts # 66 KB of migration testsKey record types
| Record | File | Description |
|---|---|---|
TLDocument |
records/TLDocument.ts |
Document singleton (document:document). |
TLPage |
records/TLPage.ts |
Page within a document. |
TLShape |
records/TLShape.ts |
Union of all concrete shape records. |
TLBinding |
records/TLBinding.ts |
Relationship between two shapes (e.g., arrow bound to shape). |
TLAsset |
records/TLAsset.ts |
Image/video/bookmark asset. |
TLInstance |
records/TLInstance.ts |
Per-instance editor state (current page, current tool, theme). |
TLInstancePageState |
records/TLPageState.ts |
Per-instance per-page selection/hover state. |
TLInstancePresence |
records/TLPresence.ts |
Multiplayer presence (cursor, selection). |
TLPointer |
records/TLPointer.ts |
Local pointer state. |
TLCamera |
records/TLCamera.ts |
Per-instance per-page camera. |
TLUser |
records/TLUser.ts |
User-level state (theme preference). |
Concrete shape records
Under packages/tlschema/src/shapes/:
| File | Shape kind |
|---|---|
TLBaseShape.ts |
Base type. |
TLArrowShape.ts |
Arrows. |
TLDrawShape.ts |
Freehand draw. |
TLGeoShape.ts |
Geometric primitives (rect, ellipse, …). |
TLLineShape.ts |
Multi-point line. |
TLNoteShape.ts |
Sticky note. |
TLTextShape.ts |
Text label. |
TLImageShape.ts |
Image. |
TLVideoShape.ts |
Video. |
TLBookmarkShape.ts |
Bookmark card. |
TLEmbedShape.ts |
Iframe embed. |
TLFrameShape.ts |
Frame container. |
TLHighlightShape.ts |
Highlighter. |
TLGroupShape.ts |
Group. |
ShapeWithCrop.ts |
Crop helper type used by image/video. |
How it works
graph LR
Schema["createTLSchema()"] -->|registers| RecordTypes
Schema -->|registers| Migrations
Schema -->|registers| Validators
RecordTypes --> Store["new Store({ schema })"]
Validators --> Store
Migrations --> StorecreateTLSchema() returns a StoreSchema that the editor passes to new Store(...). The schema knows how to validate every record, migrate older versions on load, and serialize for snapshots.
Style props
packages/tlschema/src/styles/ defines StyleProp instances — color, dash, fill, font, size. These are shared across shapes (a draw stroke and a geo shape both use the same color style prop), and the UI's style panel reads them generically. The list of style props in use determines what shows up in the panel.
Migrations
Every schema change ships a migration:
- Record-level migration — declared inside the record's file via
defineMigrations({ ... }). - Store-level migration — declared in
store-migrations.tsfor changes that span records (introducing a new record type, restructuring relationships). - Migration tests in
migrations.test.tssnapshot the up/down behavior.
Integration points
- Imports.
@tldraw/store(RecordType, StoreSchema),@tldraw/utils,@tldraw/validate. - Importers.
@tldraw/editorre-exports the entire schema. The dotcom client uses it for parsing.tldrsnapshots;@tldraw/sync-coreuses it to validate inbound records over the wire.
Entry points for modification
- New shape kind? Add
TLNewShape.tsundershapes/, register increateTLSchema.ts(or via the shape util intldraw), add a migration test. - New prop on an existing shape? Add it to the shape's record file and write a migration that backfills a default value.
- New binding kind? Mirror the pattern under
bindings/.
Related
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.