SwayFX: the i3 rules stay, the renderer changes, and the container pins an older tag
SwayFX: Sway, but with eye candy!
At a glance
- What is it?
- wlrfx/swayfx is a fork of the Sway Wayland compositor that drops the simple wlr_renderer for a GLES2 fx_renderer, adding blur, shadows, rounded corners and dimmed unfocused windows. The renderer swap is the whole idea, but the build recipes in the repository pull an older tag and source from a second account.
- Who is it for?
- SwayFX fits someone already running Sway who wants blur, shadows and rounded corners without giving up i3 style configuration, and who accepts that the fork tracks upstream wlroots itself.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- wlrfx/swayfx2,446 ★ · +52
| Repository | 2026-09-29 | 2026-11-14 |
|---|---|---|
| wlrfx/swayfx | 2.4k | 2.4k |
52 Stars in the last 46 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
One renderer is the entire fork
Sway is described upstream as restricted to only include the functionality that existed in i3. This fork changes a single component: it ditches the simple wlr_renderer and replaces it with fx_renderer, capable of rendering with GLES2 effects. Every advertised addition follows from that swap. The documented list is blur, anti-aliased rounded corners on borders and titlebars, shadows, dimming of unfocused windows, a scratchpad treated as minimize so that docks and panels carrying a taskbar interpret minimize and unminimize requests correctly, and a Nixified repository so NixOS users can contribute and test without assembling a shell by hand.
The numeric limits attached to those effects are where the fork draws its own boundaries. Blur takes between 0 and 10 passes and a radius from 0 to 10, with noise on a 0 to 1 scale and brightness, contrast and saturation each from 0 to 2. Shadows allow a blur radius from 0 to 99. Animations run from 0 to 5000 milliseconds. So blur gets a tenth of the radius range shadows get, and `shadow_offset <x offset> <y offset>` is the one shadow entry given without a documented range at all.
The container recipe pins 0.5.3 and names a second account
The build arguments in compose.yml freeze five versions for the image, and one of them is already behind the project's own releases.
services:
swayfxbuild:
container_name: swayfxbuild
build:
args:
WLROOTSVERSION: 0.19.0
WLROOTSLIBVERSION: 0.19
SWAYFXVERSION: 0.5.3
SCENEFXVERSION: 0.4.1
SCENEFXLIBVERSION: 0.4
OPT_SWAYFX: /opt
volumes:
- ./opt:/optRelease 0.6 is dated 2026-08-05 and the default branch was last pushed on 2026-09-27, so a container assembled from this file produces the 0.5.3 generation of the code against wlroots 0.19.0. Nothing in the file explains the lag or points at the newer tag.
The Dockerfile goes one step further. Its last RUN block begins fetching from `https://github.com/WillPower3309/swayfx/`, an account that is not the repository owner, and the file ends on that line: the closing quote, the tag, and anything following the download are simply not in it. The block above it pulls wlroots 0.19.0 as a tarball from the freedesktop GitLab. Anyone who trusts this recipe is combining four upstream projects, and one of the four sources is not the project the repository documents.
Container output lands in the checkout, then root copies it into /usr/local
The service mounts the host directory ./opt at /opt inside the container, so build artifacts appear inside the working tree instead of in a volume kept beside it. After the build, the documented procedure is three steps: start the container, become root, then read every file under opt/ and copy it to the matching path under /usr/local, stripping the opt prefix as it goes.
# build the container and run it (which builds SwayFX)
docker compose up --build
# become root to install the previously built files
sudo bash
# copy all files into the host file system at /usr/local/
while read -r FILE; do
NEW_FILE=/usr/local${FILE#opt}
NEW_DIR=$(dirname "${NEW_FILE}")
[[ -d ${NEW_DIR} ]] || mkdir -p "${NEW_DIR}"
echo "Creating '${NEW_FILE}'"
cp "${FILE}" "${NEW_FILE}"
done < <(command find opt/ -type f)The loop depends on bash process substitution and on dirname, so it will not survive a plain POSIX shell. It runs with root privileges on the host and creates destination directories as needed without asking, which means a half-finished image can overwrite system paths before anyone inspects what the image actually produced. The container also carries a fixed container_name of swayfxbuild, so two checkouts on one machine cannot build at the same time.
The scratchpad option ships with its own warning attached
Two of the new directives are described in terms of what they still get wrong. `scratchpad_minimize` turns the scratchpad into a minimize operation, which is what lets docks and panels carrying a taskbar read minimize and unminimize requests, an upstream problem tracked at swaywm/sway issue 6457. The help text for the option ends by asking that it be kept off, because there are many kinks to iron out here. `blur_xray` behaves the same way: it sets floating windows to blur against the background rather than against the windows below them, and its own description says you probably want it set to disable.
The configuration example then works against that advice. The layer_effects block offered for waybar switches blur_xray on among its five entries, so anyone copying it lands on the setting the option text steers them away from. A third entry carries a milder version of the same admission: `shadows_on_csd` draws the shadow against client-side decorations, and the note beside it says the shadow might not fit some windows.
swaymsg sets one effect per call, the config file sets five
Panel effects can arrive from the config file or from a running compositor, and the two paths do not have the same capacity. The config form accepts a block of effects for one layer namespace.
layer_effects "waybar" {
blur enable;
blur_xray enable;
blur_ignore_transparent enable;
shadows enable;
corner_radius 20;
}The runtime form is `swaymsg layer_effects "waybar" "blur enable"`, carrying the note that you can only set one effect at a time through swaymsg. That limit appears nowhere in the config form, so a panel that looks correct in the file can be reduced to a single effect by an external script.
Discovering namespaces also needs a filter tool.
swaymsg -r -t get_outputs | jq '.[0].layer_shell_surfaces | .[] | .namespace'A note beside that command says an application built against GTK is likely to register under gtk-layer-shell rather than under the program name. The available effects for a namespace are blur, blur_xray, blur_ignore_transparent, shadows, corner_radius and reset, where reset clears every effect previously applied to that layer.
A manual build names no wlroots version at all
The dependency list for a manual build names meson, wlroots, wayland, wayland-protocols, pcre2, json-c, pango, cairo and scenefx, with gdk-pixbuf2, swaybg, scdoc and git marked optional: gdk-pixbuf2 is there for additional system tray image formats and swaybg for the wallpaper. A footnote marks meson, wayland-protocols, scdoc and git as compile-time dependencies. scenefx is a second project under the same owner, so the GLES work this compositor is built on is maintained apart from the compositor itself.
Not one version constraint appears on any of them. wlroots is the dependency that moves fastest, and the container recipe shows the project treating 0.19.0 as its target, yet the manual path leaves the reader to match a renderer API surface by hand.
meson build/
ninja -C build/
sudo ninja -C build/ installThe trailing slashes and the build directory name are part of the documented commands. Installation writes straight into /usr/local and no prefix option appears in those three lines.
Without logind and without seatd, sway needs a setuid bit
On systems that have neither logind nor seatd there is no session service to hand the compositor its seat, and the documented workaround is to make the binary setuid.
sudo chmod a+s /usr/local/bin/swayThe line after it states that SwayFX will drop root privileges shortly after startup. That single sentence is the whole description: there is no platform condition attached to the chmod, no statement about what happens if the drop is delayed or fails, and no procedure for removing the bit afterwards. The manual steps place this note immediately after the install step, so anyone following them in order ends up holding a setuid compositor and has no documented way to tell whether that is the expected state on their distribution.
The path is hardcoded to /usr/local/bin/sway, so a build installed under a different prefix needs the command adjusted by hand.
The tree carries its own swaybar, swaymsg and swaynag
This repository is not only the compositor. Alongside sway/ it holds swaybar/, swaymsg/, swaynag/, client/, common/, completions/, protocols/, include/ and assets/, with sway.desktop, config.in, meson.build, meson_options.txt, build.sh, a flake and a Dockerfile at the root. The install step therefore writes four binaries whose names a Sway installation already owns, all into /usr/local, and the documented procedure offers no way to install this fork beside Sway rather than over it.
The contribution guide is equally specific about what belongs here. The stated preference is eye-candy type improvements, kept that way to hold the scope appropriate, and anything that might fall outside it should be raised as an issue first so it can be discussed before code exists. That is a sensible guardrail for a fork of this size, and it also tells a contributor in advance what will not be merged. The repository shows 172 open issues against 2401 stars and 125 forks, carries an MIT license, and uses master as its default branch.
Editorial conclusion
SwayFX fits someone already running Sway who wants blur, shadows and rounded corners without giving up i3 style configuration, and who accepts that the fork tracks upstream wlroots itself. Before adopting it, check which wlroots release the renderer code in the tree expects against the 0.19.0 the container pins, read the scratchpad_minimize text to the end rather than the first line, and decide whether panels will be styled from the config file or driven by swaymsg, because the two paths do not accept the same number of effects. If blur matters more than frame timing, verify it on your own graphics stack first, because no performance figures ship with any of these options.
Frequently asked questions
What are the differences between swayfx and sway?
SwayFX keeps the i3 era configuration and replaces one piece: the simple wlr_renderer is dropped for fx_renderer, which draws with GLES2 effects. On top of that swap it adds blur, anti-aliased rounded corners, shadows, dimming of unfocused windows, and a scratchpad treated as minimize. The GLES work lives in a separate project under the same owner, scenefx, which appears in the dependency list.
how to install swayfx on debian
The Debian route is not written inline; it points at a separate INSTALL-deb.md in the repository root. Nix users get nix build, ./result/bin/sway and nix develop. The container route needs docker compose up --build, then a root shell that copies everything under opt/ into /usr/local. The general route is meson build/, ninja -C build/ and sudo ninja -C build/ install, with no wlroots version named anywhere in it.
is swayfx stable
Two signals from the repository, with no test data attached to either. Release 0.6 is dated 2026-08-05 and the default branch was last pushed on 2026-09-27, while the help text for scratchpad_minimize asks that the option be kept off because there are many kinks to iron out. The repository shows 172 open issues. None of that says anything about your own hardware.
how to use swayfx
You run it as sway: the Nix path ends at ./result/bin/sway, and the setuid note names /usr/local/bin/sway. New directives go into the config, among them animation_duration_ms, corner_radius, default_dim_inactive, titlebar_separator and layer_effects for panels. Runtime changes use swaymsg layer_effects "waybar" "blur enable", and only one effect fits into a single swaymsg call.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/wlrfx-swayfx)Star history chart for your README
[](https://hysenlabs.com/projects/wlrfx-swayfx)Was this useful?