Repository navigation
Add opt-in WinUI 3 (Fluent) Windows target: --target windows-winui #4680
Description
Activity
- addedenhancementNew capability or improvementNew capability or improvementhelp wantedExtra attention is neededExtra attention is needed
on Jun 6, 2026 I am looking forward to this one.
Reacted by Ralph Küpper@proggeramlug What I had in mind was that Perry should target WinUI via Windows Reactor. Read this merged pull request from the windows-rs repo: microsoft/windows-rs#4479
Here is the operative section which states that a WinUI app built this way is a small, single executable. This is not in conflict with Perry's single executable model. And it shows that the apps performance runs circles around a C# counterpart, whether using C# with JIT or AOT. And no runtime framework to deploy.
Windows Reactor is a UI library for Rust developers targeting WinUI 3 to deliver native, efficient Windows experiences. It brings a React-like component model to native Windows desktop apps:
Declarative UI, no macros — build UIs as pure functions of state using a builder DSL and tuple-based children
Function components — typed props, context propagation, and error boundaries
Hooks — use_state, use_reducer, use_effect, use_context, use_memo, use_callback, use_resource, and more
55+ widgets — Button, TextBlock, NavigationView, Grid, and many more, plus virtualized lists (ListView, GridView, FlipView) with templated row rendering
Async — use_resource and use_mutation for background data loading
Theming — runtime light/dark switching with ThemeRef brush bindings
Accessibility — built-in automation property modifiers, keyboard accelerators, and tooltips
Small footprint — single ~3 MB binary, no runtime framework to deployProgress + findings: bootstrap proven, bindgen wall hit, Windows Reactor evaluated
Status update on the incremental WinUI 3 build-out (
--target windows-winui).Landed / in flight
- Step 1 (target plumbing + scaffold): done (the
#4681series). The crate re-exports the Win32 backend and shares its Fluent DWM chrome (Mica, rounded corners, theme-aware title bar), so--target windows-winuibuilds/links/runs today through Win32. - Step 2 (Windows App SDK bootstrap): merged in feat(ui-windows-winui): real Windows App SDK bootstrap probe (#4680 step 2) #4896.
winui::bootstrap::initialize()resolves the bootstrapper at runtime viaLoadLibraryW+MddBootstrapInitialize2(no link dependency → preserves the single self-contained.exe; absent runtime → falls back to Win32). - Step 3 (render-backend dispatch seam): PR feat(ui-windows-winui): render-backend dispatch seam + startup probe (#4680 step 3) #4897.
winui::backend::active()(Fluent iff bootstrap Ready, else Win32) + a.CRT$XCUstartup probe that runs only inwindows-winuibinaries + an HRESULT diagnostic underPERRY_WINUI_DIAG.
Bootstrap is now proven end-to-end
On a host with the WinAppSDK 1.6 framework installed, the bootstrap initially failed with
HRESULT 0x80670016— the framework package was registered but the DDLM (Dynamic Dependency Lifetime Manager) was not. After registering the DDLM/Main/Singleton runtime packages,initialize()flipsRuntimeMissing → Readyand the seam reportsfluent. So both arms of theMddBootstrapInitialize2FFI are validated against a real runtime. (The diagnostic added in #4897 is what pinpointed the missing-DDLM cause.)The bindgen wall: stock
windows-bindgencan't generateMicrosoft.UI.XamlTried generating
Microsoft.UI.XamlRust projections from the WinAppSDK winmd:windows-bindgen0.58 (our currentwindowspin): panicsnot implemented: Microsoft.UI.Dispatching.DispatcherQueue— every XAML control pullsDependencyObject → DispatcherQueue.windows-bindgen0.66 (latest on crates.io): gets further, then panicstype not found: Microsoft.UI.Composition.IAnimationObject—UIElementimplements it, but Composition metadata isn't in the WinAppSDKlib/uap10.0/*.winmdset.
Conclusion: raw projection generation at our toolchain is a toolchain dead-end, not just an effort problem.
Windows Reactor evaluation (windows-rs PR #4479)
windows-reactor(Kenny Kerr / the windows-rs team, merged to master, MIT/Apache-2.0) is a React-style declarative WinUI 3 framework for Rust — single ~3 MB exe, no framework to deploy, WinAppSDK 2.x.It solves exactly the two hardest blockers:
- The bindgen closure problem is solved and the output is committed:
crates/libs/reactor/src/bindings.rsis a ~941 KB checked-inMicrosoft.UI.Xamlprojection, produced with windows-rs's newer method-level-filtering / vtable-demotion bindgen. Applicationsubclassing (app_shim.rs), bootstrap, and single-exe packaging (build.rscopiesBootstrap.dllandresources.prinext to the exe) are all done.
But its public API is a React DSL (
use_state, function components, declarative element trees), which does not fit Perry's pipeline — Perry's compiler emits imperative C-ABI calls from LLVM and can't author Rust component/hook functions. Under the DSL, though, reactor has an imperative reconciler backend (core/backend.rs— enum-keyed widget kinds + property setters) plusbindings.rs+app_shim.rs, which are the pieces Perry needs.Recommended approach — reuse the plumbing, not the DSL
- New
perry-ui-winui3-syscrate that vendors (MIT/Apache, attribution preserved) reactor'sMicrosoft.UI.Xamlbindings.rs+ the Application/bootstrap/packaging shim, on the latestwindows-core— decoupled fromperry-ui-windows'swindows0.58 (Cargo compiles multiplewindowsversions fine). - Build Perry's imperative
perry_ui_*WinUI FFI on top, mapping the perry-ui widget set → XAML controls imperatively, behind thewinui::backend::active()seam from feat(ui-windows-winui): render-backend dispatch seam + startup probe (#4680 step 3) #4897. - Move the bootstrap default to WinAppSDK 2.x and reuse reactor's
build.rspattern to fetch winmd + copyBootstrap.dll/resources.pri.
Costs/risks: a newer
windows-coremajor in the tree (isolated to the new crate); WinAppSDK 2.x runtime; maintaining a vendored ~941 KBbindings.rs(reactor isversion = "0.0.0", i.e. not yet on crates.io, so vendor or git-pin); reactor is days-old/experimental → expect churn.This removes the bindgen + Application-hosting dead-ends and is the most credible path to real Fluent rendering. Win32 (
--target windows) stays the default and unaffected throughout.Reacted by Paul O- Step 1 (target plumbing + scaffold): done (the
Thanks, @proggeramlug. I agree with you, that the best approach is to reuse the plumbing, but not the DSL.
- added 3 commits that reference this issue
on Jun 15, 2026 - addedrfcProposal that needs design agreement before implementationProposal that needs design agreement before implementationtriagedMaintainer reviewed; type, scope, and next step are clearMaintainer reviewed; type, scope, and next step are clearand removedenhancementNew capability or improvementNew capability or improvement
on Jul 26, 2026 Closed by #8722, landed on
mainvia #8733 (squash0749bd338).That PR was landed through a batch wrapper PR rather than merged directly, so GitHub's close keyword never fired at merge time. Verified before closing:
crates/perry-ui-windows-winui/and the vendored Reactor snapshot atthird_party/windows-winui/are both onmain.Note the backend's runtime behaviour is unverified — it cannot be built or run from macOS, so someone on Windows should confirm it works before it is relied on. See the follow-up note on #8722 about stale callback pointers captured into Reactor element-tree closures.
Reacted by Paul O
Summary
Add an opt-in WinUI 3 / Fluent rendering backend for Windows, selectable via
--target windows-winui, alongside the existing Win32/GDI backend (crates/perry-ui-windows).Motivation from discussion #3486: the current Win32/GDI output looks dated (boxy, flat, no animation, Win7-era controls). WinUI 3 brings Fluent Design — rounded corners, Mica/Acrylic materials, smooth animations, modern typography, crisp auto-DPI — and is the closest Windows analog to our iOS/Android look-and-feel.
Scope / decisions
.exemodel. Keep Win32 as the default target; expose WinUI via--target windows-winui. Mirrors how we ship multiple Apple targets.microsoft/windows-rs(already a dep,windows = "0.58") is the WinRT projection crate, not a UI lib. WinUI from Rust = driving WinAppSDK + XAML through the WinRT projections (imperative XAML object trees in Rust).Work breakdown (rough)
perry-ui-windows-winui(or a feature on the existing crate) wiring WinAppSDK + Microsoft.UI.Xaml projections.--target windows-winuithrough the compile/link pipeline; bootstrapper/runtime acquisition (Microsoft.WindowsAppRuntime.Bootstrap).apply_styledispatcher for the WinUI backend (parity with macOS/GTK4/Win32).Acceptance
--target windows-winuiproduces a runnable app rendering the ToDo sample with Fluent chrome (Mica, rounded corners, animated controls).Tracks discussion #3486. Companion near-term Win32 polish: see the linked Win32 Fluent-polish issue.