Processing-Tutorial: Kinetic Typography 1

In the last years i’ve observed a new tendency in typography and graphic design which has been made possible by the rise of affordable animation-software like Adobe After Effects, variable fonts and more accessible tools in Creative Coding: Kinetic Typography is the new kid in town, an umbrella term for moving, flexible typographic systems.

Some good examples: The whole work by DIA studio and the crazy cool AR-app “Weird Type” by Zach Lieberman.

In this tutorial i wanna show you a fancy approach on animating type. Our application will segment a simple lettering into rectangular pieces and shift each snippet slightly different on the horizontal axis. To do so, we will utilize a two-dimensional grid and put a sine-wave into it. Ready? Let’s go!

Download this tutorial with all assets on Github

The copy()-function

If we want to copy the pixels of a defined area to another, the copy-function is the right tool for us. In its simplest form it takes 8 arguments: The first four integer-values define the area that we want to copy. The last four define the destination. For clarity I will use variables in this tutorial.

// SOURCE
int sx = 0;
int sy = 0;
int sw = 100;
int sh = 100;

// DESTINATION
int dx = 100;
int dy = 100;
int dw = 200;
int dh = 200;

copy(sx, sy, sw, sh, dx, dy, dw, dh);

To get the best results and prevent visual feedback, we can put another parameter in there, which defines the template, we want to copy the pixels from. So instead of getting the pixels directly from the sketch, we use another surface like an image or a PGraphics-object as a reference, which can be passed as an additional argument into the first place of the copy-function.

a digital passepartout

In the example above i copy an area of an PImage-surface to my sketch-window. The mouse-position controls the coordinates of the source.

  // SOURCE
  int sx = mouseX+150;
  int sy = mouseY+150;
  int sw = 150;
  int sh = 150;


  // DESTINATION
  int dx = width/2-125;
  int dy = height/2-125;
  int dw = 250;
  int dh = 250;

  copy(img, sx, sy, sw, sh, dx, dy, dw, dh);

In our kinetic type-experiment we wanna do exactly the same, but with multiple elements in a two-dimensional grid. Let’s wrap up the actual sketch to get going.

Preparing the sketch

First we have to create and initialize the PGraphics-object we want to use as a template. Then we create and initialize a PFont. Note: Make sure that you’ve copied the font-file to the data-folder!

PGraphics pg;
PFont font;

void setup() {
  font = createFont("RobotoMono-Regular.ttf", 600);
  size(800, 800, P2D);
  pg = createGraphics(800, 800, P2D);
}

Next we put the lettering onto the PGraphics-element inside the draw-function and center it.

Just in case you have never worked with PGraphics: It is comparable with a layer in Photoshop, so it can be treated as an independent sketch in our actual sketch. It is a very powerful tool to manage complexity and to crop things. As always: Look up the reference if you’re stuck here!

void draw() {
  background(0);
  pg.beginDraw();
  pg.background(0);
  pg.fill(255);
  pg.textFont(sansBlack);
  pg.textSize(800);
  pg.pushMatrix();
  pg.translate(width/2, height/2-215);
  pg.textAlign(CENTER, CENTER);
  pg.text("a", 0, 0);
  pg.popMatrix();
  pg.endDraw();
}

Now if we hit the run-button we won’t see anything, because we do not draw the PGraphics-element anyway. Let’s do this quickly using the image-function, so we can check if everything is sitting in the right place.

image(pg,0,0);

So far so good. What we have to do now is wrapping up a two-dimensional for-loop to create a grid. But before we need to define the number of tiles that we want to get vertically and horizontally, which we can use to calculate the correct dimensions. Let’s start with 8 tiles on both on the x- and the y-axis.

  int tilesX = 8;
  int tilesY = 8;

  int tileW = int(width/tilesX);
  int tileH = int(height/tilesY);

  for (int y = 0; y < tilesY; y++) {
    for (int x = 0; x < tilesX; x++) {
      ...
    }
  }
Note: I’ve added a grid of rectangles to visualize what we are doing here.

Next let’s place the copy-function into the grid and put the tile-dimensions and -positions into the right places.

  int tilesX = 8;
  int tilesY = 8;

  int tileW = int(width/tilesX);
  int tileH = int(height/tilesY);

  for (int y = 0; y < tilesY; y++) {
    for (int x = 0; x < tilesX; x++) {

      // SOURCE
      int sx = x*tileW;
      int sy = y*tileH;
      int sw = tileW;
      int sh = tileH;


      // DESTINATION
      int dx = x*tileW;
      int dy = y*tileH;
      int dw = tileW;
      int dh = tileH;
      
      copy(pg, sx, sy, sw, sh, dx, dy, dw, dh);

    }
  }

If we run the sketch now, we’ll see a white, lowercase “a” on our window. Nothing fancy seems to happen here. Why is that?

Actually we are already copying the tiles to the appropriate positions, but we don’t do anything with them. If you look at the code above, you’ll see that the source-values are equal to the destination-values. So what we have to do now is writing a logic that tells the elements how to move.

We can either manipulate the source or the destination. Both approaches can produce totally diverse and interesting effects. To keep things simple, we’ll play with the source coordinates (sx and sy) in this tutorial.

Pushing a wave through the grid

Now it’s time to define a variable that represents the distortion-effect. That variable has to be inside of the nested for-loop and it has to differ slighty in each iteration. If the output of this variable is too chaotic, it will produce random-like effects. That’s not exactly what we want. Our aim is to get a smooth movement and that’s why we’ll use the sin()-function, controlled by the frameCount and the coordinates inside our loop.

int wave = int(sin(frameCount * 0.01 + ( x * y )) * 30);

If you have never worked with the sin()-function yet, don’t worry. It produces a value between -1 and 1 and takes a number as an argument to control its phase. Look up the Processing-reference if you are stuck here. Understanding how waves work in Processing is extremely helpful for a variety of things, especially if you work on animations.

Last but not least we’ll mix the wave-variable into the source-x-coordinate.

int sx = x*tileW + wave;

Here’s the complete code

PFont font;
PGraphics pg;

void setup() {
  font = createFont("RobotoMono-Regular.ttf", 600);
  size(800, 800, P2D);
  pg = createGraphics(800, 800, P2D);
}

void draw() {
  background(0);

  // PGraphics 

  pg.beginDraw();
  pg.background(0);
  pg.fill(255);
  pg.textFont(font);
  pg.textSize(800);
  pg.pushMatrix();
  pg.translate(width/2, height/2-215);
  pg.textAlign(CENTER, CENTER);
  pg.text("a", 0, 0);
  pg.popMatrix();
  pg.endDraw();

  int tilesX = 16;
  int tilesY = 16;

  int tileW = int(width/tilesX);
  int tileH = int(height/tilesY);

  for (int y = 0; y < tilesY; y++) {
    for (int x = 0; x < tilesX; x++) {

      // WARP
      int wave = int(sin(frameCount * 0.05 + ( x * y ) * 0.07) * 100);

      // SOURCE
      int sx = x*tileW + wave;
      int sy = y*tileH;
      int sw = tileW;
      int sh = tileH;


      // DESTINATION
      int dx = x*tileW;
      int dy = y*tileH;
      int dw = tileW;
      int dh = tileH;
      
      copy(pg, sx, sy, sw, sh, dx, dy, dw, dh);

    }
  }
}

That’s it!

We’re done! I hope you understand everything properly. If you have any recommendations for this tutorial, feel free to get in touch with me. And of course i would love to see what kind of visuals you come up with. Drop me a line!

post@timrodenbroeker.de

Happy coding!

Download this tutorial with all assets on Github

    Published by Tim on Tuesday April 16, 2019

    related blogposts

    19. July 2019

    Getting started with Creative Coding

    I quite get often asked for advices on how to get started with creative coding. These are my most essential […]

    14. April 2019

    Processing-Tutorial: Video Export

    One of the most powerful features of Processing in comparison to all web-based approaches and frameworks (like p5.js) is the […]

    1. March 2019

    How to rasterize an image with Processing

    In this post i’ll teach you how to access the data of an image and how to use it to […]

    28. February 2019

    My 10 favorite Processing-libraries

    So called “libraries” extend the functionality of the software-development-enviroment Processing. Please handle those extensions with care: If you are a […]

    18. December 2018

    Processing or p5.js? My opinions

    In this video i share my opinions about the benefits of p5.js and Processing. I also talk about how i’ve […]

    Subscribe to my newsletter!