chenglou / react-motion

A spring that solves your animation problems.
MIT License
21.68k stars 1.16k forks source link

Theoretical: Timeline Rewind/Replay Implementation #55

Closed srcspider closed 8 years ago

srcspider commented 9 years ago

I think the best way to move animation forward in react is to make it dead simple to experiment with the animation on a set of potentially multipage actions.

For example, let's say I have an admin panel, I have a certain flow to getting from listing to a form and then performing an action and I want to set some nice animations for doing all that, ideally by setting a crude version then experimenting by recording and replaying back.

This can potentially benefit more then just the developer.

For simplicity sake, lets assuming we have the following, as their not that hard (probably) and some technologies related to them are still surfacing as we speak or in their growing stages (eg. baobab v2).

Problems & Questions

How could we go about saving animation state to said structure? (with out key paths everywhere) How can we go about triggering animation state from said structure? How can we go about storing animation configuration in the state structure? How can we go about reading in a human understandable format the configuration from the tree? How can we go about resetting everything? (ie. stop/replay) How do we handle animation that's applied to many items? (ie. shared components that appear in multiple areas)

nkbt commented 9 years ago

This works well with https://github.com/in-flux/in-flux I mixed it with react-motion last week and got smooth and awesome transitions for different components navigation on the page

nkbt commented 9 years ago

Not sure how all this related to react-motion itself.

srcspider commented 9 years ago

Hm. With the multiple-page example I didn't mean that this would be a system that would be handling page change animation but that timelines recording should be able to go though routing systems. Sorry I guess I put too much emphasis on the pages changing. If you have a single page and are doing a lot of actions then it should be able to record that.

Not sure how all this related to react-motion itself.

The system that does the animation should be the one that manages the timeline; or at least that's what I think, may be wrong approach.

I started this as a theorycrafting to see if people have thought about the harder problems and have any insight or answers they could share. Ideas can always help in implementing other similar things even if something like the ideal solution described in the first post never comes to fruition. I know @chenglou implemented a very simple timeline system that he showed for his demos (off-topic: what's the keys for slowmo in demos anyway?) so figured he might have thought about some of the more adv. versions of that.

You may be right in that this may be better created as a seperate thing just to keep react-motion not bloated though.

nkbt commented 9 years ago

Hopefully I get it right this time...

timeline you are talking about seems like a cross-component state. When you want to share some state between components the answer is simple - use Flux.

That means you can create a timeline store to keep track state of animation and then apply it when needed to ReactMotion elements (or their animated targets directly).

You can also wrap your timeline component into ReactMotion and then do everything else the way you wish. Maybe with flux, maybe passing props to children.

This still seems like totally independent task. You can actually write some wrapper-component and publish it separately

PS: hack keys are gone for the moment. will be added back later

srcspider commented 9 years ago

@nkbt

This works well with https://github.com/in-flux/in-flux

Cool. I'll have to parouse the code later. Sadly any router that requires being able to have access to the components when defining the router won't ever work for me, since my production needs requirements mean the component data never exists until someone requires the page (webpack require.ensure style universal app). The routers end up being very simplistic and custom built for the job.

timeline you are talking about seems like a cross-component state. When you want to share some state between components the answer is simple - use Flux.

Uh. Maybe my way of doing things is just non-standard:

I looked over flux, the patterns involved in it seems too unnecessarily verbose for my purposes. My way may not be the best but it's stupid simple, so easier to figure out when something goes wrong.

That means you can create a timeline store to keep track state of animation and then apply it when needed to ReactMotion elements (or their animated targets directly).

I don't really understand this, but it may be just be that I'm missing something. I only found react-motion recently. I'll have to experiment some more.

PS: hack keys are gone for the moment. will be added back later

:+1:

nkbt commented 9 years ago

You don't have to require components for routing purposes. See explanation https://github.com/in-flux/in-flux/issues/52

bsansouci commented 9 years ago

You should check out https://github.com/gaearon/redux and their DevTools.

nkbt commented 9 years ago

Just wanted to give a link to redux as well, cheers =)

srcspider commented 9 years ago

off-topic but @nkbt in your in-flux/in-flux#52 example you still clearly have access to the Chart object. I'm sure it's dynamically loaded in some sense specific to in-flux but I don't see how it's dynamic in the sense I meant. When I say dynamic I mean the application has NO code for Chart and browser went and made a network call to get code that describes how to make a Chart page, injected that code into its current context along with all dependencies specific to getting Chart page to work and displayed the page.

Anyway talking about routers will get complicated real fast, since as soon as you combine dynamic with universal apps you need to talk about entry points to enable the user to load only code specific to a page when they ask for a page; so it's probably best not to derail further.

gaearon commented 9 years ago

I really really want to build some cool demos with Redux DevTools + React Motion. You can track Redux DevTools here: https://github.com/gaearon/redux/pull/234

They already allow time travel and hot reloading like I demoed in my ReactEurope talk.

The nice thing about DevTools is it's easy to create your own. For example, instead of the sidebar with a list of actions (what I have right now) you can reuse time travel code but build your own UI on top of it. (For example, you can draw past and future states of the animation instead, similar to what @chenglou showed in his talk.)

If you'd like to give Redux a try and use its time travel implementation together with React Motion, hit me up here or on Reactiflux Slack channel and I can help you get it running.

gaearon commented 9 years ago

I just released Redux DevTools.

Feel free to participate in the custom monitor challenge! Would be very cool to try this together with React Motion but it's time for me to go to bed.

chenglou commented 9 years ago

This is a non-brainer (btw how far have we come to be able assume that this can be done "just like that"? Awesome), but just a comment: to do the replay correctly you need to keep track of every single state the animation is in, not just the final position. For example, this is cool: https://twitter.com/jlongster/status/619266601662201856

But it's not an intended behavior, in the sense that you probably actually want it to snap to the destination without tweening. Transitioning between two destinations here is a byproduct of how react-motion + hot loader works (just like when you're modifying a css value of a class that has transition. It'll animate but you didn't intend it to). I'm not saying it's not desirable; in fact, it probably helps with prototyping some curves a bit, but again, it's not necessarily the intended behavior.

Likewise, rewinding time should literally rewind each state backward. If it's an ease-out, the rewind looks like an ease-in. If you're not tracking the intermediate values (state) and only asking the item to go back to the previous end position, you'll have an ease-out again. It still looks cool, but it's not what you're looking for.

That's just one aspect of this though. The other aspects of redux are still very valuable. And if you do record the intermediate states then it'll work fine (need to disable tweening between values though. You don't wanna interpolate between two intermediate values just because you're slow at dragging the timeline slider).

Btw you know what would be cool? That onion skin thing. I'm not sure how well it generalizes though, for stateful components and all. For stateless ones it looks really good. This is partially why I wanted a way to do the first point here.

chenglou commented 8 years ago

Great discussion btw, thanks again. But since there's nothing actionable for me right now (and I don't think RM's doing anything outrageous that'd prevent rewind/replay) I'll close this =).