Alpha · one-line install

Write the markup. Lumen renders it.

A declarative, markup-first UI framework for native desktop apps — a Rust ECS core, GPU rendering, and live hot reload of your markup, styles, and script.

Author a .lmn tree, an optional CSS-subset sheet, and an optional .rhai script. Save to reload — state preserved.

main.lmn
main.rhai
<root bg="#0c1c30" padding="32" gap="20"
      align="center" justify="center">
  <label class="display" id="counter"
         text="0" bind-text="clicks" />
  <row gap="14" justify="center">
    <button class="primary" id="bump"  text="+1" />
    <button class="primary" id="reset" text="reset" />
  </row>
  <script src="main.rhai" />
</root>
Counter
3
+1
reset
What you'll feel

Fast where it counts.

The things a UI developer actually notices: how soon a click paints, what the app costs while it sits there, and how a save lands.

Next frame
click → paint

An input marks the frame dirty and the very next redraw paints it — latency bounded by your display's refresh, nothing added on top.

0% idle
cpu at rest

The event loop parks between events. When nothing changes, nothing repaints — no polling, no background churn, the CPU sleeps.

No restart
save → repaint

Hot reload swaps markup, CSS, or script in place. Focus, scroll position, and signal values all survive the swap.

Architecture guarantees, verified in the winit event loop — not benchmark dumps. For throughput on your own hardware, run cargo bench -p benches.

Why Lumen

A tiny authoring surface over a serious runtime.

Three files describe your app. Underneath, a two-world ECS core drives layout, styling, and GPU paint — and every save reloads without losing your place.

three files

Markup, styles, script

A fixed tag vocabulary, a familiar CSS-subset styling layer, and a small embedded scripting language for view logic and reactive signals.

hot reload

Save to reload

Markup, CSS, and script all reload on save — preserving focus, scroll position, and signal values across the swap.

gpu paint

Rendered on the GPU

Every frame is composited as retained vector paths — crisp at any DPI, with full glyph shaping and flexbox & grid layout.

signals

Reactive bindings

Name a signal, bind it with bind-text, and the loop closes: edits flow back, derived values flow out.

a11y + ime

Accessible & global

An accessibility tree, IME composition, and Unicode BiDi shaping for mixed left-to-right and right-to-left text.

lsp · mcp · ffi

Tooling & embedding

An LSP server and formatter, an MCP server to inspect a running app, and a C ABI — with Rust, C++ & Python SDKs on top — to drive Lumen from other languages.

The reactive loop

Markup binds. Script mutates. The view re-derives.

A signal is a named entry in a host-local store. A <label bind-text> reads it; a click handler writes it; the label re-renders. No view-model to wire by hand.

main.rhai
fn on_start() {
    on("click", "bump",  "handle_bump");
    on("click", "reset", "handle_reset");
}

fn handle_bump(id) {
    let n = signal("clicks", 0);
    n.set(n.get() + 1);
}

fn handle_reset(id) {
    signal("clicks", 0).set(0);
}
main.css
:root {
  --color-accent: #5fd9e0;
  --color-bg:     #163459;
  --radius-pill:  24;
}

.display { text-align: center; font-size: 96; }

.primary {
  bg:       var(--color-bg);
  hover-bg: #1d4477;
  radius:   var(--radius-pill);
}
.primary:focus { outline: 2 var(--color-accent); }
Scope

What ships today — and what's next.

Lumen is pre-1.0 and honest about its edges. Everything on the left works now; everything on the right is on the roadmap, not yet built.

Shipping today

  • One-line install (prebuilt lumenc)
  • Plugin registry — lumenc add
  • Linux, Windows & macOS desktop
  • Hot reload — markup, CSS & script
  • Accessibility tree (AccessKit)
  • IME composition & Unicode BiDi
  • C / C++ FFI with shipped headers
  • LSP server + VS Code extension
  • MCP server for app automation
  • Dark mode via @media (prefers-color-scheme)
  • Virtualized lists

Planned

  • Multi-window apps
  • Keyframe & spring animation
  • Web / WASM target
Quick start

One line in, one window out.

The installer drops the prebuilt lumenc on your machine — no Rust toolchain, no sudo. Scaffold a starter and it opens live.

Full install guide →
# install the prebuilt toolchain $ curl -fsSL https://lumen-ui.dev/install.sh | sh # scaffold a counter app and run it $ lumenc new counter my-app $ lumenc run my-app