Damirados
Emerge & Solve - a GUI framework for Elixir
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (Solve) libraries that form a framework when put together even though they don’t depend on each other.
Currently only Linux is supported, to be precise Wayland and DRM (Nerves). MacOS and Windows support is planned sometime in the future. Tested only with AMD (Wayland and DRM), rpi5 and rk3566 nerves devices (DRM)
There is also a Solve LiveView adapter in the works, you will have to ask @ken-kost for the timeline on that.
If you want more details check out on hex and github. Rest of the post will be on hows and whys of development.
Getting artificial elephant out of the room
Before I get any further, this project was a successful experiment on how far I can push gen AI coding. 90%+ of the code in those repos is LLM generated and I could maybe credit it for about 5% of the engineering behind that code, there were sessions with 50+ prompts in plan mode before implementation. I have a pretty good understanding of how incapable AI is. That being sad I still have some coding standards and these projects don’t meet them but that is a future me cleanup problem. If this has made you lose all interest I fully respect that. However this post is 0% AI. I will not even use it for spelling & grammar. I have enough trauma of trying to use LLMs to write the docs and I still hate current state of docs. We can start a new thread if anyone wants more details on AI usage, I would like to keep this one focused on GUI.
Motivation
I use nerves both Professionally and all my hobby projects are tied to it, all of those require UI running on nerves devices and I need/want them to be both easy and fun to develop and high performance at the same time. I also have aspirations to develop a mix of OBS and real-time Davinci Resolve using this system on top of membrane, foundation for video pipelines is already in there.
I have spend half of my career building UIs. Using native Android/iOS, meteor.js, Elm, React, ReactNative, Flutter, Surface/LiveView, Keechma-next(Clojure/Script) in various combinations of state managements and different css frameworks/UI toolkits between all of it.
Most of these tools share a common trait. They are painful to use or turn painful to use as UI becomes complex, each set of tradeoffs falls apart in one way or the other. These 2 are most pleasant from both sides:
- Elm-ui is only lib where I could basically one shot full page from the design without ever running it and it would turn out mostly correct. Emerge API is based on it. When used in Elm this lib becomes painful because elm pushes you into prop drilling.
- Keechma-next had the most pleasant state management solution of them all. It achieves full decoupling of UI and state without prop drilling while having explicit and declarative data flow in a way that scales very well with complexity. Solve is an attempt at 1:1 elixir re-implementation.
It boils down to me wishing for a combination of those 2 every time I have to write an UI. Last time I was building a larger feature in flutter for nerves device just tipped me over and I have decided to just go for it.
Implementation
Emerge is mostly a Rust NIF backed by skia.
You declare a recursive struct in elixir via function based DSL. Struct is diffed with previous version in Elixir, diff is then serialized into binary and sent over to the Rustler NIF.
Rust side consists of the layout engine, renderer and event engine.
Different back-end implementations need to provide renderer with surface to render into and they need to provide output to the event engine.
Hope some of you find this project useful even as it is in this initial version. There is a lot of essential features still missing. More backends and features are coming in the future along with performance optimizations as there is some low-hanging fruit on that side.
If you try it out and are unable to implement a UI feature you want using Emerge feel free to reach out and propose a new feature.
Most Liked
Damirados
Emerge 0.3.2 is out. It contains few bug fixes compared to 0.3.1 and some more performance improvements.
That being said everything else on the roadmap mentioned with 0.3.1 release has been put on hold and next release is likely few months away. @cblavier That includes video example.
I consider where both projects are now a very successful proof of concept. The term I like to use is MVS (Minimum viable slop)
Developer facing APIs turned out pretty much how I wanted.
Internally, general architecture is OK but code is horrendous and I don’t see a point in continuing adding anything on top of it.
I am doing full deslopification phase. I have started from an empty project and am redoing it all by hand.
Still leveraging AI for a lot of stuff here but it is not allowed to modify any files in the repo.
There should be no breaking changes introduced by the rewrite and I encourage you try it out if you need UI for your Nerves project, please do report any bugs you find. I am sure there are some introduced cached layout and rendering as caching is too hard of a problem for AI to tackle.
Nerves meetup EU recording will be out soon so watch out for it if you are interested in whys and hows behind this project.
Damirados
I actually have a working demo of H265 decoding pipeline with membrane that displays dynamic transparent overlay, all zero-copy and GPU accelerated. I will try to clean it up and upload it as new emerge demo sooner than macOS video work is finished then, may take a week or two.
What nerves device are you currently using? Emerge currently requires GPU with atomic mode setting for DRM backend, that means rpi4 and rpi5 or mostly any arrch64 device that has working gpu drivers. in the future I will enable legacy mode setting to bring it to older devices and add precompiled arm 32 bit builds into release. There is a limit on how many things I can work on in parallel though so this may take some time.
Damirados
Emerge 0.3.1 is out compared to 0.2.1:
- There is initial version of layout caching and renderer cache. Depending on app structure it can bring huge performance improvements especially on animated sections.
- There is now
Input.slider Size.min/maxare now proper size resolution combiners. For example now you can have an element withheight(min(content(), fill())attribute and it will be content sized until content becomes bigger than it’s fill portion. TodoApp in demo now uses it for entries so it grows with entries to screen size and then after that entries become scrollable since entries element hasscrollbar_yon it.
Next roadmap:
- Add headless backend, you give it
pidand it sends rendered binary to thatpidevery time there is a change. - Make all backends automatically fallback to raster rendering in case there is no gpu.
- Add option for output pixel format (HDR displays, 1 bit or 2 bit e ink displays)
- Both of these will be preliminary work for running it on nerves badge/ nerves starter kit. Goal is to have next release run on it









