Skip to main content

Creating your first animation

We want to create the following animation (click the "Play" button below to see it in action):

Using Japit, we can describe this animation with the following code. Don't worry if you don't understand it yet! We'll go through it step by step.

import { $center, $fill, createAnimation } from 'japit';

const svg = document.querySelector('svg');
svg.style.width = '1000px';
svg.style.height = '500px';

const setup = (b) => {
b.select(1)
.fill('green')
.circle((c) => c.radius(100).centerX(300).centerY(150));

b.select(2)
.fill('purple')
.rectangle((r) => r.topLeftX(700).topLeftY(50).width(100).height(200));

b.select('1-2')
.stroke($fill(1))
.strokeWidth(5)
.zIndex(-1)
.line((l) => l.start($center(1)).end($center(2)));
};

const moveRectangle = (b) => {
b.duration(1);
b.select(2).circle((c) => c.centerY(375));
};

const changeColors = (b) => {
b.duration(0.5);
b.select(1).fill($fill(2));
};

const player = createAnimation(svg, [setup, moveRectangle, changeColors]);
player.play();

Let's start by getting a high-level overview of the code.

Creating the high-level structure

First, we need a canvas to draw our animation on. As Japit is a library for animating SVGs, we'll start by querying an SVG element that is already present in our DOM and set its size:

const svg = document.querySelector('svg');
svg.style.width = '1000px';
svg.style.height = '500px';

Next, we create three functions, setup, moveRectangle, and changeColors, that describe our animation:

const setup = (b) => {
// ...
};

const moveRectangle = (b) => {
// ...
};

const changeColors = (b) => {
// ...
};

The setup function defines the initial state of our animation; the moveRectangle function how the rectangle moves down and turns into a circle; and changeColors how the circle and the line turn purple. We'll take a closer look at how we achieve these particular effects down below, but for now we'll skip to the remaining two lines:

const player = createAnimation(svg, [setup, moveRectangle, changeColors]);
player.play();

We pass the SVG element and an array containing the setup, moveRectangle, and changeColors functions to createAnimation. The function returns an AnimationPlayer object, which can play the three steps of our animation in order. Then we call play on it to start playing the animation.

Describing the actual animation

Let's take a closer look at setup:

const setup = (b) => {
b.select(1)
.fill('green')
.circle((c) => c.radius(100).centerX(300).centerY(150));

b.select(2)
.fill('purple')
.rectangle((r) => r.topLeftX(700).topLeftY(50).width(100).height(200));

b.select('1-2')
.stroke($fill(1))
.strokeWidth(5)
.zIndex(-1)
.line((l) => l.start($center(1)).end($center(2)));
};

Creating elements

In Japit, we refer to every element in our animation via an identifier, which is a Number, String, or Symbol. Here we use

  • 1 as identifier for the left circle,
  • 2 for the right rectangle, and
  • '1-2' for the line connecting them.

To change an element with a given identifier, we call the select method on the AnimationBuilder b and pass in the identifier. There is no need to explicitly create the elements as Japit will create them for us on the fly.

After selecting an element, we can change its properties by calling methods on the TransitionBuilder returned by select. Here we set the fill color of 1 to green and change its shape to a circle with radius 100 at x-coordinate 300 and y-coordinate 100 via:

b.select(1)
.fill('green')
.circle((c) => c.radius(100).centerX(300).centerY(150));

Similarly, we create the rectangle with identifier 2 by calling:

b.select(2)
.fill('purple')
.rectangle((r) => r.topLeftX(700).topLeftY(50).width(100).height(200));

Expressing dependencies

Last, we construct the line '1-2' connecting the two shapes. However, this time we don't specify its fill and endpoints explicitly. Instead, we use the $fill and $center functions to set its fill to the fill of 1 and its endpoints to the centers of 1 and 2, respectively:

b.select('1-2')
.stroke($fill(1))
.strokeWidth(5)
.zIndex(-1)
.line((l) => l.start($center(1)).end($center(2)));

Animating values

It's time to start animating. We move the rectangle down and turn it into a circle via:

const moveRectangle = (b) => {
b.duration(1);
b.select(2).circle((c) => c.centerY(375));
};

Calling b.duration(1) sets the duration of the animation to one second. Then we select the rectangle via its identifier 2 and change its shape to a circle with y-coordinate of 375. Notice that Japit automatically infers the unspecified values like the x-coordinate and radius of the circle from the shape of the rectangle.

Observe how the endpoint of the line is automatically updated to match the center of 2 as we set the endpoint of '1-2' to $center(2) above.

Last, we change the fill color of 1 to the fill color of 2:

const changeColors = (b) => {
b.duration(0.5);
b.select(1).fill($fill(2));
};

Now, the stroke of '1-2' is equal to the fill of 1, which is in turn equal to the fill of 2, resulting in all three elements being 'purple'.

note

There is no difference between setting values and animating them. Setting a value just corresponds to an animation with a duration of 0. As 0 is the default duration, there is no need to explicitly specify it in setup.