Making animations with code


Recently I’ve made this animation only using code (Typescript).

And today, I will show you how you can make this by yourself.

This project on Github

https://github.com/VladimirPapazov88/battery-animation

We will use the library called Motion Canvas. So lets start by creating a new project.

npm init @motion-canvas@latest

We will use these settings:
✔ Language TypeScript (Recommended)
✔ How would you like to render your animation? Video (FFmpeg)

Note

You can open visual editor by running:

npm start

Now let’s create new scene for button animation, for that we need to create new file in src/scenes called buttonClick.tsx.

Note

One yield block runs all animations inside it asynchronous. So different yield blocks represent different parts of animation.

Code (pretty much self explanatory):

// Imports
import {makeScene2D, Rect, Txt, Img} from '@motion-canvas/2d';
import {all, createRef} from '@motion-canvas/core';

export default makeScene2D(function* (view) {

  // Creating references to objects
  const button1 = createRef<Rect>();
  const cursor = createRef<Img>();
  const text = createRef<Txt>();
  
  // Adding objects to view
  
  // Background
  view.add(
    <Rect
      x={0}
      y={0}
      width={1920}
      height={1080}
      fill="#1a1a1a"
    />
  );
  
  // Button
  view.add(
    <Rect
      ref={button1}
      x={15}
      width={500}
      height={200}

      radius={10}
      fill="#454545"
    />,
  );

  // Text
  view.add(
    <Txt
      ref={text}
      x={15}
      y={0}
      text="Charge"
      fontSize={50}
      fontFamily="monospace"
      fill="#ffffff"
    />
  )
  
  // Mouse cursor
  view.add(
    <Img
      ref={cursor}
      x={1015}
      y={595}
      width={150}
      height={150}
      src="public/cursor-alt-svgrepo-com.svg"
    />
  );
  
  // Animation
  
  // First part
  // Cursor movement
  yield* all(
    cursor().position.x(50, 1),
    cursor().position.y(50, 1)
  );

  // Second part
  // Click
  yield* all(
    cursor().scale(0.5, 0.5).to(1, 0.5),
    
    text().scale(0.9, 0.5).to(1, 0.5),
    button1().scale(0.9, 0.5).to(1, 0.5)
  );

  // Third part
  // Transition to another scene
  yield* all(
    cursor().position.x(1015, 1),
    cursor().position.y(595, 1),

    text().text("Charging", 1),

    button1().fill("#1a1a1a", 1),
    button1().stroke("#ffffff", 1),
    button1().lineWidth(10, 1),
  )
});

Note

Point (0, 0) in Motion Canvas is the center of the screen.

Now with that part done, let’s make battery animation (src/scenes/battery.tsx), it’s a bit more complex. We will have two rectangles. One will be with main background color and second will have battery background color (this color changes through time). First will open second rectangle through time. Just like that we will have that smooth charging animation.

Code:

// Imports
import {makeScene2D, Rect, Txt} from '@motion-canvas/2d';
import {all, createRef, Direction, slideTransition} from '@motion-canvas/core';

export default makeScene2D(function* (view) {
  // Creating references to objects
  const body = createRef<Rect>();
  const charge = createRef<Rect>();
  const text = createRef<Txt>();
  const tip = createRef<Rect>();

  // Adding objects to view 
  // Background
  view.add(
    <Rect
      x={0}
      y={0}
      width={1920}
      height={1080}
      fill="#1a1a1a"
    />
  );
  
  // Main rectangle
  view.add(
    <Rect
      ref={body}
      x={15}
      width={500}
      height={200}
      radius={10}
      fill="#e13238"
      stroke="#ffffff"
      lineWidth={10}
    />,
  );
  
  // Tip of the battery
  view.add(
    <Rect
      ref={tip}
      x={280}
      width={30}
      height={55}
      fill="#ffffff"
    />,
  );
  
  // Overlay rectangle (it will change it width to achieve charging effect)
  view.add(
    <Rect
      ref={charge}
      x={260}
      width={490}
      height={190}
      radius={10}
      fill="#1a1a1a"
      offset={{ x: 1, y: 0 }} // Pivot point set to the center
    />,
  );

  // Text
  view.add(
    <Txt
      ref={text}
      x={15}
      y={0}
      text="Charging"
      fontSize={50}
      fontFamily="monospace"
      fill="#ffffff"
    />
  )
  
  // Animation
  
  // Complete transition by showing tip of the battery
  yield* all(
    tip().opacity(0, 0).to(1, 0.5),
  )

  // Animation
  yield* all(
    body().fill('#22ff00', 2),
    
    charge().width(0, 2),

    text().text("Charged", 2),
    text().fill("#000000", 2)
  );
});

Now let’s add those scenes to our project by editing src/project.ts

import {makeProject} from '@motion-canvas/core';

// Importing scenes
import battery from './scenes/battery?scene';
import buttonClick from './scenes/buttonClick?scene';

export default makeProject({
  scenes: [buttonClick, battery],
});

This project on Github

https://github.com/VladimirPapazov88/battery-animation

Finally, we can render final animation. I used these settings:

Render settings
Final result