Skip to content

Rework nav selection pill animation for lower GPU cost - #5209

Merged
Gabriel Dufresne (GabrielDuf) merged 2 commits into
mainfrom
fix/nav-pill-animation-perf
Jul 29, 2026
Merged

Rework nav selection pill animation for lower GPU cost#5209
Gabriel Dufresne (GabrielDuf) merged 2 commits into
mainfrom
fix/nav-pill-animation-perf

Conversation

@GabrielDuf

Copy link
Copy Markdown
Contributor

The sliding selection pill added in #5194 was expensive on the GPU and could balloon or fail to follow the page. This reworks how the pill moves — same WinUI-style effect, far cheaper, and correct during startup.

Problem

The pill animation drove Canvas.Top and Height, both layout-affecting properties. Every animation frame forced a full measure/arrange pass plus re-rasterization, and on a Mica window that re-presents the entire translucent surface each frame. Measured ~13% GPU while a single pill slide was on screen — disproportionate for a 3×16 px bar, and rough on low-end machines.

Two secondary issues surfaced while fixing it:

  • The edge-stretch was proportional to travel distance and unbounded, so the long Discover→Settings jump (which crosses the empty gap to the footer group) ballooned the pill to ~5× its height — it read as a rubber band, not the subtle WinUI elastic.
  • A startup race: if the pill's position update fired before the target nav item had a layout, it was silently dropped and never retried — so switching pages while the app was still opening left the pill behind.

Changes

  • Transform-driven motion. The pill now animates via RenderTransform (TranslateTransform.Y + ScaleTransform.ScaleY) instead of layout properties. The compositor moves a cached layer with no per-frame layout pass, and there's no per-move Animation/KeyFrame allocation (less GC).
  • Shorter duration (400 ms → 180 ms). On Mica the cost is presents × window-area; shortening at a steady 60 fps cuts presents ~55% while staying smooth. Net effect: GPU spike drops from ~13% to the ~5–6% range, for ~0.18 s per navigation.
  • Capped, distance-aware stretch. The pill's center slides while ScaleY bumps via 1 + stretch·sin, with stretch clamped so the peak is 2× regardless of distance (short hops stretch proportionally less). Keeps the Fluent elastic feel without the balloon.
  • Startup layout-race fix. When the target item isn't laid out yet, defer via its LayoutUpdated and retry (it fires every layout pass, so it self-heals across the several passes at startup). Any newer selection — or hiding the pill — clears the pending retry so the latest selection always wins.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Reworks the sidebar selection pill animation to reduce GPU and layout costs while improving startup reliability.

Changes:

  • Uses render transforms for movement and capped stretching.
  • Shortens animation duration to 180 ms.
  • Retries positioning when startup layout is incomplete.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/UniGetUI.Avalonia/Views/SidebarView.axaml.cs
@GabrielDuf
Gabriel Dufresne (GabrielDuf) merged commit 7969683 into main Jul 29, 2026
5 checks passed
@GabrielDuf
Gabriel Dufresne (GabrielDuf) deleted the fix/nav-pill-animation-perf branch July 29, 2026 14:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants