#ui-framework #declarative-ui #declarative #ui #cross-platform-gui #gui-applications

ribir_gpu

Ribir is a framework for building modern native/wasm cross-platform user interface applications

25 releases

new 0.3.0-alpha.4 Apr 17, 2024
0.3.0-alpha.1 Mar 27, 2024
0.0.1-alpha.5 Jul 4, 2023
0.0.0 Feb 26, 2023

#562 in GUI

Download history 24/week @ 2024-01-26 82/week @ 2024-02-02 37/week @ 2024-02-09 100/week @ 2024-02-16 167/week @ 2024-02-23 299/week @ 2024-03-01 148/week @ 2024-03-08 190/week @ 2024-03-15 296/week @ 2024-03-22 177/week @ 2024-03-29 103/week @ 2024-04-05

775 downloads per month
Used in 2 crates

MIT license

290KB
7K SLoC

Ribir - Non-intrusive Declarative GUI Framework

Ribir-logo

Use Rust to build multi-platform applications from a single codebase.

What's Ribir?

Ribir is a Rust GUI framework that helps you build beautiful and native multi-platform applications from a single codebase.

Experience a novel approach to UI development that's directly based on your data structure APIs. Any data mutation will trigger a precise UI update. Your focus should be on designing your data structure and its APIs. Then, you can describe your data's UI without intruding on its logic.

At First Glance

A simple example of a counter:

use ribir::prelude::*;
fn main() {
  let counter = fn_widget! {
    let cnt = Stateful::new(0);
    @Row {
      @FilledButton {
        on_tap: move |_| *$cnt.write() += 1,
        @{ Label::new("Inc") }
      }
      @H1 { text: pipe!($cnt.to_string()) }
    }
  };
  App::run(counter);
}

To use Ribir without DSL:

use ribir::prelude::*;

fn main() {
  let counter = |ctx: &BuildCtx| {
    let cnt = Stateful::new(0);

    let c_cnt = cnt.clone_writer();
    let inc_btn = FilledButton::declarer()
      .on_tap(move |_| *c_cnt.write() += 1)
      .finish(ctx)
      .with_child(Label::new("Inc"), ctx);

    let counter = H1::declarer()
      .text(pipe!($cnt.to_string()))
      .finish(ctx);

    Row::declarer()
      .finish(ctx)
      .with_child(inc_btn, ctx)
      .with_child(counter, ctx)
      .build(ctx)
  };
}

More Examples

Features

  • Declarative language does not introduce a fully new language but rather provides a set of Rust macros for easy interaction.
  • Widgets compose system has four kinds of widgets to support you can implement your widget in different ways:
    • function widget and Compose, from other widgets composition.
    • Render, implement your layout and paint anything you want.
    • ComposeChild, control the compose logic between parent and child widgets and specify the template of child widgets.
  • Non-intrusive state converts your data to a listenable state and updates the view according to the change of the state.
  • Layout system learning and inspired by Flutter Sublinear layout, but not the same.
  • Event system is a composition event system, that supports event bubbling and capture. Allow to compose with any widget, and exists only if you use it.
  • Theme system supports full and inherit/partial themes, so you can use it to override or dynamically switch the theme of the subtree. Include palette, icons, animate transitions, the decoration widget of the widget, etc. In a very rough state and the API will be redesigned soon.
  • Animations based on the state but no side effect, it's almost stable in concept, but not many predefined animations yet.
  • Painter converts the view to 2D paths.
  • GPU render is a backend of the Painter, do path tessellation so that you can easily render the triangles in any GPU render engine. A wgpu implementation is provided as the default GPU render engine. Tessellation base on [lyon].
  • Text support basic text typography and IME input, in a usable but rough stage.
  • Widgets library provides 20+ basic widgets, but all are in a rough stage, and the API is not stable yet.

Architecture overview

Support Platform

Platform Support situation
Linux
Windows
macOS
iOS 🚧 Not yet
Android 🚧 Not yet
Web 🚧 Not yet

Love Ribir?

If you like Ribir, give our repo a ⭐ STAR ⬆️ and WATCH 👀 our repository to stay updated with the latest developments!

Every encouragement and feedback can support us to go further.

Known Issues

The pipe/watch may easily introduce a cycle reference, which will cause a memory leak if you do not manually unsubscribe. We'll resolve this issue in v0.2.0.

In most cases, the framework will be able to avoid cycle reference automatically. Documentation will be updated to explain how to avoid cycle reference in the rest cases, and we will provide an API to help developers resolve it.

For a complete list of known issues, please see Issues.

Contributing

We are grateful to the community for contributing bug fixes and improvements.

😎 New to Ribir?

Start learning about the framework by helping us improve our documentation. Feel free to open a new "Documentation" issue. We are also very welcome:

  • Point out to us where our document has misunderstandings
  • Pull requests which improve test coverage
  • Add undocumented code (e.g. built-in widget)
  • Report typo

For more information please read:

🤔 Confused about something?

Feel free to go to Discussions and open a new "Q&A" to get help from contributors. Often questions lead to improvements to the ergonomics of the framework, better documentation, and even new features!

😱 Found a bug?

Please report all bugs! We are happy to help support developers fix the bugs they find if they are interested and have the time.

Thanks

This project exists thanks to all the people who contributed:


We also found inspiration from the following frameworks:

License

Ribir is MIT-licensed

Dependencies

~19–51MB
~850K SLoC