DEV Community

Cover image for How the animation engine of Cubecubed works?
Duc Phat
Duc Phat

Posted on

How the animation engine of Cubecubed works?

Hello, everyone. It has been a tough day to me so far. Nah, it's okay, I can continue working with Cubecubed.

Summer of Math Exposition 2 (#SoME2) deadline is coming to town. If you haven't heard about it but want to make an explanatory math video then I would encourage you to join in the competition. August 15 is the deadline (we are much far from there).

Cubecubed is the tool our team use for the final entry. It's not so great because it lacks a lot of features we need.

But my point is not just that.

As I said in the last article, my ambition for maintaining Cubecubed is to build a tool for teachers and students to visually interact with math. Cubecubed, still, has not gained much popularity, nor Manim nor any other visualization tools out there. So now, I am here, listing them to spread the word of teaching and learning math in a new way.

The first version - the bad, the worst and the horrible

Back when I first implemented the animation engine, it was a complete mess. The code is even the mystery to me, let alone other people. Maybe they just pass by the repo to see what is inside, or they want to contribute to it. I realized that is not fair to them. So I simplified it to a whole new level.

Now I want to share it with you.

The new one

Let this small video exemplify it.

The full code listing for the video is here. We will not talk about the whole thing, but focus more on the animation stuff.

Let's play the first animation.

group.play([new Create({ cubicon: square1, duration: 2000 })]);
Enter fullscreen mode Exit fullscreen mode

Here, group.play() takes in an array of animations to play, which are technically called a queue in Cubecubed. The current queue has only one animation Create.

The man behind the mystery - groupElapsed

In Group class, groupElapsed is a trivial property. It is the heart of the animation engine. When the engine sees the above line of code, it will play all of the animations included in the queue then calculate the time needed (which we call queueElapsed) to finish them. queueElapsed now has the value of 2000 (2 seconds).

Move on to the next queue!

group.play([
    new Create({ cubicon: square2, duration: 2000 }),
    new Rotate({ cubicon: square1, duration: 3000, degree: 45 }),
]);
Enter fullscreen mode Exit fullscreen mode

Line up, guys!

We all want the second queue plays after the last one has finished. Actually, this is a thing in Cubecubed. Queues are played sequentially, one after another. So what is the magic here? If you inspect the code of Cubecubed on GitHub, you'll see the play() method of all animation classes take sleepTime as a parameter. sleepTime is the amount of time to wait before playing.

But how can we calculate this sleepTime magic?

It's really simple. sleepTime is just Group().groupElapsed in disguise. Passing the former to the play() methods solves everything.

Queue-mon says: "Just play, don't wait"

We can see there are two animations in the queue now, Create and Rotate. Keep in mind, all animations in the same queue will play asynchronously. But what exactly happens behind the scene?

Similar to the last queue, the current one needs to calculate the queueElapsed. But how?

(Just to remind you, groupElapsed is now 2000)

Because the animations play asynchronously, we just need to take their maximum duration. Pseudocode: queueElapsed = max(2000, 3000) = 3000, then groupElapsed = groupElapsed + queueElapsed = 2000 + 3000 = 5000.

Any next queues will have to wait 5 seconds, and so on.

Guide for contributions

camelCase

If you plan to code a new animation and create a PR to the GitHub repo, make sure the class has:

  • the constructor which takes in params parameters, an object with cubicon, duration and ease properties. If the cubicon property accepts two or more cubicon types, please define the union TypeScript type for it.

  • a play(sleepTime: number) method. Then, create a private method, name it as the (camelCase) form of the class name (CamelCase). Finally, call it from the play() method.

Phew, just imagine how many words I would have written in this article if the animation engine did not improve. It would be a... Anyway, that is everything of the animation engine. In the next article, I will talk about d3 and how to render cubicons with it. It will definitely the great resource for you if you want to contribute to the Cubecubed project. So, stay tuned.

Top comments (0)