radial_menu_geometry_and_overflow_spec - mark-ik/graphshell GitHub Wiki
Date: 2026-03-01
Status: Canonical interaction contract
Priority: Pre-renderer/WGPU required
Related:
command_surface_interaction_spec.md-
../2026-03-01_ux_migration_design_spec.md(§5.6) ../subsystem_ux_semantics/ux_tree_and_probe_spec.md../subsystem_ux_semantics/ux_scenario_and_harness_spec.md
This spec defines Radial Palette Mode layout, hit testing, overflow behavior, and readability invariants.
It governs:
- tier-1 and tier-2 ring geometry,
- label placement and overlap prevention,
- overflow strategy and deterministic ordering,
- periphery-rail positioning and hover scaling behavior,
- keyboard/gamepad parity,
- diagnostics and test contracts.
It does not govern:
- action semantics,
- command ranking,
- omnibar or palette behavior outside radial activation.
- Right-click contextual summon draws a hub-circle outline at pointer origin.
- Default hub diameter target is approximately three mouse-cursor widths.
- Hub diameter is configurable per profile.
- Tier 1 represents categories only.
- Exactly 1–8 category buttons are visible per page.
- Buttons sit on a periphery rail and may be repositioned by user along that rail.
- Assignment/order is deterministic after user customization is applied.
- Activation origin is pointer (or focused node center for keyboard invocation).
- Tier 2 represents options for the currently selected Tier-1 category.
- Tier-2 entries occupy unique angular lanes; no z-stacked entries at same radius/lane.
- Tier-2 radius is configurable per profile and must be greater than hub radius by fixed tokenized spacing.
- Tier-1 category semantics are equivalent to Context Palette Tier-1 strip; Tier-2 option semantics are equivalent to Context Palette Tier-2 list.
- Every visible sector hit region must meet minimum logical size requirements.
- Hit region may exceed visual wedge footprint to preserve accessibility target size.
- Default button size is compact for dense packing.
- Hovered button expands up to half of the hub-circle radius, then returns to compact size on hover exit.
- Hover scaling must not violate lane non-overlap constraints.
Overflow resolution order:
- Context-eligible actions only,
- Tier-1 ring gets top-priority categories (max 8 per page),
- Tier-2 ring gets commands for selected category (max 8 per page),
- Remaining categories/options paginate by deterministic page index.
Determinism invariant:
- Given identical action set + context + profile, ring assignment order is stable.
- Labels are bounded text fields aligned radially away from the center and anchored to each button.
- Labels are hidden when the button is not hovered.
- Hover reveals the label; overflow text is revealed via gentle radial-direction scrolling in-field.
- On Tier-1 category selection, Tier-1 radial labels collapse and selected category label appears in hub.
- Tier-2 labels follow the same bounded radial text-field rule.
- Label bounding boxes must not overlap at final layout.
- On conflict, resolver applies: radial offset → in-field truncation/scroll policy → pagination.
- Focused/hovered/disabled sectors have distinct visual states.
- Disabled sectors remain readable but non-invokable.
- Keyboard and gamepad can invoke any visible sector action without pointer movement.
- Numeric/compass mapping remains stable across openings.
- Radial Palette Mode must be usable both with drag-gesture selection and with hover/click selection.
When open, Radial Palette Mode subtree must include:
- root
radial-palettenode, - Tier-1 category ring node + one
RadialSectorper visible category button, - Tier-2 option ring node + one
RadialSectorper visible option button, - action id metadata per sector,
- explicit
enabledstate, - per-button rail position metadata,
- per-button hover-scale state.
Required channels:
-
ux:radial_layout(Info; sector count, ring counts, page) -
ux:radial_overflow(Warn; overflow pages used) -
ux:radial_label_collision(Warn; pre/post collision counts) -
ux:radial_mode_fallback(Warn; radial → context palette fallback reason)
Required scenario coverage:
- 1–8 category contexts render all Tier-1 categories on one ring page.
- Tier-1 category selection drives Tier-2 option ring for selected category.
-
8 categories/options trigger deterministic paging.
- Tier-1/Tier-2 rings never produce lane/radius overlap under hover scaling.
- Label collision resolver reduces collisions at default ring radius; zero final overlaps via full three-stage pipeline (offset → truncation → pagination).
- Keyboard/gamepad invocation parity with pointer invocation.
- Drag-gesture and click/hover flows both complete command dispatch + dismiss.
- Click-away dismisses without mutation.
- Geometry constraints in §2 are implemented.
- Overflow policy in §3 is deterministic and tested.
- Readability constraints in §4 hold across supported DPI tiers (label collision resolver is best-effort; full three-stage convergence — offset → truncation → pagination — across all DPI tiers is not yet CI-gated).
- UxTree/diagnostics outputs in §5 are implemented.
- Scenario tests in §6 are part of CI UX contract gate (scenarios 1–6 covered as unit tests in
render/radial_menu.rs; scenarios 7–8 require egui rendering context and remain integration-test only). - Radial hub and per-tier diameters are profile-configurable (persisted via
HUB_RADIUS_KEY,TIER1_RING_RADIUS_KEY,TIER2_RING_RADIUS_KEY; runtime-tunable withAlt+Up/Downfamily; clamped to[MIN, MAX]bounds per tier).
Implementation notes:
- Deterministic tier paging, overflow telemetry, and fallback diagnostics are live in
render/radial_menu.rs. - UxTree now projects explicit Tier-1/Tier-2 ring container nodes and a radial overflow/readability summary node in
shell/desktop/workbench/ux_tree.rs. - Radial Tier-1 category ordering now reuses shared context+recency+pin policy from
render/action_registry.rs, matching Context Palette Mode behavior. - Runtime radial geometry tuning is available in radial mode (
Alt+Up/Downfor Tier-1 ring radius,Alt+Shift+Up/Downfor Tier-2,Alt+Ctrl+Up/Downfor hub); values persist via UI state keys. - §6 scenario unit tests (scenarios 1–6) added in
render/radial_menu.rstests module (#270): single-page Tier-1 fit, Tier-2 action list per category, overflow paging determinism, hover-scale non-overlap pre-check, label collision reduction invariant, angular nearest-entry parity. - Remaining open item: readability convergence CI gate across DPI tiers (§4 full three-stage pipeline verification).