Animations can make or break your website’s user experience. But, if you’re using a third-party library to create animations, it’s important to choose carefully. The same library that enables you to create complex animations will often have a significant impact on your website’s overall performance. Before making any final decisions, be sure to weigh the pros and cons of adding animations to your site.
Most libraries offer techniques for improving website animations, but they are often optional. One approach for creating fast and performant animations is to use a JavaScript promise to create asynchronous animations that don’t block the main thread on the browser.
Shifty is a JavaScript animation library that offers first-class support for this feature. In this article, we’ll explore Shifty’s features and demonstrate how it utilizes JavaScript promises to create high-performing animations that can be used with async/await functions.
Jump ahead:
- Prerequisites
- What is async/await animation?
- What are the benefits of async/await animation?
- What is Shifty?
- Getting started
- Understanding Shifty’s building blocks
Prerequisites
To follow along with the examples in this article, you should have a fundamental understanding of JavaScript and promises.
What is async/await animation?
async/await animations refer to the use of JavaScript asynchronous functions and the await
keyword to create smooth and performant animations. This approach allows for the execution of animations without blocking the main thread on the browser.
JavaScript is synchronous by default, so code execution occurs in sequence. In other words, the JavaScript code will wait for the animation to start before loading other site functionalities. However, with asynchronous animations, the website can load without waiting for the animation.
This approach involves creating an async
function containing the animation logic and using the await
keyword to wait for the completion of each animation step before moving on to the next.
Here’s how the structure of an async/await animation looks:
(async () => { const { ... } = await tween({...}); const { ... } = await tween({...}); tweenable.tween({...}); })();
In this example, when the Immediately Invoked Function Expression (IIFE) function gets invoked, it waits for the first animation command (or tween
) to execute before moving to the next. By utilizing this approach, developers can create intricate and sophisticated animations that are both readable and easy to maintain.
What are the benefits of async/await animation?
There are several advantages to using the async/await approach for creating animations, including:
- Non-blocking: async/await doesn’t block the main thread, so other code can continue to execute while an animation is running
- Readability: async/await simplifies the process of working with complex animations by making the code more readable and easier to understand
- Error handling: async/await provides better error handling than traditional callback-based animation libraries. Errors can be caught using try/catch blocks, making it easier to debug and fix errors in the code, and adding extra functionality
- Customizability: async/await allows for a high degree of customizable animations, making it possible to create unique and engaging user experiences
What is Shifty?
Shifty is a JavaScript tweening library for building fast, asynchronous, and efficient animations for web applications. Tweening libraries manage the transition and translation of an object’s property value, resulting in the desired motion of the animated object.
This low-level animation library simplifies the process of animating HTML elements using JavaScript — without the need for complex CSS or third-party plugins. It focuses on optimal performance and flexibility, making it ideal for developers who want to create customizable and extensible animation tools.
Shifty’s unique selling proposition lies in its inbuilt support for executing animations using JavaScript promises. However, the library offers many additional benefits that are worth highlighting:
- Speed: Shifty is engineered to consume minimal memory, resulting in optimal animation performance. The library is optimized to use system resources efficiently, ensuring that animations run smoothly and seamlessly without causing a significant drain on system resources
- Extensibility: Shifty’s low-level code and flexible API make it simple for developers to expand and customize the animation library to suit their specific needs. This unopinionated approach to animation empowers developers to build upon Shifty’s foundation and create tailored animations that perfectly align with their application’s requirements
- Rendering agnostic: Shifty primarily focuses on animation logic and does not directly manipulate or render graphical elements on the screen. This design approach allows for greater flexibility and ease of integration with different rendering mechanisms, such as the Document Object Model and HTML canvas
- Lightweight: Shifty adds minimal overhead to a project. When loading the complete package from the CDN, Shifty only adds 5.8kB to a project, while the core package adds just 4.2kB. Compared to other popular animation libraries, like GreenSock and Anime.js, Shifty’s compact size is a notable advantage, making it an excellent choice for developers who want to optimize the performance of their web applications without sacrificing functionality
Getting started
You can add Shifty to your project using a package manager, such as npm or Yarn, or via CDN.
If you have a simple vanilla JavaScript application that doesn’t utilize a package manager, you can simply integrate Shifty into the project by adding either of these links within a <script>
tag in your markup: https://unpkg.com/shifty or https://unpkg.com/shifty/dist/shifty.core.js.
Alternatively, you can use npm or Yarn to add it as a dependency in your project using the following commands:
npm install --save shifty //or yarn add shifty
N.B., you’ll need to have Node.js installed on your machine to add Shifty as a dependency
Understanding Shifty’s building blocks
Shifty is comprised of two primary classes, namely the Tweenable
and Scene
classes. These classes export methods that let us create and control how animations are rendered.
Tweenable
class
The Tweenable
class is the core building block of Shifty. It provides the main API used to define an animation’s start and end state. It also lets us define custom easing functions that control the acceleration and declaration of animation, as well as the interpolation between different states of an object over a specified period of time. It does this by breaking down the animation into smaller steps or “tweens” that move the object from one state to another.
Here’s the simplest way to use the Tweenable
class:
import { tween } from "shifty"; tween({ from: { x: 0, y: 50 }, to: { x: 10, y: -30 }, duration: 1500, easing: "easeOutQuad", render: (state) => console.log(state), }).then(() => console.log("All done!"));
We can instantiate a tweenable
instance that lets us reuse tweens and have more control over the animation:
const { tween } = shifty; const element = document.querySelector("#tweenable"); const animate = async () => { const { tweenable } = await tween({ render: ({ x }) => { element.style.transform = `translateX(${x}px)`; }, easing: "easeInOutQuad", duration: 300, from: { x: 0 }, to: { x: 200 }, }); await tweenable.tween({ to: { x: 0 }, }); await tweenable.tween({ to: { x: 200 }, }); }; animate();
Shifty’s tweens are functions that accept an object argument with properties that define the target element to be animated, the start and end point, duration, and easing type for an animation.
These properties are as follows:
from
: defines the starting values of the tween animationto
: defines the ending values of the tween animationduration
: specifies the length of time, in milliseconds, that the tween animation should take to completeeasing
: specifies the easing function that should be used to control the rate of change of the tween over timerender
: specifies the function that should be called at each step of the tween animation; this function is responsible for updating the target element’s style properties to reflect the current state of the tween animation
Each tween
in Shifty is a promise; therefore, we can chain a .then()
callback that will execute after the tween
has been completed:
const element = document.querySelector("#tweenable"); tween({ render: ({ x }) => { element.style.transform = `translateX(${x}px)`; }, easing: "easeInOutQuad", duration: 500, from: { x: 0 }, to: { x: 300 }, }) .then(({ tweenable }) => tweenable.tween({ to: { x: 200 }, }) ) .then(({ tweenable }) => tweenable.tween({ to: { x: 100 }, }) ) .then(({ tweenable }) => tweenable.tween({ to: { x: 0 }, }) );
Alternatively, we can use JavaScript’s async/await syntax to avoid chaining .then()
callbacks, resulting in a more concise and readable code structure:
const element = document.querySelector("#tweenable"); (async () => { const { tweenable } = tween({ render: ({ x }) => { element.style.transform = `translateX(${x}px)`; }, easing: "easeInOutQuad", duration: 500, from: { x: 0 }, to: { x: 300 }, }); await tweenable.tween({ to: { x: 200 }, }); await tweenable.tween({ to: { x: 100 }, }); await tweenable.tween({ to: { x: 0 }, }); })();
With this approach, we can generate multiple autonomous tweens that adhere to the promise flow and are executed sequentially.
async/await’s capability to run within loops without blocking the thread enables us to generate infinite animation loops without getting stuck in an endless cycle:
const element = document.querySelector("#tweenable"); (async () => { while (true) { const { tweenable } = tween({ render: ({ x }) => { element.style.transform = `translateX(${x}px)`; }, easing: "easeInOutQuad", duration: 500, from: { x: 0 }, to: { x: 300 }, }); await tweenable.tween({ to: { x: 200 }, }); await tweenable.tween({ to: { x: 100 }, }); await tweenable.tween({ to: { x: 0 }, }); } })();
Thanks to the async/await block, the while
loop functions exactly as intended here, even though in a synchronous function, it would lead to an infinite loop and cause the page to crash.
We can also utilize the try/catch block to create more intricate animations. The concept behind this technique involves creating a tween within an IIFE async function with a try/catch block wrapped in a while
loop. When the animation is rejected, the animation’s promise is treated as a caught exception, and the control flow is diverted to the catch
block, which is then utilized to execute another animation function:
const { style } = document.querySelector("#tweenable"); const tweenable = new shifty.Tweenable( { scale: 1, color: "#ee6b33", x: 100, y: 100, }, { render: ({ scale, color }) => { style.transform = `scale(${scale})`; style.background = color; }, } ); const tween = tweenable.tween.bind(tweenable); const switcher = async () => { while (true) { try { await tween({ to: { scale: 0.5, color: "#333" }, easing: "bouncePast", duration: 750, }); await tween({ delay: 200, to: { scale: 1, color: "#db3d9f" }, easing: "easeOutQuad", duration: 750, }); break; } catch (e) {} } }; (async () => { while (true) { try { await tween({ delay: 200, to: { scale: 0.75, color: "#eebc33", }, duration: 1200, easing: "easeOutQuad", }); await tween({ delay: 100, to: { scale: 1, color: "#68db3d", }, }); } catch (e) { await switcher(); } } })(); document.addEventListener("click", (e) => { tweenable.cancel(); });
In this example, the animation gets rejected as soon as you click anywhere in the browser, thus causing the catch
block to await the switcher
function. The switcher
function is another async
function that leverages a similar pattern to change the cube’s color
.
Once the switcher
function breaks and exits its while
loop, the initial IIFE function repeats. Unlike the try/catch block within the IIFE function, the switcher catch
block doesn’t have any operation; hence, the while
loop simply restarts and tries again:
See the Pen
Shifty Example by David Omotayo (@david4473)
on CodePen.
Scene
class
Shifty’s Scene
class provides a mechanism that lets us group and coordinate related tweenable
objects to create complex animations, with the ability to play, pause, stop, and seek the entire scene as a whole.
A set of methods called members manages the timing and sequence control. Here are some of the primary methods of the Scene
class:
scene.play()
: starts playing the scene, executing alltweenable
objects in the scene:
See the Pen
Shifty scene.play() example by David Omotayo (@david4473)
on CodePen.
scene.pause()
: stops the scene from playing, halting the execution of anytweenable
objects currently running:
See the Pen
Shifty scene.pause() example by David Omotayo (@david4473)
on CodePen.
scene.stop()
: stops the scene from playing, likewise halting the execution of anytweenable
objects currently running:
See the Pen
Shifty scene.stop() example by David Omotayo (@david4473)
on CodePen.
scene.resume()
: resumes the execution of paused scenes:
See the Pen
Shifty scene.resume() example by David Omotayo (@david4473)
on CodePen.
These members can easily create animations with multiple moving parts that need to be synchronized and coordinated in time:
See the Pen
Shifty scene demo by David Omotayo (@david4473)
on CodePen.
Conclusion
In this article, we demonstrated how Shifty uses asynchronous JavaScript code to produce fast, high-performance animations. We examined Shifty’s fundamental components and looked at various techniques for constructing animations using the Tweenable
and Scene
classes.
The illustrations presented in this article may not be exceedingly intricate, but they demonstrate how we can utilize Shifty and async/await functions to generate dynamic and engaging animations with minimal JavaScript code.
The post Build async-awaitable animations with Shifty appeared first on LogRocket Blog.
from LogRocket Blog https://ift.tt/mBYNosk
Gain $200 in a week
via Read more