A native macOS screenshot & screen-recording tool, built from scratch in Swift.
UX inspired by CleanShot X — original code, not a fork.
Menu-bar app (no Dock icon). Everything is driven from the menu-bar
Sicon and global hotkeys.
- Capture — full screen, drag-to-select region, scrolling capture (image stitching + Accessibility scroll-offset), and text capture (Vision OCR).
- OCR result window — recognized text next to the captured image, editable, with QR code detection and one-click translation into 24 languages via Apple's on-device Translation framework (no API key, works offline once the language pack is downloaded).
- Smart region selection — the screen freezes the instant you hit the hotkey (so nothing under the overlay can change, and apps never lose their focused state), with a pixel loupe, window snapping, and item snapping: hover to outline the button / card / panel under the cursor and click to grab it. Hold
⌥for a free selection, or hold⌘while dragging over a table to take the whole rows it touches, edge to edge. - Color picker — freeze the screen and magnify it 12× to land on the exact pixel (arrow keys nudge one pixel at a time), then click to copy as HEX,
rgb(),hsl(), SwiftUIColororNSColor—←/→switches format without leaving the picker. - Screen recording — record a region to
.mov, with pause/resume, restart, and discard. Optionally captures system audio and the microphone as two separate tracks (mute the mic mid-take from the recording bar), and quietly logs every click so the editor can turn them into zooms. - Annotation editor — shapes, text, arrows, numbered step counters, and a blur tool for hiding anything you don't want in the shot (drag a box; the stroke-width control doubles as blur strength); zoom via buttons,
⌘ +/-/0, and trackpad pinch. Select a layer and press⌫to drop it, or pick a new colour / stroke width to restyle it in place.⎋backs out one step at a time — text field, selection, then the editor itself. - Redact — the editor reads the screenshot the moment it opens and counts what it can see: emails, phone numbers, card numbers (Luhn-checked) with their CVV, expiry date and cardholder name, API tokens, labelled passwords/OTPs, and ID/SSN/passport numbers. Anything that needs a label to be meaningful (a bare
231is not a CVV) is only matched next to one, and names are only touched on an image that already has card data on it. Press Redact and each one gets its own solid black box — sized to the string, not the whole line. A box, not a blur: blur is still the original pixels transformed, a flat fill means what was underneath isn't in the exported file at all. Nothing is touched until you press it,⌘Ztakes the whole batch back out, and a false positive goes away with Select +⌫. Vision OCR on-device; the image never leaves the Mac. - Stickers — drop a folder of images into
~/Library/Application Support/SlopShot/Stickers/(or use Import) and every folder becomes a pack. Animated stickers work: GIF, APNG, animated WebP, and the horizontal sprite sheets Zalo ships. Put one on a still screenshot and the editor plays it live — Copy, Share and Save then hand you an animated GIF instead of a flattened frame. - Sticker store — packs are downloaded on demand, not bundled: Get packs in the sticker popover lists what is on the CDN with a cover, sticker count and size, and pulls the one you pick (checksum-verified) straight into your library. Keeps the app a few MB instead of a few hundred. It is only static files behind an R2 bucket — point it somewhere else with
defaults write com.thanglb.slopshot stickerStoreURL "https://…", and publish your own withtools/publish_packs.swift. - Floating preview card — Copy / Save / Share / Pin, drag-out to other apps.
- Video editor — Quick Look (in-app player) plus a full editor built around a lane-based timeline: trim handles on a filmstrip, cut stretches out of the middle, speed ramps (0.25×–10×), freeze frames, eased zoom, blur/pixelate censor regions, and text captions. Press a tool and the effect drops in at the playhead — drag the pill along its lane to move it, its edges to stretch it, and the box straight on the video to aim it. Two effects on the same lane can never overlap: they stop against each other, or slide to the nearest gap. Auto Zoom turns the clicks you made while recording into zoom-ins in one press. Preview and export share one Core Image composition, so what you see is exactly what lands in the file. Exports MOV / MP4 / GIF with separate Quality, Resolution and FPS controls (a plain trim still takes the lossless passthrough path).
- Searchable capture history — every screenshot is OCR'd in the background, so the history window is searchable by what is written inside the picture: type
staging.envor an error message and the shot comes back. The last 100 captures are kept; a row whose temp file the OS has since swept still keeps its thumbnail and its text. - Settings and configurable global hotkeys — plus a permissions list (Screen Recording, Accessibility) with live status and a button straight to the right System Settings pane, since macOS only ever asks once and a mis-clicked Deny is otherwise silent and unrecoverable from inside the app.
brew trust aislopware/tap # Homebrew 6+ gates third-party taps
brew install --cask aislopware/tap/slopshotbrew trust exists from Homebrew 6 on; older versions print "Unknown command" and install
fine without it. Later, brew upgrade swaps in the new version and SlopShot reopens itself.
Universal (Apple Silicon + Intel), macOS 15+. The DMG is signed with a Developer ID and
notarized by Apple, and the ticket is stapled to the .app itself — so the first launch
works offline, with no right-click-Open dance. Or grab the DMG from
Releases and check it against the
SHA256SUMS attached to the same release.
Download slopshot_<version>_amd64.deb (or _arm64.deb) from
Releases and install it with apt, which
pulls in the dependencies:
sudo apt install ./slopshot_*_amd64.debA separate app in Rust + GPUI (linux/) with the same features —
capture, recording, scrolling capture, OCR, history, the annotation editor with stickers and
GIF export, a tray icon and the same settings — except translation, which is macOS-only for
now. Run slopshot once
(or enable Launch at login in its Settings): on GNOME it registers Ctrl+Alt+1 / 2 / 5
as system shortcuts, since GNOME has no portal for global hotkeys yet. On first launch
SlopShot asks for the screenshot permission: click Continue, then Allow in GNOME's
"Allow SlopShot to take screenshots?" prompt (Enter selects Deny). The tray icon needs the
AppIndicator extension, which Ubuntu ships enabled.
Swift · SwiftUI · AppKit · ScreenCaptureKit · AVFoundation / AVKit · Vision (OCR) · CoreGraphics/CoreText · XcodeGen
Requires Xcode (macOS 15+ SDK) and XcodeGen (brew install xcodegen).
make run # build Debug + launch
make install # build Release → sign → copy to /ApplicationsThe Makefile auto-detects the signing identity, so a fresh clone just works:
- if a self-signed certificate named
SlopShot Devexists in your Keychain, it's used (this keeps the macOS Screen-Recording / Accessibility permissions across rebuilds); - otherwise it falls back to ad-hoc signing (
-) — builds and runs fine, but the permissions reset on each rebuild. For a one-time install that's a non-issue.
Override anytime: make install SIGN_ID="Your Identity".
Optional (to keep permissions stable across rebuilds): create a self-signed Code Signing
certificate named SlopShot Dev in Keychain Access → Certificate Assistant →
Create a Certificate….
The app is not sandboxed. A locally-built app has no quarantine flag, so Gatekeeper lets it run without warnings — the Developer ID signing and notarization above only apply to the DMGs cut by the release pipeline.
Commit subjects are conventional commits, enforced by a commit-msg hook — the version
number and the whole of CHANGELOG.md are generated from them, so a subject outside the
grammar contributes to neither:
brew install prek git-cliff
make hooks # installs the pre-commit + commit-msg hooksfeat(stickers): download packs on demand instead of bundling them
fix(timeline): keep two effects on one lane from overlapping
Cutting a release is make release-preview → make release → push the tag; CI then builds
universal, signs, notarizes, publishes the GitHub Release and bumps the Homebrew cask. The
whole thing — including how the signing material is fetched without ever touching a log —
is written up in docs/release-pipeline.md.
The logo (an S inside viewfinder crop-corners) is generated programmatically — no image files:
swift tools/make_icon.swift # regenerates AppIcon + the menu-bar templateEverything under tools/ operates on ~/Library/Application Support/SlopShot/Stickers/,
one folder per pack. The order matters — enlarge first, compress second:
./tools/fetch_zalo_pack.sh --range 43516 43531 "Ami Bụng Bự" # animated sprite sheets off the CDN
xcrun swift tools/upscale_stickers.swift "Ami Bụng Bự" # 130px → 384px, keeps every frame
xcrun swift tools/webp_stickers.swift "Ami Bụng Bự" # → animated WebP, ~7× smaller
xcrun swift tools/publish_packs.swift --upload r2:my-bucket # zip + covers + packs.json → CDNpublish_packs.swift writes .work/store/ (a zip and a cover per pack, plus a packs.json
manifest with a SHA-256 for each), then rclone syncs it to any S3-compatible bucket. That
is the whole backend — the app reads packs.json and downloads a zip. Uploading needs an
rclone remote:
rclone config create r2 s3 provider=Cloudflare region=auto \
access_key_id=… secret_access_key=… \
endpoint=https://<account-id>.r2.cloudflarestorage.comPersonal learning project. Provided as-is.