Sweets
Configuration

Animations

Motion when switching workspaces.

Sweets animates workspace switches, window opening, closing, and tiled layout changes. The animations are Sweets' own, built on the scene graph. There is no external effects dependency.

sweets.animations{ ... }

sweets.animations {
  enabled = true, -- master switch (false = every animation instant)
  workspace_switch = {
    enabled   = true,
    duration  = 220,                  -- ms, 0–5000 (0 = instant)
    direction = "auto",               -- "auto" | "horizontal" | "vertical"
    curve     = "0.33,1.0,0.68,1.0",  -- cubic-bézier easing
  },
  window_open = {
    enabled       = true,
    type          = "fade",           -- "fade" | "zoom"
    initial_scale = 0.8,              -- zoom only, 0.1–1.0
    duration      = 200,              -- ms, 0–5000 (0 = instant)
    curve         = "0.33,1.0,0.68,1.0",
  },
  window_move = {
    enabled  = true,
    duration = 250,                   -- ms, 0–5000 (0 = instant)
    curve    = "0.33,1.0,0.68,1.0",
  },
  window_close = {
    enabled  = true,
    duration = 200,                   -- ms, 0–5000 (0 = instant)
    curve    = "0.33,1.0,0.68,1.0",
  },
}
KeyTypeDefaultDescription
enabledbooltrueMaster switch. false makes every animation instant
workspace_switchtableThe workspace-switch slide
window_opentableThe window-open fade or zoom
window_movetableThe tiled move/resize animation
window_closetableThe window-close fade

Each animation has its own enabled. The master switch and the block's switch must both be on for it to play.

workspace_switch

FieldTypeDefaultDescription
enabledbooltrueTurn the workspace slide on or off
durationint220Slide length in ms, 0–5000 (0 = instant)
directionstring"auto""auto", "horizontal", or "vertical"
curvestring | table"0.33,1.0,0.68,1.0"Easing (see Curves)

window_open

FieldTypeDefaultDescription
enabledbooltrueTurn the window-open effect on or off
typestring"fade""fade" or "zoom"
initial_scalenumber0.8Zoom starting scale, 0.11.0; ignored by fade
durationint200Effect length in ms, 0–5000 (0 = instant)
curvestring | table"0.33,1.0,0.68,1.0"Easing (see Curves)

When opening a tiled window also moves existing windows, the reveal edge follows the window_move clock while the fade or zoom keeps its own window_open duration. The two clocks are independent, so a slow open continues smoothly after a faster neighbor settles.

The newcomer stays clipped to the area the moving edge uncovers, so it never appears underneath a still-resizing neighbor. The seam keeps sweets.gaps.inner spacing for the whole glide.

Zoom scales a temporary snapshot from the centre while the live window stays at its final geometry. Client input, layout state, and configure size stay stable throughout. The snapshot covers content, subsurfaces, and border, and cannot receive pointer input.

window_move

FieldTypeDefaultDescription
enabledbooltrueTurn the tiled move/resize animation on or off
durationint250Animation length in ms, 0–5000 (0 = instant)
curvestring | table"0.33,1.0,0.68,1.0"Easing (see Curves)

When the layout changes — opening or closing a tiled window, switching layouts, resizing the master — the affected windows slide and resize to their new slots instead of snapping.

Behavior guarantees during a transition:

  • A displaced neighbor keeps covering the space a new window will occupy, so no desktop background flashes through.
  • Each animated window stays confined to its source monitor, including surface, border, and popups.
  • Content is clipped at its natural resolution, not stretched, so text and terminal cells keep their shape.
  • Configured gaps stay filled the whole time.
  • Floating windows and interactive drag-resize are unaffected.

A rare mixed-axis change, where one dimension grows while the other shrinks, snaps the size but keeps the positional glide.

Layout switches

Switching between layouts uses frozen frames and moving cutouts: the windows that are changing size move live, while the rest of the layout stays visually stable behind them. This applies to every layout pair — including shared-slot layouts like monocle and deck — and to all four master positions.

The result is that a switch never exposes the desktop, never flickers between live content and background, and never resizes windows that are not involved.

Rapid layout requests are coordinated per workspace. The current transition finishes one complete layout before the next begins, and only the latest requested layout is kept. Repeated cycle commands update that single pending target, so an even number cancels the switch and an odd number lands on the other layout.

With animations disabled, requests are immediate and bypass this coordination.

Maximize and fullscreen

Maximize, unmaximize, and both directions of the compositor fullscreen action use the same duration and curve.

Application-requested fullscreen changes are instant in both directions. Wayland does not identify video surfaces, so this boundary keeps browser video and games responsive without disabling ordinary layout animation.

Switching directly between maximized and fullscreen animates between the two output boxes, so the window contracts or expands from its visible frame. Reversing mid-animation hands the current visual box to the new direction rather than restarting from a stale slot.

Fullscreen freezes and masks the floating layer, since it occludes it. Maximize deliberately leaves floating windows live above the maximized client.

Closing

Closing uses the reverse transition. The closing snapshot is cropped away by the expanding survivor and released when the move settles.

When the focused window closes, keyboard focus and the focused border move to the next eligible window immediately. With pointer follow_focus on, the pointer moves in the same step. The closing snapshot then finishes on its own.

window_close

FieldTypeDefaultDescription
enabledbooltrueTurn the window-close fade on or off
durationint200Fade length in ms, 0–5000 (0 = instant)
curvestring | table"0.33,1.0,0.68,1.0"Easing (see Curves)

When a window closes, a temporary snapshot of its content and border fades out in place. The fade starts the moment the window actually goes away, so a close the application refuses — to show a "save changes?" dialog — never fades.

It runs concurrently with the survivors' window_move glide, so neighbors reclaim the space while the old window melts away over them. The snapshot cannot receive pointer input, never leaves its monitor, and is released when the fade completes.

Set window_close = { enabled = false } or duration = 0 for instant disappearance. Windows closing on a workspace you are not viewing never fade.

Snapshots that only hold a vacated slot for anti-flash purposes — drag starts, minimize, a tiled window turning floating — stay at full opacity. Only real closes fade.

Turning animations off

The top-level enabled = false makes everything instant with one switch. Your settings are kept, so flipping it back to true restores them.

Each block also has its own enabled, and both must be on for the animation to play. workspace_switch = { enabled = false } disables just the slide.

Curves

The curve controls acceleration feel independently of duration. It is a cubic-bézier timing function — the same model as CSS cubic-bezier(), Hyprland, and Mango.

Pass four numbers as "x1,y1,x2,y2" or a { x1, y1, x2, y2 } table. These are the two control points of a curve whose endpoints are fixed at (0,0) and (1,1).

local quick = "0.46,1.0,0.29,0.99"
local bounce = { 0.34, 1.56, 0.64, 1.0 }

sweets.animations {
  workspace_switch = { duration = 200, curve = quick },
}

Sweets does not reserve curve names. Use ordinary Lua variables, as above, to name and reuse curves.

The x values must stay within 0..1. The y values may go past 1 or below 0 to make the slide overshoot and settle back, for a springy feel. The default 0.33,1.0,0.68,1.0 is an ease-out; linear is 0.0,0.0,1.0,1.0.

The slide

When you switch workspaces on the same output, the outgoing workspace slides off one edge while the incoming one slides in from the opposite edge. A higher-numbered workspace enters from the trailing edge (right or bottom), a lower-numbered one from the leading edge.

The slide is paced by the monitor's refresh rate, so it stays smooth on high-refresh and 4K displays and never spins the CPU when idle. Windows keep their arranged positions — only a temporary offset animates — so nothing is re-laid-out.

Triggering another switch mid-slide retargets the current slide smoothly. If a command changes geometry, visibility, grouping, or layout during the slide, Sweets finishes the slide first and then applies it. The command is never discarded.

Slide direction

ValueBehavior
"auto"Horizontal (the default)
"horizontal"Slide left/right
"vertical"Slide up/down

Multi-monitor. The sliding workspace is clipped to its own monitor and is never drawn on a neighboring screen, on any axis or arrangement. Only the output whose workspace changed animates.

Only interactive workspace switches animate. Switches caused by a config reload, monitor hotplug, or workspace reassignment apply instantly.

The slide animates window content and grouped-window tab strips together.

Window open

When a window maps for the first time, the whole window — content and border — uses the configured fade or zoom effect. Like the slide, it is paced by the monitor's refresh rate.

Set window_open = { enabled = false } or duration = 0 for instant appearance. Windows mapping onto a workspace you are not viewing do not animate.

Fade is the default. Set type = "zoom" for an 80% to 100% centred zoom, and adjust initial_scale for a subtler or stronger effect. Fully translucent clients using fade may briefly reach full opacity as the fade ends, before their own transparency re-applies.

On this page