DEV Community

Cover image for Shipping a GUI Without the .NET Runtime: 2 Months with MewUI, a Cross-Platform UI Framework
Youngjae Song
Youngjae Song

Posted on

Shipping a GUI Without the .NET Runtime: 2 Months with MewUI, a Cross-Platform UI Framework

In December 2025, after wrapping up a year-end rush at work, I ended up with about ten days off starting around Christmas. Since software development is my day job, I still had that itch to build something even during a break, and I found myself wanting to make an open-source project in step with the AI era. After that work had taken on a recognizable shape, I made the first commit under the name MewUI on January 6, 2026.

The initial goal was simple: a "lightweight UI framework that is easy to ship."
But once I actually started building it, I realized that staying lightweight was less about "having less" and more about "providing the essential features in the simplest possible form."

As of roughly two months later (March 6, 2026), MewUI had already expanded to include cross-platform support, templates/virtualization, a property system, themes/styling, and state transitions + animation.

This article looks back at where MewUI started, how it reached its current shape over those two months, and how that process shaped the decisions behind it as well as the direction ahead.


MewUI Built-in Control Showcase

Note: MewUI is still strongly in a prototype (proof-of-concept) stage, so its API, architecture, and behavior may still change on the road to v1.0.


0) Starting Point: I Wanted Small Utilities to Be "Light to Build and Light to Ship"

When you build GUI utilities in .NET, there are moments when the shipping cost feels excessive relative to the functionality. Requiring a runtime installation, shipping bulky outputs, and feeling heavy at startup are all familiar problems.

For .NET developers, this feels even more immediate. We already have a familiar and productive toolchain, and if possible we want to stay "all in .NET." But in practice, even a tiny GUI tool with maybe 10KB of actual logic can end up pulling in a .NET Desktop Runtime well over 100MB, or forcing you to explain extra setup steps just to run it.


Build output of a WPF self-contained single-file app

There are options like Avalonia that support NativeAOT, but even then you still end up with outputs in the tens of megabytes, which is not a trivial cost.


Build output of a Native-AOT Avalonia app

MewUI started from that point. The core goals were:

  • A single executable built around NativeAOT and deployable without a runtime installation
  • The minimum set of basic UI features needed for small tools
  • As small a deployment size as possible, fast startup, and low resource usage (*)
  • A structure that keeps cross-platform support in view

Even though this was my first open-source project, it reached roughly 30K views on r/dotnet and 100+ GitHub Stars within two days of being published.
I took that as a sign that there is at least some latent demand for "lightweight UI with lower deployment cost" in a .NET desktop ecosystem still centered around WPF and Avalonia.


Build output of Native-AOT Mew UI app

(*) That said, as the framework expanded to include templates, styling, animation, and more, "low resource usage" has become harder and harder to preserve at the same level as in the beginning.


1) Development Method: 100% Vibe Coding

Once the concept was clear, MewUI was built by discussing implementation with coding assistants and then expanding from there.
My role was less "the one who writes every line" and more the one who sets direction and validates the result.

Drawing on my experience as an application developer working with WinForms, WPF, and Avalonia, along with past experience developing DirectX engines, I set the direction and the criteria, then reviewed the outcome.

  • First discuss with a coding assistant and decide "what feature should exist" and "what concept or design model should implement it"
  • Once the concept is set, let the coding assistant implement it, then expand if the result is acceptable
  • Review the implementation and feed anything unreasonable back into the concept and requirements

I started with the GPT Plus plan, but eventually switched to Claude Max this month, and I have been consistently burning through the weekly usage limit.


2) Design Direction: Between WinForms and WPF, and Another Path

It did not begin with the name "MewUI." The starting point was an attempt to build a modern, GPU-accelerated form of WinForms, and before it was called MewUI, the very first solution was named TinyWinForms.

The first question I had to settle in MewUI's early design was: "Should this go in the direction of WinForms, in the direction of WPF, or toward something else?"

WinForms is simple and pragmatic. But once you start doing custom painting in order to get the visualization you want, the rules and consistency that used to be the framework's responsibility shift back onto the developer, and the perceived difficulty rises sharply.
WPF provides a powerful structure around trees, layout, resources, and styles, but the system itself becomes correspondingly large and complex.


Lightweight MewUI Visual Tree Structure

Looking at the strengths and weaknesses of both, MewUI took the following compromise:

  • Keep a minimal UI tree and layout unit so it does not fall all the way into WinForms-style "draw everything yourself"
  • Keep roles and responsibilities as thin as possible so it does not simply replicate WPF
  • Use a code-centered composition model instead of an XAML pipeline so the way UI is assembled stays explicit

In other words, it is closer to "taking only the minimum structural skeleton from WPF while pulling WinForms' custom-painting burden up into the framework."
That choice later led into templates/virtualization, the property system, and styling/state transitions.

For UI representation itself, I adopted C# Markup. I wanted to keep the declarative strengths of XAML, but MewUI's target of a simpler structure and a simpler deployment model pointed away from splitting UI definition into a separate markup language and pipeline. C# Markup was the compromise: keep the UI definition in C#, while still composing it declaratively.

For example, it looks like this:

var window = new Window()
    .Title("Hello MewUI")
    .Resizable(520, 360)
    .Padding(12)
    .Content(
        new StackPanel()
            .Spacing(8)
            .Children(
                new Label()
                    .Text("Hello, Aprillz.MewUI")
                    .FontSize(18)
                    .Bold(),
                new Button()
                    .Content("Quit")
                    .OnClick(() => Application.Quit())
            )
    );

Application.Run(window);
Enter fullscreen mode Exit fullscreen mode

3) Expanding Cross-Platform: From Windows to Linux, and then macOS

At first, the goal was simply "ship light." But the .NET ecosystem already had cross-platform alternatives like Avalonia. If MewUI remained Windows-only, it would have a hard time escaping the position of being just a "smaller substitute" for WPF.

That led MewUI to develop a split like this:

  • Controls/layout
  • Platform host and windowing system
  • Rendering/graphics backend

The reason for that split is straightforward.

  • Control and layout code should not need to know about window creation or a specific rendering API
  • When adding a platform, it should be possible to replace the host/backend while leaving the UI layer intact

When Cross-Platform Became a Practical Option


MewUI running on Windows 11 with Direct2D Backend

Early on, I implemented GDI and Direct2D (D2D) backends side by side in order to directly feel the trade-offs between WinForms and WPF.
That work established a graphics abstraction over the rendering API, and from there the path toward adding an OpenGL backend followed.


MewUI running on Linux with OpenGL Backend

Once the OpenGL backend was ready, integration with Linux (X11) became much easier. The next target was macOS.
After getting hold of an M1 MacBook Air and testing it, I found that OpenGL worked there as well. Still, in an environment where OpenGL is classified as legacy, it was hard to consider it a clean platform-integrated answer. That led me to consider a Metal direction for a more consistent integration story.


MewUI running on macOS with Metal Backend

In the end I tried a Metal backend, and to keep that integration coherent I even went as far as porting NanoVG, which has a Metal implementation, into fully managed code.
Because the platform/window host and graphics backend had already been separated, I could keep experimenting and integrating from D2D to OpenGL to Metal without making large disruptive changes to the UI layer.

For reference, the GDI backend is still maintained on Windows as well. Even with the feature set expanded, it still runs at 60Hz in 4K environments, including animation, without falling behind the other backends.

Cross-platform support was never a single huge all-at-once goal. It was closer to something that becomes incrementally reachable once the core pieces are separated.


4) The Limits of Visualization Are the Limits of a UI Framework

The value of a GUI framework is determined less by "how many controls it has" than by how far it can visualize data in the shape you actually need.

Even back when I used WinForms, the framework's limitations became obvious the moment I wanted to tailor the presentation of data: eventually I had to fall back to OwnerDraw or some other form of custom painting. From that point on, the barrier to entry rose sharply.

To lower that barrier, MewUI unified list/tree/grid-style data presentation around a "template + virtualization" model, organized around three axes:

  • Data adapter: standardize how items are read and how selection state is handled
  • Template: define how an item should be shown in a delegate-based way
  • Virtualization/reuse: materialize only the visible range and reuse containers

To implement that without relying on reflection-based binding or an XAML pipeline, templates were defined through delegates split into two stages: one for creating the visible shape, and one for attaching and updating the data.
As a result, requirements like placing icon + text on a TreeView node or composing a GridView cell out of a checkbox, icon, and subtext can be handled by changing the template definition rather than introducing entirely new controls.


Delegate-based Data Templating Example in MewUI

5) The Property System: Turning Repetition into Infrastructure

As the number of controls grew, the number of properties grew with them, and so did the amount of boilerplate. Coding assistants made the repetitive implementation itself manageable, but from the framework's point of view I still had to decide whether this repetition should remain scattered across the codebase or be pulled up into the system itself.

Once properties start multiplying, the same questions come up over and over:

  • Where should a default value come from, including theme-based defaults?
  • How should binding and updates be attached?
  • If a local override is cleared, where should the value fall back to?
  • When a value changes, what should that trigger: measure, layout, draw?

There were already proven references. WPF solves this with DependencyProperty, and Avalonia solves it with StyledProperty.
Rather than copying either one directly, MewUI distilled a lighter compromise aligned with its lightweight, NativeAOT-oriented goals into a form called MewProperty.

In practice, introducing the property system did not stop at "we reduced boilerplate." It also opened the way for natural extensions above it.

Defaults / change notification / binding: with MewProperty at the center, it became possible to unify where a value comes from, who reacts when it changes, and how it propagates, including theme-based defaults.
In other words, the boilerplate that used to multiply with every new property — backing fields, initialization, change notification, binding glue — could be absorbed into the framework's default mechanics.

Style system: visual rules that had previously been scattered across per-control code became something that could be managed declaratively, and that in turn created the base needed for the state transitions and animation that came later.
To apply those declarations in practice, MewUI also supports patterns such as managing and referencing styles by name, or grouping scope by hierarchy through the container tree.

State transitions + animation: common states such as hover, focus, pressed, and disabled were generalized so that each control would not have to implement them independently.
When a state changes, style and theme rules determine the final values for visual slots such as background, foreground, and border, and the renderer consumes those results.
Once that transition structure existed, animation was no longer a massive new layer to bolt on. It became a natural extension built on top of the already implemented Continuous render mode.


Newly implemented Animation System

6) Rules for Preserving MewUI's Identity

Over those two months, the feature set grew a lot, but I kept returning to the same questions.

  1. Does this actually raise the value of MewUI as a usable UI framework?
  2. If it belongs, can it be implemented in the simplest possible form?
  3. Is its behavior predictable in AOT/Trim environments?
  4. Can it behave consistently across platforms?

These four questions were not rules for clinging only to lightness. They were the criteria for deciding what kinds of concepts MewUI would accept, and in what form. In practice, foundations that were far from lightweight in themselves — such as templates and the property system — still entered the framework over those two months, but even those concepts were pushed toward the thinnest and simplest form I could manage.

The reason these criteria mattered was also clear. In MewUI, lightness was not just a preference; it was close to an identity. Pulling in something already proven like SkiaSharp would also bring stability and consistency, but it would bring its deployment cost and dependency structure with it. Simply following WPF or Avalonia would only make MewUI's position less distinct. What mattered was not "adding less," but continuing to judge what was worth accepting, and in what form and at what cost, even if doing so required more work.


7) The Next Step: Polishing and Expanding Toward v1.0

From here, the time for "polishing" feels more important than the time for simply "adding features."

Concept Validation Through Open-Source Porting: Improving by Actually Using It

By rewriting open-source utility projects in MewUI, I am trying to identify missing pieces and rough edges early through the actual process of building applications. The coding assistant handles the broad outline of the porting first, and then I refine the resulting developer experience and structure against real usage.


SharpKeys (by randyrants) Ported to MewUI


nfd2nfc (by elgar328) Ported to MewUI

Tools for Improving the Development Experience

Real-world validation is not only about runtime features. It also depends on how quickly a code-first UI can actually be built and revised.

These tools are not mature yet, but they have already started to appear, beginning with Hot Reload and the VisualTree Inspector.


MewUI Live Visual Tree and Inspector

Design-time Preview for faster visual feedback, or formatter-style tooling that makes a Fluent API easier to read and work with, could naturally follow from here. In the end, tools like these matter on a different axis from runtime features: they refine the experience of actually building and changing applications on top of MewUI, and I believe they are also important to whether the framework ends up being used and adopted in practice.

Extension Control Ecosystem: Keep the Core Thin, Ship the Extensions Separately

Many UI frameworks become heavy through expansion of the control catalog.
But in practice, there are moments when real application development needs more than the core alone can provide.

The direction I am considering is to keep the core thin while providing controls such as Docking, Chart, and DataGrid as separate extension packages.
The MewUI WebView2 package, for example, is currently implemented as a Windows-only component. For features that belong outside the core, it seems more realistic to let them grow from what is already feasible instead of insisting that every feature preserve the same cross-platform surface from day one.


WebView2 Control Package for MewUI

Skill Documents for Agents

MewUI's C# code markup is a more efficient format for coding assistants to work with. In WinForms, token cost grows quickly because property-setting and event-wiring code tends to become long. XAML is better in that respect, but as UI grows it also becomes long. MewUI can express the same UI in shorter code.

In actual open-source porting work, an agent that already had enough context from building MewUI was producing code that showed a real understanding of how MewUI should be used. That is why I want to systematically write skill documents that can be applied directly to major coding assistants, and take that all the way to a form that can be shared publicly as well.


Closing

The last two months were less "I started small and it got bigger" than they were a period of repeatedly deciding what to add and what to leave out in order to keep MewUI light, and through that process making its identity clearer.

I hope this article helps people encountering MewUI for the first time, or people curious about trying a new UI framework, understand why it took this shape. And for anyone who wants to build a UI framework themselves, I hope it also offers a look into the decisions and trade-offs behind it.

MewUI's reason to exist will only become clearer through the process of being used to satisfy real needs and proving its value in practice.

Top comments (0)