A light-weight macOS system wide app for trackpad haptics.
45
stars
52
commits
Swift
primary language
Jul 18, 2026
updated
Feel the interface, not just see it.
Tactile is a macOS menu-bar utility that taps your Force Touch trackpad's haptic motor whenever the cursor passes over something clickable, in any app, system-wide. Built as an accessibility aid: instead of relying on the subtle hover-color change most apps use, you feel a physical tick under your finger when the cursor reaches a button, link, checkbox, menu, or tab.
https://github.com/user-attachments/assets/b410fdf5-21cd-40d7-971e-5c15e5669e02
Tactile reads the same macOS Accessibility tree that VoiceOver uses. A global mouse monitor watches cursor movement, a background hit-tester asks the system what element is under the cursor, and when the cursor enters a clickable element, the trackpad ticks once.
The pipeline is fully event-driven: when the mouse is still, Tactile does nothing at all (0% CPU). While moving, sampling is throttled and cached per-element, so continuous use stays under a few percent of one core.
<div>-style buttons that never reach the
accessibility tree still tick. Source in extension/.Tactile can also be used as a low-vision aid. Beyond the haptic feedback, it adds visual reinforcement for anyone who has trouble tracking a small cursor or telling what's interactive on screen:
Together with the haptic tick, this gives low-vision users three independent signals — feel, color, and shape — for the same event.
https://github.com/user-attachments/assets/39e714b6-001d-41fa-ad16-dd00278f0ac2
https://github.com/user-attachments/assets/3d63dd16-311b-4e34-bc6e-0c753deea56e
https://github.com/user-attachments/assets/be978b1a-c9f5-4f8b-85c8-eac8164a2af8
https://github.com/user-attachments/assets/32005d36-5cf8-4fb2-bb97-1f0e5bf81fd9
To enable these, go to Tactile Settings -> visual aids
Tactile.app from the latest release and drag it to /Applications.Tactile is notarized by Apple, so it opens normally with no Gatekeeper workaround. The whole source is here for you to inspect or build yourself.
For web pages, install the companion extension for richer coverage: it picks up
custom buttons the app would otherwise miss in the browser. Get it from the
Chrome Web Store
(or build from source; see extension/README.md). Then
enable Browser integration in Settings → Apps & Browser.
Open Tactile.xcodeproj in Xcode and run. Package dependencies (Sparkle)
resolve automatically. The app is unsandboxed, the system-wide Accessibility
API requires it, so it isn't App Store distributable; distribute with Developer
ID signing and notarization.
Automatic updates use Sparkle and are driven by
appcast.xml at the repo root (the feed URL is set in
Info.plist → SUFeedURL). One-time setup, then per-release steps:
One time: signing keys
generate_keys (bundled with the Sparkle package /
release tools). It
stores a private key in your login Keychain and prints a public key.Info.plist → SUPublicEDKey, and commit.Ship the public key in a release that keeps the previous Apple code-signing
identity. Existing installations do not trust a newly added Sparkle key until
they have installed it once. If the Apple code-signing identity must change at
the same time, first publish a bridge update signed with the old identity and
containing the new public key. Add sparkle:minimumAutoupdateVersion to the
later update so older builds install the bridge first.
Each release
MARKETING_VERSION and CURRENT_PROJECT_VERSION in the project..app.sign_update Tactile-x.y.z.zip → copies an edSignature.<item> to appcast.xml with <enclosure url="…" length="…" sparkle:edSignature="…"/> pointing at the zip on the GitHub release, bump
sparkle:version/shortVersionString, and push.Users then get the update in-app via Check for Updates… or the background check.
dlopen and falls back safely;
everything else is public API. The whole source is here.MIT © Mason Chen
52 commits
Swift
93.6%
JavaScript
5.8%
A light-weight macOS system wide app for trackpad haptics.
45
stars
52
commits
Swift
primary language
Jul 18, 2026
updated
Feel the interface, not just see it.
Tactile is a macOS menu-bar utility that taps your Force Touch trackpad's haptic motor whenever the cursor passes over something clickable, in any app, system-wide. Built as an accessibility aid: instead of relying on the subtle hover-color change most apps use, you feel a physical tick under your finger when the cursor reaches a button, link, checkbox, menu, or tab.
https://github.com/user-attachments/assets/b410fdf5-21cd-40d7-971e-5c15e5669e02
Tactile reads the same macOS Accessibility tree that VoiceOver uses. A global mouse monitor watches cursor movement, a background hit-tester asks the system what element is under the cursor, and when the cursor enters a clickable element, the trackpad ticks once.
The pipeline is fully event-driven: when the mouse is still, Tactile does nothing at all (0% CPU). While moving, sampling is throttled and cached per-element, so continuous use stays under a few percent of one core.
<div>-style buttons that never reach the
accessibility tree still tick. Source in extension/.Tactile can also be used as a low-vision aid. Beyond the haptic feedback, it adds visual reinforcement for anyone who has trouble tracking a small cursor or telling what's interactive on screen:
Together with the haptic tick, this gives low-vision users three independent signals — feel, color, and shape — for the same event.
https://github.com/user-attachments/assets/39e714b6-001d-41fa-ad16-dd00278f0ac2
https://github.com/user-attachments/assets/3d63dd16-311b-4e34-bc6e-0c753deea56e
https://github.com/user-attachments/assets/be978b1a-c9f5-4f8b-85c8-eac8164a2af8
https://github.com/user-attachments/assets/32005d36-5cf8-4fb2-bb97-1f0e5bf81fd9
To enable these, go to Tactile Settings -> visual aids
Tactile.app from the latest release and drag it to /Applications.Tactile is notarized by Apple, so it opens normally with no Gatekeeper workaround. The whole source is here for you to inspect or build yourself.
For web pages, install the companion extension for richer coverage: it picks up
custom buttons the app would otherwise miss in the browser. Get it from the
Chrome Web Store
(or build from source; see extension/README.md). Then
enable Browser integration in Settings → Apps & Browser.
Open Tactile.xcodeproj in Xcode and run. Package dependencies (Sparkle)
resolve automatically. The app is unsandboxed, the system-wide Accessibility
API requires it, so it isn't App Store distributable; distribute with Developer
ID signing and notarization.
Automatic updates use Sparkle and are driven by
appcast.xml at the repo root (the feed URL is set in
Info.plist → SUFeedURL). One-time setup, then per-release steps:
One time: signing keys
generate_keys (bundled with the Sparkle package /
release tools). It
stores a private key in your login Keychain and prints a public key.Info.plist → SUPublicEDKey, and commit.Ship the public key in a release that keeps the previous Apple code-signing
identity. Existing installations do not trust a newly added Sparkle key until
they have installed it once. If the Apple code-signing identity must change at
the same time, first publish a bridge update signed with the old identity and
containing the new public key. Add sparkle:minimumAutoupdateVersion to the
later update so older builds install the bridge first.
Each release
MARKETING_VERSION and CURRENT_PROJECT_VERSION in the project..app.sign_update Tactile-x.y.z.zip → copies an edSignature.<item> to appcast.xml with <enclosure url="…" length="…" sparkle:edSignature="…"/> pointing at the zip on the GitHub release, bump
sparkle:version/shortVersionString, and push.Users then get the update in-app via Check for Updates… or the background check.
dlopen and falls back safely;
everything else is public API. The whole source is here.MIT © Mason Chen
52 commits
Swift
93.6%
JavaScript
5.8%