Repository navigation
Hover intent: tooltips and hover cards wait, then stay warm, app-wide - #20528
Conversation
Tooltips show at once on every control a sweep passes, a neighbor never waits for a warm group, a labeled button repeats its label, and a pointer heading diagonally into the workspace card slides it to the row it crosses, then the card closes under the pointer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e (red) Title tooltips show on the first frame on every control a sweep passes, a labeled control repeats its text, the minimap's turn preview shows after 110 ms and cools at once, and a fast sweep lights each row with a half-faded fill. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One policy for the app and its pages (HoverIntentTiming in CmuxNextDesign, HOVER_INTENT in webviews/src/ui/hoverIntent.ts, a test keeps them equal): - Tooltips wait 800 ms before the first shows (AppKit's NSInitialToolTipDelay is about 1 s), then a neighbor's shows at once while the group is warm; warmth cools 500 ms after the last one hid. A click, key or scroll cools it. A control whose own label says the tooltip shows none (#20375's rule). - Sidebar hover cards keep the 1 s dwell and slide row to row while warm. A pointer heading into the card along the safe triangle no longer hands it to a row it crosses (300 ms aim), a pointer resting on the card keeps it, and leaving starts a 200 ms grace. - Web rows light on the frame the pointer reaches them, with no fade-in (desktop.css), so a fast sweep flashes no half-lit rows. - Moved onto the primitive: TooltipPresenter, the WorkspaceHoverCard dwell, HoverCardMachine's leave window, Base UI's TooltipProvider, title tooltips, toolbar hints, the minimap's turn preview, the markdown link card, and the submenu safe triangle geometry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Bead |
This comment has been minimized.
This comment has been minimized.
|
Unclear: CI failed on
Not re-run automatically: Written by |
|
cmux-next tour of The tour job failed before the tour ran (build or setup); the run log has the output. The tour produced no media. Tours are data in |
…d glass (red) Leo 2026-10-14: the first tooltip waits about 400-500 ms, fades in over the fade-in token rising 2 pt, a warm neighbor's is there at once, and it fades out quicker; Reduce Motion keeps the fade with no rise. The tooltip is frosted glass whose tint keeps the text 4.5:1 over pure black and pure white, opaque under Reduce Transparency, one surface for pages and the app. Review fixes covered here: a titled control inside a view with a tooltip shows neither; moving down the sidebar with drift toward the card slides the card at once; a key typed while a toolbar hint waits drops it; the hover-card grace check now advances the clock. TooltipSurface (the token) and a TooltipPanel shim of the names the tests read land here so the test target compiles; behavior is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The first tooltip of a group now waits 450 ms (was 800; Leo asked for 400-500): a sweep across a toolbar still sits 30-100 ms on each button, far under it, while a deliberate rest answers in under half a second. It fades in over the fade-in token (120 ms) rising 2 pt; a warm neighbor's is there at once with no fade; it fades out over the fade-out token (80 ms). Reduce Motion keeps the fade and drops the rise. Pages: the popup-open and popup-close times, and the warm group's hint marks itself data-instant. One tooltip surface, native and pages (TooltipSurface): frosted glass (NSVisualEffectView behind the window; backdrop-filter blur 24px) under the popup surface at the least alpha that keeps the primary text 4.5:1 over pure black and pure white (--cmux-tooltip-tint for pages), a one-device-pixel separator rim, and an elevation-1 shadow (0 1px 2px black at 7%). Reduce Transparency draws the opaque popup surface. Review fixes: the safe triangle counts a move as aiming only when it heads for the card more than it runs along it, so tab and sidebar cards slide at once again; a titled control inside a view with a tooltip shows neither; a show that finds its view gone leaves the intent cold; a cooled group drops its other intents' waits; the instant row-hover rule matches only class names ending in -row, -item or -option. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#20481 landed --cmux-hairline (one device pixel); the tooltip rim uses it instead of a local 2x media query. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
The drift slide now starts by the list's right edge, where the old safe triangle is widest, and the labeled control inside a tooltip view waits past AppKit's delay too; on the red commit both passed vacuously. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of the fades: a click, key, scroll or app switch faded the tooltip over 80 ms, so it lingered over the menu a click opened; AppKit's goes at once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of the fades: - A click, key, scroll or app switch hides the tooltip at once (native hideNow, pages' dismiss), as AppKit's; only leaving it fades it out. - New text on a tooltip that is fading in no longer cuts the fade short. - The toolbar hint's card stays mounted once loaded and closes through open=false, so Base UI fades it out (and in again next time). - The rim width comes from the screen the tooltip shows on, not the one it last showed on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
debug.pointer_hover delivered tracking-area events but left the pointer itself where the real mouse was, so a shown tooltip's recheck (which read NSEvent.mouseLocation) put it away after half a second on a headless capture host. The tooltip recheck now reads PointerHover.pointer(in:) (the real pointer, or DEBUG's synthesized one), and pointer_hover sets that synthesized pointer, as debug.mouse does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
- regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38545858866
Fleet hosts with no display drop layer animations, as the dialog fade tests note; the fade tests skip there and require an on-screen window. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… op-next-theme/hover-intent
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
red: web / Web status; do not merge until green; see lane-rules |
|
Agents: |
WebKit's tracking area has an owner that is not a responder, so debug.mouse move never reached the agent pane's page on a capture slot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Gallery312 states changed: agent-pane.artifact-panel/markdown, agent-pane.artifact-panel/html, agent-pane.trust-ask/trusted, agent-pane.transcript/long-code, agent-pane.artifact-panel/closed, ... · 1 new state · 51 broken states · 108 play checks failed Diff page and renders (the run's 306 more on the diff page. Live preview (follows this branch; start it with
Play checks failed (0 px anchor movement, 0 layout shift, no frame over 33 ms unless the entry gives a reason):
606 nondeterministic states differed from a second render of the same head (a clock or fixture leak) and are not counted as changes. |
# Conflicts: # webviews/src/pages/shared/desktop.css
…er (base red) AgentTabStore takes build: since its tag parameter was replaced; the test still passed tag:, so CmuxNextAppTests did not compile on feat-cmux-next. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- regenerated Packages/macOS/CmuxNext/ci-target-graph.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38587906262
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
On a capture slot the sidebar toggle's tooltip was 'Default': the sidebar's bottom Default item reports a visible rect past its bounds, so its tracking area spans the sidebar, and the deepest tracker the pointer entered won. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… op-next-theme/hover-intent
AppKit reported the sidebar's bottom Default item's visible rect past its bounds, so its tracking area covered the whole sidebar and, being the deepest, its tooltip won over the toggle's, New Workspace's and every row's, and showed by the window's bottom edge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
debug.agent_pane {action: hover, x, y} sends a mouse moved event straight to the
agent page's web view, which takes it in a window that is not key; a posted
move reached no view there.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
WebKit takes no mouse moves in a window that is not key, and a capture slot's never is, so the hover goes to the page as pointer and mouse events at the point. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Found 1 test failure on Blacksmith runners: Failure
|
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
…opped CmuxNextAgentLanes) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
Base #20528 (hover intent) replaces this PR's tooltip delay and warm window (TOOLTIP_DELAY/TOOLTIP_WARM): take base's titleTooltips/Tooltip. Base #20454 moved the composer's pickers; drop their tooltips that repeat the face again, and mark the ones that add a path or a time with tooltip-allow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>






Summary
Tooltips and hover cards used to show at once on every control or row the pointer passed, so a sweep across a toolbar or down a list left a trail of them. They now follow one hover-intent policy, the same in the app and in its pages, modeled on AppKit. The tooltip itself is now frosted glass.
Tooltips
fadeIntoken (120 ms) and rises 2 pt.fadeOuttoken (80 ms).TooltipSurface):NSVisualEffectViewbehind the window natively, andbackdrop-filter: blur(24px)in pages.--cmux-hairlinefrom Composer and New Tab rims draw one device pixel, concentric at every scale #20481).--elevation-1in pages andPopupStyle.elevation1natively (0 1px 2px, black at 7%, 12% in dark). Base had given the title tooltip--elevation-2; a tooltip is the smallest surface, so it takes step 1.Sidebar workspace cards
Row highlights in pages appear on the frame the pointer reaches the row, with no fade-in, so a fast sweep no longer leaves half-faded tints. The fade on leaving stays, and native sidebar rows keep their cross-fade from #20315.
Why these numbers
AppKit's tooltip waits
NSInitialToolTipDelay, about 1 s at the default setting, and after that the next view's tooltip shows at once. Leo asked for 400–500 ms, and 450 ms sits comfortably on both sides of the trade:The other values:
motion.tooltip.delayHOVER_INTENT.tooltipDelaymotion.tooltip.warmHOVER_INTENT.tooltipWarmmotion.hoverCard.dwell(existing)HOVER_INTENT.cardDwellmotion.hoverCard.graceHOVER_INTENT.cardGracemotion.hoverCard.aimHOVER_INTENT.cardAimMotionFade.fadeIn/.fadeOut--ui-popup-open/--ui-popup-closeTooltipSurface.blurRadius--tooltip-blurTooltipSurface.minimumTintAlpha--tooltip-tintfallbackTooltipSurface.shadow=PopupStyle.elevation1--tooltip-shadow: var(--elevation-1)Every value is a tunable or a design token, not a user setting.
HoverIntentTiming.standard) and in the web constantHOVER_INTENT.webviews/test/hover-intent-parity.test.tsfails when the two drift.webviews/test/tooltip-surface.test.tsdoes the same for the surface constants.--cmux-tooltip-tint(WebTheme).The primitive
Native,
CmuxNextDesign/HoverIntent/HoverIntent.swift:HoverIntentTimingreads the timing through the tunables.HoverIntent<Target>is a pure reducer that owns the delay and the warm group. Its owner runs the effects on oneDemandTimer, and the clock is injectable.CGRect.isAimedAt(from:to:)is the safe triangle plus the heading test.TooltipPresenterruns onHoverIntent.HoverCardMachineandHoverCardCoordinatoruse the timing and the aim test.TooltipPaneldrawsTooltipSurfaceand runs the fades throughMotion.set, socheck-motionstays green.Web,
webviews/src/ui/hoverIntent.ts:HoverIntent, plusHoverGroupfor the warm group. Pages share one tooltip group, and cooling the group also drops other intents' pending waits.useHoverIntenthook.aimingAt, the safe triangle.HoverClock.pages/shared/desktop.css(--tooltip-*,data-starting-style,data-ending-style, anddata-instantfor a warm neighbor).Timers moved onto it
TooltipPresenter(every nativethemedToolTip/.themedHelp)HoverIntent: 450 ms, then warmWorkspaceHoverCardController.delaymotion.hoverCard.dwellread inlineHoverIntentTiming.current.cardDwellHoverCardMachine.leaveWindowcardGrace(200 ms), plusaimWindowand a hold while the pointer is on the cardui/TooltipTooltipProvider(Base UI)delay={0}delay=450,timeout=500(Base UI's warm window)ui/titleTooltips.ts(everytitlein pages)HoverIntenton the shared tooltip groupui/Toolbar.tsxhintuseHoverIntenton the shared group; keyboard focus shows it at oncePOPOVER_DELAY_MSuseHoverIntent(450 ms, then follows ticks at once)setTimeoutHoverIntentfor the pointer; the caret's card keeps 250 msacpmux/useHoverIntent.ts)aimingAtfromui/hoverIntent.ts; its 150 ms submenu delay is unchangedLeft as they are:
TabPreviewPolicydelay. They already run throughHoverCardMachine, so they get the grace and the aim test (with the heading check, so sliding along the strip still hands the card over at once).NSMenuItem.toolTipstays AppKit's own.<Tooltip>) keep Base UI's own warm window, which has the same 450/500 ms timing, separate from the title-tooltip group.A tooltip far from the pointer no longer wins
While recording I found that the toolbar's first tooltip took about 1 s on base, and a warm neighbor's tooltip appeared and then vanished. The cause was the sidebar's bottom "Default" row: AppKit reported its
visibleRectas{{-8,-692},{208,720}}, past its 34 × 24 bounds, so its.inVisibleRecttracking area covered the whole sidebar. As the deepest tracker it beat the toggle and New Workspace, and its tooltip was placed off the window until the 500 ms recheck picked the real one.TooltipPresenternow only lets trackers whose view is under the pointer compete (and falls back to all of them if none is). Base has the same bug, which the before clips show.Overlap with #20375
#20375 (open) also edits
webviews/src/ui/titleTooltips.tsandTooltip.tsx(TOOLTIP_DELAY 1000,TOOLTIP_WARM 400) and addstest/tooltip-rules.ts. Whichever lands second resolves the conflict. This PR's timing is Leo's 450 ms, fromHOVER_INTENT.Testing
Red and green ran the same commands. Each red commit comes before its fix in the branch.
Native (fleet:
cmux-ci run --class light --script scripts/ci/run-swift-testing-suites.sh --arg Packages/macOS/CmuxNext)Red, first round, at
76ccbaeee84d(aws-m4pro-9):TooltipHoverIntentTestshad 6 issues. A sweep showed["Back", "Forward", "Reload", "Share", "Downloads"], and the first tooltip showed with no delay.SidebarHoverCardDwellTestsfailed: the diagonal path into the card slid it tows-2, and the card closed while the pointer rested on it.Red, second round, at
bdd850384de2(aws-m4pro-9):TooltipHoverIntentTestsfailed because the tooltip waited 800 ms instead of 450 ms.TooltipSurfaceTestsfailed: no--cmux-tooltip-tint, and no tooltip after 500 ms.ThemedTooltipTestsfailed: the fill was opaque instead of the frosted tint.Red for the strengthened review tests, at
13410b2baca7(a not-for-merge branch: the red commit plus the two tests), on aws-m4pro-2:movingDownTheListWithDriftSlidesTheCardAtOncefailed: the card stayed on row 0.aLabeledControlInsideATooltipViewShowsNeitherfailed: it showed the container's "Page actions".Red for the Default-row bug, at
6a3c382d94b0(the red test on its own) on aws-m4pro-3:aDeeperTooltipAwayFromThePointerDoesNotWinfailed with(presenter.shown?.text → "Default") == "Back".Green:
081bbafon aws-m4pro-7, a display host, so no motion skips: every suite passed, includingTooltipSurface,TooltipHoverIntent,ThemedTooltip,SubtleElevation,SidebarHoverCardDwellandSpareNewTabChatOpensTabs.33444f2de1feon aws-m4pro-2: 306 of 306 suites passed, includingaDeeperTooltipAwayFromThePointerDoesNotWin.BranchStateResourcesTestsandPinnedPageTests(waiting on a pinned tab). Both passed in every other round, and this PR doesn't touch them.AcpmuxBundleReplacedTestsskipped for want of a published cmux-tui tree). That's infra.SpareNewTabChatOpensTabsTests, which passedtag:toAgentTabStore(build:).Web (
heavy --mem 4G bun test; browser tests useCMUX_BROWSER_TESTS=1 heavy --mem 6G, Chromium)Red at
ae4b3073af6e:src/ui/titleTooltips.test.tsfailed 3 cases.test/hover-intent-cards.test.tsxfailed 1 (the minimap preview showed after 110 ms).test/hover-row-sweep.test.tsfailed 2: a sweep sampled 27 half-faded fills.Red at
bdd850384de2:titleTooltips.test.tsfailed 2: the 450 ms delay, and a key not dropping a waiting toolbar hint.test/tooltip-surface.test.tsfailed 4:rgb(52, 49, 68)fill instead of the tint, with no blur;Red at
aaa5d137f8ea:tooltip-surface.test.tsshowed a click leaving the tooltip fading ({hidden: false, ending: true}).Green:
web / react-apps-checkat33444f2de1feran 270 test files. Every file this PR adds or changes passes:titleTooltips,hover-intent-parity,hover-intent-cards,hover-row-sweep,tooltip-surface,popup-surface,subtle-elevation,chat-header-tooltipsandui-a11y. The one red istheme-colors.test.ts, onagent-session/acpmux/composerStates.css:28, a line that came from New Tab composer: quiet focus rim and theme-surface fill #20561 on base and isn't in this branch.subtle-elevation.test.tsandtooltip-surface.test.ts(6/6, Chromium).Final head
6248e28573c0: the tipa5f878e69fc7merged in, withci-target-graph.jsonrestored to the tip's (the merge had droppedCmuxNextAgentLanes).cmux-ciisolated,check-release-compile.sh).subtle-elevation,popup-surface,hover-intent-parityandtitleTooltipspassed 50/50.react-apps-checkthere stopped at lint, on sevencontrol-has-associated-labelwarnings in base'shome-channels/ChiefSheet.tsxandConversationSheets.tsx.Guards:
crash_ratchet.py,check-concurrency.sh,check-system-blueandcheck-motionall pass.Clips
Each clip is before (left, feat-cmux-next) and after (right, this PR), both recorded the same way on a capture mini at about 60 fps with the art wallpaper on. Native hovers are driven with
debug.pointer_hover. Pages are hovered with a new debug-onlydebug.agent_pane {action:"hover"}, which fires the page's pointer events, because an inactive capture-slot app gets no real mouse moves. Base was built from feat-cmux-next plus only the three debug commits. Times are from frame onsets.Fast sweep: sidebar rows, then title-bar and pane-toolbar buttons at sweep speed. Before, the pane toolbar leaves a trail of tooltips (Changes, Terminal, Browser); after, nothing shows.
sweep.mp4 (full quality)
Slow dwell, native: rest on the sidebar toggle, slide to New Workspace, leave, rest again. After: the first tooltip shows 0.50 s after the rest, New Workspace shows at once (warm), and after cooling the next rest waits again (3.27 to 3.75 s). Before: the first takes about 0.85 s, and New Workspace's tooltip shows then vanishes at the recheck (the Default-row bug above).
dwell-native.mp4 (full quality)
Slow dwell, page toolbar: over the art wallpaper. Before: instant (0.33 to 0.35 s). After: 0.31 to 0.83 s, then neighbors at once.
dwell-page.mp4 (full quality)
Sidebar cards: rest on a workspace row (1 s card), then slide down. The card follows row to row once open, in both.
cards.mp4 (full quality)
Jump to latest, busy wallpaper: after a fling up a real chat. Before: instant. After: 0.50 s, on the frosted glass surface, then fades out over 80 ms.
jump-wallpaper.mp4 (full quality)
Jump to latest, light theme (Rose Pine Dawn): the same over a light page; the tint keeps the label readable.
jump-light.mp4 (full quality)
Page toolbar, light theme: the page dwell again under Rose Pine Dawn.
dwell-page-light.mp4 (full quality)
Changelog
Changed: Tooltips and hover cards wait briefly before showing, then show instantly for neighbors, like macOS.
🤖 Generated with Claude Code