Animations
Configure window and workspace transitions.
Animations are disabled by default. Enable the master switch to use the accepted transition families. Unsupported operations keep the normal immediate presentation.
Configuration
Declare sweets.animations({ ... }) at most once in each installed or personal
configuration layer. Personal fields override installed fields. Omitted fields
inherit the lower layer or built-in default.
sweets.animations({
enabled = true,
workspace_switch = {
enabled = true,
duration = 220,
direction = "auto",
curve = { 0.33, 1.0, 0.68, 1.0 },
},
window_open = {
enabled = true,
type = "fade",
scale = 0.8,
direction = "down",
distance = 48,
duration = 160,
curve = { 0.33, 1.0, 0.68, 1.0 },
},
window_move = {
enabled = true,
duration = 220,
curve = { 0.33, 1.0, 0.68, 1.0 },
},
window_resize = {
enabled = true,
duration = 220,
curve = { 0.33, 1.0, 0.68, 1.0 },
},
window_close = {
enabled = true,
type = "fade",
scale = 0.8,
direction = "down",
distance = 48,
duration = 160,
curve = { 0.33, 1.0, 0.68, 1.0 },
},
window_minimize = {
enabled = true,
type = "fade",
scale = 0.8,
direction = "down",
distance = 48,
duration = 160,
curve = { 0.33, 1.0, 0.68, 1.0 },
},
})| Key | Default | Behavior |
|---|---|---|
enabled | false | Master switch for every animation family |
workspace_switch | Enabled, 220 ms | Translates explicit numbered-workspace switches on one output |
window_open | Fade, 0.8 scale, down 48 px, 160 ms | Fades, zooms, or rigidly slides the first complete map of a managed window |
window_move | Enabled, 220 ms | Translates eligible same-output, same-size window moves |
window_resize | Enabled, 220 ms | Animates eligible same-output discrete resize batches |
window_close | Fade, 0.8 scale, down 48 px, 160 ms | Fades, shrinks, or rigidly slides the retained final image after an irreversible close |
window_minimize | Fade, 0.8 scale, down 48 px, 160 ms | Reversibly fades, zooms, or rigidly slides a complete window during minimize and restore |
The child switches matter only when the top-level enabled value is true.
A duration of zero also makes that family immediate.
Window open and close
window_open starts after a newly managed window has complete content ready to
display. type = "fade" retains the original fade. type = "zoom" uniformly
scales one complete content-and-border object from scale to its exact ready
size while fading it in. type = "slide" keeps that complete object at its
natural size and translates it from the configured hidden endpoint while
fading it in. Text, content, border, and the backdrop mask follow one sample.
Remapping an existing window does not replay the effect.
scale defaults to 0.8 and accepts finite values from 0.1 through 1.0.
The field remains validated and retained when type = "fade", so changing the
type later does not discard its tuning. direction accepts "left",
"right", "up", or "down"; distance is an integer from 0 through
4096 logical pixels. They default to "down" and 48 and affect only slide.
A pointer button or interactive window grab settles an active zoom or slide
before input routing; keyboard focus and client geometry remain at the ready
endpoint throughout.
window_close starts only after the client actually unmaps or destroys its
window. A close request that the client refuses does not animate. Fade retains
the final geometry while alpha reaches zero. Zoom flattens the detached content
and border into one renderer-owned object, then uniformly shrinks it from scale
1.0 to the independently configured window_close.scale while fading out.
Slide translates that same detached object toward its configured hidden
endpoint without resizing it. Sibling reflow uses its own timeline, and client
destruction cannot produce an empty frame or a second live copy beneath
translucent pixels. Opening and closing slides remain clipped to their owning
output even when the configured offset crosses an adjacent output.
Opening and closing apply to managed Wayland toplevels and normal managed X11 windows. Popups, layer surfaces, input methods, and X11 override-redirect windows do not use these families.
Window minimize and restore
window_minimize accepts the same type, scale, direction, and distance
fields as window open and close, in addition to enabled, duration, and
curve. Fade changes only alpha. Zoom scales the complete window uniformly
about its center. Slide translates it rigidly toward the configured offset;
Sweets does not infer a taskbar or panel target.
Minimize changes focus and logical state immediately. A non-interactive, renderer-owned image of the complete window starts fading after sibling reflow is ready, then releases its snapshot and frame demand at zero alpha. Restore waits for complete current client content and final layout geometry.
When restore interrupts a compatible outgoing effect, the same image reverses from the last alpha, scale, and translation accepted for presentation. A workspace, output, or geometry change uses a conservative ready effect at the destination instead, never a copy on both outputs. Activation and foreign- toplevel restore use the same path, and minimized-window recency is unchanged.
If another minimize or restore arrives before the previous layout transaction has produced complete ready geometry, Sweets uses the immediate latest result for that operation. It does not layer an obsolete grid or stack slot over the new topology. Reversal remains continuous once the first ready handoff has started the fade.
Calling restore-minimized when no minimized window remains is a true no-op;
it does not capture or hold an unrelated in-progress resize animation.
Window movement and resize
window_move animates a complete window between ready positions on one output.
The client content, popups, border, corners, and backdrop effect move together.
window_resize handles ready, discrete layout changes on one output. It can
animate coordinated changes to several windows with one shared timeline.
Sweets crops a complete natural-size image during a size change. It does not
stretch or crossfade client content.
Some size changes cannot be represented from one complete image. During an
explicit layout or master-position action, Sweets then keeps each affected
window at its complete final ready size and translates it from the old slot
origin to the new slot using window_move. Width and height are not animated
in this fallback. Other unrepresentable resize operations remain immediate.
Popup pixels also wait for the resize endpoint.
Interactive pointer move and resize stay pointer-matched and immediate. During a tiled move, vacated siblings may use coordinated relayout and a same-output drop may animate the dragged window from its released geometry into the selected slot. Cross-output window movement, visibility-changing Deck/Monocle membership, multi-window fullscreen changes, and recovery operations remain immediate.
Closing a tiled window is a safe removal-only exception. Sweets retains the departing complete window, waits for all affected survivor buffers, then starts the close effect and coordinated survivor resize together. Rapid closes follow the latest client-ready transaction. A change that also reveals or adds a window, times out, or cannot preserve complete natural-size content stays on the immediate path.
Workspace switching
workspace_switch animates successful explicit switches between numbered
workspaces on one output. The outgoing and incoming windows remain clipped to
that output.
direction accepts these values:
| Value | Behavior |
|---|---|
"auto" | Horizontal movement based on workspace number |
"horizontal" | Always use the horizontal axis |
"vertical" | Always use the vertical axis |
Special-workspace changes, cross-output window migration, output repair, and workspace changes interrupted by a grab or secure lock remain immediate.
Interruptions and fallback
A compatible rapid reversal continues from the most recently displayed visual position. It does not restart from the old endpoint.
If another discrete operation arrives before the earlier layout transaction has reached its first renderer materialization fence, Sweets skips the unshown intermediate target and prepares only the latest result from the last displayed presentation. Close and minimize readiness ownership follows that latest transaction, so a rapid mixed sequence cannot strand a detached image.
If that operation arrives while a newly opened window has not yet submitted its first animation frame, Sweets waits for that one renderer-owned image before continuing the transaction. The newcomer remains owned exclusively by its opening effect at final geometry; it is never treated as part of the old layout. Only windows that were already displayed enter sibling relayout, so they animate from pixels that actually appeared instead of dropping the entire resize batch to an immediate fallback.
Interactive pointer move and resize are intentionally different. Every ready intermediate client geometry is displayed immediately, then the next queued pointer target begins. Resize suppresses cosmetic relayout and retains that ownership through its last client-ready completion after release, so it has no movement or resize animation tail. A tiled move instead keeps only the dragged root pointer-matched; vacated siblings and final same-output placement remain animation-eligible. Direct manipulation stays responsive whether animations are enabled or disabled. While the first sibling reflow waits for client-ready buffers, Sweets keeps the last complete source object below the live roots as a vacated-slot cover. The cover retires with that exact transaction barrier, so neither animated nor non-animated grabs briefly expose the wallpaper.
After an animation has displayed a frame, a compatible operation starts from that renderer-accepted frame. An incompatible operation, missing renderer resources, output change, secure lock, or client-readiness timeout uses one complete ready result. A pointer grab takes over on its first motion. Sweets does not show a placeholder, empty slot, duplicated window, or partially prepared sibling layout.
Reloading a changed animation family settles that family's active transition once; the new curve, duration, or effect applies to later transitions. Turning off the master switch settles all active families without changing the final non-animated layout.
Whole-output screenshots and recordings include the displayed animation. A detached closing image is visual-only and is not available through isolated window capture.
Family settings
Every family accepts these fields:
| Field | Type | Default | Allowed values |
|---|---|---|---|
enabled | Boolean | true | true or false |
duration | Integer | Family-specific | 0 through 5000 milliseconds |
curve | Four-number array | { 0.33, 1.0, 0.68, 1.0 } | A bounded cubic Bézier curve |
Workspace, move, and resize durations default to 220 ms. Open and close durations default to 160 ms.
window_open, window_close, and window_minimize additionally accept these
fields independently:
| Field | Type | Default | Allowed values |
|---|---|---|---|
type | String | "fade" | "fade", "zoom", or "slide" |
scale | Number | 0.8 | Finite 0.1 through 1.0 |
direction | String | "down" | "left", "right", "up", or "down" |
distance | Integer | 48 | 0 through 4096 logical pixels |
initial_scale is not a valid field; the public zoom field is named scale.
Curves
curve is a Lua array in CSS cubic Bézier order:
local quick = { 0.46, 1.0, 0.29, 0.99 }
sweets.animations({
enabled = true,
window_move = { duration = 180, curve = quick },
})The first and third entries must be between 0.0 and 1.0. The second and
fourth entries may be between -4.0 and 4.0. The array must contain exactly
four finite numbers.
Named curves, strings, named table fields, and arrays with missing or extra
entries are invalid. { 0.0, 0.0, 1.0, 1.0 } is linear.
Reload behavior
A valid reload changes later transitions. An active transition keeps the direction, distance, scale, curve, and duration with which it started. Changing its effect type settles the active presentation once before later transitions use the new type.
Disabling the master switch or an active family settles that family once and releases its resources. Setting its duration to zero has the same effect. An invalid reload keeps the last valid configuration.
Validate an edited file before reloading:
sweets --check-config ~/.config/sweets/sweets.luaFor performance counters and renderer fallback diagnostics, see Performance Diagnostics.