motion-blue switch

This commit is contained in:
Siddharth
2025-11-28 16:08:11 -07:00
parent 6fb9a24834
commit 8f31bde518
7 changed files with 41 additions and 5 deletions
+17 -1
View File
@@ -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<string[]>([]);
const [customImages, setCustomImages] = useState<string[]>([]);
const fileInputRef = useRef<HTMLInputElement>(null);
@@ -230,6 +232,20 @@ export function SettingsPanel({ selected, onWallpaperChange, selectedZoomDepth,
</div>
</div>
<div className="mb-6">
<div className="grid grid-cols-2 gap-3">
{/* Motion Blur 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">Motion Blur</div>
<Switch
checked={motionBlurEnabled}
onCheckedChange={onMotionBlurChange}
className="data-[state=checked]:bg-[#34B27B]"
/>
</div>
</div>
</div>
<div className="mb-6">
<Button
onClick={() => setShowCropDropdown(!showCropDropdown)}
+6 -1
View File
@@ -37,6 +37,7 @@ export default function VideoEditor() {
const [wallpaper, setWallpaper] = useState<string>(WALLPAPER_PATHS[0]);
const [shadowIntensity, setShadowIntensity] = useState(0);
const [showBlur, setShowBlur] = useState(false);
const [motionBlurEnabled, setMotionBlurEnabled] = useState(true);
const [cropRegion, setCropRegion] = useState<CropRegion>(DEFAULT_CROP_REGION);
const [zoomRegions, setZoomRegions] = useState<ZoomRegion[]>([]);
const [selectedZoomId, setSelectedZoomId] = useState<string | null>(null);
@@ -285,6 +286,7 @@ export default function VideoEditor() {
showShadow: shadowIntensity > 0,
shadowIntensity,
showBlur,
motionBlurEnabled,
cropRegion,
onProgress: (progress: ExportProgress) => {
setExportProgress(progress);
@@ -390,6 +392,7 @@ export default function VideoEditor() {
showShadow={shadowIntensity > 0}
shadowIntensity={shadowIntensity}
showBlur={showBlur}
motionBlurEnabled={motionBlurEnabled}
cropRegion={cropRegion}
trimRegions={trimRegions}
/>
@@ -440,7 +443,7 @@ export default function VideoEditor() {
</div>
{/* Right section: settings panel */}
<SettingsPanel
<SettingsPanel
selected={wallpaper}
onWallpaperChange={setWallpaper}
selectedZoomDepth={selectedZoomId ? zoomRegions.find(z => 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}
@@ -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<VideoPlaybackRef, VideoPlaybackProps>(({
showShadow,
shadowIntensity = 0,
showBlur,
motionBlurEnabled = true,
cropRegion,
trimRegions = [],
}, ref) => {
@@ -88,6 +90,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
const lockedVideoDimensionsRef = useRef<{ width: number; height: number } | null>(null);
const layoutVideoContentRef = useRef<(() => void) | null>(null);
const trimRegionsRef = useRef<TrimRegion[]>([]);
const motionBlurEnabledRef = useRef(motionBlurEnabled);
const clampFocusToStage = useCallback((focus: ZoomFocus, depth: ZoomDepth) => {
return clampFocusToStageUtil(focus, depth, stageSizeRef.current);
@@ -294,6 +297,10 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
trimRegionsRef.current = trimRegions;
}, [trimRegions]);
useEffect(() => {
motionBlurEnabledRef.current = motionBlurEnabled;
}, [motionBlurEnabled]);
useEffect(() => {
if (!pixiReady || !videoReady) return;
@@ -351,6 +358,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
focusY: DEFAULT_FOCUS.cy,
motionIntensity: 0,
isPlaying: false,
motionBlurEnabled: motionBlurEnabledRef.current,
});
requestAnimationFrame(() => {
@@ -585,6 +593,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
focusY: state.focusY,
motionIntensity,
isPlaying: isPlayingRef.current,
motionBlurEnabled: motionBlurEnabledRef.current,
});
};
@@ -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;
@@ -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;
}
+3 -1
View File
@@ -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;
+3
View File
@@ -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,