Benchmarks

Reproducible numbers, software-rendered, no GPU. Everything below is measured by the harness in tests/e2e/ and you can re-run it yourself.

Honest metric. We report unique_fps: genuinely distinct frames per second, counted with ffmpeg mpdecimate. A recording's nominal/container fps pads toward a minimum rate with duplicate frames, so it overstates motion and is not comparable across tools.

Recording throughput across CI runners

The same harness (tests/e2e/ci-bench.sh) recording a lossless FFV1 clip of an animated page, on three machines:

config (FFV1, software) GitLab
EPYC 7B13, 2 vCPU
GitHub
EPYC 7763, 4 vCPU
laptop
Ryzen 5700U, 16T
Chromium 720p whole-desktop10.010.19.9
Chromium 1080p whole-desktop9.79.99.9
Chromium 1080p focused-window15.536.343.2
KWrite 1080p whole-desktop7.67.88.0

Whole-desktop capture pins near 10 unique fps regardless of core count (2 → 4 → 16): it is bounded by synchronous frame readback on the compositor thread, not the CPU. Focused-window capture is several times faster and scales with the machine. Practical guidance: record a single app in --mode focused-window for the smoothest clip; whole-desktop is for capturing the broader session at a steady ~10 fps.

Lossless recording: waymux vs the standard X11 approach

Same machine, same page (the demanding software-WebGL waymux logo), 1280x720, 8 seconds, no GPU. waymux focused-window vs the usual headless-CI recipe (Xvfb + ffmpeg x11grab + x264 -qp 0). Unique fps on a 4-vCPU GitHub runner, before and after a recording-pipeline pass:

method (lossless)beforeafter
waymux focused-window (FFV1)6.55.8
waymux focused-window (x264-lossless)n/a11.1
Xvfb + ffmpeg x11grab (x264)10.610.8

The original FFV1 path lost to x11grab on a constrained runner (6.5 vs 10.6): FFV1 is a heavier CPU encoder, and the WebGL source already saturates the four cores, so multithreading FFV1 did not help here. Adding a CPU x264-lossless codec (libx264rgb, bit-exact RGB, fed bgr0 to skip a conversion, with a writer thread decoupling the pipe) closes the gap: waymux now matches x11grab (11.1 vs 10.8) at the same CPU and file size. The same parity holds on a 16-thread laptop (x264-lossless and x11grab within a frame of each other, both ahead of FFV1).

So you get x11grab-class lossless throughput and waymux's integration: Wayland-native, any app per-window, no Xvfb/ffmpeg plumbing, and recording paired with spawn, input, and screenshots in one tool. FFV1 stays the default for exact-pixel determinism; reach for --codec x264-lossless on small runners.

Reproduce it

No checkout needed: the published image carries the harness:

# recording throughput sweep (table 1)
docker run --rm --shm-size=512m -e RECORD_SECS=10 -e ARTIFACT_DIR=/out \
  -v "$PWD/out:/out" --entrypoint dbus-run-session \
  ghcr.io/waymux/waymux-ci -- bash /app/tests/e2e/ci-bench.sh
cat out/benchmark.md

The head-to-head additionally needs Xvfb (apt-get install -y xvfb inside the image); the GitHub workflow does exactly that and attaches both clips.

The test content

The head-to-head page is a glowing 3D w rendered in software WebGL (SwiftShader, no GPU), demanding enough to stress the full render + capture pipeline, and a fun thing to watch. Open it →