Spot is designed to be easy to use and provide a consistent API across different platforms (mainly Mac & Linux). It’s inspired by React, but written in Go, aiming to combine the best of both worlds: the easy tooling & performance of Go with a modern, reactive approach to UI development.
Key features:
- Cross-platform: Leveraging FLTK[1] & Cocoa[2], Spot works on Mac, Linux, and the BSDs with plans for native Windows support in the future.
- Reactive UI: Adopts a React-like model for building UIs, making it intuitive for those familiar with reactive frameworks.
- Traditional, native widget set: Utilizes native widgets where available to provide a more traditional look and feel.
Why I built it:
I was searching for a cross-platform GUI toolkit for Go that had a more traditional appearance, and none of the existing options quite met my needs. I then started playing with Gocoa and go-fltk and suddenly I worked on an experiment to see how challenging it would be to build something like React in Go, and it kinda evolved into Spot. ¯\_(ツ)_/¯
In 2024, is there a still place for classic desktop GUIs—even with a modern spin?
I’d love to hear your thoughts, feedback, and any suggestions for improvement. Also, contributions are very welcome.
Thank you for checking it out!
I'd seriously recommend that you consider cutting this. Perhaps keep the lessons you've learned to retain future flexibility, but get good on one toolkit first. GUI toolkits, GUI bindings, GUI in general drowns you in details as it is, volunteering to drown in several different underlying toolkit's details may sound appealing because you may feel like you're growing your metaphorical market, but what you will almost certainly end up with is doing all toolkits badly instead of even one toolkit well, and that won't be good.
We've all heard about how the first 90% is 90% of the work, and then the remaining 10% is another 90% of the work. GUIs make that look like hopeless pie-in-the-sky optimism, where the first 10% is 90% of the work, and then the next 10% is ten times the work, and then the next 10% is another ten times the work. Trying to be cross-platform will strangle you.
However, based on my experience with some similar previous discussions, I don't expect you to immediately buy and agree with my arguments. What I'll really suggest then is to keep what I've said here in the back of your mind, and when you find you're staring down the three toolkits that rigidly require a three-way mutually contradictory way of handling rich text or something, then think back to this post and consider giving yourself permission to drop all but the best-supported and/or most popular underlying toolkit.
I'm curious how you'll end up solving for cross-platform layout when native controls have different intrinsic sizes per platform?
This is something I haven't seen solved super well in cross platform toolkits.
Wishing you luck though.
For a native toolkit, I was impressed to see FLTK supports Ctrl-+ and Ctrl+- to zoom the entire application like a browser. And https://github.com/fltk-rs/fltk-theme?tab=readme-ov-file#wid... really improved my impression of how "native" FLTK can be made to look.
On a related note, I discovered GoVCL https://z-kit.cc/en/ recently and am interested to try it out.
Self-contained Spot "Hello World" is 2.3MiB on my Mac. Not pretty, but works for me.
With the reactive approach you are able to write a single rendering function that describes the interface for any given state and the framework takes care of the rest (when to call that function, what "input" to give it).
It's just way easier to wrap my head around this and after working with React it is hard to go back. Hence the experiment to see if something comparable could be done in Go.
TextBox { Text: app.currentUser.name }
Instead of having to call setText on that TextBox.
What I'm still missing is why it has to involve a virtual tree being maintained and synchronized with the real GUI tree. The UI engine could implement the above binding by instantiating for the user a callback trigerred when the bound property changes and changing precisely the value currently shown on the screen. Hence, the UI engine is in charge of the callbacks, which keeps the user unburdened by callbacks.
(Or at least, to paraphrase Joseph Heller, “it’s intuitive once you get your head around it”)
Using the virtual tree, you are able to build components which dynamically change the rendered subtree based on the current state.
The web had a lack of options for state management and hence React coupled the two.
Would you consider listing the supported platforms in the readme? I think that would be a pretty interesting piece of information:
- Windows
- Linux
- macOS
- *BSD
- Android
- iOS
- Web
- Tizen
Maybe like it's on flutter docs: https://docs.flutter.dev/reference/supported-platformsEventually found a way to do something similar using just the standard Go html/template.
I’ve written about the implementation here:
https://www.sheshbabu.com/posts/react-like-composition-using...
Wails is still pretty epic as well though.
Alternatively, something that targets many platforms, including mobile.
I've been searching for something for quite a while and the closest is qt and react native, both painful choices for various reasons
My (low prio, though) goal is to implement a Win32-based backend, though, the first step is done: https://github.com/roblillack/spot/pull/4
> https://github.com/roblillack/spot/blob/main/ui/init_fltk.go...
Does this imply GOMAXPROCS needs to be set to at least 2?
This is necessary for most UI libraries and in Spot's case implemented for both the FLTK and the Cocoa backend.
What does building for cross platform look like? Would love if there was a command that produced my MacOs .app and Windows exe without me having to dive into package management/containers/signing headaches per platform.
So you still need to have a build pipeline with multiple operating systems, signing/notarization tools, etc. :(
For macOS you need signing/notarization tools either when building natively or when cross-compiling, it's not any different. `rcodesign` has made this process much easier in recent years.
I swear half the electron apps use it for ease of Xplatform build.
I’d love something like this for giving my CLIs UIs.
If someone implements GTK I would absolutely use it, its just fltk is no fun in Linux world
https://github.com/fyne-io/fyne
for years but will check this out
( terminal but still great go guis:
https://github.com/gizak/termui
https://github.com/charmbracelet/bubbletea )
Never used but should be in this list:
I'm sure it has its perfect use cases, though.
Spot does not have any optimizations regarding render performance at the moment and it might never be necessary to add them.
On the other hand, due to the reactive programming model, I really like how state management get a lot clearer—especially when working with multiple goroutines.