Raya Tabassum: Generative Text Assignment

Concept:

This kinetic typography transforms static text into an interactive visual display. By treating each point of the font’s letters as a vehicle, the sketch brings the text “Dream” to life, allowing it to respond dynamically to the viewer’s mouse movements. Vehicles “arrive” at their designated spots to form the letters of the word and “flee” when the mouse comes close, creating an engaging effect that feels both chaotic and ordered. The addition of the gradient background adds depth and visual interest, making the typography a part of an aesthetically pleasing composition of a sunset.

Use your mouse to go through the word to interact with it:

Font Points Extraction and Vehicle Initialization:

//Extract points from the font
let points = font.textToPoints(textString, 75, 320, fontSize, {
  sampleFactor: 0.1
});

//Initialize vehicles for each point
for (let i = 0; i < points.length; i++) {
  let pt = points[i];
  let vehicle = new Vehicle(pt.x, pt.y);
  vehicles.push(vehicle);
}

Extracting points from text and converting them into “vehicles” was a bit complex due to the need to handle font rendering and point manipulation. The textToPoints() function is used to get the vector points for each letter, which are then used to create vehicle objects that simulate motion.

Also for the Vehicle class, implementing behaviors such as “arrive” and “flee” required understanding of steering behaviors and force accumulation in a physics-based simulation. Balancing these forces to achieve smooth and natural movement was challenging, especially when trying to simulate both attraction to a target point and repulsion from the mouse cursor.

Full code:

//Preload the font
let font;
let vehicles = []; //Array to hold the 'vehicle' objects

function preload() {
  //Load the font from the assets
  font = loadFont('Hogfish DEMO.otf'); 
}

function setup() {
  createCanvas(700, 500); //Set up the canvas
  //Create a background gradient
  setGradient(0, 0, width, height, color('#EBC249'), color('#A52D56'), Y_AXIS);

  //Define the text properties
  let textString = 'Dream';
  let fontSize = 180;
  //Convert the text to a series of points
  let points = font.textToPoints(textString, 75, 330, fontSize, {
    sampleFactor: 0.1 //Determines the density of the points
  });

  //Create a vehicle object for each point
  for (let i = 0; i < points.length; i++) {
    let pt = points[i];
    let vehicle = new Vehicle(pt.x, pt.y);
    vehicles.push(vehicle);
  }
}

function draw() {
  //Refresh the gradient background each frame
  setGradient(0, 0, width, height, color('#EBC249'), color('#A52D56'), Y_AXIS);

  //Update and display each vehicle
  for (let i = 0; i < vehicles.length; i++) {
    let v = vehicles[i];
    v.behaviors();
    v.update();
    v.show();
  }
}

//Constants for gradient direction
const Y_AXIS = 1;
const X_AXIS = 2;

//Function to create a gradient background
function setGradient(x, y, w, h, c1, c2, axis) {
  noFill();

  //Create a vertical gradient
  if (axis === Y_AXIS) {
    for (let i = y; i <= y + h; i++) {
      let inter = map(i, y, y + h, 0, 1);
      let c = lerpColor(c1, c2, inter);
      stroke(c);
      line(x, i, x + w, i);
    }
  } 
  //Create a horizontal gradient
  else if (axis === X_AXIS) {
    for (let i = x; i <= x + w; i++) {
      let inter = map(i, x, x + w, 0, 1);
      let c = lerpColor(c1, c2, inter);
      stroke(c);
      line(i, y, i, y + h);
    }
  }
}

//The Vehicle class
class Vehicle {
  constructor(x, y) {
    this.pos = createVector(random(width), random(height)); // Start position
    this.target = createVector(x, y); //Target position
    this.vel = p5.Vector.random2D(); //Initial velocity
    this.acc = createVector(); //Acceleration
    this.r = 8; //Radius
    this.maxspeed = 10; //Maximum speed
    this.maxforce = 1; //Maximum steering force
  }

  //Combine behaviors
  behaviors() {
    let arrive = this.arrive(this.target);
    let mouse = createVector(mouseX, mouseY);
    let flee = this.flee(mouse);

    arrive.mult(1);
    flee.mult(5);

    this.applyForce(arrive);
    this.applyForce(flee);
  }

  //Apply a force to the vehicle
  applyForce(f) {
    this.acc.add(f);
  }

  //Update the vehicle's position
  update() {
    this.pos.add(this.vel);
    this.vel.add(this.acc);
    this.acc.mult(0); //Reset acceleration each frame
  }

  //Display the vehicle
  show() {
    stroke(255);
    strokeWeight(8);
    point(this.pos.x, this.pos.y);
  }

  //Steer the vehicle towards a target
  arrive(target) {
    let desired = p5.Vector.sub(target, this.pos); //A vector pointing from the position to the target
    let d = desired.mag();
    let speed = this.maxspeed;
    if (d < 100) {
      //Adjust speed based on distance to the target
      speed = map(d, 0, 100, 0, this.maxspeed);
    }
    desired.setMag(speed);
    let steer = p5.Vector.sub(desired, this.vel);
    steer.limit(this.maxforce);
    return steer;
  }

  //Make the vehicle flee from the mouse
  flee(target) {
    let desired = p5.Vector.sub(target, this.pos);
    let d = desired.mag();
    if (d < 50) {
      desired.setMag(this.maxspeed);
      desired.mult(-1); //Go in the opposite direction
      let steer = p5.Vector.sub(desired, this.vel);
      steer.limit(this.maxforce);
      return steer;
    } else {
      return createVector(0, 0); //No force if the mouse is far away
    }
  }
}

 

Leave a Reply