diff --git a/src/components/VideoEditor.tsx b/src/components/VideoEditor.tsx
index 3ffb6a67..443770da 100644
--- a/src/components/VideoEditor.tsx
+++ b/src/components/VideoEditor.tsx
@@ -250,6 +250,30 @@ export default function VideoEditor() {
className="w-full"
/>
+ {/* Sharpness */}
+
+
+
+
+
+
updateRecipe({ sharpness: Number(e.target.value) })}
+ aria-label="Adjust sharpness"
+ className="w-full"
+ />
+
} title="Output format" delay={190}>
diff --git a/src/hooks/useVideoEditor.ts b/src/hooks/useVideoEditor.ts
index 2f94bcbf..7c9a066d 100644
--- a/src/hooks/useVideoEditor.ts
+++ b/src/hooks/useVideoEditor.ts
@@ -106,6 +106,10 @@ function validateRecipe(recipe: EditRecipe, duration: number ): string | null {
recipe.saturation < 0 || recipe.saturation > 3,
"Saturation must be between 0 and 3.",
],
+ [
+ recipe.sharpness < 0 || recipe.sharpness > 3,
+ "Sharpness must be between 0 and 3.",
+ ],
];
return (
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
index 976307a4..f0e618b9 100644
--- a/src/lib/constants.ts
+++ b/src/lib/constants.ts
@@ -19,5 +19,6 @@ export const DEFAULT_RECIPE: EditRecipe = {
saturation: 1,
stabilization: false,
soundOnCompletion: false,
+ sharpness: 0,
normalizeAudio: false,
};
\ No newline at end of file
diff --git a/src/lib/ffmpeg.ts b/src/lib/ffmpeg.ts
index 4f215075..32d4acb3 100644
--- a/src/lib/ffmpeg.ts
+++ b/src/lib/ffmpeg.ts
@@ -120,6 +120,9 @@ function buildVideoFilter(recipe: EditRecipe, targetW: number, targetH: number):
`crop=${targetW}:${targetH}`
);
}
+ if (recipe.sharpness !== 0) {
+ filters.push(`unsharp=5:5:${recipe.sharpness}:5:5:0.0`);
+ }
if (recipe.speed !== 1) {
const pts = (1 / recipe.speed).toFixed(4);
diff --git a/src/lib/types.ts b/src/lib/types.ts
index 521a82c2..8054cf04 100644
--- a/src/lib/types.ts
+++ b/src/lib/types.ts
@@ -16,6 +16,7 @@ export interface EditRecipe {
contrast: number;
saturation: number;
soundOnCompletion: boolean;
+ sharpness: number;
}
export type OverlayPosition =
@@ -82,6 +83,7 @@ export const DEFAULT_RECIPE: EditRecipe = {
contrast: 0,
saturation: 0,
soundOnCompletion: false,
+ sharpness: 1,
};
export const MAX_FILE_SIZE =