A visual statechart editor combining tldraw’s infinite canvas with XState v5’s state machine runtime. The goal: bidirectional editing between visual diagrams, text notation, and executable state machines.

Current Status

Phase 1 MVP complete. The core interaction loop works: visual state nodes → XState machine → events → state changes → visual feedback. Single-user, no collaborative sync yet.

Demo shows a traffic light state machine (Red → Green → Yellow → Red). Click any state to advance the machine.

Architecture

Stack:

  • Canvas: tldraw v2 with custom StateNodeShape
  • State Runtime: XState v5 with setup() pattern
  • Integration: React hooks (useActor) for reactive updates
  • Testing: Vitest + jsdom (7 tests passing)

Data Flow:

User clicks canvas shape

Send XState event (NEXT)

XState actor updates state

React hook subscribes to state change

Update tldraw shape props (isActive)

Visual feedback renders

Key Discoveries

Phase 1 revealed critical integration patterns not documented elsewhere:

tldraw Custom Shape Contract

Required methods: getGeometry(), component(), getDefaultProps(), indicator(). Shapes render via HTMLContainer (React components in HTML), not raw SVG. Type system must extend TLBaseShape<'shape-type', PropsInterface>.

XState v5 + React Integration

Create and start actor at module scope (singleton). useActor(actor) returns [snapshot, send] for subscription. Critical: actors MUST be started before component mount.

tldraw Editor Lifecycle

Use useRef<Editor | null> + onMount callback. Shape creation must happen in onMount or after editor available. Event handling: attach listeners to container DOM element, return cleanup function.

Roadmap

Why This Exists

Existing statechart tools are either:

  • Text-only (XState visualizer) — no spatial reasoning
  • Visual-only (draw.io, Miro) — not executable
  • Full IDEs (Stately) — heavy, opinionated

This playground sits in between: a sketch-first tool that produces executable state machines. Inspired by sketch.systems.

Open Questions

  • How to handle hierarchical/composite states visually?
  • Best tree-diffing algorithm for bidirectional sync?
  • Performance with 1000+ state nodes?