MewUI를 처음 공개한 지 2개월이 지났습니다. 그동안 진행했던 작업 내용들을 되짚어보고자 합니다.
(주말동안 이 글을 준비하느라 주말아침을 못올렸습니다
월요일 오후에 올리곘습니다!!
)
2025년 12월, 연말에 몰아치던 업무를 해치우고 나니 크리스마스부터 약 열흘 남짓의 휴가가 주어졌다. 개발을 업으로 삼고 있다 보니 쉬는 동안에도 손이 근질근질했고, AI 시대에 발맞춰 오픈소스 프로젝트를 하나 만들어 보자는 생각이 들었다. 그렇게 시작한 작업이 어느 정도 형태를 갖춘 뒤, 2026년 1월 6일 MewUI라는 이름으로 첫 커밋을 남겼다.
처음의 목표는 단순했다. “배포가 용이한 가벼운 UI 프레임워크”. 그런데 막상 만들다 보니, 가벼움을 유지하려면 “없는 게 미덕”이 아니라 “필수 기능을 가장 단순한 형태로 갖추는 것”이 더 중요했다.
약 2개월이 지난 현재(2026년 3월 6일), MewUI는 크로스 플랫폼, 템플릿/가상화, 프로퍼티 시스템, 테마/스타일링, 상태 전이 + 애니메이션까지 범위를 넓혔다.
이 글은 MewUI가 지난 2개월 동안 어디서 출발해 지금의 모습에 이르렀는지, 그 과정의 판단을 되짚고 앞으로의 방향까지 살펴보는 글이다.
참고: MewUI는 현재 프로토타입(Proof-of-Concept) 성격이 강해서, v1.0으로 가는 과정에서 API/아키텍처/동작이 바뀔 수 있다.
0) 출발점: 작은 유틸리티를 “가볍게 만들고 가볍게 배포”하고 싶었다
.NET으로 GUI 유틸리티를 만들다 보면, 기능에 비해 배포 부담이 과하다고 느끼는 순간이 있다. 런타임 설치를 요구하거나, 배포물이 커지고, 실행 초기에 무겁게 느껴지는 문제들이다.
.NET 개발자에게 이 문제는 더 선명하게 다가온다. 익숙하고 생산적인 도구 체인을 두고, 가능하면 “.NET으로 끝내고” 싶기 때문이다. 그런데 실제로는 10KB 남짓한 로직의 작은 GUI 기반 도구를 만들었는데도 닷넷 데스크탑 런타임 크기는 100MB를 훌쩍 넘기거나, 배포를 위해 이것저것을 안내해야 하는 상황을 쉽게 마주친다.
NativeAOT를 지원하는 Avalonia 같은 선택지도 있지만, 결과물이 3~40MB대로 줄어드는 수준이라 여전히 부담이 남는다.
MewUI는 이 지점에서 출발했다. 핵심 목표는 다음과 같다.
- NativeAOT를 전제로, 런타임 설치 없이 배포 가능한 단일 실행 파일
- 소형 도구에 필요한 최소한의 기본 UI 기능
- 가능한 작은 배포 크기, 빠른 구동, 낮은 리소스 사용(*)
- 크로스 플랫폼을 염두에 둔 구조
처음 공개하는 오픈소스 프로젝트였지만, 공개 이틀 만에 r/dotnet에서 약 30K 조회와 GitHub 100+ Stars를 기록했다.
WPF·Avalonia 위주의 .NET 데스크탑 환경에서 “배포 부담이 적은 경량 UI”에 대한 잠재 수요가 어느 정도 존재했음을 보여주는 신호라고 평가한다.
(*) 다만 프레임워크가 템플릿/스타일링/애니메이션 등으로 확장되면서 “낮은 리소스 사용”은 초기만큼 달성하기가 점점 어려워지고 있다.
1) 개발 방식: 100% 바이브 코딩
MewUI는 개념이 정리되면, 코딩 어시스턴트와 토론하며 구현을 진행하고 확장하는 방식으로 만들어졌다.
나는 구현자라기보다, 방향을 잡고 결과를 검증하는 역할에 가까웠다.
응용프로그램 개발자로서 WinForms·WPF·Avalonia 등을 다뤄온 경험과, 과거 DirectX 엔진 개발 경험을 바탕으로 “방향과 기준”을 잡고 결과를 검증했다.
- 코딩 어시스턴트와 토론하며 “어떤 기능을 어떤 개념(설계 모델)으로 구현할지” 먼저 의사결정한다
- 개념이 정해지면 코딩 어시스턴트가 구현하고 내가 승인하면 확장을 진행한다
- 구현 결과를 리뷰해서 “불합리한 점”을 다시 개념/요구사항으로 되돌린다
처음엔 $20달러짜리 GPT Plus 플랜으로 시작했지만 결국 이번달에 Claude Max 플랜으로 전환했고, 주간 사용 한도까지 지속적으로 소진하고 있는 실정이다.
2) 설계 방향: WinForms와 WPF 사이, 그리고 다른 길
처음부터 “MewUI”라는 이름이 있었던 것은 아니다. 출발점은 GPU 가속을 받는 현대적인 WinForms를 만들려는 시도였고, MewUI라는 이름을 달기 전 최초 솔루션 이름은 TinyWinForms였다.
MewUI의 초기 설계에서 가장 먼저 정리한 질문은 “WinForms처럼 갈 것인가, WPF처럼 갈 것인가, 아니면 다른 길을 낼 것인가”였다.
WinForms는 단순하고 현실적이다. 다만 “원하는 시각화”를 위해 커스텀 페인팅으로 들어가는 순간, 프레임워크가 책임지던 규칙과 일관성이 개발자 쪽으로 넘어오며 체감 난이도가 급격히 달라진다.
WPF는 강력한 구조(트리/레이아웃/리소스/스타일)를 제공하지만, 그만큼 시스템 자체가 크고 복잡해진다.
MewUI는 이 둘의 장단을 보고, 다음과 같은 방향으로 절충했다.
- WinForms처럼 “직접 그리기”로 빠지지 않도록, 최소한의 UI 트리/레이아웃 단위를 둔다
- WPF를 그대로 복제하지 않도록, 역할과 책임을 가능한 얇게 나눈다
- XAML 파이프라인 대신 코드 중심 구성으로, UI를 조합하는 흐름을 명시적으로 드러낸다
즉 “WPF의 골격을 최소 단위로만 취하고, WinForms의 커스텀 페인팅 부담을 시스템 쪽으로 끌어올린다”는 쪽에 더 가깝다.
이 선택은 이후 템플릿/가상화, 프로퍼티 시스템, 스타일/상태 전이로 이어졌다.
UI를 표현하는 방식으로는 C# Markup을 택했다. XAML이 가진 선언적 UI 구성의 이점은 가져가고 싶었지만, MewUI가 목표로 한 단순한 구성과 배포 방식에는 UI를 별도 마크업과 파이프라인으로 분리하지 않는 편이 더 가까웠다. 그래서 UI 정의를 C# 안에 두면서도 선언적으로 조합할 수 있는 C# Markup 방식을 도입했다.
예를 들면 이런 식이다.
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);
3) 크로스 플랫폼으로 확장하기: Windows에서 Linux, 그리고 macOS까지
처음에는 “가볍게 배포된다”가 목적이었지만, .NET 생태계에는 이미 Avalonia 같은 크로스 플랫폼 대안이 존재했다. Windows 전용으로만 남으면 WPF의 ‘작은 대체재’라는 입지에서 벗어나기 어려웠다.
그러다 보니 MewUI도 아래와 같은 분리 구조를 갖추게 됐다.
- 컨트롤/레이아웃
- 플랫폼 호스트와 윈도우 시스템
- 렌더링/그래픽스 백엔드
이 분리의 의미는 단순하다.
- 컨트롤/레이아웃 코드는 “윈도우 생성”이나 특정 렌더링 API를 몰라도 된다
- 플랫폼을 늘릴 때, UI 레이어를 그대로 둔 채 호스트/백엔드만 교체할 수 있다
크로스 플랫폼이 현실적인 선택지가 된 순간들
초기에는 WinForms와 WPF의 트레이드오프를 직접 확인하기 위해, GDI와 Direct2D(D2D) 백엔드를 나란히 구현해 보았다.
이때 렌더링 API를 가리는 그래픽스 추상화가 자리 잡았고, 그 위에 OpenGL 백엔드가 추가됐다.
OpenGL 백엔드가 준비되자 Linux(X11) 환경과의 연동은 플랫폼 호스트 구현만으로 간단히 이루어졌다. 다음은 macOS였다.
M1 MacBook Air를 마련해 확인해 보니 macOS에서도 OpenGL은 잘 동작했다. 다만 OpenGL이 레거시로 분류되는 환경에서 “플랫폼과 매끄럽게 통합된 선택지”라고 보기는 어려웠다. 그래서 더 일관된 통합을 위해 Metal 방향을 검토하게 됐다.
결국 Metal 백엔드를 시도했고, 통합을 일관되게 가져가기 위해 Metal 구현체가 있는 NanoVG를 풀 매니지드로 포팅하는 단계까지 진행했다.
플랫폼/윈도우 호스트와 그래픽스 백엔드를 분리해 둔 덕분에, UI 레이어 코드를 크게 수정하지 않고도 D2D → OpenGL → Metal로 실험과 통합을 반복할 수 있었다.
참고로 Windows에서는 GDI 백엔드도 계속 유지하고 있다. 전반적인 기능이 확장된 지금도 4K 환경에서 애니메이션을 포함한 모든 기능이 60Hz로 다른 백엔드와 다름없이 동작한다.
크로스 플랫폼은 “한 번에 거창한 목표”라기보다, 핵심을 분리해 두면 단계적으로 넓혀 갈 수 있는 구조에 가까웠다.
4) 시각화의 한계가 곧 UI 프레임워크의 한계다
GUI 프레임워크로서의 가치는 “컨트롤이 몇 개 있나”보다, 데이터(정보)를 의도에 맞게 어느 정도까지 시각화할 수 있나에서 갈린다.
WinForms를 쓰던 시절에도, 데이터 표현을 조금만 의도에 맞게 바꾸려 하면 결국 OwnerDraw/커스텀 페인팅 같은 “직접 그리기”를 해야 한다는 프레임워크의 한계가 드러났고, 그 지점부터 진입장벽이 급격히 올라갔다.
MewUI는 이 진입장벽을 낮추기 위해 리스트/트리/그리드 같은 데이터 표시를 “템플릿 + 가상화” 모델로 통일했고, 핵심을 아래 세 가지 축으로 정리했다.
- 데이터 어댑터: 아이템을 읽는 방식/선택 상태를 표준화
- 템플릿: “아이템을 어떻게 보여줄지”를 델리게이트 기반으로 정의
- 가상화/재사용: 보이는 범위만 실체화하고 컨테이너를 재사용
이러한 개념을 구현하기 위해 리플렉션 기반 바인딩이나 XAML 파이프라인에 의존하지 않고, 템플릿을 “보이는 형태를 만드는 단계”와 “데이터를 끼워 갱신하는 단계”로 나눠 델리게이트로 정의할 수 있도록 했다.
그 결과 TreeView 노드에 아이콘+텍스트를 얹거나 GridView의 한 셀에 체크박스/아이콘/서브텍스트를 조합하는 요구도, 컨트롤을 새로 만들기보다 템플릿 정의를 바꾸는 방식으로 처리할 수 있게 됐다.
5) 프로퍼티 시스템: 반복을 시스템으로 끌어올리다
컨트롤이 늘면서 속성도 같이 불어났고, 그만큼 보일러플레이트 코드도 같이 늘었다. 코딩 어시스턴트 덕분에 반복 구현 자체는 감당 가능했지만, 프레임워크 입장에서는 “이 반복을 계속 흩어진 코드로 둘 것인가, 시스템으로 끌어올릴 것인가”를 결정해야 했다.
특히 속성이 많아지면 매번 비슷한 문제가 따라온다.
- 기본값을 어디서 가져올지(테마 기반 포함)
- 바인딩/갱신을 어떤 규칙으로 붙일지
- 로컬 오버라이드를 해제하면 어디로 돌아갈지
- 변경이 발생했을 때 어떤 동작을 유발할지(측정/배치/그리기)
이미 검증된 레퍼런스도 있다. WPF는 DependencyProperty, Avalonia는 StyledProperty로 이 문제를 풀었다.
MewUI는 그 둘을 그대로 복제하기보다는, 경량/NativeAOT 지향이라는 목표에 맞게 절충한 결과를 MewProperty라는 형태로 정리했다.
결과적으로 프로퍼티 시스템의 도입은 “보일러플레이트를 줄였다”에서 끝나지 않았다. 이 위에 더 많은 기능을 얹을 수 있게 됐다.
기본값 / 변경 통지 / 바인딩: MewProperty를 중심으로 “값이 어디서 오고(테마 기반 기본값 포함), 값이 바뀌면 누가 알고, 어떻게 갱신할지”를 한 규칙으로 묶을 수 있게 됐다.
즉, 속성이 늘어날수록 따라오던 보일러플레이트(필드/초기화/변경 통지/바인딩 연결)를 “시스템의 기본 흐름”으로 흡수할 수 있게 됐다.
스타일 시스템: 이전에는 컨트롤별 코드에 흩어져 있던 시각 규칙을 “선언적으로 관리”할 수 있게 되었고, 그 위에서 뒤에 등장하는 상태 전이/애니메이션까지 연결할 수 있는 기반이 됐다.
그 선언을 실제로 적용하기 위한 방식으로, 스타일을 이름으로 관리/참조하거나 계층 구조(컨테이너 트리) 기준으로 적용 범위를 묶는 패턴을 함께 제공했다.
상태 전이 + 애니메이션: 마우스 오버/포커스/누름/비활성 등과 같은 “공통 상태”를 컨트롤마다 제각각 구현하지 않도록, 상태 모델과 트리거를 공통화했다.
상태가 바뀌면 배경/전경/테두리 같은 시각 슬롯은 스타일/테마 규칙으로 최종 값이 정해지고, 렌더는 그 결과를 사용하도록 정리했다.
전이 구조가 만들어지고 나니, 애니메이션 지원은 “새로 큰 걸 얹는 일”이라기보다 이미 구현해 둔 Continuous 렌더 모드 위에 올리는 확장에 가까웠다.
6) MewUI의 정체성을 지키기 위한 합의들
2개월 동안 기능은 많이 늘었지만, 매번 같은 질문을 던졌다.
- 쓸모 있는 UI 프레임워크로서의 가치를 실제로 올려주는가?
- 넣는다면 “가장 단순한 형태”로 구현할 수 있는가?
- AOT/Trim 환경에서 예측 가능하게 동작하는가?
- 크로스 플랫폼에서 일관되게 동작할 수 있는가?
이 네 가지 질문은 가벼움만 붙드는 규칙이 아니라, 필요한 개념을 어떤 형태로 받아들일지 정하는 기준이었다. 실제로 지난 2개월 동안 템플릿이나 속성 시스템처럼 결코 가볍지 않은 기반도 계속 들어갔지만, 그런 개념도 가능한 한 더 얇고 단순한 형태로 최적화해 넣으려 했다.
이 기준이 필요했던 이유도 분명했다. MewUI에서 가벼움은 단순한 선택이 아니라 정체성에 가까웠다. 이미 검증된 SkiaSharp을 끌어오면 안정성과 일관성은 따라오지만, 그만큼 배포 비용과 의존성 구조도 함께 받아들여야 한다. 무작정 WPF나 Avalonia를 따라가는 것은 MewUI에게는 포지션을 흐리게 만들 뿐이다. 결국 중요한 것은 “덜 넣는 것”이 아니라, 수고를 동반하더라도 가치 있는 것을 어떤 형태와 비용으로 받아들일지 계속 판단하는 일이었다.
7) 다음 단계: v1.0을 향한 가다듬기와 확장
지금부터는 “기능을 더하는 일”보다 “가다듬기”의 시간이 더 중요해 보인다.
오픈소스 포팅으로 개념 검증: “직접 써보며” 개선하기
오픈소스 유틸리티 프로젝트들을 MewUI로 다시 작성해보며, 실제 응용프로그램을 만드는 과정에서 드러나는 불편한 지점과 부족한 요소를 조기에 식별하고 있다. 큰 틀의 포팅은 코딩 어시스턴트가 먼저 진행하되, 그 위에서 개발 경험과 구조를 현실 기준으로 계속 정비하는 방식이다.
개발 경험을 위한 도구
실사용 검증은 런타임 기능만의 문제가 아니다. 코드 중심 UI를 실제로 얼마나 빠르게 만들고 수정할 수 있는지도 중요하다.
아직 성숙한 단계는 아니지만, Hot Reload와 VisualTree Inspector를 시작으로 개발 경험을 위한 도구들도 이미 들어가기 시작했다.
여기에 디자인 타임 Preview처럼 화면을 더 빠르게 확인하는 도구나, Fluent API 스타일 코드를 더 읽기 좋고 다루기 쉽게 만드는 포맷터 같은 확장도 고려하고 있다. 이런 도구들은 런타임 기능과는 다른 축에서, MewUI 위에서 실제로 만들고 수정하는 경험을 다듬고 프레임워크가 실제로 쓰이고 퍼지는 데에도 영향을 준다고 생각한다.
확장 컨트롤 생태계: 코어는 얇게, 확장은 분리 제공
많은 UI 프레임워크가 “컨트롤 카탈로그 확장”에서 무거워진다.
하지만 현실적으로 앱 개발에는 코어만으로 부족한 순간이 온다.
코어는 얇게 유지하되, Docking, Chart, DataGrid와 같은 확장 컨트롤은 별도 확장 패키지처럼 분리 제공하는 방향을 고려하고 있다.
MewUI용 WebView2 패키지는 현재 Windows 전용으로 개발해 둔 상태다. 코어가 아닌 확장 기능들은 반드시 모든 플랫폼에 대한 일관성만을 고집하기보다, 가능한 것부터 먼저 만들고 넓혀 가는 편이 MewUI가 쓰일 수 있는 곳을 확장하는 현실적인 경로라고 본다.
한편, AvalonEdit처럼 규모가 큰 컨트롤을 MewUI로 포팅해 보는 것도 확장을 위한 한 전략이다. 기존 WPF·Avalonia 오픈소스 자산을 MewUI 위로 어느 수준까지 옮길 수 있는지 보기 위한 실험이다.
코딩 어시스턴트를 위한 스킬 문서
MewUI의 C# 코드 마크업은 코딩 어시스턴트가 다루기에 더 효율적인 형식이다. WinForms는 속성 설정과 이벤트 연결 코드가 길어져 토큰 비용이 빠르게 커지고, XAML도 그보다는 낫지만 UI가 커질수록 결국 길어진다. MewUI는 같은 UI를 더 짧은 코드로 표현할 수 있다.
실제로 오픈소스 포팅에서 있어서도 MewUI를 개발하면서 맥락을 충분히 파악하고 있던 코딩 에이전트는 MewUI를 잘 이해하고 활용한 코드를 만들어 내고 있었다. 그래서 주요 코딩 어시스턴트에 바로 적용할 수 있는 스킬 문서를 체계적으로 작성하고, 공개 가능한 형태로 함께 배포하는 쪽까지 이어 가려 한다.
마무리
지난 2개월은 “가볍게 시작해서 커졌다”기보다, 가볍게 남기 위해 무엇을 넣고 무엇을 덜어낼지 계속 고민하는 과정에서 MewUI의 정체성을 더욱 또렷하게 확립해 온 시간에 가까웠다.
이 글이 처음 MewUI를 접한 사람이나 새로운 UI 프레임워크를 써보고 싶은 사람에게는 왜 이런 방향의 프레임워크가 나왔는지를 보여 주고, UI 프레임워크를 직접 만들어 보고 싶은 사람에게는 그 뒤에 놓인 고민과 판단을 들여다보는 글이 되면 좋겠다.
MewUI의 존재 이유는 결국 누군가의 필요에 의해서 실제로 쓰이며 가치를 증명하는 과정 속에서 더 분명해질 것이다.













