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 } } }