Repository files navigation

Flux

A calmer menu bar. A fast, stable, near-zero-resource menu bar manager for macOS — a Bartender alternative built for performance and stability first.

LightDark
Flux settings, lightFlux settings, dark

Why Flux

Most menu-bar managers feel buggy because they continuously capture and redraw the menu bar with ScreenCaptureKit. That approach burns CPU/GPU, needs Screen Recording permission, and breaks on every macOS update.

Flux takes the opposite approach. It plants its own invisible, expandable status items as section dividers and collapses them to push other apps' icons off the visible bar. The result:

  • ~0% CPU at idle — it only reacts to clicks, nothing polls or redraws.
  • Minimal permissions — the core menu-bar manager needs no Screen Recording or Accessibility grant. Calendar and Camera ask only when their widgets are enabled; the optional lock-screen overlay uses macOS's lock-screen window space instead of screen capture.
  • Stable across releases — relies on documented NSStatusItem behaviour, not private or capture APIs. Targets Sonoma (14), Sequoia (15), Tahoe (26) and is forward-compatible with the upcoming Golden Gate (27).

The three zones (just like Bartender)

[ Always-Hidden ] ‹‹ [ Hidden ] ‹ ⌄ [ Shown ] 🕓
│ │ │
always-hidden hidden Flux chevron
divider divider
ZoneBehaviour
ShownAlways visible. Anything to the right of the chevron — it never hides.
HiddenRevealed when you click the Flux chevron (the "drawer").
Always-HiddenRevealed only with ⌥ (option) — kept fully out of the way.

Nothing is hidden until you say so. On a fresh install Flux seeds its chevron and dividers to the left of every icon you already have, so all of them start in Shown and the bar looks exactly as it did before. You then drag icons leftward, past the chevron, to tuck them away.

You assign an icon to a zone by ⌘-dragging it to one side of a Flux divider — the native macOS gesture. To make the (normally invisible) zone boundaries visible while you do this, open Arrange Menu Bar — from Settings or the chevron's right-click menu. Flux reveals every icon and drops a labeled marker at each boundary, so you can see exactly where to drop each icon:

  • Left of the Hidden marker → Hidden
  • Left of the Always Hidden marker → Always-Hidden
  • Right of the Hidden marker → Shown

Click Done (or the ✓ that replaces the chevron) to apply. Flux remembers the arrangement across launches.

Features (MVP)

  • Click the chevron (or press the global hotkey, ⌃⌥⌘F by default and fully rebindable in Settings) to reveal. Clicking a revealed icon keeps it open so you can use it; clicking down in a window re-hides.
  • Arrange Mode — a guided editor that reveals labeled zone markers in the live menu bar so assigning icons to Shown / Hidden / Always-Hidden is clear and visible.
  • Optional Always-Hidden zone.
  • Notch panel — Alcove-inspired compact redesign (M7) — a seamless solid-black panel sized to the notch suite's shared footprint, with overshoot springs on open and a snappy, no-bounce close, plus a soft content morph as it expands. Hover (or click) the camera housing to expand a Now Playing widget: artwork, title/artist, a scrubber, and transport controls for whatever's playing (any app, via a vendored MediaRemote adapter). Open gesture, hover delays, and which widgets are enabled are all configurable in Settings → Notch.
  • Duo view (M7) — an opt-in toggle in Settings → Notch shows Now Playing and Calendar side by side when Now Playing is expanded (with a clear access prompt if Calendar permission is missing); expanding Calendar on its own still shows it alone.
  • Activity cycling & restore (M7) — while a live-activity wing is showing, swipe left/right to cycle through every other queued activity, swipe up to dismiss the one showing (restorable — the last 5 dismissed activities can be brought back), and swipe down to open the widget panel.
  • File Shelf — drag files straight onto the notch to hold them: hovering a drag over the (collapsed) camera housing expands the shelf automatically, and dropping copies the files in (they survive the source being moved, ejected, or deleted). From the shelf: click a tile to open it, drag it back out to Finder/Mail/Slack/etc., or use the tile's context menu for AirDrop, "Show in Finder", or "Copy". An optional auto-clear (never / 1 / 3 / 7 days) in Settings → Notch tidies the shelf on its own.
  • Calendar — your upcoming events (Today/Tomorrow), with a colored dot per calendar, time range, and location, right in the notch. Needs Calendar access; Settings → Notch shows the live grant/denied status and a button to request access or jump straight to System Settings if it's off. A wing appears automatically when an event is starting within 10 minutes — no repeating timer, just a single scheduled check for the next event's own threshold.
  • Live Activities — brief wings around the notch for battery, Bluetooth, and calendar events: a wing when you plug in, unplug, or cross below 20% battery unplugged (tinted to read as urgent, re-arming once you're back above 25% or plugged in), a wing when AirPods or another Bluetooth audio/HID accessory connects or disconnects, with a best-effort battery reading when the OS reports one, and a wing when a calendar event is about to start. Each is independently toggled in Settings → Notch.
  • Mirror — a live camera preview right in the notch, for a quick "how do I look" check. The camera only ever runs while the widget is actually open; needs Camera access, with the same live grant/denied status and re-request button as every other permission-gated feature.
  • Timers — start a 1/5/10/25 minute countdown from the shared Flux menu. A live wing shows the nearest remaining time with second precision while a timer runs, and a higher-priority wing (with a sound) announces completion. The Timer live display toggle in Settings → Notch controls both.
  • Clipboard — an in-memory-only history of what you copy, with click-to-copy-back, per-item removal, and Clear All. Off by default — history collection is opt-in, since clipboard contents routinely include passwords and other sensitive one-time text; nothing is ever written to disk, and password-manager-marked copies (the nspasteboard.org concealed/transient convention) are never captured at all. Cmd-C/Cmd-X are captured immediately, with pasteboard change polling as a fallback for menu copies, screenshots, files, and scripts.
  • Lock screen — optionally keeps the solid-black notch silhouette and native Liquid Glass surfaces visible on the macOS lock screen. When something is playing, the centered Now Playing card shows artwork/title/artist plus previous/play-next controls; the card is the only interactive overlay and the rest of the lock-screen UI remains mouse-transparent. The current live activity appears as a compact caption widget (battery, Bluetooth, calendar, timer, ...), with a short thunky system click on unlock. Each sub-feature has its own toggle, all nested under the master switch. Off by default: it uses macOS lock-screen notifications and a dynamically loaded system-level window-space bridge, so the integration is isolated and can be disabled cleanly if a future macOS release changes it — see Settings → Lock Screen.
  • Auto re-hide after an adjustable delay.
  • Launch at login (via SMAppService — the modern, sanctioned API).
  • Three menu-bar icon styles: Chevron / Dot / Line.
  • Light & dark, adapts to your system accent color.
  • Runs as a true agent: no Dock icon, no app switcher entry.

Privacy and permissions

Calendar and Camera are the only TCC permissions Flux currently requests. Both are opt-in and behind their own explicit Grant Access button in Settings → Notch; the permission-gated widget shows its own "access needed" state until you ask for it. Everything else in the app (menu-bar hiding, the notch panel, widget cycling, Now Playing, battery/Bluetooth/timer/calendar-event wings, and the lock-screen overlay) does not use Screen Recording. Permissions are requested only when a capability needs them, and denied features continue to show a useful fallback state.

  • Bluetooth device wings need no permission at all. Flux detects accessory connect/disconnect through the system's own device registry (the IOKit AppleDeviceManagementHIDEventService that already reports accessory battery, permission-free) plus CoreAudio's device list — it never requests Bluetooth access, so nothing prompts, and the wings are on by default like the rest of the notch suite.
  • Clipboard history is opt-in and in-memory only — nothing is captured until you turn it on, and nothing it captures is ever written to disk.

Every grant above is revocable at any time in System Settings, and every gated feature degrades gracefully (its own empty/permission state) rather than breaking the rest of the app when access isn't there.

Install

Grab the latest Flux.dmg from the Releases page, open it, and drag Flux into Applications. On first launch, right-click the app → Open (it's ad-hoc signed, not notarized). A chevron appears near your clock.

A note on permissions: Flux is ad-hoc signed rather than notarized with a paid Developer ID, which means macOS can — and sometimes does — treat an update as a new, untrusted binary and quietly drop a previously granted TCC permission (Calendar or Camera). If a permission-gated widget suddenly shows its "access needed" state after updating Flux, that's why — Settings → Notch shows the live grant/denied status for each permission and a button to re-request it or jump straight to the right System Settings pane.

Build & run

Requires Xcode 15+ (built and tested on Xcode 26 / Swift 6.3, macOS 26).

# Build the signed .app bundle → build/Flux.app
./Scripts/build_app.sh release
# Package a distributable disk image → build/Flux.dmg
./Scripts/build_dmg.sh
# Launch it
open build/Flux.app

Or for quick iteration:

swift build && swift run

The debug executable cannot register Launch at login; use the bundled app for that setting so macOS does not launch a bare process through Terminal.

Developer / CI helpers

The executable understands a few headless flags used for testing:

Flux --selftest # functional test of the collapse engine
Flux --snapshot out.png [light|dark] # render the real settings UI to a PNG
Flux --snapshot-notch out.png [dark] [collapsed|activity|expanded|lockscreen] # render the notch panel to a PNG

Architecture

Sources/Flux/
main.swift # agent entry point (.accessory activation)
App/AppDelegate.swift # wires settings ↔ engine ↔ login ↔ hotkey
MenuBar/
MenuBarManager.swift # reveal/collapse state machine, auto-rehide, menu, arrange
ControlItem.swift # one NSStatusItem as chevron or expandable divider
MenuBarArranger.swift # observable toggle for Arrange Mode (Settings ↔ engine)
MenuBarSection.swift # the three-zone model
MenuBarIconStyle.swift # chevron / dot / line
Settings/
SettingsStore.swift # UserDefaults-backed, observable
SettingsView.swift # tab host (General / Menu Bar / Notch / About)
SettingsRows.swift # shared row primitives
Tabs/ # one file per settings tab
SettingsWindowController.swift
Notch/
NotchWindowController.swift # owns the notch panel's lifecycle
NotchViewModel.swift # collapsed/activity/expanded state machine
NotchWidget.swift # widget protocol + registry
LiveActivity.swift # priority-queued "wings" content
LiveActivitySources.swift # NotchActivityRouter — single home for every activity producer
TimerActivity.swift # live timer-wing formatting and selection
Widgets/NowPlayingWidget.swift
Widgets/ShelfWidget.swift # tiles, drag in/out, AirDrop/Finder/Copy
Widgets/CalendarWidget.swift # agenda, permission states
Widgets/MirrorWidget.swift # live camera preview; owns CameraService start/stop itself
Widgets/ClipboardWidget.swift # history list, click-to-copy-back, Clear All
LockScreenPresenter.swift # EXPERIMENTAL: fade in/out, lock/unlock, unlock sound
LockScreenContentView.swift # EXPERIMENTAL: live media/activity widgets on the lock screen
Services/NowPlaying/ # MediaRemote adapter — the sole Now Playing source
Services/Shelf/ # ShelfStore (copy-in, manifest, QuickLook thumbs, expiry)
Services/CalendarService.swift # EventKit, refresh on EKEventStoreChanged (no polling)
Services/PowerMonitor.swift # IOKit battery/AC events (plug/unplug, low battery)
Services/DeviceMonitor.swift # permission-free BT connect/disconnect: IOKit matching notifications + CoreAudio device list + IORegistry battery
Services/CameraService.swift # AVCaptureSession behind Mirror, started/stopped by the widget itself
Services/ClipboardMonitor.swift # keyboard-assisted capture + changeCount fallback
Services/TimerService.swift # countdown timers, single boundary Task, completions publisher
Login/LoginItemManager.swift # SMAppService launch-at-login
Hotkey/HotkeyManager.swift # Carbon global hotkeys (menu-bar toggle + notch toggle)
Hotkey/HotkeyShortcut.swift # the chord model + ⌃⌥⌘F / ⌃⌥⌘N defaults
Hotkey/HotkeyRecorderView.swift # click-to-record shortcut field
Support/PermissionCenter.swift # unified TCC status/request for Calendar/Camera
Support/ # logging, app info, render/snapshot/selftest

Roadmap (post-MVP)

  • Per-app list control and a searchable drawer popover (needs Accessibility + ScreenCaptureKit — deliberately deferred to keep the MVP resource-light).
  • Custom hotkey recording, profiles, triggers (show on update/active).
  • Graduating the lock-screen silhouette out of "experimental," if it proves durable across macOS updates.

License

MIT © 2026 Ammar Badawy.

About

A calmer menu bar for macOS — a fast, stable, zero-permission Bartender alternative.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Flux

A calmer menu bar. A fast, stable, near-zero-resource menu bar manager for macOS — a Bartender alternative built for performance and stability first.

LightDark
Flux settings, lightFlux settings, dark

Why Flux

Most menu-bar managers feel buggy because they continuously capture and redraw the menu bar with ScreenCaptureKit. That approach burns CPU/GPU, needs Screen Recording permission, and breaks on every macOS update.

Flux takes the opposite approach. It plants its own invisible, expandable status items as section dividers and collapses them to push other apps' icons off the visible bar. The result:

  • ~0% CPU at idle — it only reacts to clicks, nothing polls or redraws.
  • Minimal permissions — the core menu-bar manager needs no Screen Recording or Accessibility grant. Calendar and Camera ask only when their widgets are enabled; the optional lock-screen overlay uses macOS's lock-screen window space instead of screen capture.
  • Stable across releases — relies on documented NSStatusItem behaviour, not private or capture APIs. Targets Sonoma (14), Sequoia (15), Tahoe (26) and is forward-compatible with the upcoming Golden Gate (27).

The three zones (just like Bartender)

[ Always-Hidden ] ‹‹ [ Hidden ] ‹ ⌄ [ Shown ] 🕓
│ │ │
always-hidden hidden Flux chevron
divider divider
ZoneBehaviour
ShownAlways visible. Anything to the right of the chevron — it never hides.
HiddenRevealed when you click the Flux chevron (the "drawer").
Always-HiddenRevealed only with ⌥ (option) — kept fully out of the way.

Nothing is hidden until you say so. On a fresh install Flux seeds its chevron and dividers to the left of every icon you already have, so all of them start in Shown and the bar looks exactly as it did before. You then drag icons leftward, past the chevron, to tuck them away.

You assign an icon to a zone by ⌘-dragging it to one side of a Flux divider — the native macOS gesture. To make the (normally invisible) zone boundaries visible while you do this, open Arrange Menu Bar — from Settings or the chevron's right-click menu. Flux reveals every icon and drops a labeled marker at each boundary, so you can see exactly where to drop each icon:

  • Left of the Hidden marker → Hidden
  • Left of the Always Hidden marker → Always-Hidden
  • Right of the Hidden marker → Shown

Click Done (or the ✓ that replaces the chevron) to apply. Flux remembers the arrangement across launches.

Features (MVP)

  • Click the chevron (or press the global hotkey, ⌃⌥⌘F by default and fully rebindable in Settings) to reveal. Clicking a revealed icon keeps it open so you can use it; clicking down in a window re-hides.
  • Arrange Mode — a guided editor that reveals labeled zone markers in the live menu bar so assigning icons to Shown / Hidden / Always-Hidden is clear and visible.
  • Optional Always-Hidden zone.
  • Notch panel — Alcove-inspired compact redesign (M7) — a seamless solid-black panel sized to the notch suite's shared footprint, with overshoot springs on open and a snappy, no-bounce close, plus a soft content morph as it expands. Hover (or click) the camera housing to expand a Now Playing widget: artwork, title/artist, a scrubber, and transport controls for whatever's playing (any app, via a vendored MediaRemote adapter). Open gesture, hover delays, and which widgets are enabled are all configurable in Settings → Notch.
  • Duo view (M7) — an opt-in toggle in Settings → Notch shows Now Playing and Calendar side by side when Now Playing is expanded (with a clear access prompt if Calendar permission is missing); expanding Calendar on its own still shows it alone.
  • Activity cycling & restore (M7) — while a live-activity wing is showing, swipe left/right to cycle through every other queued activity, swipe up to dismiss the one showing (restorable — the last 5 dismissed activities can be brought back), and swipe down to open the widget panel.
  • File Shelf — drag files straight onto the notch to hold them: hovering a drag over the (collapsed) camera housing expands the shelf automatically, and dropping copies the files in (they survive the source being moved, ejected, or deleted). From the shelf: click a tile to open it, drag it back out to Finder/Mail/Slack/etc., or use the tile's context menu for AirDrop, "Show in Finder", or "Copy". An optional auto-clear (never / 1 / 3 / 7 days) in Settings → Notch tidies the shelf on its own.
  • Calendar — your upcoming events (Today/Tomorrow), with a colored dot per calendar, time range, and location, right in the notch. Needs Calendar access; Settings → Notch shows the live grant/denied status and a button to request access or jump straight to System Settings if it's off. A wing appears automatically when an event is starting within 10 minutes — no repeating timer, just a single scheduled check for the next event's own threshold.
  • Live Activities — brief wings around the notch for battery, Bluetooth, and calendar events: a wing when you plug in, unplug, or cross below 20% battery unplugged (tinted to read as urgent, re-arming once you're back above 25% or plugged in), a wing when AirPods or another Bluetooth audio/HID accessory connects or disconnects, with a best-effort battery reading when the OS reports one, and a wing when a calendar event is about to start. Each is independently toggled in Settings → Notch.
  • Mirror — a live camera preview right in the notch, for a quick "how do I look" check. The camera only ever runs while the widget is actually open; needs Camera access, with the same live grant/denied status and re-request button as every other permission-gated feature.
  • Timers — start a 1/5/10/25 minute countdown from the shared Flux menu. A live wing shows the nearest remaining time with second precision while a timer runs, and a higher-priority wing (with a sound) announces completion. The Timer live display toggle in Settings → Notch controls both.
  • Clipboard — an in-memory-only history of what you copy, with click-to-copy-back, per-item removal, and Clear All. Off by default — history collection is opt-in, since clipboard contents routinely include passwords and other sensitive one-time text; nothing is ever written to disk, and password-manager-marked copies (the nspasteboard.org concealed/transient convention) are never captured at all. Cmd-C/Cmd-X are captured immediately, with pasteboard change polling as a fallback for menu copies, screenshots, files, and scripts.
  • Lock screen — optionally keeps the solid-black notch silhouette and native Liquid Glass surfaces visible on the macOS lock screen. When something is playing, the centered Now Playing card shows artwork/title/artist plus previous/play-next controls; the card is the only interactive overlay and the rest of the lock-screen UI remains mouse-transparent. The current live activity appears as a compact caption widget (battery, Bluetooth, calendar, timer, ...), with a short thunky system click on unlock. Each sub-feature has its own toggle, all nested under the master switch. Off by default: it uses macOS lock-screen notifications and a dynamically loaded system-level window-space bridge, so the integration is isolated and can be disabled cleanly if a future macOS release changes it — see Settings → Lock Screen.
  • Auto re-hide after an adjustable delay.
  • Launch at login (via SMAppService — the modern, sanctioned API).
  • Three menu-bar icon styles: Chevron / Dot / Line.
  • Light & dark, adapts to your system accent color.
  • Runs as a true agent: no Dock icon, no app switcher entry.

Privacy and permissions

Calendar and Camera are the only TCC permissions Flux currently requests. Both are opt-in and behind their own explicit Grant Access button in Settings → Notch; the permission-gated widget shows its own "access needed" state until you ask for it. Everything else in the app (menu-bar hiding, the notch panel, widget cycling, Now Playing, battery/Bluetooth/timer/calendar-event wings, and the lock-screen overlay) does not use Screen Recording. Permissions are requested only when a capability needs them, and denied features continue to show a useful fallback state.

  • Bluetooth device wings need no permission at all. Flux detects accessory connect/disconnect through the system's own device registry (the IOKit AppleDeviceManagementHIDEventService that already reports accessory battery, permission-free) plus CoreAudio's device list — it never requests Bluetooth access, so nothing prompts, and the wings are on by default like the rest of the notch suite.
  • Clipboard history is opt-in and in-memory only — nothing is captured until you turn it on, and nothing it captures is ever written to disk.

Every grant above is revocable at any time in System Settings, and every gated feature degrades gracefully (its own empty/permission state) rather than breaking the rest of the app when access isn't there.

Install

Grab the latest Flux.dmg from the Releases page, open it, and drag Flux into Applications. On first launch, right-click the app → Open (it's ad-hoc signed, not notarized). A chevron appears near your clock.

A note on permissions: Flux is ad-hoc signed rather than notarized with a paid Developer ID, which means macOS can — and sometimes does — treat an update as a new, untrusted binary and quietly drop a previously granted TCC permission (Calendar or Camera). If a permission-gated widget suddenly shows its "access needed" state after updating Flux, that's why — Settings → Notch shows the live grant/denied status for each permission and a button to re-request it or jump straight to the right System Settings pane.

Build & run

Requires Xcode 15+ (built and tested on Xcode 26 / Swift 6.3, macOS 26).

# Build the signed .app bundle → build/Flux.app
./Scripts/build_app.sh release
# Package a distributable disk image → build/Flux.dmg
./Scripts/build_dmg.sh
# Launch it
open build/Flux.app

Or for quick iteration:

swift build && swift run

The debug executable cannot register Launch at login; use the bundled app for that setting so macOS does not launch a bare process through Terminal.

Developer / CI helpers

The executable understands a few headless flags used for testing:

Flux --selftest # functional test of the collapse engine
Flux --snapshot out.png [light|dark] # render the real settings UI to a PNG
Flux --snapshot-notch out.png [dark] [collapsed|activity|expanded|lockscreen] # render the notch panel to a PNG

Architecture

Sources/Flux/
main.swift # agent entry point (.accessory activation)
App/AppDelegate.swift # wires settings ↔ engine ↔ login ↔ hotkey
MenuBar/
MenuBarManager.swift # reveal/collapse state machine, auto-rehide, menu, arrange
ControlItem.swift # one NSStatusItem as chevron or expandable divider
MenuBarArranger.swift # observable toggle for Arrange Mode (Settings ↔ engine)
MenuBarSection.swift # the three-zone model
MenuBarIconStyle.swift # chevron / dot / line
Settings/
SettingsStore.swift # UserDefaults-backed, observable
SettingsView.swift # tab host (General / Menu Bar / Notch / About)
SettingsRows.swift # shared row primitives
Tabs/ # one file per settings tab
SettingsWindowController.swift
Notch/
NotchWindowController.swift # owns the notch panel's lifecycle
NotchViewModel.swift # collapsed/activity/expanded state machine
NotchWidget.swift # widget protocol + registry
LiveActivity.swift # priority-queued "wings" content
LiveActivitySources.swift # NotchActivityRouter — single home for every activity producer
TimerActivity.swift # live timer-wing formatting and selection
Widgets/NowPlayingWidget.swift
Widgets/ShelfWidget.swift # tiles, drag in/out, AirDrop/Finder/Copy
Widgets/CalendarWidget.swift # agenda, permission states
Widgets/MirrorWidget.swift # live camera preview; owns CameraService start/stop itself
Widgets/ClipboardWidget.swift # history list, click-to-copy-back, Clear All
LockScreenPresenter.swift # EXPERIMENTAL: fade in/out, lock/unlock, unlock sound
LockScreenContentView.swift # EXPERIMENTAL: live media/activity widgets on the lock screen
Services/NowPlaying/ # MediaRemote adapter — the sole Now Playing source
Services/Shelf/ # ShelfStore (copy-in, manifest, QuickLook thumbs, expiry)
Services/CalendarService.swift # EventKit, refresh on EKEventStoreChanged (no polling)
Services/PowerMonitor.swift # IOKit battery/AC events (plug/unplug, low battery)
Services/DeviceMonitor.swift # permission-free BT connect/disconnect: IOKit matching notifications + CoreAudio device list + IORegistry battery
Services/CameraService.swift # AVCaptureSession behind Mirror, started/stopped by the widget itself
Services/ClipboardMonitor.swift # keyboard-assisted capture + changeCount fallback
Services/TimerService.swift # countdown timers, single boundary Task, completions publisher
Login/LoginItemManager.swift # SMAppService launch-at-login
Hotkey/HotkeyManager.swift # Carbon global hotkeys (menu-bar toggle + notch toggle)
Hotkey/HotkeyShortcut.swift # the chord model + ⌃⌥⌘F / ⌃⌥⌘N defaults
Hotkey/HotkeyRecorderView.swift # click-to-record shortcut field
Support/PermissionCenter.swift # unified TCC status/request for Calendar/Camera
Support/ # logging, app info, render/snapshot/selftest

Roadmap (post-MVP)

  • Per-app list control and a searchable drawer popover (needs Accessibility + ScreenCaptureKit — deliberately deferred to keep the MVP resource-light).
  • Custom hotkey recording, profiles, triggers (show on update/active).
  • Graduating the lock-screen silhouette out of "experimental," if it proves durable across macOS updates.

License

MIT © 2026 Ammar Badawy.

About

A calmer menu bar for macOS — a fast, stable, zero-permission Bartender alternative.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Flux

A calmer menu bar. A fast, stable, near-zero-resource menu bar manager for macOS — a Bartender alternative built for performance and stability first.

LightDark
Flux settings, lightFlux settings, dark

Why Flux

Most menu-bar managers feel buggy because they continuously capture and redraw the menu bar with ScreenCaptureKit. That approach burns CPU/GPU, needs Screen Recording permission, and breaks on every macOS update.

Flux takes the opposite approach. It plants its own invisible, expandable status items as section dividers and collapses them to push other apps' icons off the visible bar. The result:

  • ~0% CPU at idle — it only reacts to clicks, nothing polls or redraws.
  • Minimal permissions — the core menu-bar manager needs no Screen Recording or Accessibility grant. Calendar and Camera ask only when their widgets are enabled; the optional lock-screen overlay uses macOS's lock-screen window space instead of screen capture.
  • Stable across releases — relies on documented NSStatusItem behaviour, not private or capture APIs. Targets Sonoma (14), Sequoia (15), Tahoe (26) and is forward-compatible with the upcoming Golden Gate (27).

The three zones (just like Bartender)

[ Always-Hidden ] ‹‹ [ Hidden ] ‹ ⌄ [ Shown ] 🕓
│ │ │
always-hidden hidden Flux chevron
divider divider
ZoneBehaviour
ShownAlways visible. Anything to the right of the chevron — it never hides.
HiddenRevealed when you click the Flux chevron (the "drawer").
Always-HiddenRevealed only with ⌥ (option) — kept fully out of the way.

Nothing is hidden until you say so. On a fresh install Flux seeds its chevron and dividers to the left of every icon you already have, so all of them start in Shown and the bar looks exactly as it did before. You then drag icons leftward, past the chevron, to tuck them away.

You assign an icon to a zone by ⌘-dragging it to one side of a Flux divider — the native macOS gesture. To make the (normally invisible) zone boundaries visible while you do this, open Arrange Menu Bar — from Settings or the chevron's right-click menu. Flux reveals every icon and drops a labeled marker at each boundary, so you can see exactly where to drop each icon:

  • Left of the Hidden marker → Hidden
  • Left of the Always Hidden marker → Always-Hidden
  • Right of the Hidden marker → Shown

Click Done (or the ✓ that replaces the chevron) to apply. Flux remembers the arrangement across launches.

Features (MVP)

  • Click the chevron (or press the global hotkey, ⌃⌥⌘F by default and fully rebindable in Settings) to reveal. Clicking a revealed icon keeps it open so you can use it; clicking down in a window re-hides.
  • Arrange Mode — a guided editor that reveals labeled zone markers in the live menu bar so assigning icons to Shown / Hidden / Always-Hidden is clear and visible.
  • Optional Always-Hidden zone.
  • Notch panel — Alcove-inspired compact redesign (M7) — a seamless solid-black panel sized to the notch suite's shared footprint, with overshoot springs on open and a snappy, no-bounce close, plus a soft content morph as it expands. Hover (or click) the camera housing to expand a Now Playing widget: artwork, title/artist, a scrubber, and transport controls for whatever's playing (any app, via a vendored MediaRemote adapter). Open gesture, hover delays, and which widgets are enabled are all configurable in Settings → Notch.
  • Duo view (M7) — an opt-in toggle in Settings → Notch shows Now Playing and Calendar side by side when Now Playing is expanded (with a clear access prompt if Calendar permission is missing); expanding Calendar on its own still shows it alone.
  • Activity cycling & restore (M7) — while a live-activity wing is showing, swipe left/right to cycle through every other queued activity, swipe up to dismiss the one showing (restorable — the last 5 dismissed activities can be brought back), and swipe down to open the widget panel.
  • File Shelf — drag files straight onto the notch to hold them: hovering a drag over the (collapsed) camera housing expands the shelf automatically, and dropping copies the files in (they survive the source being moved, ejected, or deleted). From the shelf: click a tile to open it, drag it back out to Finder/Mail/Slack/etc., or use the tile's context menu for AirDrop, "Show in Finder", or "Copy". An optional auto-clear (never / 1 / 3 / 7 days) in Settings → Notch tidies the shelf on its own.
  • Calendar — your upcoming events (Today/Tomorrow), with a colored dot per calendar, time range, and location, right in the notch. Needs Calendar access; Settings → Notch shows the live grant/denied status and a button to request access or jump straight to System Settings if it's off. A wing appears automatically when an event is starting within 10 minutes — no repeating timer, just a single scheduled check for the next event's own threshold.
  • Live Activities — brief wings around the notch for battery, Bluetooth, and calendar events: a wing when you plug in, unplug, or cross below 20% battery unplugged (tinted to read as urgent, re-arming once you're back above 25% or plugged in), a wing when AirPods or another Bluetooth audio/HID accessory connects or disconnects, with a best-effort battery reading when the OS reports one, and a wing when a calendar event is about to start. Each is independently toggled in Settings → Notch.
  • Mirror — a live camera preview right in the notch, for a quick "how do I look" check. The camera only ever runs while the widget is actually open; needs Camera access, with the same live grant/denied status and re-request button as every other permission-gated feature.
  • Timers — start a 1/5/10/25 minute countdown from the shared Flux menu. A live wing shows the nearest remaining time with second precision while a timer runs, and a higher-priority wing (with a sound) announces completion. The Timer live display toggle in Settings → Notch controls both.
  • Clipboard — an in-memory-only history of what you copy, with click-to-copy-back, per-item removal, and Clear All. Off by default — history collection is opt-in, since clipboard contents routinely include passwords and other sensitive one-time text; nothing is ever written to disk, and password-manager-marked copies (the nspasteboard.org concealed/transient convention) are never captured at all. Cmd-C/Cmd-X are captured immediately, with pasteboard change polling as a fallback for menu copies, screenshots, files, and scripts.
  • Lock screen — optionally keeps the solid-black notch silhouette and native Liquid Glass surfaces visible on the macOS lock screen. When something is playing, the centered Now Playing card shows artwork/title/artist plus previous/play-next controls; the card is the only interactive overlay and the rest of the lock-screen UI remains mouse-transparent. The current live activity appears as a compact caption widget (battery, Bluetooth, calendar, timer, ...), with a short thunky system click on unlock. Each sub-feature has its own toggle, all nested under the master switch. Off by default: it uses macOS lock-screen notifications and a dynamically loaded system-level window-space bridge, so the integration is isolated and can be disabled cleanly if a future macOS release changes it — see Settings → Lock Screen.
  • Auto re-hide after an adjustable delay.
  • Launch at login (via SMAppService — the modern, sanctioned API).
  • Three menu-bar icon styles: Chevron / Dot / Line.
  • Light & dark, adapts to your system accent color.
  • Runs as a true agent: no Dock icon, no app switcher entry.

Privacy and permissions

Calendar and Camera are the only TCC permissions Flux currently requests. Both are opt-in and behind their own explicit Grant Access button in Settings → Notch; the permission-gated widget shows its own "access needed" state until you ask for it. Everything else in the app (menu-bar hiding, the notch panel, widget cycling, Now Playing, battery/Bluetooth/timer/calendar-event wings, and the lock-screen overlay) does not use Screen Recording. Permissions are requested only when a capability needs them, and denied features continue to show a useful fallback state.

  • Bluetooth device wings need no permission at all. Flux detects accessory connect/disconnect through the system's own device registry (the IOKit AppleDeviceManagementHIDEventService that already reports accessory battery, permission-free) plus CoreAudio's device list — it never requests Bluetooth access, so nothing prompts, and the wings are on by default like the rest of the notch suite.
  • Clipboard history is opt-in and in-memory only — nothing is captured until you turn it on, and nothing it captures is ever written to disk.

Every grant above is revocable at any time in System Settings, and every gated feature degrades gracefully (its own empty/permission state) rather than breaking the rest of the app when access isn't there.

Install

Grab the latest Flux.dmg from the Releases page, open it, and drag Flux into Applications. On first launch, right-click the app → Open (it's ad-hoc signed, not notarized). A chevron appears near your clock.

A note on permissions: Flux is ad-hoc signed rather than notarized with a paid Developer ID, which means macOS can — and sometimes does — treat an update as a new, untrusted binary and quietly drop a previously granted TCC permission (Calendar or Camera). If a permission-gated widget suddenly shows its "access needed" state after updating Flux, that's why — Settings → Notch shows the live grant/denied status for each permission and a button to re-request it or jump straight to the right System Settings pane.

Build & run

Requires Xcode 15+ (built and tested on Xcode 26 / Swift 6.3, macOS 26).

# Build the signed .app bundle → build/Flux.app
./Scripts/build_app.sh release
# Package a distributable disk image → build/Flux.dmg
./Scripts/build_dmg.sh
# Launch it
open build/Flux.app

Or for quick iteration:

swift build && swift run

The debug executable cannot register Launch at login; use the bundled app for that setting so macOS does not launch a bare process through Terminal.

Developer / CI helpers

The executable understands a few headless flags used for testing:

Flux --selftest # functional test of the collapse engine
Flux --snapshot out.png [light|dark] # render the real settings UI to a PNG
Flux --snapshot-notch out.png [dark] [collapsed|activity|expanded|lockscreen] # render the notch panel to a PNG

Architecture

Sources/Flux/
main.swift # agent entry point (.accessory activation)
App/AppDelegate.swift # wires settings ↔ engine ↔ login ↔ hotkey
MenuBar/
MenuBarManager.swift # reveal/collapse state machine, auto-rehide, menu, arrange
ControlItem.swift # one NSStatusItem as chevron or expandable divider
MenuBarArranger.swift # observable toggle for Arrange Mode (Settings ↔ engine)
MenuBarSection.swift # the three-zone model
MenuBarIconStyle.swift # chevron / dot / line
Settings/
SettingsStore.swift # UserDefaults-backed, observable
SettingsView.swift # tab host (General / Menu Bar / Notch / About)
SettingsRows.swift # shared row primitives
Tabs/ # one file per settings tab
SettingsWindowController.swift
Notch/
NotchWindowController.swift # owns the notch panel's lifecycle
NotchViewModel.swift # collapsed/activity/expanded state machine
NotchWidget.swift # widget protocol + registry
LiveActivity.swift # priority-queued "wings" content
LiveActivitySources.swift # NotchActivityRouter — single home for every activity producer
TimerActivity.swift # live timer-wing formatting and selection
Widgets/NowPlayingWidget.swift
Widgets/ShelfWidget.swift # tiles, drag in/out, AirDrop/Finder/Copy
Widgets/CalendarWidget.swift # agenda, permission states
Widgets/MirrorWidget.swift # live camera preview; owns CameraService start/stop itself
Widgets/ClipboardWidget.swift # history list, click-to-copy-back, Clear All
LockScreenPresenter.swift # EXPERIMENTAL: fade in/out, lock/unlock, unlock sound
LockScreenContentView.swift # EXPERIMENTAL: live media/activity widgets on the lock screen
Services/NowPlaying/ # MediaRemote adapter — the sole Now Playing source
Services/Shelf/ # ShelfStore (copy-in, manifest, QuickLook thumbs, expiry)
Services/CalendarService.swift # EventKit, refresh on EKEventStoreChanged (no polling)
Services/PowerMonitor.swift # IOKit battery/AC events (plug/unplug, low battery)
Services/DeviceMonitor.swift # permission-free BT connect/disconnect: IOKit matching notifications + CoreAudio device list + IORegistry battery
Services/CameraService.swift # AVCaptureSession behind Mirror, started/stopped by the widget itself
Services/ClipboardMonitor.swift # keyboard-assisted capture + changeCount fallback
Services/TimerService.swift # countdown timers, single boundary Task, completions publisher
Login/LoginItemManager.swift # SMAppService launch-at-login
Hotkey/HotkeyManager.swift # Carbon global hotkeys (menu-bar toggle + notch toggle)
Hotkey/HotkeyShortcut.swift # the chord model + ⌃⌥⌘F / ⌃⌥⌘N defaults
Hotkey/HotkeyRecorderView.swift # click-to-record shortcut field
Support/PermissionCenter.swift # unified TCC status/request for Calendar/Camera
Support/ # logging, app info, render/snapshot/selftest

Roadmap (post-MVP)

  • Per-app list control and a searchable drawer popover (needs Accessibility + ScreenCaptureKit — deliberately deferred to keep the MVP resource-light).
  • Custom hotkey recording, profiles, triggers (show on update/active).
  • Graduating the lock-screen silhouette out of "experimental," if it proves durable across macOS updates.

License

MIT © 2026 Ammar Badawy.

About

A calmer menu bar for macOS — a fast, stable, zero-permission Bartender alternative.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Flux

A calmer menu bar. A fast, stable, near-zero-resource menu bar manager for macOS — a Bartender alternative built for performance and stability first.

LightDark
Flux settings, lightFlux settings, dark

Why Flux

Most menu-bar managers feel buggy because they continuously capture and redraw the menu bar with ScreenCaptureKit. That approach burns CPU/GPU, needs Screen Recording permission, and breaks on every macOS update.

Flux takes the opposite approach. It plants its own invisible, expandable status items as section dividers and collapses them to push other apps' icons off the visible bar. The result:

  • ~0% CPU at idle — it only reacts to clicks, nothing polls or redraws.
  • Minimal permissions — the core menu-bar manager needs no Screen Recording or Accessibility grant. Calendar and Camera ask only when their widgets are enabled; the optional lock-screen overlay uses macOS's lock-screen window space instead of screen capture.
  • Stable across releases — relies on documented NSStatusItem behaviour, not private or capture APIs. Targets Sonoma (14), Sequoia (15), Tahoe (26) and is forward-compatible with the upcoming Golden Gate (27).

The three zones (just like Bartender)

[ Always-Hidden ] ‹‹ [ Hidden ] ‹ ⌄ [ Shown ] 🕓
│ │ │
always-hidden hidden Flux chevron
divider divider
ZoneBehaviour
ShownAlways visible. Anything to the right of the chevron — it never hides.
HiddenRevealed when you click the Flux chevron (the "drawer").
Always-HiddenRevealed only with ⌥ (option) — kept fully out of the way.

Nothing is hidden until you say so. On a fresh install Flux seeds its chevron and dividers to the left of every icon you already have, so all of them start in Shown and the bar looks exactly as it did before. You then drag icons leftward, past the chevron, to tuck them away.

You assign an icon to a zone by ⌘-dragging it to one side of a Flux divider — the native macOS gesture. To make the (normally invisible) zone boundaries visible while you do this, open Arrange Menu Bar — from Settings or the chevron's right-click menu. Flux reveals every icon and drops a labeled marker at each boundary, so you can see exactly where to drop each icon:

  • Left of the Hidden marker → Hidden
  • Left of the Always Hidden marker → Always-Hidden
  • Right of the Hidden marker → Shown

Click Done (or the ✓ that replaces the chevron) to apply. Flux remembers the arrangement across launches.

Features (MVP)

  • Click the chevron (or press the global hotkey, ⌃⌥⌘F by default and fully rebindable in Settings) to reveal. Clicking a revealed icon keeps it open so you can use it; clicking down in a window re-hides.
  • Arrange Mode — a guided editor that reveals labeled zone markers in the live menu bar so assigning icons to Shown / Hidden / Always-Hidden is clear and visible.
  • Optional Always-Hidden zone.
  • Notch panel — Alcove-inspired compact redesign (M7) — a seamless solid-black panel sized to the notch suite's shared footprint, with overshoot springs on open and a snappy, no-bounce close, plus a soft content morph as it expands. Hover (or click) the camera housing to expand a Now Playing widget: artwork, title/artist, a scrubber, and transport controls for whatever's playing (any app, via a vendored MediaRemote adapter). Open gesture, hover delays, and which widgets are enabled are all configurable in Settings → Notch.
  • Duo view (M7) — an opt-in toggle in Settings → Notch shows Now Playing and Calendar side by side when Now Playing is expanded (with a clear access prompt if Calendar permission is missing); expanding Calendar on its own still shows it alone.
  • Activity cycling & restore (M7) — while a live-activity wing is showing, swipe left/right to cycle through every other queued activity, swipe up to dismiss the one showing (restorable — the last 5 dismissed activities can be brought back), and swipe down to open the widget panel.
  • File Shelf — drag files straight onto the notch to hold them: hovering a drag over the (collapsed) camera housing expands the shelf automatically, and dropping copies the files in (they survive the source being moved, ejected, or deleted). From the shelf: click a tile to open it, drag it back out to Finder/Mail/Slack/etc., or use the tile's context menu for AirDrop, "Show in Finder", or "Copy". An optional auto-clear (never / 1 / 3 / 7 days) in Settings → Notch tidies the shelf on its own.
  • Calendar — your upcoming events (Today/Tomorrow), with a colored dot per calendar, time range, and location, right in the notch. Needs Calendar access; Settings → Notch shows the live grant/denied status and a button to request access or jump straight to System Settings if it's off. A wing appears automatically when an event is starting within 10 minutes — no repeating timer, just a single scheduled check for the next event's own threshold.
  • Live Activities — brief wings around the notch for battery, Bluetooth, and calendar events: a wing when you plug in, unplug, or cross below 20% battery unplugged (tinted to read as urgent, re-arming once you're back above 25% or plugged in), a wing when AirPods or another Bluetooth audio/HID accessory connects or disconnects, with a best-effort battery reading when the OS reports one, and a wing when a calendar event is about to start. Each is independently toggled in Settings → Notch.
  • Mirror — a live camera preview right in the notch, for a quick "how do I look" check. The camera only ever runs while the widget is actually open; needs Camera access, with the same live grant/denied status and re-request button as every other permission-gated feature.
  • Timers — start a 1/5/10/25 minute countdown from the shared Flux menu. A live wing shows the nearest remaining time with second precision while a timer runs, and a higher-priority wing (with a sound) announces completion. The Timer live display toggle in Settings → Notch controls both.
  • Clipboard — an in-memory-only history of what you copy, with click-to-copy-back, per-item removal, and Clear All. Off by default — history collection is opt-in, since clipboard contents routinely include passwords and other sensitive one-time text; nothing is ever written to disk, and password-manager-marked copies (the nspasteboard.org concealed/transient convention) are never captured at all. Cmd-C/Cmd-X are captured immediately, with pasteboard change polling as a fallback for menu copies, screenshots, files, and scripts.
  • Lock screen — optionally keeps the solid-black notch silhouette and native Liquid Glass surfaces visible on the macOS lock screen. When something is playing, the centered Now Playing card shows artwork/title/artist plus previous/play-next controls; the card is the only interactive overlay and the rest of the lock-screen UI remains mouse-transparent. The current live activity appears as a compact caption widget (battery, Bluetooth, calendar, timer, ...), with a short thunky system click on unlock. Each sub-feature has its own toggle, all nested under the master switch. Off by default: it uses macOS lock-screen notifications and a dynamically loaded system-level window-space bridge, so the integration is isolated and can be disabled cleanly if a future macOS release changes it — see Settings → Lock Screen.
  • Auto re-hide after an adjustable delay.
  • Launch at login (via SMAppService — the modern, sanctioned API).
  • Three menu-bar icon styles: Chevron / Dot / Line.
  • Light & dark, adapts to your system accent color.
  • Runs as a true agent: no Dock icon, no app switcher entry.

Privacy and permissions

Calendar and Camera are the only TCC permissions Flux currently requests. Both are opt-in and behind their own explicit Grant Access button in Settings → Notch; the permission-gated widget shows its own "access needed" state until you ask for it. Everything else in the app (menu-bar hiding, the notch panel, widget cycling, Now Playing, battery/Bluetooth/timer/calendar-event wings, and the lock-screen overlay) does not use Screen Recording. Permissions are requested only when a capability needs them, and denied features continue to show a useful fallback state.

  • Bluetooth device wings need no permission at all. Flux detects accessory connect/disconnect through the system's own device registry (the IOKit AppleDeviceManagementHIDEventService that already reports accessory battery, permission-free) plus CoreAudio's device list — it never requests Bluetooth access, so nothing prompts, and the wings are on by default like the rest of the notch suite.
  • Clipboard history is opt-in and in-memory only — nothing is captured until you turn it on, and nothing it captures is ever written to disk.

Every grant above is revocable at any time in System Settings, and every gated feature degrades gracefully (its own empty/permission state) rather than breaking the rest of the app when access isn't there.

Install

Grab the latest Flux.dmg from the Releases page, open it, and drag Flux into Applications. On first launch, right-click the app → Open (it's ad-hoc signed, not notarized). A chevron appears near your clock.

A note on permissions: Flux is ad-hoc signed rather than notarized with a paid Developer ID, which means macOS can — and sometimes does — treat an update as a new, untrusted binary and quietly drop a previously granted TCC permission (Calendar or Camera). If a permission-gated widget suddenly shows its "access needed" state after updating Flux, that's why — Settings → Notch shows the live grant/denied status for each permission and a button to re-request it or jump straight to the right System Settings pane.

Build & run

Requires Xcode 15+ (built and tested on Xcode 26 / Swift 6.3, macOS 26).

# Build the signed .app bundle → build/Flux.app
./Scripts/build_app.sh release
# Package a distributable disk image → build/Flux.dmg
./Scripts/build_dmg.sh
# Launch it
open build/Flux.app

Or for quick iteration:

swift build && swift run

The debug executable cannot register Launch at login; use the bundled app for that setting so macOS does not launch a bare process through Terminal.

Developer / CI helpers

The executable understands a few headless flags used for testing:

Flux --selftest # functional test of the collapse engine
Flux --snapshot out.png [light|dark] # render the real settings UI to a PNG
Flux --snapshot-notch out.png [dark] [collapsed|activity|expanded|lockscreen] # render the notch panel to a PNG

Architecture

Sources/Flux/
main.swift # agent entry point (.accessory activation)
App/AppDelegate.swift # wires settings ↔ engine ↔ login ↔ hotkey
MenuBar/
MenuBarManager.swift # reveal/collapse state machine, auto-rehide, menu, arrange
ControlItem.swift # one NSStatusItem as chevron or expandable divider
MenuBarArranger.swift # observable toggle for Arrange Mode (Settings ↔ engine)
MenuBarSection.swift # the three-zone model
MenuBarIconStyle.swift # chevron / dot / line
Settings/
SettingsStore.swift # UserDefaults-backed, observable
SettingsView.swift # tab host (General / Menu Bar / Notch / About)
SettingsRows.swift # shared row primitives
Tabs/ # one file per settings tab
SettingsWindowController.swift
Notch/
NotchWindowController.swift # owns the notch panel's lifecycle
NotchViewModel.swift # collapsed/activity/expanded state machine
NotchWidget.swift # widget protocol + registry
LiveActivity.swift # priority-queued "wings" content
LiveActivitySources.swift # NotchActivityRouter — single home for every activity producer
TimerActivity.swift # live timer-wing formatting and selection
Widgets/NowPlayingWidget.swift
Widgets/ShelfWidget.swift # tiles, drag in/out, AirDrop/Finder/Copy
Widgets/CalendarWidget.swift # agenda, permission states
Widgets/MirrorWidget.swift # live camera preview; owns CameraService start/stop itself
Widgets/ClipboardWidget.swift # history list, click-to-copy-back, Clear All
LockScreenPresenter.swift # EXPERIMENTAL: fade in/out, lock/unlock, unlock sound
LockScreenContentView.swift # EXPERIMENTAL: live media/activity widgets on the lock screen
Services/NowPlaying/ # MediaRemote adapter — the sole Now Playing source
Services/Shelf/ # ShelfStore (copy-in, manifest, QuickLook thumbs, expiry)
Services/CalendarService.swift # EventKit, refresh on EKEventStoreChanged (no polling)
Services/PowerMonitor.swift # IOKit battery/AC events (plug/unplug, low battery)
Services/DeviceMonitor.swift # permission-free BT connect/disconnect: IOKit matching notifications + CoreAudio device list + IORegistry battery
Services/CameraService.swift # AVCaptureSession behind Mirror, started/stopped by the widget itself
Services/ClipboardMonitor.swift # keyboard-assisted capture + changeCount fallback
Services/TimerService.swift # countdown timers, single boundary Task, completions publisher
Login/LoginItemManager.swift # SMAppService launch-at-login
Hotkey/HotkeyManager.swift # Carbon global hotkeys (menu-bar toggle + notch toggle)
Hotkey/HotkeyShortcut.swift # the chord model + ⌃⌥⌘F / ⌃⌥⌘N defaults
Hotkey/HotkeyRecorderView.swift # click-to-record shortcut field
Support/PermissionCenter.swift # unified TCC status/request for Calendar/Camera
Support/ # logging, app info, render/snapshot/selftest

Roadmap (post-MVP)

  • Per-app list control and a searchable drawer popover (needs Accessibility + ScreenCaptureKit — deliberately deferred to keep the MVP resource-light).
  • Custom hotkey recording, profiles, triggers (show on update/active).
  • Graduating the lock-screen silhouette out of "experimental," if it proves durable across macOS updates.

License

MIT © 2026 Ammar Badawy.

About

A calmer menu bar for macOS — a fast, stable, zero-permission Bartender alternative.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Flux

A calmer menu bar. A fast, stable, near-zero-resource menu bar manager for macOS — a Bartender alternative built for performance and stability first.

LightDark
Flux settings, lightFlux settings, dark

Why Flux

Most menu-bar managers feel buggy because they continuously capture and redraw the menu bar with ScreenCaptureKit. That approach burns CPU/GPU, needs Screen Recording permission, and breaks on every macOS update.

Flux takes the opposite approach. It plants its own invisible, expandable status items as section dividers and collapses them to push other apps' icons off the visible bar. The result:

  • ~0% CPU at idle — it only reacts to clicks, nothing polls or redraws.
  • Minimal permissions — the core menu-bar manager needs no Screen Recording or Accessibility grant. Calendar and Camera ask only when their widgets are enabled; the optional lock-screen overlay uses macOS's lock-screen window space instead of screen capture.
  • Stable across releases — relies on documented NSStatusItem behaviour, not private or capture APIs. Targets Sonoma (14), Sequoia (15), Tahoe (26) and is forward-compatible with the upcoming Golden Gate (27).

The three zones (just like Bartender)

[ Always-Hidden ] ‹‹ [ Hidden ] ‹ ⌄ [ Shown ] 🕓
│ │ │
always-hidden hidden Flux chevron
divider divider
ZoneBehaviour
ShownAlways visible. Anything to the right of the chevron — it never hides.
HiddenRevealed when you click the Flux chevron (the "drawer").
Always-HiddenRevealed only with ⌥ (option) — kept fully out of the way.

Nothing is hidden until you say so. On a fresh install Flux seeds its chevron and dividers to the left of every icon you already have, so all of them start in Shown and the bar looks exactly as it did before. You then drag icons leftward, past the chevron, to tuck them away.

You assign an icon to a zone by ⌘-dragging it to one side of a Flux divider — the native macOS gesture. To make the (normally invisible) zone boundaries visible while you do this, open Arrange Menu Bar — from Settings or the chevron's right-click menu. Flux reveals every icon and drops a labeled marker at each boundary, so you can see exactly where to drop each icon:

  • Left of the Hidden marker → Hidden
  • Left of the Always Hidden marker → Always-Hidden
  • Right of the Hidden marker → Shown

Click Done (or the ✓ that replaces the chevron) to apply. Flux remembers the arrangement across launches.

Features (MVP)

  • Click the chevron (or press the global hotkey, ⌃⌥⌘F by default and fully rebindable in Settings) to reveal. Clicking a revealed icon keeps it open so you can use it; clicking down in a window re-hides.
  • Arrange Mode — a guided editor that reveals labeled zone markers in the live menu bar so assigning icons to Shown / Hidden / Always-Hidden is clear and visible.
  • Optional Always-Hidden zone.
  • Notch panel — Alcove-inspired compact redesign (M7) — a seamless solid-black panel sized to the notch suite's shared footprint, with overshoot springs on open and a snappy, no-bounce close, plus a soft content morph as it expands. Hover (or click) the camera housing to expand a Now Playing widget: artwork, title/artist, a scrubber, and transport controls for whatever's playing (any app, via a vendored MediaRemote adapter). Open gesture, hover delays, and which widgets are enabled are all configurable in Settings → Notch.
  • Duo view (M7) — an opt-in toggle in Settings → Notch shows Now Playing and Calendar side by side when Now Playing is expanded (with a clear access prompt if Calendar permission is missing); expanding Calendar on its own still shows it alone.
  • Activity cycling & restore (M7) — while a live-activity wing is showing, swipe left/right to cycle through every other queued activity, swipe up to dismiss the one showing (restorable — the last 5 dismissed activities can be brought back), and swipe down to open the widget panel.
  • File Shelf — drag files straight onto the notch to hold them: hovering a drag over the (collapsed) camera housing expands the shelf automatically, and dropping copies the files in (they survive the source being moved, ejected, or deleted). From the shelf: click a tile to open it, drag it back out to Finder/Mail/Slack/etc., or use the tile's context menu for AirDrop, "Show in Finder", or "Copy". An optional auto-clear (never / 1 / 3 / 7 days) in Settings → Notch tidies the shelf on its own.
  • Calendar — your upcoming events (Today/Tomorrow), with a colored dot per calendar, time range, and location, right in the notch. Needs Calendar access; Settings → Notch shows the live grant/denied status and a button to request access or jump straight to System Settings if it's off. A wing appears automatically when an event is starting within 10 minutes — no repeating timer, just a single scheduled check for the next event's own threshold.
  • Live Activities — brief wings around the notch for battery, Bluetooth, and calendar events: a wing when you plug in, unplug, or cross below 20% battery unplugged (tinted to read as urgent, re-arming once you're back above 25% or plugged in), a wing when AirPods or another Bluetooth audio/HID accessory connects or disconnects, with a best-effort battery reading when the OS reports one, and a wing when a calendar event is about to start. Each is independently toggled in Settings → Notch.
  • Mirror — a live camera preview right in the notch, for a quick "how do I look" check. The camera only ever runs while the widget is actually open; needs Camera access, with the same live grant/denied status and re-request button as every other permission-gated feature.
  • Timers — start a 1/5/10/25 minute countdown from the shared Flux menu. A live wing shows the nearest remaining time with second precision while a timer runs, and a higher-priority wing (with a sound) announces completion. The Timer live display toggle in Settings → Notch controls both.
  • Clipboard — an in-memory-only history of what you copy, with click-to-copy-back, per-item removal, and Clear All. Off by default — history collection is opt-in, since clipboard contents routinely include passwords and other sensitive one-time text; nothing is ever written to disk, and password-manager-marked copies (the nspasteboard.org concealed/transient convention) are never captured at all. Cmd-C/Cmd-X are captured immediately, with pasteboard change polling as a fallback for menu copies, screenshots, files, and scripts.
  • Lock screen — optionally keeps the solid-black notch silhouette and native Liquid Glass surfaces visible on the macOS lock screen. When something is playing, the centered Now Playing card shows artwork/title/artist plus previous/play-next controls; the card is the only interactive overlay and the rest of the lock-screen UI remains mouse-transparent. The current live activity appears as a compact caption widget (battery, Bluetooth, calendar, timer, ...), with a short thunky system click on unlock. Each sub-feature has its own toggle, all nested under the master switch. Off by default: it uses macOS lock-screen notifications and a dynamically loaded system-level window-space bridge, so the integration is isolated and can be disabled cleanly if a future macOS release changes it — see Settings → Lock Screen.
  • Auto re-hide after an adjustable delay.
  • Launch at login (via SMAppService — the modern, sanctioned API).
  • Three menu-bar icon styles: Chevron / Dot / Line.
  • Light & dark, adapts to your system accent color.
  • Runs as a true agent: no Dock icon, no app switcher entry.

Privacy and permissions

Calendar and Camera are the only TCC permissions Flux currently requests. Both are opt-in and behind their own explicit Grant Access button in Settings → Notch; the permission-gated widget shows its own "access needed" state until you ask for it. Everything else in the app (menu-bar hiding, the notch panel, widget cycling, Now Playing, battery/Bluetooth/timer/calendar-event wings, and the lock-screen overlay) does not use Screen Recording. Permissions are requested only when a capability needs them, and denied features continue to show a useful fallback state.

  • Bluetooth device wings need no permission at all. Flux detects accessory connect/disconnect through the system's own device registry (the IOKit AppleDeviceManagementHIDEventService that already reports accessory battery, permission-free) plus CoreAudio's device list — it never requests Bluetooth access, so nothing prompts, and the wings are on by default like the rest of the notch suite.
  • Clipboard history is opt-in and in-memory only — nothing is captured until you turn it on, and nothing it captures is ever written to disk.

Every grant above is revocable at any time in System Settings, and every gated feature degrades gracefully (its own empty/permission state) rather than breaking the rest of the app when access isn't there.

Install

Grab the latest Flux.dmg from the Releases page, open it, and drag Flux into Applications. On first launch, right-click the app → Open (it's ad-hoc signed, not notarized). A chevron appears near your clock.

A note on permissions: Flux is ad-hoc signed rather than notarized with a paid Developer ID, which means macOS can — and sometimes does — treat an update as a new, untrusted binary and quietly drop a previously granted TCC permission (Calendar or Camera). If a permission-gated widget suddenly shows its "access needed" state after updating Flux, that's why — Settings → Notch shows the live grant/denied status for each permission and a button to re-request it or jump straight to the right System Settings pane.

Build & run

Requires Xcode 15+ (built and tested on Xcode 26 / Swift 6.3, macOS 26).

# Build the signed .app bundle → build/Flux.app
./Scripts/build_app.sh release
# Package a distributable disk image → build/Flux.dmg
./Scripts/build_dmg.sh
# Launch it
open build/Flux.app

Or for quick iteration:

swift build && swift run

The debug executable cannot register Launch at login; use the bundled app for that setting so macOS does not launch a bare process through Terminal.

Developer / CI helpers

The executable understands a few headless flags used for testing:

Flux --selftest # functional test of the collapse engine
Flux --snapshot out.png [light|dark] # render the real settings UI to a PNG
Flux --snapshot-notch out.png [dark] [collapsed|activity|expanded|lockscreen] # render the notch panel to a PNG

Architecture

Sources/Flux/
main.swift # agent entry point (.accessory activation)
App/AppDelegate.swift # wires settings ↔ engine ↔ login ↔ hotkey
MenuBar/
MenuBarManager.swift # reveal/collapse state machine, auto-rehide, menu, arrange
ControlItem.swift # one NSStatusItem as chevron or expandable divider
MenuBarArranger.swift # observable toggle for Arrange Mode (Settings ↔ engine)
MenuBarSection.swift # the three-zone model
MenuBarIconStyle.swift # chevron / dot / line
Settings/
SettingsStore.swift # UserDefaults-backed, observable
SettingsView.swift # tab host (General / Menu Bar / Notch / About)
SettingsRows.swift # shared row primitives
Tabs/ # one file per settings tab
SettingsWindowController.swift
Notch/
NotchWindowController.swift # owns the notch panel's lifecycle
NotchViewModel.swift # collapsed/activity/expanded state machine
NotchWidget.swift # widget protocol + registry
LiveActivity.swift # priority-queued "wings" content
LiveActivitySources.swift # NotchActivityRouter — single home for every activity producer
TimerActivity.swift # live timer-wing formatting and selection
Widgets/NowPlayingWidget.swift
Widgets/ShelfWidget.swift # tiles, drag in/out, AirDrop/Finder/Copy
Widgets/CalendarWidget.swift # agenda, permission states
Widgets/MirrorWidget.swift # live camera preview; owns CameraService start/stop itself
Widgets/ClipboardWidget.swift # history list, click-to-copy-back, Clear All
LockScreenPresenter.swift # EXPERIMENTAL: fade in/out, lock/unlock, unlock sound
LockScreenContentView.swift # EXPERIMENTAL: live media/activity widgets on the lock screen
Services/NowPlaying/ # MediaRemote adapter — the sole Now Playing source
Services/Shelf/ # ShelfStore (copy-in, manifest, QuickLook thumbs, expiry)
Services/CalendarService.swift # EventKit, refresh on EKEventStoreChanged (no polling)
Services/PowerMonitor.swift # IOKit battery/AC events (plug/unplug, low battery)
Services/DeviceMonitor.swift # permission-free BT connect/disconnect: IOKit matching notifications + CoreAudio device list + IORegistry battery
Services/CameraService.swift # AVCaptureSession behind Mirror, started/stopped by the widget itself
Services/ClipboardMonitor.swift # keyboard-assisted capture + changeCount fallback
Services/TimerService.swift # countdown timers, single boundary Task, completions publisher
Login/LoginItemManager.swift # SMAppService launch-at-login
Hotkey/HotkeyManager.swift # Carbon global hotkeys (menu-bar toggle + notch toggle)
Hotkey/HotkeyShortcut.swift # the chord model + ⌃⌥⌘F / ⌃⌥⌘N defaults
Hotkey/HotkeyRecorderView.swift # click-to-record shortcut field
Support/PermissionCenter.swift # unified TCC status/request for Calendar/Camera
Support/ # logging, app info, render/snapshot/selftest

Roadmap (post-MVP)

  • Per-app list control and a searchable drawer popover (needs Accessibility + ScreenCaptureKit — deliberately deferred to keep the MVP resource-light).
  • Custom hotkey recording, profiles, triggers (show on update/active).
  • Graduating the lock-screen silhouette out of "experimental," if it proves durable across macOS updates.

License

MIT © 2026 Ammar Badawy.

About

A calmer menu bar for macOS — a fast, stable, zero-permission Bartender alternative.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Flux

A calmer menu bar. A fast, stable, near-zero-resource menu bar manager for macOS — a Bartender alternative built for performance and stability first.

LightDark
Flux settings, lightFlux settings, dark

Why Flux

Most menu-bar managers feel buggy because they continuously capture and redraw the menu bar with ScreenCaptureKit. That approach burns CPU/GPU, needs Screen Recording permission, and breaks on every macOS update.

Flux takes the opposite approach. It plants its own invisible, expandable status items as section dividers and collapses them to push other apps' icons off the visible bar. The result:

  • ~0% CPU at idle — it only reacts to clicks, nothing polls or redraws.
  • Minimal permissions — the core menu-bar manager needs no Screen Recording or Accessibility grant. Calendar and Camera ask only when their widgets are enabled; the optional lock-screen overlay uses macOS's lock-screen window space instead of screen capture.
  • Stable across releases — relies on documented NSStatusItem behaviour, not private or capture APIs. Targets Sonoma (14), Sequoia (15), Tahoe (26) and is forward-compatible with the upcoming Golden Gate (27).

The three zones (just like Bartender)

[ Always-Hidden ] ‹‹ [ Hidden ] ‹ ⌄ [ Shown ] 🕓
│ │ │
always-hidden hidden Flux chevron
divider divider
ZoneBehaviour
ShownAlways visible. Anything to the right of the chevron — it never hides.
HiddenRevealed when you click the Flux chevron (the "drawer").
Always-HiddenRevealed only with ⌥ (option) — kept fully out of the way.

Nothing is hidden until you say so. On a fresh install Flux seeds its chevron and dividers to the left of every icon you already have, so all of them start in Shown and the bar looks exactly as it did before. You then drag icons leftward, past the chevron, to tuck them away.

You assign an icon to a zone by ⌘-dragging it to one side of a Flux divider — the native macOS gesture. To make the (normally invisible) zone boundaries visible while you do this, open Arrange Menu Bar — from Settings or the chevron's right-click menu. Flux reveals every icon and drops a labeled marker at each boundary, so you can see exactly where to drop each icon:

  • Left of the Hidden marker → Hidden
  • Left of the Always Hidden marker → Always-Hidden
  • Right of the Hidden marker → Shown

Click Done (or the ✓ that replaces the chevron) to apply. Flux remembers the arrangement across launches.

Features (MVP)

  • Click the chevron (or press the global hotkey, ⌃⌥⌘F by default and fully rebindable in Settings) to reveal. Clicking a revealed icon keeps it open so you can use it; clicking down in a window re-hides.
  • Arrange Mode — a guided editor that reveals labeled zone markers in the live menu bar so assigning icons to Shown / Hidden / Always-Hidden is clear and visible.
  • Optional Always-Hidden zone.
  • Notch panel — Alcove-inspired compact redesign (M7) — a seamless solid-black panel sized to the notch suite's shared footprint, with overshoot springs on open and a snappy, no-bounce close, plus a soft content morph as it expands. Hover (or click) the camera housing to expand a Now Playing widget: artwork, title/artist, a scrubber, and transport controls for whatever's playing (any app, via a vendored MediaRemote adapter). Open gesture, hover delays, and which widgets are enabled are all configurable in Settings → Notch.
  • Duo view (M7) — an opt-in toggle in Settings → Notch shows Now Playing and Calendar side by side when Now Playing is expanded (with a clear access prompt if Calendar permission is missing); expanding Calendar on its own still shows it alone.
  • Activity cycling & restore (M7) — while a live-activity wing is showing, swipe left/right to cycle through every other queued activity, swipe up to dismiss the one showing (restorable — the last 5 dismissed activities can be brought back), and swipe down to open the widget panel.
  • File Shelf — drag files straight onto the notch to hold them: hovering a drag over the (collapsed) camera housing expands the shelf automatically, and dropping copies the files in (they survive the source being moved, ejected, or deleted). From the shelf: click a tile to open it, drag it back out to Finder/Mail/Slack/etc., or use the tile's context menu for AirDrop, "Show in Finder", or "Copy". An optional auto-clear (never / 1 / 3 / 7 days) in Settings → Notch tidies the shelf on its own.
  • Calendar — your upcoming events (Today/Tomorrow), with a colored dot per calendar, time range, and location, right in the notch. Needs Calendar access; Settings → Notch shows the live grant/denied status and a button to request access or jump straight to System Settings if it's off. A wing appears automatically when an event is starting within 10 minutes — no repeating timer, just a single scheduled check for the next event's own threshold.
  • Live Activities — brief wings around the notch for battery, Bluetooth, and calendar events: a wing when you plug in, unplug, or cross below 20% battery unplugged (tinted to read as urgent, re-arming once you're back above 25% or plugged in), a wing when AirPods or another Bluetooth audio/HID accessory connects or disconnects, with a best-effort battery reading when the OS reports one, and a wing when a calendar event is about to start. Each is independently toggled in Settings → Notch.
  • Mirror — a live camera preview right in the notch, for a quick "how do I look" check. The camera only ever runs while the widget is actually open; needs Camera access, with the same live grant/denied status and re-request button as every other permission-gated feature.
  • Timers — start a 1/5/10/25 minute countdown from the shared Flux menu. A live wing shows the nearest remaining time with second precision while a timer runs, and a higher-priority wing (with a sound) announces completion. The Timer live display toggle in Settings → Notch controls both.
  • Clipboard — an in-memory-only history of what you copy, with click-to-copy-back, per-item removal, and Clear All. Off by default — history collection is opt-in, since clipboard contents routinely include passwords and other sensitive one-time text; nothing is ever written to disk, and password-manager-marked copies (the nspasteboard.org concealed/transient convention) are never captured at all. Cmd-C/Cmd-X are captured immediately, with pasteboard change polling as a fallback for menu copies, screenshots, files, and scripts.
  • Lock screen — optionally keeps the solid-black notch silhouette and native Liquid Glass surfaces visible on the macOS lock screen. When something is playing, the centered Now Playing card shows artwork/title/artist plus previous/play-next controls; the card is the only interactive overlay and the rest of the lock-screen UI remains mouse-transparent. The current live activity appears as a compact caption widget (battery, Bluetooth, calendar, timer, ...), with a short thunky system click on unlock. Each sub-feature has its own toggle, all nested under the master switch. Off by default: it uses macOS lock-screen notifications and a dynamically loaded system-level window-space bridge, so the integration is isolated and can be disabled cleanly if a future macOS release changes it — see Settings → Lock Screen.
  • Auto re-hide after an adjustable delay.
  • Launch at login (via SMAppService — the modern, sanctioned API).
  • Three menu-bar icon styles: Chevron / Dot / Line.
  • Light & dark, adapts to your system accent color.
  • Runs as a true agent: no Dock icon, no app switcher entry.

Privacy and permissions

Calendar and Camera are the only TCC permissions Flux currently requests. Both are opt-in and behind their own explicit Grant Access button in Settings → Notch; the permission-gated widget shows its own "access needed" state until you ask for it. Everything else in the app (menu-bar hiding, the notch panel, widget cycling, Now Playing, battery/Bluetooth/timer/calendar-event wings, and the lock-screen overlay) does not use Screen Recording. Permissions are requested only when a capability needs them, and denied features continue to show a useful fallback state.

  • Bluetooth device wings need no permission at all. Flux detects accessory connect/disconnect through the system's own device registry (the IOKit AppleDeviceManagementHIDEventService that already reports accessory battery, permission-free) plus CoreAudio's device list — it never requests Bluetooth access, so nothing prompts, and the wings are on by default like the rest of the notch suite.
  • Clipboard history is opt-in and in-memory only — nothing is captured until you turn it on, and nothing it captures is ever written to disk.

Every grant above is revocable at any time in System Settings, and every gated feature degrades gracefully (its own empty/permission state) rather than breaking the rest of the app when access isn't there.

Install

Grab the latest Flux.dmg from the Releases page, open it, and drag Flux into Applications. On first launch, right-click the app → Open (it's ad-hoc signed, not notarized). A chevron appears near your clock.

A note on permissions: Flux is ad-hoc signed rather than notarized with a paid Developer ID, which means macOS can — and sometimes does — treat an update as a new, untrusted binary and quietly drop a previously granted TCC permission (Calendar or Camera). If a permission-gated widget suddenly shows its "access needed" state after updating Flux, that's why — Settings → Notch shows the live grant/denied status for each permission and a button to re-request it or jump straight to the right System Settings pane.

Build & run

Requires Xcode 15+ (built and tested on Xcode 26 / Swift 6.3, macOS 26).

# Build the signed .app bundle → build/Flux.app
./Scripts/build_app.sh release
# Package a distributable disk image → build/Flux.dmg
./Scripts/build_dmg.sh
# Launch it
open build/Flux.app

Or for quick iteration:

swift build && swift run

The debug executable cannot register Launch at login; use the bundled app for that setting so macOS does not launch a bare process through Terminal.

Developer / CI helpers

The executable understands a few headless flags used for testing:

Flux --selftest # functional test of the collapse engine
Flux --snapshot out.png [light|dark] # render the real settings UI to a PNG
Flux --snapshot-notch out.png [dark] [collapsed|activity|expanded|lockscreen] # render the notch panel to a PNG

Architecture

Sources/Flux/
main.swift # agent entry point (.accessory activation)
App/AppDelegate.swift # wires settings ↔ engine ↔ login ↔ hotkey
MenuBar/
MenuBarManager.swift # reveal/collapse state machine, auto-rehide, menu, arrange
ControlItem.swift # one NSStatusItem as chevron or expandable divider
MenuBarArranger.swift # observable toggle for Arrange Mode (Settings ↔ engine)
MenuBarSection.swift # the three-zone model
MenuBarIconStyle.swift # chevron / dot / line
Settings/
SettingsStore.swift # UserDefaults-backed, observable
SettingsView.swift # tab host (General / Menu Bar / Notch / About)
SettingsRows.swift # shared row primitives
Tabs/ # one file per settings tab
SettingsWindowController.swift
Notch/
NotchWindowController.swift # owns the notch panel's lifecycle
NotchViewModel.swift # collapsed/activity/expanded state machine
NotchWidget.swift # widget protocol + registry
LiveActivity.swift # priority-queued "wings" content
LiveActivitySources.swift # NotchActivityRouter — single home for every activity producer
TimerActivity.swift # live timer-wing formatting and selection
Widgets/NowPlayingWidget.swift
Widgets/ShelfWidget.swift # tiles, drag in/out, AirDrop/Finder/Copy
Widgets/CalendarWidget.swift # agenda, permission states
Widgets/MirrorWidget.swift # live camera preview; owns CameraService start/stop itself
Widgets/ClipboardWidget.swift # history list, click-to-copy-back, Clear All
LockScreenPresenter.swift # EXPERIMENTAL: fade in/out, lock/unlock, unlock sound
LockScreenContentView.swift # EXPERIMENTAL: live media/activity widgets on the lock screen
Services/NowPlaying/ # MediaRemote adapter — the sole Now Playing source
Services/Shelf/ # ShelfStore (copy-in, manifest, QuickLook thumbs, expiry)
Services/CalendarService.swift # EventKit, refresh on EKEventStoreChanged (no polling)
Services/PowerMonitor.swift # IOKit battery/AC events (plug/unplug, low battery)
Services/DeviceMonitor.swift # permission-free BT connect/disconnect: IOKit matching notifications + CoreAudio device list + IORegistry battery
Services/CameraService.swift # AVCaptureSession behind Mirror, started/stopped by the widget itself
Services/ClipboardMonitor.swift # keyboard-assisted capture + changeCount fallback
Services/TimerService.swift # countdown timers, single boundary Task, completions publisher
Login/LoginItemManager.swift # SMAppService launch-at-login
Hotkey/HotkeyManager.swift # Carbon global hotkeys (menu-bar toggle + notch toggle)
Hotkey/HotkeyShortcut.swift # the chord model + ⌃⌥⌘F / ⌃⌥⌘N defaults
Hotkey/HotkeyRecorderView.swift # click-to-record shortcut field
Support/PermissionCenter.swift # unified TCC status/request for Calendar/Camera
Support/ # logging, app info, render/snapshot/selftest

Roadmap (post-MVP)

  • Per-app list control and a searchable drawer popover (needs Accessibility + ScreenCaptureKit — deliberately deferred to keep the MVP resource-light).
  • Custom hotkey recording, profiles, triggers (show on update/active).
  • Graduating the lock-screen silhouette out of "experimental," if it proves durable across macOS updates.

License

MIT © 2026 Ammar Badawy.

About

A calmer menu bar for macOS — a fast, stable, zero-permission Bartender alternative.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Flux

A calmer menu bar. A fast, stable, near-zero-resource menu bar manager for macOS — a Bartender alternative built for performance and stability first.

LightDark
Flux settings, lightFlux settings, dark

Why Flux

Most menu-bar managers feel buggy because they continuously capture and redraw the menu bar with ScreenCaptureKit. That approach burns CPU/GPU, needs Screen Recording permission, and breaks on every macOS update.

Flux takes the opposite approach. It plants its own invisible, expandable status items as section dividers and collapses them to push other apps' icons off the visible bar. The result:

  • ~0% CPU at idle — it only reacts to clicks, nothing polls or redraws.
  • Minimal permissions — the core menu-bar manager needs no Screen Recording or Accessibility grant. Calendar and Camera ask only when their widgets are enabled; the optional lock-screen overlay uses macOS's lock-screen window space instead of screen capture.
  • Stable across releases — relies on documented NSStatusItem behaviour, not private or capture APIs. Targets Sonoma (14), Sequoia (15), Tahoe (26) and is forward-compatible with the upcoming Golden Gate (27).

The three zones (just like Bartender)

[ Always-Hidden ] ‹‹ [ Hidden ] ‹ ⌄ [ Shown ] 🕓
│ │ │
always-hidden hidden Flux chevron
divider divider
ZoneBehaviour
ShownAlways visible. Anything to the right of the chevron — it never hides.
HiddenRevealed when you click the Flux chevron (the "drawer").
Always-HiddenRevealed only with ⌥ (option) — kept fully out of the way.

Nothing is hidden until you say so. On a fresh install Flux seeds its chevron and dividers to the left of every icon you already have, so all of them start in Shown and the bar looks exactly as it did before. You then drag icons leftward, past the chevron, to tuck them away.

You assign an icon to a zone by ⌘-dragging it to one side of a Flux divider — the native macOS gesture. To make the (normally invisible) zone boundaries visible while you do this, open Arrange Menu Bar — from Settings or the chevron's right-click menu. Flux reveals every icon and drops a labeled marker at each boundary, so you can see exactly where to drop each icon:

  • Left of the Hidden marker → Hidden
  • Left of the Always Hidden marker → Always-Hidden
  • Right of the Hidden marker → Shown

Click Done (or the ✓ that replaces the chevron) to apply. Flux remembers the arrangement across launches.

Features (MVP)

  • Click the chevron (or press the global hotkey, ⌃⌥⌘F by default and fully rebindable in Settings) to reveal. Clicking a revealed icon keeps it open so you can use it; clicking down in a window re-hides.
  • Arrange Mode — a guided editor that reveals labeled zone markers in the live menu bar so assigning icons to Shown / Hidden / Always-Hidden is clear and visible.
  • Optional Always-Hidden zone.
  • Notch panel — Alcove-inspired compact redesign (M7) — a seamless solid-black panel sized to the notch suite's shared footprint, with overshoot springs on open and a snappy, no-bounce close, plus a soft content morph as it expands. Hover (or click) the camera housing to expand a Now Playing widget: artwork, title/artist, a scrubber, and transport controls for whatever's playing (any app, via a vendored MediaRemote adapter). Open gesture, hover delays, and which widgets are enabled are all configurable in Settings → Notch.
  • Duo view (M7) — an opt-in toggle in Settings → Notch shows Now Playing and Calendar side by side when Now Playing is expanded (with a clear access prompt if Calendar permission is missing); expanding Calendar on its own still shows it alone.
  • Activity cycling & restore (M7) — while a live-activity wing is showing, swipe left/right to cycle through every other queued activity, swipe up to dismiss the one showing (restorable — the last 5 dismissed activities can be brought back), and swipe down to open the widget panel.
  • File Shelf — drag files straight onto the notch to hold them: hovering a drag over the (collapsed) camera housing expands the shelf automatically, and dropping copies the files in (they survive the source being moved, ejected, or deleted). From the shelf: click a tile to open it, drag it back out to Finder/Mail/Slack/etc., or use the tile's context menu for AirDrop, "Show in Finder", or "Copy". An optional auto-clear (never / 1 / 3 / 7 days) in Settings → Notch tidies the shelf on its own.
  • Calendar — your upcoming events (Today/Tomorrow), with a colored dot per calendar, time range, and location, right in the notch. Needs Calendar access; Settings → Notch shows the live grant/denied status and a button to request access or jump straight to System Settings if it's off. A wing appears automatically when an event is starting within 10 minutes — no repeating timer, just a single scheduled check for the next event's own threshold.
  • Live Activities — brief wings around the notch for battery, Bluetooth, and calendar events: a wing when you plug in, unplug, or cross below 20% battery unplugged (tinted to read as urgent, re-arming once you're back above 25% or plugged in), a wing when AirPods or another Bluetooth audio/HID accessory connects or disconnects, with a best-effort battery reading when the OS reports one, and a wing when a calendar event is about to start. Each is independently toggled in Settings → Notch.
  • Mirror — a live camera preview right in the notch, for a quick "how do I look" check. The camera only ever runs while the widget is actually open; needs Camera access, with the same live grant/denied status and re-request button as every other permission-gated feature.
  • Timers — start a 1/5/10/25 minute countdown from the shared Flux menu. A live wing shows the nearest remaining time with second precision while a timer runs, and a higher-priority wing (with a sound) announces completion. The Timer live display toggle in Settings → Notch controls both.
  • Clipboard — an in-memory-only history of what you copy, with click-to-copy-back, per-item removal, and Clear All. Off by default — history collection is opt-in, since clipboard contents routinely include passwords and other sensitive one-time text; nothing is ever written to disk, and password-manager-marked copies (the nspasteboard.org concealed/transient convention) are never captured at all. Cmd-C/Cmd-X are captured immediately, with pasteboard change polling as a fallback for menu copies, screenshots, files, and scripts.
  • Lock screen — optionally keeps the solid-black notch silhouette and native Liquid Glass surfaces visible on the macOS lock screen. When something is playing, the centered Now Playing card shows artwork/title/artist plus previous/play-next controls; the card is the only interactive overlay and the rest of the lock-screen UI remains mouse-transparent. The current live activity appears as a compact caption widget (battery, Bluetooth, calendar, timer, ...), with a short thunky system click on unlock. Each sub-feature has its own toggle, all nested under the master switch. Off by default: it uses macOS lock-screen notifications and a dynamically loaded system-level window-space bridge, so the integration is isolated and can be disabled cleanly if a future macOS release changes it — see Settings → Lock Screen.
  • Auto re-hide after an adjustable delay.
  • Launch at login (via SMAppService — the modern, sanctioned API).
  • Three menu-bar icon styles: Chevron / Dot / Line.
  • Light & dark, adapts to your system accent color.
  • Runs as a true agent: no Dock icon, no app switcher entry.

Privacy and permissions

Calendar and Camera are the only TCC permissions Flux currently requests. Both are opt-in and behind their own explicit Grant Access button in Settings → Notch; the permission-gated widget shows its own "access needed" state until you ask for it. Everything else in the app (menu-bar hiding, the notch panel, widget cycling, Now Playing, battery/Bluetooth/timer/calendar-event wings, and the lock-screen overlay) does not use Screen Recording. Permissions are requested only when a capability needs them, and denied features continue to show a useful fallback state.

  • Bluetooth device wings need no permission at all. Flux detects accessory connect/disconnect through the system's own device registry (the IOKit AppleDeviceManagementHIDEventService that already reports accessory battery, permission-free) plus CoreAudio's device list — it never requests Bluetooth access, so nothing prompts, and the wings are on by default like the rest of the notch suite.
  • Clipboard history is opt-in and in-memory only — nothing is captured until you turn it on, and nothing it captures is ever written to disk.

Every grant above is revocable at any time in System Settings, and every gated feature degrades gracefully (its own empty/permission state) rather than breaking the rest of the app when access isn't there.

Install

Grab the latest Flux.dmg from the Releases page, open it, and drag Flux into Applications. On first launch, right-click the app → Open (it's ad-hoc signed, not notarized). A chevron appears near your clock.

A note on permissions: Flux is ad-hoc signed rather than notarized with a paid Developer ID, which means macOS can — and sometimes does — treat an update as a new, untrusted binary and quietly drop a previously granted TCC permission (Calendar or Camera). If a permission-gated widget suddenly shows its "access needed" state after updating Flux, that's why — Settings → Notch shows the live grant/denied status for each permission and a button to re-request it or jump straight to the right System Settings pane.

Build & run

Requires Xcode 15+ (built and tested on Xcode 26 / Swift 6.3, macOS 26).

# Build the signed .app bundle → build/Flux.app
./Scripts/build_app.sh release
# Package a distributable disk image → build/Flux.dmg
./Scripts/build_dmg.sh
# Launch it
open build/Flux.app

Or for quick iteration:

swift build && swift run

The debug executable cannot register Launch at login; use the bundled app for that setting so macOS does not launch a bare process through Terminal.

Developer / CI helpers

The executable understands a few headless flags used for testing:

Flux --selftest # functional test of the collapse engine
Flux --snapshot out.png [light|dark] # render the real settings UI to a PNG
Flux --snapshot-notch out.png [dark] [collapsed|activity|expanded|lockscreen] # render the notch panel to a PNG

Architecture

Sources/Flux/
main.swift # agent entry point (.accessory activation)
App/AppDelegate.swift # wires settings ↔ engine ↔ login ↔ hotkey
MenuBar/
MenuBarManager.swift # reveal/collapse state machine, auto-rehide, menu, arrange
ControlItem.swift # one NSStatusItem as chevron or expandable divider
MenuBarArranger.swift # observable toggle for Arrange Mode (Settings ↔ engine)
MenuBarSection.swift # the three-zone model
MenuBarIconStyle.swift # chevron / dot / line
Settings/
SettingsStore.swift # UserDefaults-backed, observable
SettingsView.swift # tab host (General / Menu Bar / Notch / About)
SettingsRows.swift # shared row primitives
Tabs/ # one file per settings tab
SettingsWindowController.swift
Notch/
NotchWindowController.swift # owns the notch panel's lifecycle
NotchViewModel.swift # collapsed/activity/expanded state machine
NotchWidget.swift # widget protocol + registry
LiveActivity.swift # priority-queued "wings" content
LiveActivitySources.swift # NotchActivityRouter — single home for every activity producer
TimerActivity.swift # live timer-wing formatting and selection
Widgets/NowPlayingWidget.swift
Widgets/ShelfWidget.swift # tiles, drag in/out, AirDrop/Finder/Copy
Widgets/CalendarWidget.swift # agenda, permission states
Widgets/MirrorWidget.swift # live camera preview; owns CameraService start/stop itself
Widgets/ClipboardWidget.swift # history list, click-to-copy-back, Clear All
LockScreenPresenter.swift # EXPERIMENTAL: fade in/out, lock/unlock, unlock sound
LockScreenContentView.swift # EXPERIMENTAL: live media/activity widgets on the lock screen
Services/NowPlaying/ # MediaRemote adapter — the sole Now Playing source
Services/Shelf/ # ShelfStore (copy-in, manifest, QuickLook thumbs, expiry)
Services/CalendarService.swift # EventKit, refresh on EKEventStoreChanged (no polling)
Services/PowerMonitor.swift # IOKit battery/AC events (plug/unplug, low battery)
Services/DeviceMonitor.swift # permission-free BT connect/disconnect: IOKit matching notifications + CoreAudio device list + IORegistry battery
Services/CameraService.swift # AVCaptureSession behind Mirror, started/stopped by the widget itself
Services/ClipboardMonitor.swift # keyboard-assisted capture + changeCount fallback
Services/TimerService.swift # countdown timers, single boundary Task, completions publisher
Login/LoginItemManager.swift # SMAppService launch-at-login
Hotkey/HotkeyManager.swift # Carbon global hotkeys (menu-bar toggle + notch toggle)
Hotkey/HotkeyShortcut.swift # the chord model + ⌃⌥⌘F / ⌃⌥⌘N defaults
Hotkey/HotkeyRecorderView.swift # click-to-record shortcut field
Support/PermissionCenter.swift # unified TCC status/request for Calendar/Camera
Support/ # logging, app info, render/snapshot/selftest

Roadmap (post-MVP)

  • Per-app list control and a searchable drawer popover (needs Accessibility + ScreenCaptureKit — deliberately deferred to keep the MVP resource-light).
  • Custom hotkey recording, profiles, triggers (show on update/active).
  • Graduating the lock-screen silhouette out of "experimental," if it proves durable across macOS updates.

License

MIT © 2026 Ammar Badawy.

About

A calmer menu bar for macOS — a fast, stable, zero-permission Bartender alternative.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Flux

A calmer menu bar. A fast, stable, near-zero-resource menu bar manager for macOS — a Bartender alternative built for performance and stability first.

LightDark
Flux settings, lightFlux settings, dark

Why Flux

Most menu-bar managers feel buggy because they continuously capture and redraw the menu bar with ScreenCaptureKit. That approach burns CPU/GPU, needs Screen Recording permission, and breaks on every macOS update.

Flux takes the opposite approach. It plants its own invisible, expandable status items as section dividers and collapses them to push other apps' icons off the visible bar. The result:

  • ~0% CPU at idle — it only reacts to clicks, nothing polls or redraws.
  • Minimal permissions — the core menu-bar manager needs no Screen Recording or Accessibility grant. Calendar and Camera ask only when their widgets are enabled; the optional lock-screen overlay uses macOS's lock-screen window space instead of screen capture.
  • Stable across releases — relies on documented NSStatusItem behaviour, not private or capture APIs. Targets Sonoma (14), Sequoia (15), Tahoe (26) and is forward-compatible with the upcoming Golden Gate (27).

The three zones (just like Bartender)

[ Always-Hidden ] ‹‹ [ Hidden ] ‹ ⌄ [ Shown ] 🕓
│ │ │
always-hidden hidden Flux chevron
divider divider
ZoneBehaviour
ShownAlways visible. Anything to the right of the chevron — it never hides.
HiddenRevealed when you click the Flux chevron (the "drawer").
Always-HiddenRevealed only with ⌥ (option) — kept fully out of the way.

Nothing is hidden until you say so. On a fresh install Flux seeds its chevron and dividers to the left of every icon you already have, so all of them start in Shown and the bar looks exactly as it did before. You then drag icons leftward, past the chevron, to tuck them away.

You assign an icon to a zone by ⌘-dragging it to one side of a Flux divider — the native macOS gesture. To make the (normally invisible) zone boundaries visible while you do this, open Arrange Menu Bar — from Settings or the chevron's right-click menu. Flux reveals every icon and drops a labeled marker at each boundary, so you can see exactly where to drop each icon:

  • Left of the Hidden marker → Hidden
  • Left of the Always Hidden marker → Always-Hidden
  • Right of the Hidden marker → Shown

Click Done (or the ✓ that replaces the chevron) to apply. Flux remembers the arrangement across launches.

Features (MVP)

  • Click the chevron (or press the global hotkey, ⌃⌥⌘F by default and fully rebindable in Settings) to reveal. Clicking a revealed icon keeps it open so you can use it; clicking down in a window re-hides.
  • Arrange Mode — a guided editor that reveals labeled zone markers in the live menu bar so assigning icons to Shown / Hidden / Always-Hidden is clear and visible.
  • Optional Always-Hidden zone.
  • Notch panel — Alcove-inspired compact redesign (M7) — a seamless solid-black panel sized to the notch suite's shared footprint, with overshoot springs on open and a snappy, no-bounce close, plus a soft content morph as it expands. Hover (or click) the camera housing to expand a Now Playing widget: artwork, title/artist, a scrubber, and transport controls for whatever's playing (any app, via a vendored MediaRemote adapter). Open gesture, hover delays, and which widgets are enabled are all configurable in Settings → Notch.
  • Duo view (M7) — an opt-in toggle in Settings → Notch shows Now Playing and Calendar side by side when Now Playing is expanded (with a clear access prompt if Calendar permission is missing); expanding Calendar on its own still shows it alone.
  • Activity cycling & restore (M7) — while a live-activity wing is showing, swipe left/right to cycle through every other queued activity, swipe up to dismiss the one showing (restorable — the last 5 dismissed activities can be brought back), and swipe down to open the widget panel.
  • File Shelf — drag files straight onto the notch to hold them: hovering a drag over the (collapsed) camera housing expands the shelf automatically, and dropping copies the files in (they survive the source being moved, ejected, or deleted). From the shelf: click a tile to open it, drag it back out to Finder/Mail/Slack/etc., or use the tile's context menu for AirDrop, "Show in Finder", or "Copy". An optional auto-clear (never / 1 / 3 / 7 days) in Settings → Notch tidies the shelf on its own.
  • Calendar — your upcoming events (Today/Tomorrow), with a colored dot per calendar, time range, and location, right in the notch. Needs Calendar access; Settings → Notch shows the live grant/denied status and a button to request access or jump straight to System Settings if it's off. A wing appears automatically when an event is starting within 10 minutes — no repeating timer, just a single scheduled check for the next event's own threshold.
  • Live Activities — brief wings around the notch for battery, Bluetooth, and calendar events: a wing when you plug in, unplug, or cross below 20% battery unplugged (tinted to read as urgent, re-arming once you're back above 25% or plugged in), a wing when AirPods or another Bluetooth audio/HID accessory connects or disconnects, with a best-effort battery reading when the OS reports one, and a wing when a calendar event is about to start. Each is independently toggled in Settings → Notch.
  • Mirror — a live camera preview right in the notch, for a quick "how do I look" check. The camera only ever runs while the widget is actually open; needs Camera access, with the same live grant/denied status and re-request button as every other permission-gated feature.
  • Timers — start a 1/5/10/25 minute countdown from the shared Flux menu. A live wing shows the nearest remaining time with second precision while a timer runs, and a higher-priority wing (with a sound) announces completion. The Timer live display toggle in Settings → Notch controls both.
  • Clipboard — an in-memory-only history of what you copy, with click-to-copy-back, per-item removal, and Clear All. Off by default — history collection is opt-in, since clipboard contents routinely include passwords and other sensitive one-time text; nothing is ever written to disk, and password-manager-marked copies (the nspasteboard.org concealed/transient convention) are never captured at all. Cmd-C/Cmd-X are captured immediately, with pasteboard change polling as a fallback for menu copies, screenshots, files, and scripts.
  • Lock screen — optionally keeps the solid-black notch silhouette and native Liquid Glass surfaces visible on the macOS lock screen. When something is playing, the centered Now Playing card shows artwork/title/artist plus previous/play-next controls; the card is the only interactive overlay and the rest of the lock-screen UI remains mouse-transparent. The current live activity appears as a compact caption widget (battery, Bluetooth, calendar, timer, ...), with a short thunky system click on unlock. Each sub-feature has its own toggle, all nested under the master switch. Off by default: it uses macOS lock-screen notifications and a dynamically loaded system-level window-space bridge, so the integration is isolated and can be disabled cleanly if a future macOS release changes it — see Settings → Lock Screen.
  • Auto re-hide after an adjustable delay.
  • Launch at login (via SMAppService — the modern, sanctioned API).
  • Three menu-bar icon styles: Chevron / Dot / Line.
  • Light & dark, adapts to your system accent color.
  • Runs as a true agent: no Dock icon, no app switcher entry.

Privacy and permissions

Calendar and Camera are the only TCC permissions Flux currently requests. Both are opt-in and behind their own explicit Grant Access button in Settings → Notch; the permission-gated widget shows its own "access needed" state until you ask for it. Everything else in the app (menu-bar hiding, the notch panel, widget cycling, Now Playing, battery/Bluetooth/timer/calendar-event wings, and the lock-screen overlay) does not use Screen Recording. Permissions are requested only when a capability needs them, and denied features continue to show a useful fallback state.

  • Bluetooth device wings need no permission at all. Flux detects accessory connect/disconnect through the system's own device registry (the IOKit AppleDeviceManagementHIDEventService that already reports accessory battery, permission-free) plus CoreAudio's device list — it never requests Bluetooth access, so nothing prompts, and the wings are on by default like the rest of the notch suite.
  • Clipboard history is opt-in and in-memory only — nothing is captured until you turn it on, and nothing it captures is ever written to disk.

Every grant above is revocable at any time in System Settings, and every gated feature degrades gracefully (its own empty/permission state) rather than breaking the rest of the app when access isn't there.

Install

Grab the latest Flux.dmg from the Releases page, open it, and drag Flux into Applications. On first launch, right-click the app → Open (it's ad-hoc signed, not notarized). A chevron appears near your clock.

A note on permissions: Flux is ad-hoc signed rather than notarized with a paid Developer ID, which means macOS can — and sometimes does — treat an update as a new, untrusted binary and quietly drop a previously granted TCC permission (Calendar or Camera). If a permission-gated widget suddenly shows its "access needed" state after updating Flux, that's why — Settings → Notch shows the live grant/denied status for each permission and a button to re-request it or jump straight to the right System Settings pane.

Build & run

Requires Xcode 15+ (built and tested on Xcode 26 / Swift 6.3, macOS 26).

# Build the signed .app bundle → build/Flux.app
./Scripts/build_app.sh release
# Package a distributable disk image → build/Flux.dmg
./Scripts/build_dmg.sh
# Launch it
open build/Flux.app

Or for quick iteration:

swift build && swift run

The debug executable cannot register Launch at login; use the bundled app for that setting so macOS does not launch a bare process through Terminal.

Developer / CI helpers

The executable understands a few headless flags used for testing:

Flux --selftest # functional test of the collapse engine
Flux --snapshot out.png [light|dark] # render the real settings UI to a PNG
Flux --snapshot-notch out.png [dark] [collapsed|activity|expanded|lockscreen] # render the notch panel to a PNG

Architecture

Sources/Flux/
main.swift # agent entry point (.accessory activation)
App/AppDelegate.swift # wires settings ↔ engine ↔ login ↔ hotkey
MenuBar/
MenuBarManager.swift # reveal/collapse state machine, auto-rehide, menu, arrange
ControlItem.swift # one NSStatusItem as chevron or expandable divider
MenuBarArranger.swift # observable toggle for Arrange Mode (Settings ↔ engine)
MenuBarSection.swift # the three-zone model
MenuBarIconStyle.swift # chevron / dot / line
Settings/
SettingsStore.swift # UserDefaults-backed, observable
SettingsView.swift # tab host (General / Menu Bar / Notch / About)
SettingsRows.swift # shared row primitives
Tabs/ # one file per settings tab
SettingsWindowController.swift
Notch/
NotchWindowController.swift # owns the notch panel's lifecycle
NotchViewModel.swift # collapsed/activity/expanded state machine
NotchWidget.swift # widget protocol + registry
LiveActivity.swift # priority-queued "wings" content
LiveActivitySources.swift # NotchActivityRouter — single home for every activity producer
TimerActivity.swift # live timer-wing formatting and selection
Widgets/NowPlayingWidget.swift
Widgets/ShelfWidget.swift # tiles, drag in/out, AirDrop/Finder/Copy
Widgets/CalendarWidget.swift # agenda, permission states
Widgets/MirrorWidget.swift # live camera preview; owns CameraService start/stop itself
Widgets/ClipboardWidget.swift # history list, click-to-copy-back, Clear All
LockScreenPresenter.swift # EXPERIMENTAL: fade in/out, lock/unlock, unlock sound
LockScreenContentView.swift # EXPERIMENTAL: live media/activity widgets on the lock screen
Services/NowPlaying/ # MediaRemote adapter — the sole Now Playing source
Services/Shelf/ # ShelfStore (copy-in, manifest, QuickLook thumbs, expiry)
Services/CalendarService.swift # EventKit, refresh on EKEventStoreChanged (no polling)
Services/PowerMonitor.swift # IOKit battery/AC events (plug/unplug, low battery)
Services/DeviceMonitor.swift # permission-free BT connect/disconnect: IOKit matching notifications + CoreAudio device list + IORegistry battery
Services/CameraService.swift # AVCaptureSession behind Mirror, started/stopped by the widget itself
Services/ClipboardMonitor.swift # keyboard-assisted capture + changeCount fallback
Services/TimerService.swift # countdown timers, single boundary Task, completions publisher
Login/LoginItemManager.swift # SMAppService launch-at-login
Hotkey/HotkeyManager.swift # Carbon global hotkeys (menu-bar toggle + notch toggle)
Hotkey/HotkeyShortcut.swift # the chord model + ⌃⌥⌘F / ⌃⌥⌘N defaults
Hotkey/HotkeyRecorderView.swift # click-to-record shortcut field
Support/PermissionCenter.swift # unified TCC status/request for Calendar/Camera
Support/ # logging, app info, render/snapshot/selftest

Roadmap (post-MVP)

  • Per-app list control and a searchable drawer popover (needs Accessibility + ScreenCaptureKit — deliberately deferred to keep the MVP resource-light).
  • Custom hotkey recording, profiles, triggers (show on update/active).
  • Graduating the lock-screen silhouette out of "experimental," if it proves durable across macOS updates.

License

MIT © 2026 Ammar Badawy.

About

A calmer menu bar for macOS — a fast, stable, zero-permission Bartender alternative.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages