Find your mouse cursor.
A menu bar utility for macOS that highlights the cursor when you lose it on a multi-display setup. Press a hotkey or double-tap a modifier key and the cursor position lights up. Requires macOS 13 or later.
brew install --cask dominion525/tap/dominion525-blip
Installing by the fully qualified name adds the tap and trusts that cask alone.
The releases carry the same app as a zip and a disk image for a manual install. Both are signed with a Developer ID certificate and notarized.
- macOS 13 or later on Apple Silicon (Intel Macs are not supported)
- Xcode (for xcodebuild and XCTest)
- XcodeGen (
brew install xcodegen), which generates Blip.xcodeproj from project.yml
./build.sh
open Blip.app
build.sh runs these steps.
- Generate Blip.xcodeproj from project.yml with XcodeGen. This happens on every build so new source files are picked up. Blip.xcodeproj is a build product and is not committed
- Build the Release configuration with xcodebuild and copy the resulting Blip.app to the repository root. Xcode takes care of Info.plist and the resource bundles
- Draw the app icon with Scripts/make-icon.swift, convert it to icns with Scripts/make-icns.sh, and bundle it. The bundle icon sits on a light gray rounded square; the About panel shows the drawing alone, black in light mode and white in dark mode
- Sign the app. A Developer ID Application certificate from the Keychain is used when present; otherwise the app is signed ad hoc. The CODESIGN_IDENTITY environment variable overrides the identity
CODESIGN_IDENTITY="Apple Development" ./build.sh
An ad hoc signature changes on every rebuild, so the Input Monitoring permission can become invalid after rebuilding. Signing with a certificate keeps the app identity stable.
The project can also be opened in Xcode: run xcodegen generate, then open Blip.xcodeproj.
./test.sh
There are two test suites. test.sh runs both.
- BlipCoreTests (
swift test): the AppKit-free logic (coordinate math, double-tap detection, effect timing, modifier key codes) - BlipTests (
xcodebuild test -scheme Blip): the app itself. Each effect is drawn into an offscreen bitmap and checked pixel by pixel; overlay window configuration and rebuilds, settings persistence, the settings window controls, the menus, the launch sequence, and the consistency of the string tables are covered. These tests run hosted by the app
Creating the event tap and obtaining the Input Monitoring permission depend on a grant the user makes in an OS dialog, so they are out of scope for the tests and are checked by hand. The decision that turns tap events into a double-tap is a pure function and is covered.
BlipCore coverage is measured with:
swift test --enable-code-coverage
xcrun llvm-cov report .build/debug/BlipCorePackageTests.xctest/Contents/MacOS/BlipCorePackageTests \
-instr-profile .build/debug/codecov/default.profdata -ignore-filename-regex='\.build/|Tests/'
Pushing a v* tag builds, notarizes, and publishes the app.
git tag v0.1.0
git push origin v0.1.0
The tag has to match MARKETING_VERSION in project.yml, or the workflow stops before building. The release carries two files, either of which opens on another Mac without Gatekeeper blocking it.
Blip-<version>.zip The app, packaged after its notarization ticket is stapled
Blip-<version>.dmg The same stapled app next to a link to Applications
The disk image is notarized and stapled in its own right, because the quarantine attribute lands on whichever file the browser downloaded.
The workflow then publishes the update: it signs the zip with the Sparkle key, appends an item to the appcast on the gh-pages branch, and writes the release notes beside it. That branch is served at https://blip.dominion525.com, which is where the app looks for updates. Last it bumps the Homebrew cask.
The workflow reads eight repository secrets.
Secret Contents
BUILD_CERTIFICATE_BASE64 Developer ID Application certificate exported as .p12, base64 encoded
P12_PASSWORD Export password of that .p12
KEYCHAIN_PASSWORD Any string; unlocks the temporary keychain on the runner
NOTARY_KEY_ID App Store Connect API key ID
NOTARY_ISSUER_ID App Store Connect issuer ID
NOTARY_KEY_P8_BASE64 The .p8 API key file, base64 encoded
SPARKLE_PRIVATE_KEY EdDSA private key that signs each update, exported with Sparkle's generate_keys
HOMEBREW_TAP_TOKEN Fine-grained token that can write to dominion525/homebrew-tap
The same steps run locally against a profile stored by xcrun notarytool store-credentials. Building the disk image needs create-dmg (brew install create-dmg), and drives Finder to lay out the volume window, so windows open and close while it runs.
./build.sh
NOTARY_KEYCHAIN_PROFILE=blip ./Scripts/notarize.sh
./Scripts/make-dmg.sh
NOTARY_KEYCHAIN_PROFILE=blip ./Scripts/notarize.sh Blip-<version>.dmg
Blip puts a cursor icon in the menu bar and does not appear in the Dock.
Menu item Action
Show Spotlight Show the effect now
Settings… Open the settings window (⌘,)
About Blip Open the About panel
Check for Updates… Look for a newer version now
Restart Blip Quit and launch again
Quit Blip Quit (⌘Q)
Two triggers show the effect; both are configured in the settings window.
- Hotkey (default ⌥⌘Z). Click the field and press the keys. A modifier plus a key, or a function key on its own, can be recorded
- Modifier double-tap (default Left Control). Choose from left or right Control, Shift, Option, and Command, or turn it off
The settings window also picks the effect and turns on launch at login.
The effect hides itself after 1.2 seconds. While visible it follows the cursor, and the apps underneath stay clickable. With several displays, the effect appears only on the display that contains the cursor and the others are dimmed.
Spotlight dims the screen and cuts a ringed hole around the cursor.
Zoom shrinks a hole the size of the screen onto the cursor.
Flash blinks the ring and spreads ripples out from the cursor.
Focus Lines points manga-style speed lines at the cursor and jitters them across three frames.
Blip watches for a newer version on its own, and Check for Updates asks right away. When one is out it shows what changed and offers to install it. The download is checked against the key the app carries before anything is replaced, and Blip restarts itself into the new version.
Installed with Homebrew instead? brew upgrade picks up new versions as well. Either route leaves
the app where it was, so the Input Monitoring permission and the login item carry over.
- The hotkey is registered through Carbon's RegisterEventHotKey (via the KeyboardShortcuts library) and needs no permission
- The modifier double-tap watches key events to tell left from right, which needs the Input Monitoring permission. The OS dialog appears on first launch; enable Blip under System Settings > Privacy & Security > Input Monitoring. Until then the double-tap does nothing and the settings window shows the state
- Showing the effect and reading the cursor position need no permission
The hotkey, the double-tap modifier, and the selected effect are stored in UserDefaults (com.dominion525.blip). Launch at login is registered with SMAppService and appears under Login Items in System Settings.
The display language follows the system setting (English and Japanese). It can be changed for Blip alone under System Settings > General > Language & Region > Applications.
Most values that are not in the settings window live in enum Config in Sources/Blip/main.swift. Edit them and run build.sh again. The intervals for re-checking the Input Monitoring permission live in Sources/Blip/ModifierTapMonitor.swift instead.
Name Default Meaning
spotRadius 55 Spot radius (pt)
dimOpacity 0.55 Opacity of the dim layer
ringColor yellow Ring color
ringWidth 4 Ring line width (pt)
autoHideSeconds 1.2 Seconds until the effect hides
trackingInterval 1/60 Cursor tracking interval (s)
zoomDuration 0.35 Zoom duration (s)
zoomOvershoot 0.15 Zoom overshoot as a fraction of the spot radius
flashBlinkPeriod 0.2 Flash blink period (s)
flashRingWidthScale 1.5 Ring width multiplier while the Flash ring blinks
flashRippleInterval 0.3 Ripple emission interval (s)
flashRippleLifetime 0.6 Ripple lifetime (s)
flashRippleMaxScale 3 Maximum ripple radius as a multiple of the spot radius
focusLinesCount 150 Number of focus lines
focusLinesInnerRadius 80 Clear radius at the center of the focus lines (pt)
focusLinesInnerJitter 30 Jitter of the focus line tips (pt)
focusLinesWidthRange 6...22 Width of the focus lines at the outer end (pt)
focusLinesFrameCount 3 Number of focus line animation frames
focusLinesFrameInterval 1/12 Focus line frame interval (s)
doubleTapInterval 0.3 Maximum time between the two taps (s)
Package.swift BlipCore package (AppKit-free logic) and BlipCoreTests
project.yml XcodeGen spec: the Blip app target, BlipTests, and the KeyboardShortcuts dependency
Sources/BlipCore/ Coordinate math, double-tap detection, effect timing (covered by tests)
Sources/Blip/main.swift Config, overlay window management, AppDelegate
Sources/Blip/EffectRenderer.swift Drawing for each effect
Sources/Blip/ModifierTapMonitor.swift Modifier double-tap monitor (event tap)
Sources/Blip/SettingsWindowController.swift Settings window
Sources/Blip/Settings.swift UserDefaults access
Sources/Blip/LoginItem.swift SMAppService wrapper for launch at login
Sources/Blip/Localization.swift String lookup
Sources/Blip/Info.plist Written by XcodeGen from the info: block in project.yml
Sources/Blip/Resources/ Localizable.strings (en / ja)
Tests/BlipCoreTests/ XCTest (swift test)
Tests/BlipTests/ XCTest (xcodebuild test, hosted by the app)
build.sh Assembles and signs Blip.app
test.sh Runs both test suites
Scripts/make-icon.swift App icon artwork (--plate for the background square, --dark for the white variant)
Scripts/make-icns.sh Converts a PNG into an icns
Scripts/make-dmg.sh Builds the disk image with create-dmg
Scripts/make-dmg-background.swift Background of the disk image window
Scripts/notarize.sh Submits the app or the disk image to the notary service and staples the ticket
Scripts/make-release-notes.sh Renders a release's body into the page Sparkle shows
.github/workflows/ci.yml Runs both test suites and build.sh on pull requests
.github/workflows/release.yml Builds, notarizes, and publishes a release on a v* tag
.github/workflows/release-notes.yml Rebuilds the notes page when a release body is edited
docs/ Effect recordings shown in this file
- A modifier pressed together with another key does not count as a tap, so ⌃C and similar combinations never trigger the effect
- The hotkey field does not accept a modifier on its own or Shift plus a key
- The login item is tied to the location of Blip.app. Re-enable it after moving the app
- An ad hoc signed Blip.app opened on another Mac is blocked by Gatekeeper
MIT. See LICENSE.
The app depends on KeyboardShortcuts, which is MIT licensed as well.