-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
General discussion #1
Comments
@jeremyckahn wrote in jeremyckahn/rekapi#46:
The idea basically came from looking at what Rekapi uses Shifty for, which is basically just the interpolation engine. Other than reusing some simple Shifty methods on the Actors it doesn't appear that anything from it is required other than what gets called from I was having trouble figuring out how to modify the event-based hook system that the token module uses to be able to precalculate and save more of the work in a way amenable to being stored in a The intent is that Rekapi could, at keyframe creation time, preprocess the keyframe value (saving the produced decoder function), and then create and save an interpolator. Then at playback time all that needs to happen (in const state = nextProperty.interpolate(this.state, nextProperty.state,
interpolatedPosition);
this.value = nextProperty.decode(state); Notably, at playback time you did not have to parse either the current or next property's value (i.e. to tokenize and pick apart CSS), you directly call a function to interpolate the values, and you directly call a function to turn the tweened state back into the format needed for the Rekapi state (i.e. regenerate the CSS with the new values popped in). Because you're directly calling an interpolation and decode function, these can be made to be very efficient. In fact, you can compile them! Let's say you're tweening from fromState = {
transform__0: 10,
transform__1: 10,
}
toState = {
transform__0: 25,
transform__1: 40,
} It will also produce a toEasing = {
transform__0: easeInOutSine,
transform__1: linear,
} Then you feed These functions could be implemented as: interpolator = (new Function('easing0', 'easing1', `
return function (fromState, toState, position, outputState) {
outputState = outputState || { };
outputState.transform__0 =
fromState.transform__0
+ (toState.transform__0 - fromState.transform__0)
* easing0(position);
outputState.transform__1 =
fromState.transform__1
+ (toState.transform__1 - fromState.transform__1)
* easing1(position);
return outputState;
};
`))(easeInOutSine, linear);
decoder = (new Function(`
return function (outputState) {
return {
transform:
'translateX(' + outputState.transform__0.toString() +
'px) rotate(' + outputState.transform__1.toString() +
'deg)'
};
}
`)(); It looks wordy and ugly, but the resulting functions would be incredibly fast. Obviously you'll need to cache these so that you don't regenerate the same function over and over again, but that should be relatively easy. And again, all of this work can happen at keyframe creation time, not runtime. I do want to get to the point of having a compiler like this, but first I'm just trying to get basic functionality and to prove out the API. Basically, in summary: Extract the "interesting" parts out of Shifty (interpolation, preprocessing algorithms), ruthlessly minimize, and turn the efficiency up to 11. |
I'm not wild about the |
These are some amazing ideas. Shifty is admittedly not the fastest tweening engine out there, but that's because I prioritized extensibility and flexibility over pure performance. Yours is a much more performance-driven approach, which can make a huge difference on some projects like the ones you are working on. I'm all for this. The idea of compiling optimized interpolation functions is very interesting. I haven't seen this technique before and I wonder how it might stack up to GSAP, the current king of the hill in terms of performance for animation libraries. I estimate that this would be pretty close to GSAP's level. Once this gets built out, I'd be totally open to replacing "classic" Shifty for this one as the interpolation engine for Rekapi. Doing so would probably necessitate a 2.0 release. I could also roll my ES6-ification work into that release, making for a pretty big advancement for Rekapi. Please let me know if you want to go that route, and I'll work with you to make it happen. About the name: Yeah, shifty-fp isn't great. Not long ago, I started on a 2.0 version of Rekapi, which was a total rewrite, but I later decided to spin it off into a separate project called alt-rekapi. It's very incomplete, and I'm not working on it at the moment so as to focus on other projects. But, like this project, it's a reimagining of what Rekapi could be if built with modern tools and practices. It uses Redux and Immutable.js, so our heads are in the same place. Perhaps this could fit into the picture somehow? Since it's conceptually similar to this project, what do you think of "alt-shifty?" |
Yeah, I hate names. Thesaurus has "drift" as a synonym of "shift", and amazingly there's not "drifty" npm package yet, but there is a "drifty" company (https://github.com/driftyco) so that's no good. Besides, drift racing is kind of ridiculous. :D Shift -> Mutate. Googling "mutaty" gets https://en.wiktionary.org/wiki/mutati. Calling a mostly-functional package anything like "mutate" is kind of ironic. ;) Between -> Betwixt. Already an npm package. "reshifty" sounds awkward. I kind of like "retween". Actually the more I think about it the more I like it. Rekapi, Redux, Retween. I think I will go steal the npm package name if nothing else. |
Well, I'm sold enough to rename the repository. ;-) |
Retween is great! I love it. |
Any particular reason why the easing formulas are exported as one big object instead of just exporting each function individually? My best guess would be compatibility with some other library, but it's jsut a guess. Also, any particular reason why the exported functions in files where only one thing is exported aren't being Not criticizing, just interested in your coding style. |
Hi @jv-PintoBobcat, For 1), just because it was easy for the moment. They really should be separate so that a module builder can only take the ones that are being used. For 2), mostly because I started with everything in index.js and haven't cleaned it up yet. I'm pretty much following Redux's coding style, so I will probably change it around to use default exports and then re-exporting with names in index.js like it does. It's only 24 hours old after all! ;) |
Fair enough. Code on, my good man. |
@jeremyckahn, I did some looking at the speed test you linked above. It looks to me like the primary reason that GSAP is faster is not necessarily raw tweening performance, but rather that it is batching everything up into one |
I made a quick modification to Shifty to use a global Adding a similar delay parameter to Shifty should make it behave just the same as GSAP. |
(Aforementioned quick and dirty Shifty hack is here.) |
Incredible. Thanks for sharing your research! I definitely want to incorporate performance tweaks like this since they are so significant (and simple!). I'm a little backed up with various things right now, so I haven't had time to dig into your various changes and respond to all threads. It's high on my list of things to do, though – just letting you know that I haven't lost track of anything! |
Turns out GSAP is still a bit faster. I'm pretty sure it has something to do with how they're batching and/or manipulating the DOM. At 3000 dots they get within 1-2 FPS of each other, but at 500 dots you can see in the profiler/timeline that GSAP has more idle time. |
Batching seems like a smart idea. Even if there are multiple Shifty actually does have delay functionality. I'm pretty sure I implemented that some time after I forked the GSAP performance test — I will have update my fork to use that to see what the performance difference is when I have some time. Thanks for the reminder! |
No description provided.
The text was updated successfully, but these errors were encountered: