diff --git a/src/components/ui/slider.tsx b/src/components/ui/slider.tsx index 9398b33..dcb8ef7 100644 --- a/src/components/ui/slider.tsx +++ b/src/components/ui/slider.tsx @@ -15,10 +15,10 @@ const Slider = React.forwardRef< )} {...props} > - - + + - + )) Slider.displayName = SliderPrimitive.Root.displayName diff --git a/src/components/video-editor/SettingsPanel.tsx b/src/components/video-editor/SettingsPanel.tsx index 9808871..d5ecbb5 100644 --- a/src/components/video-editor/SettingsPanel.tsx +++ b/src/components/video-editor/SettingsPanel.tsx @@ -1,6 +1,7 @@ import { cn } from "@/lib/utils"; import { useEffect, useRef } from "react"; import { getAssetPath } from "@/lib/assetPath"; +import { Slider } from "@/components/ui/slider"; import { Switch } from "@/components/ui/switch"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Button } from "@/components/ui/button"; @@ -48,8 +49,8 @@ interface SettingsPanelProps { onZoomDepthChange?: (depth: ZoomDepth) => void; selectedZoomId?: string | null; onZoomDelete?: (id: string) => void; - showShadow?: boolean; - onShadowChange?: (showShadow: boolean) => void; + shadowIntensity?: number; + onShadowChange?: (intensity: number) => void; showBlur?: boolean; onBlurChange?: (showBlur: boolean) => void; cropRegion?: CropRegion; @@ -68,7 +69,7 @@ const ZOOM_DEPTH_OPTIONS: Array<{ depth: ZoomDepth; label: string }> = [ { depth: 5, label: "3.5×" }, ]; -export function SettingsPanel({ selected, onWallpaperChange, selectedZoomDepth, onZoomDepthChange, selectedZoomId, onZoomDelete, showShadow, onShadowChange, showBlur, onBlurChange, cropRegion, onCropChange, videoElement, onExport }: SettingsPanelProps) { +export function SettingsPanel({ selected, onWallpaperChange, selectedZoomDepth, onZoomDepthChange, selectedZoomId, onZoomDelete, shadowIntensity = 0, onShadowChange, showBlur, onBlurChange, cropRegion, onCropChange, videoElement, onExport }: SettingsPanelProps) { const [wallpaperPaths, setWallpaperPaths] = useState([]); const [customImages, setCustomImages] = useState([]); const fileInputRef = useRef(null); @@ -194,22 +195,32 @@ export function SettingsPanel({ selected, onWallpaperChange, selectedZoomDepth, )} -
-
-
Drop Shadow
- -
-
-
Blur Background
- +
+
+ {/* Drop Shadow Slider */} +
+
+
Shadow
+ {Math.round(shadowIntensity * 100)}% +
+ onShadowChange?.(values[0])} + min={0} + max={1} + step={0.01} + className="w-full [&_[role=slider]]:bg-[#34B27B] [&_[role=slider]]:border-[#34B27B]" + /> +
+ {/* Blur Background Switch */} +
+
Blur
+ +
diff --git a/src/components/video-editor/VideoEditor.tsx b/src/components/video-editor/VideoEditor.tsx index f20ae8e..f49315a 100644 --- a/src/components/video-editor/VideoEditor.tsx +++ b/src/components/video-editor/VideoEditor.tsx @@ -33,7 +33,7 @@ export default function VideoEditor() { const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(0); const [wallpaper, setWallpaper] = useState(WALLPAPER_PATHS[0]); - const [showShadow, setShowShadow] = useState(false); + const [shadowIntensity, setShadowIntensity] = useState(0); const [showBlur, setShowBlur] = useState(false); const [cropRegion, setCropRegion] = useState(DEFAULT_CROP_REGION); const [zoomRegions, setZoomRegions] = useState([]); @@ -229,7 +229,8 @@ export default function VideoEditor() { codec: 'avc1.640033', wallpaper, zoomRegions, - showShadow, + showShadow: shadowIntensity > 0, + shadowIntensity, showBlur, cropRegion, onProgress: (progress: ExportProgress) => { @@ -270,7 +271,7 @@ export default function VideoEditor() { setIsExporting(false); exporterRef.current = null; } - }, [videoPath, wallpaper, zoomRegions, showShadow, showBlur, cropRegion, isPlaying]); + }, [videoPath, wallpaper, zoomRegions, shadowIntensity, showBlur, cropRegion, isPlaying]); const handleCancelExport = useCallback(() => { if (exporterRef.current) { @@ -329,7 +330,8 @@ export default function VideoEditor() { onSelectZoom={handleSelectZoom} onZoomFocusChange={handleZoomFocusChange} isPlaying={isPlaying} - showShadow={showShadow} + showShadow={shadowIntensity > 0} + shadowIntensity={shadowIntensity} showBlur={showBlur} cropRegion={cropRegion} /> @@ -373,8 +375,8 @@ export default function VideoEditor() { onZoomDepthChange={(depth) => selectedZoomId && handleZoomDepthChange(depth)} selectedZoomId={selectedZoomId} onZoomDelete={handleZoomDelete} - showShadow={showShadow} - onShadowChange={setShowShadow} + shadowIntensity={shadowIntensity} + onShadowChange={setShadowIntensity} showBlur={showBlur} onBlurChange={setShowBlur} cropRegion={cropRegion} diff --git a/src/components/video-editor/VideoPlayback.tsx b/src/components/video-editor/VideoPlayback.tsx index 62c3d40..06d51c1 100644 --- a/src/components/video-editor/VideoPlayback.tsx +++ b/src/components/video-editor/VideoPlayback.tsx @@ -25,6 +25,7 @@ interface VideoPlaybackProps { onZoomFocusChange: (id: string, focus: ZoomFocus) => void; isPlaying: boolean; showShadow?: boolean; + shadowIntensity?: number; showBlur?: boolean; cropRegion?: import('./types').CropRegion; } @@ -51,6 +52,7 @@ const VideoPlayback = forwardRef(({ onZoomFocusChange, isPlaying, showShadow, + shadowIntensity = 0, showBlur, cropRegion, }, ref) => { @@ -722,15 +724,15 @@ const VideoPlayback = forwardRef(({ className="absolute inset-0 bg-cover bg-center" style={{ ...backgroundStyle, - filter: showBlur ? 'blur(2px)' : 'none', + filter: showBlur ? 'blur(3px)' : 'none', }} />
0) + ? `drop-shadow(0 ${shadowIntensity * 12}px ${shadowIntensity * 48}px rgba(0,0,0,${shadowIntensity * 0.7})) drop-shadow(0 ${shadowIntensity * 4}px ${shadowIntensity * 16}px rgba(0,0,0,${shadowIntensity * 0.5})) drop-shadow(0 ${shadowIntensity * 2}px ${shadowIntensity * 8}px rgba(0,0,0,${shadowIntensity * 0.3}))` : 'none', }} /> diff --git a/src/lib/exporter/frameRenderer.ts b/src/lib/exporter/frameRenderer.ts index 020d1bc..56bb281 100644 --- a/src/lib/exporter/frameRenderer.ts +++ b/src/lib/exporter/frameRenderer.ts @@ -12,6 +12,7 @@ interface FrameRenderConfig { wallpaper: string; zoomRegions: ZoomRegion[]; showShadow: boolean; + shadowIntensity: number; showBlur: boolean; cropRegion: CropRegion; videoWidth: number; @@ -434,7 +435,7 @@ export class FrameRenderer { if (this.config.showBlur) { ctx.save(); - ctx.filter = 'blur(2px)'; + ctx.filter = 'blur(3px)'; ctx.drawImage(bgCanvas, 0, 0, w, h); ctx.restore(); } else { @@ -445,11 +446,22 @@ export class FrameRenderer { } // Draw video layer with shadows on top of background - if (this.config.showShadow && this.shadowCanvas && this.shadowCtx) { + if (this.config.showShadow && this.config.shadowIntensity > 0 && this.shadowCanvas && this.shadowCtx) { const shadowCtx = this.shadowCtx; shadowCtx.clearRect(0, 0, w, h); shadowCtx.save(); - shadowCtx.filter = 'drop-shadow(0 12px 48px rgba(0,0,0,0.7)) drop-shadow(0 4px 16px rgba(0,0,0,0.5)) drop-shadow(0 2px 8px rgba(0,0,0,0.3))'; + + // Calculate shadow parameters based on intensity (0-1) + const intensity = this.config.shadowIntensity; + const baseBlur1 = 48 * intensity; + const baseBlur2 = 16 * intensity; + const baseBlur3 = 8 * intensity; + const baseAlpha1 = 0.7 * intensity; + const baseAlpha2 = 0.5 * intensity; + const baseAlpha3 = 0.3 * intensity; + const baseOffset = 12 * intensity; + + shadowCtx.filter = `drop-shadow(0 ${baseOffset}px ${baseBlur1}px rgba(0,0,0,${baseAlpha1})) drop-shadow(0 ${baseOffset/3}px ${baseBlur2}px rgba(0,0,0,${baseAlpha2})) drop-shadow(0 ${baseOffset/6}px ${baseBlur3}px rgba(0,0,0,${baseAlpha3}))`; shadowCtx.drawImage(videoCanvas, 0, 0, w, h); shadowCtx.restore(); ctx.drawImage(this.shadowCanvas, 0, 0, w, h); diff --git a/src/lib/exporter/videoExporter.ts b/src/lib/exporter/videoExporter.ts index fdcd35c..c4d468d 100644 --- a/src/lib/exporter/videoExporter.ts +++ b/src/lib/exporter/videoExporter.ts @@ -9,6 +9,7 @@ interface VideoExporterConfig extends ExportConfig { wallpaper: string; zoomRegions: ZoomRegion[]; showShadow: boolean; + shadowIntensity: number; showBlur: boolean; cropRegion: CropRegion; onProgress?: (progress: ExportProgress) => void; @@ -50,6 +51,7 @@ export class VideoExporter { wallpaper: this.config.wallpaper, zoomRegions: this.config.zoomRegions, showShadow: this.config.showShadow, + shadowIntensity: this.config.shadowIntensity, showBlur: this.config.showBlur, cropRegion: this.config.cropRegion, videoWidth: videoInfo.width,