v0.6.1 aa12db3

README.md RawHistoryFolder

NeferGUI

A pure-Go GUI renderer for Linux: build your view from the current model, style it with CSS, and draw it with Vulkan into DMA-BUF buffers. Controls return events during the view call. No cgo required.

NeferGUI imports no Wayland library. Your application owns the Wayland client (connection, surface, linux-dmabuf feedback, buffer import, seat events) and drives a Renderer; github.com/bnema/neferclient is a client toolkit built for this. The two do not import each other: the application copies plain fields between them.

[!WARNING] Early development. No release yet. Expect bugs and breaking changes. Platform accessibility is not connected.

A small example

The view is plain Go. The model type is yours.

type Model struct{ Count int }

view := func(f *nefergui.Frame, m *Model) {
	root := f.Root().Column()
	root.Text("Hello, Wayland!")
	if root.Button("Count", nefergui.Key("count")).Activated() {
		m.Count++
	}
	root.Text(fmt.Sprintf("Clicked %d times", m.Count))
}

The client loop, on one owner goroutine:

r, err := nefergui.NewRenderer(nefergui.RendererConfig{MainDevice: dev, Formats: formats})
r.Resize(320, 200, 1)          // on configure and scale changes
r.Input(&nefergui.Input{...})  // for each pointer, key and focus event

var out nefergui.Output
if ok, err := r.Render(&out, &model, view); ok && err == nil {
	// import out.Planes as a wl_buffer when out.NewBuffer, attach with the
	// acquire/release points, commit
}
r.Released(buffer) // when out.ReleaseFD becomes readable

RendererConfig.Styles loads your own CSS; default styles work without it. See ExampleRenderer and runtime for the full contract.

Demo

examples/demo is a document workspace (toolbar, document list, text editor, properties pane, light and dark themes) in a Wayland window, using neferclient as the client. It lives in its own module, so NeferGUI does not depend on neferclient, and it always builds against the NeferGUI code in this checkout:

cd examples && go run ./demo

Requirements

Go 1.27, libvulkan.so.1 and usable fonts. The GPU must export DMA-BUF and support DRM syncobj timelines (kernel 6.6 or later for eventfd waits). The compositor, reached through your Wayland client, must offer linux-dmabuf and linux-drm-syncobj; fractional scaling also needs viewporter. No X11 or software-rendering fallback.

go get github.com/bnema/nefergui

Documentation

License

GNU GPL v3. Third-party code and test fonts retain their own licenses and attribution.

source
1# NeferGUI
2
3A pure-Go GUI renderer for Linux: build your view from the current model, style it with CSS, and draw it with Vulkan into DMA-BUF buffers. Controls return events during the view call. No cgo required.
4
5NeferGUI imports no Wayland library. Your application owns the Wayland client (connection, surface, linux-dmabuf feedback, buffer import, seat events) and drives a `Renderer`; [github.com/bnema/neferclient](https://github.com/bnema/neferclient) is a client toolkit built for this. The two do not import each other: the application copies plain fields between them.
6
7> [!WARNING]
8> **Early development.** No release yet. Expect bugs and breaking changes. Platform accessibility is not connected.
9
10## A small example
11
12The view is plain Go. The model type is yours.
13
14```go
15type Model struct{ Count int }
16
17view := func(f *nefergui.Frame, m *Model) {
18	root := f.Root().Column()
19	root.Text("Hello, Wayland!")
20	if root.Button("Count", nefergui.Key("count")).Activated() {
21		m.Count++
22	}
23	root.Text(fmt.Sprintf("Clicked %d times", m.Count))
24}
25```
26
27The client loop, on one owner goroutine:
28
29```go
30r, err := nefergui.NewRenderer(nefergui.RendererConfig{MainDevice: dev, Formats: formats})
31r.Resize(320, 200, 1)          // on configure and scale changes
32r.Input(&nefergui.Input{...})  // for each pointer, key and focus event
33
34var out nefergui.Output
35if ok, err := r.Render(&out, &model, view); ok && err == nil {
36	// import out.Planes as a wl_buffer when out.NewBuffer, attach with the
37	// acquire/release points, commit
38}
39r.Released(buffer) // when out.ReleaseFD becomes readable
40```
41
42`RendererConfig.Styles` loads your own CSS; default styles work without it. See `ExampleRenderer` and [runtime](docs/runtime.md) for the full contract.
43
44## Demo
45
46[`examples/demo`](examples/demo) is a document workspace (toolbar, document list, text editor, properties pane, light and dark themes) in a Wayland window, using neferclient as the client. It lives in its own module, so NeferGUI does not depend on neferclient, and it always builds against the NeferGUI code in this checkout:
47
48```sh
49cd examples && go run ./demo
50```
51
52## Requirements
53
54Go 1.27, `libvulkan.so.1` and usable fonts. The GPU must export DMA-BUF and support DRM syncobj timelines (kernel 6.6 or later for eventfd waits). The compositor, reached through your Wayland client, must offer linux-dmabuf and linux-drm-syncobj; fractional scaling also needs viewporter. No X11 or software-rendering fallback.
55
56```sh
57go get github.com/bnema/nefergui
58```
59
60## Documentation
61
62- [Controls](docs/controls.md) and [layout](docs/layout.md)
63- [CSS properties and limitations](docs/css.md)
64- [Runtime requirements and behavior](docs/runtime.md) and [troubleshooting](docs/troubleshooting.md)
65- [Performance](docs/performance.md)
66- [Architecture decisions](docs/adr)
67
68## License
69
70[GNU GPL v3](LICENSE). Third-party code and test fonts retain their own licenses and attribution.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 12

↑↓ moveenter openesc close