libLuna Documentation
PL EN
GitHub

Under the hood

Architecture

Six crates, one dependency direction and one drawing contract. libLuna is not trying to recreate GTK — it is trying to stay small enough to hold in your head and fix.

Layer names

LayerGNOME equivalentKDE equivalentLuna
ToolkitGTKQtlibLuna
Environment / shellGNOMEKDE PlasmaLuna
Wayland compositorMutterKWinSelene

These docs cover libLuna, but the architecture only makes sense together: applications paint with libLuna, speak standard Wayland, and Selene accepts windows and manages the screen.

Crate map

Dependencies only point downwards. Widgets do not know how DRM works. The platform does not know how to paint a button. The theme does not know who uses it.

Drawing and text

Scene graph

libluna-render::scene is a backend-independent list of DrawCommands. Widgets build the scene without touching pixels.

CPU backend

tiny-skia rasterises shapes with anti-aliasing; the RGBA8888 buffer goes through wl_shm.

Text

fontdue + a system font. No kerning or complex scripts yet; cosmic-text is planned without a contract change.

Icons

SVG rasterised with resvg (no text or bitmaps) plus a set of pastel vector icons.

Separating the scene from the backend makes it possible to add a GPU (EGL/dmabuf) backend without changing widgets. It is also why tests can run without a window: a scene can be compared or rendered to PNG.

The widget model

The target model is retained, but the drawing contract stays immediate:

text · contract
Widget:
  measure(constraints) -> Size       // how much it wants
  allocate(rect)                     // where it goes
  paint(scene, theme)                // drawing
  hit(event) -> Handled | Propagate  // input
  focus / grab / hover

Today layout is a separate Node tree with measure/allocate passes, while widgets remain leaves with paint and *_at methods. That lets you use them by hand (as in the demo) or through layout.

Talking to the compositor

CaseProtocolIn libLuna
Regular application windowxdg-shell + CSDAppConfig::new(...), your own HeaderBar.
Panel / dock / backgroundwlr-layer-shellAppConfig::layer(LayerConfig::top_panel(...)).
OSD / notificationswlr-layer-shell overlayLayerConfig::overlay(...), transparency.
Lock screenoverlay + exclusive keyboardLayerConfig::lock_screen(...).
Clipboardwl_data_deviceFrame::copy_to_clipboard / paste_from_clipboard.

There is no client-side X11 backend. XWayland serves X11 applications inside Selene, but a new libLuna app speaks native Wayland.

Theming

Tokens live in libluna-core::style: spacing, radii, typography, control metrics and the palette. Widgets read them in paint and layout, so a style changes geometry, not just colours.

rust · three levels
// 1. variant
frame.set_preference(ThemePreference::Dark);

// 2. accent
frame.set_accent(Accent::Teal);

// 3. style from a file (colours + geometry)
frame.set_style(Some("nord".into()));

Details: Themes & tokens.

Deliberately deferred

AT-SPI accessibility

Important for a real desktop, but it needs a D-Bus bridge and an accessibility tree. Planned later.

IME / text-input-v3

Comfortable CJK input and a virtual keyboard. Basic text events work today.

GPU / dmabuf

Zero-copy for Vulkan/EGL clients. Rendering is CPU today, but the scene contract stays.

Fractional scaling

Blur-free HiDPI. Scale is already exposed through Frame::scale and Scale.

Drag & drop

Clipboard works; cross-application DnD comes later.

xdg_activation

A new window sometimes needs to be found behind another. The protocol is planned in Selene.

Repository and building

bash
# the whole project
make build
make test

# libLuna only
cd libluna
cargo test --workspace
cargo doc --no-deps

# demo and gallery
cargo run --manifest-path apps/luna-demo/Cargo.toml --bin gallery
cargo run --manifest-path apps/luna-demo/Cargo.toml --bin render -- docs/images/out.png

Each directory is a separate Cargo workspace with its own Cargo.lock. The meta-repository only orchestrates the build. More about releases: docs/repositories.md.