Headless mode
Runs NeferWL without a screen, for tests and quick checks:
neferwl --backend=headless --screenshot /tmp/neferwl-shots
WAYLAND_DISPLAY=<name from the log> foot
latest.png shows the current frame; frames.ffconcat records frame timing. Every frame is also saved as frame-NNNNNN.png, so the directory grows. latest.png is a hard link to the newest frame, so replace it rather than editing it in place.
--size 640x360,640x360 creates two outputs, arranged left to right,
for testing focus-monitor-left/right and moving columns between outputs.
- With several outputs, each writes to
<dir>/HEADLESS-<n>/.
--timeout 5s stops NeferWL after 5 seconds.
grim and recorders work too; see Screen capture.
Recording a video
Convert the screenshots and their real-time timing index into a video:
ffmpeg -f concat -safe 0 -i /tmp/shots/frames.ffconcat -vf "fps=60,format=yuv420p" -c:v libx264 -crf 18 demo.mp4
For a GIF, convert demo.mp4 with ffmpeg's palettegen and paletteuse filters.
Demo recording
Run tools/demo/record.sh. It requires Go 1.27, rootless Docker, ffmpeg, network access and an AMD GPU.
It builds the Arch image (apps, tesseract, AT-SPI) and the compositor binary, then records the 1080p README demo.
The compositor runs headless inside a disposable container, with the binary and a work directory bind-mounted and /dev/dri passed for the GPU.
The image only carries Mesa's radeon Vulkan driver, and hint scans need the sync files that a hardware driver exports; the script stops early without an AMD render node.
Firefox opens a live DuckDuckGo page, so the recording needs the network and its content varies.
A FIFO feeds input.txt while the script launches the apps on the same clock.
The hint step makes Firefox fullscreen and labels the page with hint; hint-click <words> then types the label of the link that shows those words, found from the scan's dump and an OCR read of the still page (hint-read).
The recording only counts if the compositor stops on the quit key that ends input.txt; reaching its --timeout first fails the run as truncated.
Temporary captures are removed by default; set KEEP_CAPTURE=1 to keep successful runs.
The recording and poster replace docs/media/demo.mp4 and docs/media/demo.png.
--input <file>, or --input - for stdin, plays one command per line:
| Command |
Effect |
type <text> |
Type text |
key Super+Return |
Press a key, with optional Shift, Ctrl, Alt or Super |
hold Super+h 1s |
Press a key like key, hold it, then release it |
press Super, release Super |
Hold or release a modifier across mouse actions (Super, Shift, Ctrl, Alt) |
sleep 1s |
Wait |
move <x> <y> |
Move the pointer, in output coordinates |
click [left|right|middle], down <button>, up <button> |
Mouse buttons |
swipe up|down|left|right |
Three-finger flick |
swipe4 up|down |
Four-finger flick |
examples/testime sends a preedit string, then commits text, each time an app enables text input:
WAYLAND_DISPLAY=<name> go run ./examples/testime -preedit nihon -commit 日本
-count <n> exits after n commits; -delay sets the time between preedit and commit.
Colour check
make color-check renders examples/testpattern on a headless output and checks the colours, in SDR and in HDR (--headless-hdr). It needs a GPU and /dev/udmabuf, and is not part of make check.
On a real screen, compare by eye:
WAYLAND_DISPLAY=<name> go run ./examples/testpattern -mode hdr -fullscreen # or -mode sdr
source
1# Headless mode
2
3Runs NeferWL without a screen, for tests and quick checks:
4
5```sh
6neferwl --backend=headless --screenshot /tmp/neferwl-shots
7WAYLAND_DISPLAY=<name from the log> foot
8```
9
10- `latest.png` shows the current frame; `frames.ffconcat` records frame timing. Every frame is also saved as `frame-NNNNNN.png`, so the directory grows. `latest.png` is a hard link to the newest frame, so replace it rather than editing it in place.
11- `--size 640x360,640x360` creates two outputs, arranged left to right,
12 for testing `focus-monitor-left/right` and moving columns between outputs.
13- With several outputs, each writes to `<dir>/HEADLESS-<n>/`.
14- `--timeout 5s` stops NeferWL after 5 seconds.
15- `grim` and recorders work too; see [Screen capture](../capture.md).
16
17## Recording a video
18
19Convert the screenshots and their real-time timing index into a video:
20
21```sh
22ffmpeg -f concat -safe 0 -i /tmp/shots/frames.ffconcat -vf "fps=60,format=yuv420p" -c:v libx264 -crf 18 demo.mp4
23```
24
25For a GIF, convert `demo.mp4` with ffmpeg's `palettegen` and `paletteuse` filters.
26
27### Demo recording
28Run `tools/demo/record.sh`. It requires Go 1.27, rootless Docker, ffmpeg, network access and an AMD GPU.
29It builds the Arch image (apps, tesseract, AT-SPI) and the compositor binary, then records the 1080p README demo.
30The compositor runs headless inside a disposable container, with the binary and a work directory bind-mounted and `/dev/dri` passed for the GPU.
31The image only carries Mesa's radeon Vulkan driver, and hint scans need the sync files that a hardware driver exports; the script stops early without an AMD render node.
32Firefox opens a live DuckDuckGo page, so the recording needs the network and its content varies.
33A FIFO feeds `input.txt` while the script launches the apps on the same clock.
34The hint step makes Firefox fullscreen and labels the page with `hint`; `hint-click <words>` then types the label of the link that shows those words, found from the scan's dump and an OCR read of the still page (`hint-read`).
35The recording only counts if the compositor stops on the quit key that ends `input.txt`; reaching its `--timeout` first fails the run as truncated.
36Temporary captures are removed by default; set `KEEP_CAPTURE=1` to keep successful runs.
37The recording and poster replace `docs/media/demo.mp4` and `docs/media/demo.png`.
38
39## Input scripts
40
41`--input <file>`, or `--input -` for stdin, plays one command per line:
42
43| Command | Effect |
44|---|---|
45| `type <text>` | Type text |
46| `key Super+Return` | Press a key, with optional Shift, Ctrl, Alt or Super |
47| `hold Super+h 1s` | Press a key like `key`, hold it, then release it |
48| `press Super`, `release Super` | Hold or release a modifier across mouse actions (`Super`, `Shift`, `Ctrl`, `Alt`) |
49| `sleep 1s` | Wait |
50| `move <x> <y>` | Move the pointer, in output coordinates |
51| `click [left\|right\|middle]`, `down <button>`, `up <button>` | Mouse buttons |
52| `swipe up\|down\|left\|right` | Three-finger flick |
53| `swipe4 up\|down` | Four-finger flick |
54
55## Testing input methods
56
57`examples/testime` sends a preedit string, then commits text, each time an app enables text input:
58
59```sh
60WAYLAND_DISPLAY=<name> go run ./examples/testime -preedit nihon -commit 日本
61```
62
63`-count <n>` exits after n commits; `-delay` sets the time between preedit and commit.
64
65## Colour check
66
67`make color-check` renders `examples/testpattern` on a headless output and checks the colours, in SDR and in HDR (`--headless-hdr`). It needs a GPU and `/dev/udmabuf`, and is not part of `make check`.
68
69On a real screen, compare by eye:
70
71```sh
72WAYLAND_DISPLAY=<name> go run ./examples/testpattern -mode hdr -fullscreen # or -mode sdr
73```