What does HackerNews think of rui?

Declarative Rust UI library

Language: Rust

#113 in Rust
For 5 years or so, I'm watching for GUI infrastructure for my imaginary audio applications. And recently I started to develop an audio application in Rust. What I learned is that there is no a single best library in any language. Also, you shouldn't rely on anything as if it even a very popular thing at the moment it can become unmaintained very quickly. So it's better to choose a satisfying solution in what available currently and abstract it as much as possible to be able to switch to something else in the future. I also did a very simple benchmarks for GUI libraries I was interested in (instantiating 10 000 rectangles, styling them and doing layout) and the leader on macOS was the browser (Tauri) with Slint at the second place. But, unfortunately, Tauri is unusable for such kind of application because of IPC. If you need to visualize your audio data, you need to continuously send it to GUI. The fastest way of communication for that would only be WebRTC, because of the sandboxing. Or you would need to go all WASM, but then you don't have access to a lot of other features you needed. As a suggestion, take another look at Qt. At very least MuseScore and Ardour use it. Also, at my opinion the most mature Rust GUI library yet is egui, not Iced. FYI, Audulus uses immediate mode GUI based on nanovg (https://github.com/audulus/vger#why). And they develop their own Rust GUI library BTW (https://github.com/audulus/rui)
My rui library can render UIs at 120fps, uses similar SDF techniques (though uses a single shader for all rendering): https://github.com/audulus/rui

Is their GPUI library open source?

I think the jury is still out on whether rust is good or bad for UI. Once rust UI libraries are more mature we'll get a sense of it. There are some advantages of static typing, even for UI (see SwiftUI for example). I'll grant the pickiness of rust can be a challenge. Anyway give us some time to work on stuff.

Here's my effort: https://github.com/audulus/rui

I've done a library for vector graphics on the GPU which works pretty well for my uses:

https://github.com/audulus/vger

and a rust version:

https://github.com/audulus/vger-rs

(which powers my rust GUI library: https://github.com/audulus/rui)

Here's the approach for rendering path fills. From the readme:

> The bezier path fill case is somewhat original. To avoid having to solve quadratic equations (which has numerical issues), the fragment function uses a sort-of reverse Loop-Blinn. To determine if a point is inside or outside, vger tests against the lines formed between the endpoints of each bezier curve, flipping inside/outside for each intersection with a +x ray from the point. Then vger tests the point against the area between the bezier segment and the line, flipping inside/outside again if inside. This avoids the pre-computation of Loop-Blinn, and the AA issues of Kokojima.

It works pretty well, and doesn't require as much preprocessing as the code in the article. Also doesn't require any GPU compute (though I do use GPU compute for some things). I think ultimately the approach in the article (essentially Piet-metal, aka tessellating and binning into tiles) will deliver better performance, and support more primitives, but at greater implementation complexity. I've tried the Piet-metal approach myself and it's tricky! I like the simpler Shadertoy/SDF inspired approach :)

A more scrappy approach is what I'm trying to do with my library, rui [1]. Just get something out there. Also, it's really in service of my (already released) app, as opposed to trying to be a successful open source project. If others happen to like it, great!

That said, I think Druid is a good Minimum Viable Product. I just needed GPU acceleration for my app, and wanted something closer to SwiftUI, which I'm used to.

[1] https://github.com/audulus/rui

I tried using interior mutability in rui [1] but the clunkiness appeared in having to call clone on the Rc/Arc too often. I'd have a few clones before moving into a closure, like this:

        let text = self.text.clone();
        focus(move |has_focus| {
            let text = text.clone();
            state(TextEditorState::new(), move |state| {
                let text = text.clone();
                let text2 = text.clone();
                let cursor = state.with(|s| s.cursor);
                let state2 = state.clone();
currently looks like this:

    focus(move |has_focus| {
        state(TextEditorState::new, move |state, cx| {
            let cursor = cx[state].cursor;
            canvas(move |cx, rect, vger| {
(Note the context (cx) passed to callbacks to look things up.)

[1] https://github.com/audulus/rui

I’ve been writing SwiftUI lately and it’s the most productive GUI toolkit out there.

Taylor Holliday of the Audulus fame is porting it to Rust

https://github.com/audulus/rui

I've got a little Rust GUI library that's pretty young, and relatively simple, so maybe fun to contribute to: https://github.com/audulus/rui :)