smart-cut
Detect and remove silences, filler words, and dead space from video/audio using AI silence detection.
SKILL.mdAutoAnimation/.claude/skills/smart-cut/SKILL.md
GitHubPurpose
Analyze audio to detect silence regions and filler words ("um", "uh", "like", "you know", etc.), then remove them from the timeline. This tightens pacing and improves viewer retention. Two detection systems work together: RMS energy analysis for silences and word-matching against alignment timestamps for fillers.
Steps
Prepare audio for analysis. Decode the audio blob into an
AudioBufferusingdecodeAudioBlob(blob)fromsilenceDetection.ts. This uses the Web Audio API'sAudioContext.decodeAudioData().Run combined detection. Call
detectAll(audioBuffer, words, settings)fromsilenceDetection.tswhich runs both detectors and merges results:- Silence detection:
detectSilences(audioBuffer, settings)analyzes 50ms windows of RMS energy. Regions where energy falls belowsilenceThresholdDb(default -40dB) for longer thanminSilenceDuration(default 0.4s) are flagged. - Filler word detection:
detectFillerWords(words, fillerList)matches word timestamps against a configurable filler list. Supports single-word ("um") and multi-word ("you know") fillers.
- Silence detection:
Configure detection settings. The
DetectionSettingsobject controls:silenceThresholdDb: dB below peak to consider as silence (default -40)minSilenceDuration: minimum silence duration in seconds (default 0.4)fillerWords: array of filler words/phrases to detect (default includes: um, uh, uhm, hmm, like, you know, basically, actually, so, right, i mean)
Review detected regions. Results are
SilenceRegion[]withid,type('silence' or 'filler'),startTime,endTime,word(for fillers), andenabled(toggle for inclusion). The store provides filtering by mode: 'all', 'silence', or 'fillers'.Preview and toggle regions. Use
useSmartCutStore:toggleRegion(regionId)-- enable/disable individual regionstoggleAll(enabled)-- bulk enable/disablesetFilterMode(mode)-- filter display by type
Apply smart cut. Call
useSmartCutStore.getState().applySmartCut()which:- Sorts enabled regions by start time
- Trims dialogue lines that contain removed regions
- Cascades frame shifts -- subsequent content shifts earlier by cumulative removed duration
- Reduces total timeline frames
- Clears regions after applying
Alternative: SilenceRemovalService. For transcript-based removal (using Whisper word timestamps), use
getSilenceRemovalService().analyzeTranscript(words, mode, fps)fromsilenceRemoval.ts. This offers three speed modes:natural: threshold 1.5s (only long pauses)fast: threshold 0.8s (noticeable pauses)extra-fast: threshold 0.3s + filler word removal- Returns
AnalysisResultwithsilences,fillers,totalRemovedSec, andedits(TimelineEdit[] for direct timeline application)
Key Files
src/services/silenceDetection.ts-- detectSilences(), detectFillerWords(), detectAll(), decodeAudioBlob(), SilenceRegion, DetectionSettings, DEFAULT_SETTINGSsrc/services/silenceRemoval.ts-- SilenceRemovalService, analyzeTranscript(), RemovalMode, TimelineEditsrc/stores/useSmartCutStore.ts-- analyzeAudio(), toggleRegion(), applySmartCut(), detection state managementsrc/components/panels/SmartCutPanel.tsx-- Smart cut UIsrc/components/panels/SilenceRemovalPanel.tsx-- Silence removal panel UI
Common Issues
- Threshold too aggressive: Default -40dB catches most silences. For noisy recordings, lower to -35dB or -30dB. For clean studio audio, -45dB or -50dB works better.
- Short silences missed: Increase
minSilenceDurationthreshold. Natural speech has ~200ms pauses between words that should not be removed. - Filler detection false positives: Words like "so" and "like" have legitimate uses. Review detected fillers before applying. The
enabledtoggle lets users exclude false positives. - Frame shift cascading: After applying cuts, all subsequent content shifts earlier. This affects dialogue lines, text overlays, and any frame-based elements. Only dialogue lines are auto-adjusted; other elements may need manual repositioning.
- Minimum gap preserved:
SilenceRemovalServicekeeps a 75ms gap (MIN_GAP_SEC) between clips after removal for natural breathing room.
Examples
// Web Audio-based detection
import { detectAll, decodeAudioBlob, DEFAULT_SETTINGS } from '@/services/silenceDetection'
const audioBuffer = await decodeAudioBlob(audioBlob)
const regions = detectAll(audioBuffer, wordTimestamps, {
...DEFAULT_SETTINGS,
silenceThresholdDb: -35,
minSilenceDuration: 0.5,
})
// Transcript-based detection
import { getSilenceRemovalService } from '@/services/silenceRemoval'
const service = getSilenceRemovalService()
const result = service.analyzeTranscript(whisperWords, 'fast', 30)
// result.totalRemovedSec, result.edits (TimelineEdit[])
// Store-based workflow
const store = useSmartCutStore.getState()
await store.analyzeAudio(audioBlob, wordTimestamps)
// Review regions, toggle as needed, then:
store.applySmartCut()