How Screen Capture and Recording Functionality Is Implemented in Vorssaint-utils
Vorssaint-utils implements screen capture and recording through two tightly-coupled Swift services: ScreenCaptureService routes all screenshot-style tools while ScreenRecorderService manages asynchronous video sessions with system audio capture and disk-space monitoring.
Vorssaint-utils is an open-source macOS utility library that unifies screenshot, OCR, color picking, and screen recording capabilities under a permission-first architecture. The implementation separates UI coordination from media engine management, allowing consistent region selection across static captures and video recordings.
Architecture of the Core Services
The codebase organizes functionality into distinct service layers defined in Sources/Vorssaint/Services/.
ScreenCaptureService acts as the unified entry point for all capture-related tools. Located in Sources/Vorssaint/Services/QuickTools/ScreenCaptureService.swift (lines 31-78), this singleton handles hot-key registration via QuickToolHotkey, permission checks, countdown timers, and the ScreenshotSelectionController UI. It routes user selections to downstream processors like ScreenshotService, ScreenTextService, or ScreenRecorderService.
ScreenRecorderService manages the complete lifecycle of a screen-recording session. Found in Sources/Vorssaint/Services/Recorder/ScreenRecorderService.swift (lines 43-78), this service validates prerequisites, creates recording sessions, drives the video engine, and handles audio routing. It monitors disk space, implements pause/resume logic, and persists the final MOV file.
RecorderSession is an inner class of ScreenRecorderService defined in the same file (lines 24-42). It encapsulates a single recording by instantiating the RecorderWriter, starting the RecorderCaptureEngine, collecting audio samples, and capturing pointer and typing data. The session handles unexpected stops and microphone unavailability before finalizing the output file.
Capture Workflow for Screenshots and OCR
The static capture implementation follows a five-stage pipeline orchestrated by ScreenCaptureService.
Hot-Key Registration and Permission Validation
When a user triggers a capture tool, ScreenCaptureService receives the event through hot-keys registered during its init. The service immediately verifies screen-recording permissions via Permissions.shared.requestScreenRecording(). For the color picker tool, it falls back to a native color-sampler path that requires fewer permissions.
Countdown and Selection UI
If the user configures a delay, ScreenCaptureService starts a countdown via tickCountdown that updates the floating QuickToolHUD.showCountdown. Once the countdown completes, the service instantiates a ScreenshotSelectionController with specific policies: freeze screen state, include or exclude the pointer, and hide Vorssaint's own windows from the selection.
Routing Logic
Upon region confirmation, ScreenCaptureService.route(_:selected:recorderAudio:) dispatches the result to the appropriate handler:
.captured→ Forwards toScreenshotServicefor standard screenshots orScreenTextServicefor OCR processing..region→ Initiates video recording by callingScreenRecorderService.record(region:audioOptions:)..color→ InvokesColorSamplerServiceto sample the pixel value.
Recording Workflow Implementation
Video capture follows an eleven-step asynchronous process managed by ScreenRecorderService.
Session Preparation and Validation
The entry point toggle() triggers prepareForSelection(), which performs three checks before recording:
- Feature availability via
AppFeature.screenRecorder.isAvailable. - Permission state for screen recording, accessibility, and microphone access.
- Disk space sufficiency via
RecorderSupport.canStart.
If a countdown is configured in DefaultsKey.recorderCountdown, prepareCountdown displays the HUD each second until recording begins.
Engine and Audio Initialization
beginRecording(region:generation:) creates a new RecorderTakeStore.Take, reads user preferences (frame rate, audio options), and instantiates a RecorderSession. Inside RecorderSession.start(), the service launches the RecorderCaptureEngine and initializes audio sources:
- System audio via
RecorderSystemAudioTap(preferred) or stream output fallback. - Microphone capture via
RecorderMicrophoneCaptureifDefaultsKey.recorderMicrophoneis enabled.
The session monitors writesTapAudio and streamHeard to verify audio integrity and switch sources if the tap fails.
Input Sampling and UI Indicators
During recording, RecorderPointerSampler tracks mouse movement and RecorderTypingSampler captures typed characters. These data streams are saved alongside the video track.
A floating RecorderIndicator displays elapsed time and pause/stop controls. The indicator excludes its own window from capture via indicator.excludedWindowNumbers to prevent UI artifacts in the final recording.
Pause, Resume, and Disk Monitoring
The service delegates pause/resume logic to RecorderPauseClock to freeze elapsed time accurately. A background task checkDiskSpace periodically queries available storage; if space runs low, the recording stops automatically with a HUD warning.
Finalization
Calling stop() cancels the capture engine, flushes the RecorderWriter, writes pointer and typing tracks, and invokes deliver(_:,reason:) to either open the editor or save directly to the user-configured saveDestination.
Key Architectural Concepts
- Singleton pattern: Both
ScreenCaptureService.sharedandScreenRecorderService.sharedprovide global access points observed by the UI layer, includingScreenRecorderSettingsviews and radial menus. - Separation of concerns: The
ScreenshotSelectionControllerUI component is reused across screenshots, OCR, color picking, and recording, whileRecorderSessionisolates video-specific logic. - Asynchronous design: Recording start and stop are
asyncoperations executing on background queues (writerQueue, global utility queue) to maintain UI responsiveness. - Permission-first approach: All entry points verify screen-recording, accessibility, and microphone permissions before accessing system resources, requesting authorization only when needed.
- Pluggable audio architecture: System audio capture prefers the
AudioTapimplementation but falls back to stream output; microphone capture remains optional and user-configurable.
Practical Implementation Examples
import Vorssaint
// Toggle recording start/stop from a global shortcut
ScreenRecorderService.shared.toggle()
// Capture a screenshot with a 2-second delay
ScreenCaptureService.shared.capture(initial: .screenshot)
// Programmatically record a specific region with system audio only
let region = RecorderSupport.Region(
displayID: 12345,
origin: .zero,
pixelSize: CGSize(width: 1280, height: 720)
)
let audioOpts = RecorderSelectionAudioOptions()
audioOpts.systemAudio = true
audioOpts.microphone = false
ScreenRecorderService.shared.record(region, audioOptions: audioOpts)
// Pause or resume from UI callbacks
ScreenRecorderService.shared.togglePause()
Summary
- Dual-service architecture:
ScreenCaptureServicecoordinates static captures whileScreenRecorderServicehandles video lifecycle management. - Unified selection UI: The
ScreenshotSelectionControllersupports screenshots, OCR, color picking, and recording through policy-based configuration. - Permission-first validation: All workflows check
Permissions.sharedbefore accessing screen-recording or microphone resources. - Asynchronous recording:
RecorderSessionmanages theRecorderCaptureEngine, audio taps, and input samplers on background queues. - Resilient audio handling: The system verifies tap functionality via
writesTapAudioandstreamHeard, falling back to stream capture when necessary. - Runtime monitoring: Disk-space checks and pause/resume functionality ensure reliable long-form recordings.
Frequently Asked Questions
How does Vorssaint-utils handle missing screen recording permissions?
The framework checks permissions at every entry point using Permissions.shared.requestScreenRecording(). If authorization is missing, the service prompts the user before instantiating the capture UI or starting the RecorderCaptureEngine.
Can the screen recorder capture both system audio and microphone input simultaneously?
Yes. ScreenRecorderService initializes both a RecorderSystemAudioTap for system audio and a RecorderMicrophoneCapture for microphone input when DefaultsKey.recorderMicrophone is enabled. The RecorderSession writes both streams to the MOV file while monitoring audio integrity.
How is the region selection UI reused between screenshots and video recording?
The ScreenshotSelectionController accepts policy parameters that define behavior for freezing the screen, showing the pointer, and hiding Vorssaint windows. ScreenCaptureService instantiates this controller for all tools, routing the resulting region to either ScreenshotService or ScreenRecorderService.record(region:audioOptions:) based on the selected tool type.
What triggers automatic stopping of a recording?
A background task checkDiskSpace monitors available storage during the session. If disk space falls below the threshold defined in RecorderSupport.canStart, the service calls stop() automatically and displays a warning HUD to prevent data loss from insufficient storage.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →