Skip to content

Mode HUD: transient bezel and menu-bar sticky glyphs - #9

Open
RyBo wants to merge 5 commits into
mainfrom
feat/mode-hud
Open

Mode HUD: transient bezel and menu-bar sticky glyphs#9
RyBo wants to merge 5 commits into
mainfrom
feat/mode-hud

Conversation

@RyBo

@RyBo RyBo commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Toggling a mode (split orientation, float, zoom, workspace float, binding mode) gives no visual feedback today. You can zoom a window, forget about it, and be confused an hour later.

This adds two things:

Transient bezel. A dark translucent rounded bezel (native .hudWindow material, SF Symbol + label) fades in at the lower center of the focused window's display when a mode changes, holds, then fades out. Same treatment as the macOS volume bezel: click-through, never steals focus, fade only. Rapid toggles swap the text in place and reset the dismiss clock. Configurable via a new optional hud: section (enabled, fade_in, hold, fade_out, bottom_offset, font_size), hot-reloads like the rest of the config.

Menu-bar sticky glyphs. While a sticky state is active the status item shows it: 🌿 ⛶ zoomed, 🌿 ~ focused float, 🌿 ≈ desktop floated. Sticky state is recomputed at the retile funnel, so states cleared without a toggle (closing a zoomed window, a reconcile re-float, a Space switch) update the menu bar too.

Implementation follows the existing seams: a pure HudEvent/StickyState model in the Command layer, emission from the mutation methods (they know the resulting state), and an App-layer HudController modeled on FocusOverlayController. toggleSplitOrientation now returns the new orientation so a lone window emits nothing.

Tests: 177 passing (up from 173), covering the event-to-title/symbol mapping, suffix composition, hud config decode and validation, and the new geometry helper.

🤖 Generated with Claude Code

RyBo and others added 5 commits July 19, 2026 02:15
Pure groundwork for the mode HUD: a HudEvent enum with title/SF-symbol
strings and a StickyState suffix for the menu bar, plus a bottom-center
hudOrigin helper in Geometry. toggleSplitOrientation now returns the new
orientation (nil for a lone leaf) so a caller can report the real result.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New `hud` block controls the mode bezel (enabled, fade_in, hold,
fade_out, bottom_offset, font_size), decoded the same way as
focus_indicator. Adds negative-value checks to the validator and a
commented example block to config.example.yaml.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The mode toggles now report their resulting state through onHudEvent
(float, zoom, split, preselect, workspace float, focus mode, binding
mode enter), each fired after the mutation so a no-op emits nothing.
Sticky state is recomputed and pushed at the retile funnel and on every
focus-overlay notify, so states cleared without a toggle (a zoomed
window closed, a reconcile re-float) still update the menu bar.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
HudController draws a click-through .hudWindow bezel with an SF Symbol
and label at the lower center of the target display, fading in, holding,
then out. A generation counter keeps a stale fade-out from hiding a
bezel that was re-shown, rapid toggles swap content instantly, and a
display-change check hides it if its monitor goes away. AppDelegate
builds it, feeds it onHudEvent, and reloads its style alongside the
overlay.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 🌿 status item now appends ⛶/~/≈ when a window is zoomed, the
focused window floats, or the desktop is floated, so a state you can't
otherwise see stays visible. It seeds from the manager's current state
at launch (the controller is built after start) and updates on each
pushed change. Output is byte-identical when nothing is sticky.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant