One View subclass, many renderers. There are two families of backend:
- Native-fidelity — map the view tree to the OS's real controls, with the platform's own layout, fonts, animations, and accessibility.
- Self-drawing — paint every pixel ourselves for a pixel-identical look everywhere. The engine that does this is rasterizer-agnostic (see the renderer seam), so the same layout, hit-testing, gestures and paint pass drive SkiaSharp, a from-scratch WebGPU renderer, a game engine's texture, or — on Godot — the engine's own 2D draw commands.
And two routes to get there (see Architecture → the two backend routes):
- Native shim for the compiler-plugin toolkits (SwiftUI, Compose) — a thin Swift/Kotlin layer.
- Pure C# for the bindable ones (GTK, WinUI, WPF, Web) and the self-drawing one (Skia) — no native code.
| Platform | Renders as | Route | Status | Doc |
|---|---|---|---|---|
| iOS | SwiftUI | Swift shim (xcframework, P/Invoke) | ✅ Verified on simulator | Apple |
| macOS | SwiftUI (AppKit-hosted) | Same Swift shim | ✅ Verified on desktop | Apple |
| tvOS | SwiftUI | Same Swift shim (#if os(tvOS) fallbacks) |
✅ Verified on Apple TV sim | Apple |
| Android | Jetpack Compose | Kotlin shim (.aar, JNI) |
✅ Verified on emulator | Android |
| Linux | GTK4 | Pure C# (Gir.Core, no shim) | ✅ Verified on desktop | Linux/GTK |
| Linux | Self-drawn on a native Wayland surface | Pure C# (libwayland/xkbcommon P/Invoke, no shim) | 🧩 Scaffolded — builds clean; never run against a compositor (protocol tables unit-tested) | Linux/Wayland |
| Windows | WinUI 3 | Pure C# (no shim) | 🧩 Scaffolded — never compiled, no tests | Windows |
| Windows | WPF | Pure C# (no shim) | 🧩 Scaffolded — compiles clean (macOS cross-target + windows-latest CI), never run |
WPF |
| Windows | Self-drawn on a WinForms / WPF surface | Pure C# (Skia engine, no shim) | 🧩 Host compiles clean (same CI job), never run; the engine it hosts is CI-verified | WinForms |
| Web | HTML/DOM | Pure C# (Blazor WASM, no shim) | ✅ Verified in Chrome | Web |
| Any (Skia) | Self-drawn canvas | Pure C# (SkiaSharp) | ✅ Verified (macOS window + PNG) | Skia |
| Any (WebGPU) | Self-drawn, on the GPU | Pure C# (wgpu-native, no Skia) | ✅ Verified on Metal via headless pixel readback (8 CI tests); Vulkan/D3D12 unexercised | WebGPU |
| MonoGame | Self-drawn into a Texture2D |
Pure C# (Skia engine + game component) | ✅ Verified — real window and back buffer on macOS/DesktopGL | MonoGame |
| Godot | Godot's own 2D draw commands (no Skia) | Pure C# (Control node) |
✅ Verified on Godot 4.7.2, macOS/Metal — both the native and the Skia-texture route | Godot |
| Unity | Self-drawn into a Texture2D |
Pure C# (Skia engine + Unity host) | 🧩 Host compiles against UnityEngine reference assemblies; never run | Unity |
| Any (terminal) | Characters in a TTY | Pure C# (XenoAtom.Terminal.UI) | ✅ Verified headlessly on macOS (35 CI tests); not yet driven by hand in a live terminal | Terminal/TUI |
What "Verified" means, and what CI actually covers. ✅ Verified means the backend was run and inspected on the stated target — it is not a claim of test coverage. The automated suite (
tests/SwiftDotNet.Tests, 364 green) exercises Core, Skia and the terminal backend only. There are no GTK, Web, WinUI, WPF, WinForms, SwiftUI, Compose, MonoGame or Godot rendering tests, so per-backend behaviour in the tables throughout these docs is verified by hand, not by CI. The two game-engine backends that are marked ✅ were verified by driving their sample heads non-interactively —--shot/--tap, described on each page — and reading the captured frame. Prefer adding a Core, Skia or TUI test for new behaviour — those are the ones that run on macOS.
- Want the real platform look & accessibility? Use the native-fidelity backend for that OS.
- Want a uniform look on every platform, or a target the native backends can't reach (dependency-free
desktop, embedded/framebuffer Linux)? Use Skia. Trade-off: no native accessibility, and
WebView/Mapcan't be painted onto a canvas — they need a real OS control floated over it, which today only the MAUI host does (see the platform-view seam). - Already have a .NET MAUI app? You don't need a backend — host a SwiftDotNet tree in a MAUI page with
SwiftDotNetSkiaView, and put real MAUI controls back inside it withMauiView. There is deliberately no MAUI backend (nothing here translates nodes intoLabel/Button/Entry): it would reach no platform the Apple, Compose and WinUI backends don't already reach with higher fidelity. See MAUI Interop. - Want the self-drawn look with no native imaging dependency, or GPU-resident rendering? Use WebGPU. Trade-off: PNG-only images, no complex text shaping, and group opacity is approximated.
- Rendering inside a game engine? Three hosts, and the choice is mostly which engine you are already in: MonoGame (verified; MonoGame ships no UI of its own, so this fills a real gap), Godot (verified; the default route draws with Godot's renderer, so there is no native dependency and it exports wherever Godot does), and Unity (compiles, never run). All three support a transparent HUD over a live scene.
- On Windows specifically? Three answers, and they are genuinely different products.
WinUI 3 is the modern Fluent one (but has never compiled). WPF is real
Win32 controls with UI Automation accessibility, and is the one that actually builds today.
WinForms gets the Skia canvas and only the Skia canvas — a native WinForms backend
would have had to no-op half the modifier vocabulary, so it was deliberately not built. The same Skia
canvas is available on WPF too (
SwiftDotNet.Skia.Wpf) when you want the uniform look instead of the native one. - No display server at all — SSH, a container, CI? Use Terminal/TUI. Trade-off: one glyph
size (so
.Fontbecomes emphasis, not scale), no transforms or animation, and images become character art unless the terminal speaks Sixel/Kitty.
Everything in Core — DSL, State<T>, Node, TreeDiffer, patch protocol,
SwiftApp — is shared verbatim. A few pure-math helpers are shared into the backends too, so they can't
drift apart: GridEngine (track parsing + grid cell placement)
and AbsoluteLayoutBounds (proportional-bounds resolution) are
called by every C# backend and ported line-for-line into the Swift and Kotlin shims. A backend implements exactly one interface,
IBridge, plus a host. The same
SharedUI.ContentView renders on all of them.