Layer Rules
Match layer-shell roots by namespace and current layer, then apply live root or popup appearance.
sweets.layer_rule({ ... }) selects live compositor appearance for layer-shell
roots such as panels, launchers, notification surfaces, and wallpapers. Layer
rules are separate from window rules because layer surfaces have a different
identity and do not use window opening policy.
sweets.layer_rule({
namespace = "rofi",
layer = "overlay",
opacity = 0.92,
blur = true,
blur_mode = "optimized",
blur_ignore_alpha = 0.35,
popups = { opacity = 0.85, blur = true, corner_radius = 12 },
})Rules are optional. An unmatched layer root uses compositor opacity 1.0, does
not receive compositor-forced blur, and keeps normal client and protocol
behavior.
Matchers
Every rule requires at least one matcher and at least one appearance property. When both matchers are present, both must match the same layer root.
| Field | Type | Matches |
|---|---|---|
namespace | string | The namespace supplied by the layer-shell client |
layer | string | The current committed "background", "bottom", "top", or "overlay" layer |
Matching is exact and case-sensitive. Sweets does not interpret substrings,
globs, regular expressions, or Lua callbacks. namespace cannot be empty.
Namespace is fixed for the layer surface's lifetime. A client may commit a new
layer; Sweets then updates the typed identity and re-resolves the current rules.
For example, a namespace-only rule keeps matching if the client moves between
bottom and top, while a rule containing layer = "top" follows its current
layer.
Appearance properties
| Field | Type | Effect when specified |
|---|---|---|
opacity | number | Whole-root opacity from 0.0 through 1.0 |
blur | boolean | Force or suppress blur for the matching root tree |
blur_mode | string | Override the global mode with "optimized" or "scene" |
blur_ignore_alpha | number | Suppress forced blur where composed client alpha is at or below 0.0 through 1.0 |
popups | table | Descendant XDG popup opacity, blur, and blur_mode |
Opacity multiplies the root and all its ordinary subsurfaces once. Independent
XDG popups are not part of that multiplier. A value of 0.0 makes the root
tree invisible without unmapping it: layout, exclusive zones, keyboard
interactivity, pointer hit testing, and client protocol state remain unchanged.
Blur is independent from transparency and still requires the global
sweets.blur master switch.
blur_mode changes the source used by an active effect but does not enable an
effect by itself.
blur_ignore_alpha shapes compositor-forced blur from the visible client
pixels. It is useful for launchers that own a full-output transparent surface.
The threshold uses client alpha before the rule's opacity multiplier:
sweets.layer_rule({
namespace = "rofi",
blur = true,
blur_ignore_alpha = 0.35,
})0.0 excludes only fully transparent pixels. Higher values can also remove
faint shadows. Omit the field to blur the complete arranged root geometry.
sweets.blur({
enabled = true,
mode = "optimized",
strength = 8,
noise = 0.02,
})
sweets.layer_rule({
namespace = "waybar",
opacity = 0.9,
blur = true,
})blur = true supplies a whole-root effect when the root and ordinary
subsurface tree has no non-empty client-requested blur region. A non-empty
client region remains authoritative and retains its exact shape. blur = false
vetoes client-requested blur in that root tree. The resolved blur_mode applies
to either form. blur_ignore_alpha affects only the compositor-forced form.
Role popups remain independent from root opacity, force, veto, mode, and alpha
masking. A nested popups block styles every descendant XDG popup:
sweets.layer_rule({
namespace = "waybar",
popups = {
opacity = 0.85,
blur = true,
blur_mode = "scene",
corner_radius = 12,
},
})The popup opacity does not multiply root opacity. It preserves popup placement,
focus, grabs, input, and mapping, including at 0.0. Input-method popups,
ordinary subsurfaces, and client-emulated menus are outside this policy.
Popup blur requires the global master. blur = false vetoes client popup blur.
true supplies whole-popup blur only without a non-empty client region.
An exact non-empty client region wins. blur_mode selects "optimized" or
"scene" for either form. blur_ignore_alpha never affects popup blur.
Popup opacity affects client content only. It does not attenuate the backdrop effect below the popup.
corner_radius clips either backdrop-effect form without clipping popup client
pixels or input. It accepts the window radius's uniform integer or four-corner
table and defaults to 0, because Wayland does not expose the client's visual
radius.
Rule order and merging
Every matching rule contributes properties in declaration order. A later rule replaces only the properties it specifies; omitted properties remain from an earlier match.
sweets.layer_rule({
layer = "top",
opacity = 0.95,
})
sweets.layer_rule({
namespace = "waybar",
layer = "top",
opacity = 0.85,
blur = true,
})Every top-layer root receives opacity 0.95. A matching Waybar root then
receives opacity 0.85 and forced blur. Installed rules run first; personal
rules append afterward, including declarations loaded with sweets.include.
Layer rules have their own limit of 128 entries and 32 KiB of retained matcher text. They do not consume the window-rule budget. Unknown fields, invalid types, non-finite or out-of-range opacity, missing matchers, missing appearance properties, and invalid layer or blur-mode names reject the complete candidate.
Inspecting live identity
Use the typed IPC query to see the identity and appearance Sweets actually resolved for every live layer-shell root:
sweets msg layersThe snapshot reports the exact namespace and current protocol layer, stable
root ID, map state, requested and resolved output, arranged global geometry,
keyboard interactivity, opacity, blur inherit/force/veto policy, resolved
mode, global blur gate, retained client blur demand, and current effect demand.
This makes client-side overrides visible—for example, a panel configured as
top may commit itself to bottom. Independent XDG popups are not roots and
are omitted. Add --json when a script needs the complete response envelope.
Live reload and rendering
Every valid configuration reload resolves all current layer roots against one complete new rule snapshot and installs their effective appearances atomically. The update does not remap, rearrange, configure, reposition, dismiss, focus, or disturb popup grabs. A visible effective change requests one redraw and invalidates output capture; static root or popup opacity and blur do not pace frames.
Forced blur is a visual element immediately below its owning root and uses the
root's arranged geometry. Output capture includes the same composition shown on
screen. Opacity below 1.0 or active blur requires compositor composition and
blocks direct primary-plane scanout, while the hardware cursor plane remains
independently eligible.
In optimized mode, background and bottom layer roots normally contribute to the shared output source. A root currently consuming forced or client-requested blur is excluded from that source so it cannot sample itself. Scene mode uses the same owner-bounded capture and renderer-failure isolation as window blur.