diff --git a/src/components/video-editor/SettingsPanel.tsx b/src/components/video-editor/SettingsPanel.tsx
index 5d016b238..aa7d2bfd0 100644
--- a/src/components/video-editor/SettingsPanel.tsx
+++ b/src/components/video-editor/SettingsPanel.tsx
@@ -12,6 +12,7 @@ import {
} from "@/components/ui/select";
import { Switch } from "@/components/ui/switch";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
+import { useTheme } from "@/contexts/ThemeContext";
import { getAssetPath, getRenderableAssetUrl, getWallpaperThumbnailUrl } from "@/lib/assetPath";
import type { ExtensionSettingField } from "@/lib/extensions";
import { extensionHost, type FrameInstance } from "@/lib/extensions";
@@ -27,7 +28,6 @@ import minimalCursorUrl from "../../../Minimal Cursor.svg";
import { useI18n, useScopedT } from "../../contexts/I18nContext";
import type { AppLocale } from "../../i18n/config";
import { SUPPORTED_LOCALES } from "../../i18n/config";
-import { useTheme } from "@/contexts/ThemeContext";
import { AnnotationSettingsPanel } from "./AnnotationSettingsPanel";
import { loadEditorPreferences, saveEditorPreferences } from "./editorPreferences";
import { SliderControl } from "./SliderControl";
@@ -50,9 +50,6 @@ import type {
ZoomMode,
ZoomTransitionEasing,
} from "./types";
-import {
- isZeroPadding,
-} from "./videoPlayback/layoutUtils";
import {
DEFAULT_AUTO_CAPTION_SETTINGS,
DEFAULT_CROP_REGION,
@@ -76,6 +73,7 @@ import {
SPEED_OPTIONS,
} from "./types";
import { fromCursorSwaySliderValue, toCursorSwaySliderValue } from "./videoPlayback/cursorSway";
+import { isZeroPadding } from "./videoPlayback/layoutUtils";
import {
cursorSetAssets,
getCursorStyleSizeMultiplier,
@@ -348,6 +346,10 @@ interface SettingsPanelProps {
onClipSpeedChange?: (speed: number) => void;
onClipMutedChange?: (muted: boolean) => void;
onClipDelete?: (id: string) => void;
+ selectedAudioId?: string | null;
+ selectedAudioVolume?: number | null;
+ onAudioVolumeChange?: (volume: number) => void;
+ onAudioDelete?: (id: string) => void;
shadowIntensity?: number;
onShadowChange?: (intensity: number) => void;
backgroundBlur?: number;
@@ -721,6 +723,10 @@ export function SettingsPanel({
onClipSpeedChange,
onClipMutedChange,
onClipDelete,
+ selectedAudioId,
+ selectedAudioVolume,
+ onAudioVolumeChange,
+ onAudioDelete,
shadowIntensity = 0.67,
onShadowChange,
backgroundBlur = 0,
@@ -3031,7 +3037,7 @@ export function SettingsPanel({
{selectedTrimId && (
@@ -3094,6 +3100,39 @@ export function SettingsPanel({
)}
+
+ {selectedAudioId && (
+
+
+
+ {tSettings("audio.volumeTitle", "Audio Volume")}
+
+
+ {Math.round((selectedAudioVolume ?? 1) * 100)}%
+
+
+
onAudioVolumeChange?.(v)}
+ formatValue={(v) => `${Math.round(v * 100)}%`}
+ parseInput={(text) => parseFloat(text.replace(/%$/, "")) / 100}
+ />
+
+
+ )}
);
diff --git a/src/components/video-editor/VideoEditor.tsx b/src/components/video-editor/VideoEditor.tsx
index bc2c01ef0..580627ac4 100644
--- a/src/components/video-editor/VideoEditor.tsx
+++ b/src/components/video-editor/VideoEditor.tsx
@@ -3257,6 +3257,23 @@ export default function VideoEditor() {
);
}, []);
+ const handleAudioVolumeChange = useCallback((volume: number) => {
+ if (!selectedAudioId) {
+ return;
+ }
+
+ if (!Number.isFinite(volume)) {
+ return;
+ }
+
+ const nextVolume = Math.max(0, Math.min(1, volume));
+ setAudioRegions((prev) =>
+ prev.map((region) =>
+ region.id === selectedAudioId ? { ...region, volume: nextVolume } : region,
+ ),
+ );
+ }, [selectedAudioId]);
+
const handleAudioDelete = useCallback(
(id: string) => {
setAudioRegions((prev) => prev.filter((region) => region.id !== id));
@@ -4396,6 +4413,8 @@ export default function VideoEditor() {
effectiveSpeedRegions,
frame,
smokeExportConfig.encodingMode,
+ smokeExportConfig.fps,
+ smokeExportConfig.quality,
],
);
@@ -5188,6 +5207,15 @@ export default function VideoEditor() {
selectedClipId && handleClipMutedChange(muted)
}
onClipDelete={handleClipDelete}
+ selectedAudioId={selectedAudioId}
+ selectedAudioVolume={
+ selectedAudioId
+ ? (audioRegions.find((r) => r.id === selectedAudioId)
+ ?.volume ?? null)
+ : null
+ }
+ onAudioVolumeChange={handleAudioVolumeChange}
+ onAudioDelete={handleAudioDelete}
shadowIntensity={shadowIntensity}
onShadowChange={setShadowIntensity}
backgroundBlur={backgroundBlur}
diff --git a/src/components/video-editor/timeline/Row.tsx b/src/components/video-editor/timeline/Row.tsx
index f2aba7238..f54e5a9cb 100644
--- a/src/components/video-editor/timeline/Row.tsx
+++ b/src/components/video-editor/timeline/Row.tsx
@@ -30,7 +30,11 @@ export default function Row({ id, children, label, hint, isEmpty, labelColor = "
{hint}
)}
-