Deep Dive

UI Engineering in the Age of AI

Cross-platform Web UI was a good answer before AI. Writing code is cheaper now; verifying it is not. GPU UI and generating native apps for each platform both have an opening. We tested 10 frameworks.

OriginalNo reproduction in any form without permission

Three windows stand for Web, self-drawn GPU UI and native. Their lines converge on a red verification mark.

On 2025-12-12, Zed engineer mikayla-maki closed a PR proposing custom shaders for GPUI. The reply was polite. It thanked the contributor, then said: “we’re shifting focus to core product work at Zed, and without a Zed use case, I can’t validate this code”. It ended with a smiley.

GPUI is Zed’s own GPU UI framework. It often comes up in discussions of Electron alternatives. Less than four months earlier, Zed had announced a $32,000,000 round led by Sequoia, bringing its total funding past $42,000,000.

More than nine months later, on 2026-9-26, developer egoist created a repository called MyGo. After 39 days, it had 1,042 commits, 890 of them with Claude credited.

Claude comes from Anthropic. Anthropic’s own desktop app uses Electron.

Taken together, those three facts seem a little odd. We tested 10 frameworks on two machines to see where the field stands.

01Why We Tested

Electron is still used by desktop apps such as Claude and Codex: the Web has a mature ecosystem, one codebase can serve multiple platforms, and models know it well. AI reduces development costs, but cross-platform compatibility and maintenance still take work.

GPU-rendered UI offers another route, but GPUI still prioritizes Zed; cross-platform rendering and a widget ecosystem require sustained investment. MyGo shows how AI and ready-made components can accelerate a first version. Production maturity and long-term maintainability remain unproven.

Flutter, Compose, Slint, egui and iced make different tradeoffs. We tested 10 frameworks with the same scenarios, measuring smoothness, CPU, memory and visual fidelity to see what each approach actually costs.

02We Ran Local Tests

We tested 10 frameworks with the same scenarios on an Apple M4 Max and a ThinkPad T14 Gen6. Both platforms have CPU and memory measurements; Windows also has external frame measurements from PresentMon. Mac frame callbacks differ between frameworks and are not used for cross-framework comparison. Hardware and memory metrics differ too, so we compare frameworks only within each platform.

This is a dense animation workload: 500 cards, each 96×64 logical pixels, overlap in 25 columns. Each has a corner radius of 12, a 135° gradient and a shadow with blur 16 and vertical offset 4. All cards update their positions on frame callbacks, moving in circles of radius 12 with a four-second period. We run five 30-second rounds and report the median.

The main question is how much CPU the framework needs to update the UI, prepare drawing and submit rendering while many elements with visual effects move continuously, and whether it delivers frames consistently. CPU covers the application process tree; it is neither GPU utilization nor a breakdown of individual stages. Read it alongside frame intervals: producing fewer frames can also lower CPU use. The scene contains 500 cards, but occlusion and window clipping mean that not all 500 are drawn in full every frame.

500 overlapping blue-purple rounded cards with gradients and shadows
Figure 1Animation stress-test scene: 500 cards with gradients and shadows. Electron / macOS, captured from the test app with motion frozen at its starting position.

Windows

Table 1Windows measurements, medians of 5 runs. Frames are p95 display intervals (ms); 8.3 means a full 120Hz. CPU uses 100% for one logical core. Memory is private commit (MiB).
FrameworkList frameMotion frameStream CPUEdit CPUMotion CPUMotion RAM
WPF (native)8.668473%13%49%2,425
Electron8.810831%92%138%947
TauriInvalid9254%105%148%913
GPUI8.616.724%4%22%142
MyGo8.48.611%6%33%115
egui8.88.512%20%49%388
iced8.98.520%3%25%215
Slint8.58.527%99%67%61
Flutter8.48022%105%91%4,934
Compose8.816034%106%102%2,422

All frameworks kept up with list scrolling. Motion exposed the gap: with 500 cards carrying shadows and gradients, the Rust and Go frameworks that draw their own UI mostly held 120Hz. Flutter, Electron, Tauri and Compose reached frame intervals of 80 to 160ms. WPF’s 684ms came from 500 separate shadow effects. Turning them off brought it back to 8.3ms, so this is not a general WPF problem.

Text editing is another hurdle. With 10 characters inserted per second into a 5,000-line document, Flutter, Compose and Slint all saturated one core. Flutter also lost thirty percent of the input on Windows.

Mac

Table 2Mac measurements, medians of 5 runs. CPU uses one logical core as 100%; memory is phys_footprint (MiB). The machine was not idle. No frame rates comparable across frameworks are reported.
FrameworkStream CPUEdit CPUMotion CPUList memoryMotion RAM
SwiftUI87.5%8.9%99.1%4037
Electron16.1%62.0%102.2%536698
Tauri42.1%86.9%78.7%753555
GPUI22.5%2.9%17.0%341335
MyGo8.2%2.8%16.3%368371
egui8.6%7.2%20.4%803839
iced18.2%7.5%15.0%489491
Slint18.4%52.1%26.7%423416
Flutter18.3%101.9%237.4%468994
Compose31.3%105.1%107.5%7101,295

On Mac, animation CPU was about 15%–20% for GPUI, MyGo, egui and iced, versus 237% for Flutter and around 100% for Electron and Compose. During text editing, Flutter and Compose still approached one full core. Slint used 52%, below its 99% on Windows.

In the list scenario, SwiftUI’s roughly 40 MiB, GPUI’s 340 MiB and egui’s 800 MiB primarily describe application-process footprints. Native UI can use system rendering services outside the app: Apple documents AppKit’s preference for out-of-process layer-tree rendering, so some rendering and compositing work occurs elsewhere. Custom renderers also use system compositing, but app-process figures alone cannot compare how these paths divide the work. M-series unified memory means CPU and GPU share physical memory, not that all associated costs are charged to the app’s phys_footprint.

In five short GPU traces each for SwiftUI’s list and animation scenes, no GPU execution events were observed for the app PID, while WindowServer was active. This neither means SwiftUI uses no GPU nor attributes the whole desktop’s activity to it. WindowServer’s memory baseline fluctuated by about 205 MiB; the absence of large shared objects in snapshots also cannot rule out reuse of existing system resources. These results establish a lower application-process footprint for SwiftUI, not a lower total rendering cost or proof that the system pays the entire difference.

These numbers describe only these two machines, these versions and our test applications. Methods and full data are in section 05.

03It Was Never About Picking Just One

Editors, developer tools and business apps have different requirements for text input, animation, memory, cross-platform delivery and widget ecosystems. Each has its own use cases. Choosing a framework means deciding which tradeoffs are acceptable.

Many frameworks are also using retention, caching and partial updates to avoid repeating layout and drawing work. GPUI combines immediate and retained modes. The UI model, the work it can reuse and the time it takes to draw a frame are separate questions.

MyGo, iced, GPUI, Slint and egui all keep up with animation demands, with low CPU usage. Slint uses the least memory, egui’s memory use is relatively high, and GPUI requires you to supply your own editing controls. MyGo is currently used mainly by the author’s own apps and has not undergone extensive validation at production scale.

Flutter, Electron, and Compose also had poor frame intervals and resource usage in this animation stress test. Tauri’s package is just 11 MB, but its runtime memory use is similar to Electron’s.

04Verification Is the Bottleneck

We now think verification matters more than rendering.

Writing code has become cheaper. Confirming that it is correct still takes time. In the Stack Overflow 2025 developer survey, 66% had encountered AI solutions that were “almost right, but not quite”, and 45.2% said debugging AI code took more time. In a survey Sonar released in 01/2026, 96% of developers did not fully trust the functional correctness of AI-generated code, and only 48% said they always checked before committing. Sonar sells code inspection tools, so those figures deserve some caution, but they align with the earlier survey.

The Slint and egui releases attracted little attention. We think they matter more than the rendering advances. Agents need to inject input and take screenshots to make a change, look at it, then change it again. Checking an interface once meant someone sitting at a machine and clicking through it. Machines are now starting to take on that work.

There are three approaches for now. Cross-platform Web UI has the most resources at hand. Drawing UI directly on the GPU needs no browser alongside it, and the barrier to building it is lower than before. Native apps for each platform are the oldest approach. Once, only large companies could afford several teams. The difficulty now is the threefold increase in bugs and support scope that Breunig describes. If verification gets cheaper and quality improves, generating a native app directly for each platform could also work.

We are also exploring our own GPU UI approach. The difference is that we bring in much of the Web developer experience: JSX-like components, CSS-like styling, flexbox layout, reactive state and browser-style DevTools, all compiled to native code. It is still early.

We do not know which answer will win. Several may coexist for a long time. The three facts at the start still hold today. The PR remains closed, MyGo keeps growing, and Claude’s desktop app still uses Electron. It is a very interesting time.

05Test Report

Testing ran from November 4 to 6, 2026. Each framework implemented the same scenes using recommended practices, default settings and release builds. We reran Compose’s design page and the idle scene that shares its implementation after correcting the blur.

Table 3Test environments. Hardware, windows and memory metrics differ between the two machines. Comparisons are therefore within each platform, not between absolute values across platforms.
ItemMacWindows
MachineApple M4 Max, 16 cores, 64 GBThinkPad T14 Gen6, Core Ultra 7 255H, Arc 140T integrated GPU, 32 GB
OSmacOS 26.4Windows 11 Pro 10.0.26300
DisplayStudio Display,60Hz,2x2880×1800,120Hz,200%
Window1440×900 logical pixels1280×720 logical pixels; borderless 1440×900 design page
Memory metricphys_footprintprivate commit (committed private memory, not physical usage)
Frame metricApplication callbacks; meanings vary by framework, not used for comparisonPresentMon 2.6.0 display intervals, externally measured
Machine stateNot idle; other development tasks running during testsNo other user activity
Table 4Frameworks and versions tested. Rendering paths come from runtime logs or actual framework API returns. “Unverified” means no runtime evidence was obtained in this test.
FrameworkVersionMac render pathWindows render path
SwiftUI / WPFmacOS 26.4 SDK / .NET Framework 4.8.1System compositingWPF default D3D9 pipeline
Electron45.2.2UnverifiedChromium,ANGLE D3D11
Tauri2.12.5WKWebViewWebView2 156,ANGLE D3D11
GPUIZed c4273271Metal, defaultsUnverified
MyGo86ec3b30UnverifiedUnverified
eguieframe 0.37.0MetalVulkan
iced0.14.0MetalVulkan
Slint1.18.1FemtoVG,OpenGLFemtoVG,OpenGL ES
Flutter3.47.9Impeller,MetalImpeller,ANGLE D3D11
Compose1.12.2Skiko,MetalSkiko,D3D12
Table 5Test scenarios. In-app timers drive each scenario with no manual interaction. Test data uses a fixed seed.
ScenarioWorkload
IdleShow the design page, then leave it still to measure idle cost
List10,000-row virtualized list, row height 64, scrolling at a constant 2,000 px/s
StreamingLoad 200 past messages, then append 40 words per second to the last one, staying at the bottom
Editing5,000-line document, inserting 10 characters per second at the cursor
Motion500 cards, 96×64, corner radius 12, gradients and shadows, moving in circles using the same formula
Design page11 design specifications: fonts, shadows, hairlines, gradients, P3, background blur, corners, emoji, OpenType, mixed Chinese and English

Each scenario ran 5 times per framework, 30 seconds per run, sequentially in shuffled order. All values below are medians. Across the 5 runs, the median range was about 3%; ninety percent were within 24%. List and motion tests were rerun after specifications were aligned, so the columns were not collected during the same period. CPU uses 100% for one logical core. Multiprocess apps include all child processes. For Tauri on Mac, we also counted the WebKit processes the system launched for it. Windows frame data uses only runs uniquely attributable to one swapchain with zero dropped records.

We checked actual delivered output for both streaming and editing. Flutter editing on Windows completed only 68%; all others exceeded 99%.

Table 6Windows CPU, in %.
FrameworkIdleListStreamingEditingMotion
WPF2.637.272.713.549.3
Electron6.142.830.692.1137.8
Tauri31.658.253.7104.9147.8
GPUI1.510.624.33.621.5
MyGo0.017.910.66.332.8
egui0.315.912.219.648.9
iced0.321.320.23.024.5
Slint0.362.726.999.166.8
Flutter0.631.221.8104.690.6
Compose0.535.934.4106.4101.8
Table 7Windows memory, private commit, in MiB.
FrameworkIdleListStreamingEditingMotion
WPF1571932502062,425
Electron280397392556947
Tauri260313346536913
GPUI135142160138142
MyGo132135133132115
egui379386396460388
iced212224274321215
Slint79877220261
Flutter6363963746674,934
Compose4215445743,3722,422
Table 8Windows display intervals, in ms. At 120Hz, 8.33 is the full frame rate. Runs counts the runs with valid frame data.
FrameworkList p95List p99RunsMotion p95Motion p99Runs
WPF8.68.75684.3719.35
Electron8.88.94108.3115.92
Tauri——091.7100.05
GPUI8.68.8516.725.15
MyGo8.48.758.616.75
egui8.88.958.58.75
iced8.98.958.58.65
Slint8.58.858.58.75
Flutter8.48.6580.588.65
Compose8.88.95160.3211.85
Table 9Mac CPU, in %. Machine not idle.
FrameworkIdleListStreamingEditingMotion
SwiftUI1.016.987.58.999.1
Electron2.516.716.162.0102.2
Tauri6.332.042.186.978.7
GPUI0.49.722.52.917.0
MyGo0.113.28.22.816.3
egui0.19.08.67.220.4
iced0.124.218.27.515.0
Slint0.113.118.452.126.7
Flutter0.211.018.3101.9237.4
Compose0.423.331.3105.1107.5
Table 10Mac memory, phys_footprint, in MiB.
FrameworkIdleListStreamingEditingMotion
SwiftUI324013629337
Electron205536567707698
Tauri101753601570555
GPUI74341358320335
MyGo75368361356371
egui414803817862839
iced75489541598491
Slint151423386434416
Flutter156468455663994
Compose3507107091,4261,295
Table 11Startup measures process launch to the first frame callback (ms), not the first screen with a cold cache. Size is the distribution directory (MB), excluding system WebView and .NET.
FrameworkMac startupWindows startupMac sizeWindows size
Native (SwiftUI / WPF)2284493.0<0.1
Electron295818267.0376.4
Tauri56562212.511.2
GPUI25527711.913.4
MyGo74212613.111.5
egui30927717.417.4
iced25759014.414.2
Slint26127218.517.0
Flutter2441,04343.930.0
Compose5501,074123.1113.8

Design fidelity

The blur check calls for softened stripes in a specific panel inside the window. Applying Modifier.blur at 24 dp to the stripe layer in Compose 1.12.2 produced smooth transitions in native window captures on Mac and Windows. SwiftUI likewise blurs the known stripe layer before adding a translucent white overlay. Both checks cover that specific content layer. Compose Desktop API

Comparison of stripe panels across ten frameworks. Compose, SwiftUI, Electron, Tauri, MyGo and Flutter show smooth transitions. The other four show sharp stripe boundaries.
Figure 2Native 2× Mac window captures, cropped to the same stripe panel and scaled down proportionally.

The GPUI, iced, egui and Slint test implementations applied a translucent overlay to the stripes. The stripe boundaries were still sharp in the retest. GPUI’s Blurred and iced’s window::Settings::blur affect content behind the window. We found no built-in drawing API for local backdrop blur in the tested versions. iced can render local effects with custom drawing, and egui can call into a renderer via PaintCallback. GPUI · iced window settings · egui paint callback

The Slint test used version 1.18.1 with FemtoVG. That version lacked the element-level backdrop-blur property. Upstream later added the property for its Skia renderer. The captures show the FemtoVG path in 1.18.1. Slint upstream issue

The design page has 11 checks. GPUI, egui, iced, Slint and Compose did not reproduce the P3 swatch in the tested Mac output. Windows captures lack a color profile, so P3 is not judged; flag emoji appear as letters in all tested Windows implementations.

Table 12Technology choices for key modules, taken from source code and official documentation for the pinned framework versions.
FrameworkLayoutTextAccessibility
GPUITaffyCoreText on macOSAccessKit
eguiImmediate-mode layoutepaint + harfrustAccessKit
icedOwn flex layoutcosmic-textNo system bridge found
SlintCompile-time lowering + runtime layoutParleyAccessKit
FlutterRenderBox constraintsSkParagraphSemantics tree bridge
ComposeMeasurePolicySkParagraph via SkikoSemantics; Java Access Bridge on Windows
ElectronBlinkChromium text pipelineChromium accessibility tree
TauriSystem WebViewSystem WebViewExposed via WebView
SwiftUIStack / LayoutTextKit,Core TextBuilt into the system

Layout approaches are converging. Text remains the biggest divide. When iced requested PingFang 700 on macOS, Latin letters fell back to Menlo Bold.

Limitations:

  • Only one machine per platform. Motion results came from an Intel integrated GPU and may not apply to discrete GPUs.
  • The Mac was not idle during testing. Frame data came only from application callbacks and is not compared across frameworks.
  • Shadow blur semantics vary. egui, iced and GPUI use approximations. Editing controls are not equivalent either; GPUI uses a modified example editor.
  • CPU and memory tables cover the app and included helper processes. WindowServer and driver costs are not allocated per window, and benefits from reusing shared system resources are not quantified; these tables cannot rank total system rendering costs.
  • We did not obtain valid results for input-method candidate windows, the Mac accessibility tree or power consumption.
U

ui.surf Editors

ui.surf Editors · 1 article