w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.5k stars 661 forks source link

[css-timing] spring() timing function #280

Open grorg opened 8 years ago

grorg commented 8 years ago

Originally sent to www-style: http://www.w3.org/mid/1F5F295B-DF6C-485F-ACFC-64F2C6BE5E41@apple.com (there is some discussion on the list that I won't copy into this description - please read it on the archives)

Proposal: spring() timing function in CSS and Web Animations

We propose adding a new timing function for transitions and animations to simulate the effect of a spring-based motion between the endpoints.

Over the past few years, Apple's designers have moved to more physically-based motion effects. Not only do these look more natural and fun, they also are often easier to tweak to get a desired effect. By far the most common type of motion we've seen is a simulation of a spring.

There are a lot of online resources discussing why this is good. Here is one of my favourites: Creating Animations and Interactions with Physical Models --> https://iamralpht.github.io/physics/

We're still discussing what is the best way to expose springy animations. Some internal feedback has suggested that our parameterisation below is too hard to author, and that we should favor a more simple F = -kx approach. I'm sure there are lots of people reading who have opinions. Please share these opinions!

Here is what we propose today as a starting point:

spring(mass stiffness damping initialVelocity)

Simulate a spring using the solving algorithm defined by this JavaScript function [1].

mass: The mass of the object attached to the end of the spring. Must be greater than 0. Defaults to 1.

stiffness: The spring stiffness coefficient. Must be greater than 0. Defaults to 100.

damping: The damping coefficient. Must be greater than or equal to 0. Defaults to 10.

initialVelocity: The initial velocity of the object attached to the spring. Defaults to 0, which represents an unmoving object. Negative values represent the object moving away from the spring attachment point, positive values represent the object moving towards the spring attachment point.

NOTE: The definition of spring() above uses spaces to separate parameters because "So I tied an onion to my belt, which was the style at the time" [2]. Since all the other timing functions are comma-separated, maybe it is better to be consistent?

What's unusual about this form of timing function is that the animation effect is now independent of its duration. The spring timing function completely controls how the animation reaches its end point, and certain parameter values can produce an animation that does not settle at the end point before the animation duration expires (technically they never completely settle).

We therefore also propose a new keyword for duration: "auto", which means the duration will be calculated to be the time where the animation has settled.

NOTE: Lots of hand-waving here at the moment. Firstly, what "settle" means to most people is dependent on the type of animation, and the size of the animating object, and the distance being animated over. Secondly, we'd need to describe how this works for a keyframed animation, where the duration applies over all the keyframes.

The spring() timing function as described above has been implemented in WebKit. It is currently exposed in the Safari Technology Preview, although note that the current implementation does not handle optional parameters (you have to specify them all). It's not exposed in regular Safari builds - we'll consider that if we can reach consensus here.

For what it's worth, the implementation in WebKit was fairly simple. We don't think this is a big burden to browsers.

Meanwhile, here is a demo page that has the effect implemented in JavaScript [3]

Of course, all this should apply to Web Animations... left as an exercise for the reader :)

[1] https://webkit.org/demos/spring/spring.js [2] https://frinkiac.com/?q=style%20at%20the%20time [3] https://webkit.org/demos/spring/

With lots of love,

weinig and dino

grorg commented 8 years ago

It seems that #229 is related

shans commented 8 years ago

I think there's no need for both a stiffness and a mass, particularly if we aren't trying to get all physical with real units 'n stuff.

The spring equation (Hooke's Law) is F = kx - but F is just ma, so we have a = (k/m) x - i.e. the acceleration on the object is proportional to the distance away from the resting point.

You should just expose that relationship, rather than two values that lead to redundancy.

Damping uses stiffness and mass too - but it's probably better just to expose the zeta directly, particularly because this allows people to easily choose between overdamped, critically damped, and underdamped.

shans commented 8 years ago

A bigger issue - this doesn't feel like a timing function as it doesn't modify the course of the animation over a fixed time (which is why you've proposed the 'auto' duration, which is scary because what does that mean for animations that aren't spring functions?).

An alternative (switching to Web Animations terms for a second) might be to replace the KeyframeEffect with a SpringEffect? I don't know what this would mean in terms of CSS syntax though.

othermaciej commented 8 years ago

If you expose zeta instead of the damping coefficient then perhaps it would make more sense to expose the natural frequency (ω0) instead of k/m. Besides the fact that these choices may make spring parameters easier to understand and author, it is also convenient that zeta is dimensionless and omega-nought is a frequency, which CSS has a unit for.

vidhill commented 8 years ago

I have added a proposition as to how this and any other scripted easing function could be defined here, https://github.com/w3c/csswg-drafts/issues/229#issuecomment-233468454 would like to hear your thoughts

birtles commented 6 years ago

Moving this to css-timing.

samhenrigold commented 3 years ago

@birtles Has this gotten any further consideration?

birtles commented 3 years ago

@birtles Has this gotten any further consideration?

@samhenrigold Yes, you can follow the discussion in #229. There's a very pragmatic and promising proposal from @jakearchibald starting here: https://github.com/w3c/csswg-drafts/issues/229#issuecomment-861247074

rihok commented 2 years ago

@birtles Has this gotten any further consideration?

@samhenrigold Yes, you can follow the discussion in #229. There's a very pragmatic and promising proposal from @jakearchibald starting here: #229 (comment)

The proposal would allow pre-calculating spring-like motion in discreete steps, but not "springs" as velocity driven value changes over time. Springs are useful because they retain the velocity throughout value changes, so the transition can look smooth regardless of how often the value is changed. That's not possible to define in discreete steps, so I'd say the proposal for a spring() function would still need further consideration. Perhaps I'm missing some discussions around this though.

Edit: It does appear that the Safari implementation isn't tracking velocity throughout changes actually. Seems like the velocity is reset on every change, which severely limits its usefulness.

jakearchibald commented 2 years ago

Yeah, spring() kinda sits uncomfortably between a regular easing and a physics system. Eg, it doesn't take into consideration the movement of parent objects, and it'd likely be too complicated to do so.

rihok commented 2 years ago

I don't think it needs to be that complicated. Taking into account parent velocity wouldn't even make sense for something like color interpolation for example.