> Experience has shown us that an immediate mode API is the only sane way to program GUI applications
I wonder how long till they pivot away from this belief. I feel like everyone in UI goes through this phase as some point, but in the end it doesn't scale to truly complicated UI
Yeah. Based on my personal experience I think the optimum probably is some kind of hybrid of old-school imperative retained and declarative retained, both with opt-in reactivity is probably the correct balance for "serious" high-utility desktop applications. Declarative approaches are great for smaller components but become a nightmare for anything much more complex than a relatively simple mobile app while imperative requires a lot of extra legwork at the component level, and as I understand (which may be incorrect) is that immediate mode makes certain types of optimization more difficult.
In my experience, it's the opposite. Immediate mode GUI, or at least a functional and declarative approach, is the only way I've seen it scale well. It's more modular and scale-independent. On the other hand, retained mode, or imperative/OOP approach to state management, becomes complicated and monstrous quickly; it's the dominant style and can be made to work OK, but typically hellish to maintain or develop beyond a certain scale.
Admittedly I'm simplifying too much and conflating paradigms. My preference is something like "functional core, imperative shell" or maybe "immediate-mode core, retained-mode shell" if that makes sense.
Obviously most GUIs are not nearly that complex so immediate mode can get you quite far. Its biggest limitation is that it makes it hard to do some layouts. Your GUI layout becomes dictated by your data dependencies which is quite awkward.
Absolutely zero difficulty redoing this in a react style renderer. The only complexity is being careful with your data dependencies so as to not needlessly rerender.
Each pane is easily isolated, can share data with a view model scoped properly, etc. Writing it in an imperative toolkit is a "oops I forgot to update my data here" kind of hell. Data binding makes it slightly less worse
> Absolutely zero difficulty redoing this in a react style renderer
I would not classify a react style renderer as "immediate mode". It has aesthetic similarities with IM GUIs, but ultimately there is a fully retained tree under the hood, that gets diffed/mutated on every update
it's very hard. These “change the entire world” commits make for a history that is impractical to follow for a human, and therefore of little interest to me.
I think a challenge for a vibe coded library to gain adoption is if there is a lack of human time investment in its creation, how do we know there will be investment in its maintenance?
Most open source projects are abandoned because the author never finds enough time to work on it or can't muster the focus and attention needed.
It is not true that there is "lack" of human investment in the creation of this. If anything, I spent the last two weeks glued to the screen most of the time, to a degree I have never experienced before, building out all the different areas that lead to this release.
I will not mention the monetary investment because it's not the type that matters here.
Attention, which is arguably the most scarce form of investment, was invested in ample amounts.
> I spent the last two weeks glued to the screen most of the time, to a degree I have never experienced before,
With respect, a single period of manic hyperfocus is not what makes a project, it is being in it for the long-haul and putting in the hours here and there even when it isn't fun any more and you have many other things you might rather be doing.
To be clear I don't want to detract from what you've made here. Agentic engineering done right does still require a lot time and attention IMO. But you've still got a challenge on your hands to demonstrate to potential adopters that you're in it for the long haul.
Source is the new binary. Specs and requirements are where the engineering is happening now. Of course, this was anticipated in 1971 with the creation of the very successful PRIDE methodology, but it's taken a few decades, and a complete devaluation of their profession due to AI, for programmers to catch up.
I understand the core is the layout engine and a component library? Does the rendering somehow benefit from GPU?
I recently had a good experience creating custom UI based on ebitengine — also a cross-platform Go engine. As it is a game engine, it has this built in game drawing loop, GPU-accelerated, with some cross-platform kb/mouse input handling. And this feels like a good platform to build the layout engine and components on top of. Have you ever considered this? Or how does your approach compare to that of ebitengine? Did you try (and do you position) your library to build custom UI for some underpowered computers such as Raspberry Pi?
they are useless too. 99.99999% of normal people do not open terminal in their entire life nor do not even know what that is. get out and touch grass, friends.
I had a look through the code to see how it manages not to use a pile of C libraries with cgo like other Go GUI libraries.
The answer is platform dependent:
Windows loads the relevant DLLs by hand and calls them. This is a well established technique in Go programs and due to the super stable DLL interface works well.
Linux has an x11 and Wayland backends and these implement (through a library) the wire protocols directly in Go which is nice and will make cross compilation and distribution easy.
macOS does appear to use cgo to access the cocoa libraries. macOS doesn't like statically linked Go programs anyway though as they don't use system name resolution so this isn't a bad compromise, but will mean macOS stuff needs to be built on macOS I think.
I didn't see Android or iOS support.
A nice innovative approach to GUI building. Since the lowest common denominator for the backends is an RGBA buffer, this will bypass all accessibility things the OS provides.
The above gleaned after a few minutes reading the source so may not be 100% accurate.
> Mobile is under consideration (no decision yet). If it is supported, it will be limited to utility-style apps — not games or rich multi-touch experiences.
No Multiple Windows so even desktop apps will be limited to "utility-style apps".
I compiled and ran the process_monitor example on linux: it works, compiles fast and is about 10mb. Also cross-built for windows and it's 8.4mb. Can't build for macos/arm64
Theres is another new project which does NOT rely on CGO https://github.com/gogpu/ui Its basically the whole WebGPU implemented in Go. Theres also Gio, but not sure if its still active. CGO is a huge pain…
> What is it that matters for "immediate mode"? Is it that the UI renders everything every frame? No. It's that you build the UI by describing what it should look like everyframe, based only (or mostly) on the data. This is why React won...
I don't think that's why React got so popular. React popularized unidirectional data flow, which is different than immediate mode rendering. This readme file seems to conflate the two of those.
Now that I think of it, couldn't one argue that React itself is a retained mode UI, since it choses which components to re-render and which not to?
Super vibe coded project still uses an LRU cache (github.com/dboslee/lru v0.0.1) as a dependency, this is exactly the things these llms were supposed to solve right, why the hell do people still add these 100 lines dependencies in their projects?
This looks better than the other native Go GUI frameworks. Frameworks like these are a really good target for coding agents: the biggest impediment to building a new UI framework is the sheer amount of meticulous grunt work needed. So, sure, I'm on board with the idea of languages not normally a perfect fit for native UI work getting solid, generated frameworks.
But: what's the real advantage at this point to having frameworks like these? I can get arbitrary SwiftUI interfaces built very quickly, with a lot of attention to macOS (for instance) idiom, and an automatically generated interface between the SwiftUI app and Go. That works pretty great. Why take the UX hit at all?
I think AIs generally "like" the API surface exposed by Shirei. They seem to understand it pretty well and are able to "vibe code" any kind of UI you ask of them using this framework.
To your general point though, yes, there's a lot of uncertainty about what things it makes sense to build in the AI era. I don't have good answers for what would make sense for 10 years down the road, but at this point of time, I think a project like this actually makes perfect sense.
Now that AI can write the code for us, we need better frameworks and libraries, because a lot of what we have now is quite honestly slop.
You could say that you could get AI to maintain 3 separate codebases of the same application UI, each one targeted to a different platform, and the AI will maintain the feature parity and you won't have to worry about it.
For now, AI can take care of coding, but it does not relieve you of having to pay attention to things. If you create 2 or 3 code bases for the different platforms you target, the maintenance burden still falls on you.
But I don't know for how long the situation will remain like this.
Last year I did not think I'd be using AI for coding. I dug up a few tweets I posted last year saying that LLMs have hit a plateau and will stop improving, and that AI coding is a scam being promoted by charlatans.
37 comments
[ 3.6 ms ] story [ 42.2 ms ] threadI wonder how long till they pivot away from this belief. I feel like everyone in UI goes through this phase as some point, but in the end it doesn't scale to truly complicated UI
Admittedly I'm simplifying too much and conflating paradigms. My preference is something like "functional core, imperative shell" or maybe "immediate-mode core, retained-mode shell" if that makes sense.
https://github.com/wolfpld/tracy
https://blog.reds.ch/wp-content/uploads/2018/09/questa13.png
Or something like Visual Studio.
Obviously most GUIs are not nearly that complex so immediate mode can get you quite far. Its biggest limitation is that it makes it hard to do some layouts. Your GUI layout becomes dictated by your data dependencies which is quite awkward.
Each pane is easily isolated, can share data with a view model scoped properly, etc. Writing it in an imperative toolkit is a "oops I forgot to update my data here" kind of hell. Data binding makes it slightly less worse
I would not classify a react style renderer as "immediate mode". It has aesthetic similarities with IM GUIs, but ultimately there is a fully retained tree under the hood, that gets diffed/mutated on every update
However, when the commit history has stuff like
it's very hard. These “change the entire world” commits make for a history that is impractical to follow for a human, and therefore of little interest to me.It is not true that there is "lack" of human investment in the creation of this. If anything, I spent the last two weeks glued to the screen most of the time, to a degree I have never experienced before, building out all the different areas that lead to this release.
I will not mention the monetary investment because it's not the type that matters here.
Attention, which is arguably the most scarce form of investment, was invested in ample amounts.
With respect, a single period of manic hyperfocus is not what makes a project, it is being in it for the long-haul and putting in the hours here and there even when it isn't fun any more and you have many other things you might rather be doing.
I recently had a good experience creating custom UI based on ebitengine — also a cross-platform Go engine. As it is a game engine, it has this built in game drawing loop, GPU-accelerated, with some cross-platform kb/mouse input handling. And this feels like a good platform to build the layout engine and components on top of. Have you ever considered this? Or how does your approach compare to that of ebitengine? Did you try (and do you position) your library to build custom UI for some underpowered computers such as Raspberry Pi?
> ebitengine
I have considered using it as a backend, but the blocker for me was how it handles resizing: the window content will stretch while it's being resized.
can I run it on Android? iOS?
no? then 99.999999% of real world users cannot access it. and if it is desktop oly, what is the point? it is no better than web.
The answer is platform dependent:
Windows loads the relevant DLLs by hand and calls them. This is a well established technique in Go programs and due to the super stable DLL interface works well.
Linux has an x11 and Wayland backends and these implement (through a library) the wire protocols directly in Go which is nice and will make cross compilation and distribution easy.
macOS does appear to use cgo to access the cocoa libraries. macOS doesn't like statically linked Go programs anyway though as they don't use system name resolution so this isn't a bad compromise, but will mean macOS stuff needs to be built on macOS I think.
I didn't see Android or iOS support.
A nice innovative approach to GUI building. Since the lowest common denominator for the backends is an RGBA buffer, this will bypass all accessibility things the OS provides.
The above gleaned after a few minutes reading the source so may not be 100% accurate.
https://judi.systems/shirei/
No Multiple Windows so even desktop apps will be limited to "utility-style apps".
I compiled and ran the process_monitor example on linux: it works, compiles fast and is about 10mb. Also cross-built for windows and it's 8.4mb. Can't build for macos/arm64
I don't think that's why React got so popular. React popularized unidirectional data flow, which is different than immediate mode rendering. This readme file seems to conflate the two of those.
Now that I think of it, couldn't one argue that React itself is a retained mode UI, since it choses which components to re-render and which not to?
But: what's the real advantage at this point to having frameworks like these? I can get arbitrary SwiftUI interfaces built very quickly, with a lot of attention to macOS (for instance) idiom, and an automatically generated interface between the SwiftUI app and Go. That works pretty great. Why take the UX hit at all?
To your general point though, yes, there's a lot of uncertainty about what things it makes sense to build in the AI era. I don't have good answers for what would make sense for 10 years down the road, but at this point of time, I think a project like this actually makes perfect sense.
Now that AI can write the code for us, we need better frameworks and libraries, because a lot of what we have now is quite honestly slop.
You could say that you could get AI to maintain 3 separate codebases of the same application UI, each one targeted to a different platform, and the AI will maintain the feature parity and you won't have to worry about it.
For now, AI can take care of coding, but it does not relieve you of having to pay attention to things. If you create 2 or 3 code bases for the different platforms you target, the maintenance burden still falls on you.
But I don't know for how long the situation will remain like this.
Last year I did not think I'd be using AI for coding. I dug up a few tweets I posted last year saying that LLMs have hit a plateau and will stop improving, and that AI coding is a scam being promoted by charlatans.