History System (Undo/Redo)
Relevant source files
The following files were used as context for generating this wiki page:
The History System in Rocreate is a tile-based undo/redo mechanism designed for memory efficiency and high performance in a professional painting environment. It tracks changes to the canvas state as efficient deltas or "composed" states, allowing users to traverse through previous actions without excessive memory consumption.
The system is built around a layered architecture: a core history engine that manages the stack of entries, an executor that handles the logic of traversing that stack, and a coordinator that synchronizes these states with the application UI and rendering engine.
Sources: CLAUDE.md:15, src/app/script/klecks/history/kl-history.ts:1-20
Architecture and Components
The History System consists of several interacting classes that separate state management from execution logic.
Core Components Table
| Component | Description | Source |
|---|---|---|
KlHistory | The central state engine. Manages the stack of THistoryEntry objects and calculates memory estimates to enforce limits. | src/app/script/klecks/history/kl-history.ts:24-34 |
KlHistoryExecutor | Logic wrapper that decides whether to perform an undo/redo on the main history or temporary history. | src/app/script/klecks/history/kl-history-executor.ts:17-23 |
HistoryCoordinator | A service that integrates the history system with the broader app services, providing a unified API for UI components. | src/app/script/app/services/history-coordinator.ts:19-27 |
KlTempHistory | Manages transient states that should not be permanently stored in the main history stack (e.g., mid-transformation states). | src/app/script/klecks/history/kl-history-executor.ts:4-5 |
System Relationship Diagram
This diagram illustrates how the various history components interact with the main application controller.
State Management and Memory Constraints
The KlHistory class manages an array of THistoryEntry objects. Because Rocreate handles high-resolution graphics, the system implements strict memory thresholds to prevent browser crashes.
Memory Optimization Logic
The system uses a "tile-based" approach where the canvas is divided into 256x256 tiles to optimize updates. It enforces a total memory limit (defaulting to 1 GB) for all history entries combined. If a new action exceeds this limit, the system "composes" forward the oldest entries, merging them into a single baseline state to free up memory.
Key Configuration Constants:
HISTORY_TILE_SIZE: 256 (pixels)maxUndoSteps: 20 (base limit)totalThresholdBytes: 1,000,000,000 (1 GB)isFreeThresholdBytes: 2048 (size below which an entry doesn't count against the step limit)
Sources: src/app/script/klecks/history/kl-history.ts:13-50
Push and Composition Flow
When a new action is performed, the push method is called. This logic handles replacing the current "top" of the stack if requested (e.g., incremental brush strokes) and prunes entries if memory limits are reached.
Execution Logic (Undo/Redo)
The KlHistoryExecutor manages the actual movement of the history index. It prioritizes KlTempHistory over the main KlHistory. If a temporary state (like a transformation preview) is active, the system will undo/redo within that temporary context first.
Execution types
The system differentiates between four execution types:
undo: Moving back in main history.redo: Moving forward in main history.tempUndo: Moving back in temporary history.tempRedo: Moving forward in temporary history.
Sources: src/app/script/klecks/history/kl-history-executor.ts:6-10
Undo Sequence Diagram
The following diagram shows the sequence of events when a user triggers an undo command.
Integration with KlApp
In KlApp, the history system is deeply integrated with the drawing loop and layer management. Every significant change—such as a layer merge, a filter application, or a brush stroke completion—is pushed to the history.
Pause and Resume
The system includes a pause(boolean) mechanism. This is critical for complex actions that trigger multiple internal state changes (e.g., a filter that adds a temporary layer and then merges it). Pausing prevents the creation of unintended intermediary undo steps.
Sources: src/app/script/klecks/history/kl-history.ts:82-90, src/app/script/app/kl-app.ts:397-410
Listener Pattern
The system uses a broadcast mechanism to notify the UI when the "Undo-able" or "Redo-able" state changes. This allows the Top Bar buttons to enable or disable themselves dynamically based on the current index position in the stack.
Sources: src/app/script/klecks/history/kl-history.ts:58-65, src/app/script/app/services/history-coordinator.ts:95-101
Conclusion
The Rocreate History System provides a robust and memory-aware foundation for non-destructive editing. By combining a main history stack with a temporary stack and enforcing strict memory composition, it ensures that high-performance painting remains stable even during long creative sessions with limited hardware resources.