# NotchOverlayManager: Handling MacBook Notch-Aware Displays in FluidVoice

> Learn how NotchOverlayManager handles MacBook notch-aware displays in FluidVoice. Discover seamless UI orchestration and automatic display detection for better user experience.

- Repository: [ALTIC/FluidVoice](https://github.com/altic-dev/FluidVoice)
- Tags: internals
- Published: 2026-07-01

---

**NotchOverlayManager** is a singleton service in the FluidVoice macOS app that orchestrates overlay UI within the MacBook's physical notch, automatically detecting display capabilities and managing transitions between expanded and compact presentation modes via DynamicNotchKit.

The **NotchOverlayManager** sits at the heart of FluidVoice's user interface layer, bridging the gap between the audio processing pipeline and the visual feedback system. As implemented in [altic-dev/FluidVoice](https://github.com/altic-dev/FluidVoice), this singleton class abstracts the complexity of the MacBook's camera housing, turning it into a functional UI element that displays recording status, transcription previews, and command outputs without encroaching on the main workspace.

## What Is NotchOverlayManager?

### Core Architecture

The **NotchOverlayManager** follows a strict singleton pattern accessible via `NotchOverlayManager.shared`. It acts as a centralized coordinator that consumes audio level publishers, monitors the active application, and delegates rendering to **DynamicNotchKit**, a third-party framework that creates SwiftUI-backed overlays conforming to the physical notch geometry.

Located in [[`Sources/Fluid/Services/NotchOverlayManager.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Services/NotchOverlayManager.swift)](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Services/NotchOverlayManager.swift), the class maintains internal state machines for the current presentation mode, tracks generation counters to prevent race conditions during rapid show-hide cycles, and caches the last audio publisher to support seamless re-presentation after temporary dismissal.

### Screen Detection and Compact Support

Before presenting any UI, the manager interrogates the display hardware through `OverlayScreenResolver.screenForCurrentPointer()`. It specifically checks for **auxiliary safe areas** that indicate a true MacBook notch display:

```swift
let supportsCompact = screen.auxiliaryTopLeftArea != nil || screen.auxiliaryTopRightArea != nil

```

When `supportsCompact` evaluates to true, the manager can elect a **compact** presentation style that occupies only the notched portion of the menu bar. On standard external displays lacking these auxiliary areas, it automatically falls back to a full **expanded** presentation that respects the standard menu bar height.

## How NotchOverlayManager Handles MacBook Notch Displays

### DynamicNotchKit Integration

The manager instantiates a `DynamicNotch` object configured with SwiftUI view hierarchies defined in [[`Sources/Fluid/Views/NotchContentViews.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Views/NotchContentViews.swift)](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Views/NotchContentViews.swift). Depending on the computed policy, it injects one of several view configurations:

- `NotchExpandedView` – Full-height overlay for screens without notch support or when user preferences demand maximum visibility.
- `NotchCompactLeadingView` / `NotchCompactTrailingView` – Split views that align to the left and right of the physical camera housing.
- `NotchCompactBottomView` – An alternative compact layout for bottom-aligned presentations.

### Presentation Policies

The `NotchPresentationPolicy` structure (constructed via `NotchPresentationPolicy.forMode`) determines which visual elements appear inside the notch. This policy respects the user's choice in `SettingsStore.shared.notchPresentationMode`, which can be set to **standard** or **minimal**. In minimal mode, the manager suppresses the prompt selector and streaming preview, showing only the essential recording indicator and waveform.

### The Show/Hide Lifecycle

Entry points for visibility are strictly controlled through `show(audioLevelPublisher:mode:)`. This method:

1. Increments an internal generation counter to invalidate pending async blocks from previous calls.
2. Resolves the target screen and selects the appropriate layout strategy.
3. Constructs the `DynamicNotch` instance and binds the audio level publisher to the waveform visualization.
4. Invokes `notch.show()` with the configured animation duration.

Dismissal follows a similarly rigorous path through `hide()`, which cancels active app monitoring, terminates retry timers, and triggers the notch's dismissal animation before nullifying the internal reference.

### Command Output Expansion Mode

When the user triggers a command that generates textual output (such as a code explanation or translation), the manager transitions from the standard recording notch to a specialized command view:

```swift
NotchOverlayManager.shared.showExpandedCommandOutput()

```

This method hides the primary notch, instantiates a new `DynamicNotch` configured with `NotchCommandOutputExpandedView`, and presents it with a spring animation. The `toggleExpandedCommandOutput()` convenience method allows the UI to switch between collapsed and expanded states without reconstructing the entire overlay hierarchy.

### Bottom Overlay Fallback

If `SettingsStore.shared.overlayPosition` equals **.bottom**, the manager bypasses the notch entirely and delegates rendering to `BottomOverlayWindowController`. This path supports the same audio publisher and mode logic but positions the UI as a floating panel above the Dock rather than inside the menu bar, accommodating users who prefer traditional overlay placements or work with external displays lacking a physical notch.

## Key Implementation Details

### Audio Publisher Management

The manager stores a reference to the most recent `AnyPublisher<Float, Never>` via `lastAudioPublisher`. This caching mechanism enables the `show()` method to resume visualization immediately when the user invokes a mode change without requiring the audio engine to reinstantiate its publishers.

### Asynchronous State Safety

To prevent stale closures from corrupting the UI during rapid context switches, every show operation increments a `generation` integer. Completion handlers and asynchronous screen resolution blocks capture this generation value and abort execution if the stored `activeGeneration` has changed, eliminating race conditions between sequential `show()` and `hide()` calls.

## Code Examples

Configure and display a standard dictation overlay that respects the current screen's notch capabilities:

```swift
import Combine

let audioPublisher = audioEngine.levelPublisher.eraseToAnyPublisher()
NotchOverlayManager.shared.show(
    audioLevelPublisher: audioPublisher,
    mode: .dictation
)

```

Switch to compact presentation mode for supported displays:

```swift
SettingsStore.shared.notchPresentationMode = .minimal
NotchOverlayManager.shared.setMode(.dictation)

```

Display command output results in an expanded notch view:

```swift
NotchOverlayManager.shared.showExpandedCommandOutput()
// Later, dismiss the command view
NotchOverlayManager.shared.hideExpandedCommandOutput()

```

Handle user interaction when the notch is clicked:

```swift
NotchOverlayManager.shared.onNotchClicked = {
    if NotchOverlayManager.shared.isShowingCommandOutput {
        NotchOverlayManager.shared.hideExpandedCommandOutput()
    } else {
        NotchOverlayManager.shared.toggleExpandedCommandOutput()
    }
}

```

Update the transcription text in real-time while streaming preview is enabled:

```swift
NotchOverlayManager.shared.updateTranscriptionText("Processing your request...")

```

## Source File Reference

| File | Purpose |
|------|---------|
| [NotchOverlayManager.swift](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Services/NotchOverlayManager.swift) | Singleton coordinator managing DynamicNotchKit integration, lifecycle, and presentation policies. |
| [NotchContentViews.swift](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Views/NotchContentViews.swift) | SwiftUI view definitions for expanded, compact, and command-output notch states. |
| [SettingsStore.swift](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Persistence/SettingsStore.swift) | User defaults wrapper exposing `notchPresentationMode` and `overlayPosition` preferences. |
| [BottomOverlayWindowController.swift](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/UI/BottomOverlayWindowController.swift) | Alternative window controller for bottom-screen overlay when notch presentation is disabled. |
| [ActiveAppMonitor.swift](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Services/ActiveAppMonitor.swift) | Observes frontmost application changes to update the overlay's application icon display. |

## Summary

- **NotchOverlayManager** is a singleton service that abstracts MacBook notch complexity through **DynamicNotchKit**, providing a unified API for overlay presentation.
- The manager automatically detects notch-compatible displays by checking `auxiliaryTopLeftArea` and `auxiliaryTopRightArea`, falling back gracefully on external monitors.
- It supports both **standard** and **compact** presentation modes driven by `NotchPresentationPolicy` and user preferences stored in **SettingsStore**.
- The show/hide lifecycle uses generation counters to prevent race conditions during rapid UI transitions.
- For non-notch displays or user preference, the manager can redirect output to a **bottom overlay** via `BottomOverlayWindowController`.

## Frequently Asked Questions

### What is the purpose of the NotchOverlayManager in FluidVoice?

**NotchOverlayManager** centralizes all user interface elements that appear in or around the MacBook's camera notch. It handles audio visualization, transcription previews, command output display, and mode indicators, ensuring these elements render correctly regardless of screen type while preventing visual overlap with system menu bar items.

### How does NotchOverlayManager detect if a MacBook screen supports compact notch presentation?

The manager queries the `NSScreen` instance returned by `OverlayScreenResolver.screenForCurrentPointer()` for the presence of `auxiliaryTopLeftArea` or `auxiliaryTopRightArea`. If these properties are non-nil, the screen is identified as having a physical camera housing capable of supporting the compact split-view layout; otherwise, the manager defaults to the full expanded presentation style.

### Can NotchOverlayManager display UI at the bottom of the screen instead of the notch?

Yes. When `SettingsStore.shared.overlayPosition` is set to **.bottom**, the manager instantiates `BottomOverlayWindowController` instead of `DynamicNotch`, positioning a floating panel above the Dock. This behavior maintains feature parity—including audio visualization and command output—while accommodating user preference or hardware configurations where the notch is unavailable.

### How does the manager handle audio level visualization?

The manager accepts an `AnyPublisher<Float, Never>` via `show(audioLevelPublisher:mode:)` and binds it to the waveform views inside the notch content. It caches the publisher reference in `lastAudioPublisher` to support seamless re-presentation, allowing the audio engine to maintain continuous emission without recreating publishers between hide and show operations.