Skip to content

perf(macos): unthrottled WebKit, parked launcher panel, paint-resize-syncro#451

Merged
Xoshbin merged 2 commits into
Xoshbin:mainfrom
AllDaGearNoIdea:perf/webkit-fluidity
Jul 7, 2026
Merged

perf(macos): unthrottled WebKit, parked launcher panel, paint-resize-syncro#451
Xoshbin merged 2 commits into
Xoshbin:mainfrom
AllDaGearNoIdea:perf/webkit-fluidity

Conversation

@AllDaGearNoIdea

Copy link
Copy Markdown
Contributor

This is a V2 of the fluidity stuff I did before, but learning from Raycast's technical deep-dive

I used this as an opportunity to try out Claude Fable, which created docs/explanation/launcher-rendering-lifecycle.md and picked up and corrected some edge cases.

Essentially, this aims to make the app feel as close as possible to a properly native macOS app, within the constraints of WebKit.

I've kept this dedicated and separate, so it accounts for the existing "what's new flow", but I believe this current implementation is wrong, and will put in a PR to correct that soon tldr the user shouldn't be essentially blocked from using the app after every update.

1. Keep WebKit unthrottled and at full cadence

WebKit throttles when a view isn't visible,

  • Occlusion detection off (respondsToSelector-gated SPI, WKWebView + NSWindow spellings, logged fallbacks).
  • requestIdleCallback enabled via WebKit's feature-flag SPI, with a JS polyfill (src/lib/idle.ts) so nothing depends on the flag landing. What's New check, perf report, and a new emoji-font prewarm now run at idle instead of competing with first paint.
  • The ~60fps rendering-update cap lifted (PreferPageRenderingUpdatesNear60FPSEnabled off) so rAF-driven UI tracks ProMotion displays at native cadence. Rendering stays demand-driven, so a static launcher draws no extra frames.
  • Flash-free HUD, onboarding, and settings reveals: order in hidden, reveal on WebKit's next presented frame (_doAfterNextPresentationUpdate), with a reveal-generation handshake for the HUD and watchdogs so nothing can wedge invisible.

2. Panel lifecycle improvements

"Hidden" now means ordered in at alpha 0, mouse-transparent, never key, so the WebContent process stays in the visible activity state while hidden. Post-hide state resets composite invisibly, and every summon is an alpha flip of an already-fresh surface. A boot prewarm makes the first summon as instant as every later one. Focus returns to the previous app via an order-out/re-order-in pair (the one sequence that works for a non-activating panel of an Accessory app).

3. Resizes upon paint confirmation

Grows into extension views commit the NSWindow resize on exactly the webview paint that carries the new view: JS requests the resize at $effect time, Rust arms a presentation hook, JS confirms from a rAF in the swap's rendering update,
and the hook commits resize + Show More bar in the same transaction as the new pixels. Generation-counted supersession and withdrawal make rapid open/Escape/open cycles stable (no 480→96→480 bounce), a parked-window shortcut keeps hidden transitions instant, and a watchdog guards the wedged-WebContent case. Window geometry only ever moves in sync with a request that still describes the current UI.

Note: Scoped to macOS, with existing behaviour as fallback for other platforms.

Testing

  • cargo test (2516), clippy --all-targets -D warnings, cargo doc -D warnings, vitest (launcher 2864, sdk 573) all green.
  • Contract tests cover the grow protocol end-to-end: effect-time send + one-frame confirm, open→escape→reopen gate routing, and withdrawal of a sent grow when a reversal is deferred.
  • New modules (idle.ts, emojiPrewarm.ts) have colocated tests.
  • Verified live: parked/reveal cycles, boot log confirms occlusion + both feature flags applied, flash-free settings/HUD reveals.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request implements a parked panel lifecycle and presentation-gated resizes on macOS to achieve a flicker-free rendering experience for the launcher and HUD, alongside idle-time scheduling and emoji font prewarming. The review feedback identifies two potential panic risks in macos.rs caused by calling .unwrap() on window.ns_window(), suggesting safer, graceful error-handling alternatives.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread asyar-launcher/src-tauri/src/platform/macos.rs
Comment thread asyar-launcher/src-tauri/src/platform/macos.rs
@Xoshbin

Xoshbin commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Hey @AllDaGearNoIdea welcome back, Thanks for this — really impressive piece of work. The write-up alone (plus the new launcher-rendering-lifecycle.md doc) makes the "why" behind every one of these changes clear, which made reviewing it a lot easier than it could've been given how deep this goes into WebKit/AppKit internals.

I tested the three changes locally against main and the difference is real: instant reopen even right after boot, no flash on grow into an extension view, and the rapid open→Escape→reopen bounce is genuinely gone. Nice touch pulling in the Raycast deep-dive for the presentation-update gating approach — the generation-counted supersession logic in particular is a clean way to handle the race.

Merging this now. One thing worth keeping on our radar going forward: this leans on several private, undocumented Apple APIs (_setWindowOcclusionDetectionEnabled:, _setEnabled:forFeature:, _doAfterNextPresentationUpdate:, etc.). They're gated defensively so we degrade gracefully if Apple renames or removes one, but we should treat every macOS/Safari update as a "re-verify this still works" checkpoint rather than assuming it forever holds — silent regressions here would be easy to miss since they just fall back to pre-PR behavior rather than erroring loudly. Also worth watching over the next few weeks: since the launcher's webview and its background timers now stay fully active even while "hidden," it'd be good to sanity-check idle battery/CPU impact against main isn't materially worse.

Appreciate you flagging the What's New flow issue separately rather than scope-creeping it into this PR — looking forward to that follow-up.

Thanks again for the careful, well-tested work. I honestly missed your contributions.

@Xoshbin Xoshbin merged commit c925a7d into Xoshbin:main Jul 7, 2026
1 check passed
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.

2 participants