Freya πŸ¦€

Native GUI library for Rust

Β·

5 min read

Freya πŸ¦€

hey πŸ‘‹

I'm Marc and I am happy to announce the first alpha (v0.1) of Freya, an experimental cross-platform native GUI library for πŸ¦€ Rust, built on top of 🧬 Dioxus and powered by the πŸ–ΌοΈ Skia library.

What is Freya πŸ¦€ ?

Freya is a GUI library that extends Dioxus by adding its own renderer based on Skia with the help of a custom layout library, its own elements namespace, attributes and events, plus a set of components and hooks, and also some developer tools like a Devtools panel or a headless components testing runner.

Do you want to try it?

Read this. Just be aware that it is still in the ⚠️ experimentation phase, I would like this first release to be an opportunity to gather feedback, suggestions, new contributions and ideas!

What is Dioxus 🧬 ?

Dioxus is a renderer-agnostic UI library for Rust, like React. It uses components as functions and hooks. It supports many renderers: web, backend with SSR, liveview and fullstack, desktop and mobile with webview, desktop with WGPU, or even TUI.

Learn more about Dioxus. And see the differences with Freya.

Reasons to use Freya βœ…

  • Dioxus: very easy to use, it's blazingly fast and has a bright future.

  • Native renderer: Looks the same on all platforms and avoids compatibility issues

  • Built-in Components and hooks: From a simple Button to a VirtualScrollView or animation utilities.

  • Headless testing runner: Make sure your components work before making a release.

  • Languages: Just Rust!

Reasons to not use Freya ❌

  • It's still experimental: it might contain bugs, have performance issues or some APIs not being fully usable yet.

  • Lack of ecosystem: You can use renderer-agnostic libraries of Dioxus but it is still a small ecosystem, and non-existent for Freya.

  • Lack of docs: Some things are not fully documented and others could be improved.

Example

Here there is a simple counter app with Freya (source code here):

fn app(cx: Scope) -> Element {
    let mut count = use_state(cx, || 0);

    render!(
        rect {
            height: "20%",
            width: "100%",
            background: "rgb(233, 196, 106)",
            padding: "12",
            color: "rgb(20, 33, 61)",
            label { 
                font_size: "20", 
                "Number is: {count}"
            }
        }
        rect {
            height: "80%",
            width: "100%",
            background: "rgb(168, 218, 220)",
            color: "black",
            padding: "12",
            onclick: move |_| count += 1,
            label { "Click to increase!" }
        }
    )
}

Image description

✨ Supported features

  • ⛏️ Built-in components (button, scroll views, switch and more)

  • πŸš‡ Built-in hooks library (animations, text editing and more)

  • πŸ” Built-in devtools panel (experimental ⚠️)

  • 🧰 Built-in headless testing runner for components

  • 🎨 Theming support (not extensible yet ⚠️)

  • πŸ›©οΈ Cross-platform (Windows, Linux, MacOS)

  • πŸ–ΌοΈ SKSL Shaders support

  • πŸ”„οΈ Dioxus Hot-reload integration

  • πŸ“’ Multi-line text editing (experimental ⚠️)

  • 🦾 Basic Accessibility Support (experimental ⚠️)

  • 🧩Compatible with dioxus-std and other Dioxus renderer-agnostic libraries

πŸ’» Supported platforms

All major desktop OS:

  • Windows

  • Linux

  • macOS

It could technically run on more platforms, like Mobile or Web via Wasm, feel free to contribute 😁

πŸ”„ Hot reload

Freya supports Dioxus's hot reload, which means that you can write and update the layout, styling and other static attributes of your components without having to recompile any rust code, it updates on the fly.

🧰 Testing

Freya supports headless testing of components, you can simulate from the window size to events, like mouse or keyboard, and also assert the layout or text values of your components.

Simple example:

#[tokio::test]
async fn no_state() {
    fn no_state_app(cx: Scope) -> Element {
        render!(
            label {
                "Hello"
            }
        )
    }

    let mut utils = launch_test(no_state_app);

    assert_eq!(utils.root().get(0).get(0).text(), Some("Hello"));
}

A more complex example that even simulates click events:

#[tokio::test]
async fn simulate_events() {
    fn stateful_app(cx: Scope) -> Element {
        let enabled = use_state(cx, || false);
        render!(
            rect {
                width: "100%",
                height: "100%",
                background: "red",
                direction: "both",
                onclick: |_| {
                    enabled.set(true);
                },
                label {
                    "Is enabled? {enabled}"
                }
            }
        )
    }

    let mut utils = launch_test(stateful_app);

    let rect = utils.root().get(0);
    let label = rect.get(0);

    // Inital render
    utils.wait_for_update().await;

    let text = label.get(0);

    assert_eq!(text.text(), Some("Is enabled? false"));

    utils.push_event(FreyaEvent::Mouse {
        name: "click".to_string(),
        cursor: (5.0, 5.0).into(),
        button: Some(MouseButton::Left),
    });

    // New render after clicking
    utils.wait_for_update().await;

    let text = label.get(0);

    assert_eq!(text.text(), Some("Is enabled? true"));
}

πŸ” DevTools

Freya integrates an experimental DevTools panel to help you navigate and inspect the elements of your app while you are developing. It is not included in release builds.

You can do:

  • Inspect the DOM

  • Inspect element's styles

  • Inspect the element's computed layout

πŸ€“ Complex examples

For simpler examples see the Freya repository.

Freya-editor: An experimental code editor.

Demo

Canvas: A canvas for floating editors that you can drag around.

Image description

πŸ“† Roadmap

  • More elements, components, hooks and events.

  • Better performance, both for rendering and layout.

  • Better developer tools (Devtools panel, test runner, etc)

  • More and better documentation

I am aware Freya is not perfect, and it will take some time to be production-ready, but I am sure it will keep getting better.

πŸ‘€ See you soon!

I hope you liked this post and want to try Freya at some point, or even contribute!

Make sure to give Dioxus some love, Jonathan, Evan and the other contributors have made an amazing work with Dioxus, they have been a fundamental piece for Freya to work πŸ«‚.

Also thanks to Armin for his amazing work in rust-skia and help with issues and doubts πŸ’ͺ, and Tropix126 for his work in new styling features like more font customization, better rounded corners, better shadows and a few more things πŸ’― !

You can leave a star ⭐ in the repository or sponsor me on GitHub Sponsors if you want πŸ’–. You can join the Discord server or follow me on 🐦 Twitter, I usually share the progress I make in Freya.

Thanks!

Β