Declarative UI Programming in Rust for Native Applications
I have spent the last couple of weeks learning Rust. I was very fascinated by the potential of Rust for building high-performance applications, at the same time as it has high level abstractions. Since I’m coming from the web and React world, I set out to explore the possibilities of Rust in the context of UI programming. The result of this exploration is Appy, an experimental framework inspired by React that uses Rust’s performance capabilities to render components directly with OpenGL.
This framework is still in its early stages, and it should be understood as an experiment. However, I’m excited to share what I’ve learned so far and start a conversation about the possibilities of Rust for UI programming.
At its core, Appy relies on the Rust, RSX, OpenGL and the Simple DirectMedia Layer (SDL) library for rendering graphics. SDL provides cross-platform functionality, which means that the apps built with Appy can potentially be deployed on a range of platforms. However, at present, only the Android and desktop versions of the deployment tool are fully operational. That said, adding an iOS or wasm tool chain should be a straightforward process.
Hello World
If you’re familiar with React, you’ll recognise the syntax of Appy, which lets you write code that looks like HTML or XML. This is a “hello world” application:
use appy::{*};
#[main_window]
pub fn app()->Elements {
apx!{
<bg col=0x800000/>
<text text="Hello World".to_string() align=Align::Center/>
}
}
But unlike React, Appy doesn’t use a virtual DOM to manage UI updates. Instead, Appy renders components directly with OpenGL. This approach eliminates the need for a DOM and, consequently, the need to update it. The result is a leaner, faster, and more efficient framework that offers significant performance benefits over traditional UI frameworks.
Hooks
In Appy, the concepts of React hooks are still present. Hooks are a way of using state and other React features in functional components, without having to use class components. In Appy, I use a similar approach with Rust closures.
For example, let’s say you have a component that needs to update its state based on user input. You can create a Rust closure that handles the update, and then pass that closure as a prop to the component. When the user input happens, the closure is called, and the component’s state is updated accordingly. For example:
Recommended by LinkedIn
use appy::{*};
#[main_window]
pub fn app()->Elements {
let (v,set_v)=use_state(||1);
let on_button_click=cb_with_clone!([v,set_v],move||{
set_v(*v+1);
});
let s=format!("Hello: {}",*v);
apx!{
<blk top=Pc(25.0) height=Pc(25.0)>
<text text=s.to_string() align=Align::Center size=Pc(100.0)/>
</blk>
<blk top=Pc(50.0) height=Pc(20.0) width=Pc(25.0)>
<bg col=0x808080/>
<text text="+1".to_string() align=Align::Center size=Pc(100.0)/>
<interaction on_click=on_button_click/>
</blk>
}
}
Deployment
As part of the experiment, I also created a deployment tool. Deploying an Appy app to Android is a simple process that involves running a single command. I found tutorials online that explained how to get SDL up and running on Android. It was quite time-consuming process, which involved several steps of copying files back and forth, and finally opening Android Studio to build the project. I have automated the process to make it much easier and more efficient, so that starting a project doesn’t feel like a hurdle.
Conclusion
The code for Appy is available on GitHub, along with some examples to help you get a better understanding. One of the examples is a simple calculator, which I built to get a feel for what it’s like to use the framework.
I found the workflow of using Appy to be quite enjoyable. Being able to write code in a functional style, and still get native performance without having to deal with the a virtual DOM, was refreshing. The use of Rust closures to handle state updates and other events felt natural and intuitive.
While Appy is still in the experimental stages, I believe it has potential as a cross-platform UI framework for Rust developers. The ability to leverage SDL and OpenGL for business and productivity apps could be a game-changer, both in terms of performance and developer productivity.
I’m excited to continue working on Appy and exploring the possibilities of declarative UI programming in Rust. If you’re interested in trying it out or contributing, feel free to check out the code on Github and join in the conversation.
If you made it this far, let me also mention that I am currently seeking job opportunities where I can use my skills and knowledge to contribute to exciting projects. Perhaps you have a project where I could leverage and further develop Appy? Or something else interesting.
References and links
Does this also run on ios devices?