Build Descript
KINDAreplaces $24/mosaves $288/yrback to the verdict
A tool that transcribes media with word-level timestamps, presents the transcript as the editing surface, turns text deletions into a cut list, plays back the edit without rendering, and only renders through ffmpeg when you export.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the build and the desktop shell.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - installfree
Why Conversion for transcription and the final render both go through it.
Get it brew install ffmpeg, your package manager, or a static build. open ↗
Verify
ffmpeg -encoders lists libx264 - installfree, but transcription takes real time on your machine
Why Word-level timestamps are the mechanism. Without them there is no product here.
Get it Build whisper.cpp and download a model. Confirm the word timestamp output before building anything on it. open ↗
Verify
Output contains per-word start and end times - have readyfree
Why Sync drift, caption timing and speaker handling only reveal themselves at length and with more than one voice.
Get it Use your own recordings. One over ten minutes and one conversation.
Verify
Both are available and their durations recorded - have readyfree
Why Every export writes a new file and every source needs a converted audio copy for transcription.
Get it Estimate several times your source size and check free space.
Verify
Free space comfortably exceeds the estimate
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- media(id, path, kind, duration_ms, sample_rate, has_video, content_hash) - words(id, media_id, ordinal, text, start_ms, end_ms, confidence, speaker) · the editing surface - cuts(id, media_id, start_ms, end_ms, reason) · reason is manual, filler or silence - speakers(media_id, label, display_name) - projects(id, name, media_ids_json, created_at) - A cut is a range, never a modification. The source file is read-only for the life of the project.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
WHISPER_MODEL_PATH | required | ./models/ggml-base.en.bin | The transcription model. Larger is more accurate and slower. |
OUTPUT_DIR | required | ./exports | Where renders are written. Never the source directory. |
CUT_PAD_MS | required | 40 | How far a cut extends into surrounding silence, to avoid clicks at the edit. |
SILENCE_THRESHOLD_DB | required | -35 | Level below which audio counts as silence for detection. |
SILENCE_MIN_MS | required | 600 | Minimum silence length before it is proposed as a cut. A pause is not a silence to remove. |
FILLER_WORDS | required | um,uh,like,you know | The filler list, editable because it is language and speaker specific. |
The build, in order
Word-level timestamps
Every word in the transcript knows exactly when it was said.
Mono 16 kHz 16 bit is what whisper.cpp expects. Convert from the source rather than feeding it the original.
terminalffmpeg -i source.mp4 -ar 16000 -ac 1 -c:a pcm_s16le audio.wav
Explicitly. Segment level is the default and it cannot support this product.
Files
src/transcribe.tsterminalwhisper-cli -m models/ggml-base.en.bin -f audio.wav --output-json-full
Pick a word from the middle of a sentence, play its range, and listen. This is the test that matters.
done when · tick each as it passeswatch out- Segment-level timestamps are the default in most transcription output and they are useless here, because a segment is a sentence and you need to cut a word. Enable word-level output explicitly and check the result, since a segment timestamp will look plausible in the data and fail the moment you cut.
Deleting text, deleting time
Selecting words and pressing delete produces a cut range, and the transcript reflows.
Words as spans with their timestamps attached. Selection maps to a time range.
Files
src/editor.tsA deletion becomes a range. Adjacent or overlapping ranges merge, or the cut list grows without bound.
Files
src/cuts.tsExtend slightly into the gap between words. Flag cuts with no gap available.
Files
src/cuts.ts
done when · tick each as it passeswatch out- Cutting exactly at word boundaries clips the natural gap between words and produces an audible click at every edit. Extend each cut slightly into the surrounding silence, and where two words are contiguous with no gap, accept the tighter cut and flag it as likely audible.
Preview without rendering
You hear the edit immediately, without waiting for anything to encode.
On approaching a cut, seek to its end. Keep a small lookahead so the seek is issued before the boundary.
Files
src/preview.tsHighlight the current word. This is also how you notice alignment problems.
Files
src/preview.tsSeveral short cuts in a row must not produce several audible seeks. Merge the playback plan rather than seeking repeatedly.
Files
src/preview.ts
done when · tick each as it passeswatch out- Rendering a preview after every edit makes the tool useless, because editing is a hundred small changes and each render is seconds. Skip ranges during playback instead: seeking is instant and the result is close enough to judge the edit.
Filler words and silences
The obvious cleanup is one action, and you can see exactly what it will remove.
A configurable list. Language and speaker specific, so make the list editable rather than fixed.
Files
src/fillers.tsThreshold and minimum duration, both settings. A pause is not a silence to remove.
Files
src/silence.tsterminalffmpeg -i audio.wav -af silencedetect=n=-35dB:d=0.6 -f null -
Review with counts, bulk accept as one undoable action, and remembered rejections.
Files
src/proposals.ts
done when · tick each as it passeswatch out- Removing every detected filler makes speech sound unnaturally clipped, because some hesitations carry meaning and rhythm. Propose rather than apply, show the count, and let a bulk accept be a deliberate action rather than a default.
Rendering the export
The exported file matches the preview, including the video.
Trim and concatenate kept ranges in one ffmpeg invocation for both streams.
Files
src/render.tsTwenty cuts in a ten minute file, checked at the end. Drift accumulates and only shows at length.
Output alongside, checksum the source before and after as a test.
Files
src/render.test.ts
done when · tick each as it passeswatch out- Trimming video at a non-keyframe produces either a frozen frame or a re-encode of the whole file, and doing this per cut with many cuts is very slow. Concatenate trimmed segments through a filter graph in one pass rather than cutting and joining files, and accept that a full re-encode is the honest cost of frame-accurate cuts.
Speakers, captions and formatsproduct builder
Multi-speaker recordings are usable and the output carries its transcript.
Labels applied to word ranges, correctable by hand since automatic assignment will be imperfect.
Files
src/speakers.tsAgainst the edited timeline, not the original. Check a caption near the end of a heavily cut file.
Files
src/captions.tsAudio only and a vertical crop. Both reuse the same cut list.
Files
src/exports.ts
done when · tick each as it passeswatch out- Caption timings computed from the original transcript will be wrong after any cut, because every subsequent word has moved earlier. Recompute timings against the edited timeline, and verify by checking a caption near the end of a heavily edited file.
That is the whole plan for Descript. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- A polished nonlinear editor with layers and transitions.
- Voice cloning and generated corrections.
- Real-time collaborative editing.
- The workflow polish of the commercial product.
- polished nonlinear editor
- overdub/voice tools
- filler-word workflows
- templates
- cloud collaboration
- rendering reliability
- Automatic speaker diarisation to seed the labels you then correct
- A word-level search across a library of transcripts
- Chapter markers derived from the edited transcript
Need the files? The project pack on the verdict page hands your agent the whole brief · more audio & video.