An ultra-smooth circular menu tool for macOS with both click-to-execute and press-drag-release execution after selection.
OpenFire draws inspiration from both GTA V and PopClip, then massively refactors and optimizes the UI, interaction model, and performance with native Core Animation and Swift Concurrency.
🚀 Esports-level Response Speed
Bottom-layer hit testing based on mouseDown / mouseDragged / mouseUp. Bid farewell to missed clicks. In both workflows, the wheel is triggered only after you finish the text selection and release the mouse button. From there, OpenFire supports two distinct execution styles:
- Release, then click to execute: select text, release to open the wheel, then click the action you want.
- Release, press, drag, then release to execute: select text, release to open the wheel, immediately press again, drag across to the target slice, then release to fire that action.
The hover state tracks your cursor with near-zero latency, so the second mode feels closer to a GTA V weapon wheel than a traditional context menu.
💫 Native Blur & 60FPS Animations
Uses NSVisualEffectView and CAShapeLayer buffer pool. Page flipping, hovering, and clicking animations are buttery smooth with no frame drops.
🎛️ Highly Customizable UI Adjust the radial menu's Ring Opacity and Max Items limit (6, 8, 12, or 16 items per page) directly from the Menu Bar. You can also toggle GTA Mode for a heavier weapon-wheel style presentation with a darker HUD-like look.
🔌 Hot-pluggable Plugin System
Supports custom .openfireext plugin packages. Features double-click installation, background thread asynchronous loading, and a package management mechanism supporting deletion and disabling.
🧠 Smart Trigger Context Rewritten Accessibility recognition logic at the foundation. Text-selection actions stay focused on the selected content itself, while input-related actions still respect whether the current focus is actually editable.
✂️ Cleaner Quick Actions
When OpenFire detects that you clicked into an editable field and there is no active text selection, it can show a lightweight Paste / Clear capsule near the cursor for quick paste access or for clearing the current clipboard contents. When the clipboard is empty, this shortcut does not appear. The built-in Paste action can also appear in the radial menu for editable selections.
🚫 Customizable App Blacklist
Built-in automatic blacklist management UI. Supports dragging and dropping apps, or browsing via the + button to precisely block specific software.
- Download the latest
.dmgfrom the Releases page. - Open the downloaded file and drag the OpenFire app into your
Applicationsfolder. - Launch OpenFire.
- Open System Settings → Privacy & Security → Accessibility and grant permissions to OpenFire (required for text selection detection).
OpenFire has two ways to open the wheel, and they are easy to confuse if described as one flow:
- Mouse selection trigger: select text normally, then release the mouse button. The wheel appears only after the selection is complete and the button is up.
- Optional manual hotkey trigger: if you set an
Open Menu Hotkeyin the menu bar, OpenFire can open the wheel for the current selection without waiting for the mouse-release flow.
Once the wheel is already visible, there are two ways to execute an action:
- Release, then click: let the wheel pop up, then click the slice you want.
- Release, press, drag, then release: let the wheel pop up, press down again right away, drag into the target slice, then release to fire it.
The second execution style is the signature interaction: as soon as the wheel appears, you can go straight into a weapon-wheel-like press-drag-release motion instead of pausing to click a slice.
If you need to debug why the wheel did or did not appear, see the dedicated Diagnostics Guide.
OpenFire does not simply fire on every mouse drag. The current trigger pipeline is intentionally conservative:
- A gesture must first look like an actual text-selection drag. Very short movements are treated as normal clicks instead of selection triggers.
- OpenFire suppresses obvious non-text scenarios before trying to acquire text:
- file drags detected through the drag pasteboard
- frontmost file-management or self contexts such as Finder, Dock, Desktop, and OpenFire itself
- known screenshot tools
- window drags, detected by checking whether the frontmost window frame actually moved during the gesture
- If the gesture survives those filters, OpenFire tries native Accessibility selection first.
- If Accessibility does not yield usable selected text quickly enough, OpenFire falls back to a guarded
Cmd+Cpath and waits briefly for a fresh clipboard update. - The wheel appears only after OpenFire has real non-empty selected text from one of those paths.
In practice, this means:
- normal text selection in native editors should usually trigger through Accessibility
- browser and WebView selections may trigger through either Accessibility or the
Cmd+Cfallback, depending on what the host app exposes - Telegram is allowed to rely more heavily on the
Cmd+Cfallback because its AX hit/focus state is often unreliable at mouse-up time - dragging files or dragging windows should not trigger the wheel
- editable text inside otherwise blocked contexts, such as Finder rename fields, can still trigger normally
Cmd+C fallback is OpenFire's backup acquisition path for apps that do not expose selected text reliably through the Accessibility API.
Instead of guessing the selected text, OpenFire does the following:
- Save the current pasteboard snapshot.
- Wait very briefly so physical modifier keys from the user's gesture do not interfere with the synthetic copy event.
- Post a synthetic
Cmd+C. - Poll the system pasteboard for a short window and wait for a fresh non-empty text value to appear.
- If a fresh copied value really arrived, use that text as the selection and restore the previous pasteboard snapshot.
This path exists mainly for apps such as:
- Telegram
- Electron-based apps
- browser or WebView hosts whose Accessibility selection state is incomplete or delayed
It is intentionally guarded and is not a blind "always copy on every drag" behavior. OpenFire still checks context before allowing the fallback result to trigger the wheel. It also restores the previous clipboard only when the synthetic copy actually produced a fresh copied value, which helps avoid unnecessary clipboard churn.
So in short:
Accessibility APIis the preferred pathCmd+Cfallback is the compatibility path- both still require OpenFire to conclude that the gesture looked like text selection rather than a file drag, window drag, or other non-text interaction
OpenFire lives in the macOS menu bar and exposes the main controls there:
- Ring Opacity:
0% (Opaque)to100% (Transparent) - GTA Mode: swaps the wheel into a heavier GTA V-style HUD presentation
- Max Items in Menu:
6 / 8 / 12 / 16 - Open Menu Hotkey: manually open the wheel for the current selection. Default:
Shift + Option + D - Auto Trigger Toggle Hotkey: turn automatic text-selection triggering on or off. Default:
Shift + Option + X - Plugin Management and App Blacklist
Note: when GTA Mode is enabled, the wheel is intentionally rendered fully opaque and the opacity menu is disabled.
OpenFire's true power lies in its plugin system. Plugins exist as .openfireext packages containing a simple Config.json.
| 🔌 Plugin | 📝 Description |
|---|---|
| Copy / Cut / Delete | Core editing actions for the selected text itself. |
| Search / Translate / Dict | Everyday text actions for web search, translation, and the macOS Dictionary app. |
| Open Link / Reveal in Finder | Context-aware built-ins for URLs and file paths. They stay visible and become executable only when the current selection matches. |
These default built-ins are part of OpenFire itself. They can be enabled, disabled, reordered, and also edited from the menu bar. Editing a built-in plugin creates your own override on top of the bundled default.
Enabled plugins keep their slot in the wheel. If the current selection does not match a plugin's context, the action stays visible but disabled instead of disappearing before pagination.
The built-in Paste action can appear in the text-selection wheel when the current focus is editable, and it is also reused by the empty-input Paste / Clear popup.
Built into the package, they can be enabled or removed at any time via the "Plugin Management" interface:
- 🔍 Baidu Search / Google Search: search the selected text on the web.
- 🧑💻 GitHub Search: search the selected text on GitHub.
- 📚 NeoDB Book Search / Douban Book Search: look up books directly from the current selection.
- 🎬 Douban Movie Search: search selected movie titles on Douban.
✈️ Search in Telegram: send the selected text into Telegram search.- 📂 Reveal in Finder: when the selection is a file path, open its location in Finder.
- 🖥️ Run Shell: a default-disabled script plugin that runs a bundled shell script with the selected text.
- 💻 Run in iTerm2: a default-disabled plugin that sends the selected text to iTerm2 as a shell command.
OpenFire comes with a fully-featured Visual Plugin Editor built right into the app. You no longer need to write JSON configurations manually!
- Click the 🔥 OpenFire icon in the macOS Menu Bar.
- Select Plugin Management...
- Click the
+button at the bottom to open the Plugin Editor. - Fill in the details and choose an action type.
- 🌐
url: Open the system browser to visit{text} - 🐚
shell-script: Run a bundled shell script with the selected text injected via environment variables - 🍎
applescript: Run a bundled AppleScript with the selected text passed in by OpenFire - ⌨️
key-combo: Record system combo shortcuts directly from the UI - 📋
copy: Copy to clipboard - 📝
paste: Paste into the current input area - 📂
reveal-path: Open the selected file path in Finder
For shell-script and applescript, the standard plugin layout is to point action.script at a bundled script file inside the .openfireext package. OpenFire also supports inline script text in the same script field for short snippets. When triggered, the selected text is injected into $OPENFIRE_TEXT and OPENFIRE_TEXT_FILE.
Recommended package layout
My Script.openfireext/
Config.json
script.sh
Example: Shell script file
"action": {
"type": "shell-script",
"script": "script.sh"
}Example: AppleScript file
"action": {
"type": "applescript",
"script": "script.applescript"
}Inline alternative for short scripts
"action": {
"type": "shell-script",
"script": "echo \"Selected: $OPENFIRE_TEXT\" >> ~/Desktop/openfire.log"
}- Language: Swift 5.9, AppKit, Objective-C Runtime
- Rendering: Core Animation (
CAShapeLayer,CATextLayer,CATransaction) - Event Monitoring: CGEventTap, macOS Accessibility API (
AXUIElement,AXObserver) - Concurrency: GCD (
DispatchQueue.global) and Swift Concurrency
See CHANGELOG.md.
OpenFire is released under the MIT License.