Hyprland Spring Animation Configuration: A Complete Guide to Physics-Based Motion
Configure physics-based spring animations in Hyprland using the hl.curve() API with mass, stiffness, and dampening parameters, then reference them via the spring field in any animation definition.
Hyprland spring animation configuration allows you to replace traditional easing curves with physical simulations that follow Hooke's law. The compositor supports two curve types—classic bezier curves and spring-based curves—with the latter providing natural, inertia-based motion for windows, workspaces, and UI transitions by solving differential equations at runtime.
How Spring Physics Work in Hyprland
Unlike static bezier curves, spring animations simulate a virtual mass attached to a spring. The animation manager calculates motion frame-by-frame using three tunable physical constants:
| Parameter | Description | Typical Range |
|---|---|---|
| mass | Inertia of the virtual mass; larger values delay acceleration | 0.1 – 5.0 |
| stiffness | Restoring force of the spring; higher values create snappier motion | 100 – 400 |
| dampening | Damping factor controlling oscillation; higher values reduce bounce | 10 – 30 |
When you reference a spring in an animation, Hyprland delegates timing calculations to the spring solver rather than a predefined curve lookup. This produces organic deceleration and optional overshoot based on the damping ratio derived from your parameters.
Defining Spring Curves in Configuration
The hl.curve() Syntax
Springs are declared globally using the hl.curve() function with type = "spring". According to the source code in src/config/lua/bindings/LuaBindingsConfigRules.cpp (lines 447-448), the engine validates that referenced spring names exist at configuration load time—missing definitions trigger immediate startup errors.
Define a custom spring in your hyprland.lua:
-- Define a spring named "soft" with gentle, bouncy motion
hl.curve("soft", {
type = "spring",
mass = 1.5,
stiffness = 180,
dampening = 20
})
The Config::animationTree() stores these definitions, making them available to the animation factory at Animation::mgr()->createAnimation.
Parameter Tuning Guidelines
Use lower stiffness (100-150) for relaxed, floating movements suitable for workspace transitions. Increase mass (2.0+) to create heavy, luxurious window movements, or decrease it below 1.0 for twitchy, responsive feedback. Adjust dampening above 25 to eliminate overshoot entirely, or keep it between 10-15 for iOS-style elastic snap-back effects.
Applying Springs to Animations
Once defined, reference your spring in any animation block using the spring key. The AnimationManager (implemented in src/managers/AnimationManager.cpp) automatically instantiates the physics solver when it detects a spring reference instead of a bezier curve.
Window Open and Close Animations
Target window lifecycle events via entries processed by src/desktop/view/animationControllers/WindowAnimationController.cpp:
hl.animation({
leaf = "windowsIn",
enabled = true,
speed = 4.2,
spring = "soft",
style = "popin 85%"
})
This configuration replaces the default easing with your physics-based curve when windows spawn.
Workspace Transitions
Control workspace sliding and fading through src/state/WorkspacePlacementController.cpp:
hl.animation({
leaf = "workspace",
enabled = true,
speed = 5.0,
spring = "soft"
})
Workspace animations benefit from springs with higher stiffness (300+) to ensure the desktop feels anchored and responsive during rapid switching.
Mixing Curve Types
Hyprland allows simultaneous use of bezier and spring curves. Maintain legacy easing for subtle fades while using springs for dramatic motion:
-- Retain bezier for opacity changes
hl.curve("default", {
type = "bezier",
points = {0.25, 0.1, 0.25, 1.0}
})
-- Use spring for spatial movement
hl.curve("dynamic", {
type = "spring",
mass = 0.8,
stiffness = 250,
dampening = 22
})
Source Code Implementation Details
The spring system integrates at multiple layers of the Hyprland codebase:
- Validation:
LuaBindingsConfigRules.cppparseshl.curve()declarations and validates spring references inhl.animation()blocks, emitting configuration errors if names are undefined (lines 447-448). - Storage: Curve definitions reside in the configuration tree accessed via
Config::animationTree(). - Instantiation:
AnimationManager.cpphandles the creation of animation objects, selecting between bezier interpolation and spring physics based on the presence of thespringfield. - Window Hooks:
WindowAnimationController.cppandWorkspacePlacementController.cppconsume these animations to drive visual updates during state changes.
The physics solver implements the classic Hooke's law differential equation, guaranteeing deterministic, frame-rate-independent motion across all monitor refresh rates.
Summary
- Declare springs with
hl.curve("<name>", { type = "spring", mass = ..., stiffness = ..., dampening = ... })before referencing them. - Reference springs in animation blocks via the
springkey to activate physics-based motion instead of bezier curves. - Validate configuration: Undefined spring names cause startup errors in
LuaBindingsConfigRules.cpp. - Tune physics: Adjust
massfor inertia,stiffnessfor speed, anddampeningfor overshoot control to match your ergonomic preferences. - Scope freely: Use different springs for windows, workspaces, and UI elements by targeting specific animation leaves.
Frequently Asked Questions
What is the difference between bezier and spring curves in Hyprland?
Bezier curves are predefined mathematical functions that interpolate between start and end values using control points, producing consistent timing regardless of distance. Spring curves simulate physical mass-spring systems, where animation duration varies based on the "distance" to travel and the physics constants, creating natural acceleration and deceleration that responds dynamically to the amount of change.
How do I fix "spring not found" configuration errors?
This error originates from src/config/lua/bindings/LuaBindingsConfigRules.cpp when an animation references a spring name not defined in your configuration. Ensure you declare the spring with hl.curve("yourName", { type = "spring", ... }) before the hl.animation() block that references it via spring = "yourName". Check for typos in the name string, as the validator performs exact string matching at startup.
What are the optimal mass, stiffness, and dampening values for smooth animations?
For general desktop use, start with mass = 1.0, stiffness = 200, and dampening = 20. For snappy window management, use mass = 0.6, stiffness = 300, dampening = 25. For relaxed, cinematic motion, try mass = 2.5, stiffness = 120, dampening = 15. Values outside the documented ranges (mass > 5.0 or stiffness > 500) may cause instability or excessive duration according to the animation manager's solver implementation.
Can I use different springs for windows and workspaces?
Yes. Hyprland's animation tree supports distinct configurations per animation leaf. Define multiple springs—such as hl.curve("windowSpring", ...) and hl.curve("workspaceSpring", ...)—then reference the appropriate name in each hl.animation() block by setting its leaf parameter to "windowsIn" or "workspace" respectively. Each animation type maintains independent curve references in Config::animationTree().
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →