Build ScreenFlow
A local screen recorder whose hard problems are capturing through the supported framework with permission handled properly, writing the take to disk continuously so a crash never destroys it, and keeping variable rate screen frames in step with a microphone over a long recording.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- have readyfree if you have one
Why The permission flow, the picker and the capture framework are the first phase, and none of it can be tested anywhere else.
Get it Any supported Mac, with the ability to change privacy settings.
Verify
A trivial capture helper records five seconds of the screen - installfree
Why The capture helper is native, and the toolchain download is large enough to be worth starting before you need it.
Get it Install Xcode or the command line tools from Apple. open ↗
Verify
swiftc --version prints a version - installfree
Why Assembly, trimming and export all shell out to it, and ffprobe is how you verify timestamps and drift.
Get it Your package manager, or a static build from the official downloads page. open ↗
Verify
ffmpeg -version and ffprobe -version both print a version - have readyfree
Why Drift, disk growth and crash recovery all behave perfectly on a two minute clip and reveal themselves only on a long one.
Get it Record yourself working for half an hour with a clap at the start and the end.
Verify
The clap appears at the same moment in both tracks at both ends - decidefree
Why This tool writes gigabytes without being asked, and deciding the limits after filling a disk means deciding them under pressure.
Get it Write down the minimum free space to start recording and how long segments survive a successful export.
Verify
Both are in the environment and enforced in code
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- recordings(id, started_at, ended_at, source_kind, state, segments_dir, bytes, recovered_from_crash) - segments(recording_id, ordinal, path, start_pts_ms, end_pts_ms, bytes, sealed_at) · written as they arrive and sealed as they close - tracks(recording_id, kind, device_name, sample_rate, channels, first_pts_ms) · screen, microphone and system audio each carry their own clock - projects(id, name, folder, created_at) · media referenced by relative path, so the folder can be moved or copied - edits(project_id, ordinal, recording_id, in_ms, out_ms, track_kind) · an edit list, never a rewritten source - exports(id, project_id, preset, path, settings_json, bytes, started_at, finished_at, exit_code) · the settings that produced the file, kept with it - No operation in this model modifies a source recording, which is the only reason a mistaken trim at midnight is survivable.
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 |
|---|---|---|---|
DATABASE_PATH | required | ./data/recorder.db | Recordings, segments, edits and exports. |
PROJECTS_DIR | required | ~/Movies/Recordings | Project folders holding media. Referenced relatively so they can move. |
CAPTURE_HELPER_PATH | required | ./helper/build/CaptureHelper | The native helper. Without it there is no capture at all. |
FFMPEG_PATH | required | /opt/homebrew/bin/ffmpeg | Assembly, trimming and export. |
SEGMENT_SECONDS | required | 5 | How much of a take a crash can cost. Smaller is safer and slightly busier. |
MIN_FREE_BYTES | required | 10000000000 | Recording refuses to start below this and stops cleanly if it is reached. |
SEGMENT_RETENTION_DAYS | required | 14 | After a successful export only. The cleanup reports what it removed. |
The build, in order
Capture through the supported path
Recording starts only after permission is granted, through the system's own picker.
One small process with one job, talking to the rest over a local socket.
Files
helper/Capture.swiftsrc/capture/client.pyA missing description string is a silent denial at the worst moment.
Files
helper/Info.plistLess code, fewer prompts, and the sources the person actually expects.
Files
helper/Picker.swift
done when · tick each as it passeswatch out- Building your own window list and capturing through the older CoreGraphics calls still works today, prompts the person with warnings about software that can collect detailed information about them, and is the path Apple is closing; it also breaks quietly after an update nobody chose. Use ScreenCaptureKit with the system picker, and handle a denied permission as a first class state.
A take that survives the process dying
Whatever was recorded before a crash is still on disk and playable.
A few seconds each; the cost is negligible and the insurance total.
Files
src/capture/segments.pyThe recovery path is the feature, so it runs automatically.
Files
src/recover.pytests/test_recover.pyRefusing to start beats stopping at minute fifty.
Files
src/disk.py
done when · tick each as it passeswatch out- Buffering the take and muxing one file when the person presses stop means a crash, a forced restart or a full disk at minute fifty destroys the entire recording, which is the single thing this kind of tool must never do. Seal a segment every few seconds and make a crashed session recoverable from what is already on disk.
Picture and sound that stay together
A long recording is still in sync at the end.
Never recompute a time from a frame index.
Files
src/capture/segments.pysrc/assemble.pySeparate clocks, aligned at assembly, not merged at capture.
Files
src/audio.pyA number in the test output, not a feeling while watching.
Files
tests/test_drift.py
done when · tick each as it passeswatch out- Assuming a constant frame rate is safe because screen capture reports one is how a forty minute tutorial ends up with the mouse click arriving a second before the sound: the capture delivers frames when the screen changes, so the frame count and the wall clock disagree more the longer you record. Keep the timestamps from capture and assemble against them.
Trimming without re-encoding everything
Cutting the dead air off the front takes seconds and costs no quality.
The timeline is data and the file is evidence.
Files
src/edits.pyRe-encode the boundary pieces only, and say when you had to.
Files
src/export/trim.pyOne test that makes the whole model true.
Files
tests/test_source_untouched.py
done when · tick each as it passeswatch out- Re-encoding a twenty minute recording to remove two seconds at the front costs a long wait and a generation of quality every time somebody changes their mind, which they will, four times. Store an edit list, copy the stream where keyframes allow, and re-encode only the pieces at the boundaries.
Disk, cleanup and a project you can carryproduct builder
The tool does not fill the disk and a project folder still opens somewhere else.
Absolute paths are what stop a project from moving.
Files
src/projects.pyAfter, and only after, the export exited cleanly.
Files
src/retention.pySo a file can be reproduced rather than remembered.
Files
src/export/presets.py
done when · tick each as it passeswatch out- Segments accumulating in a temporary directory forever is how a screen recorder quietly consumes two hundred gigabytes, and the person discovers it when the disk is full during the recording they actually needed. Apply a retention after a successful export, report the bytes removed, and show current usage in the interface.
That is the whole plan for ScreenFlow. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Multitrack compositing, transitions and titles.
- Stock media libraries.
- Hosted upload and sharing.
- Camera compositing and keying.
- production codecs, rendering speed, and media templates
- hosted recording reliability
- large-scale rendering
- distribution and podcast hosting
- professional codecs, effects, and collaboration
- Cursor emphasis and click highlighting, which is a compositing pass over an existing timeline
- Automatic silence detection to suggest cuts, once the edit list has proven itself
- A second export preset tuned for a specific destination, with its settings recorded like the first
Need the files? The project pack on the verdict page hands your agent the whole brief · more screen recording.