Undo and Redo

Klippy provides fast, reliable history across the editor. Project‑level changes (media/text/zoom/props, captions, transitions, settings) go into a unified history stack; transcript‑driven range edits have an additional local stack. Most multi‑step operations are batched into a single, semantic entry (e.g., “Added 6 files”).

1) Keyboard & UI

  • Undo: Ctrl/Cmd+Z
  • Redo: Ctrl/Cmd+Shift+Z (or Ctrl/Cmd+Y)

2) Project‑level history

  • Stack fields: projectState.history and projectState.future.
  • Actions: recordHistory, undo, redo, clearHistory.
  • When content changes (e.g., setMediaFiles, setTextElements), durations are recomputed and a history entry is recorded.
  • Transitions, captions, canvas size, export settings, recording state are included in snapshots.

3) Edits‑level history

  • Slice: edits stores remove/mute/silence ranges.
  • Local undo/redo: undoEdits and redoEdits manage its own history/future.
  • Preview lane ranges are kept in edits and mirrored to the timeline preview controls.

4) Unified history middleware

The store wires middlewares in a specific order (app/store/index.ts):

  1. StateUpdateQueue — groups related updates before observers run.
  2. DurationMiddleware — debounced recompute after content changes.
  3. Validation — ensures invariants for time ranges/rows.
  4. UnifiedHistory — attaches a single meaningful history entry per logical action.
  5. CombinedUndoRedo — mirrors edits slice undo/redo when project undo/redo is invoked, keeping both stacks consistent.

5) Semantic batching

For flows that touch many items (import, bulk caption updates, transcript suggestions), we use runInBatch(dispatch, fn, description) so the user sees a single concise entry in history.

  • Examples: stock media adds, global drops, transcript suggestion preview/apply, caption generate/import.
  • Inside a batch, child actions set meta.skipHistory: true; the batch writes one final entry with a clear description.
  • Guidelines documented in docs/HISTORY_AND_BATCHING.md.

6) What’s not tracked

  • Ephemeral/UI‑only actions (playhead moves, selection, zoom changes) are excluded from history.
  • These are filtered by NON_HISTORY_ACTIONS in the history middleware.

7) Tips

  • Use batching for multi‑dispatch flows to avoid spamming the history panel.
  • Provide descriptive labels (e.g., “Inserted 3 media items”, “Applied transcript edits”).
  • Prefer selectors for derived values when building undoable UI, to keep snapshots small.