Version: 0.0.1 (very early stage)
License: MIT OR Apache-2.0 (dual)
Target Platform: Windows-first, architecture supports future Linux/macOS
Last Updated: January 8, 2026
After thorough research (see Appendix A: WinUI 3 Research), Luma will use Win32 (user32 + GDI) as the Windows backend, not WinUI 3 or Windows App SDK.
Rationale:
- ✅ Win32 fully supported in
windowscrate with complete Rust bindings - ✅ In-box on every Windows version (minimal memory footprint)
- ✅ Battle-tested, stable, well-documented API
- ❌ WinUI 3/XAML explicitly removed from
windowscrate (June 2022) - ❌ Microsoft states: "XAML only truly supports MSBuild+C#"
- ❌
windows-appcrate experimental, undocumented behavior, unsustainable
Dark Mode Strategy:
- Phase 1-3: Dark title bars via
DwmSetWindowAttribute(optional), light window contents (acceptable limitation) - Phase 4+: Custom control rendering for full dark mode support
- Future: DirectComposition-based rendering layer (as suggested by Microsoft)
See full research findings in Appendix A.
- Project Overview
- Architecture
- Dependencies
- Project Structure
- Core Design Principles
- Layout System
- Widget System
- Serialization Format
- Implementation Phases
- API Examples
- Testing Strategy
- Future Enhancements
Luma (Latin for "light") is a native GUI framework for Rust that provides:
- Native UI: Uses OS-native UI components (Win32 API on Windows)
- Safe Abstractions: Wraps unsafe platform APIs in safe Rust interfaces
- Layout-Based: Grid/box layout system (similar to Swing, wxWidgets)
- Visual Editor: GUI editor application built with Luma itself (dogfooding)
- JSON Definitions: Define UIs in JSON, load at runtime
- Type-Safe Builders: All widgets use builder pattern with Result-based validation
- Cross-Platform Ready: Architecture supports Windows, macOS, Linux
- ✓ Automatic layout calculation (recalculates on window resize by default)
- ✓ Nested layout support (containers can hold layouts)
- ✓ Builder pattern for all widgets
- ✓ Comprehensive error handling with
thiserror - ✓ Multi-select support for ListBox widget
- ✓ Future: Visual GUI editor
- ✓ Future: Code generation from visual designs
luma/
├── crates/
│ ├── luma-core/ # Platform-agnostic core + layout engine
│ ├── luma-windows/ # Win32 backend implementation
│ ├── luma-serde/ # JSON serialization for UI definitions
│ ├── luma-gui/ # Main public API (platform selection)
│ └── luma-editor/ # Visual GUI editor (future)
└── examples/ # Example applications
- luma-core: Platform-agnostic types, traits, and layout engine
- luma-windows: Win32-specific implementations
- luma-serde: Serialization/deserialization of UI definitions
- luma-gui: Public API that selects platform backend at compile time
- luma-editor: Visual editor application (future)
Uses cfg-if crate for clean platform selection:
cfg_if! {
if #[cfg(windows)] {
use luma_windows::*;
} else if #[cfg(target_os = "macos")] {
compile_error!("macOS support not yet implemented");
} else {
compile_error!("Unsupported platform");
}
}All approved and locked in:
[workspace.dependencies]
# Error handling & serialization
thiserror = "1.0" # Error types with derive macros
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" # JSON for UI definitions
# Utilities
bitflags = "2.4" # Widget/layout flags and styles
cfg-if = "1.0" # Clean platform conditional compilation
tracing = "0.1" # Logging/debugging (dev only)
once_cell = "1.19" # Lazy static initialization
# Internal workspace crates
luma-core = { path = "crates/luma-core", version = "0.0.1" }
luma-windows = { path = "crates/luma-windows", version = "0.0.1" }
luma-serde = { path = "crates/luma-serde", version = "0.0.1" }
luma-gui = { path = "crates/luma-gui", version = "0.0.1" }
# Windows-specific
[workspace.dependencies.windows]
version = "0.52"
features = [
"Win32_Foundation",
"Win32_UI_WindowsAndMessaging",
"Win32_Graphics_Gdi",
"Win32_System_LibraryLoader",
]- thiserror: Industry-standard error handling with derive macros
- serde/serde_json: De facto standard for serialization in Rust
- bitflags: Clean, type-safe flag definitions
- cfg-if: More readable than nested
#[cfg]attributes - tracing: Structured logging for debugging (development only)
- once_cell: Lazy statics for global state initialization
- windows: Official Microsoft crate for Win32 APIs
luma/
├── Cargo.toml # Workspace root
├── PLAN.md # This file
├── README.md # Project overview
├── LICENSE-MIT
├── LICENSE-APACHE
├── .gitignore
│
├── crates/
│ ├── luma-core/ # Platform-agnostic core
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs # Public exports
│ │ ├── error.rs # Error types (thiserror)
│ │ ├── geometry.rs # Point, Size, Rect
│ │ ├── ids.rs # WidgetId, WindowId
│ │ ├── handle.rs # Safe Handle<T> wrapper
│ │ ├── traits.rs # Backend traits
│ │ ├── flags.rs # bitflags for widgets/windows
│ │ │
│ │ └── layout/ # Layout system
│ │ ├── mod.rs
│ │ ├── container.rs # Container trait
│ │ ├── constraints.rs # LayoutConstraints, Alignment, Padding
│ │ ├── box_layout.rs # BoxLayout (horizontal/vertical)
│ │ ├── grid_layout.rs # GridLayout (Phase 5)
│ │ └── engine.rs # Layout calculation engine
│ │
│ ├── luma-windows/ # Win32 backend
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs
│ │ ├── application.rs # Win32 message loop
│ │ ├── window.rs # HWND window wrapper
│ │ ├── button.rs # Button control
│ │ ├── label.rs # Static text (Phase 2)
│ │ ├── textinput.rs # Edit control (Phase 2)
│ │ ├── checkbox.rs # Checkbox (Phase 2)
│ │ ├── listbox.rs # Listbox (Phase 2)
│ │ ├── panel.rs # Container widget
│ │ ├── utils.rs # Win32 helpers
│ │ └── error.rs # Win32 error conversion
│ │
│ ├── luma-serde/ # Serialization (Phase 3)
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs
│ │ ├── ui_def.rs # UiDefinition structs
│ │ ├── loader.rs # Runtime UI loader
│ │ └── saver.rs # Save UI definitions
│ │
│ ├── luma-gui/ # Main public API
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs # Platform selection (cfg-if)
│ │ ├── prelude.rs # Convenience re-exports
│ │ ├── application.rs # Application API
│ │ ├── window.rs # Window + WindowBuilder
│ │ ├── panel.rs # Panel container widget
│ │ │
│ │ ├── widgets/ # Widget APIs
│ │ │ ├── mod.rs
│ │ │ ├── button.rs # Button + ButtonBuilder
│ │ │ ├── label.rs # Label + LabelBuilder (Phase 2)
│ │ │ ├── textinput.rs # TextInput + Builder (Phase 2)
│ │ │ ├── checkbox.rs # CheckBox + Builder (Phase 2)
│ │ │ └── listbox.rs # ListBox + Builder (Phase 2)
│ │ │
│ │ └── layout/ # Public layout API
│ │ ├── mod.rs
│ │ ├── box_layout.rs # Public BoxLayout wrapper
│ │ └── grid_layout.rs # Public GridLayout (Phase 5)
│ │
│ └── luma-editor/ # GUI editor (Phase 4)
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs
│ ├── main.rs # Editor application entry
│ ├── editor.rs # Main editor window
│ ├── canvas.rs # Visual design canvas
│ ├── toolbox.rs # Widget palette
│ ├── properties.rs # Property inspector
│ └── codegen.rs # Generate Rust code (future)
│
└── examples/
├── hello_window.rs # Basic empty window
├── button_demo.rs # Button in BoxLayout
├── layout_demo.rs # BoxLayout examples
├── nested_layout.rs # Nested layouts
├── ui_from_json.rs # Load UI from JSON (Phase 3)
└── form_demo.rs # Form with multiple widgets (Phase 2)
Unlike VCL or WinForms, Luma uses layout managers exclusively:
- BoxLayout: Arranges widgets horizontally or vertically
- GridLayout: Arranges widgets in a grid (Phase 5)
- Nested Layouts: Containers can hold layouts containing more containers
Rationale: Better for responsive UIs, visual editors, and window resizing.
Any widget can potentially contain a layout:
pub trait Widget {
fn set_layout(&mut self, layout: Box<dyn Container>) -> Result<()>;
fn get_layout(&self) -> Option<&dyn Container>;
fn set_bounds(&mut self, bounds: Rect) -> Result<()>;
fn get_bounds(&self) -> Rect;
}- Window: Top-level container with layout
- Panel: Container widget for grouping
- Button/Label: Leaf widgets (don't contain layouts)
By default, layouts automatically recalculate when:
- Window is resized
- Widgets are added/removed
- Widget constraints change
Opt-out available for performance-critical scenarios.
All widgets use builders that validate at build time:
let button = Button::builder()
.label("Click Me")
.on_click(|| println!("Clicked!"))
.build(&window)?; // Returns Result<Button, Error>Using thiserror, all errors are strongly typed:
#[derive(Error, Debug)]
pub enum Error {
#[error("Failed to create window: {0}")]
WindowCreation(String),
#[error("Failed to create widget: {0}")]
WidgetCreation(String),
#[error("Invalid parameter: {0}")]
InvalidParameter(String),
#[cfg(windows)]
#[error("Windows API error: {0}")]
Windows(#[from] windows::core::Error),
}Platform-specific handles are wrapped safely:
pub struct Handle<T> {
raw: *mut std::ffi::c_void,
_marker: PhantomData<T>,
}
impl<T> Drop for Handle<T> {
fn drop(&mut self) {
// Platform-specific cleanup
}
}Phase 1: Single-threaded event loop (matches native platform model)
Phase 2 (future): Thread-safe messaging with window.invoke() for background thread updates
pub trait Container {
fn add(&mut self, widget: Box<dyn Widget>, constraints: LayoutConstraints);
fn remove(&mut self, widget: &dyn Widget);
fn layout(&mut self, available_space: Size) -> Result<()>;
}#[derive(Debug, Clone, Copy)]
pub struct LayoutConstraints {
pub min_width: Option<u32>,
pub max_width: Option<u32>,
pub min_height: Option<u32>,
pub max_height: Option<u32>,
pub preferred_width: Option<u32>,
pub preferred_height: Option<u32>,
pub expand_horizontal: bool,
pub expand_vertical: bool,
pub alignment: Alignment,
pub padding: Padding,
}
impl LayoutConstraints {
pub fn preferred_width(mut self, width: u32) -> Self { ... }
pub fn preferred_height(mut self, height: u32) -> Self { ... }
pub fn expand_horizontal(mut self, expand: bool) -> Self { ... }
pub fn expand_vertical(mut self, expand: bool) -> Self { ... }
pub fn expand_both(mut self, expand: bool) -> Self { ... }
pub fn padding(mut self, padding: Padding) -> Self { ... }
pub fn alignment(mut self, alignment: Alignment) -> Self { ... }
}#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Alignment {
Start, // Left or Top
Center, // Centered
End, // Right or Bottom
Fill, // Stretch to fill available space
}#[derive(Debug, Clone, Copy)]
pub struct Padding {
pub top: u32,
pub right: u32,
pub bottom: u32,
pub left: u32,
}
impl Padding {
pub fn zero() -> Self { ... }
pub fn all(value: u32) -> Self { ... }
pub fn symmetric(vertical: u32, horizontal: u32) -> Self { ... }
}#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LayoutDirection {
Horizontal,
Vertical,
}
pub struct BoxLayout {
direction: LayoutDirection,
gap: u32, // Space between children
children: Vec<(Box<dyn Widget>, LayoutConstraints)>,
}
impl BoxLayout {
pub fn horizontal() -> Self { ... }
pub fn vertical() -> Self { ... }
pub fn with_gap(mut self, gap: u32) -> Self { ... }
pub fn add(&mut self, widget: impl Widget + 'static, constraints: LayoutConstraints) { ... }
}Layout Algorithm (Vertical):
- Calculate total fixed height (non-expanding widgets)
- Calculate remaining space for expanding widgets
- Distribute remaining space equally among expanding widgets
- Position each widget with padding applied
- If widget has child layout, recursively trigger layout
pub struct GridLayout {
rows: u32,
columns: u32,
horizontal_gap: u32,
vertical_gap: u32,
children: Vec<(Box<dyn Widget>, LayoutConstraints)>,
}
impl GridLayout {
pub fn new(rows: u32, columns: u32) -> Self { ... }
pub fn with_gaps(mut self, h_gap: u32, v_gap: u32) -> Self { ... }
}- Window: Top-level container
- Panel: Container for grouping widgets with layouts
- Button: Clickable button with text label
- Label: Static text display
- TextInput: Single-line editable text field
- CheckBox: Boolean toggle
- ListBox: List selection (single or multi-select)
bitflags! {
pub struct WindowFlags: u32 {
const RESIZABLE = 0b0001;
const MINIMIZABLE = 0b0010;
const MAXIMIZABLE = 0b0100;
const CLOSABLE = 0b1000;
const TITLED = 0b10000;
}
}
bitflags! {
pub struct ButtonFlags: u32 {
const DEFAULT = 0b0001; // Activated by Enter key
const TOGGLE = 0b0010; // Toggle button (on/off)
}
}
bitflags! {
pub struct ListBoxFlags: u32 {
const MULTI_SELECT = 0b0001; // Allow multiple selection
const SORTED = 0b0010; // Sort items alphabetically
const VSCROLL = 0b0100; // Vertical scrollbar
const HSCROLL = 0b1000; // Horizontal scrollbar
}
}Type-safe approach with separate callbacks:
pub struct ListBoxBuilder {
// ...
}
impl ListBoxBuilder {
// Single-select mode
pub fn on_select_single<F>(mut self, callback: F) -> Self
where F: FnMut(usize) + 'static
{ ... }
// Multi-select mode (automatically sets MULTI_SELECT flag)
pub fn on_select_multi<F>(mut self, callback: F) -> Self
where F: FnMut(Vec<usize>) + 'static
{ ... }
// Cannot specify both - validated at build() time
pub fn build(self, parent: &Window) -> Result<ListBox> { ... }
}{
"version": "0.0.1",
"window": {
"title": "My Application",
"width": 500,
"height": 400,
"resizable": true,
"layout": {
"type": "BoxLayout",
"direction": "vertical",
"gap": 10,
"children": [
{
"id": "header_panel",
"widget_type": "Panel",
"properties": {},
"constraints": {
"preferred_height": 60
},
"layout": {
"type": "BoxLayout",
"direction": "horizontal",
"gap": 5,
"children": [
{
"id": "btn_new",
"widget_type": "Button",
"properties": {
"label": "New"
},
"constraints": {
"preferred_width": 80,
"expand_vertical": true
}
},
{
"id": "btn_open",
"widget_type": "Button",
"properties": {
"label": "Open"
},
"constraints": {
"preferred_width": 80,
"expand_vertical": true
}
}
]
}
},
{
"id": "content_label",
"widget_type": "Label",
"properties": {
"text": "Content goes here"
},
"constraints": {
"expand_horizontal": true,
"expand_vertical": true,
"alignment": "center"
}
}
]
}
}
}use luma_serde::UiLoader;
let window = UiLoader::load_from_file("ui/main_window.json")?;
window.show()?;use luma_editor::codegen;
let ui_def = UiDefinition::load("ui/main_window.json")?;
let rust_code = codegen::generate_rust_code(&ui_def);
std::fs::write("src/generated_ui.rs", rust_code)?;Goal: Basic window + button with BoxLayout working on Windows
-
Workspace Setup
- Create root
Cargo.tomlwith workspace configuration - Create
README.md,LICENSE-MIT,LICENSE-APACHE - Create
.gitignorefor Rust projects - Set up crate directory structure
- Create root
-
luma-core Implementation
error.rs: Error types withthiserrorgeometry.rs: Point, Size, Rect structsids.rs: WidgetId, WindowId newtypeshandle.rs: Safe Handle wrappertraits.rs: Backend traits (ApplicationBackend, WindowBackend, ButtonBackend)flags.rs: WindowFlags, ButtonFlags withbitflagslayout/constraints.rs: LayoutConstraints, Alignment, Paddinglayout/container.rs: Container traitlayout/box_layout.rs: BoxLayout implementation
-
luma-windows Implementation
application.rs: Win32 message loop (GetMessage, DispatchMessage)window.rs: HWND wrapper with CreateWindowExWbutton.rs: Button control (CreateWindowExW with "BUTTON" class)panel.rs: Panel container widgetutils.rs: String conversion helpers (UTF-8 ↔ UTF-16)error.rs: Win32 error conversion
-
luma-gui Implementation
lib.rs: Platform selection withcfg-ifprelude.rs: Convenience re-exportsapplication.rs: Cross-platform Application wrapperwindow.rs: Window + WindowBuilderpanel.rs: Panel wrapperwidgets/button.rs: Button + ButtonBuilderlayout/box_layout.rs: Public BoxLayout API
-
Examples
hello_window.rs: Empty windowbutton_demo.rs: Window with button in vertical layoutnested_layout.rs: Panel with nested horizontal layout
-
Testing
- Unit tests for geometry types
- Unit tests for layout constraints
- Unit tests for builder patterns
- Manual testing: Run examples and verify behavior
- ✓ Window displays on Windows
- ✓ Button renders and responds to clicks
- ✓ BoxLayout arranges widgets correctly
- ✓ Layout recalculates on window resize
- ✓ Nested layouts work correctly
- ✓ All examples compile and run
- ✓ No panics or crashes during normal operation
Goal: Implement all essential widgets with layout support
-
Label Widget
- Win32: STATIC control
- API: Label + LabelBuilder
- Properties: text, alignment
-
TextInput Widget
- Win32: EDIT control (single-line)
- API: TextInput + TextInputBuilder
- Properties: text, placeholder, read-only
- Events: on_text_changed
-
CheckBox Widget
- Win32: BUTTON with BS_CHECKBOX style
- API: CheckBox + CheckBoxBuilder
- Properties: label, checked
- Events: on_checked_changed
-
ListBox Widget
- Win32: LISTBOX control
- API: ListBox + ListBoxBuilder
- Properties: items, flags (MULTI_SELECT, SORTED)
- Events: on_select_single, on_select_multi
-
Examples
form_demo.rs: Complete form with all widget typeslistbox_demo.rs: Single and multi-select demos
-
Testing
- Unit tests for each widget builder
- Integration test: Form with all widgets
- Manual testing: Verify native look and feel
- ✓ All 7 essential widgets implemented
- ✓ Each widget integrates properly with layout system
- ✓ Native Windows appearance maintained
- ✓ Events fire correctly
- ✓ ListBox multi-select works as designed
Goal: Define UIs in JSON and load at runtime
-
luma-serde Crate
ui_def.rs: UiDefinition, WindowDef, LayoutDef, WidgetDef structsloader.rs: Runtime UI loadersaver.rs: Save UI definitions to JSON
-
UiLoader Implementation
- Parse JSON into UiDefinition
- Build Window from WindowDef
- Build layouts recursively
- Build widgets with properties
- Connect to parent window
-
Examples
ui_from_json.rs: Load and display UI from JSON- Create sample JSON files for various UIs
-
Testing
- Unit tests for JSON parsing
- Integration test: Load complex nested layout
- Verify all widget types load correctly
- Test error handling for invalid JSON
- ✓ Can define complete UI in JSON
- ✓ Runtime loader creates functional UI
- ✓ Nested layouts load correctly
- ✓ Widget properties apply correctly
- ✓ Error messages helpful for invalid JSON
Goal: Visual editor for designing UIs (built with Luma itself)
-
Editor Window Structure
- Main window with three-panel BoxLayout
- Left panel: Toolbox (widget palette)
- Center panel: Canvas (design area)
- Right panel: Properties inspector
-
Toolbox Implementation
- List of available widget types
- Click to select widget type
- Simple UI: ListBox with widget names
-
Canvas Implementation
- Display current UI being edited
- Click to select widgets
- Highlight selected widget
- Show layout boundaries (debug visualization)
-
Properties Inspector
- Display selected widget properties
- Editable fields for text, size, etc.
- Layout constraint editors
-
Core Editor Features
- New project
- Add widget to layout
- Remove widget
- Edit widget properties
- Save to JSON
- Load from JSON
- Preview UI
-
Testing
- Manual testing: Design sample UIs
- Verify saved JSON loads correctly
- Test round-trip: Save → Load → Save
- ✓ Editor runs and is stable
- ✓ Can create simple UIs visually
- ✓ Saved JSON files are valid
- ✓ Loaded UIs match the design
- ✓ Editor itself demonstrates Luma capabilities
Note: Code generation deferred to future phase
Goal: Add grid layout support
-
GridLayout Implementation
luma-core/layout/grid_layout.rs- Row/column-based positioning
- Gap support (horizontal and vertical)
- Cell spanning (future enhancement)
-
API Integration
- Public GridLayout in luma-gui
- GridLayout in JSON format
- Update UI loader
-
Editor Support
- Add GridLayout to editor
- Layout type selector
- Grid configuration UI
-
Examples
grid_demo.rs: GridLayout examples
- ✓ GridLayout works alongside BoxLayout
- ✓ JSON format supports GridLayout
- ✓ Editor can create grid-based UIs
- ✓ Proper resize behavior
Goal: Production-ready 0.1.0 release
-
Documentation
- Comprehensive rustdoc comments for all public APIs
- User guide (getting started, tutorials)
- Architecture documentation
- Contributing guide
-
Examples Gallery
- Polished examples for each feature
- Screenshot/demo for each example
- Example descriptions
-
Performance
- Profile layout calculation
- Optimize Win32 message handling
- Reduce allocations where possible
-
Bug Fixes
- Edge cases in layout system
- Window resize glitches
- Memory leaks (verify Drop impls)
-
Release Preparation
- Update version to 0.1.0
- Finalize README
- Prepare release notes
- Publish to crates.io (optional)
- ✓ All public APIs documented
- ✓ User guide complete
- ✓ No known critical bugs
- ✓ Examples are polished
- ✓ Ready for 0.1.0 release
use luma_gui::prelude::*;
fn main() -> Result<()> {
let app = Application::new()?;
let mut window = Window::builder()
.title("Hello, Luma!")
.size(400, 300)
.build()?;
let mut layout = BoxLayout::vertical().with_gap(10);
let button = Button::builder()
.label("Click Me!")
.on_click(|| println!("Button clicked!"))
.build(&window)?;
layout.add(button, LayoutConstraints::default()
.preferred_height(40)
.expand_horizontal(true));
window.set_layout(layout)?;
window.show()?;
app.run()
}use luma_gui::prelude::*;
fn main() -> Result<()> {
let app = Application::new()?;
let mut window = Window::builder()
.title("Nested Layout Demo")
.size(500, 400)
.build()?;
let mut main_layout = BoxLayout::vertical().with_gap(10);
// Top panel with horizontal button row
let mut top_panel = Panel::new(&window)?;
let mut button_layout = BoxLayout::horizontal().with_gap(5);
button_layout.add(
Button::builder().label("New").build(&top_panel)?,
LayoutConstraints::default().expand_horizontal(true)
);
button_layout.add(
Button::builder().label("Open").build(&top_panel)?,
LayoutConstraints::default().expand_horizontal(true)
);
button_layout.add(
Button::builder().label("Save").build(&top_panel)?,
LayoutConstraints::default().expand_horizontal(true)
);
top_panel.set_layout(button_layout)?;
main_layout.add(top_panel, LayoutConstraints::default().preferred_height(50));
// Content area
let label = Label::builder()
.text("Content Area")
.build(&window)?;
main_layout.add(label, LayoutConstraints::default().expand_both(true));
window.set_layout(main_layout)?;
window.show()?;
app.run()
}use luma_gui::prelude::*;
fn main() -> Result<()> {
let app = Application::new()?;
let mut window = Window::builder()
.title("Form Demo")
.size(400, 300)
.build()?;
let mut layout = BoxLayout::vertical().with_gap(10);
// Name field
layout.add(
Label::builder().text("Name:").build(&window)?,
LayoutConstraints::default().preferred_height(20)
);
layout.add(
TextInput::builder().build(&window)?,
LayoutConstraints::default().preferred_height(30).expand_horizontal(true)
);
// Options
layout.add(
CheckBox::builder().label("Subscribe to newsletter").build(&window)?,
LayoutConstraints::default().preferred_height(25)
);
// Submit button
layout.add(
Button::builder()
.label("Submit")
.on_click(|| println!("Form submitted!"))
.build(&window)?,
LayoutConstraints::default().preferred_height(40)
);
window.set_layout(layout)?;
window.show()?;
app.run()
}use luma_gui::prelude::*;
fn main() -> Result<()> {
let app = Application::new()?;
let mut window = Window::builder()
.title("ListBox Demo")
.size(300, 400)
.build()?;
let mut layout = BoxLayout::vertical().with_gap(10);
// Multi-select listbox
let listbox = ListBox::builder()
.items(vec!["Item 1", "Item 2", "Item 3", "Item 4"])
.on_select_multi(|indices| {
println!("Selected items: {:?}", indices);
})
.sorted(true)
.build(&window)?;
layout.add(listbox, LayoutConstraints::default().expand_both(true));
window.set_layout(layout)?;
window.show()?;
app.run()
}use luma_gui::prelude::*;
use luma_serde::UiLoader;
fn main() -> Result<()> {
let app = Application::new()?;
// Load UI from JSON file
let mut window = UiLoader::load_from_file("ui/main_window.json")?;
window.show()?;
app.run()
}All tests in #[cfg(test)] mod tests blocks:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_point_creation() {
let p = Point { x: 10, y: 20 };
assert_eq!(p.x, 10);
assert_eq!(p.y, 20);
}
#[test]
fn test_layout_constraints_builder() {
let constraints = LayoutConstraints::default()
.preferred_width(100)
.expand_horizontal(true);
assert_eq!(constraints.preferred_width, Some(100));
assert!(constraints.expand_horizontal);
}
}In tests/ directory at workspace root:
// tests/window_creation.rs
use luma_gui::prelude::*;
#[test]
fn test_window_creation() {
let _app = Application::new().unwrap();
let window = Window::builder()
.title("Test")
.size(400, 300)
.build();
assert!(window.is_ok());
}For each phase:
- Run all examples
- Verify visual appearance matches expectations
- Test window resize behavior
- Test widget interactions (clicks, typing, etc.)
- Check for memory leaks (long-running tests)
- Verify error messages are helpful
Use tracing for debugging (development only):
tracing::info!("Creating Win32 window: title='{}', size={}x{}", title, width, height);
tracing::debug!("Layout calculated: {} widgets positioned", child_count);
tracing::error!("Failed to create window: {}", error);Enable with environment variable:
RUST_LOG=luma=debug cargo run --example hello_window
-
Platform Support
- macOS support (Cocoa/AppKit)
- Linux support (GTK)
-
More Widgets
- TreeView (hierarchical data)
- TabControl (tabbed interface)
- ProgressBar (progress indication)
- Slider (numeric input)
- ComboBox/DropDown (selection)
- TextArea (multi-line text)
- Toolbar (button groups)
- StatusBar (status information)
-
Advanced Layout
- Cell spanning in GridLayout
- FlowLayout (wrapping layout)
- Custom layout managers
- Layout animations
-
Styling & Theming
- Custom colors
- Custom fonts
- Theme support
- Dark mode (via
DwmSetWindowAttributefor title bars, custom rendering for controls)
-
Code Generation
- Generate Rust code from JSON
- Hot reload during development
- Visual Studio Code extension
-
Advanced Editor Features
- Undo/redo
- Copy/paste widgets
- Alignment guides
- Snapping to grid
- Component/template system
- Drag-and-drop on canvas
-
Accessibility
- Screen reader support
- Keyboard navigation
- High contrast themes
- Accessibility hints
-
Graphics & Drawing
- Custom painting API
- Canvas widget
- Image display
- SVG support
-
Dialogs
- File picker (open/save)
- Message boxes
- Color picker
- Font picker
-
Performance
- Virtual scrolling for large lists
- Layout caching
- Partial redraws
- GPU acceleration (future)
-
Developer Tools
- Layout inspector
- Performance profiler
- Widget hierarchy viewer
- Live property editing
- Window displays on Windows
- Button responds to clicks
- BoxLayout positions widgets correctly
- Layout recalculates on resize
- All examples run without errors
- No crashes or panics
- All 7 widgets implemented
- Form example works completely
- ListBox multi-select functions correctly
- Native Windows look maintained
- JSON format defined and documented
- Runtime loader works for all widget types
- Nested layouts load correctly
- Error messages are helpful
- Editor launches and runs stably
- Can design simple UIs visually
- Save/load cycle preserves designs
- Editor demonstrates Luma's power
- GridLayout works correctly
- Editor supports GridLayout
- Examples demonstrate grid usage
- All APIs documented
- User guide complete
- Ready for 0.1.0 release
- Community feedback positive
- Follow Rust API guidelines
- Use
rustfmtfor formatting - Use
clippyfor lints - Comprehensive documentation comments
- Meaningful variable names
- Clear error messages
- Feature branches for each task
- Descriptive commit messages
- Squash commits before merging
- Keep main branch stable
- Rustdoc comments for all public APIs
- Examples in doc comments
- Architecture decisions documented
- Update PLAN.md as design evolves
- Profile before optimizing
- Minimize allocations in hot paths
- Lazy initialization where appropriate
- Cache layout calculations when possible
For questions, issues, or contributions, please refer to:
- Repository: (add GitHub URL when available)
- Documentation: (add docs URL when available)
- Issues: (add issue tracker URL when available)
Question: Should Luma use WinUI 3 / Windows App SDK for native Windows 11 dark mode support?
Answer: No. Win32 is the correct choice.
In June 2022, Microsoft explicitly removed all XAML APIs from the windows crate:
- PR #1836: "Remove Xaml from windows crate"
- Reason: "Xaml is designed squarely for C# developers"
- Kenny Kerr (maintainer): "there are currently no plans to provide a Rust-friendly version of Xaml"
Separate crate exists: windows-app (experimental, not recommended)
Major Issues Identified:
- WinUI has undocumented behavior and undocumented assumptions about host processes
- Only truly supports MSBuild + C#
- Implementing
IXamlMetadataProvideralone is insufficient - Controls appear to work but crash unpredictably in WinUI stack
- No source code access makes debugging nearly impossible
- Incomplete fusion manifests cause crashes
- Quirks change between WinUI 3 releases
Microsoft's Official Position (Rivera, Windows team):
"WinUI has undocumented behavior and makes undocumented assumptions about its host process. (XAML only truly supports MSBuild+C#.) Finding and adjusting for those quirks--that changed between WinUI 3 releases--through trial and error was wasting everyone's time."
"I think the sustainable way forward is to throw away XAML and build on top of DirectComposition. That's a gargantuan effort and not something folks are working on at this time."
- Top 2: WinForms and WPF (both require .NET)
- Very low usage: WinRT XAML (in-box XAML)
- Zero usage in Rust: WinRT XAML
- ✅ Win32 (user32 + GDI): Fully supported, stable, in-box, complete Rust bindings
- ✅ Windows.UI.WindowManagement.AppWindow (UWP): Available but deprecated for new development
Pros:
- Battle-tested with complete Rust bindings via
windowscrate - In-box on every Windows version (minimal memory footprint)
- No experimental/unsupported territory
- Stable API that won't change unexpectedly
Dark Mode Limitation (Acceptable for MVP):
- Can implement dark title bars via
DwmSetWindowAttribute(DWMWA_USE_IMMERSIVE_DARK_MODE) - Window contents (buttons, panels) remain light themed (standard Win32 controls)
- This is consistent with many existing Win32 applications
- Documented limitation, not a blocker
Future Dark Mode Strategy:
- Phase 1-3 (MVP): Dark title bars optional, light controls (acceptable)
- Phase 4+: Custom control rendering (owner-drawn controls) for full dark mode
- Phase 5+: DirectComposition-based rendering layer (hardware-accelerated)
- Alternative: WebView2 backend for Electron-like experience
- GitHub Issue: microsoft/windows-rs#2153 (Feature request: WinUI 3 and Windows App SDK Support)
- GitHub PR: microsoft/windows-rs#1836 (Remove Xaml from windows crate)
- windows crate documentation: https://microsoft.github.io/windows-docs-rs/
Last Updated: January 8, 2026
Status: Phase 1 implementation complete (luma-core, luma-windows, luma-gui)
Next Step: Begin Phase 2 - Complete widget set (Label, TextInput, CheckBox, ListBox)