feat: Clip effects, asset sorting, and timeline improvements

Major features and improvements:

* **Clip Effects**:
  * Added UI in Properties Panel to manage effects on video/image clips (add, remove, toggle, reorder).
  * Implemented dynamic parameter fields for effects.
  * Added support for keyframing effect parameters.

* **Assets Panel**:
  * Added sorting options: Name, Type, Duration, and File Size.
  * Persisted view preferences (grid/list mode, sort order) to local storage.
  * Refactored media item rendering and drag interactions.

* **Timeline & Interaction**:
  * **Keyframe Dragging**: Added ability to drag keyframes directly on the timeline element.
  * **Resizing**: Improved resize logic to respect neighboring clips (prevents overlaps).
  * **Visuals**: Implemented tiled background rendering for video/image clips on the timeline.
  * **Shortcuts**: Added "Deselect All" action bound to the `Escape` key.
  * **Fixes**: Corrected drag-and-drop coordinate calculations when the timeline track area is scrolled.

* **Text Elements**:
  * Refactored text background storage to use an explicit `enabled` flag.
  * Added `V8toV9` storage migration to update existing projects.

* **Architecture**:
  * Moved export state management to `ProjectManager` for better lifecycle handling.
  * Refactored `PropertiesPanel` sections to be more composable (custom headers, borders).
This commit is contained in:
Maze Winther
2026-03-02 13:13:07 +01:00
parent 93bea01c9e
commit e7dcb586c0
66 changed files with 3688 additions and 1333 deletions
@@ -1,4 +1,8 @@
import type { ImageElement, StickerElement, VideoElement } from "@/types/timeline";
import type {
ImageElement,
StickerElement,
VideoElement,
} from "@/types/timeline";
import { BlendingSection, TransformSection } from "./sections";
export function VideoProperties({
@@ -10,7 +14,11 @@ export function VideoProperties({
}) {
return (
<div className="flex h-full flex-col">
<TransformSection element={element} trackId={trackId} />
<TransformSection
element={element}
trackId={trackId}
showTopBorder={false}
/>
<BlendingSection element={element} trackId={trackId} />
</div>
);