Halo
A native macOS menu bar app that records the screen and a live webcam bubble, composited in real time on the GPU, with zero third-party dependencies and zero network calls.
- Tech
- Swift, SwiftUI, AppKit, ScreenCaptureKit, AVFoundation, Metal
- Date
- Jul 26 to 30, 2026
- Status
- In Development
- Links
- Repository ↗
Loom is the default screen recorder for developer demo videos, but it's Electron and pushes recordings to the cloud by default. Native alternatives with the same webcam-bubble compositing, ScreenStudio, CleanShot X, exist but are closed source. I built Halo, a native macOS menu bar app that records the screen and a circular webcam overlay simultaneously, composites them in real time on the GPU, and writes a single local file, with zero third-party dependencies and zero network calls anywhere in the capture path.
Architecture
Compositing Pipeline
Screen capture (ScreenCaptureKit), camera capture, and microphone/system audio capture (AVFoundation) each run on their own independently clocked queue. Rather than compositing on every frame as it arrives, which would let a variable-rate screen feed and a fixed 30fps camera feed drift apart, each source drops its latest frame into a single-slot handoff buffer, and a fixed-rate render tick pulls whatever's currently sitting in both slots and composites them through a custom Metal shader pipeline into a circular bubble over the screen capture. The composited frame goes to a single AVAssetWriter, confined to one serial queue so it's never touched from two threads at once.
Audio Mixing
Microphone and system audio are independently clocked too. Instead of appending buffers at a write head, which lets small rate mismatches compound into permanent drift, each converted buffer is placed at its exact computed time offset into a flat accumulation buffer and summed with whatever's already there. A late-arriving buffer has its overlapping portion discarded rather than corrupting the mix, and a size cap prevents unbounded memory growth if the writer ever stalls.
Technical Challenges
Building on ScreenCaptureKit and AVFoundation surfaced a few sharp edges worth calling out. AVAudioConverter silently truncates and discards audio past a 4096-frame limit per call rather than erroring, so the mixer proactively slices any buffer that could exceed it. A single-entry CMSampleTimingInfo's duration field describes each individual sample's duration, not the whole buffer's, an easy mistake that would have stayed invisible in the output; catching it before it shipped meant reading the API's actual contract instead of assuming the obvious interpretation. And macOS keys Screen Recording and Camera permissions to an app's code identity, so an ad-hoc-signed dev build gets a new identity, and a fresh permission prompt, on every rebuild; the fix was a stable local signing certificate plus automatic detection and cleanup of stale permission records.
Other
- 100 unit tests across the recording, compositing, and timeline logic, none of which need camera or screen-recording hardware access to run.
- Guaranteed-playable output on every interruption path (disk full, display disconnect, permission revocation), rather than a corrupted or zero-byte file.
- Nearly 10,000 lines of Swift with zero third-party dependencies, first-party Apple frameworks only.