iu_ui

While cross-platform GUI libraries in Rust are fantastic, michiu takes the opposite direction...

iu_ui is the last 5 letters of michiu_ui, and it looks like a face


Example

A simple counter example showcasing both reactive UI declaration and explicit event loop control:

[dependencies] michiu = "0.2.2" pollster = "1.0.1" 
use michiu::{accessibility::a11y, prelude::*}; fn main() -> Result<(), Box<dyn std::error::Error>> { let _ = MichiuWindow::init_dpi_awareness(); let com = MichiuComContext::new_ro_single()?; let builder = MichiuWindowBuilder::new() .with_title("Sample App") .with_visible(false) .with_com_context(&com) .with_no_redirection_bitmap(true) .with_inner_size(LogicalSize::new(600.0, 500.0)) .into_unvalidated(); let window = MichiuWindow::build(builder.try_into()?)?; let scale_factor = window.scale_factor() as f32; let handle = window.handle().assume_valid(); let rect = handle.client_rect(); let renderer = pollster::block_on(MichiuRenderer::new( handle.hwnd(), rect.cast(), scale_factor, ))?; let (mut app, mut pump) = MichiuAppBuilder::new(window) .with_accessibility_support(true) .with_auto_resolve_cursor(true) .build_with_ui(renderer, move || { let (count, set_count) = create_signal(0u32); flex( ii().size_full() .justify_center() .items_center() .bg_color(oklch(0.209, 0.0, 0.0)), ) .tag::<a11y::AMain>() .child( flex( ii().r(4.0) .size((200.0, 40.0)) .justify_center() .bg_color(oklch(0.3132, 0.0, 0.0)) .cursor_pointer() .pressed(ii().transform_scale(0.98, 0.98)) .hovered(ii().bg_color(oklch(0.4017, 0.0, 0.0))) .focusable_self_both() .focused_visible( ii().outline_solid(2.0) .outline_offset(2.0) .outline_color(oklch(0.5433, 0.1913, 266.76)), ), ) .tag::<a11y::AButton>() .on_click(move || set_count.set(count.get() + 1)) .label( move || format!("Count: {}", count.get()), ii().font_size(18.0).text_color(oklch(0.9491, 0.0, 0.0)), ), ) })?; app.set_visible(true); while pump.wait_event(|event, _, raw| { let resp = app.standard_handle_window_event(&event, &raw); if resp.needs_redraw { app.redraw_requested(); } if resp.needs_update_window { app.update_window(); } if resp.consumed { return; } if let MichiuAnyEvent::Window { event, .. } = event { match event { MichiuEvent::CloseRequested => { app.destroy(); } MichiuEvent::Destroyed => { app.quit(); } MichiuEvent::RedrawRequested => { app.standard_redraw(); } _ => {} } } })? {} Ok(()) } 

Architectures

Composition
  • Foreground Layer (wgpu / DX12): Renders UI elements. Areas designated for external visuals are physically punched out using SDF masks and subtractive blending.
  • Background Layer (DirectComposition): Hosts raw IDCompositionVisual2 (ExternalVisual) alongside opaque backgrounds.

This setup allows for zero-copy visual "sandwiches" (e.g., WebView2 ⇄ Native UI ⇄ WebView2) composed at the OS level.

(Note: The WebView2 integration is currently an experimental proof-of-concept for the composition pipeline).

Widget-less

There are no fixed widget structs like Button or TextInput. Every node is just an Entity(KeyData).

  • Nodes gain capabilities (.text(), .modify(), .on_click(), etc.) dynamically by registering their IDs into Structure of Arrays (SoA) tables. A "component" is merely an intersection of multiple SoA tables on an Entity.
  • Styles are defined as standalone Modifiers (ii()) and shared via CoW (Arc::make_mut).
  • Internal layout and rendering rely on flat 1D arrays:
    • FlatDfsSequence: Linear DFS traversal for 2-pass Taffy layout calculations.
    • SortedEntitiesVec: Shared between forward-pass GPU batching and reverse-pass (rev()) hit-testing.

Because of this DOD foundation, borrow-checker conflicts are virtually non-existent, allowing developers to mix paradigms depending on the context:

  • Reactive: Automatic dependency tracking with create_signal and .provide().
  • Direct imperative mutation: Moving Entity directly into closures.
  • Contextual: Using cx.current() via _with handlers.
  • Tag queries: Attaching marker types (.tag::<MyTag>()). Marker tags like a11y::AButton (A11yInferenceTag) handle both semantic queries and Windows UI Automation (AccessKit) mapping at once.
Win32 API
  • No Inversion of Control: You explicitly drive pump.wait_event(...) and can directly hook into raw Win32 messages (HWND, UINT, WPARAM, LPARAM).
  • Style Guards (michiu_guard): Prevents common Win32 UB and invalid states at type/validation levels (e.g., mutually exclusive flags like WS_CHILD vs WS_POPUP, OLE STA requirements, DirectComposition synchronization rules).
  • Raw external inputs are wrapped in Unvalidated<T> (with escape hatches like assume_valid for prototyping).
External

Instead of bundling heavy media decoders:

  • ExternalVisual: OS-level zero-copy composition via IDCompositionVisual2.
  • ExternalTexture: Supplies external buffers (video frames, decoders) directly to wgpu via resolve_view.
  • ExternalData: Reactive, file-watched asset loading (e.g., custom style sheets).

Workspace

Published Crates:

  • michiu: The facade crate (you only need this for most use cases)
  • michiu_ui: Core DOD UI engine and wgpu / DirectComposition renderer
  • michiu_window: Win32 windowing, event pump, and message handling
  • michiu_guard: Compile-time and runtime validation layer for Win32/COM invariants

Workspace Examples & Catalogs:

  • sample_collection/: Interactive testbed showcasing composition pipelines, transforms, and events.
  • a11y_catalog/: Catalog of copy-paste accessible UI patterns and high-contrast theme tests.

What started as a simple IME indicator tool somehow escalated into building an entire DirectComposition-based GUI framework from scratch.

Since this is still very much an experimental project, please feel free to poke around and share your thoughts! Impressions on the API ergonomics, simple questions, or bug reports are all super welcome—you don't have to be a graphics guru.

(If you happen to spot any obvious Win32/COM blunders, do let me know—just please be gentle... :pleading_face:)

1 post - 1 participant

Read full topic