shadow intensity

This commit is contained in:
Siddharth
2025-11-25 15:00:06 -07:00
parent 6634d0eb53
commit f887d09865
6 changed files with 63 additions and 34 deletions
+3 -3
View File
@@ -15,10 +15,10 @@ const Slider = React.forwardRef<
)}
{...props}
>
<SliderPrimitive.Track className="relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20">
<SliderPrimitive.Range className="absolute h-full bg-primary" />
<SliderPrimitive.Track className="relative h-1.5 w-full grow overflow-hidden rounded-full bg-white/10">
<SliderPrimitive.Range className="absolute h-full bg-[#34B27B]" />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block h-4 w-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
<SliderPrimitive.Thumb className="block h-4 w-4 rounded-full border-2 border-[#34B27B] bg-[#34B27B] shadow transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#34B27B]/50 disabled:pointer-events-none disabled:opacity-50" />
</SliderPrimitive.Root>
))
Slider.displayName = SliderPrimitive.Root.displayName
+30 -19
View File
@@ -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<string[]>([]);
const [customImages, setCustomImages] = useState<string[]>([]);
const fileInputRef = useRef<HTMLInputElement>(null);
@@ -194,22 +195,32 @@ export function SettingsPanel({ selected, onWallpaperChange, selectedZoomDepth,
)}
</div>
<div className="mb-6 space-y-4">
<div className="flex items-center justify-between p-3 rounded-xl bg-white/5 border border-white/5">
<div className="text-sm font-medium text-slate-200">Drop Shadow</div>
<Switch
checked={showShadow}
onCheckedChange={onShadowChange}
className="data-[state=checked]:bg-[#34B27B]"
/>
</div>
<div className="flex items-center justify-between p-3 rounded-xl bg-white/5 border border-white/5">
<div className="text-sm font-medium text-slate-200">Blur Background</div>
<Switch
checked={showBlur}
onCheckedChange={onBlurChange}
className="data-[state=checked]:bg-[#34B27B]"
/>
<div className="mb-6">
<div className="grid grid-cols-2 gap-3">
{/* Drop Shadow Slider */}
<div className="p-3 rounded-xl bg-white/5 border border-white/5 space-y-2">
<div className="flex items-center justify-between">
<div className="text-xs font-medium text-slate-200">Shadow</div>
<span className="text-[10px] text-slate-400 font-mono">{Math.round(shadowIntensity * 100)}%</span>
</div>
<Slider
value={[shadowIntensity]}
onValueChange={(values) => onShadowChange?.(values[0])}
min={0}
max={1}
step={0.01}
className="w-full [&_[role=slider]]:bg-[#34B27B] [&_[role=slider]]:border-[#34B27B]"
/>
</div>
{/* Blur Background Switch */}
<div className="flex items-center justify-between p-3 rounded-xl bg-white/5 border border-white/5">
<div className="text-xs font-medium text-slate-200">Blur</div>
<Switch
checked={showBlur}
onCheckedChange={onBlurChange}
className="data-[state=checked]:bg-[#34B27B]"
/>
</div>
</div>
</div>
+8 -6
View File
@@ -33,7 +33,7 @@ export default function VideoEditor() {
const [currentTime, setCurrentTime] = useState(0);
const [duration, setDuration] = useState(0);
const [wallpaper, setWallpaper] = useState<string>(WALLPAPER_PATHS[0]);
const [showShadow, setShowShadow] = useState(false);
const [shadowIntensity, setShadowIntensity] = useState(0);
const [showBlur, setShowBlur] = useState(false);
const [cropRegion, setCropRegion] = useState<CropRegion>(DEFAULT_CROP_REGION);
const [zoomRegions, setZoomRegions] = useState<ZoomRegion[]>([]);
@@ -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}
@@ -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<VideoPlaybackRef, VideoPlaybackProps>(({
onZoomFocusChange,
isPlaying,
showShadow,
shadowIntensity = 0,
showBlur,
cropRegion,
}, ref) => {
@@ -722,15 +724,15 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
className="absolute inset-0 bg-cover bg-center"
style={{
...backgroundStyle,
filter: showBlur ? 'blur(2px)' : 'none',
filter: showBlur ? 'blur(3px)' : 'none',
}}
/>
<div
ref={containerRef}
className="absolute inset-0"
style={{
filter: showShadow
? '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))'
filter: (showShadow && shadowIntensity > 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',
}}
/>
+15 -3
View File
@@ -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);
+2
View File
@@ -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,