animatedjs/interactive-docs

Create Arbitrary Animated Values

Closed this issue · 9 comments

Just a reminder to investigate how to add a createAnimatedValue or come up with some way to allow people to create Animated values that can return anything. Mostly thinking about instances in React Native where props are Arrays like in strokeDash for ReactART, or ScrollView contentOffset.

This has less to do with web I suppose.

This could also avoid having to add special cases like Animated.add and Animated.multiply as your animated value could receive animated values.

gre commented

I was thinking it would be great to be able to map an animated value.

I mean: map(value, v => v * 2 + 1)

do you think it's a bad idea? The only problem I would see is it makes animated not "serializable" and portable to a native implementation for instance, but this would be very expressive.

I know nothing about the native side but if it does go all native, do you think it'd be possible to create a bridged module that would receive 2 animated references and then you'd have to write your specific animation logic in the native world?

gre commented

AFAIK natively implementing the animation loop was one of the idea behind react native Animated, but today I feel that moving the Animated core engine to implementations (ObjC, Java, web) will be tough to maintain and more complex to provide a powerful API.
Also I would be curious to know if the JS animation loop is that much a bottleneck, I feel it would be a premature optimisation where we would lose a lot of power on the other side. In one of my recent experiment, it seems to be blazing fast, and my OpenGL code is the bottleneck. But maybe I'm wrong and there is a bottleneck there?

So I guess there is an important design decision to be made here, because if staying in JS world, we could allow more powerful things (like mapping a value).

I think if we allow such thing, we should be able to do things as powerful as in react-motion, I mean doing any user defined arithmetic operation over the animated value.
This could also simplify some internal code, for instance the recent add and multiply could be implemented like this (in a functional style):

add = (aValue, bValue) => flatMap(aValue, a => map(bValue, b => a + b))
multiply = (aValue, bValue) => flatMap(aValue, a => map(bValue, b => a * b))

and user could implement more advanced use-cases. Here is just one use-case:

sawtooth = aValue => map(aValue, a => a % 1)
// assume I have absoluteTime, an Animated.Value that tracks the time (not sure how it's possible to do this)
const animatedValueFrom0to1inSawtoothWay = sawtooth(absoluteTime)

I'm not sure if this approach of things match Animated philosophy, I used to do animation with just functions, and I wish we could reconciliate the 2 worlds. :)

vjeux commented

Some more context here. JavaScript itself is absolutely fast enough to drive animations without dropping frames. If you are just animating, the end to end process with animated clocks at less than 1ms.

The problem is that you need to do work in javascript that is not animation related. For navigation, you need to construct the scene you are going to render, for scrollview, need to parse json that is coming your way, log stuff...

The problem is that we don't have a good mechanism in JavaScript to interrupt some code that takes time in order to reliably run some high pri work. So the idea is to be able to serialize the animation pipeline and be able to run it outside of the js thread.

Now, the other part doesn't need to be in obj-c or java, it can actually be executed in JavaScript. I've always wanted to have two js processes in react native, one general one like we have now and a high performance one for animations and some core logic that we have much higher time constraints on.

vjeux commented

If we have js powering animations in the main thread we could implement what you define by toStringify the function and eval-ing it in the animation vm. We just need to ensure that it doesn't have any dependencies.

gre commented

@vjeux Interesting :) Thanks for the background

So would this concept still apply in the web via running animations in a web worker? Or is that seemingly overkill?

vjeux commented

The problem with web workers is that you can run the animation at 60fps but cannot touch the dom unless you go back to the main thread which can be blocked if there's some processing, so you don't get much wins that way.

You need to make everything run in a web worker and have the animation run on the main thread for it to be useful (what we do on react native).

Another approach that browser vendors are thinking about is to give a special web worker the ability to touch the dom and run synchronously with scrollviews. Still no prototypes but in discussions

vjeux commented

Something we are working on is to make React and Relay work in a more incremental fashion where they can work for 10ms and yield back control and repeat. This part is work but relatively straightforward.

The hard part is that you want to do some ui work when you yield. For example you are rendering a story that takes 200ms and at the same time running an animation. The animation may call render at some point in which case you may be in a conflicting state withthe other react rendering that's happening at the same time.

We explored a few options here but haven't yet found a good solution. This is the big challenge of 60fps :)