RULES:
-Use the mouse (either by pressing or moving around) to interact with animations
-Click any key to cycle through different animations (click within the canvas first if not working because wordpress is weird)
Note: If file is opened through google browser, mouse isn’t limited on first animation and they all generally run smoother
//Ashley Chan
//Section C
//ashleyc1@andrew.cmu.edu
//Final Project - Type in Motion
/////////////////////////////////////
// MAIN CONTROL //
///////////////////////////////////
var index = 0;
//global var for images
var revealImg;
var twinkleImg;
var eraseImg;
var sprayHintImage;
var sprayOverlayImage;
function preload() {
//load all the images
revealImg = loadImage("https://i.Imgur.com/giFSIcI.jpg?1");
twinkleImg = loadImage("https://i.imgur.com/hqn6Cv9.jpg?1");
eraseImg = loadImage("https://i.imgur.com/VO4buSz.png");
sprayHintImage = loadImage("https://i.imgur.com/P6LkUET.jpg");
sprayOverlayImage = loadImage("https://i.imgur.com/dr6JWoH.png");
}
function setup() {
createCanvas(480, 180);
background(0);
//index that cycles through animations
//call each animations' setups
//depending on index number
if(index == 0){
revealSetup();
}
if(index == 1){
twinkleSetup();
}
if(index == 2){
eraseSetup();
}
if(index == 3){
spraySetup();
}
}
function draw() {
//call each animations' draw depending on index number
if(index == 0) {
revealDraw();
}
if(index == 1){
twinkleDraw();
}
if(index == 2){
eraseDraw();
}
if(index == 3){
sprayDraw();
}
}
// Cycles through animations every time
//any key is pressed
function keyPressed(){
index = (index + 1)%4;
setup();
}
////////////////////////////////////////////
// REVEAL ANIMATION //
///////////////////////////////////////////
//var that will spell out reveal
var revealCircles;
var revealDots;
function revealSetup(){
//Draw a black rectangle for every animation
//because we need to make sure the animations
//restart without actually calling setup
//and messing everything up
fill(0);
rect(0, 0, 480, 180);
revealCircles = [];
revealDots = [];
// iterate through pixels
image(revealImg, 0, 100);
revealImg.loadPixels();
for(var i = 0; i < 2 * revealImg.width; i++) {
for(var j = 0; j < revealImg.height; j++) {
var revealIndex = i * 2 + (j * revealImg.width)*8;
//locate the dark pixels of underlaying image
//where there is dark, make a revealCircle
if (revealImg.pixels[revealIndex] < 200){
revealDots.push(createVector( i / 2, j * 2));
}
}
}
var num_circles = 0;
//draw certain number of revealCircles every frame
while (num_circles < 400){
var c = revealCreateCircle();
if (c) {
revealCircles.push(c);
num_circles++;
}
}
}
function revealDraw(){
background(0);
//draw the revealCircles
for(var i = 0; i < revealCircles.length; i++) {
var x = revealCircles[i].x;
var y = revealCircles[i].y;
var r = revealCircles[i].r;
//calculate distance around mouse
//any space within radius will be drawn and shown
var d = dist(x, y, mouseX, mouseY);
if (d < 90) {
//center image
push();
scale(.5, .5);
translate(150, 0);
revealCircles[i].show();
pop();
}
}
}
//While creating a new revealCircle
//Do not create one inside existing one
function revealCreateCircle(){
var x;
var y;
// find a random position to create a revealCircle
var position = int(random(0, revealDots.length));
x = revealDots[position].x;
y = revealDots[position].y;
var valid = true;
for (var i = 0; i < revealCircles.length; i++) {
//Don't draw inside another revealCircle
// If generated already drawn revealCircle, redo
if (dist(x, y, revealCircles[i].x, revealCircles[i].y) <= revealCircles[i].r) {
valid = false;
break;
}
}
//if no revealCircle drawn at spot, draw one
if (valid) {
return new revealCircle(x, y, width, height);
}
return false;
}
//define the circles
function revealCircle(xPos, yPos, gwidth, gheight){
this.x = xPos;
this.y = yPos;
this.r = 8;
this.width = gwidth;
this.height = gheight;
//controls the look of the revealCircles
//randomizes color when mouse is pressed
this.show = function(){
fill(255);
noStroke();
strokeWeight(1);
ellipse(this.x, this.y, this.r);
}
}
////////////////////////////////////////////////
// TWINKLE ANIMATION //
///////////////////////////////////////////////
//var that will spell out twinkle
var twinkleCircles;
var twinkleDots;
function twinkleSetup(){
fill(0);
rect(0, 0, 480, 180);
twinkleCircles = [];
twinkleDots = [];
// iterate through pixels
//image(twinkleImg, 0, 100);
twinkleImg.loadPixels();
//locate the dark pixels of underlaying image
//where there is dark, make a twinkleCircle
for(var i = 0; i < 2 * twinkleImg.width; i++) {
for(var j = 0; j < twinkleImg.height; j++) {
var twinkleIndex = i * 2 + (j * twinkleImg.width)*8;
if (twinkleImg.pixels[twinkleIndex] < 200){
twinkleDots.push(createVector( i / 2, j * 2));
}
}
}
var num_circles = 0;
//draw certain number of twinkleCircles every frame
while (num_circles < 300){
var c = twinkleCreateCircle();
if (c) {
twinkleCircles.push(c);
num_circles++;
}
}
//draw the twinkleCircles
for(var i = 0; i < twinkleCircles.length; i++) {
var x = twinkleCircles[i].x;
var y = twinkleCircles[i].y;
var r = twinkleCircles[i].r;
//center image
push();
scale(.6, .6);
translate(50, 80);
twinkleCircles[i].show();
pop();
}
}
function twinkleDraw(){
//if mouse pressed, "redraw" circles
//so that color is randomized
if(mouseIsPressed) {
for(var i = 0; i < twinkleCircles.length; i++) {
var x = twinkleCircles[i].x;
var y = twinkleCircles[i].y;
var r = twinkleCircles[i].r;
//center image
push();
scale(.6, .6);
translate(50, 80);
twinkleCircles[i].show();
pop();
}
}
}
//While creating a new twinkleCircle
//Do not create one inside existing one
function twinkleCreateCircle(){
var x;
var y;
// find a random position to create a twinkleCircle
var position = int(random(0, twinkleDots.length));
x = twinkleDots[position].x;
y = twinkleDots[position].y;
var valid = true;
for (var i = 0; i < twinkleCircles.length; i++) {
//Don't draw inside another twinkleCircle
// If generate already drawn twinkleCircle, redo
if (dist(x, y, twinkleCircles[i].x, twinkleCircles[i].y) <= twinkleCircles[i].r) {
valid = false;
break;
}
}
//if no twinkleCircle drawn at spot, draw one
if (valid) {
return new twinkleCircle(x, y, width, height);
}
return false;
}
//define twinkleCircles
function twinkleCircle(xPos, yPos, gwidth, gheight){
this.x = xPos;
this.y = yPos;
this.r = 8;
this.width = gwidth;
this.height = gheight;
//controls the look of the twinkleCircles
//randomizes color when mouse is pressed
this.show = function(){
stroke(255);
strokeWeight(1);
//start out as empty twinkleCircles
var value = 0;
fill(value);
//change the color every time mouse is pressed
if (mouseIsPressed) {
value = random(0, 255);
fill(value, value, value);
}
ellipse(this.x, this.y, this.r);
}
}
////////////////////////////////////////////
// ERASE ANIMTATION //
///////////////////////////////////////////
//var for erase animation
var eraseLastMinute;
var eraseCurrentMinute;
//eraseIndex for animations
var eraseIndex = 0;
function eraseSetup() {
//scale(.5, .5);
fill(0);
rect(0, 0, 480, 180);
eraseImg.loadPixels();
eraseLastMinute = minute();
//make for loop to control how many images we are making
for (i = 0; i < 50; i++) {
image(eraseImg, random(-50, 800),
random(-50, height), 100, 43);
}
}
function eraseDraw() {
fill(0);
noStroke();
ellipse(mouseX, mouseY, 30, 30);
//call setup and reset every minute
eraseCurrentMinute = minute();
//if a minute has passed, call setup and generate
//different arrangement of words
if (eraseLastMinute != eraseCurrentMinute) {
eraseSetup();
}
}
///////////////////////////////////////////
// SPRAY ANIMATION //
//////////////////////////////////////////
var sprayDots;
function spraySetup() {
fill(0);
rect(0, 0, 480, 180);
noCursor();
noStroke();
sprayDots = [];
}
function sprayDraw() {
image(sprayHintImage, 50, 100);
sprayHintImage.resize(300, 100);
background(0);
var position = createVector(mouseX, mouseY);
//if mouse is pressed, draw a bunch of sprayCircles
//that move toward the overlaying image
if (mouseIsPressed) {
var target = sprayFindPixel();
var spraydot = new sprayDot(position, target);
sprayDots.push(spraydot);
//allow user to draw a bunch of dots
if (sprayDots.length > 2000) sprayDots.shift();
}
//draws the sprayDots
for (var i = 0; i < sprayDots.length; i++) {
//make sure sprayDots align with hint image
push();
translate(100, 50);
sprayDots[i].update();
sprayDots[i].draw();
pop();
}
//call image of Spray outline
image(sprayOverlayImage, 100, 50);
sprayOverlayImage.resize(300, 100);
}
//calculate where the underlying image is dark
//and then draw a spraydot overtop
function sprayFindPixel() {
var x;
var y;
for (var i = 0; i < 200; i++) {
x = floor(random(sprayHintImage.width));
y = floor(random(sprayHintImage.height));
if (red(sprayHintImage.get(x, y)) < 255) break;
}
return createVector(x, y);
}
//create sprayDots and define characteristics
function sprayDot(position, target) {
this.position = position;
this.target = target;
this.diameter = random(10, 20);
}
sprayDot.prototype.update = function() {
this.position =
p5.Vector.lerp(this.position, this.target, 0.1);
};
sprayDot.prototype.draw = function() {
//color of sprayDots
fill(255);
ellipse(this.position.x, this.position.y, this.diameter, this.diameter);
};
For this project, I was interested in creating interactive animations that allowed type to be dynamic. I wanted the user to interact with the text based on the actions the words described (erase = erase the words). This project was super challenging and I wish I had more time to generate more interactive animations but I’m overall satisfied with it because I like exploring how to make type more dynamic that I can now use within my own art and design practice.