Week 4: Spell-Binding Incantations (Generative Text)

I solemnly swear I was up to no good with this assignment.

I have been back into a Harry Potter phase of sorts so of course I had to project that agenda onto this assignment. My urge for this week had always been to make text representative of its meaning, because I love when that is done in media. And when I thought of linking it to Harry Potter, I thought that spells would be the perfect way to achieve this effect.

I ran through a lot of ideas and settled on three relatively well-known spells: Wingardium Leviosa, Accio, and Lumos. Wingardium Leviosa (LeviOsa not LeviosAR) is the levitating charm many people might remember from the first movie, which does exactly what you would expect a levitating charm to do. So, I wanted this text to float up from the bottom and then once it had reached around the top, keep hovering over there. This was simple enough with a function to change the y value according to a particular speed.

In the process of floating up (pay attention, Ron)

The Accio spell can summon any object you take the name of (unless of course it has some anti-summoning protection). To put this effect in text I wanted to have the letters floating around the screen randomly, and then have them abruptly come to their final location. For this, I re-used the Letter class we had done in class, and some of the code from the circular orbit example, because I basically wanted to achieve the opposite flow of it. I made some minor changes to the Letter class, which is here:

class Letter { //copied from in-class code with very slight changes
  float x, y;
  float xSpeed, ySpeed;
  char letter;

  Letter(float _x, float _y, char _c) {
    x = _x;
    y = _y;
    xSpeed = ySpeed = 0;
    letter = _c;
  }

  void update() {
    x += xSpeed;
    y += ySpeed;
  }

  void display() {
    text(letter,x,y);
  }

  void checkEdges() {
    if (y>height) {
      y=0;
    }
    if (y<0) {
      y=height;
    }
    if (x>width) {
      x=0;
    }
    if (x<0) {
      x=width;
    }
  }
}

Here’s a random screenshot of the moving letters:

Accio a coherent blog post :’)

And finally, Lumos would produce a small glowing white light at the tip of your wand, useful for seeing in the darkness. This was pretty simple to achieve, by drawing white text instead of the yellow when a certain time had passed, but also having some yellow transparent bigger text in the background. The idea was that the colour change from yellow to white would give the lighting up effect.

The Golden Trio

Having decided the overall placement and executing the spells, I thought of inserting a background for a more Harry Potter-esque experience, and decided there could be nothing better than the Hogwarts castle itself.

Hoggy hoggy Hogwarts in the background

And then I added a darker tint and added an alpha value to make it faded, and I was done!

Final Still

I haven’t talked a lot about my process so I’ll mention the highlights here. First of all, I had to download the font and it was not a monospaced one, as I realised in my very first test. So I had to figure out a way to make them it look regularly spaced in the spells where I was separating characters, and for this I used arrays. Every element of the two text_width arrays stored the length of the string uptil the current character, and I updated that alongside in the displaying loop. For the Wingardium Leviosa levitation, I also added the noise code from class to make it look more natural.

Iconic Harry Potter Font

For each spell, I made a function which carried out their meaning, and timed them using frameCount. I also included the functionality that on clicking the mouse, frameCount would be reset to -1, hence essentially restarting the sketch. I was thinking of adding Hedwig’s theme as an audio file to run in the background, but then I thought it wouldn’t run long enough and would sound weird. I do plan to check out if I can keep the audio running without it resetting with the mouse click. And of course, the background image and font file had to be included in the sketch folder in Processing.

This was the main sketch’s code:

PFont f;
PImage img;
String spell1 = "Wingardium Leviosa"; //spell for levitation
String spell2 = "Accio"; //spell for summoning something
String spell3 = "Lumos"; //spell for lighting the tip of the wand
int posx1;
int posy1;
float posx2;
int posy2;
int speed = 2;
float[] text_widths1; //will help in determining the width of substrings
float[] text_widths2;
int x_offset = 250;
Letter letters[] = new Letter[spell2.length()]; 

void setup(){
  size(640, 640);
  img = loadImage("Hogwarts background.jpg");
  f = createFont("HARRYP__.TTF", 72); //Harry Potter font used in the movies
  textFont(f);
  textAlign(CENTER);
  posx1 = width/2 - x_offset;
  posy1 = height - 72;
  posx2 = width/2 - textWidth(spell2)/2;
  posy2 = height/2 - 36;
  text_widths1 =  new float[spell1.length()];
  text_widths2 =  new float[spell2.length()];
  for(int i = 0; i<spell2.length(); i++){ //initialising the moving letters for Accio
    letters[i] = new Letter(random(640), random(640), spell2.charAt(i));
    letters[i].xSpeed = random(-5,5);
    letters[i].ySpeed = random(-5,5);
  }
}

void draw(){
  background(0);
  tint(136, 152, 155, 80); //dark, faded effect
  image(img, 0, 0);
  
  fill(245, 206, 49);
  for(int i=0; i<spell1.length(); i++)
  {
    //as it is not a monospaced font, text_widths arrays help in storing the width of the string upto
    // that character. Here I calculate this by adding the previous element of the array to the width of the current letter
    if(i==0)
      text_widths1[i] = textWidth(spell1.charAt(i)); 
    else
      text_widths1[i] = text_widths1[i-1] + textWidth(spell1.charAt(i));
      
    text(spell1.charAt(i), posx1 + (i==0? text_widths1[0]-13: text_widths1[i]), posy1 + noise(frameCount*.01+i*0.01)*100 - 50);

  } 
  levitate(); //starts the levitating effect 
  
  if(frameCount > 250 && frameCount < 400) //for the passage of time
  {
    for(int i = 0; i<spell2.length(); i++){ //random movement
      letters[i].update();
      letters[i].display();
      letters[i].checkEdges();
    }
  }
  
  if(frameCount >= 400)
    summon(); //to bring the letters into place
    
  if(frameCount >= 450 && frameCount < 525){
    //fill(181, 192, 193); - discarded idea for turning grey to yellow
    fill(245, 206, 49);
    text(spell3, width/2 + 100, height-height/4);
  }
  
  if(frameCount >= 525){
    lightItUp(); //to give the effect of the yellow being lit up into white
  }
  
}

void levitate(){
  if(posy1 - speed > 120) //to levitate upwards uptil a certain point below the border is reached
    posy1 -= speed;
}

void summon(){
  for(int i = 0; i<spell2.length(); i++){ //stops the random movement by fixing x and y values
    if(i==0)
      text_widths2[i] = textWidth(spell1.charAt(i));
    else
      text_widths2[i] = text_widths2[i-1] + textWidth(spell1.charAt(i));
      
    letters[i].x = posx2 + (i==0? text_widths2[0]-13: text_widths2[i]); //same logic for character widths
    letters[i].y = posy2;
    letters[i].display();
  }
}

void lightItUp(){
  fill(245, 206, 49, 90); //to give a faint yellow glow from behind
  textSize(79);
  text(spell3, width/2 + 100, height-height/4);
  fill(255);
  textSize(72);
  text(spell3, width/2 + 100, height-height/4);
}

void mouseClicked(){
  frameCount = -1; //resets everything because setup() is called at frameCount = 0
}

And with all that said, here is the video with all the animations I have been talking about:

I hope this was able to achieve even a little bit of a magical effect. And there’s nothing more to add from my side, so I’ll just say:

Mischief Managed.

2 thoughts on “Week 4: Spell-Binding Incantations (Generative Text)”

Leave a Reply