Skip to content

add circular menu style and hud zoom - #18

Merged
vgreg merged 2 commits into
mainfrom
wheel-menu-style-and-hud-zoom
Aug 18, 2026
Merged

add circular menu style and hud zoom#18
vgreg merged 2 commits into
mainfrom
wheel-menu-style-and-hud-zoom

Conversation

@vgreg

@vgreg vgreg commented Aug 18, 2026

Copy link
Copy Markdown
Owner

Custom menus can now be drawn as a circular "wheel" instead of the vertical list, and every HUD scales with a single config key.

Config

{
  "menu_style": "list",
  "hud_zoom": 1.0,

  "menus": {
    "git": [ ... ],

    "window": {
      "style": "wheel",
      "items": [ ... ]
    }
  }
}
  • menu_style"list" (default) or "wheel"; "donut" and "radial" are accepted aliases.
  • hud_zoom — multiplier for every HUD, default 1.0, clamped to 0.75–3.0.
  • Menus accept both the original bare-array form (inherits the global style) and a new object form with a per-menu style. Both can be mixed freely.

Unknown style strings warn and fall back to the list rather than throwing, so a typo cannot blank the whole config on hot-reload.

Wheel interaction

Two ways to drive it, both live at once:

  • Either thumbstick aims — the ring stays still and the highlight follows the item under the stick. Returning to centre keeps the last selection.
  • Dpad left/right rotates — the ring turns and the highlight stays on the fixed marker at 12 o'clock.

Selection (A/RT) and cancellation (B/X/LT) are unchanged from the list. Menus over 16 items fall back to the list with a warning.

Notable implementation points

Analog input inside an overlay did not previously exist. pollControllers dropped all axis input whenever an overlay was visible. That branch now forwards the dominant thumbstick to the menu before returning, with its own larger deadzone (0.4 vs the 0.1 tuned for pointer drift) so the highlight does not jitter near centre. Mouse and scroll emission stays suppressed exactly as before.

HUDZoom uses a Layout, not scaleEffect alone. scaleEffect is render-only and leaves the reported layout size untouched — and the panels size themselves from NSHostingView.fittingSize, so they would stay unscaled and clip their contents. Reporting zoom × the ideal size is synchronous and correct on the first layout pass. At zoom == 1 the content is returned untouched, so the default appearance is unchanged.

Also fixes two pre-existing sizing bugs the zoom work surfaced: CustomMenuController.show sized its panel without a layout pass, and HelpController.show never re-fitted at all.

Verification

Automated: config decoding (both menu forms, aliases, bad-value fallback, zoom clamping), 15 assertions on the wheel's aim and rotation math, offscreen renders of both styles, Xcode build, mkdocs build --strict, and a launch smoke test.

Rendering the wheel offscreen caught the hub hints crowding the chips at 3 and 9 o'clock, which is why the ring radius and hub inset are wider than first drafted.

Anything needing a physical controller or a live NSPanel — stick aiming, dpad rotation, on-screen panel sizing at zoom — is listed as a checklist in TO_VERIFY.md.

🤖 Generated with Claude Code

vgreg and others added 2 commits August 18, 2026 11:37
Custom menus can now be drawn as a circular "wheel" instead of the vertical
list, and every HUD scales with a single config key.

menu_style sets the default presentation ("list" or "wheel", with "donut" and
"radial" as aliases); an individual menu overrides it by switching from the
bare-array form to { "style": ..., "items": [...] }. The array form stays valid
and inherits the global default. Unknown style strings warn and fall back to
the list rather than throwing, so a typo cannot blank the config on hot-reload.

The wheel offers two ways to drive it at once: either thumbstick aims, leaving
the ring still while the highlight follows the stick, and dpad left/right
rotates the ring against a fixed marker at 12 o'clock. Selection and
cancellation keep the same buttons as the list.

Aiming needs analog input inside an overlay, which did not previously exist:
pollControllers dropped all axis input whenever an overlay was visible. That
branch now forwards the dominant thumbstick to the menu before returning, with
its own larger deadzone (0.4) so the highlight does not jitter near centre.
Mouse and scroll emission stays suppressed exactly as before.

hud_zoom scales all five overlays. HUDZoom leans on a small Layout rather than
scaleEffect alone: scaleEffect is render-only and leaves the reported size
untouched, so the panels — which size themselves from NSHostingView.fittingSize
— would stay unscaled and clip their contents. Reporting zoom x the ideal size
is synchronous and correct on the first layout pass. At zoom 1 the content is
returned untouched, so the default appearance is unchanged.

Also fixes two pre-existing sizing bugs surfaced by the zoom work:
CustomMenuController.show sized its panel without a layout pass, and
HelpController.show never re-fitted at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The example config had picked up hud_zoom but not menu_style or the object-form
menu, so it no longer matched the sample config.json it mirrors. Add both, plus
notes explaining that the bare-array and object menu forms can be mixed.

The menu action reference described how to open a menu but never pointed at the
page defining one; link it. Add a feature bullet for HUD scaling, which was
otherwise only discoverable in the config reference.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vgreg
vgreg merged commit a3edd35 into main Aug 18, 2026
@vgreg
vgreg deleted the wheel-menu-style-and-hud-zoom branch August 18, 2026 19:25
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