A modern, cross-platform UI toolkit for Rust, C, C++ & Python. Inspired by shadcn/ui, React Native, and NativeWind.
โจ Declarative โข ๐จ Tailwind-style utilities โข ๐ผ Themeable โข ๐ Cross-platform โข ๐ง Multi-language โข โ๏ธ MIT/Apache
use showcase_common::create_showcase_ui;
fn main() -> std::io::Result<()> {
// Create and run a cross-platform UI
mkui::run!(create_showcase_ui, console)
}Or build it step by step:
use mkui::prelude::*;
fn main() -> Result<(), MkuiError> {
let app = Mkui::new()?
.child(
View::new()
.class("flex-1 items-center justify-center")
.child(Text::new("Hello World!").class("text-xl font-bold"))
.child(
Button::new("Press me")
.variant(ButtonVariant::Primary)
.on_press(|| println!("Button pressed!"))
)
);
app.run()
}#include "mkui.hpp"
int main() {
try {
auto app = mkui::createApp();
auto root = app->root();
auto container = app->viewChild(root, "flex-1 items-center justify-center");
app->textChild(container, "Hello World!",
mkui::TextVariant::Heading1, "text-xl font-bold");
app->buttonChild(container, "Press me", mkui::ButtonVariant::Primary);
app->runConsole();
} catch (const mkui::MkuiException& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}#include "mkui_c.h"
int main() {
MkuiApp* app = mkui_app_new();
if (!app) return 1;
MkuiNodeId root = mkui_app_root(app);
MkuiNodeId container = mkui_app_view_child(app, root,
"flex-1 items-center justify-center");
mkui_app_text_child(app, container, "Hello World!",
MKUI_TEXT_HEADING_1, "text-xl font-bold");
mkui_app_button_child(app, container, "Press me", MKUI_BUTTON_PRIMARY, "",
(MkuiActionId){UINT32_MAX, UINT32_MAX});
MkuiResult result = mkui_app_run_console(app);
mkui_app_free(app);
return result.code == MKUI_SUCCESS ? 0 : 1;
}import mkui_py
def main():
try:
app = mkui_py.App()
root = app.root()
container = app.view_child(root, "flex-1 items-center justify-center")
app.text_child(container, "Hello World!",
mkui_py.TEXT_HEADING_1, "text-xl font-bold")
app.button_child(container, "Press me", mkui_py.BUTTON_PRIMARY)
app.run_console()
except Exception as e:
print(f"Error: {e}")
return 1
return 0
if __name__ == "__main__":
exit(main())miklabs/ui uses a Tailwind-like utility system for layout, spacing, colors, and typography.
Examples:
flex-1,items-center,justify-betweenp-4,mt-2,gap-3rounded-lg,bg-surface,text-primary
Variants work like shadcnโs cva:
button:
base: "inline-flex items-center justify-center rounded-lg transition"
variants:
intent:
primary: "bg-primary text-primary-foreground hover:bg-primary/80"
outline: "border border-input hover:bg-muted"
size:
sm: "h-8 px-3 text-sm"
md: "h-10 px-4 text-base"
lg: "h-12 px-6 text-lg"
default:
intent: "primary"
size: "md"mkui is organized around a single contract crate that every backend consumes. Backend-specific code never leaks into the contract.
| Crate | Responsibility | Maturity |
|---|---|---|
mkui-core |
Shared contract: component model, headless logic, theme / layout / input / style / error. Zero backend deps. | Stable |
mkui-text |
Text-system trait + from-scratch bitmap prototype. No external text-stack deps (no cosmic-text / swash / freetype / fontdue). | Experimental (bitmap prototype, trait stable) |
mkui-wgpu |
WGPU scene primitives + declarative builders + winit ApplicationHandler shell. Backs the HUD-style 2D pipeline. |
Experimental (shipping; declarative AppTree bridge per ADR 0006) |
mkui-web |
Web/WASM backend. Translates the shared component tree into DOM via web-sys. |
Stable |
mkui-console |
Terminal backend. Translates the shared component tree into crossterm output. |
Stable |
mkui |
Bridge crate. Re-exports the backend chosen by Cargo features and presents a single Mkui entry point. |
Stable |
mkui-runtime |
Portable application-tree substrate (AppTree, NodeId, ActionId, class parser, JSON snapshots). Every binding builds into this same arena. |
Stable (Sprint 4) |
mkui-vector2d |
Backend-neutral 2D path model + deterministic Slug glyph curve/band encoder (font-units, y-up). No GPU deps. | Stable (Sprint 7) |
mkui-vector2d-wgpu |
WGPU adapter for mkui-vector2d's Slug encoder โ packs blobs into GPU buffers + single-horizontal-ray WGSL coverage pipeline. Behind slug feature (default off in mkui-wgpu). |
Stable (Sprint 7) |
mkui-c |
C/C++ FFI bindings โ handle-based nested API over mkui-runtime's AppTree. CI builds + clippy gates active. |
Stable (Sprint 4) |
mkui-py |
Python bindings via PyO3 0.29.0. Handle-based nested API. Builds + tests on Python 3.9โ3.14. | Stable (Sprint 4) |
componentsโ the renderable tree:Component,View,Text,Button.headlessโ pure-logic components (state, events, a11y traits) shared by every backend.themeโTheme,ThemeMode,ColorTheme(no platform colors).layoutโLayout,FlexDirection,Justify,Align,Edges.inputโInputEvent,Key,PointerButton(backend-neutral events).style,event,state,errorโ supporting contracts.
- DOM construction,
web-sys/wasm-bindgentypes โmkui-web. - Terminal styles, crossterm/ratatui types โ
mkui-console. - WGPU pipelines, scene transforms, winit shell โ
mkui-wgpu. - Text layout / rasterization โ
mkui-text.
A new backend is any crate that:
- Depends on
mkui-core(and onlymkui-corefrom the contract side). - Consumes
mkui_core::components::Componenttrees viaAnydowncasting. - Maps
theme::Themeandlayout::Layoutvalues to its native styling. - Normalizes its native events into
mkui_core::input::InputEvent.
If a contract change is needed (e.g. a new component type), it goes in
mkui-core so every backend keeps consuming the same model.
The load-bearing architectural decisions behind the workspace shape above
are documented as ADRs (Architecture Decision Records) under
docs/architecture/:
- ADR 0001 โ
mkui-coreas the contract crate - ADR 0002 โ
mkui-textowns the stack (no external Rust text crates) - ADR 0003 โ
mkui-webregistry-based extension - ADR 0004 โ
mkui-wgpu2D HUD pipeline port - ADR 0005 โ
mkui-runtimeas the portable AppTree substrate - ADR 0006 โ
mkui-wgpudeclarative bridge overmkui-runtime::AppTree - ADR 0007 โ GPU resource ownership for wgpu text and
mkui-vector2d
New contributors and reviewers should start with the ADR index for the format conventions and one-sentence summaries.
mkui is single-threaded by design. The component tree (AppTree) and the
ActionRegistry must be built, mutated, and driven from a single thread โ
they are intentionally !Send + !Sync. Actions are stored as
Rc<RefCell<โฆ>>, so the tree and its callbacks never cross a thread boundary.
This is a deliberate invariant, not an oversight: adding Send + Sync bounds
prematurely would force every binding (Rust, C, Python) to thread those bounds
through closures that never actually cross threads.
Where the boundary sits:
- The host may be multithreaded. Your application can run any number of threads for I/O, compute, or networking.
- mkui's tree must be driven from one thread. All
AppTree/ActionRegistryaccess โ construction, mutation, event dispatch, and themkui-wgpurender walk โ has to happen on that one owning thread (typically the main / UI thread). Marshal data from worker threads back to the UI thread before touching the tree. - Errors stay local too.
MkuiErrorisSend + Syncon native targets so results can flow across spawned tasks, but the WASMJsValuevariant is!Send + !Syncbecause errors there are local to the single-threaded WASM context.
A future host (Python, C, โฆ) wanting to drive UI from a non-main thread should
treat this as a hard constraint today. The design rationale lives in
ADR 0005 (the
ActionRegistry single-threaded decision) and
ADR 0006 (the declarative
bridge over AppTree). Cross-thread support is explicitly out of scope until a
real multithreaded runtime exists.
- Desktop: Windows, macOS, Linux โ
- Console: Terminal UIs with crossterm โ
- Web: via WebAssembly โ
- Native WGPU: HUD-style 2D scene pipeline +
winitApplicationHandlershell shipped inmkui-wgpu. Bitmap-text fallback is the current default; richer text rendering is on the roadmap, tracked in project issues. - Mobile: iOS, iPadOS, Android ๐ง (planned)
- Rust: Native support with full ergonomic API โ
- C: FFI bindings โ handle-based nested API on the
mkui-runtimesubstrate; CI build + clippy gates active โ - C++: Modern C++17 wrapper (RAII + exceptions) over the C handle API โ
- Python: PyO3 0.29.0 bindings โ handle-based API on the same substrate; builds + tests on Python 3.9โ3.14 โ
- JavaScript/TypeScript: WASM bindings ๐ง (planned)
QApplication app(argc, argv);
QWidget window;
QPushButton *button = new QPushButton("Click me", &window);
QObject::connect(button, &QPushButton::clicked, []() { qDebug() << "Clicked!"; });
window.show();
return app.exec();#include "mkui.hpp"
int main() {
try {
auto app = mkui::createApp();
auto on_click = app->registerCallback([]() { std::cout << "Clicked!\n"; });
app->buttonChild(app->root(), "Click me",
mkui::ButtonVariant::Primary, "px-4 py-2 rounded-lg",
on_click);
app->runConsole();
} catch (const mkui::MkuiException& e) {
std::cerr << e.what() << "\n";
}
}โ Fewer lines, declarative, and styled with utilities.
Experience miklabs/ui across different platforms and languages:
Console Showcase - Terminal UI with crossterm
cargo run --bin console-showcase
# Navigate: โโโโ | Interact: Space/Enter | Quit: q/EscWeb Showcase - WebAssembly in browser
cd examples/web-showcase
wasm-pack build --target web
# Serve the generated files with any static serverHeadless Showcase - Pure logic without rendering
cargo run --bin headless-showcaseC Example - Manual memory management
cd examples/c-example
make runC++ Example - Modern RAII with exceptions
cd examples/cpp-example
make runNative Window โ minimal mkui-wgpu smoke: opens a winit window via the
ApplicationHandler shell and paints a clear color + a single quad through
the HUD Scene API. Any visual regression in the HUD pipeline shows up here.
cargo run -p native-window --releaseโน
mkui-pybuilds on Python 3.9โ3.14. The PyO3 0.29.0 bump (#5) cleared the old Python 3.13 ceiling, so the full workspace โ includingmkui-pyโ tests on a current interpreter.
Python Example - PyO3 bindings with exception handling
cd examples/python-example
# Build the Python bindings first
cd ../../crates/mkui-py
uv venv && source .venv/bin/activate # any Python 3.9โ3.14
maturin develop --release
# Run the Python example
cd ../../examples/python-example
python main.py- โ Unified API: Same UI code works across console, web, and native
- โ Error Handling: Proper error propagation with platform-specific types
- โ Memory Safety: Automatic cleanup in Rust/C++, manual in C
- โ Styling: Tailwind-like utility classes work everywhere
- โ Components: Views, Text, Buttons with multiple variants
Before opening a PR, run the workspace checks. The default mkui-py test
path does not link libpython (PyO3's extension-module feature
provides the symbols at load time), so the everyday loop runs the full
workspace โ mkui-py included โ with no Python toolchain required.
mkui-c is likewise in-matrix: the Sprint 4 handle-based rewrite added
// SAFETY: annotations on every unsafe block and mkui-c re-entered
the CI matrix (build + clippy + test) as of v0.5.0.
# Everyday loop โ full workspace, no Python toolchain required
cargo build --workspace
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo fmt --all -- --checkThe Python bindings additionally carry two interpreter-linked tests
(byte-identical snapshot parity + a live import mkui_py smoke). They are
feature-gated behind parity-test (which enables pyo3/auto-initialize
and links a real libpython), so they stay out of the default path. Run
them against any Python 3.9โ3.14 interpreter with:
# Python binding verification (links libpython via PYO3_PYTHON)
PYO3_PYTHON=$(which python3) cargo test -p mkui-py \
--no-default-features --features "parity-test,console" --lockedBackend-specific feature checks for the bridge crate:
cargo test -p mkui # default: no backend, verifies init-error path
cargo test -p mkui --features console # console backend smokeNative WGPU smoke (opens a winit window, paints a single quad via the HUD
Scene API):
cargo run -p native-window --releaseThe web backend is exercised by examples/web-showcase via wasm-pack;
the bridge-crate cargo test runs cover the contract + dispatch surface only.
- Shared contract โ
mkui-corecomponent model (View/Text/Button), headless state/variant logic, theme / layout / input contracts. - Console backend โ
mkui-console, crossterm-driven terminal UI. - Web backend โ
mkui-web, DOM construction viaweb-sys/ WebAssembly. - Native WGPU pipeline โ
mkui-wgpuships a HUD-style 2D scene API (quads, panels, hit regions, theme-aware variant resolvers) plus awinitApplicationHandlershell so a native window is one call away. - Text system โ
mkui-textdefines aTextSystemtrait with a from-scratch bitmap implementation (BitmapTextSystem). No external text-stack dependencies. The bitmap path is the current default and stays as the permanent debug-fallback / visual-regression oracle. - First shadcn-aligned atoms โ
Badge(6 variants) andDot(status variants + halo + animation modifiers) inmkui-wgpu. - CI โ
fmt,clippy -D warnings,test, and release build fully gated.
- Component surface โ expand the shadcn-aligned atom set on top of
mkui-wgpu. - Layout engine โ flexbox-style layout integration for the shared contract.
- RSX macro โ JSX-like authoring is a target (#76).
The previous
mkui-rsxplaceholder crate was deleted in Sprint 6 (#74); a future implementation would land as a new crate when the design is scoped. - Native text rendering โ extending
mkui-textbeyond the bitmap prototype is on the roadmap. The specific approach is internal; the trait surface is the public contract. - FFI hardening โ
mkui-cis gated in CI (build + clippy + test) with// SAFETY:annotations on everyunsafeblock since the Sprint 4 handle-based rewrite;mkui-pybuilds + tests on Python 3.9โ3.14 since the PyO3 0.29.0 bump (#5).
- Mobile (iOS / Android) backends.
- JavaScript / TypeScript bindings.
- Accessibility, theming polish, hot reload.
mkui is an open UI framework that drives its own internal work first; public roadmap detail tracks shipped capabilities rather than aspirational plans. Sprint-by-sprint direction beyond what's in this list lives in project issues, not the README.
See CHANGELOG.md for release notes.
- Website: miklabs.com/ui (coming soon)
- GitHub Discussions: github.com/miklabs/ui/discussions
- Discord: coming soon
MIT or Apache 2.0 (permissive, no GPL headaches).