diff --git a/src/components/video-editor/SettingsPanel.tsx b/src/components/video-editor/SettingsPanel.tsx
index 377cbbe..36fa255 100644
--- a/src/components/video-editor/SettingsPanel.tsx
+++ b/src/components/video-editor/SettingsPanel.tsx
@@ -1,3 +1,4 @@
+import * as SliderPrimitive from "@radix-ui/react-slider";
import {
Bug,
ChevronDown,
@@ -65,8 +66,11 @@ import type {
import {
DEFAULT_WEBCAM_SIZE_PRESET,
MAX_PLAYBACK_SPEED,
+ MAX_ZOOM_SCALE,
+ MIN_ZOOM_SCALE,
ROTATION_3D_PRESET_ORDER,
SPEED_OPTIONS,
+ ZOOM_DEPTH_SCALES,
} from "./types";
function CustomSpeedInput({
@@ -170,6 +174,9 @@ interface SettingsPanelProps {
onWallpaperChange: (path: string) => void;
selectedZoomDepth?: ZoomDepth | null;
onZoomDepthChange?: (depth: ZoomDepth) => void;
+ selectedZoomCustomScale?: number | null;
+ onZoomCustomScaleChange?: (scale: number) => void;
+ onZoomCustomScaleCommit?: () => void;
selectedZoomFocusMode?: ZoomFocusMode | null;
onZoomFocusModeChange?: (mode: ZoomFocusMode) => void;
hasCursorTelemetry?: boolean;
@@ -263,6 +270,9 @@ export function SettingsPanel({
onWallpaperChange,
selectedZoomDepth,
onZoomDepthChange,
+ selectedZoomCustomScale,
+ onZoomCustomScaleChange,
+ onZoomCustomScaleCommit,
selectedZoomFocusMode,
onZoomFocusModeChange,
hasCursorTelemetry = false,
@@ -593,7 +603,9 @@ export function SettingsPanel({
{zoomEnabled && selectedZoomDepth && (
- {ZOOM_DEPTH_OPTIONS.find((o) => o.depth === selectedZoomDepth)?.label}
+ {selectedZoomCustomScale != null
+ ? `${selectedZoomCustomScale.toFixed(2)}×`
+ : ZOOM_DEPTH_OPTIONS.find((o) => o.depth === selectedZoomDepth)?.label}
)}
@@ -601,7 +613,10 @@ export function SettingsPanel({
{ZOOM_DEPTH_OPTIONS.map((option) => {
- const isActive = selectedZoomDepth === option.depth;
+ const effectiveScale =
+ selectedZoomCustomScale ??
+ (selectedZoomDepth != null ? ZOOM_DEPTH_SCALES[selectedZoomDepth] : null);
+ const isActive = effectiveScale === ZOOM_DEPTH_SCALES[option.depth];
return (