Build Screen Studio
A recorder that captures the screen flat while writing a separate high-frequency cursor and click track, then generates smooth zoom keyframes from that track in post, applies padding, rounded corners and a background, and renders a finished video you never had to edit by hand.
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 if you already own a Mac
Why ScreenCaptureKit needs 12.3 as a floor, and the composite pipeline is GPU work. An old integrated GPU will export slower than real time.
Get it Apple menu, then About This Mac.
Verify
About This Mac reports macOS 13 or higher - installfree
Why Builds the app and provides Instruments, which you will need when the export is slow.
Get it Mac App Store or developer.apple.com/xcode. open ↗
Verify
xcodebuild -version prints 16 or higher - decidefree
Why Screen Recording is required to capture at all. Microphone is optional and only for narration.
Get it System Settings, then Privacy and Security. Both must be re-granted during development whenever the binary changes signature or path.
Verify
A test capture returns pixels rather than a black frame - have readyfree
Why The thresholds in Phase 2 cannot be chosen in the abstract. You need a form being filled, a terminal session and a slow read to see where the generator over-triggers.
Get it Record them yourself before writing the detection code, and keep them as fixtures.
Verify
Three recordings with their cursor tracks are saved as test fixtures - account99 USD per year
Why Product phase only. Without it there is no notarization and a Gatekeeper warning on every other Mac.
Get it Enrol at developer.apple.com/programs. open ↗
Verify
A Developer ID Application certificate appears in Xcode settings
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- recordings(id, video_path, width, height, scale, fps, started_at, duration_ms) - cursor_samples(recording_id, t_ms, x, y) · sampled at a high fixed rate, independent of video frame rate - cursor_events(recording_id, t_ms, kind) · kind is click, drag_start, drag_end, keypress or scroll - keyframes(id, recording_id, t_ms, scale, center_x, center_y, easing) · generated in Phase 2, editable afterwards - projects(id, recording_id, padding, corner_radius, background_json, trim_start_ms, trim_end_ms) - The flat recording is never modified. Every effect is a function of the source plus the project row, which is what makes re-rendering at a different size free.
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 |
|---|---|---|---|
RECORDINGS_DIR | required | ~/Movies/ScreenStudio | Where flat recordings and project files are written. These are large, so pick a disk with room. |
CURSOR_SAMPLE_HZ | required | 120 | Cursor sampling rate. Must be well above the video frame rate or the motion looks stepped. |
ZOOM_MIN_INTERVAL_MS | required | 2500 | Minimum time between zoom-ins. Raising this calms a busy video. |
ZOOM_MIN_DWELL_MS | required | 600 | How long the cursor must stay in an area to count as intent. Lowering it makes the video restless. |
ZOOM_MAX_SCALE | required | 2.2 | How far in the automatic zoom will go. Beyond about two and a half the source pixels start to show. |
SPARKLE_FEED_URL | optional | https://example.com/appcast.xml | Product phase only. |
The build, in order
Record flat, and capture the cursor track
A plain recording exists alongside a dense, accurate record of where the cursor was and what it did.
SCStream configured for the display's real pixel dimensions. Write with AVAssetWriter, starting the session from the first video sample's timestamp.
Files
Recorder.swiftA high-rate timer reading the global cursor position, timestamped against the same clock as the video session. Log clicks with an event tap or a global monitor.
Files
CursorTrack.swiftRecord a deliberate click at a known screen position, then confirm the logged event timestamp matches the frame where the click is visible.
Files
test/alignment.md
done when · tick each as it passeswatch out- Do not apply zoom while recording. A zoomed recording throws away the pixels outside the zoom, so a badly chosen zoom is permanent and a re-render is impossible. Record everything, decide later.
- Sample the cursor far more often than the video frame rate. Sampling per frame gives you a stair-stepped path that produces visibly jerky motion once you smooth and amplify it.
Generating zoom from the track
The zoom keyframes are computed from what the cursor did, and they are good enough that you rarely touch them.
Cluster click events in time and space. Treat sustained dwell within a small radius as intent too, because reading and typing matter as much as clicking.
Files
Intent.swiftZoom in slightly before the action so the viewer arrives with it, and hold briefly after so the result is visible before pulling out.
Files
Keyframes.swiftA minimum interval between zooms, a minimum dwell to qualify, and a maximum zoom rate. These three numbers are the whole feel of the product.
Files
Keyframes.swift
done when · tick each as it passeswatch out- Following the cursor continuously produces motion sickness. The cursor moves constantly and most of that movement means nothing. Zoom on intent, which is clicks and sustained dwell, not on position.
Easing and framing
The motion looks designed rather than computed, and the frame never shows the edge of the source.
Ease in and out between keyframe pairs. Compare against linear side by side once; you will not go back.
Files
Easing.swiftCompute the visible rectangle at the current scale and clamp its centre so the rectangle stays inside the source. Test the corners explicitly.
Files
Framing.swiftA Core Image pipeline: scale and translate the source, round the corners, and draw over a background colour or gradient.
Files
Composite.swift
done when · tick each as it passeswatch out- Clamp the centre point, not the offset. Clamping after computing the offset lets the frame drift past the edge of the source at high zoom levels and shows background where video should be, usually at exactly the moment of most interest.
Rendering and export
The finished video comes out at the size you asked for, and rendering is not slower than watching.
One Metal-backed CIContext reused across frames. Creating a context per frame is the single most common reason exports crawl.
Files
Renderer.swiftNamed presets with fixed pixel sizes. Assert the output dimensions rather than trusting the scale arithmetic.
Files
Presets.swiftPass the original audio track through rather than re-encoding it, and confirm sync at the end of a long export.
Files
Renderer.swift
done when · tick each as it passeswatch out- Compositing on the CPU makes a two minute recording take longer than two minutes to export, which turns a pleasant tool into an errand. Keep the pipeline on the GPU through Core Image with a Metal-backed context, and measure the export against real-time before adding any more effects.
Trim and manual correction
The one zoom the generator got wrong takes ten seconds to fix.
Video thumbnails, click markers and keyframe handles on one scrubbable track.
Files
Timeline.swiftDrag to move, delete, insert. Preview updates from the source, which is why nothing was baked in.
Files
Timeline.swiftMark keyframes as generated or manual, and warn before regeneration discards manual ones.
Files
Keyframes.swift
done when · tick each as it passeswatch out- Automatic generation will be wrong occasionally, and a tool with no manual override forces a re-record for a five second mistake. The keyframes are data, so make them editable from the beginning rather than treating generation as final.
Signing, notarization and updatesproduct builder
Other people can install it and receive fixes.
Hardened runtime, Developer ID, notarytool, stapler. Confirm the usage description strings are present or the prompts never appear.
terminalxcrun notarytool submit Studio.zip --keychain-profile AC --wait xcrun stapler staple Studio.app
EdDSA key pair, private half outside the repository, appcast over HTTPS.
Files
appcast.xmlWhich permission enables which feature, and what refusing each one costs.
Files
README.md
done when · tick each as it passeswatch out- Signing invalidates the Screen Recording grant testers gave the unsigned build, and macOS will not prompt again. Say so in the release notes with the removal steps.
That is the whole plan for Screen Studio. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- The tuned motion design judgement of the commercial product.
- Hosted sharing, links and viewer analytics.
- Camera overlay with background removal.
- Multi-track video editing.
- exceptional macOS capture polish, motion design, and ongoing compatibility
- instant hosted sharing
- viewer analytics
- team libraries
- cross-device capture
- Keystroke overlays generated from the event track you are already recording
- Automatic silence trimming using the audio track
- A vertical export preset that reframes around the cursor rather than letterboxing
Need the files? The project pack on the verdict page hands your agent the whole brief · more screen recording.