detached ade2f39

docs(readme): rework the pitch, why NeferWL and why Go (#88)

Replace the gaming tagline with one about performance, describe what is
left out and what moves, put the simple config forward, rename
"Why not Rust?" to "But why Go?" and answer the GC objection with
the allocation guards and reference numbers, and list every library
NeferWL grew, including go-wayland-bindings and neferclient.
commit
ade2f392facd709c224b86159509fe279662868f
author
bnema · · 2026-10-02 19:19 UTC
committer
GitHub · · 2026-10-02 19:19 UTC
parent
13c6a90
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
1 file · +20 -11
M README.md +20 -11
@@ -7,7 +7,7 @@
77 <a href="https://github.com/bnema/neferwl/stargazers"><img src="https://badgen.net/github/stars/bnema/neferwl?icon=github" alt="GitHub stars"></a>
88 </p>
99
10-<p align="center">A Wayland compositor for people who live in a terminal and die in games.</p>
10+<p align="center">A Wayland compositor that spends its frames on your apps, not on itself.</p>
1111
1212 > [!WARNING]
1313 > **Early alpha.** NeferWL is developed and tested mostly on AMD CPUs and GPUs. NVIDIA support is incomplete and untested; expect bugs and breaking config changes.
@@ -16,9 +16,11 @@
1616
1717 ## Why NeferWL
1818
19-NeferWL exists because I wanted a compositor that puts performance first and picks up new Wayland protocols and kernel features as soon as they land. Games get the whole GPU, and the compositor stays out of the way.
19+I wanted a compositor I would never have to think about. It takes the newest Wayland protocols and kernel features as they land, gives games the whole GPU, and otherwise stays out of sight.
2020
21-The design is deliberately small, and it will stay small: no animations, no themes, no built-in bar or wallpaper. Anything that adds latency or work per frame is left out. About 40–80 MB of RAM with two 4K monitors, and almost no CPU while the screen does not change.
21+It is small on purpose, and it will stay small. No blur, no shadows, no rounded corners, no themes, no built-in bar or wallpaper. The only motion is a touchpad swipe that follows your fingers, and a brief pulse on the window you just focused, which you can turn off. Anything else that costs a frame is left out. About 40–80 MB of RAM with two 4K monitors, and almost no CPU while the screen does not change.
22+
23+The config fits in your head: one `key = value` per line, every key has a default, and an empty file is a valid config. See [Configuration](#configuration).
2224
2325 ## Features
2426
@@ -28,7 +30,7 @@ The design is deliberately small, and it will stay small: no animations, no them
2830 - **Workspaces.** Numbered workspaces are created and removed as needed. Named workspaces declare their columns (width and command); NeferWL starts the commands and places each window.
2931 - **Multi-monitor.** Each output has its own workspaces. When an output is unplugged its workspaces move to another one, and return when it is plugged back. Fractional scale per output.
3032 - **External clients.** No built-in bar, launcher or notifications. Waybar, fuzzel, mako, nefercap, cliphist, swayidle, wlr-randr and input methods such as fcitx5 work through their standard protocols. See [Desktop integration](docs/desktop.md).
31-- **Config.** One `key = value` file, reloaded on save without closing windows. A JSON state file describes outputs, workspaces and windows for scripts.
33+- **Simple config.** One flat `key = value` file, reloaded on save without closing windows. A bad line only warns and keeps its default, and `neferwl validate-config` checks a file before you use it. A JSON state file describes outputs, workspaces and windows for scripts.
3234
3335 Config example:
3436
@@ -115,16 +117,23 @@ The file has one `key = value` per line, and `#` starts a comment. A missing fil
115117 - [Headless mode](docs/headless.md): run without a screen, take screenshots, play input scripts and test input methods.
116118 - [Performance](docs/performance.md): how to profile, the allocation guards, and reference numbers.
117119
118-## Why not Rust?
120+## But why Go?
121+
122+Most Wayland compositors are written in C (wlroots, Sway, Mutter), C++ (KWin, Hyprland, gamescope) or Rust (niri, COSMIC). The usual objection to Go is the garbage collector. It is a fair one, so here is how NeferWL deals with it.
119123
120-Most Wayland compositors are written in C (wlroots, Sway, Mutter), C++ (KWin, Hyprland, gamescope) or Rust (niri, COSMIC). NeferWL uses Go on purpose:
124+- **The hot path does not allocate.** Frame callbacks, presentation reports, DRM flips, Vulkan submissions and surface updates reuse memory owned by the goroutine that handles them. `make check` runs allocation guards that fail the build when one of these paths starts allocating.
125+- **The GC has almost nothing to collect.** Client buffers live in shared and GPU memory, not on the Go heap, so the live heap is a few megabytes. Playing a 4K HDR video with 65 tiled subsurfaces committing every frame, GC takes under 9 % of a process that itself takes 13 % of a core. See [Performance](docs/performance.md).
126+- **No cgo.** NeferWL builds with `CGO_ENABLED=0`. libwayland, Vulkan and libinput are loaded at runtime through [purego](https://github.com/ebitengine/purego) with fixed-arity calls: no reflection, no allocation at the boundary.
127+- **The concurrency model fits.** Input, each output and each client own their own state in their own goroutine, and talk over channels. There is no mutex on window state, and the race detector checks every test.
128+- **It is a pleasure to work on.** A full build takes seconds, and tests, race detection, profiling and formatting come with the language.
121129
122-- **Readable.** Go is small and explicit. Goroutines and channels fit a compositor where input, each output and the clients own their own state.
123-- **Tooling.** A full build takes seconds, and tests, the race detector, profiling and formatting come with the language.
124-- **No cgo.** NeferWL builds with `CGO_ENABLED=0`: libwayland, Vulkan and libinput are loaded at runtime through [purego](https://github.com/ebitengine/purego).
125-- **Speed.** With care for allocations and the garbage collector, input, rendering and buffer handling run close to native code.
130+I also like bringing more tools to the Go ecosystem. NeferWL grew its own libraries along the way, and other Go projects can use them:
126131
127-I like bringing more tools to the Go ecosystem. NeferWL grew its own libraries along the way, [purego-libwayland](https://github.com/bnema/purego-libwayland), [purego-vulkan](https://github.com/bnema/purego-vulkan) and [wlturbo](https://github.com/bnema/wlturbo), and other Go projects can use them.
132+- [purego-libwayland](https://github.com/bnema/purego-libwayland): libwayland-server without cgo.
133+- [purego-vulkan](https://github.com/bnema/purego-vulkan): Vulkan without cgo, generated from `vk.xml`.
134+- [go-wayland-bindings](https://github.com/bnema/go-wayland-bindings): Wayland protocol bindings, generated from the upstream XML.
135+- [wlturbo](https://github.com/bnema/wlturbo): a fast Wayland client.
136+- [neferclient](https://github.com/bnema/neferclient): a client toolkit on top of them: connection, outputs, surface roles, seat and dmabuf presentation.
128137
129138 ## Developing the bindings
130139
@@ -7,7 +7,7 @@
7 <a href="https://github.com/bnema/neferwl/stargazers"><img src="https://badgen.net/github/stars/bnema/neferwl?icon=github" alt="GitHub stars"></a>7 <a href="https://github.com/bnema/neferwl/stargazers"><img src="https://badgen.net/github/stars/bnema/neferwl?icon=github" alt="GitHub stars"></a>
8 </p>8 </p>
9 9
10-<p align="center">A Wayland compositor for people who live in a terminal and die in games.</p>10+<p align="center">A Wayland compositor that spends its frames on your apps, not on itself.</p>
11 11
12 > [!WARNING]12 > [!WARNING]
13 > **Early alpha.** NeferWL is developed and tested mostly on AMD CPUs and GPUs. NVIDIA support is incomplete and untested; expect bugs and breaking config changes.13 > **Early alpha.** NeferWL is developed and tested mostly on AMD CPUs and GPUs. NVIDIA support is incomplete and untested; expect bugs and breaking config changes.
@@ -16,9 +16,11 @@
16 16
17 ## Why NeferWL17 ## Why NeferWL
18 18
19-NeferWL exists because I wanted a compositor that puts performance first and picks up new Wayland protocols and kernel features as soon as they land. Games get the whole GPU, and the compositor stays out of the way.19+I wanted a compositor I would never have to think about. It takes the newest Wayland protocols and kernel features as they land, gives games the whole GPU, and otherwise stays out of sight.
20 20
21-The design is deliberately small, and it will stay small: no animations, no themes, no built-in bar or wallpaper. Anything that adds latency or work per frame is left out. About 40–80 MB of RAM with two 4K monitors, and almost no CPU while the screen does not change.21+It is small on purpose, and it will stay small. No blur, no shadows, no rounded corners, no themes, no built-in bar or wallpaper. The only motion is a touchpad swipe that follows your fingers, and a brief pulse on the window you just focused, which you can turn off. Anything else that costs a frame is left out. About 40–80 MB of RAM with two 4K monitors, and almost no CPU while the screen does not change.
22+
23+The config fits in your head: one `key = value` per line, every key has a default, and an empty file is a valid config. See [Configuration](#configuration).
22 24
23 ## Features25 ## Features
24 26
@@ -28,7 +30,7 @@ The design is deliberately small, and it will stay small: no animations, no them
28 - **Workspaces.** Numbered workspaces are created and removed as needed. Named workspaces declare their columns (width and command); NeferWL starts the commands and places each window.30 - **Workspaces.** Numbered workspaces are created and removed as needed. Named workspaces declare their columns (width and command); NeferWL starts the commands and places each window.
29 - **Multi-monitor.** Each output has its own workspaces. When an output is unplugged its workspaces move to another one, and return when it is plugged back. Fractional scale per output.31 - **Multi-monitor.** Each output has its own workspaces. When an output is unplugged its workspaces move to another one, and return when it is plugged back. Fractional scale per output.
30 - **External clients.** No built-in bar, launcher or notifications. Waybar, fuzzel, mako, nefercap, cliphist, swayidle, wlr-randr and input methods such as fcitx5 work through their standard protocols. See [Desktop integration](docs/desktop.md).32 - **External clients.** No built-in bar, launcher or notifications. Waybar, fuzzel, mako, nefercap, cliphist, swayidle, wlr-randr and input methods such as fcitx5 work through their standard protocols. See [Desktop integration](docs/desktop.md).
31-- **Config.** One `key = value` file, reloaded on save without closing windows. A JSON state file describes outputs, workspaces and windows for scripts.33+- **Simple config.** One flat `key = value` file, reloaded on save without closing windows. A bad line only warns and keeps its default, and `neferwl validate-config` checks a file before you use it. A JSON state file describes outputs, workspaces and windows for scripts.
32 34
33 Config example:35 Config example:
34 36
@@ -115,16 +117,23 @@ The file has one `key = value` per line, and `#` starts a comment. A missing fil
115 - [Headless mode](docs/headless.md): run without a screen, take screenshots, play input scripts and test input methods.117 - [Headless mode](docs/headless.md): run without a screen, take screenshots, play input scripts and test input methods.
116 - [Performance](docs/performance.md): how to profile, the allocation guards, and reference numbers.118 - [Performance](docs/performance.md): how to profile, the allocation guards, and reference numbers.
117 119
118-## Why not Rust?120+## But why Go?
121+
122+Most Wayland compositors are written in C (wlroots, Sway, Mutter), C++ (KWin, Hyprland, gamescope) or Rust (niri, COSMIC). The usual objection to Go is the garbage collector. It is a fair one, so here is how NeferWL deals with it.
119 123
120-Most Wayland compositors are written in C (wlroots, Sway, Mutter), C++ (KWin, Hyprland, gamescope) or Rust (niri, COSMIC). NeferWL uses Go on purpose:124+- **The hot path does not allocate.** Frame callbacks, presentation reports, DRM flips, Vulkan submissions and surface updates reuse memory owned by the goroutine that handles them. `make check` runs allocation guards that fail the build when one of these paths starts allocating.
125+- **The GC has almost nothing to collect.** Client buffers live in shared and GPU memory, not on the Go heap, so the live heap is a few megabytes. Playing a 4K HDR video with 65 tiled subsurfaces committing every frame, GC takes under 9 % of a process that itself takes 13 % of a core. See [Performance](docs/performance.md).
126+- **No cgo.** NeferWL builds with `CGO_ENABLED=0`. libwayland, Vulkan and libinput are loaded at runtime through [purego](https://github.com/ebitengine/purego) with fixed-arity calls: no reflection, no allocation at the boundary.
127+- **The concurrency model fits.** Input, each output and each client own their own state in their own goroutine, and talk over channels. There is no mutex on window state, and the race detector checks every test.
128+- **It is a pleasure to work on.** A full build takes seconds, and tests, race detection, profiling and formatting come with the language.
121 129
122-- **Readable.** Go is small and explicit. Goroutines and channels fit a compositor where input, each output and the clients own their own state.130+I also like bringing more tools to the Go ecosystem. NeferWL grew its own libraries along the way, and other Go projects can use them:
123-- **Tooling.** A full build takes seconds, and tests, the race detector, profiling and formatting come with the language.
124-- **No cgo.** NeferWL builds with `CGO_ENABLED=0`: libwayland, Vulkan and libinput are loaded at runtime through [purego](https://github.com/ebitengine/purego).
125-- **Speed.** With care for allocations and the garbage collector, input, rendering and buffer handling run close to native code.
126 131
127-I like bringing more tools to the Go ecosystem. NeferWL grew its own libraries along the way, [purego-libwayland](https://github.com/bnema/purego-libwayland), [purego-vulkan](https://github.com/bnema/purego-vulkan) and [wlturbo](https://github.com/bnema/wlturbo), and other Go projects can use them.132+- [purego-libwayland](https://github.com/bnema/purego-libwayland): libwayland-server without cgo.
133+- [purego-vulkan](https://github.com/bnema/purego-vulkan): Vulkan without cgo, generated from `vk.xml`.
134+- [go-wayland-bindings](https://github.com/bnema/go-wayland-bindings): Wayland protocol bindings, generated from the upstream XML.
135+- [wlturbo](https://github.com/bnema/wlturbo): a fast Wayland client.
136+- [neferclient](https://github.com/bnema/neferclient): a client toolkit on top of them: connection, outputs, surface roles, seat and dmabuf presentation.
128 137
129 ## Developing the bindings138 ## Developing the bindings
130 139

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 26

Tags 10

↑↓ moveenter openesc close