This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is the tldraw monorepo - an infinite canvas SDK for React applications. It's organized using yarn workspaces with packages for the core editor, UI components, shapes, tools, and supporting infrastructure.
Requires Node ^20.0.0. Enable corepack to ensure correct yarn version:
npm i -g corepack && yarnyarn dev- Start development server for examples app at localhost:5420yarn dev-app- Start tldraw.com client app developmentyarn dev-docs- Start documentation site developmentyarn dev-vscode- Start VSCode extension developmentyarn dev-template <template name>- Runs a template
yarn build- Build all packages (incremental, builds only what changed)yarn build-package- Build SDK packages onlyyarn build-app- Build tldraw.com client appyarn build-docs- Build documentation site
yarn testin a workspace - Run tests in watch mode (cd to workspace first)yarn test runin a workspace - Run tests once without watch modeyarn test run --grep "pattern"- Run matching tests in a workspaceyarn vitest- Run all tests across repo (slow, avoid unless necessary)yarn e2e- Run end-to-end tests for examplesyarn e2e-dotcom- Run end-to-end tests for tldraw.com
yarn lint- Lint packageyarn lint-current- Lint only changed files (faster)yarn typecheck- Type check all packages (run from repo root; also runsrefresh-assets)yarn format- Format code with Prettieryarn format-current- Format only changed files (faster)yarn api-check- Validate public API consistency
IMPORTANT: NEVER run bare tsc - always use yarn typecheck.
If the typecheck command is not found, you're not running it from the repo root.
@tldraw/editor - Foundational infinite canvas editor
- No shapes, tools, or UI - just the core engine
- State management using reactive signals (@tldraw/state)
- Shape system via ShapeUtil, Tools via StateNode
- Bindings system for shape relationships
@tldraw/tldraw - Complete "batteries included" SDK
- Builds on editor with full UI, shapes, and tools
- Default shape utilities (text, draw, geo, arrow, etc.)
- Complete tool set (select, hand, eraser, etc.)
- Responsive UI system with customizable components
@tldraw/store - Reactive client-side database
- Document persistence with IndexedDB
- Reactive updates using signals
- Migration system for schema changes
@tldraw/tlschema - Type definitions and validators
- Shape, binding, and record type definitions
- Validation schemas and migrations
- Shared data structures
Reactive state management
- Uses @tldraw/state for reactive signals (Atom, Computed)
- All editor state is reactive and observable
- Automatic dependency tracking prevents unnecessary re-renders
Shape system
- Each shape type has a ShapeUtil class defining behavior
- ShapeUtil handles geometry, rendering, interactions
- Extensible - custom shapes via new ShapeUtil implementations
Tools as state machines
- Tools implemented as StateNode hierarchies
- Event-driven with pointer, keyboard, tick handlers
- Complex tools have child states (e.g., SelectTool has Brushing, Translating, etc.)
Bindings system
- Relationships between shapes (arrows to shapes, etc.)
- BindingUtil classes define binding behavior
- Automatic updates when connected shapes change
- Unit tests:
packages/<workspace>/src/**/*.test.ts(alongside source or insrc/test/) - E2E tests:
apps/examples/e2e/andapps/dotcom/client/e2e/ - Test in
packages/tldrawif you need default shapes/tools - Run from workspace:
cd packages/tldraw && yarn test run --grep "pattern"
See .claude/skills/write-unit-tests/ and .claude/skills/write-e2e-tests/ for detailed patterns.
apps/
├── examples/ # SDK examples and demos
├── docs/ # Documentation site (tldraw.dev)
├── dotcom/ # tldraw.com application
│ ├── client/ # Frontend React app
│ ├── sync-worker/ # Multiplayer backend
│ └── asset-upload-worker/
└── vscode/ # VSCode extension
packages/
├── editor/ # Core editor engine
├── tldraw/ # Complete SDK with UI
├── store/ # Reactive database
├── tlschema/ # Type definitions
├── state/ # Reactive signals library
├── sync/ # Multiplayer SDK
├── utils/ # Shared utilities
├── validate/ # Lightweight validation library
├── assets/ # Icons, fonts, translations
└── create-tldraw/ # npm create tldraw CLI
templates/ # Starter templates for different frameworks
Uses lazyrepo for incremental builds with caching:
yarn buildbuilds only what changed- Workspace dependencies handled automatically
- Caching based on file inputs/outputs
- Parallel execution where possible
TypeScript
- Uses workspace references for fast incremental compilation
- Run
yarn typecheckbefore commits - API surface validated with Microsoft API Extractor
Monorepo management
- Yarn workspaces with berry (yarn 4.x)
- Use
yarnnotnpm- packageManager field enforces this - Dependencies managed at workspace level where possible
Asset management
- Icons, fonts, translations in
/assets(managed centrally) - Run
yarn refresh-assetsafter asset changes - Assets bundled into packages during build
- Automatic optimization and deduplication
Example development
- Main development happens in
apps/examples - Examples showcase SDK capabilities
- See
apps/examples/writing-examples.mdfor guidelines
Sentence case for titles and headings
- Always use sentence case for titles, headings, and labels (NOT Title Case)
- Examples:
- ✅ "Database configuration"
- ❌ "Database Configuration"
- ✅ "Real-time updates"
- ❌ "Real-Time Updates"
- ✅ "Custom shapes"
- ❌ "Custom Shapes"
- Exception: Proper nouns, acronyms, and class/component names remain capitalized
- ✅ "PostgreSQL database"
- ✅ "WebSocket connections"
- ✅ "NodeShapeUtil implementation"
- This applies to:
- Markdown headers (##, ###, etc.)
- Bold labels in lists (Label:)
- Documentation titles
- Code comments describing features
- Do what has been asked; nothing more, nothing less.
- NEVER create files unless they're absolutely necessary for achieving your goal.
- ALWAYS prefer editing an existing file to creating a new one.
- NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.