A C++ desktop UI framework with Vue-like simplicity.
Pure C++20. Real frames. No Electron. No JS bridge.
License: MIT C++20 Platform: Windows CMake Build: MSVC | MinGW | Clang Status: pre-release Version: v1.0.0
Website · 简体中文 · Getting Started · API Reference · Architecture · Porting
jtUI showcase
jtUI is what you get when you ask: what if a native desktop UI toolkit shipped with the developer ergonomics of Vue.js, but without paying the Electron tax?
- Pure C++20 — runtime ~150K lines, no Node, no JS engine, no webview. Your app is a single
.exe. - Real native frames — Direct2D 1.1 rendering on Windows, with backdrop blur, true gaussian box shadow, bezier/polygon primitives, HiDPI-aware geometry, GPU-decoded video frames.
- Vue-inspired developer flow — declarative widget trees,
Signal<T>/Property<T>reactivity, full-tree rebuild as the default state model. Mental model fits in one afternoon. - i18n + dual theme out of the box — one-line
Theme::set(Dark/Light)+i18n::set_locale(En/Zh)switch the entire app. No CSS-in-JS gymnastics. - Media-native widgets —
VideoPlayer(MF + Direct2D),AudioPlayer(WASAPI shared mode),WaveformView,Timeline,LevelMeter— built into the framework, not bolted on. - 40+ widgets ready across
widgets/{basic,common,media}— Buttons, Inputs, Tabs, Dialog, Popover, Tooltip, Gauges, Avatars, SidebarNav, AboutCard, and many more.
#include "jtui/jtui.hpp" int run_app() { jtui::Application app; jtui::WindowOptions options{}; options.title = "Hello jtUI"; options.frameless = true; options.size = {800.0F, 600.0F}; jtui::Window& window = app.create_window(options); jtui::theme::Theme::set(jtui::theme::ThemeMode::Dark); auto root = std::make_unique<jtui::Panel>(); root->set_role(jtui::PanelRole::Base); root->set_frame({0.0F, 0.0F, 800.0F, 600.0F}); auto title = std::make_unique<jtui::Text>("Hello, jtUI"); title->set_font_size(32.0F); title->set_bold(true); title->set_color(jtui::Color::from_hex("#FB923C")); title->set_alignment(jtui::TextAlignment::Center); title->set_frame({0.0F, 240.0F, 800.0F, 50.0F}); root->append_child(std::move(title)); auto cta = std::make_unique<jtui::Button>("Get Started"); cta->set_shape(jtui::ButtonShape::Pill); cta->set_colors( jtui::Color::from_hex("#FB923C"), jtui::Color::from_hex("#FDA45F"), jtui::Color::from_hex("#EA8224"), jtui::Color::from_hex("#1A0F05")); cta->set_frame({340.0F, 320.0F, 120.0F, 44.0F}); cta->on_clicked().connect([]() { // your callback here }); root->append_child(std::move(cta)); window.set_content(std::move(root)); return app.run(); } #if defined(_WIN32) int WINAPI wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) { return run_app(); } #else int main() { return run_app(); } #endif
Build with CMake + Ninja (full instructions below). On Windows you get a hardware-accelerated native window. On Linux the runtime stubs out (no Direct2D), useful for cross-compile and CI.
For a deeper walkthrough see docs/getting-started.md.
jtui::i18n::register_entries({ {"hero.title", "Build Native. Ship Fast.", "原生构建,极速出货。"}, }); auto title = std::make_unique<jtui::Text>(jtui::i18n::tr("hero.title")); title->set_color(jtui::theme::colors().text_strong);
Switching the whole app between Dark/Light or English/Chinese is one line — jtui::theme::Theme::set(...) / jtui::i18n::set_locale(...). Combine with a full-tree window.set_content(build_root()) rebuild and you are done.
auto glass_nav = std::make_unique<jtui::Panel>(); glass_nav->set_frame({0, 0, kWidth, kNavBarH}); glass_nav->set_background_color({0, 0, 0, 0}); // must be transparent glass_nav->set_backdrop_blur(64.0F, brand.glass_tint); root.append_child(std::move(glass_nav));
True hardware-accelerated frosted-glass nav bars — the same effect macOS Safari ships, implemented via CopyFromRenderTarget → CLSID_D2D1GaussianBlur → DrawImage + tint overlay. Degrades cleanly on systems without D2D 1.1.
card->set_corner_radius(jtui::radius_lg); card->set_shadow(jtui::theme::elevation().level_2); // CSS-like box-shadow
5 elevation levels (level_0..4) mapped to true gaussian shadows via CLSID_D2D1Shadow. No more "draw a darker rectangle behind the card" hacks.
auto video = std::make_unique<jtui::VideoPlayer>(); video->set_source("intro.mp4"); video->play(); video->set_frame({40, 80, 720, 405}); root.append_child(std::move(video));
VideoPlayer decodes via Windows Media Foundation, GPU textures from D2D bitmap atlas. AudioPlayer plays via WASAPI shared mode with sub-50ms latency. WaveformView + Timeline + LevelMeter round out a media-native widget set.
class ThumbnailArt : public hui::Widget { public: void paint(hui::PaintContext& ctx) const override { const auto f = frame(); ctx.fill_gradient_rect(f, top_color, bottom_color, /*radius=*/10.0F); ctx.fill_polygon({/* mountain silhouette */}, mountain_color); ctx.draw_bezier(p0, c1, c2, p3, leaf_color, /*thickness=*/4.0F); ctx.fill_ellipse({/* sun */}, sun_color); } [[nodiscard]] bool clips_self() const noexcept override { return true; } };
PaintContext gives you fill_rect / stroke_rect / fill_rounded_rect / fill_ellipse / line / draw_bezier / fill_polygon / fill_gradient_rect / fill_shadow / fill_backdrop_blur / draw_text / draw_texture / push_clip / pop_clip. See examples/jtui_cinema/thumbnail_art.hpp for a full geometry-based illustration widget.
class CountUpText : public hui::Widget { bool tick(float delta) override { if (progress_ >= 1.0F) return false; progress_ += delta / duration_; mark_dirty(hui::DirtyFlags::Paint); return progress_ < 1.0F; } void paint(hui::PaintContext& ctx) const override { const float eased = ease_out_cubic(progress_); ctx.draw_text(frame(), format(target_ * eased), color_, ...); } };
Built-in 60 fps tick loop (SetTimer on Windows). Return true from tick to keep animating, false to stop. See examples/jtui_invest/animated_widgets.hpp for count-up / line-chart / bar-chart animations, and examples/jtui_cinema/carousel_animator.hpp for ease-in-out carousel slide.
Three layers, each in its own subtree:
runtime/ Platform-neutral core
foundation/ Color · i18n · log · codicon lookup
object/ Node / Element / Widget · DirtyFlags · z-order
property/ Signal<T> · Property<T> · RealtimeSource<T>
theme/ SemanticColor tokens · elevation · spacing · typography
layout/ FlexBox · two-pass measure/arrange
event/ EventDispatcher · capture-target-bubble
render/ PaintContext · DrawCommand IR
media/ IVideoDecoder · IAudioDecoder · TextureHandle
app/ Application · Window · WindowFrame · TitleBar
platform/
win32/ Direct2D 1.1 renderer · MF decoder · WASAPI · codicon font loader
widgets/
basic/ Panel · Text · CodiconIcon · ScrollView · ListView · FlexBox
common/ Button · TextInput · Switch · Checkbox · Tabs · Dialog · Popover ·
Tooltip · Slider · Toolbar · Dropdown · SearchInput · ProgressBar ·
RadialGauge · SemiGauge · Gauge · Chip · Badge · Card · Avatar ·
FolderCard · MetricCard · SidebarNav · AboutCard
media/ VideoPlayer · AudioPlayer · WaveformView · Timeline · LevelMeter
api/ jtui:: namespace facade (umbrella header)
ffi/c_api/ C ABI (for FFI from other languages)
examples/ 10 brand demos (gallery + 9 product hero pages)
docs/ Architecture · API reference · Getting started
Detailed architecture in docs/architecture.md. Porting notes to non-Win32 in platform/PORTING.md.
cmake -S . -B build -G Ninja -DCMAKE_CXX_COMPILER=clang++ cmake --build build .\build\examples\gallery\gallery.exe
cmake -S . -B build-mingw -G Ninja \ -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/mingw-w64-x86_64.cmake cmake --build build-mingw # Copy build-mingw/examples/gallery/gallery.exe to a Windows machine to run.
cmake -S . -B build -G Ninja
cmake --build build
ctest --test-dir build --output-on-failureApplication::run() returns 0 immediately on Linux — there is no GTK / X11 backend yet. Use Linux only for cross-compile + unit tests today.
| Option | Default | Effect |
|---|---|---|
HUI_BUILD_EXAMPLES |
ON | Build the 10 brand examples |
HUI_BUILD_TESTS |
ON | Build tests/hui_unit_tests |
HUI_WARNINGS_AS_ERRORS |
OFF | Promote warnings to errors |
Each example is a complete brand hero page assembled from brand_tokens.hpp + i18n_catalog.hpp + main.cpp, exercising a different slice of the framework. Every example ships with Dark/Light theme + English/Chinese i18n toggles (round icon buttons in the title bar) and an About modal.
Component library: all widgets in tabbed sections + VSCode palette/codicons
gallery (dark) gallery (light) jtui_hero
Brand hero page, double-line title with inline
TextRun accent highlightsjtui_hero (dark) jtui_hero (light)
Video carousel: 5 geometric thumbnails + ease-in-out slide + real
VideoPlayerjtui_cinema (dark) jtui_cinema (light) jtui_studio
Media studio:
VideoPlayer + AudioPlayer + WaveformView cross-rebuild persistencejtui_studio (dark) jtui_studio (light)
Financial landing: backdrop blur nav + count-up animation + ScrollView
jtui_invest (dark) jtui_invest (light) jtui_atlas
KPI sparklines + chart cards + grid background
jtui_atlas (dark) jtui_atlas (light)
Code editor mock-up with hot-reload status card
jtui_live (dark) jtui_live (light) jtui_pro
Enterprise SSO landing: bezier stream lines + trust badges
jtui_pro (dark) jtui_pro (light)
Live chart background with custom
clips_self() widgetjtui_pulse (dark) jtui_pulse (light) folders_app
File manager: sidebar nav + folder grid + search filter
folders_app (dark) folders_app (light)
jtUI is on its way to a 1.0 release. Today's status:
- Stable: rendering pipeline (D2D 1.1), widget catalog, theme + i18n, animation tick, full-tree rebuild as state model, build (Windows native + MinGW cross)
- In progress: GPU texture registry, ScrollView horizontal mode, AnimationState abstraction
- Roadmap: macOS via SDL3 + Skia backend, Linux native via GTK4 or SDL3
Released under the MIT License. Commercial use is welcome — fork freely, build products, no royalty needed.
- jtai team, led by Zeng Nenghun&Tang XianSheng (https://jtai.cc) (
jwhna1@gmail.com&tang@lhht.cc). The project started March 2025 with the explicit goal of bringing Vue-like ergonomics to native C++ desktop development. - Icons:
@vscode/codicons(MIT) — 649 named glyphs embedded into the binary, loaded viaIDWriteFactory5custom font collection.
The project is in pre-release. We are not yet accepting external PRs while the API surface is stabilizing for 1.0. Issue reports and design discussions are welcome — please open an issue with your use case before sending code. See CONTRIBUTING.md and CODE_OF_CONDUCT.md.
.exe to ship.