Last week I began to use classes. This allowed me to start treating the “face” element of my sketch as a particle and easily move it across the canvas with the bouncing ball function. I felt like I needed to give my self portrait a little life. However, I still had some knowledge gaps that translated in limitations on how to make my self portrait a little more interesting.

Grabación de pantalla 2025-10-07 a la(s) 19.30.45.mov

Technical Presentation

For the technical presentation, I was aiming to overcome this barrier and understand better my own previous work to improve it and present the updated version of my self portrait. I was very tempted on doing something from scratch. However I also thought that I may also run into more problems and , because of time, presenting something I don’t feel as satisfied for the midterm deliverable. I have made a few changes in my code that I will touch more deeply in my week 6 blog with the worksheet and everything, once I finish that. Here is the complete code for my sketch.

let faces = []; // array of faces
let s = 0.5; // scale?
let r, g, b; // variables for color
function setup() {
  push();

  createCanvas(600, 500);

  //mouse position changes the r and g values of color
  r = map(mouseX, 0, width, 0, 255);
  g = map(mouseY, 0, height, 0, 255);
  b = 40;
}

function draw() {
  background(190, 60, 68);

  for (const face of faces) {
    //runs the class functions for each face on the array
    face.run();

    if (faces.length > 80) {
      // resets the array of faces at 80 faces.
      faces = [];
    }
  }
}

function mouseDragged() {
  // instantiates a new face, populating the array, with each click, making it appear where the mouse is located in x and y, as well as setting a random speed and scale.
  faces.push(
    new Face(mouseX, mouseY, random(-5, 5), random(-5, 5), random(0.05, 0.5))
  );
  colorMode(HSB, mouseX, mouseY, b, 0.5); // function to get other colors
}

class Face {
  // gets the x, y, x and y speeds as well as the scale of the face
  constructor(_x, _y, _xspeed, _yspeed, _scale) {
    this.x = _x;
    this.y = _y;
    this.xspeed = _xspeed;
    this.yspeed = _yspeed;
    this.s = _scale;

    //added current angle and target angle to the class for rotating the faces
    this.angle = random(360); // sets a random angle for the face to start
    this.targetAngle = this.angle; // it's the angle where the other one needs to get to.
  }

  run() {
    // triggers the move, bounce and display functions
    this.move();
    this.bounce();
    this.display();
  }

  move() {
    // moves the ball with a given speed
    this.x += this.xspeed;
    this.y += this.yspeed;
  }

  faceRotate() {
    if (this.angle != this.targetAngle) {
      // keep increasing the angle until it gets to the target by the following speed.
      this.angle += 0.1; // speed of rotation for the angle that is being updated
    }
  }

  bounce() {
    // base width and heigth of the largest arc of the face
    let baseW = 255; 
    let baseH = 255;
    // half of it to get the radius, but also multiply it for the value of scale to measure the distinct faces
    let halfW = (baseW / 2) * this.s;
    let halfH = (baseH / 2) * this.s;

    //bounce the faces and update the target angle where they should rotate to get the always rotating effect
    if (this.x < halfW || this.x > width - halfW) {
      this.xspeed *= -1;
      this.x = constrain(this.x, halfW, width - halfW);
      this.targetAngle += 10;
    }
    if (this.y < halfH || this.y > height - halfH) {
      this.yspeed *= -1;
      this.y = constrain(this.y, halfH, height - halfH);
      this.targetAngle += 10;
    }
  }

  display() {
    this.faceRotate(); //calling the function. this one changes the angle with the if statement
    push();

    translate(this.x, this.y); // allows me to move the entire face together. Always translate first.

    scale(this.s); //After translated now I can scale.

    rotate(this.angle); // calling the rotate function who's doing the actual rotation using the updated angle

    //helmet like skin colour part
    noStroke();
    fill(240, 204, 186);
    arc(0, 0, 255, 255, HALF_PI + QUARTER_PI, PI + PI, PIE);

    //pink rest of the head
    noStroke();
    //stroke(255, 150, 200);
    //strokeWeight(2);
    fill(random(199), 80, random(148));
    arc(0, 0, 200, 200, 0, HALF_PI + QUARTER_PI);

    //right eye small circle
    fill(80, random(199), random(142));
    stroke(84, 111, 114);
    strokeWeight(2);
    circle(50, -50, 30);

    //left eye ellipse
    fill(random(169), random(199), random(80));
    stroke(199, 129, 80);
    strokeWeight(5);
    ellipse(-50, -60, 60, 100);

    //mouth-like rectangle
    fill(71, 70, 64);
    stroke(255, 214, 206);
    strokeWeight(5);
    rect(-30, 50, 60, 10);

    //nose triangle
    stroke(71, 70, 64);
    strokeWeight(2);
    fill(random(199), 183, 80);
    triangle(0, -50, 50, -10, 0, 0);

    pop();
  }
}

This is the result of those changes all combined in a video.

faces.mov

One of the things that I was so happy to achieve in my code was the effect of rotating the face each time that it touches a canvas’ boundary. This was a hard one to think about. There’s a couple of things, that I found magical, happening within the code.

First, because I was managing each face as an object from the class Face {}, I needed to declare other this.xx variables within the constructor so I can control the angle of each individual face. I decided to declare and initialize two of these variables. The variable this.angle would represent the current angle where the face is at, initialized at a random position. While the this.targetAngle is initialized at the value of this.angle.

Screenshot 2025-10-15 at 12.00.24 PM.png

However, the this.targetAngle value will be set when the face bounces on any of the canvas’ boundaries. This rotation also would be reset each time a face bounces, allowing the face to have the effect of an infinite angular change when bouncing. I felt that this would improve the animation.

Screenshot 2025-10-15 at 12.06.49 PM.png

After that, I needed to declare a function that would help me to check and update the value of this.angle if it’s not equal to this.targetAngle. This update would allow me to gradually change the angle of each face.

Screenshot 2025-10-15 at 12.02.06 PM.png

The final step of the magic happens when I display the face. Here’s where I call the this.faceRotate() function that changes the value of the angle gradually. And finally I am using the this.angle variable to set the value of the angle.

Screenshot 2025-10-15 at 12.18.32 PM.png