Overview
Mango features a sophisticated animation system that provides smooth, configurable transitions for window movements, resizing, tag switches, and state changes. Animations use cubic Bézier curves for natural easing and can be customized per action type.
Animation Configuration
Global Animation Settings
# Enable/disable animations
animations=1 # Master switch for client animations
layer_animations=1 # Animations for layer surfaces (menus, panels)
# Animation types (zoom, slide, fade, none)
animation_type_open=slide
animation_type_close=slide
# Fade effects
animation_fade_in=1
animation_fade_out=1
fadein_begin_opacity=0.5
fadeout_begin_opacity=0.8
# Tag animation direction
tag_animation_direction=1 # 1=horizontal, 0=vertical
# Zoom animation ratios
zoom_initial_ratio=0.3 # Starting size (30%)
zoom_end_ratio=0.8 # Ending size (80%)
Animation Durations
Each animation type has a configurable duration in milliseconds:
animation_duration_move=500 # Window resize/move
animation_duration_open=400 # Window opening
animation_duration_tag=350 # Tag switching
animation_duration_close=800 # Window closing
animation_duration_focus=0 # Focus transitions (0=instant)
Animation Curves
Mango uses cubic Bézier curves for easing. Each curve is defined by four control points:
# Format: x1,y1,x2,y2 (control points)
animation_curve_open=0.46,1.0,0.29,1 # Ease out
animation_curve_move=0.46,1.0,0.29,1 # Ease out
animation_curve_tag=0.46,1.0,0.29,1 # Ease out
animation_curve_close=0.08,0.92,0,1 # Ease in-out
animation_curve_focus=0.46,1.0,0.29,1 # Ease out
animation_curve_opafadein=0.46,1.0,0.29,1 # Opacity fade in
animation_curve_opafadeout=0.5,0.5,0.5,0.5 # Opacity fade out (linear)
Bézier curves are pre-calculated at startup into 256 baked points for performance. The system uses binary search to find the curve value at any time.
Animation Types
Window Opening Animations
When a window opens, it can use different animation styles:
Slide Animation
Windows slide in from the nearest screen edge:
animation_type_open=slide
Behavior:
Determines nearest edge based on window position
Slides from off-screen to final position
Direction adapts to window location
Special rules for master/stack positions
Direction logic:
// Window closer to bottom → slide up from bottom
// Window closer to top → slide down from top
// Window closer to left → slide in from left
// Window closer to right → slide in from right
Zoom Animation
Windows scale up from center:
animation_type_open=zoom
zoom_initial_ratio=0.3 # Starts at 30% size
Behavior:
Begins at zoom_initial_ratio size
Scales up to full size
Centers on final position
Combines with opacity fade-in
Fade Animation
Windows fade in without movement:
Behavior:
Position remains static
Only opacity animates
From fadein_begin_opacity to target opacity
Fast and subtle
Window Closing Animations
Similar types available for closing:
animation_type_close=slide # or zoom, fade, none
Closing behavior:
Creates fadeout snapshot of window
Original window immediately destroyed
Snapshot animates out
Freed after animation completes
Zoom-out closing:
animation_type_close=zoom
zoom_end_ratio=0.8 # Shrinks to 80% before disappearing
Tag Switch Animations
When switching tags, windows animate in and out:
tag_animation_direction=1 # 1=horizontal, 0=vertical
animation_duration_tag=350
Animation states:
bool tagining; // Window entering view
bool tagouting; // Window leaving view
bool tagouted; // Window fully hidden
Horizontal tag animation:
Windows slide left/right
Next tag slides in from opposite direction
Previous tag slides out opposite direction
Vertical tag animation:
Windows slide up/down
Next tag slides up from bottom
Previous tag slides down to bottom
Move and Resize Animations
Smooth transitions when windows change size or position:
animation_duration_move=500
animation_curve_move=0.46,1.0,0.29,1
Triggers:
Layout changes
Manual resizing
Master/stack ratio adjustments
Gap changes
Monitor changes
Focus Animations
Optional animations when focus changes:
animation_duration_focus=0 # 0=instant, >0=animate
Effects:
Border color transition
Opacity transition (focused vs. unfocused)
Smooth visual feedback
Animation Implementation
Animation Structure
struct dwl_animation {
bool should_animate; // Animation requested
bool running; // Currently animating
bool tagining; // Tag-in animation
bool tagouted; // Tag-out complete
bool tagouting; // Tag-out animation
bool begin_fade_in; // Fade-in pending
bool tag_from_rule; // Tag set by rule
uint32_t time_started; // Animation start time (ms)
uint32_t duration; // Total duration (ms)
struct wlr_box initial; // Starting geometry
struct wlr_box current; // Current animated position
int32_t action; // Animation type (OPEN, MOVE, TAG, CLOSE)
};
Animation Actions
enum {
NONE, // No animation
OPEN, // Window opening
MOVE, // Window moving/resizing
CLOSE, // Window closing
TAG, // Tag switching
FOCUS, // Focus change
OPAFADEIN, // Opacity fade in
OPAFADEOUT // Opacity fade out
};
Animation Tick
Animations are frame-based:
void client_animation_next_tick (Client * c ) {
// Calculate elapsed time
int32_t passed_time = now () - c -> animation . time_started ;
double progress = ( double )passed_time / ( double ) c -> animation . duration ;
// Apply easing curve
double factor = find_animation_curve_at (progress, c -> animation . action );
// Interpolate position
int32_t x = c -> animation . initial . x +
( c -> current . x - c -> animation . initial . x ) * factor;
int32_t y = c -> animation . initial . y +
( c -> current . y - c -> animation . initial . y ) * factor;
// Update scene node position
wlr_scene_node_set_position ( & c -> scene -> node , x, y);
// Apply clipping and effects
client_apply_clip (c, factor);
if (progress >= 1.0 ) {
c -> animation . running = false ;
}
}
Opacity Animations
Separate system for opacity transitions:
struct dwl_opacity_animation {
bool running;
float current_opacity;
float target_opacity;
float initial_opacity;
uint32_t time_started;
uint32_t duration;
float current_border_color [ 4 ];
float target_border_color [ 4 ];
float initial_border_color [ 4 ];
};
Combined effects:
Opacity fade
Border color transition
Synchronized with position animation
Per-Window Animation Control
Override animations for specific windows:
Window Rules
# Disable animations for specific app
windowrule=appid:terminal,isnoanimation:1
# Custom animation types
windowrule=appid:rofi,animation_type_open:zoom
windowrule=appid:rofi,animation_type_close:zoom
# Disable fade effects
windowrule=appid:game,nofadein:1,nofadeout:1
Available Override Properties
const char * animation_type_open; // Override open animation
const char * animation_type_close; // Override close animation
int32_t isnoanimation; // Disable all animations
int32_t nofadein; // Disable fade-in
int32_t nofadeout; // Disable fade-out
int32_t isopensilent; // Open without animation
int32_t istagsilent; // Tag without animation
Layer Surface Animations
Layer surfaces (panels, menus) have separate animation control:
layer_animations=1
# Layer-specific rules
layerrule=animation_type_open:zoom,layer_name:rofi
layerrule=animation_type_close:zoom,layer_name:rofi
Layer animation structure:
typedef struct {
// ... other fields ...
struct dwl_animation animation;
int32_t noanim; // Disable animation
char * animation_type_open;
char * animation_type_close;
} LayerSurface;
Baked Curves
Curves are pre-calculated for performance:
#define BAKED_POINTS_COUNT 256
// Pre-calculated curve points
struct dvec2 * baked_points_move;
struct dvec2 * baked_points_open;
struct dvec2 * baked_points_tag;
struct dvec2 * baked_points_close;
struct dvec2 * baked_points_focus;
struct dvec2 * baked_points_opafadein;
struct dvec2 * baked_points_opafadeout;
Curve lookup:
double find_animation_curve_at ( double t , int32_t type ) {
// Binary search through 256 baked points
// Returns y-value for given x (time)
// O(log n) performance
}
Frame Scheduling
Animations request frame callbacks:
void request_fresh_all_monitors ( void ) {
Monitor * m;
wl_list_for_each (m, & mons, link) {
if ( m -> wlr_output -> enabled ) {
wlr_output_schedule_frame ( m -> wlr_output );
}
}
}
Animation Batching
Multiple animations processed per frame:
// In rendermon()
Client * c;
wl_list_for_each (c, & clients , link) {
if ( c -> animation . running ) {
client_draw_frame (c);
}
}
// Process fadeout animations
wl_list_for_each (c, & fadeout_clients , fadeout_link) {
client_draw_fadeout_frame (c);
}
Special Animation Cases
Overview Mode Animations
Overview uses modified animations:
overviewgappi=5 # Inner gaps in overview
overviewgappo=30 # Outer gaps in overview
Behavior:
All windows shown in grid
Different animation curves
Special sizing calculations
Backed-up states restored on exit
Scroller windows scroll smoothly:
scroller_focus_center=0 # Animate to center focused window
Effects:
Horizontal/vertical scrolling
Focus-based positioning
Smooth proportion changes
Drag Animation Disabling
Animations pause during dragging:
if (c == grabc) { // grabc = grabbed client
c -> animation . running = false ;
c -> animation . duration = 0 ;
}
Animation Debugging
Disable Animations Temporarily
# Set duration to 0 to see instant changes
animation_duration_move=0
animation_duration_open=0
animation_duration_tag=0
animation_duration_close=0
# Or disable completely
animations=0
// Check frame timing
struct timespec now;
clock_gettime (CLOCK_MONOTONIC, & now );
int32_t frame_time = timespec_to_ms ( & now ) - last_frame_time;
Best Practices
Animation Tuning Smooth experience:
Keep durations under 500ms for responsiveness
Use ease-out curves for opening (0.46,1.0,0.29,1)
Use ease-in-out for closing (0.08,0.92,0,1)
Disable animations for games and video players
Performance:
Reduce durations on slower hardware
Disable fade effects if needed
Use isnoanimation for intensive applications
Animation Curves Common easing curves: # Ease out (decelerating)
0.46,1.0,0.29,1
# Ease in (accelerating)
0.42,0,1,1
# Ease in-out (smooth)
0.42,0,0.58,1
# Linear
0.5,0.5,0.5,0.5
# Bounce-like
0.68,-0.55,0.265,1.55