docs(readme): list features by category and rewrite the motivation (#24)
Add a Features section that lists everything NeferWL supports today (windows and workspaces, displays, games, desktop integration), including HDR, output management, scale persistence, ext-workspace, screencopy and the systemd session. Rewrite Why NeferWL around performance-first design and early protocol adoption, and drop the borrow checker paragraph.
- commit
- 21a6d9ac7b28d8c79f844bc67a96040b1f013b13
- author
- bnema · · 2026-09-27 16:02 UTC
- committer
- GitHub · · 2026-09-27 16:02 UTC
- parent
- 3c68abd
- signature
- GPG Unverified
B5690EEEBB952194The key is unknown
1 file · +37 -9
M README.md +37 -9
| @@ -16,17 +16,45 @@ | |||
| 16 | 16 | ||
| 17 | 17 | ## Why NeferWL | |
| 18 | 18 | ||
| 19 | - | NeferWL has no animations, themes, built-in bar or wallpaper, by design. The compositor stays small so the CPU and GPU go to your terminal and your games. | |
| 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: direct scanout, tearing, VRR, explicit sync and HDR are in from the start. | |
| 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. NeferWL uses about 40–80 MB of RAM with two 4K monitors and almost no CPU while the screen does not change. | |
| 22 | + | ||
| 23 | + | ## Features | |
| 24 | + | ||
| 25 | + | ### Windows and workspaces | |
| 20 | 26 | ||
| 21 | 27 | - **Terminal first.** NeferWL opens your terminal at startup. Bars, launchers and notifications are external clients such as Waybar, fuzzel and mako. | |
| 22 | - | - **Column tiling.** Up to `max-columns` windows share the screen, as in Sway. Past that, new columns scroll to the right as in Niri, or split in a spiral with `overflow = fixed`. Each workspace can set its own rules. | |
| 28 | + | - **Column tiling.** Up to `max-columns` windows share the screen, as in Sway. Past that, new columns scroll to the right as in Niri, or split in a spiral with `overflow = fixed`. Each monitor and workspace can set its own rules. | |
| 23 | 29 | - **Custom workspaces.** Numbered workspaces appear and disappear as you use them. Named workspaces are outside the numbered list and shown through a bind. **Slots** declare a workspace's columns (width and command): NeferWL starts the apps in the background and puts each window in its column. | |
| 30 | + | - **Window moves.** Move a column or a single window to another workspace or monitor, stack a window into the neighbor column or pull it out, and cycle column widths. | |
| 31 | + | - **Vim keys.** Every arrow bind has an `hjkl` twin. | |
| 32 | + | - **Live config.** One `key = value` file. Every key applies when you save, keyboard layout included, and windows stay open. `neferwl validate-config` checks a file before you use it. | |
| 33 | + | ||
| 34 | + | ### Displays | |
| 35 | + | ||
| 24 | 36 | - **Multi-monitor.** Each monitor has its own workspaces. When you unplug a monitor, its workspaces move to another one; when you plug it back, they return, and your focus stays where it was. | |
| 25 | - | - **Games.** A fullscreen game is shown without composition, with tearing and VRR when the game asks for them. Details are in [the performance path](#the-performance-path). | |
| 26 | - | - **Low footprint.** About 40–80 MB of RAM with two 4K monitors, and almost no CPU while the screen does not change. | |
| 27 | - | - **Live config.** One `key = value` file. Every key applies when you save, keyboard layout included, and windows stay open. | |
| 37 | + | - **HDR.** HDR10 output on capable displays. HDR games, browsers and video players show their full range, and the desktop stays SDR at a brightness you choose. See [HDR](docs/config.md#hdr). | |
| 38 | + | - **Scaling.** Fractional scale per output, sent to clients through `wp_fractional_scale_v1` and `wp_viewporter` so text stays sharp. Zooming with a bind saves the new scale to your config. | |
| 39 | + | - **Output tools.** `wlr-output-management` lets tools such as wlr-randr and kanshi change modes, scale and position. | |
| 40 | + | ||
| 41 | + | ### Games | |
| 28 | 42 | ||
| 29 | - | An example config: | |
| 43 | + | A fullscreen game is shown without composition, with tearing and VRR when the game asks for them. Steam and Wine run through xwayland-satellite. Details are in [the performance path](#the-performance-path). | |
| 44 | + | ||
| 45 | + | ### Desktop integration | |
| 46 | + | ||
| 47 | + | - **Bars.** `ext-workspace-v1` for Waybar and ironbar, plus layer shell. | |
| 48 | + | - **Screenshots.** grim and slurp work through screencopy and image copy capture. | |
| 49 | + | - **Clipboard.** Clipboard, primary selection and clipboard managers such as cliphist. See [Clipboard](#clipboard). | |
| 50 | + | - **Idle.** swayidle and wlopm turn screens off; a video or a game keeps them on. See [Idle and screen off](#idle-and-screen-off). | |
| 51 | + | - **systemd session.** The NeferWL session starts `graphical-session.target`, so bars, portals and XDG autostart start and stop with it. | |
| 52 | + | - **Focus requests.** `xdg_activation_v1` lets a launcher or notification focus the window it opens. | |
| 53 | + | - **Cursors and input tools.** Client cursor shapes (`wp_cursor_shape_v1`) and virtual keyboards for tools such as wtype. | |
| 54 | + | - **Scripting.** A JSON state file lists outputs, workspaces and windows. See [State for scripts](#state-for-scripts). | |
| 55 | + | - **Headless mode.** Runs without a screen, takes screenshots and plays input scripts, for tests and quick checks. See [Try it](#try-it-headless). | |
| 56 | + | ||
| 57 | + | ### Example config | |
| 30 | 58 | ||
| 31 | 59 | ```text | |
| 32 | 60 | keyboard.layout = fr | |
| @@ -47,7 +75,7 @@ bind.cmd+d = workspace dev | |||
| 47 | 75 | ||
| 48 | 76 | The terminal command comes from `terminal`, then `$TERMINAL`, then `foot`. `terminal.auto-open = first` opens it once on the initial numbered workspace; `all` opens it on each visible empty workspace without slots, and `off` disables automatic opening. `--no-terminal` overrides automatic opening for one run; `spawn-terminal` still works. Launched programs inherit `$SHELL`, `$EDITOR`, and `$VISUAL`. | |
| 49 | 77 | ||
| 50 | - | ### The performance path | |
| 78 | + | ## The performance path | |
| 51 | 79 | ||
| 52 | 80 | These protocols and kernel features cut copies, waits and latency between the app and the screen: | |
| 53 | 81 | ||
| @@ -161,6 +189,8 @@ startup = swayidle -w timeout 300 wlopm-off resume wlopm-on | |||
| 161 | 189 | exec wlopm --off '*' | |
| 162 | 190 | ``` | |
| 163 | 191 | ||
| 192 | + | ## Bars | |
| 193 | + | ||
| 164 | 194 | NeferWL supports `ext_workspace_manager_v1` for bars such as Waybar 0.13+ (`ext/workspaces`) and ironbar. Bars receive workspace updates and can switch workspaces without polling. | |
| 165 | 195 | ||
| 166 | 196 | ## State for scripts | |
| @@ -212,8 +242,6 @@ Most Wayland compositors are written in C (wlroots, Sway, Mutter), C++ (KWin, Hy | |||
| 212 | 242 | ||
| 213 | 243 | 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. | |
| 214 | 244 | ||
| 215 | - | Go has no borrow checker, so the compiler does not catch memory and concurrency mistakes as Rust's does. NeferWL compensates with strict ownership (one goroutine owns each piece of state), the race detector on every test run, and protocol tests against real Wayland clients. | |
| 216 | - | ||
| 217 | 245 | ## Developing the bindings | |
| 218 | 246 | ||
| 219 | 247 | NeferWL uses tagged releases of [purego-libwayland](https://github.com/bnema/purego-libwayland) and [purego-vulkan](https://github.com/bnema/purego-vulkan). To change a binding and NeferWL together, clone the binding next to NeferWL and use a Go workspace, which is not committed: | |
| @@ -16,17 +16,45 @@ | |||||
| 16 | 16 | ||||
| 17 | ## Why NeferWL | 17 | ## Why NeferWL | ||
| 18 | 18 | ||||
| 19 | - | NeferWL has no animations, themes, built-in bar or wallpaper, by design. The compositor stays small so the CPU and GPU go to your terminal and your games. | 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: direct scanout, tearing, VRR, explicit sync and HDR are in from the start. |
| 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. NeferWL uses about 40–80 MB of RAM with two 4K monitors and almost no CPU while the screen does not change. | |||
| 22 | + | ||||
| 23 | + | ## Features | |||
| 24 | + | ||||
| 25 | + | ### Windows and workspaces | |||
| 20 | 26 | ||||
| 21 | - **Terminal first.** NeferWL opens your terminal at startup. Bars, launchers and notifications are external clients such as Waybar, fuzzel and mako. | 27 | - **Terminal first.** NeferWL opens your terminal at startup. Bars, launchers and notifications are external clients such as Waybar, fuzzel and mako. | ||
| 22 | - | - **Column tiling.** Up to `max-columns` windows share the screen, as in Sway. Past that, new columns scroll to the right as in Niri, or split in a spiral with `overflow = fixed`. Each workspace can set its own rules. | 28 | + | - **Column tiling.** Up to `max-columns` windows share the screen, as in Sway. Past that, new columns scroll to the right as in Niri, or split in a spiral with `overflow = fixed`. Each monitor and workspace can set its own rules. |
| 23 | - **Custom workspaces.** Numbered workspaces appear and disappear as you use them. Named workspaces are outside the numbered list and shown through a bind. **Slots** declare a workspace's columns (width and command): NeferWL starts the apps in the background and puts each window in its column. | 29 | - **Custom workspaces.** Numbered workspaces appear and disappear as you use them. Named workspaces are outside the numbered list and shown through a bind. **Slots** declare a workspace's columns (width and command): NeferWL starts the apps in the background and puts each window in its column. | ||
| 30 | + | - **Window moves.** Move a column or a single window to another workspace or monitor, stack a window into the neighbor column or pull it out, and cycle column widths. | |||
| 31 | + | - **Vim keys.** Every arrow bind has an `hjkl` twin. | |||
| 32 | + | - **Live config.** One `key = value` file. Every key applies when you save, keyboard layout included, and windows stay open. `neferwl validate-config` checks a file before you use it. | |||
| 33 | + | ||||
| 34 | + | ### Displays | |||
| 35 | + | ||||
| 24 | - **Multi-monitor.** Each monitor has its own workspaces. When you unplug a monitor, its workspaces move to another one; when you plug it back, they return, and your focus stays where it was. | 36 | - **Multi-monitor.** Each monitor has its own workspaces. When you unplug a monitor, its workspaces move to another one; when you plug it back, they return, and your focus stays where it was. | ||
| 25 | - | - **Games.** A fullscreen game is shown without composition, with tearing and VRR when the game asks for them. Details are in [the performance path](#the-performance-path). | 37 | + | - **HDR.** HDR10 output on capable displays. HDR games, browsers and video players show their full range, and the desktop stays SDR at a brightness you choose. See [HDR](docs/config.md#hdr). |
| 26 | - | - **Low footprint.** About 40–80 MB of RAM with two 4K monitors, and almost no CPU while the screen does not change. | 38 | + | - **Scaling.** Fractional scale per output, sent to clients through `wp_fractional_scale_v1` and `wp_viewporter` so text stays sharp. Zooming with a bind saves the new scale to your config. |
| 27 | - | - **Live config.** One `key = value` file. Every key applies when you save, keyboard layout included, and windows stay open. | 39 | + | - **Output tools.** `wlr-output-management` lets tools such as wlr-randr and kanshi change modes, scale and position. |
| 40 | + | ||||
| 41 | + | ### Games | |||
| 28 | 42 | ||||
| 29 | - | An example config: | 43 | + | A fullscreen game is shown without composition, with tearing and VRR when the game asks for them. Steam and Wine run through xwayland-satellite. Details are in [the performance path](#the-performance-path). |
| 44 | + | ||||
| 45 | + | ### Desktop integration | |||
| 46 | + | ||||
| 47 | + | - **Bars.** `ext-workspace-v1` for Waybar and ironbar, plus layer shell. | |||
| 48 | + | - **Screenshots.** grim and slurp work through screencopy and image copy capture. | |||
| 49 | + | - **Clipboard.** Clipboard, primary selection and clipboard managers such as cliphist. See [Clipboard](#clipboard). | |||
| 50 | + | - **Idle.** swayidle and wlopm turn screens off; a video or a game keeps them on. See [Idle and screen off](#idle-and-screen-off). | |||
| 51 | + | - **systemd session.** The NeferWL session starts `graphical-session.target`, so bars, portals and XDG autostart start and stop with it. | |||
| 52 | + | - **Focus requests.** `xdg_activation_v1` lets a launcher or notification focus the window it opens. | |||
| 53 | + | - **Cursors and input tools.** Client cursor shapes (`wp_cursor_shape_v1`) and virtual keyboards for tools such as wtype. | |||
| 54 | + | - **Scripting.** A JSON state file lists outputs, workspaces and windows. See [State for scripts](#state-for-scripts). | |||
| 55 | + | - **Headless mode.** Runs without a screen, takes screenshots and plays input scripts, for tests and quick checks. See [Try it](#try-it-headless). | |||
| 56 | + | ||||
| 57 | + | ### Example config | |||
| 30 | 58 | ||||
| 31 | ```text | 59 | ```text | ||
| 32 | keyboard.layout = fr | 60 | keyboard.layout = fr | ||
| @@ -47,7 +75,7 @@ bind.cmd+d = workspace dev | |||||
| 47 | 75 | ||||
| 48 | The terminal command comes from `terminal`, then `$TERMINAL`, then `foot`. `terminal.auto-open = first` opens it once on the initial numbered workspace; `all` opens it on each visible empty workspace without slots, and `off` disables automatic opening. `--no-terminal` overrides automatic opening for one run; `spawn-terminal` still works. Launched programs inherit `$SHELL`, `$EDITOR`, and `$VISUAL`. | 76 | The terminal command comes from `terminal`, then `$TERMINAL`, then `foot`. `terminal.auto-open = first` opens it once on the initial numbered workspace; `all` opens it on each visible empty workspace without slots, and `off` disables automatic opening. `--no-terminal` overrides automatic opening for one run; `spawn-terminal` still works. Launched programs inherit `$SHELL`, `$EDITOR`, and `$VISUAL`. | ||
| 49 | 77 | ||||
| 50 | - | ### The performance path | 78 | + | ## The performance path |
| 51 | 79 | ||||
| 52 | These protocols and kernel features cut copies, waits and latency between the app and the screen: | 80 | These protocols and kernel features cut copies, waits and latency between the app and the screen: | ||
| 53 | 81 | ||||
| @@ -161,6 +189,8 @@ startup = swayidle -w timeout 300 wlopm-off resume wlopm-on | |||||
| 161 | exec wlopm --off '*' | 189 | exec wlopm --off '*' | ||
| 162 | ``` | 190 | ``` | ||
| 163 | 191 | ||||
| 192 | + | ## Bars | |||
| 193 | + | ||||
| 164 | NeferWL supports `ext_workspace_manager_v1` for bars such as Waybar 0.13+ (`ext/workspaces`) and ironbar. Bars receive workspace updates and can switch workspaces without polling. | 194 | NeferWL supports `ext_workspace_manager_v1` for bars such as Waybar 0.13+ (`ext/workspaces`) and ironbar. Bars receive workspace updates and can switch workspaces without polling. | ||
| 165 | 195 | ||||
| 166 | ## State for scripts | 196 | ## State for scripts | ||
| @@ -212,8 +242,6 @@ Most Wayland compositors are written in C (wlroots, Sway, Mutter), C++ (KWin, Hy | |||||
| 212 | 242 | ||||
| 213 | 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. | 243 | 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. | ||
| 214 | 244 | ||||
| 215 | - | Go has no borrow checker, so the compiler does not catch memory and concurrency mistakes as Rust's does. NeferWL compensates with strict ownership (one goroutine owns each piece of state), the race detector on every test run, and protocol tests against real Wayland clients. | |||
| 216 | - | ||||
| 217 | ## Developing the bindings | 245 | ## Developing the bindings | ||
| 218 | 246 | ||||
| 219 | NeferWL uses tagged releases of [purego-libwayland](https://github.com/bnema/purego-libwayland) and [purego-vulkan](https://github.com/bnema/purego-vulkan). To change a binding and NeferWL together, clone the binding next to NeferWL and use a Go workspace, which is not committed: | 247 | NeferWL uses tagged releases of [purego-libwayland](https://github.com/bnema/purego-libwayland) and [purego-vulkan](https://github.com/bnema/purego-vulkan). To change a binding and NeferWL together, clone the binding next to NeferWL and use a Go workspace, which is not committed: | ||