State management
Klippy uses Redux Toolkit for predictable state, with purpose‑built slices, memoized selectors, and a layered middleware pipeline for performance (debounced duration updates, validation, and unified history tracking).
1) Store overview
- Store file:
app/store/index.ts— configures reducers and middleware. - Slices:
projectState: media/text/zoom, captions, transitions, export settings, recording, project meta, history.timeline: currentTime, play state, zoom, snapping, scroll.selection: selected element IDs and related UI state.transcripts: transcripts per media, panel prefs.edits: remove/mute/silence ranges with dedicated undo/redo.theme,ffmpeg,aiComponents,preferences,secureApi,audioEffects,projects.
- Selectors: under
app/store/selectors/*with Reselect memoization (seetimelineSelectors.ts). - Persistence: Projects/files in IndexedDB via
storageManager; state snapshots for undo/redo in memory.
2) Key slices
projectState
- Holds timeline content:
mediaFiles,textElements,zoomElements, caption tracks. - Derived durations recalculated when content changes (
calculateDurationshelper). - Transitions map (
betweenClipTransitions) and IDs. - Recording settings/state and TTS state.
- History arrays (
history/future) for project‑level undo/redo.
timeline
- Playback (
currentTime,isPlaying), timeline zoom, snapping flags. - Scroll positions and hover times for synchronized headers/markers.
edits
- Remove/mute/silence ranges with local undo/redo (
undoEdits/redoEdits). - Preview lane and focused range for quick operations.
transcripts
- Transcript text and timings per media ID.
- Panel preferences (virtualization, snap to phrases, merge thresholds).
3) Middleware pipeline
- StateUpdateQueue: Orders batched changes to minimize intermediate re‑renders.
- DurationMiddleware: Debounced recompute of content/timeline durations after edits.
- Validation: Guards invariant violations (e.g., element times, track bounds).
- UnifiedHistory + CombinedUndoRedo: Consolidates meaningful actions into a single history entry and mirrors edits slice undo/redo with project undo/redo where applicable.
See app/store/index.ts for the exact order and comments.
4) Undo and redo
- Project‑level undo/redo:
projectState.history/futurewith helpers likerecordHistory,undo,redo. - Edits‑level undo/redo: independent stacks in
editsslice for transcript‑driven ranges. - Middleware ensures both stacks remain consistent when cross‑slice actions occur.
5) Selectors
Heavy timeline UIs rely on memoized selectors from app/store/selectors/timelineSelectors.ts to avoid recomputation. Examples:
selectVisibleMediaFiles— windowing bycurrentTimeand rows.selectContentDuration— derives from media + text + audio.selectSelectedElements— resolves models from selected IDs.selectZoomLevel,selectCurrentTime,selectIsPlaying— high‑frequency reads.
6) Persistence & file storage
- Files and projects are stored in IndexedDB using a high‑level
storageManager. - Utility functions in
app/store/index.tsexposestoreFile,getFile,listProjects, etc. - Blob URLs created for preview are cleaned up by the components that own them.
7) Patterns for performance
- Prefer slice actions that update arrays immutably but compactly (e.g.,
setMediaFilesbatches duration recompute). - Use Reselect selectors in timeline rendering to avoid O(n) passes on every mouse move.
- Use
runInBatch(where applicable) to group multi‑dispatch operations into a single history entry. - Virtualize large lists (timeline rows, transcript words) and reduce overscan on low‑RAM/mobile.
8) Where to look in code
- Store:
app/store/index.ts - Project slice:
app/store/slices/projectSlice.ts - Timeline slice:
app/store/slices/timelineSlice.ts - Edits slice:
app/store/slices/editsSlice.ts - Transcripts slice:
app/store/slices/transcriptsSlice.ts - Selectors:
app/store/selectors/timelineSelectors.ts - History middlewares:
app/store/middleware/*