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!

ย