1. A Raycast blog, and Raycast v2
This May, Raycast — the macOS launcher I've always liked — was about to ship a public beta. Before that I'd been seeing people share Alpha screenshots on Twitter, and it made me itch to try it. I wanted in, but it apparently needed a work email and ID. The bar was high, so I gave up.
When Raycast v2 dropped its Public Beta, something felt off. RAM usage had more than doubled versus before; even spare time usage was over 400MB, which is wild. Even Zed, the cross-platform editor built with GPUI, sits around 400MB with a modest project open. Raycast v1 was usually 100MB to 200MB. I had a bad feeling, and sure enough, I'd been ignoring a tiny button: Download for Windows.
Remember, Raycast v1 was written in Swift and AppKit. Trying to build a cross-platform tool with the stack Apple holds in a death grip is basically suicide.
In theory it's possible, though. Swift 5.3 shipped on September 16, 2020; on September 22 the Swift project officially announced Swift on Windows, with a native Windows toolchain. The Browser Company used Swift to build the Windows version of Arc. As for performance...
So I started guessing at Raycast v2's stack. Qt? GPUI? Don't tell me it's actually Swift on Windows?
Then I read this line in their blog, and my heart sank:
That leaves us to the hybrid approach. Building our own native shells that wrap system WebViews turned out to give us exactly what we needed. A proper Xcode project on macOS, a Visual Studio project on Windows. Full access to platform APIs. The system's own WebView for UI. And complete control over how each piece talks to the others. To verify if this would actually work, we built a prototype early on. Could we get translucent windows? Native tooltips over WebView content? Would it look and feel like Raycast? The prototype came out looking nearly identical to the native app. Transparent web views blending with the window background, native overlays for things like tooltips and action panels. Essentially the same visual language we'd spent years building.
Well then. High RAM usage is clearly not some "early-build optimization problem," and it's not getting solved. To ship on Microslop's Windows, Raycast had to get in the "wheelchair" too...
2. Back to the point
Two lines in the Raycast blog stuck with me:
No
cursor: pointeron interactive controls. Desktop apps don't do this. It's small, but it immediately signals "this is a website."
No hover highlights on most controls. On macOS, buttons and list items don't highlight on hover the way they do on the web.
Reading those, I started to get what engineer-and-designer thinking actually looks like. Then those two points blew up on X. Some people said: "Changing the hover cursor from a pointing hand to an arrow is what makes it native?" Others said treating a "fully renovated" web app as a native tool is just a scam.
I started digging, and the design thinking involved was way more tangled than I'd expected.
3. Apple's design stance
Apple's own software on macOS really does use hover very little, which can feel "stiff." Hover makes interaction feel alive — like the software is still breathing, not dead. So why does Apple think hover is useless?
After going through Apple's developer docs and Human Interface Guidelines, I was wrong.
Apple doesn't think hover is useless. It thinks hover should provide extra information, not be the main proof that "this is clickable."
4. State and intent
Native macOS apps rarely have that Web-style "mouse over → background tint / scale / glow" feedback everywhere. Apple's HIG (Human Interface Guidelines) describes hover as an effect that can add scale, tint, shadow, and so on — an optional enhancement, not a requirement that every interactive element respond to hover. SwiftUI also ships onHover, onContinuousHover, hoverEffect, and similar APIs, so Apple clearly supports it. They just didn't make it the default look of every control.
The most interesting part to me is how Apple separates "state" from "intent":
pressed: the user already acted → should get clear feedback.selected: the object is in some lasting state → should get clear feedback.focused: the next target of interaction changed → feedback is warranted. Apple's HIG also describes focus as helping confirm the interaction target.hovered: the mouse just happened to pass by → the user may have no intent to act at all.
So macOS often would rather keep the interface still.
Finder sidebar, System Settings, a ton of rows/buttons in Xcode: you move the mouse over them and often nothing happens. Click or select, then a clear state appears. It produces a very particular feeling:
The UI does not chase the mouse around.
Web UI grew up in the opposite tradition. Pages historically had to keep answering:
Can you even click this thing?
So :hover became a major affordance: links change color, cards lift, buttons swap backgrounds, the cursor changes.
Native macOS controls already have a very stable visual grammar — toolbar button, sidebar row, segmented control, checkbox, menu item, and so on. Apple would rather let the control's own shape express that it is operable, and skip a second layer of hover animation.
That also explains a fun SwiftUI API choice: a Button does not automatically get a Web-style .background(...) hover just because you created it on macOS. If you really want that, you can do it quite directly:
@State private var hovering = false
Button("Open") {
// ...
}
.padding(6)
.background(hovering ? .quaternary : .clear)
.onHover { hovering = $0 }Apple gives you onHover, even onContinuousHover for continuous position, but leaves the visual meaning to the developer.
Another place that really shows Apple's thinking: they poured a huge amount of hover design into the iPad pointer. They even designed pointer morph, lift, highlight, and similar effects; SwiftUI's HoverEffect has automatic, highlight, lift, and so on.
The reason is subtle. iPad started as touch UI; once a mouse showed up, the pointer had to help people see "where the touch targets are." Mac has been pointer-first since day one. A lot of controls don't need the extra explanation.
The Raycast team actually gets this.