Skip to main content

Overview

The Scene class is the central data structure in Excalidraw that manages all elements in a drawing. It provides a reactive system for element storage, retrieval, mutation, and change tracking, serving as the single source of truth for the canvas state.

Scene Architecture

The Scene maintains multiple internal data structures optimized for different access patterns:
packages/element/src/Scene.ts
The Scene maintains both array and map representations of elements. Arrays preserve ordering, while maps provide O(1) lookup by element ID.

Creating a Scene

packages/element/src/Scene.ts

Element Access

Getting Elements

packages/element/src/Scene.ts

Getting Individual Elements

packages/element/src/Scene.ts

Container Relationships

packages/element/src/Scene.ts

Modifying the Scene

Replacing All Elements

The primary method for updating the scene:
packages/element/src/Scene.ts
replaceAllElements validates fractional indices by default. For bulk updates where indices are already valid, use { skipValidation: true } for better performance.

Mapping Elements

Update elements with a transformation function:
packages/element/src/Scene.ts
mapElements optimizes by only calling replaceAllElements if changes are detected, making it safe to use in reactive contexts.

Inserting Elements

packages/element/src/Scene.ts
Insert methods automatically sync fractional indices using syncMovedIndices to maintain proper ordering.

Mutating Elements

Mutate elements in place while triggering scene updates:
packages/element/src/Scene.ts
Set informMutation: false when:
  • Batching multiple mutations and want a single update at the end
  • Making temporary changes that will be reverted
  • Updating elements that aren’t in the scene (e.g., during element creation)

Selection Management

The Scene caches selected elements for performance:
packages/element/src/Scene.ts
The Scene maintains a sophisticated selection cache:
Cache key includes:
  • selectedElementIds reference
  • elements reference
  • includeBoundTextElement flag
  • includeElementsInFrames flag
Cache invalidation:
  • When selectedElementIds change
  • When scene elements change
  • When selection options change

Change Tracking

Scene Nonce

The Scene generates a random nonce on each update for cache invalidation:
packages/element/src/Scene.ts

Subscribing to Updates

Register callbacks to react to scene changes:
packages/element/src/Scene.ts
Always unsubscribe from scene updates when components unmount to prevent memory leaks.

Manual Update Trigger

packages/element/src/Scene.ts

Fractional Indices

The Scene automatically manages fractional indices for consistent element ordering:
packages/element/src/Scene.ts
Excalidraw uses the fractional indexing algorithm for element ordering:
  • Indices are strings like "a0", "a1", "a0V", etc.
  • Allow inserting between elements without reindexing
  • Critical for collaboration where multiple users insert elements
  • Automatically validated in development/test environments

Scene Lifecycle

packages/element/src/Scene.ts
Always call scene.destroy() when disposing of a Scene instance to prevent memory leaks.

Integration with App Component

The Scene is integrated into the main App component:

Performance Considerations

Scene Data Type

When updating scenes through the API, use the SceneData type:
packages/excalidraw/types.ts

Best Practices

  • Use mapElements for transformations instead of manual array mapping
  • Always prefer map lookups over array iteration for finding elements
  • Use getNonDeletedElements when you only need active elements
  • Call destroy() when disposing of Scene instances
  • Skip validation with { skipValidation: true } when loading trusted data
  • Batch element updates into a single replaceAllElements call
  • Use informMutation: false when batching mutations
  • Cache selection options objects to benefit from selection cache
  • Subscribe to scene updates only when necessary
  • Always unsubscribe in cleanup functions
  • Use scene nonce for cache invalidation in renderers
  • Avoid triggering updates during render cycles
  • Never mutate elements directly without using Scene methods
  • Rely on fractional indices for element ordering
  • Let Scene manage index synchronization automatically
  • Use version and versionNonce for conflict resolution

Common Patterns

Bulk Element Update

Filtering and Replacing

Adding New Elements

Removing Elements