Go SLAY
Enjoy making utility style gui apps
SLAY is a Go framework to create GUI applications.
- Native. Real computer program (binary executable): not a "web page".
- Cross platform. Same codebase to produce programs for macOS, Windows, and Linux.
- No boilerplate setup. Just provide your root view function.
- Highly ergonomic. UI builder code does not have to be "noisy".
- Immediate mode style. Just describe what the GUI should look like. No need to create or manage "widget" objects.
- Practical. Tailored towards useful utility-style computer programs; multi-media and fancy graphics are de-prioritized.
- Robust text support, with complex script shaping, bidirectional layout, and access to system fonts.
- Flex-box style layout. Containers arrange items horizontally or vertically, with options for padding, gaps, alignment, wrapping, floating, scrolling, and size expansion.
SLAY is still work in progress!
Immediate mode
Practical experience has shown that an immediate mode API is the only sane way to build GUI applications.
No one wants to write code to keep track of UI widgets and bidirectionally mirror their state with their application data.
Unfortunately, there's a lot of misunderstanding about what immediate mode means, so let's clarify what it means for SLAY.
No widget state management
Your code does not need to care at all about UI widgets. You want to display a button and perform some action when it's clicked. You want to iterate some list and for each item render a custom view with buttons, labels, and various elements.
When your data changes, you don't want to track all the previously created widgets and mutate them manually to put them in sync. You just render the view again.
Widget state is managed by the system
Just because you don't manage widgets, doesn't mean they don't exist. The system knows about widgets and keeps track of their state for you. This means the system knows which elements can receive focus, so it can support cycling focus via the 'tab' key. It keeps track of text input fields so it can position the cursor, animate, apply selection, cut and paste, etc.
UI elements are assigned an automatic id based on their placement in the UI hierarchy, but the caller can override this by supplying their own ids.
When you supply an id for an element, it must be unique and stable.
Unique means no two elements produced in the same frame can share the same ID.
If two elements in the same view are assigned the same ID, the UI will behave erratically.
Stable means that you can use string literals, but should not use strings created dynamically on the fly.
Events don't require callbacks
Input device state is just data that UI code can query like any other data on the system:
- What's the current mouse position?
- What keys are currently down?
- What text input was made this frame?
- Did mouse button get clicked this frame?
- Did this keyboard key get released this frame?
etc
Animations
SLAY creates snappy animations when the UI state changes across frames, all without any boilerplate code on the caller side.
The animations are based on the IDs. If the position, size, or color of an element changes across frames, this change will be animated.
Demo
Here's a demo "todo" list view.
Below is the annotated backing code that produces the view.
You can see the following features:
- No boilerplate code, just set window title, size, and the view function
- Using regular variables to build the UI
- UI layout using a flex-box like system
- Updating regular variables directly inside the UI builder code
- No callbacks to set variables; just use pointers
- No callbacks to handle events; just ask for mouse/keyboard state
- Button widget returns
true
if it regsitered a click event this frame - TextInput widget takes a pointer to a string

Work in Progress
SLAY is still work in progress.
The "API" surface you see in the above demo is tentative and subject to change.