RCN Initiative #46 · Cross-Platform GUI Desktop Apps · Research Brief

The Rust desktop GUI ecosystem, measured

Seven frameworks researched against primary sources, plus freya, vizia and floem added 2026-08-03 with a narrower upstream check. Ten comparable specifications built across the cohort — eight in each of the ten frameworks (80 apps), plus iteration 5's two specs in all ten and in Dioxus Native as an eleventh entry (102 apps) — and the dependency trees compared by experiment round. Revised 2026-08-30 after maintainer feedback on r/rust: every upstream-facing claim was re-verified against the pinned crate sources and current upstream; corrections are marked inline with the date, listed in report/data/corrections-2026-08-30.md, and the resulting issue list is report/data/upstream-issues.md. Two questions. Where exactly is the fragmentation? And how do you actually ship a cross-platform desktop app in Rust today?

core research 2026-07-07 · experiments reconciled through 2026-07-10 · freya/vizia/floem expansion round measured 2026-08-03 on the same machine · apple m4 pro · rustc 1.96.1 · windows round measured 2026-08-08 · ryzen ai 9 hx 370 / radeon 890m · windows 11 home 26200.7171 · methodology & full reports: gui-ecosystem-research repo

The thesis

converging bottom-up

The ecosystem is consolidating from the bottom of the stack upward. In the last 12 months the principal reusable pure-Rust text stacks converged on HarfRust, Zed dropped its custom Linux GPU layer for wgpu, and Slint/Bevy/floem migrated to parley/fontique. AccessKit is now the shared native accessibility layer. iced and floem remain unintegrated (floem's pinned rev has no accesskit anywhere in its dependency tree), while gpui support is unreleased and currently disabled in Zed. The top is still fragmented: text layout, 2D renderers, widgets, and windowing forks.

1
shared pure-Rust shaping engine. HarfRust now shapes for cosmic-text, parley and egui; gpui macOS/Windows use OS engines (its tested 0.2.2 Linux path shaped via cosmic-text/rustybuzz); webviews use browser engines; rustybuzz remains maintained elsewhere.
4
text-layout stacks still maintained (cosmic-text, parley, epaint galley, gpui). The flagship duplication.
6+
framework-side renderer families targeting a mix of wgpu, platform GPU APIs, OpenGL/Skia, and software. The least-shared layer.
1/28
among the 28 crates in all ten dependency trees, raw-window-handle is the only shared cross-platform window-handle crate. Some of those 28 are platform-specific GUI crates. Recomputed 2026-08-03 over all ten *-app lockfiles; 16 of the 28 carry version skew.

Duplication matrix

capability × framework · july 2026 · freya/vizia/floem added 2026-08-03
shared crate in-house webview missing dioxus is shown as its default webview desktop; stable dioxus-native 0.7.9 uses classic AnyRender/Vello, while development main defaults toward Vello Hybrid; current blitz-shell has no Muda dependency
Capabilityicedeguigpuitaurixilemslintdioxusfreyaviziafloem
Windowing winit winit in-houseper-platform taowinit fork winit winit+qt, linuxkms taowinit migration proposed winitvia freya-winit winit+glutin GL context floem-winitwinit fork, git-only
GPU / render backend wgpu wgpu Metal/D3Dtested 0.2.2: blade on linux; zed main: wgpu '26, unreleased webview wgpu backend-dependentGL/software in tree; wgpu/Skia opt-in webview Skia/Metalvia freya-skia fork Skia/GLglutin context wgpusoftbuffer fallback
2D renderer iced_wgpu epaint in-house webview vello femtovg+ own software; Skia/Qt opt-in webviewblitz 0.7.9: classic Vello freya-skia 0.98rust-skia fork skia-safere-exported as vizia::vg floem-vgervger-rs fork; tiny-skia sw
Text shaping harfrustvia cosmic-text harfrustin epaint 0.34+ platformCoreText/DWrite; linux (0.2.2): cosmic-text/rustybuzz webview harfrustvia parley harfrustvia parley webview HarfBuzzC++, inside Skia HarfBuzzC++, inside Skia harfrustvia parley
Text layout cosmic-text galleyshapes RTL runs; no paragraph BiDi in-house webview parley parley webviewblitz: parley Skia textlayoutICU BiDi SkParagraphSkia textlayout parleycosmic-text on stale 0.2.0
Font fallback fontdbdormant since '24 bundled platformlinux (0.2.2): fontdb webview fontique fontique webview platformSkFontMgr/CoreText platformSkFontMgr/CoreText fontiqueHan/kana unresolved on macOS
Widget layout in-house in-house taffy CSS in-house DSL+ taffy (exp.) CSSblitz: taffy+stylo torinown engine morphorm+ real CSS engine taffymin-content trap
Widgets in-house in-house low-level elementsno reusable 1st-party suite; gpui-component is 3rd-party HTML/JS in-house~15 views in-house HTML/JS in-houseInput is single-line in-houseincl. VirtualTable in-house+ understory_* git crates
Accessibility missingdraft PR #3111 AccessKitschema required; eframe adapter default unreleasedmerged 2026-05 webview AccessKit AccessKitdefault on Winit desktop webview AccessKitinline per-element attrs AccessKitdefault feature missingno accesskit in tree
IME winitsince 0.14 winit platformwindows rough; 2026-08-08 run: 7/8 apps alive+window, IME itself unexercised webview winit winit webview winiton_ime_preedit event winit winit fork
Styling / theming in-house in-house tailwind-like CSS in-house DSL CSS in-house CSS enginevizia_style; transitions in-housereactive style fns

Converging vs diverging

last 12 months

▲ Convergence wins

  • wgpu is the leading reusable native GPU layer in this sample. The stored 2026-07-07 tables record roughly 1.27k reverse dependencies but differ by one, and the raw response was not retained. Zed replaced Blade with wgpu on Linux (Feb '26), and eframe flipped its default from glow.
  • HarfRust unified reusable pure-Rust shaping in <12 months, adopted by cosmic-text 0.15, parley 0.6, and epaint 0.34. Platform/browser shapers remain.
  • AccessKit is the shared a11y layer, integrated by egui (schema required; eframe adapter default), Slint (default on Winit desktop), xilem, Bevy, vizia (default feature), freya (inline per-element attributes), Blitz, GTK 4.18, and gpui main. Iced and floem remain the holdouts; gpui is unreleased and Zed currently opts out.
  • taffy crossed framework lines, into gpui, Blitz, floem, bevy_ui, Servo (CSS Grid) and Slint (experimental). 8.9M downloads.
  • parley/fontique are absorbing the text layer. Slint 1.14, floem, and Bevy 0.19 all defected from cosmic-text/fontdb within a year.
  • Hot-patching is crossing framework lines. Dioxus's subsecond drives Bevy 0.17's shipped hotpatching feature (via dioxus-devtools), an in-progress iced integration (iced#3000), and Axum servers; since 0.7.0 the dx CLI works on any Rust project (the iced author's cargo-hot is a self-described broken exploration). Verified upstream 2026-08-08; not exercised in this corpus. Sources in report/data/hotpatch-convergence.md.

▼ Persistent divergence

  • 4 text-layout stacks. cosmic-text (System76) and parley (Linebender) are both actively funded; egui's parley attempt stalled on an API-model mismatch.
  • The tao/winit fork is still wide. tao is frozen on winit's pre-0.30 API while winit redesigns for 0.31; un-forking was long blocked on wry's WebKitGTK needs, though a gtk4 winit backend (winit-gtk4) merged 2026-07-16.
  • 6+ renderer families in the sample. They target wgpu, platform GPU APIs, OpenGL/Skia, and software; classic Vello remains alpha, and Linebender calls Vello Hybrid roughly beta.
  • The current tauri-apps Linux shell paths split on the GTK fault line. muda menubars need GTK windows, tray-icon needs a parallel GTK loop on winit, and global-hotkey itself is X11-only.
  • winit itself was mid-redesign at the snapshot. The 0.31 beta had been open for roughly seven months and 21 days, and one prolific contributor announced a hiatus citing burnout. This is a high-dependency layer, not the sample's most-depended-on crate.

The four fragmentations, explained

plain language · full primer in report/30-primer.md

A GUI framework is a tower of layers: window (winit opens the window and feeds you input) → GPU (wgpu turns one API into Metal/Vulkan/DX12) → 2D renderer (turns "rounded rect with shadow" into GPU work or pixels) → text (find fonts → shape glyphs → lay out lines) → layout (taffy computes flexbox math) → a11y (AccessKit feeds screen readers) → widgets. Several lower-layer pieces are increasingly shared. These four stories are where sharing still breaks down.

1 · Four text-layout stacks the flagship duplication

Text is a pipeline: discover fonts → shape glyphs → lay out lines. The bottom stage just consolidated. HarfRust (the HarfBuzz org's official Rust port) now shapes for cosmic-text, parley and egui. The layout stage is the genuinely expensive part: line breaking, wrapping, bidirectional text, rich text, caret and editing semantics. It still exists four times:

StackOwnerUsed byKnown holes
cosmic-textSystem76 (for COSMIC)iced, COSMIC, gpui-on-Linuxfallback via dormant fontdb
parleyLinebenderxilem, Slint, Blitz, Bevy, floemegui adoption stalled on API mismatch
epaint "galley"egui, in-houseegui onlyno paragraph-level BiDi reordering; no color emoji
line_layoutZed, in-housegpui onlyquality differs per OS (platform shapers)

The three frameworks added on 2026-08-03 do not add a fifth Rust stack: freya and vizia both delegate layout to Skia's C++ textlayout/SkParagraph over CoreText, and floem's main swapped cosmic-text for parley wholesale, after which its macOS fallback failed to resolve Han/kana at the pinned rev.

Why it persists. Both leading stacks have sustained institutional contributors: System76 employees on cosmic-text, and a mix of grants and employer-backed contributors around Linebender. Both stay active. egui tried adopting parley (egui#5784) and hit a real architecture mismatch: parley wants to own "a rectangle to fill with text"; immediate-mode egui re-derives layout every frame. Iced adopted cosmic-text in 2023; the retained primary sources establish the adoption, not why it was chosen over Parley.

Why you care. Four stacks means four independent sets of text bugs. egui shapes individual Arabic/Hebrew runs but cannot reorder multiword or mixed-direction paragraphs correctly (egui#1016); Slint's run reordering and tested selection work, while explicit base direction, UI mirroring, and codepoint-oriented backspace remain gaps. Momentum favors parley (3 frameworks migrated in 12 months) but cosmic-text won't vanish while COSMIC ships on it.

2 · Six-plus framework-side renderer families the least-shared layer

Reusable native stacks increasingly share wgpu, but renderer implementations still target a mix of wgpu, platform GPU APIs, OpenGL/Skia, and CPU software. In this sample the framework-side layer includes vello (Linebender, GPU compute), epaint (egui, CPU tessellation), iced_wgpu, femtovg (Slint default), Skia bindings (Slint premium, vizia via upstream skia-safe, freya via its own freya-skia fork), vger (floem, via a fork of vger-rs), and gpui's shader pipeline ("render like a videogame", one shader per primitive).

Why it persists. Genuinely different philosophies (compute-shader vector rendering vs tessellation vs SDF shaders), plus Slint's need to run on GPU-less microcontrollers. Vello is one prospective shared renderer, alongside reusable Skia, FemtoVG, and tiny-skia paths; classic Vello is alpha, and Linebender calls only the Hybrid path roughly beta.

Why you care. The six-plus renderer families duplicate some anti-aliasing, clipping, glyph-atlas, and GPU-driver work, but this audit did not quantify a multiplier. This layer consolidates last, if ever. The realistic near-term win is sharing the bricks (egui already adopted vello_cpu for glyph rasterization) rather than whole renderers.

3 · The widening tao/winit fork two windowing layers, drifting

In 2021 Tauri forked winit into tao because it needed native menus/tray and, decisively, GTK-hosted windows on Linux, since WebKitGTK (Wry/Tauri's supported Linux system-webview backend) can only render inside GTK containers. Menus and tray have since been extracted into winit-compatible crates (muda, tray-icon), removing part of the fork's original rationale. The GTK constraint remains (tao#509: "running webkitgtk outside of gtk is not fun or not even possible").

The drift. tao is frozen on winit's pre-0.30 closure API while winit's 0.31 redesign moved away from it (historically tracked in the now-closed winit#3367). Divergence can require parallel maintenance, but this audit did not establish that every platform fix is duplicated. Dioxus 0.7.9 still ships Tao/Wry; a winit migration is proposed in open dioxus#2706. Tauri v3 planning targets GTK4, not an un-fork. The structural fix, a windowing-agnostic wry (wry#1014) or winit GTK embedding, began landing just after the snapshot. Tauri's winit-gtk4 backend merged 2026-07-16 on winit's still-beta 0.31 architecture, and this audit found no dedicated public funding source for it.

4 · The GTK fault line in Linux shell integration GTK/X11 coupling in common tauri-apps paths

Specific Linux paths in the common tauri-apps shell crates hit a GTK/X11 boundary: muda's Linux menubar API requires a gtk::Window, so it cannot attach that menubar to a plain winit window; tray-icon's winit path requires a second GTK event loop on a parallel thread; and global-hotkey's Linux backend is X11-only. Wayland portal support already exists in Rust through ashpd, while ksni implements StatusNotifierItem. winit itself has no menu/tray API (winit#403, open since 2018).

Why you care. On Linux a native-GPU Rust app often has no tray, no menubar on a plain winit window, and no Wayland hotkey. The work left is to wire the existing portal, SNI, and DBusMenu crates into a maintained winit-compatible facade. Every winit-based framework would get that for free.

5 · Bonus: AccessKit's concentrated authorship and public-support record the a11y linchpin

What it is. Screen readers don't see pixels. They need a semantic tree ("a button named Add, focused"), and every OS has a different ancient API for it. AccessKit defines one Rust tree format with adapters for Windows UI Automation, macOS NSAccessibility, Linux AT-SPI, Android and iOS. No comparable cross-toolkit Rust abstraction was found in this audit; egui, Slint, xilem, Bevy, vizia, Blitz, GPUI (since May '26), and GTK 4.18 all integrate it, although Zed currently opts out of GPUI's path.

One active maintainer. The July snapshot said authorship was "dominated by Matt Campbell and Arnold Loubriat"; a re-check of the repository on 2026-08-29 (after a maintainer's correction on Reddit) sharpens that. Since mid-March 2026 Arnold Loubriat (DataTriny) has authored 42 of 58 commits, merged all 54 pull requests and cut every release; Matt Campbell's last commit was 2026-03-04 and his last merge 2026-03-15, though he still reviews (approved #756 on 2026-08-09) and remains a crates.io owner. Loubriat is the only public member of the AccessKit org, and by his own bio does this work in his spare time. Funding. The Sovereign Tech Fund's 2023–24 GNOME programme paid Campbell for Newton and the GTK↔AccessKit integration (GNOME STF report, "mostly wrapped up"). Since then there has been one institutional grant, which the July audit missed: an NLnet NGI0 Commons Fund grant, "iOS support for AccessKit", started 2025-11 (project page) — scoped and delivered as accesskit_ios 0.1.0 on 2026-05-11, not maintenance funding. The repository has no FUNDING.yml; accesskit.dev's "Sponsor the project" link points at Campbell's GitHub Sponsors (six sponsors, one of them a company), while Loubriat's lists two individual sponsors and no corporate one.

Why you care. The ecosystem standardized on a crate with 5.9M recent downloads that one person maintains essentially alone, on their own time, with no project-level funding channel. The remaining gaps (a web/canvas adapter, deeper text-editing semantics, and the prototype-stage Wayland a11y stack "Newton") are long-running infrastructure work; funding them — and the maintainer — is recommendation 4 below.

The load-bearing crates

who actually carries the ecosystem · verified 2026-07-07

The shared infrastructure under the sampled frameworks, ranked by how concentrated and how funded they look from public evidence. The table contains 21 entries; 15 are rated amber/red. "Author concentration" is a heuristic derived from dated public commit attribution, not a measured probability of collapse, and "none found" means no public direct funding source was identified, not proof that a contributor is unpaid. Exact reverse-dependency, sponsor, and search-result counts are dated snapshot observations whose raw query responses were not retained. Full sourced table: report/data/load-bearing-crates.md.

red: higher observed continuity risk amber: concentrated / monitor green: broader or institution-backed support
CrateWhat it isAuthor-concentration indicatorPublic support evidenceLast releaseObserved signal / interpretationAssessment
fontdbfinds fonts installed on the systemno sampled activityno public direct source or announced successor foundOct 202421-month release gap; used under Iced/COSMIC/Zed-Linux font resolutionred
apple-codesignRust-native signing & notarization from non-Mac CIhighGitHub Sponsors (8 public at snapshot)Nov 2024no release in 19 months and 69 open issues; principal open-source Rust-native path foundred
winitopens windows, delivers keyboard/mouse/IME events everywherehighno direct institutional source found; personal sponsors visibleMar 20260.31 redesign in beta for roughly 7 months and 21 days; a prolific contributor announced a hiatus citing burnout; 1,225 reverse deps recorded at snapshotamber
taffyCSS flexbox/grid layout math as a libraryhighDioxus Labs employs the lead maintainer full-time (since Mar 2024); no crate-level Sponsors listingJul 2026recent authorship concentrated in one maintainer under Zed, Bevy, Servo, Blitz, Slintamber
accesskitthe screen-reader bridge for Rust toolkits (+ GTK 4.18)high2023–24 STF/GNOME work wrapped up; NLnet NGI0 Commons grant (iOS, from 2025-11) scoped and delivered; no maintenance funding; 2 + 6 individual sponsorsAug 2026one active maintainer (Loubriat: all PR merges and releases since Apr 2026); Campbell reviews onlyamber
cosmic-texttext layout engine (the Iced/COSMIC one)highSystem76 employment supports the maintainersApr 2026active, with support concentrated in one companyamber
swashrasterizes shaped glyphs into pixelshighmaintainer employment is separate from a direct project grantJun 2026recent public commits concentrated; compatibility work continuesamber
taoTauri's winit fork (GTK-hosted windows for Linux webview)highTauri umbrella / CrabNebula involvementMay 2026recent authorship concentrated; remains on the pre-0.30 winit APIamber
mudanative menu bars & context menushighTauri umbrella; no direct source foundJun 2026recent authorship concentrated; Linux menubars require a GTK windowamber
tray-iconsystem tray iconshighTauri umbrella; no direct source foundJun 2026recent authorship concentrated; winit Linux path requires a parallel GTK loopamber
global-hotkeysystem-wide keyboard shortcutshigh / low-volumeTauri umbrella; no direct source foundMay 20266 commits in 12 months; its Linux backend is X11-only (ashpd exposes the portal separately)amber
arboardclipboard read/writehighmaintained in the 1Password organizationAug 2025~10.5-month release gap against 1,052 reverse deps at snapshotamber
rfdnative open/save file dialogshighno public direct source found; 0 public sponsors at snapshotJan 2026active, with recent public work concentrated in one maintainer; 479 reverse depsamber
notify-rustdesktop notificationshighno public direct source foundJun 2026active across three platforms, with recent authorship concentratedamber
softbufferCPU pixel buffer onto a window (software rendering)highno public direct source foundDec 202576 of roughly 84 commits in the audited year attributed to one authoramber
wgpuone GPU API → Metal/Vulkan/DX12/WebGPUlowerMozilla employs core maintainers for Firefox WebGPUJul 2026broad employer-backed contributor set in this comparisongreen
harfrustthe text shaper (ligatures, Arabic, kerning)moderateGoogle Fonts–backed, HarfBuzz orgJul 2026active with upstream/institutional backinggreen
parley + fontiquetext layout engine + font fallback (the Linebender one)lowertwo active NLnet grants (through Aug 2026) + Canva contributorJun 2026active; time-bounded grant deadlines are a continuity considerationgreen
wryembeds the OS webview (the Tauri/Dioxus renderer)lowerTauri programme; CrabNebula employs a maintainerMay 2026multiple active contributors in the sampled windowgreen
tiny-skiaCPU 2D renderer (iced's software fallback)lowerLinebender stewardship (post-handoff)Feb 2026post-handoff release shipped; activity remains modestgreen
raw-window-handlethe universal window-handle socket between cratesmoderaterust-windowing umbrella; no direct project source foundMay 2024stable API with low release activity (78M downloads at snapshot)green

One app, ten frameworks

identical spec · same machine · serial builds

A todo app (text input, Enter shortcut, per-row delete, live counter, scrolling) built idiomatically in each framework, versions pinned. All ten compiled and survived the launch check; later inspection observed their windows, and the implementations cover the source-level spec (GPUI exposes low-level elements and a hand-built input example but no reusable first-party high-level input widget, so this app approximated text input). On this M4 Pro, these ten small apps each clean-built in under a minute from a warm registry and empty target directory; that is not a general large-application ranking. Floem is the one deviation from the "latest crates.io release, pinned =x.y.z" rule: its published 0.2.0 was 20 months stale at measurement and main cannot be published (it depends on a forked winit and on git-only understory_* crates), so all eight floem apps pin git rev 778bb5f2. The unpublishable-main situation is itself a finding.

Clean release build

seconds · cargo clean → build --release
iced
22 s
vizia
22 s
egui
27 s
freya
28 s
xilem
28 s
tauri
36 s
dioxus
40 s
floem
42 s
slint
42 s
gpui
56 s
Incremental rebuilds: 1–4 s everywhere except tauri (10 s, from build-script re-validation).

Binary size, stripped

MiB · release binary after strip
gpui
4.3
dioxus
4.9
tauri
6.4
iced
8.5
xilem
9.7
egui
10.5
slint
13.2
floem
14.2
freya
18.3
vizia
19.6
A small webview executable externalizes its renderer. In the controlled live-dashboard run, webviews used 208–211 MiB including helpers versus 79–109 MiB for native-rendered apps.

Dependency tree

unique crate names in cargo tree
vizia
128
iced
140
xilem
143
egui
156
freya
192
tauri
204
floem
226
dioxus
279
slint
302
gpui
391
Of 28 crate names common to all ten trees, 16 resolve to multiple versions across apps. Version skew is a measurable fragmentation cost.

Recorded source size

lines · rust + markup/JS where applicable
iced
74
xilem
81
dioxus
90
freya
90
floem
91
slint
94
vizia
162
egui
168
tauri
208
gpui
230
GPUI is high because its reusable first-party high-level text-input/widget suite is incomplete, despite low-level elements and a hand-built input example. Counts are Rust + HTML/JS/CSS or Slint DSL and exclude JSON/TOML config, but include verification hooks embedded in source; they are not pure production-only LoC. Tauri therefore shows 208 here.

The interactivity curve

round 2 · two interaction-heavy apps × ten frameworks

Round 2 tested interaction: drag-and-drop, live data, custom charts, hover interactions, inline editing, animation. Two more apps per framework. "Pulse" is a live metrics dashboard (draggable card grid, 1–60 Hz data at default 10, hover-tooltip chart) and "Board" is a kanban (cross-column DnD, drop indicators, double-click edit). All 20 built and survived the scripted launch check, and later inspection observed their windows (floem's two retained records are launch-liveness only); interaction evidence ranges from source/API paths through retained app tests as marked per capability. Full data: report/11-interactive-results.md + per-app FRICTION.md.

built-in assembled from primitives hand-rolled approximated
Capabilityicedeguigpuitaurixilemslintdioxusfreyaviziafloem
Charts + sparklines hand-rolled egui_plot hand-rolled Canvas2D hand-rolled Path strings SVG in RSX Skia canvas vg::Canvas canvas + kurbo
Chart hover + tooltip hand-rolled crosshair 1 line + snap code hand-rolled hand-rolled hand-rolled assembled assembled assembled assembled hand-rolled
DnD: grid reorder hand-rolled egui_dnd native DnD HTML5+math hand-rolled hand-rolled hand-rolled DragZone/DropZone on_drag/on_drop draggable
DnD: cross-column hand-rolled hand-rolled native DnD hand-rolled hand-rolled DragArea 1.17 hand-rolled built-in built-in built-in
Drag ghost assembled assembled built-in free (HTML5) assembled hand-rolled hand-rolled drag_element hand-rolled built-in
Live data 1–60 Hz built-in² idiom spawn loop events task view Timer tokio DIY async-io timer cx.add_timer exec_after chain
Inline edit (dbl-click) assembled assembled own editor assembled dbl-click/Esc wrapper assembled assembled press classifier on_double_click typed DoubleClick
Animate reorder/drop snaps¹ tweens settle only CSS FLIP snaps¹ animate x,y CSS settle scale-in on drop CSS transition spring release

¹ The sample has no shared automatic FLIP/position-transition abstraction: stock iced/xilem layouts snap, while the implementations used egui tweens, hand-built CSS FLIP, explicit Slint x/y animation, or the framework-owned tweens and springs of the 2026-08-03 trio. Vizia comes closest, since a CSS transition: height genuinely animates a layout property, so the kanban's insertion gap opens and closes. Even so, no framework automatically transitions a card it did not itself move: Slint and floem animate positions only because the app positions cards by index or the framework owns the drag ghost. ² iced's time::every needs a non-default executor feature; the compile error gives no hint.

Code for both apps

total LoC (Rust + markup/JS) · same two specs
floem
774
dioxus
936
egui
1038
freya
1086
slint
1166
tauri
1199
vizia
1242
gpui
1248
iced
1394
xilem
2393
These totals include different amounts of verification/config code; publish production and harness LoC separately before treating the ranking as framework overhead.

CPU while live at 10 Hz

avg % of one core · one 30 s observation · incl. webview helpers · 2026-07-10 rerun reproduced ±≈1 pp for the original seven (retained); trio sampled 2026-08-03; occluded/backgrounded runs read far lower
floem
3.0%
iced
3.5%
freya
4.5%
vizia
6.0%
gpui
6.8%
slint
9.2%
egui
9.6%
xilem
9.9%
dioxus
11.9%
tauri
14.0%
The immediate-mode CPU-tax folklore didn't materialize in this live-dashboard sample: egui's reactive scheduler repaints at the tick rate. No controlled board-idle dataset was retained.

Memory while live

max RSS, MiB · incl. WebKit helper processes
gpui
79
floem
95
iced
95
slint
95
freya
100
xilem
106
vizia
108
egui
109
dioxus
208
tauri
211
Two clean tiers in this run: native-rendered ≈ 79–109 MiB, webview 208–211 MiB for the identical live dashboard.

What the round taught

cross-cutting findings
Nine of ten implementations drew their own charts. The experiment used only egui's helper (freya's plot/plotters feature was deliberately left unused to measure the drawing story), although current Iced- and GPUI-compatible chart crates also exist with uneven maturity, as do DnD helpers (iced_drop supports Iced 0.14 but was not discovered or evaluated during the iced implementation).
DnD support differs by layer. gpui, Slint and all three 2026-08-03 additions had strong built-in support (freya's typed DragZone/DropZone, vizia's core on_drag/on_over/on_drop, floem's draggable with an automatic ghost and spring release); other implementations used framework events, compatible helpers, or custom pointer state.
The text-input gap compounds. gpui hand-rolled its editor just for double-click edit; xilem ships a text input but hand-rolled the double-click, autofocus and Escape plumbing around it; and freya has no double-click event but ships a multi-press classifier (EventsCombos::pressed, the primitive its own text editor uses) that our first kanban missed and re-implemented with a timer (corrected 2026-08-30 after the Freya maintainer pointed it out; the Escape plumbing is still hand-rolled).
Several implementations exposed concrete traps: wry's dragDropEnabled eating drag events (documented; tauri#14373), egui drag sources making child buttons inert (egui#5822), masonry's last-wins pointer capture (unreported — filing), Dioxus events lacking the target's size (offsets exist; the rect is async via onmounted), iced's input capturing Escape (documented behaviour of event::listen; the gap is an on_escape hook, iced#2678), vizia only firing actions on the hovered entity (so a click on a card's own label silently does nothing — a regression of vizia#406, filing), and freya canvases that never repaint unless they carry an event handler (confirmed on main — filing). Upstream status checked 2026-08-30. The retained list does not establish one trap for every framework.
Documentation observation. Eight of ten implementations recorded reading vendored crate source, and several pre-current tutorials were stale. This is an observation from the study, not a universal expiry rule.

The "hard parts," measured

round 3 · OS shell integration · "Tray Notes" × 10 (macOS)

One quick-note app per framework exercising everything AROUND the window: tray, global hotkey, native menubar, dialogs, clipboard (text + image), Finder file-drop, notifications, live dark mode, multi-window, close-to-tray. Zero implementation-level not-achievable cells on tested macOS. All ten frameworks exposed a viable path, although Finder drops and some notification results were source/API-level rather than real end-to-end observations. Full matrix + evidence notes: report/12-shell-integration-results.md. The round's traps and reference shapes are distilled into a facade requirements brief: the winit shell facade, specified.

built-in assembled (helper crates + glue) hand-rolled / workaround
Capabilityicedeguigpuitaurixilemslintdioxusfreyaviziafloem
System trayassembledassembledassembledbuilt-inassembledDSL elementbuilt-intray featuretray-icontray-icon
Global hotkeyassembledassembledassembledpluginassembledassembledbuilt-inassembledassembledassembled
Native menubarmuda¹muda¹built-inbuilt-inmuda¹DSL elementbuilt-inmudamudabuilt-in
Native dialogsrfdrfdbuilt-inpluginrfdrfdrfdrfdrfdbuilt-in
Clipboard imagearboardarboardbuilt-inpluginarboardarboardarboardarboardarboardarboard+png
File drop (Finder)built-inbuilt-inbuilt-inbuilt-inworkaroundunstable featurebuilt-inbuilt-inbuilt-inbuilt-in
Notificationnotify-rustosascript²notify-rustpluginosascript²notify-rustnotify-rustnotify-rustnotify-rustnotify-rust
Dark mode (live)built-inbuilt-inbuilt-inbuilt-inhand-rolledbuilt-inbuilt-inbuilt-inbuilt-instartup-observed; live toggle not runbuilt-in
Close-to-traybuilt-inassembled³assembledbuilt-inassembledbuilt-inbuilt-inassembledassembledbuilt-in

¹ A trap reproduced in these 3 integrations: muda's predefined Edit items silently swallow ⌘X/⌘C/⌘V before the framework's own bindings, so the standard Edit menu breaks paste app-wide. Freya, vizia and floem all reach the same muda API and all three deliberately avoided the predefined Edit roles for this reason. ² notify-rust was rejected for different reasons in the two frameworks: egui hit a frame-scheduling freeze in two of three runs (cause unproven; a 2026-08-30 source check rules out the earlier delegate-replacement hypothesis and points at the helper's synchronous run-loop pumping; no minimized reproduction was retained), while xilem hit AppleScript's blocking app chooser for the use_default bundle id, a winit re-entrancy panic-abort, and silent no-banner delivery from a detached thread. ³ eframe never runs App::ui for hidden viewports, so reopen logic must live elsewhere or the window can't come back. Round upset. dioxus quietly matches Tauri here (tray, hotkey, menubar, multi-window, close-to-tray all built-in). 2026-08-03 addendum. floem is the only native-rendered framework here with native menubar, dialogs, file-drop, live dark mode, multi-window and Dock-icon reopen all built in, none of it documented outside its source. freya's tray feature owns the global tray-icon/muda handlers itself, which structurally prevents the muda channel-splitting trap dioxus hit, a trap iced and egui avoided only by deliberately routing both menus through the tray_icon::menu re-export, and floem escaped by accident via a muda version mismatch; vizia ships no shell layer beyond windowing, but its models run on the main thread with no Send bound, so the !Send tray handle just lives in app state. Scope note. This is macOS; the Linux GTK fault line (muda menubars cannot attach to plain winit windows; global-hotkey is X11-only) still holds as documented in the fragmentation stories.

One corpus, ten text stacks

round 3 · "Babel" · same 11 lines everywhere

The same multilingual corpus (Latin ligatures, Arabic/Hebrew BiDi, Chinese/Japanese/Korean, Devanagari, Thai, ZWJ emoji, one all-scripts line) rendered by every framework. Verification used screenshots plus OCR/glyph/caret diagnostics described in each FRICTION file. All ten screenshots are retained, but not every raw diagnostic output is; exact caret/OCR/mark counts and caption-specific interpretations therefore remain local observations rather than independently reproducible results. Full matrices incl. evidence levels and editing behavior: report/13-text-i18n-results.md.

The three stacks added on 2026-08-03 are not embedded above (page weight); their window-scoped captures are retained at apps/freya-babel/screenshot.png, apps/vizia-babel/screenshot.png and apps/floem-babel/screenshot.png. Verdicts: freya (Skia textlayout over CoreText) renders all 11 corpus lines, no tofu, 0 bytes of bundled fonts; vizia (SkParagraph over CoreText) also renders all 11 lines, no tofu, 0 bytes bundled; floem (parley/fontique) is the second stack in the corpus to hit the fontique Han-discovery hole xilem exposed. Han and kana ([ZH], [JA], and 世界 inside the mixed line) render as pure tofu because fontique 0.7.0 (floem's pin) rejects CoreText's PingFang answer, which has no readable font file on macOS 26, while Hangul, Devanagari, Thai and BiDi are all correct; regional-indicator flag pairs are tofu too (a harfrust AAT shaping bug). Both are fixed upstream in fontique/parley 0.8.0 (2026-03), so the fix is a dependency bump in floem, not app code (status checked 2026-08-30).

Editing is the sharper finding. Rendering mostly works. Backspace over 👨‍👩‍👧‍👦 deletes the whole cluster in WebKit and gpui's hand-rolled editor, shrinks it through valid smaller emoji in Slint (by design), and splits the cluster or leaves a dangling zero-width joiner in the tested iced, egui, and xilem editing paths. Those integrations lacked whole-cluster deletion out of the box. Source re-check 2026-08-30: cosmic-text 0.15's Backspace deletes one char while its Delete uses grapheme clusters (unreported — we are filing it); parley 0.6's backdelete treated one char as a cluster and is fixed on main by PR #715 (unreleased); egui deletes per char by design. The 2026-08-03 trio splits the same way from three more stacks: floem's Lapce editor core treats the 25-byte family as a single caret stop (the best grapheme behaviour measured here), vizia moves and selects by grapheme but deletes by scalar (its emoji state machine never advances its cursor — a one-line fix, unreported, we are filing it), and freya-edit 0.4 moves the caret by UTF-16 code unit, so a caret can land inside a surrogate pair and one Backspace corrupts the cluster and leaves a dangling joiner, in a crate that already depends on unicode-segmentation (fixed upstream in freya-edit 0.5.0-rc.1, PR #2034). Egui also dropped 13 corpus combining marks; Slint showed one notdef mark and clipped tall stacks. macOS AX selected-text queries returned garbled RTL text for egui; actual screen-reader speech was not exercised, so assistive-technology impact remains an inference.

From binary to .dmg

round 3 · packaging the todo apps · macOS · extended to all ten 2026-08-08

The seven July iteration-1 apps were bundled into launching DMGs containing ad-hoc-sealed .app bundles. The "packaging is the hard part" claim splits in two. The mechanical layer is nearly free. A revived cargo-bundle packaged all six non-Tauri frameworks with an identical 4-line stanza, under a minute each, and it beat cargo-packager, the ecosystem's "intended answer," head-to-head in this run. The trust layer is the real cliff. With no identity configured, none of the tested runs produced a distribution signature. cargo-bundle lacks signing, while Tauri/cargo-packager support it when configured. The create-dmg flows failed repeatedly on this macOS 26 machine, while a plain hdiutil create fallback was more reliable. In the standard quarantined-distribution path tested here, spctl rejected all seven of those ad-hoc bundles as expected without Developer ID signing and notarization; Tauri, cargo-packager, and the principal Rust-native cross-platform implementation rcodesign automate parts of that workflow but cannot supply Apple credentials. Bundle sizes: 5.0 MiB (GPUI) → 14.7 MiB (Slint). Reliable app-attributed notification banners and dock behavior also benefit from a bundled, identified .app. 2026-08-08 completion. The current freya, vizia and floem apps went through the identical cargo-bundle pipeline. All three launch, seal, and hdiutil-verify (spctl rejected as expected); floem, packaged for the first time, is smaller than the Skia-static pair (17.1 vs 20.3/21.7 MiB .app). The same day, an RCN-thread tip was tested: dx bundle (dioxus-cli 0.7.10) packaged all nine non-Tauri apps 9/9 from a 4-line Dioxus.toml each, and its built-in DMG step succeeded first-try for all nine, the exact step that failed on 6 of 8 tool paths in July. Costs: it rebuilds each app under its own desktop-release cargo profile (~24–53 s) and ignores [package.metadata.bundle]. Its macOS signing/notarization automation exists in the 0.7.10 code but was not exercised (no credentials, by design). Details: report/14-packaging-results.md + report/data/packaging-results.md.

Hardware, data, and async

round 4 · camera/mic · 100k-row grid · network · 30 more apps (macOS)

Round 4 tested the last untested dimensions: "Peek" (camera preview ≈30 fps, mic meter, audio, 200-image gallery), "Grid" (100k rows: virtualization, sort, filter, resize, selection), and "Fetcher" (debounce, streamed progress, and cancellation proven by a local server that logs client disconnects). All 30 apps built and ran. Full matrices with per-cell evidence labels for the original seven: report/15-media-hardware-results.md, report/16-data-grid-results.md, and report/17-async-network-results.md; the freya/vizia/floem evidence lives in report/data/iter4-rows.md and the per-app FRICTION.md files.

Camera preview: observed CPU around 30 fps

% of one core · reported ps samples/ranges · paths and resolutions differ
dioxus
5–9%
gpui
~8%
tauri
4–12%
egui
~16%*
iced
~28%
floem
~29%
vizia
~29%
freya
27–31%
slint
~34%
xilem
60–75%
The observed 4–75% range tracked different texture paths: the webviews used getUserMedia, GPUI used an undocumented public zero-copy surface path (the IOSurface is the Metal texture; NV12-only assert), and the other native paths re-uploaded RGBA frames. Resolutions and implementations differ, so don't treat the bars as a ranking, and only Dioxus retained a raw per-sample CPU CSV (the 2026-08-03 trio retained 1 Hz ps samples in their self-test logs). *egui at 720p; iced/slint/xilem/freya/vizia/floem at 1080p. floem's figure is not comparable: its vger renderer keys images by content hash in a single atlas, and any frame above roughly a third of the atlas dimension wedges image drawing permanently (the preview goes black after ~3 frames), so every frame is downscaled to ≤320×180 on the camera thread and the atlas is cleared roughly every 13 frames. Tauri also deviated from the requested cpal/rodio path by using WebAudio/getUserMedia. Dioxus's Rust-side alternative measured 4–6× its JS path for identical pixels.

What round 4 settled

condensed · details in reports 15–17
Computation was not the bottleneck in these tested grid apps. Recorded filter/sort self-tests took roughly 1.5–23 ms, including several double-digit sorts. The timings used different queries, ordering, and measurement points, so they are not a controlled framework ranking. Vizia is the one framework whose data grid is a view-constructor call: its core VirtualTable is genuinely virtualized (22 of 100,000 rows materialized at every scroll ratio), sortable, resizable and selectable, though its own row/cell wrappers eat the click that selects a row until an undocumented CSS class is given pointer-events: none. Everywhere else the table is assembled: egui_extras TableBuilder was the only other suitable first-party basis (resizing built in, sorting and shift-selection assembled in the app); iced's new table eagerly built 600k cell widgets in the inspected path; Slint's StandardTableView did not meet the chip or multi-selection parts of this spec; freya ships a Table that is a layout helper (one element per cell, 600k at this scale) and a separate VirtualScrollView that is the real answer; floem has no table widget at all. Stock virtualization exists in gpui (uniform_list), slint (Model/ListView), xilem (whose cited run scrolled roughly 8,000 rows deep rather than the full 100,000, a scroll-depth note rather than a capability limit), freya and floem; xilem's and floem's table furniture was hand-rolled.
All ten cancel network requests for real (server-verified TCP aborts, attributed by byte-exact chunk counts or correlated log offsets/timing), via ten different async architectures, none portable. Drop-based cancellation composes wherever tokio is native or bridged. Freya still runs a tokio runtime as reqwest's reactor but polls the future on its own single-threaded UI executor, so cancelling its TaskHandle drops the future at its await point. That one mechanism is debounce, stale guard and protocol-level cancellation.
One runtime-shaped trap per framework: iced's default executor has no reactor (reqwest panics at runtime; enable the tokio feature); ehttp's with_timeout flag is ignored for GET and inverted for POST, so streaming GETs are silently capped at 30 s (corrected 2026-08-30 — its default timeout does not kill an 8 s stream); gpui ships an HttpClient trait with no published transport; tauri's webview fetch is CORS-blocked from tauri://localhost (the plugin fix bakes URL scopes at build time); xilem re-exports tokio without macros; slint's spawn_local has an executor but no reactor (documented; use async_compat); dioxus's occluded windows park the whole task loop (3/6 ordinary runs, deterministic with always-on-top; 0.7.9). In-flight downloads stop because dioxus-desktop waits for the webview's JS to ack each edit batch before polling any Rust future; wry has the throttling knob, dioxus doesn't plumb it (tracked as dioxus#5586 / PR #5587). The 2026-08-03 trio adds three more shapes: freya has an executor but no interval hook (only a one-shot use_timeout behind a non-default feature) (five of its eight apps depend on async-io purely for Timer::after); vizia has no executor whatsoever, so every networked app re-invents the same thread + ContextProxy bridge, though there is also no executor mismatch to get wrong; floem likewise ships no executor, yet its ExtSendTrigger/create_ext_action pair is the cleanest foreign-thread wakeup measured here and it is the only framework with a built-in debounce_action.
Two silent, catastrophic traps live in shared layers under floem: taffy's default min_height: auto lets a scroll grow to min-content, which silently disables VirtualStack virtualization (100k rows → 16 GiB RSS and no window ever appears), and vger's content-hash atlas wedges image drawing permanently above ~320×180. One obscure style line fixes the first; nothing warns about either.
TCC observation, scoped to this machine. Four tests of unbundled cargo binaries launched from the same terminal inherited that terminal's permission decision. This is not established as a universal macOS rule.
nokhwa 0.10.11 was not usable out of the box with the FaceTime camera on this host: the tested path encountered NV12 fourcc mapping, advertised-frame-rate, and patch-release compilation problems, and required source-level workarounds. This does not establish that nokhwa is generally broken on modern macOS.

Linux reality check

round 5 · Docker/Xvfb · software GPU · X11 · arm64 Debian 12 · container rustc 1.97.0

The macOS-built apps, rebuilt and run on Linux headlessly (lavapipe software Vulkan + llvmpipe GL, WebKitGTK 2.50.6, one plausible CI configuration). All 11 tested apps compiled with zero source changes (gpui needed one -dev system package at link time); the differences live mainly in the render path and the shell layer. Font discovery/fallback and gpui's present path also differ per platform. This round predates the expansion: freya, vizia and floem have not been built or run on Linux. Verbatim logs, screenshots, and probe sources retained. Full report: report/18-linux-reality-results.md.

Default render paths. egui, slint, tauri and dioxus just work. iced panics on software Vulkan (its shader needs an f16 capability lavapipe lacks, and it does NOT auto-fall-back to its own tiny-skia); xilem hard-aborts (uncatchable lavapipe/LLVM JIT bug in vello's compute shaders); gpui silently renders nothing. Vulkan init succeeds, window maps, zero frames, zero diagnostics (root cause proven by a working probe, 2026-07-10. The event-loop hypothesis is refuted: the X socket is polled and read, and frames ARE rendered and submitted, but the X server rejects every present with BadMatch, a depth-24 PutImage blit onto gpui's depth-32 ARGB window, silently swallowed; vkcube renders because it uses the default depth-24 visual). Software Vulkan is the fragile path. WGPU_BACKEND=gl rescued both wgpu failures.
WebKitGTK workarounds are unnecessary in this environment. The DMABUF/compositing blank-window workarounds were tested and verified unnecessary on 2.50.6 in this Xvfb/llvmpipe environment for both webview apps (Tauri docs still recommend them for NVIDIA/driver-conflict setups, which is not evidence of general obsolescence).
The GTK fault line, confirmed live. The tested Muda API could not attach a menubar directly to a plain Winit window (E0277 retained); our macOS-written tray apps compiled unchanged on Linux and then panicked at launch in Muda's first GTK call. Build-only Linux CI passed while each tested launch died; tray failures without a GTK loop or without a StatusNotifier host are silent successes. global-hotkey's X11 path works end-to-end.
Text travels better than the shell. iced-babel's BiDi layout is visually/order-consistent with the macOS run (cosmic-text), CJK/Devanagari/Thai correct from Noto, CBDT color emoji works, but singleton emoji render monochrome (distro font-fallback ordering shadows Noto Color Emoji).

Windows reality check

round 6 · Ryzen AI 9 HX 370 · Radeon 890M/32.0.13058.2 · Windows 11 Home 26200.7171 · rustc 1.96.1

The 80 apps, rebuilt and launch-probed on one real Windows 11 x64 laptop (MSVC toolset pinned to 14.34, 200% DPI, WebView2 151.0.4129.59). 28 of 80 apps fail cargo build --release as-is, including three entire frameworks at 0/8 (tauri, freya, vizia), all three on packaging/distribution infrastructure rather than framework Rust code. 36 reached a visible window on the default env, and WGPU_BACKEND=dx12 rescued all 14 of the intermittent wgpu surface deaths. Verbatim logs, per-variant runs, screenshots and CSVs retained. Full report: report/21-windows-reality-results.md.

Default render paths. iced (wgpu) and slint (FemtoVG/GL) went a perfect 8/8 build + 8/8 run; gpui's in-house Direct3D 11 and dioxus's WebView2 ran 7/7 of their built apps with zero render-path flakiness; egui, xilem and floem defaults died intermittently on wgpu's FailedToCreateSurfaceForAnyBackend (empty per-backend error map — instance-level, not provably Vulkan surface creation) (floem 0/6 on default). WGPU_BACKEND=dx12 rescued all 14 surface deaths.
The build fault line is infrastructure, not Rust. tauri went 0/8 because the build script hard-fails on a missing icons/icon.ico before any app code compiles (the icon is missing from our repo — our omission, not a tauri defect); freya 0/8 because its prebuilt-Skia download died on curl(3) on this machine (the Windows asset does exist upstream and downloads elsewhere — cause unisolated; corrected 2026-08-30) and the source fallback demands LLVM; vizia 0/8 on LNK1120, five unresolved __std_* externals linking skia-safe's prebuilt skia.lib against the pinned 14.34 MSVC STL.
Camera, split verdict. The predicted nokhwa build break mostly did not happen. iced-peek and slint-peek built and ran as-is, and the msmf-manifest rebuild put all four buildable frameworks' camera apps on screen; gpui-peek did not build because our crate lists core-foundation/objc unconditionally instead of under a macOS target table (our gating bug, not a gpui limitation — corrected 2026-08-30).
Tray/toast/hotkey reality. Every built tray app's Cmd+Shift+9 registration failed AlreadyRegistered (Win+Shift+9 is an OS taskbar shortcut held on this desktop). egui-tray and xilem-tray .unwrap() and die; the other five log the failure and keep running. iced-tray captured the campaign's only tray screenshot; dioxus-tray's notify-rust show() returned Ok from a bare unsigned exe (no toast was captured, so that is not evidence of display).
Runtime numbers. slint-dash is the CPU outlier at 15.8% avg / 38% peak (per-core), consistent with the macOS re-tessellation finding; gpui-dash is the memory floor at 98 MiB max RSS vs xilem-dash's 495 MiB and dioxus-dash's 489 MiB (which carried 6 msedgewebview2.exe helper processes).
Selftest reality. Only 2 of 50 suites hit the canonical done-marker with a clean exit (both floem: grid 14/14, fetch 10/10); most of the rest did the work but were scored timeout/no-marker on macOS-shaped marker and exit conventions. iced-babel produced the campaign's only babel PNG and reproduced the macOS ZWJ-backspace corruption on Windows.
Packaging. cargo-packager's WiX route built an MSI from all 7 buildable apps, and all 7 installed and uninstalled cleanly in an elevated verification pass (6/7 passed the post-install launch check); cargo-bundle MSI and cargo-packager NSIS went 0/10 each (Component-table error; vendored-makensis plugin-path leakage); dx bundle emitted an NSIS exe rather than the expected MSI. Its silent install/uninstall worked but the installed copy failed the launch check, and the MSI-installed dioxus-app failed the same check. Three independent installed copies of dioxus-app fail to launch while the same exe runs fine from target\release.

Framework verdicts

from the framework research · versions tested

iced

0.14.0 · MIT
Enforced Elm architecture on winit + wgpu + cosmic-text. Joint-fastest build and the leanest todo-app code of the ten (74 LoC); vizia now has the leaner dependency tree. Powers COSMIC (via fork), Sniffnet, Halloy.
no a11y in stablehigh maintainer concentrationno built-in menus/tray; helpers worked on macOS14.5-mo release gap
Pick when you want structural discipline and can defer accessibility. COSMIC/Halloy use forks or master; Sniffnet ships stable Iced.

egui

0.35.0 · MIT/Apache
Immediate mode with reactive repaint. Changed shaping, font handling, and rasterization (harfrust + skrifa + vello_cpu) in '26 while retaining galley layout. The schema used here requires AccessKit; platform adapters depend on the integration and features. Ships a headless a11y-tree test harness (kittest).
AccessKit adapter default via eframeno paragraph BiDibundled fonts by defaultRerun-backed
Pick when building tools, editors, debug UIs. You get a 1 s incremental rebuild and the third-lowest round-two implementation LoC of the ten (floem and dioxus are lower).

gpui

0.2.2 · Apache-2.0
Zed's engine: hybrid retained/immediate, custom windowing, taffy layout, 120 fps discipline. Smallest binary in test. Core GPUI has low-level elements and a hand-built input example; a reusable high-level suite is typically supplied by third-party gpui-component (Zed's own ui crate is GPL).
a11y unreleased / Zed opted outcrates.io stalled 8.5 mono reusable 1st-party input$32M Series B, Aug '25
Pick when performance is the product and the team can git-pin the zed monorepo. Note: in Feb 2026 Zed leadership said GPUI work not tied to Zed's use case is deferred (Discord, quoted on HN); community continuation is happening in the gpui-ce fork.

tauri

2.11.5 · MIT/Apache
Rust core + system webviews by default (wry/tao); Windows installers can instead bundle fixed/offline WebView2. It has first-party capability controls and configurable CSP, ~30 official plugins, and an integrated first-party runtime updater. Browser-grade text/IME and a strong a11y baseline when semantic HTML/ARIA are authored.
webview a11yiOS+AndroidWebKitGTK pain on LinuxCommons Conservancy
Pick when the team knows web tech or you need mobile + updater + plugins today. The Verso/Tauri integration is archived; Servo itself remains active.

xilem

0.4.0 · Apache-2.0
Linebender's reactive framework on the converging stack: winit + vello + parley + AccessKit. Deep text semantics; no publicly documented shipping production Xilem app was found in this audit; ~15 views/widgets.
AccessKit deepalpharelease lags main 8 mopost-Google funding
Pick when experimenting with where the ecosystem is heading. Several other stacks are adopting parts of the same foundation.

slint

1.17.1 · GPL/RF/paid
Compiled .slint DSL + live tooling; the only one in this sample with a documented MCU (264 kB RAM)-to-desktop target (platform support for the 2026-08-03 trio was not researched). Slint, Xilem, Dioxus, Freya, Vizia and Floem all recorded zero source-level SPEC-1 gaps. First-class declarative menus/tray; Fluent default since 1.16.
AccessKit default on Winit desktopattribution required (RF)DSL = 2nd languagerevenue-funded GmbH
Pick when designer-driven product UIs or embedded+desktop span; read the Royalty-Free license terms first.

dioxus

0.7.9 · MIT/Apache
React-like RSX + signals over the same Tao/Wry webview family as Tauri. Normal handlers avoid a user-authored invoke boundary, but VDOM events/mutations still cross a Rust↔webview bridge. Blitz is pre-alpha: stable dioxus-native 0.7.9 uses classic AnyRender/Vello, development main defaults toward Vello Hybrid, and current blitz-shell has no Muda dependency.
webview a11ysubsecond hotpatch (now also driving Bevy)no Tauri-style security modelYC profile: Acquired
Pick when you want web ergonomics in Rust and accept a young stack. The CLI supports deep-link metadata, signing/notarization, and updater archives; no first-party runtime update client was found.

freya

0.4.0 · MIT
Dioxus-lineage signals over Skia and winit, with its own torin layout engine, though 0.4 dropped the RSX macro for a chained builder API. Richest built-ins of the three 2026-08-03 additions: typed DragZone/DropZone, a first-party camera, a stock VirtualScrollView, a tray feature that owns the global tray-icon/muda handlers, and the cleanest async story here: a single-threaded executor on the UI thread, so await then assign to a signal, no channels and no Send.
AccessKit inline per element28 s clean · 18.3 MiB192 deps · 4.5% CPU liveSkia via a personal fork
Pick when you want Dioxus-shaped reactivity with native Skia rendering and no webview, and camera or virtualized lists are on the critical path. Budget for the gaps: Input is hard-wired to one line, there is no interval hook (only the one-shot sdk::use_timeout behind a non-default feature; live data is a bare spawn plus your own async-io timer), double-click is a classifier call (EventsCombos::pressed) rather than an event, and freya-edit 0.4 moves the caret by UTF-16 code unit, so one Backspace can split a ZWJ emoji cluster and leave a dangling joiner (fixed upstream in freya-edit 0.5.0-rc.1).

vizia

0.4.0 · MIT
Fine-grained signals with an Elm-ish Model::event, on winit + Skia, plus the only real CSS engine in the sample (stylesheets, transitions, @keyframes). Smallest dependency tree and fastest builds of the three additions, and the only framework here whose data grid is a view constructor: VirtualTable is virtualized, sortable, resizable and selectable in core. Models have no Send bound and run on the main thread, which is where !Send OS handles live comfortably.
AccessKit default feature22 s clean · 19.6 MiB128 deps · 6.0% CPU liveno async executor
Pick when the app is data-dense or CSS-shaped and you want a real table without assembling one. The long-standing audio-plugin recommendation now has measurements behind it. Costs: bring your own tokio (there is no executor at all), and the framework is unusually silent about mistakes. An action only fires when the acted-on view is the hovered entity, so clicks that land on a child label do nothing at all.

floem

git 778bb5f2 · MIT
Lapce's framework: Leptos-lineage fine-grained reactivity, typed event listeners, taffy layout and the parley/fontique text stack, with the real Lapce editor core in the tree. Smallest binary and lowest live-dashboard CPU of the three additions, the most complete shell integration measured here (menubar, dialogs, file-drop, dark mode, multi-window and Dock-icon reopen all built in), cheap built-in drag-and-drop with an automatic ghost, and ExtSendTrigger foreign-thread wakeups.
no a11y anywhere in the tree42 s clean · 14.2 MiB226 deps · 3.0% CPU livegit-only; forked winit
Pick when you are building an editor-shaped app and can live on a git pin: crates.io 0.2.0 was 20 months stale at the 2026-08-03 measurement (21 by the 2026-08-04 upstream check) and main is structurally unpublishable, so every consumer inherits the fork and the churn. Rules itself out where accessibility is required, and at this rev fontique 0.7 renders Han and kana as tofu on macOS (fixed upstream in fontique 0.8.0 — a bump away) while vger's image atlas wedges above ~320×180.

Windows & forms, measured

iteration 5 · multi-window + modal · numeric forms · 22 more apps · 11th entry: Dioxus Native (Blitz) · macOS · 2026-08-30

Two specs an r/rust commenter asked for: "Windows" (what is a window — modality, parenting, shared state across windows, close veto, persistence) and "Ledger" (can the text input be a numeric input — typed filtering, locale, decimal alignment, tab order, undo — plus the corpus' first verified accessibility-tree dump). All 22 apps self-test (SELFTEST DONE … fail=0) and were re-verified by three independent passes. Full write-up: report/22-windows-forms-results.md; normalized 11-column matrices: report/data/verification/iter5-matrix.md.

The window model decides shared state before any code is written. Window-as-view frameworks (xilem, vizia, floem, gpui, iced's daemon, freya) give N windows one state tree for free; dioxus injects a Signal per VirtualDom via with_root_context (works — while GlobalSignal silently forks per window); eframe's deferred viewports force Arc<Mutex>; slint's export global is per-component-instance.
OS window-modality exists in two APIs — gpui's window.prompt and tauri's set_enabled(false) (a beginSheet: disabler under the hood); iced/slint/floem reached the same sheet with ~30 lines of objc2; everyone else ships an overlay that blocks input but is not OS modality. winit has no modal API, no cross-platform owner windows (with_owner_window is Windows-only), and addChildWindow: crashes freya (AccessKit adapter ordering) and fights tauri's always_on_top.
Numeric input is hand-rolled almost everywhere. True pre-insertion filters exist in slint (key-pressed → accept), freya (on_validate) and iced (controlled input); vizia can only post-validate; dioxus drops fast keystrokes (DOM→IPC→VDOM round trip) and needs a remount to reject one. Locale parsing was hand-rolled in 10 of 11 — only the webview got Intl.NumberFormat for free. tnum tabular figures are reachable only in the CSS engines and gpui (measured: 63.44 px vs 86.68 px for ten digits).
Accessibility, verified: named+valued trees in tauri (741 nodes), dioxus (323), egui (224), slint (209), vizia (248), freya (422, off by default; titles are frozen snapshots); values-without-names in xilem; roles-without-names/values in Dioxus Native; nothing in gpui, iced, floem. Harness trap: AccessKit trees activate lazily — the first AX walk sees only window chrome.
Dioxus Native (Blitz main, 0.3.0-beta.2) is the corpus' 11th entry: the Dioxus desktop app.rs runs on it unchanged (a #[path] include and a swapped platform.rs — the Ledger crate's own Rust is 78 lines), in one process instead of four — at 24.5–27.9 MB binaries vs 6.5 MB, 60–69 s clean builds, and with beta gaps: <select>/<input type=date|range> paint nothing, Tab emits no focus events, ⌘-chords never reach the VirtualDom — but it re-implemented its launcher and gained a genuine close veto the webview lacks. Serial measurements: measurements/reruns/20260830T193713Z/results-iter5.csv.

Choosing in five questions

the decision path, condensed
1 · Is accessibility a hard requirement this year?
Yes → Tauri/Dioxus (browser a11y tree), Slint on its default Winit desktop path, or egui through default eframe integration; vizia and freya also ship AccessKit in their default trees (freya even carries the roles inline on each element), though screen-reader depth was not exercised here. Rules out iced, released gpui, and floem, which has no accesskit anywhere in its dependency tree. Integration presence is not audited screen-reader compliance, so prototype with VoiceOver/NVDA first.
2 · Does the team know and like HTML/CSS?
Yes → Tauri (JS-first team, security/plugins/updater) or Dioxus (all-Rust, React-like). Want the CSS without the webview → vizia, the one native-GPU framework here with real stylesheets and transitions. No → native-GPU family.
3 · What shape is the app?
Forms-and-lists product → iced. Tool/editor/data-dense → egui. A real sortable, virtualized data grid out of the box → vizia. Designer-driven or embedded ambitions → Slint. Editor-class performance → gpui; editor-class text semantics on a git pin → floem. Dioxus-style reactivity with native Skia, camera or virtualized lists → freya. Research bet → xilem.
4 · Mobile from the same codebase?
Documented iOS + Android paths today → Tauri, Dioxus, or Slint (Slint's Rust iOS path uses Winit + Skia). Official Android-only is also available through egui/eframe; eframe does not document official iOS support. No mobile → all options open. Scope note: this research measured desktop only. Mobile paths here are documented upstream claims, not benchmarked.
5 · Special contexts
GNOME-first → relm4/gtk4-rs · Qt shop → cxx-qt · audio plugins → vizia (now measured in full above) /baseview · MCU + desktop → Slint · tiny utility → fltk-rs.

Whatever you pick, prototype the riskiest screen first (not hello-world), pin versions exactly (several audited tutorials were stale; this was not universal), test Linux on Wayland + NVIDIA early, and budget real time for packaging, signing, and updates. Tauri has the most integrated first-party chain; other stacks assemble maintained bundlers, platform tools/rcodesign, and Velopack.

What a working group should fund

where funding does the most, in priority order
  1. Finish the accessibility map: fund iced's AccessKit integration. The tracking issue is iced#552 (open since 2020); the live draft PR #3111 demonstrates VoiceOver on one limited Button/Text example; the most complete community attempt, PR #3281, was closed unmerged in Mar 2026. System76's fork ships a11y today via pop-os/iced. Upstream integration would close the baseline gap in this sample, but still requires widget semantics, adapter QA, maintenance, and upstream acceptance; Floem and GPUI product readiness remain separate gaps.
  2. De-GTK Linux shell integration. Today muda menubars need a GTK window and cannot attach to a plain winit window, tray-icon needs a parallel GTK event loop, and global-hotkey is X11-only; winit has no menu/tray API (winit#403, #3108). Integrating existing Rust portal/SNI/DBusMenu implementations into maintained winit-compatible facades would improve menus/tray/hotkeys for every winit-based framework, and would remove part of the remaining rationale for the tao fork (tao#509, wry#1014). Movement is real here: as of July 2026 Tauri has a merged gtk4 backend built on winit's 0.31 pluggable-backend architecture (winit-gtk4) and an open PR consuming it, though that architecture itself is still beta-only (stable winit remains 0.30.13). The corpus's requirements-and-traps input for this effort is distilled in the winit shell facade, specified (+ report/19-shell-facade-spec.md).
  3. Explore fontique interoperability for cosmic-text. fontdb has had no release since Oct 2024 and this audit found no announced maintainer succession; cosmic-text uses it and is a significant consumer in this sample. Slint already made this exact migration (slint#9564, 1.14) to fontique. A migration or adapter could reduce duplicate font discovery/fallback work, subject to maintainer and compatibility review.
  4. Sustainability grants for AccessKit and rcodesign. AccessKit now has one active maintainer: since April 2026 Arnold Loubriat has merged every pull request and cut every release, in his spare time, with two individual GitHub sponsors. The 2023–24 Sovereign-Tech-Fund-backed work administered via GNOME is wrapped up (GNOME STF report), and the one later grant — NLnet NGI0 Commons, iOS support, from 2025-11 — was scoped to a feature and is delivered. If you fund one thing in this stack, fund AccessKit's maintainer. rcodesign, the principal open-source Rust-native cross-platform implementation found, has concentrated maintenance and no release since Nov 2024.
  5. Bless a framework-neutral packager. Non-Tauri apps lack one equally integrated bundle + sign + runtime-update chain. cargo-packager had current commits as of June 23, 2026, but its latest release was 0.11.8 from November 2025. cargo-bundle is minimal. dist is CLI-shaped. The strongest measured candidate so far is dx bundle (officially any-Rust-project since 0.7.0). It packaged all nine non-Tauri apps 9/9, with a first-try DMG step and in-code signing/notarization automation. Cost: its own config file and build profile. Linux formats were untested here. On Windows it emitted an NSIS exe, not the documented MSI. Silent install/uninstall worked; the installed copy failed the launch check. cargo-packager's WiX route built an MSI from every buildable app (all seven installed and uninstalled cleanly; the MSI-installed dioxus-app copy failed the same launch check). cargo-bundle MSI and cargo-packager NSIS went 0/10. Improve a shared composition around dx or cargo-packager, or standardize on Velopack (official Rust crate) + rcodesign.