From c555f1eaebff90749bdc543592cfa80a060b29e2 Mon Sep 17 00:00:00 2001 From: cashmere Date: Sun, 9 Aug 2026 02:37:37 +0200 Subject: feat: lens effects tab, standalone motion effects, clip/asset rename, preview popout - New Lens category in the assets panel: Blur, Motion Blur, Zoom In/Out, Pan x4, Shake, Pulse, Spin, Custom Zoom. EffectDefinition gains a category field; tabs with an empty category are hidden, and the properties-panel 'Open effects' button opens the first non-empty one. - Motion effects work standalone: dropping them on the timeline creates an effect-track element that animates (scale/translate/rotate) every track below it, computed purely in the TS frame descriptor - no wasm changes, identical in preview and export. supportsStandalone removed. - Motion Blur: directional gaussian smear (amount + angle) reusing the existing WGSL shader with arbitrary u_direction. - Custom Zoom: start/end scale params (keyframable clip-level). - MotionOffset gains optional rotate, accumulated clip-level and applied to standalone layer quads via rotationDegrees. - Rename clips (timeline context menu) and media assets (media panel context menu) via a shared RenameDialog; asset rename persists through storageService with rollback on error. - Preview pops out into a Document Picture-in-Picture window and docks back; button hidden where the API is unsupported. - Export keeps running when the export popover is closed; only the explicit Cancel button aborts. - Captions and Adjustment tabs removed from the assets panel. --- apps/web/src/app/editor/page.tsx | 43 ++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) (limited to 'apps/web/src/app/editor') diff --git a/apps/web/src/app/editor/page.tsx b/apps/web/src/app/editor/page.tsx index 8229774a..5719be94 100644 --- a/apps/web/src/app/editor/page.tsx +++ b/apps/web/src/app/editor/page.tsx @@ -17,7 +17,8 @@ import { MigrationDialog } from "@/project/components/migration-dialog"; import { usePanelStore } from "@/editor/panel-store"; import { usePasteMedia } from "@/media/use-paste-media"; import { MobileGate } from "@/components/editor/mobile-gate"; -import { Suspense, useMemo, useState } from "react"; +import { Suspense, useEffect, useMemo, useState } from "react"; +import { createPortal } from "react-dom"; import { useEditor } from "@/editor/use-editor"; import { Cancel01Icon } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/react"; @@ -29,6 +30,7 @@ import { mergePreviewOverlaySources, } from "@/preview/overlays"; import { usePreviewStore } from "@/preview/preview-store"; +import { usePreviewPopoutStore } from "@/preview/popout-store"; import { getGuidePreviewOverlaySource } from "@/guides"; import { bookmarkNotesPreviewOverlay, @@ -98,6 +100,14 @@ function EditorLayout() { const setOverlayVisibility = usePreviewStore( (state) => state.setOverlayVisibility, ); + const popoutContainer = usePreviewPopoutStore((state) => state.container); + const dockPopout = usePreviewPopoutStore((state) => state.dockPopout); + + useEffect(() => { + return () => { + usePreviewPopoutStore.getState().dockPopout(); + }; + }, []); const showBookmarkNotes = isPreviewOverlayVisible({ overlay: bookmarkNotesPreviewOverlay, overlays, @@ -182,11 +192,32 @@ function EditorLayout() { minSize={30} className="min-h-0 min-w-0 flex-1" > - + {popoutContainer ? ( + <> + {createPortal( + , + popoutContainer, + )} +
+ + Preview is popped out + + +
+ + ) : ( + + )} -- cgit v1.3.1