Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
React Tween State (github.com/chenglou)
124 points by tosh on Nov 28, 2014 | hide | past | favorite | 28 comments


I worked on this with Cheng Lou a while back.

Just to preemptively address a criticism: yes, this does frame-by-frame animation in JavaScript, eschewing CSS animations. There are tricks you can use (similar to what iScroll does or did) that can leverage CSS animation, but it's likely that these won't be necessary or worth it.

The reason for this is that to truly solve animation you need to address continuous touch gestures that seamlessly transition into and out of animations (i.e. flick something, catch it with your finger mid-animation, zoom it while rotating it, then let go and have it animate out). The only way to do this is to use a programming language that can respond to events. Said another way, you should never think of animations discretely (i.e. "slide in from left") if you're thinking about building touch-based app. It won't feel natural.

My old employer has a great video about this. Detailed discussion starts here (there are two speakers that talk about it): http://youtu.be/OiY1cheLpmI?t=25m29s


I recommend anyone thinking CSS animations always outperform JS animations to have a look at Velocity.js (http://julian.com/research/velocity/).


Fire up the animation test in Chrome's timeline and view the frames. Replicate the same animation as a CSS transition. view in the timeline and report back. Hint: Pure CSS transitions are faster than JS driven ones. Not sure why so many people seem to think otherwise.


They also take longer to start. More importantly they're impossible to control.


Came here to say the same thing. I have done a few extensive benchmarks internally and the conclusions were exactly the same (even though you don't need benchmarks really to know there is a difference). CSS transitions/animations have less overhead than Javascript ones. I think the issue here is perceived performance vs actual performance. People assume just because it looks fast and runs fast, that it is fast, when it in-fact comes with some overhead (that might not be visible on the surface).


Thanks a lot for the pointer Peter.

I also was sceptical at first but apparently achieving 60 fps witch this approach is possible and has the interactivity advantages you mentioned.


Definitely doable on desktop.

IMO, if you're doing animations on mobile web you're targeting a higher end phone anyway (since you'd be crazy to do anything fancy with mobile web on a constrained device) it's less about execution speed and more about GC at that point. If you can't hit 60fps with this technique I think we need to fix garbage collection, not use a different set of animation primitives. But lots of very smart people disagree with me.


> Said another way, you should never think of animations discretely (i.e. "slide in from left") if you're thinking about building touch-based app. It won't feel natural.

That kind of goes against thinking of animation as tweens. Instead, you want something more physics based that can respond to touch in real time yet remain controllable enough for user interface usage; e.g. verlet and/or inverse kinematics.


Absolutely agree.

react-tween-state is less about the specific tweening function and more about the idea of a numeric value changing over time that can be interrupted. Instead of the standard Penner tweening functions you could just as easily substitute in some physics (like https://github.com/facebook/rebound-js). And with the DESTRUCTIVE mode of react-tween-state you can seamlessly transition between direct manipulation mode and inertia mode.

There's still a lot to do here, but I am pretty positive on the overall approach.


Reading the github page, though, this is really about tweening with no mention of interruption. However, using Verlet (not Newtonian like rebound-js!) you can easily combine both approaches since Verlet allows you to mess with a position directly (velocity is implicit in position deltas, so really stable although less accurate).

I wrote a rejected paper about this a few years ago; it might be useful as a reference:

http://research.microsoft.com/pubs/191705/uiphysics09.pdf

I wrote that when I was doing a lot of work with WPF, whose animation/data binding system is fairly similar to what is being explored in Javascript today (with frameworks like React). But beyond data binding and canned animations, I think physics is the next step.


Re: interruption, from the docs:

> stackBehavior (default: tweenState.stackBehavior.ADDITIVE). Subsequent tweening to the same state value will be stacked (added together). This gives a smooth tweening effect that is iOS 8's new default... The other option is tweenState.stackBehavior.DESTRUCTIVE, which replaces all current animations of that state value by this new one.

So DESTRUCTIVE is what allows interruption.


This is not much different from WPF's animation support, and I don't think it really helps. The interruptions are still not very natural looking. It was definitely useless for Surface (the table, not the tablet) when I was doing UX prototypes for it.


Additive is a better "interruption" in a lot of cases from what I've seen. Destructive was added after the fact for completeness. What do you think?


I would love to chat with you about what you've learned working on this stuff. If you're interested, drop me an email at floydophone at gmail dot com


This was a big part of the promise of famo.us


What a pleasant surprise =).

What Pete said (https://news.ycombinator.com/item?id=8670147) is true. I'll just address the issue of interruption here that people asked me about more than once: one of th major goals of this library is to enable interruptible and additive animation (a-la ios). There's currently no easy way to do this with CSS(1). Whether this by default uses a physics engine or not is not important; it sure can, but I decided to keep it simple. And no, in all likelihood this tiny lib doesn't beat the performance of other animation-specific libraries or the GPU accelerated CSS animations, but I was aiming for a good API first and foremost. I'll optimize accordingly.

(Also, check out my post here on the other problem with animation in gneneral: https://news.ycombinator.com/item?id=8561824)

(1) Imo, the danger of CSS is that it tends to get us 80% of the way there with 20% of the effort, while not being able to provide us with the power of achieving the last 20% at all.


I think it's crazy how one guy's static interpolation curves (http://www.robertpenner.com/easing/) keep showing up verbatim in an ever increasing array of tweening frameworks over a decade since he first posted them.

These interpolation curves can be nice in a pinch, but like I said before, the curves the curves are static, and so you can run into problems if you want to interrupt an action with another, or layer multiple tweens together.

One particularly effective way to get natural eased motion is to use a function that outputs something like the movement of a simple damped harmonic spring. With a system like this, you specify a target position relative to the current position, the sponginess of the spring, and the speed of which it oscillates. This can give you very natural results and feels a lot closer to a real physical system than a lot of these interpolation curves (EaseInOutExp, etc).

Here's some code for a damped spring system that can work really well as an alternative to predefined tween curves in user interfaces and games: http://www.ryanjuckett.com/programming/damped-springs/

And for more non-Penner interpolation alternatives, check out: http://sol.gfxile.net/interpolation/


Nice spring stuff, I hadn't seen it written up like that before. I did my own in JS recently (also based on solving the damped spring equation as a 2nd order ode; I copied my solution out of a physics textbook): https://github.com/iamralpht/iamralpht.github.io/blob/master...

I think the main advantage of using physical models is that you can feed velocity (from a touch gesture) into them. You can't really do that with the Penner equations (you could compute duration based on the derivative at t=0, but it won't feel very nice).

I wrote up some of the advantages of using physical models for UI animations and interactions here: http://iamralpht.github.io/physics/


I agree — transitions are a really bad way to think about animations. Another approach is to think of an interpolation curve as the step response to an LTI filter. This approach lets you turn any interpolation curve into a FIR filter that can handle interrupted transitions seamlessly.


Can you elaborate on this?


Verlet has worked better for me than damped springs. Velocity is implicit in verlet, meaning you can manipulate the position of a particle directly, which allows for direct control that is automatically included in velocity.


I don't understand - can someone explain???


React provides a very elegant way to update the DOM by deriving it from your application's state.

Unfortunately how animations of UI elements should be done in this model isn't as clear and elegant yet (as far as I understand).

This GitHub repository shows one way of how animations could/can be done in React in a simple way.


React JS is a front end framework that understands how to render stuff (html) in real time reactively to changes in state. React does magic with the shadow DOM, the actual DOM, and diffs in order to minimize reflows and boilerplate. Probably the biggest downside to this approach is interacting with legacy JS animations because:

1. ReactJS owns the DOM it renders. The nodes in the DOM are subject to change or even disappear at any time. React allows for hooks, but will throw exceptions if a third party fucks with the DOM under its control too much.

2. ReactJS owns the data (state) that controls rendering. Moreover, the state tends to be buried inside some nested React Element. Ordinarily, we would move the state outside of react and just update the components when the state changes (per Flux guidelines), but this is quite awkward when the state is for something like pixel offsets of a DOM node or some intermediate step in an animation- the component that does the rendering should own this information conceptually.

CSS animations tend to suck in practice- they aren't very flexible and they can't be controlled from JS (they go until completion). Existing JS frameworks for animations (eg JQueryUI) cause as much trouble as they provide solutions. The new library provides the correct solution- control animations from within React Elements themselves via a React Mixin.


I started learning React recently. I really like the way the code is laid out and I enjoy writing it so far, but trying to use jQuery animations with React seems to pretty much ruin that neatness and readability.

I did try the experimental CSSTransitionGroup, but it has some serious bugs, and didn't seem designed for in-place transitions. It's hard to find a good number of examples at this point though.

I came across the React Tween State GitHub page while googling, so I'll have to try it out. If I can get comfortable with basic animations with React, I think I'll be using it a lot more.


Great library, just made a video on it if anyone is interested in setting it up.

https://www.youtube.com/watch?v=9cY8-xCfU9E


The way I've been doing UI animation in React so far is by checking for state changes in `componentDidUpdate` and animating with Velocity.js, which works surprisingly well.

This appeals to me way more. Only concern is performance.


Awesome, just what I needed for a react project I'm starting on. thank you.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: