Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

96 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

miklabs/ui

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


๐Ÿš€ Quick Example

Rust

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()
}

C++

#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;
}

C

#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;
}

Python

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())

๐ŸŽจ Styling with Utility Classes

miklabs/ui uses a Tailwind-like utility system for layout, spacing, colors, and typography.

Examples:

  • flex-1, items-center, justify-between
  • p-4, mt-2, gap-3
  • rounded-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"

๐Ÿงญ Crate Layout

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)

What lives in mkui-core

  • 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.

What does not live in mkui-core

  • DOM construction, web-sys / wasm-bindgen types โ†’ mkui-web.
  • Terminal styles, crossterm/ratatui types โ†’ mkui-console.
  • WGPU pipelines, scene transforms, winit shell โ†’ mkui-wgpu.
  • Text layout / rasterization โ†’ mkui-text.

Adding a new backend

A new backend is any crate that:

  1. Depends on mkui-core (and only mkui-core from the contract side).
  2. Consumes mkui_core::components::Component trees via Any downcasting.
  3. Maps theme::Theme and layout::Layout values to its native styling.
  4. 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.


๐Ÿ“ Architecture

The load-bearing architectural decisions behind the workspace shape above are documented as ADRs (Architecture Decision Records) under docs/architecture/:

New contributors and reviewers should start with the ADR index for the format conventions and one-sentence summaries.

Threading model

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 / ActionRegistry access โ€” construction, mutation, event dispatch, and the mkui-wgpu render 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. MkuiError is Send + Sync on native targets so results can flow across spawned tasks, but the WASM JsValue variant is !Send + !Sync because 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.


๐ŸŒ Target Platforms & Languages

Platforms

  • Desktop: Windows, macOS, Linux โœ…
  • Console: Terminal UIs with crossterm โœ…
  • Web: via WebAssembly โœ…
  • Native WGPU: HUD-style 2D scene pipeline + winit ApplicationHandler shell shipped in mkui-wgpu. Bitmap-text fallback is the current default; richer text rendering is on the roadmap, tracked in project issues.
  • Mobile: iOS, iPadOS, Android ๐Ÿšง (planned)

Language Support

  • Rust: Native support with full ergonomic API โœ…
  • C: FFI bindings โ€” handle-based nested API on the mkui-runtime substrate; 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)

๐Ÿ“Š Comparison

Qt

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();

miklabs/ui

#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.


๐ŸŽฎ Try the Showcases

Experience miklabs/ui across different platforms and languages:

Rust Showcases

Console Showcase - Terminal UI with crossterm

cargo run --bin console-showcase
# Navigate: โ†‘โ†“โ†โ†’  |  Interact: Space/Enter  |  Quit: q/Esc

Web Showcase - WebAssembly in browser

cd examples/web-showcase
wasm-pack build --target web
# Serve the generated files with any static server

Headless Showcase - Pure logic without rendering

cargo run --bin headless-showcase

C/C++ Examples

C Example - Manual memory management

cd examples/c-example
make run

C++ Example - Modern RAII with exceptions

cd examples/cpp-example  
make run

Native Window Example

Native 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

Python Example

โ„น mkui-py builds on Python 3.9โ€“3.14. The PyO3 0.29.0 bump (#5) cleared the old Python 3.13 ceiling, so the full workspace โ€” including mkui-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

Key Features Demonstrated

  • โœ… 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

๐Ÿงช Local Verification

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 -- --check

The 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" --locked

Backend-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 smoke

Native WGPU smoke (opens a winit window, paints a single quad via the HUD Scene API):

cargo run -p native-window --release

The web backend is exercised by examples/web-showcase via wasm-pack; the bridge-crate cargo test runs cover the contract + dispatch surface only.


๐Ÿ”ฎ Current Capabilities & Direction

โœ… Current capabilities (v0.8.0)

  • Shared contract โ€” mkui-core component 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 via web-sys / WebAssembly.
  • Native WGPU pipeline โ€” mkui-wgpu ships a HUD-style 2D scene API (quads, panels, hit regions, theme-aware variant resolvers) plus a winit ApplicationHandler shell so a native window is one call away.
  • Text system โ€” mkui-text defines a TextSystem trait 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) and Dot (status variants + halo + animation modifiers) in mkui-wgpu.
  • CI โ€” fmt, clippy -D warnings, test, and release build fully gated.

๐Ÿšง Active direction

  • 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-rsx placeholder 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-text beyond the bitmap prototype is on the roadmap. The specific approach is internal; the trait surface is the public contract.
  • FFI hardening โ€” mkui-c is gated in CI (build + clippy + test) with // SAFETY: annotations on every unsafe block since the Sprint 4 handle-based rewrite; mkui-py builds + tests on Python 3.9โ€“3.14 since the PyO3 0.29.0 bump (#5).

๐Ÿ”ฎ Longer-horizon

  • 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.


๐Ÿ“œ Releases

See CHANGELOG.md for release notes.


๐Ÿ’ฌ Community


โš–๏ธ License

MIT or Apache 2.0 (permissive, no GPL headaches).

About

A modern, cross-platform UI toolkit for Rust, C++ and Python. Inspired by shadcn/ui, React Native and NativeWind.

Topics

Resources

Contributing

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages