Exploring GUI Libraries

My latest professional development days (PDD) turned into a lesson on yak-shaving, GUI frameworks and my relationship to learning.

For my last PDDs of 2025 I wanted to investigate Activity Pub for server to server communication. Activity Pub is a protocol used by the Bonfire Network (which we are involved in), Mastodon and other parts of the Fediverse.

To explore Activity Pub I wanted to build a simple image sharing server and client app. I had been playing around with this idea during the end of my sabbatical as it would serve a need of mine. So I had some parts in place before starting the PDD.

In theory a personally useful project should be a great motivator for learning. What I got instead was a teachable moment.

Several factors derailed my efforts:

I had also tried to shortcut my way to a working system:

Running the client in the browser was great (fast feedback loop, familiar dev tools). The other two didn’t pan out:

The LLM code, quick and dirty feature growth and unfamiliar GUI tooling meant I didn’t have any tests or even testable code. So I had to resort to manual testing and that of course is slow and frustrating.

So by the second day I abandoned the goal of learning about Activity Pub and instead started experimenting with more mainstream mobile app development. At some point David suggested looking into Progressive Web Apps. I continued this journey through christmas while recovering from COVID.

Mobile App libraries/frameworks I tried

All of these promise cross platform development, i.e. write your app once and it will run on Mac OS, Windows, Linux, Android, iOS.

Fyne

Fyne is a lightweight Go library for cross‑platform GUIs. I found the layout system unintuitive and the documentation was at times outdated. Struggling to center a text input in a page felt like CSS of yesteryear.

Flutter

Flutter, Google’s Dart‑based UI toolkit, required a complex setup that I couldn’t get running, so I bailed without getting the hello world to run.

React Native with Expo Framework

React Native (via Expo) let me run the app in a browser and an Android emulator with minimal pain, but the heavy JavaScript dependency chain and my unfamiliarity with React made me pivot yet again.

Switching to PWAs

At this point I also decided to try building a Progressive Web App instead of a mobile app. Things that led me down this path:

So now I wanted to explore ways to build a clientside browser application. I have built several little tools using vanilla JS/TS, but suspected that I could benefit from libraries to tackle state management, navigation etc.

Web App libraries/frameworks I tried

Leptos

Wanting saner tooling I thought I’d check out offerings from the Rust world. Previously I had used seed to build text2tabletop . It uses ‘The Elm Architecture’ (TEA) which I knew from building freeyourscience in Elm. However seed is no longer maintained, so I tried Leptos.

I liked writing regular HTML, struggled with the React inspired model, but finally bounced off the Rust syntax. A quote that sums it up for me:

Go is too simple to write complicated programs, while Rust is too complicated to write simple programs. It all depends which problem you’d rather have.
John Arundel

Elm Land

I really resonated with The Elm Architecture (TEA) in the past:

Thanks to the algebraic data types and pattern matching of Elm, it becomes possible to express valid application states purely with types1. Subsequently the compiler guides you through the actual implementation.

Elm’s latest release is six years old at this point. So at least there isn’t any churn. There is a somewhat active community. It is interesting to see that there is fork of the compiler and two languages descended from it: Gren and Roc.

Elm land brings some of the more recent web development patterns e.g components and file based routing to Elm. It was nice to come back to TEA, but having to write HTML with elm code was too much for me.

  div []
    [ button [ onClick Decrement ] [ text "-" ]
    , div [] [ text (String.fromInt count) ]
    , button [ onClick Increment ] [ text "+" ]
    ]

Also whenever you need to interact with browser features like local storage or service workers you need to write ports to go from Elm to JS and back.

Svelte

So back to the JS-ecosystem we so dearly love. Learning that Svelte had gone through a major change just over a year ago made sceptical. However, the resulting structure feels like a very elegant way of representing reactive state. Also the underlying philosophy playing nice with existing JS libraries makes it feel like an extension in capability (similar to TS) rather than a new language and ecosystem (looking at you JSX).

Searching for learning resources I found 7 GUIs. Working through them and then checking the corresponding Svelt walkthrough was a nice way to spend a day. Regardless of which GUI tooling you are using I’d highly recommend working through the 7 GUI tasks.

What really blew mind was creating an interactive SVG. Seeing circles change their size in real-time as I moved a slider did something to my brain. I think it was one of those moments where you realise that you can now make things you previously thought were out of reach. Or as others have put it:

Skill is the beginning of freedom.

My takeaways

The key takeaway of course is that quick and dirty becomes slow and tedious faster than you think.

Testable code leads to:

However it takes me a while to understand the problem domain and tooling enough to know how to structure my code into something testable.

Tools I’ll use moving forward

Threads to pull on

  1. Richard Feldman gave a great talk on this titled Making Impossible States Impossible. He is also the person behind Roc.