diff --git a/src/components/video-editor/AnnotationOverlay.tsx b/src/components/video-editor/AnnotationOverlay.tsx index ee58b361..c142ddd8 100644 --- a/src/components/video-editor/AnnotationOverlay.tsx +++ b/src/components/video-editor/AnnotationOverlay.tsx @@ -115,7 +115,8 @@ export function AnnotationOverlay({ case "blur": { const previewScaleFactor = containerWidth / BASE_PREVIEW_WIDTH; - const blurPx = BLUR_ANNOTATION_STRENGTH * previewScaleFactor; + const currentBlurStrength = annotation.blurIntensity ?? BLUR_ANNOTATION_STRENGTH; + const blurPx = currentBlurStrength * previewScaleFactor; const blurStyle = `blur(${blurPx}px)`; return ( diff --git a/src/components/video-editor/AnnotationSettingsPanel.tsx b/src/components/video-editor/AnnotationSettingsPanel.tsx index 79e465a6..9132b3c8 100644 --- a/src/components/video-editor/AnnotationSettingsPanel.tsx +++ b/src/components/video-editor/AnnotationSettingsPanel.tsx @@ -21,6 +21,7 @@ interface AnnotationSettingsPanelProps { onTypeChange: (type: AnnotationType) => void; onStyleChange: (style: Partial) => void; onFigureDataChange?: (figureData: FigureData) => void; + onBlurIntensityChange?: (intensity: number) => void; onDelete: () => void; } @@ -43,6 +44,7 @@ export function AnnotationSettingsPanel({ onTypeChange, onStyleChange, onFigureDataChange, + onBlurIntensityChange, onDelete, }: AnnotationSettingsPanelProps) { const t = useScopedT('editor'); @@ -510,10 +512,25 @@ export function AnnotationSettingsPanel({

{t('annotations.blur')}

-

+

{t('annotations.blurDescription')}

+
+
+ + {t('annotations.blurStrength', undefined, { strength: annotation.blurIntensity ?? 20 })} + +
+ onBlurIntensityChange?.(value)} + min={1} + max={100} + step={1} + className="w-full" + /> +
diff --git a/src/components/video-editor/SettingsPanel.tsx b/src/components/video-editor/SettingsPanel.tsx index 45612b8e..e341f087 100644 --- a/src/components/video-editor/SettingsPanel.tsx +++ b/src/components/video-editor/SettingsPanel.tsx @@ -223,6 +223,7 @@ interface SettingsPanelProps { onAnnotationTypeChange?: (id: string, type: AnnotationType) => void; onAnnotationStyleChange?: (id: string, style: Partial) => void; onAnnotationFigureDataChange?: (id: string, figureData: FigureData) => void; + onAnnotationBlurIntensityChange?: (id: string, intensity: number) => void; onAnnotationDelete?: (id: string) => void; autoCaptions?: CaptionCue[]; autoCaptionSettings?: AutoCaptionSettings; @@ -570,6 +571,7 @@ export function SettingsPanel({ onAnnotationTypeChange, onAnnotationStyleChange, onAnnotationFigureDataChange, + onAnnotationBlurIntensityChange, onAnnotationDelete, autoCaptions = [], autoCaptionSettings = DEFAULT_AUTO_CAPTION_SETTINGS, @@ -1301,6 +1303,11 @@ export function SettingsPanel({ ? (figureData) => onAnnotationFigureDataChange(selectedAnnotation.id, figureData) : undefined } + onBlurIntensityChange={ + onAnnotationBlurIntensityChange + ? (intensity) => onAnnotationBlurIntensityChange(selectedAnnotation.id, intensity) + : undefined + } onDelete={() => onAnnotationDelete(selectedAnnotation.id)} /> ); diff --git a/src/components/video-editor/VideoEditor.tsx b/src/components/video-editor/VideoEditor.tsx index c474732d..7dcfa089 100644 --- a/src/components/video-editor/VideoEditor.tsx +++ b/src/components/video-editor/VideoEditor.tsx @@ -2714,6 +2714,12 @@ export default function VideoEditor() { ); }, []); + const handleAnnotationBlurIntensityChange = useCallback((id: string, blurIntensity: number) => { + setAnnotationRegions((prev) => + prev.map((region) => (region.id === id ? { ...region, blurIntensity } : region)), + ); + }, []); + const handleAnnotationPositionChange = useCallback( (id: string, position: { x: number; y: number }) => { setAnnotationRegions((prev) => @@ -4511,6 +4517,7 @@ export default function VideoEditor() { onAnnotationTypeChange={handleAnnotationTypeChange} onAnnotationStyleChange={handleAnnotationStyleChange} onAnnotationFigureDataChange={handleAnnotationFigureDataChange} + onAnnotationBlurIntensityChange={handleAnnotationBlurIntensityChange} onAnnotationDelete={handleAnnotationDelete} selectedSpeedId={selectedSpeedId} selectedSpeedValue={ diff --git a/src/components/video-editor/projectPersistence.ts b/src/components/video-editor/projectPersistence.ts index 1b158276..699deefa 100644 --- a/src/components/video-editor/projectPersistence.ts +++ b/src/components/video-editor/projectPersistence.ts @@ -446,6 +446,7 @@ export function normalizeProjectEditor(editor: Partial): Pro ...region.figureData, } : undefined, + blurIntensity: isFiniteNumber(region.blurIntensity) ? region.blurIntensity : undefined, }; }) : []; diff --git a/src/components/video-editor/types.ts b/src/components/video-editor/types.ts index 172ef66f..f08ccbd2 100644 --- a/src/components/video-editor/types.ts +++ b/src/components/video-editor/types.ts @@ -247,6 +247,7 @@ export interface AnnotationRegion { style: AnnotationTextStyle; zIndex: number; figureData?: FigureData; + blurIntensity?: number; } export const DEFAULT_ANNOTATION_POSITION: AnnotationPosition = {