From 8f31bde518e657f3d6f1b254efc43c3b122f7ba5 Mon Sep 17 00:00:00 2001 From: Siddharth Date: Fri, 28 Nov 2025 16:08:11 -0700 Subject: [PATCH] motion-blue switch --- src/components/video-editor/SettingsPanel.tsx | 18 +++++++++++++++++- src/components/video-editor/VideoEditor.tsx | 7 ++++++- src/components/video-editor/VideoPlayback.tsx | 9 +++++++++ .../video-editor/videoPlayback/layoutUtils.ts | 1 - .../videoPlayback/zoomTransform.ts | 4 +++- src/lib/exporter/frameRenderer.ts | 4 +++- src/lib/exporter/videoExporter.ts | 3 +++ 7 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/components/video-editor/SettingsPanel.tsx b/src/components/video-editor/SettingsPanel.tsx index c881d48..31f96b9 100644 --- a/src/components/video-editor/SettingsPanel.tsx +++ b/src/components/video-editor/SettingsPanel.tsx @@ -55,6 +55,8 @@ interface SettingsPanelProps { onShadowChange?: (intensity: number) => void; showBlur?: boolean; onBlurChange?: (showBlur: boolean) => void; + motionBlurEnabled?: boolean; + onMotionBlurChange?: (enabled: boolean) => void; cropRegion?: CropRegion; onCropChange?: (region: CropRegion) => void; videoElement?: HTMLVideoElement | null; @@ -72,7 +74,7 @@ const ZOOM_DEPTH_OPTIONS: Array<{ depth: ZoomDepth; label: string }> = [ { depth: 6, label: "5×" }, ]; -export function SettingsPanel({ selected, onWallpaperChange, selectedZoomDepth, onZoomDepthChange, selectedZoomId, onZoomDelete, shadowIntensity = 0, onShadowChange, showBlur, onBlurChange, cropRegion, onCropChange, videoElement, onExport }: SettingsPanelProps) { +export function SettingsPanel({ selected, onWallpaperChange, selectedZoomDepth, onZoomDepthChange, selectedZoomId, onZoomDelete, shadowIntensity = 0, onShadowChange, showBlur, onBlurChange, motionBlurEnabled = true, onMotionBlurChange, cropRegion, onCropChange, videoElement, onExport }: SettingsPanelProps) { const [wallpaperPaths, setWallpaperPaths] = useState([]); const [customImages, setCustomImages] = useState([]); const fileInputRef = useRef(null); @@ -230,6 +232,20 @@ export function SettingsPanel({ selected, onWallpaperChange, selectedZoomDepth, +
+
+ {/* Motion Blur Switch */} +
+
Motion Blur
+ +
+
+
+
{/* Right section: settings panel */} - z.id === selectedZoomId)?.depth : null} @@ -451,6 +454,8 @@ export default function VideoEditor() { onShadowChange={setShadowIntensity} showBlur={showBlur} onBlurChange={setShowBlur} + motionBlurEnabled={motionBlurEnabled} + onMotionBlurChange={setMotionBlurEnabled} cropRegion={cropRegion} onCropChange={setCropRegion} videoElement={videoPlaybackRef.current?.video || null} diff --git a/src/components/video-editor/VideoPlayback.tsx b/src/components/video-editor/VideoPlayback.tsx index 197acb6..6a7ae69 100644 --- a/src/components/video-editor/VideoPlayback.tsx +++ b/src/components/video-editor/VideoPlayback.tsx @@ -27,6 +27,7 @@ interface VideoPlaybackProps { showShadow?: boolean; shadowIntensity?: number; showBlur?: boolean; + motionBlurEnabled?: boolean; cropRegion?: import('./types').CropRegion; trimRegions?: TrimRegion[]; } @@ -55,6 +56,7 @@ const VideoPlayback = forwardRef(({ showShadow, shadowIntensity = 0, showBlur, + motionBlurEnabled = true, cropRegion, trimRegions = [], }, ref) => { @@ -88,6 +90,7 @@ const VideoPlayback = forwardRef(({ const lockedVideoDimensionsRef = useRef<{ width: number; height: number } | null>(null); const layoutVideoContentRef = useRef<(() => void) | null>(null); const trimRegionsRef = useRef([]); + const motionBlurEnabledRef = useRef(motionBlurEnabled); const clampFocusToStage = useCallback((focus: ZoomFocus, depth: ZoomDepth) => { return clampFocusToStageUtil(focus, depth, stageSizeRef.current); @@ -294,6 +297,10 @@ const VideoPlayback = forwardRef(({ trimRegionsRef.current = trimRegions; }, [trimRegions]); + useEffect(() => { + motionBlurEnabledRef.current = motionBlurEnabled; + }, [motionBlurEnabled]); + useEffect(() => { if (!pixiReady || !videoReady) return; @@ -351,6 +358,7 @@ const VideoPlayback = forwardRef(({ focusY: DEFAULT_FOCUS.cy, motionIntensity: 0, isPlaying: false, + motionBlurEnabled: motionBlurEnabledRef.current, }); requestAnimationFrame(() => { @@ -585,6 +593,7 @@ const VideoPlayback = forwardRef(({ focusY: state.focusY, motionIntensity, isPlaying: isPlayingRef.current, + motionBlurEnabled: motionBlurEnabledRef.current, }); }; diff --git a/src/components/video-editor/videoPlayback/layoutUtils.ts b/src/components/video-editor/videoPlayback/layoutUtils.ts index 9a3d290..5aeab35 100644 --- a/src/components/video-editor/videoPlayback/layoutUtils.ts +++ b/src/components/video-editor/videoPlayback/layoutUtils.ts @@ -24,7 +24,6 @@ interface LayoutResult { export function layoutVideoContent(params: LayoutParams): LayoutResult | null { const { container, app, videoSprite, maskGraphics, videoElement, cropRegion, lockedVideoDimensions } = params; - const videoWidth = lockedVideoDimensions?.width || videoElement.videoWidth; const videoHeight = lockedVideoDimensions?.height || videoElement.videoHeight; diff --git a/src/components/video-editor/videoPlayback/zoomTransform.ts b/src/components/video-editor/videoPlayback/zoomTransform.ts index 145c785..1e50545 100644 --- a/src/components/video-editor/videoPlayback/zoomTransform.ts +++ b/src/components/video-editor/videoPlayback/zoomTransform.ts @@ -10,6 +10,7 @@ interface TransformParams { focusY: number; motionIntensity: number; isPlaying: boolean; + motionBlurEnabled?: boolean; } export function applyZoomTransform({ @@ -22,6 +23,7 @@ export function applyZoomTransform({ focusY, motionIntensity, isPlaying, + motionBlurEnabled = true, }: TransformParams) { if ( stageSize.width <= 0 || @@ -52,7 +54,7 @@ export function applyZoomTransform({ cameraContainer.position.set(cameraX, cameraY); if (blurFilter) { - const shouldBlur = isPlaying && motionIntensity > 0.0005; + const shouldBlur = motionBlurEnabled && isPlaying && motionIntensity > 0.0005; const motionBlur = shouldBlur ? Math.min(6, motionIntensity * 120) : 0; blurFilter.blur = motionBlur; } diff --git a/src/lib/exporter/frameRenderer.ts b/src/lib/exporter/frameRenderer.ts index 3f9531c..f5624a6 100644 --- a/src/lib/exporter/frameRenderer.ts +++ b/src/lib/exporter/frameRenderer.ts @@ -14,6 +14,7 @@ interface FrameRenderConfig { showShadow: boolean; shadowIntensity: number; showBlur: boolean; + motionBlurEnabled?: boolean; cropRegion: CropRegion; videoWidth: number; videoHeight: number; @@ -286,6 +287,7 @@ export class FrameRenderer { focusY: this.animationState.focusY, motionIntensity: maxMotionIntensity, isPlaying: true, + motionBlurEnabled: this.config.motionBlurEnabled ?? true, }); // Render the PixiJS stage to its canvas (video only, transparent background) @@ -311,7 +313,7 @@ export class FrameRenderer { const croppedVideoWidth = videoWidth * (cropEndX - cropStartX); const croppedVideoHeight = videoHeight * (cropEndY - cropStartY); - + // Calculate scale to fit in viewport const viewportWidth = width * VIEWPORT_SCALE; const viewportHeight = height * VIEWPORT_SCALE; diff --git a/src/lib/exporter/videoExporter.ts b/src/lib/exporter/videoExporter.ts index 9631598..ba115ea 100644 --- a/src/lib/exporter/videoExporter.ts +++ b/src/lib/exporter/videoExporter.ts @@ -12,6 +12,8 @@ interface VideoExporterConfig extends ExportConfig { showShadow: boolean; shadowIntensity: number; showBlur: boolean; + motionBlurEnabled?: boolean; + videoPadding?: number; cropRegion: CropRegion; onProgress?: (progress: ExportProgress) => void; } @@ -84,6 +86,7 @@ export class VideoExporter { showShadow: this.config.showShadow, shadowIntensity: this.config.shadowIntensity, showBlur: this.config.showBlur, + motionBlurEnabled: this.config.motionBlurEnabled, cropRegion: this.config.cropRegion, videoWidth: videoInfo.width, videoHeight: videoInfo.height,