State Management
Relevant source files
The following files were used as context for generating this wiki page:
State management in DOTORIXEL is built on a hierarchical architecture using Svelte 5 runes ($state, $derived, $effect) to provide reactive data flow across the editor. The system is designed to support multi-tab workflows by separating global editor preferences (shared state) from document-specific data (instance state).
The architecture centers around a Workspace that orchestrates multiple EditorState instances. Each EditorState manages a specific canvas, its history, and viewport, while referencing a common SharedState for tools and colors. This ensures that when a user switches tabs, their selected tool and palette remain consistent while the canvas content and undo history remain isolated.
Sources: issues/002-tab-system.md:43-58, src/lib/canvas/workspace.svelte.ts
Core Architecture
The state hierarchy follows a top-down approach where a single Workspace acts as the root container for the entire editing session.
State Hierarchy Diagram
The following diagram illustrates the relationship between the Workspace, Shared State, and individual Editor instances.
Component Summary
| Component | Responsibility | Scope |
|---|---|---|
| Workspace | Manages the list of open tabs, tracks the active tab, and handles tab lifecycle (add/close). | Session-wide |
| SharedState | Holds state shared across all tabs: active tool, foreground/background colors, and recent colors. | Session-wide |
| EditorState | Manages document-specific state: pixel data (WasmPixelCanvas), undo history, and viewport transforms. | Per-tab |
| CanvasInteraction | A state machine managing transient input states like drawing, panning, or pinching. | Per-view |
Sources: issues/002-tab-system.md:43-58, src/lib/canvas/canvas-interaction.svelte.ts:1-20
Workspace Management
The Workspace class provides the high-level API for multi-tab management. It ensures that at least one tab is always open and manages a monotonically increasing counter for default tab naming (e.g., "Untitled 1", "Untitled 2").
Key Methods
addTab(options): Instantiates a newEditorState. It automatically assigns a sequential name and sets the new tab as active.closeTab(index): Removes an editor from the tabs array. If the active tab is closed, it implements logic to activate the neighbor (right neighbor preferred, left if at the end).setActiveTab(index): Updates theactiveTabIndexpointer.
Sources: src/lib/canvas/workspace.svelte.ts:40-100, issues/004-workspace-class.md:16-25
Editor & Shared State
The EditorState class encapsulates the logic for a single canvas. It delegates shared properties (like activeTool) to a SharedState reference while maintaining its own reactive properties for document-specific needs.
Data Flow: Shared vs. Independent State
EditorState uses Svelte getters and setters to bridge access to SharedState. This preserves the reactivity chain; when activeTool is updated in one EditorState, all other instances sharing the same SharedState reflect the change immediately.
Sources: src/lib/canvas/editor-state.svelte.ts:50-80, issues/003-shared-state-extraction.md:12-25
Configuration Parameters
The EditorState and SharedState are initialized with the following parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
width | number | 16 | Initial canvas width. |
height | number | 16 | Initial canvas height. |
activeTool | ToolType | 'pencil' | The currently selected tool. |
foregroundColor | Color | #000000 | The primary drawing color. |
backgroundColor | Color | #FFFFFF | The secondary drawing color. |
Sources: src/lib/canvas/editor-state.svelte.ts:20-45, src/lib/canvas/shared-state.svelte.ts:15-30
Interaction State Machine
The CanvasInteraction module extracts complex pointer logic from UI components into a testable state machine. It manages transitions between different interaction modes based on user input (mouse, touch, or keyboard modifiers).
Interaction States
- idle: Default state; no active input.
- drawing: Triggered by a primary pointer down on the canvas.
- panning: Triggered by middle-click or Space + primary pointer move.
- pinching: Triggered by multi-touch gestures for zooming/rotating.
State Transition Logic
The state machine processes standard pointer events and calculates if the user intended to draw, pan, or zoom.
Session Persistence
DOTORIXEL implements an automatic session persistence system using IndexedDB. This system ensures that the Workspace state and all associated EditorState documents are saved across page refreshes.
Persistence Flow
- Dirty Tracking: The system monitors changes to pixels, workspace structure (tabs), or shared state.
- Debounced Save: Changes trigger a debounced save operation (typically 3-5 seconds) to IndexedDB.
- Safety Flush: Immediate saves are triggered on
beforeunloadorvisibilitychangeevents. - Restoration: On page load, the system attempts to reconstruct the
WorkspaceandEditorStateinstances from the stored binary pixel data and metadata.
Sources: issues/007-session-persistence.md:25-60
State management in DOTORIXEL provides a scalable foundation for a multi-tab pixel art editor by combining centralized shared logic with isolated document states, all while leveraging the high-performance reactivity of Svelte 5.