Skip to main content
OpenCut implements a robust undo/redo system using the command pattern. Every modifying operation is wrapped in a command that can be executed, undone, and redone.

Why commands?

The command pattern provides:

Undo/redo support

Every operation can be reversed and re-applied.

State encapsulation

Commands save necessary state for reversal.

Batch operations

Multiple commands can be executed as a single undoable unit.

History tracking

Complete history of all operations for debugging and analysis.

Command interface

All commands extend the base Command class:
apps/web/src/lib/commands/base-command.ts

CommandManager API

The CommandManager handles command execution and history:
apps/web/src/core/managers/commands.ts

Using commands

Basic usage

Through manager methods

Most operations are wrapped by manager methods:
Under the hood, timeline.splitElements() does:
apps/web/src/core/managers/timeline-manager.ts

Creating a command

Here’s a complete example of implementing a command:

Batch commands

Combine multiple commands into a single undoable operation:
apps/web/src/lib/commands/batch-command.ts

Using batch commands

Command organization

Commands are organized by domain in the codebase:

Execute vs push

The CommandManager has two methods for adding commands to history:
Use when the command hasn’t been executed yet:
This is the most common case.

Preview operations

Some operations support a preview mode before committing:

Command best practices

Save minimal state

Only save the state necessary to undo. Don’t save the entire editor state.

Immutable operations

Use immutable updates. Don’t mutate saved state directly.

Use batch for groups

Combine related operations into a BatchCommand for single undo.

Test undo/redo

Always test that undo properly reverses the operation.

Relationship with actions

Actions and commands work together:
Actions are “what triggered this” (user intent), while commands are “how to do it and undo it” (implementation).
  • EditorCore - The CommandManager is accessed via EditorCore
  • Actions - Actions trigger commands for user operations
  • Timeline - Timeline operations are implemented as commands
  • Scenes - Scene operations are implemented as commands