For my final project, I really wanted to work with text and explore alternate ways of moving through a poem. I chose to focus on one of my favorite poets, pablo neruda, and chose his poem, Ode to Things, as it has a lot of beauty to it.
// ilona altman
// final project
// section a
// iea @ andrew.cmu.edu
// this is a poem showcase of
var odetothings;
let fromHere;
let toHere;
let thefont; //allegra sans from GoogleFont
let poemletters = []; //array of letters
let poem = "ode to things by neruda - "; // title of the poem
let reversedpoem = reverseString(poem); // reversed
let nextimageCount; //image counter
let imagelinks= ['https://i.imgur.com/EiIMWxn.png',
'https://i.imgur.com/XCmsYws.png',
'https://i.imgur.com/fQZf2Sc.png'];
let imagesofthings = []; // image array
let currentThingImage;
function preload() {
//loading the text and the poem
odetothings = loadStrings("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/ode-2.txt");
//thefont = loadFont('thefont.ttf'); (cannot figure out hot to upload font for WordPress)
//loading the images
for (l = 0; l < imagelinks.length; l++) {
imagesofthings[l] = loadImage(imagelinks[l]);
}
}
function setup() {
createCanvas(450,640);
//initializing variables
fromHere = 0;
toHere = 14;
nextimageCount = 0;
nextimage = 0;
//initial placement for letters in a circle
for (let i = 0; i < poem.length; i ++) {
var radius = 120;
var angle = i * TWO_PI/poem.length;
var inputX = radius * sin(angle);
var inputY = radius * cos(angle);
var inputL = reversedpoem.charAt([i]);
poemletters[i] = makeLetters(inputL, inputX, inputY);
}
}
function draw() {
background(255,255,255);
//images rotating
push();
imageMode(CENTER);
rotate(frameCount/10000);
currentThingImage = image(imagesofthings[nextimage],width/2,height/3);
pop();
//updating the position of the letters
Update();
// making sure that there is continuous text
if (toHere > odetothings.length){
fromHere = 0;
toHere = 14;
}
// the text on the bottom that runs through the poem
for (var i = fromHere; i < toHere; i++) {
textSize(14);
//textFont(thefont);
fill(150,190,150);
var placeY = 340 + (i%14) * 20
text(odetothings[i], width/4, placeY);
}
}
// reversing the string so the text is easier to read
function reverseString(str) {
var splitting = str.split("");
var reversing = splitting.reverse();
var joined = reversing.join("");
return joined;
}
// the object of each letter
function makeLetters(inputL, inputX, inputY) {
var ltr = {letter: inputL,
px: inputX,
py: inputY,
showing: showLetters}; // draw the letter
return ltr;
}
function showLetters() {
push();
translate(width/2, height/3.5);
rotate(frameCount/1000);
//textFont(thefont);
textSize(30);
textAlign(CENTER);
fill(180,100,130);
text(''+ this.letter, this.px, this.py);
pop();
}
function Update() {
for (var i = 0; i < poemletters.length; i++){
poemletters[i].showing();
}
}
// when the mouse is pressed, the text cycles through
function mouseClicked() {
fromHere = fromHere + 14;
toHere = toHere + 14;
nextimageCount = nextimageCount + 1;
nextimage = nextimageCount%3;
}
]]>var renderer;
var starSize = 10;
var stars = [];
var launchSpeed = 40;
var starDuration = 1000;
var starLimit = 10;
var starGrowth = .5;
var starMoveFade = 20;
var persX = 30;
var persY = 30;
var timerMultiplier = 0.2;
var particles = [];
var particleSize = 5;
var particleSpeed = 2;
var limitZ = -7500;
var starWiggle = 4;
var bgStars = [];
var bgStarNumber = 100;
function setup() {
renderer = createCanvas(windowWidth, windowHeight, WEBGL);
for (var i = 0; i < 100; i++) {
bgStars.push(makeBackgroundStars());
bgStars[i].x = random(-15000, 16000);
}
frameRate = 60;
}
function draw() {
background(0);
fill(255);
translate(-width / 2, -height / 2, 0);
noCursor();
ellipse(mouseX, mouseY, 25);
//drawing background stars
if (bgStars.length < bgStarNumber) {
bgStars.push(makeBackgroundStars());
}
for (var i = 0; i < bgStars.length; i++) {
bgStars[i].draw();
bgStars[i].move();
if (bgStars[i].x < -15000) {
bgStars.splice(i,1);
}
}
//drawing particles
if (mouseIsPressed) {
particles.push(makeParticle());
for (var i = 0; i < particles.length; i++) {
particles[i].draw();
particles[i].move();
particles[i].remove();
if (particles[i].opq == 0){
particles.splice(i,1);
}
}
}
//drawing stars
for (var i = 0; i < stars.length; i++) {
stars[i].draw();
stars[i].count();
stars[i].move();
if (stars[i].timer > starDuration) {
stars.shift();
}
if (stars[i].x < -15000) {
stars.splice(i,1);
}
}
//removeStars
if (stars.length > starLimit) {
stars.shift();
}
}
//when the mouse is pressed, it starts creating a star
function mousePressed() {
stars.push(makeStar());
}
//as soon as the stars are done being created, they are not the newest
function mouseReleased() {
for (var j = 0; j < stars.length; j++) {
stars[j].newest = false;
}
particles = [];
}
function makeStar() {
var star = {x: mouseX, y: mouseY, z: 0,
size: starSize, newest: true,
perspectiveX: width/2 - mouseX,
perspectiveY: height/2 - mouseY,
// evolve: evolveStar,
count: countTimeStar, timer: 0,
flashX: mouseX, flashY: mouseY, flashZ: -1000,
draw: drawStar, move: moveStar, sizeDown: 20}
return star;
}
//drawing the star
//controls the growth of the star
function drawStar() {
// translate(this.x, this.y, this.z);
push();
translate(this.x, this.y, this.z);
strokeWeight(0);
stroke(200);
//radiance shown by multiple circle
for (var i = 0; i < 3; i++) {
fill(255, 255, 255, 40);
sphere(this.size * (1 + (i / 2)), 15, 15);
}
pop();
if (mouseIsPressed & this.newest == true) {
this.size += starGrowth;
}
if (mouseReleased) {
strokeWeight(0);
push();
translate(this.flashX, this.flashY, 0);
fill(255, 255, 255, 100 - 5 * (this.timer))
sphere(this.size * ((this.timer) ^ 2 / 10));
// sphere((this.size * ((this.timer)/10))/2 * 10);
pop();
}
}
//controls the movement of the star
function moveStar() {
//if it has been released,
if (this.newest == false) {
if (this.z <= limitZ) {
this.y += starWiggle * sin(millis()/300);
this.x -= starMoveFade;
while (this.sizeDown > 1) {
this.size = this.size * .99;
this.sizeDown -= 1;
print("hi")
}
}
else if (this.z > limitZ) {
this.z -= launchSpeed * this.timer * .25;
this.x -= this.perspectiveX / persX * (this.timer * timerMultiplier);
this.y -= this.perspectiveY / persY * (this.timer * timerMultiplier);
}
else {this.y -= launchSpeed * (this.timer * .05);
}
}
}
function countTimeStar() { //works!
if (frameCount % 2 == 0 & this.newest == false) {
this.timer++;
}
}
//creating particles that will gather towards the touch point
function makeParticle() {
var particle = {OriginX: mouseX, OriginY: mouseY, OriginZ: 0,
awayX: mouseX - random(-500, 500),
awayY: mouseY - random(-500, 500),
awayZ: 0 + random(-200, 200), opq: 20,
move: moveParticle, count: countTimeParticle,
draw: drawParticle, remove: removeParticle,
timer: 0}
return particle;
}
function drawParticle() {
push();
translate(this.awayX, this.awayY, this.awayZ);
fill(255, 255, 255, this.opq);
sphere(particleSize);
sphere(particleSize / 2);
pop();
}
function removeParticle() {
if (dist(this.OriginX, this.OriginY, this.OriginZ,
this.awayX, this.awayY, this.awayZ) <= 50) {
this.opq = 0;
}
}
function moveParticle() {
var distX = this.OriginX - this.awayX;
var distY = this.OriginY - this.awayY;
var distZ = this.OriginZ - this.awayZ;
this.awayX += distX * .03;
this.awayY += distY * .03;
this.awayZ += distZ * .03;
this.opq += 50 / dist(this.OriginX, this.OriginY, this.OriginZ,
this.awayX, this.awayY, this.awayZ);
}
function countTimeParticle() {
if (frameCount % 2 == 0 & this.newest == false) {
this.timer++;
}
}
function makeBackgroundStars() {
var bgStar = {x: 14000, y: random(-5000, 5000), z: limitZ,
move: moveBackgroundStars, draw: drawBackgroundStars,
size: random(20, 60), fluctuate: random(400, 800)}
return bgStar;
}
function moveBackgroundStars() {
this.x -= starMoveFade;
this.y += 2 * sin(millis() / this.fluctuate);
}
function drawBackgroundStars() {
push();
translate(this.x, this.y, this.z);
noStroke();
sphere(this.size);
fill(255, 255, 255, 30 * (sin(millis() / this.fluctuate) / 2));
sphere(2 * this.size);
pop();
}
I created an interactive star generator as a simulation for the design project, “Tesla’s Sunlit Night”. The concept is that people entering this brand pop-up shop will be able to interactive the inner walls the way this visualization allows the audience to. The only major difference in the interaction would be the clicks translated as touches.
It is meant to emphasize through experience what Tesla’s solar energy products can do. The reason this pop up is called, “Sunlit Night” is because the experience of creating stars in the dark ceiling , representing the night sky will be powered by the solar energy.
To interact, just click anywhere on the screen. The longer you hold, it will increase in size. I wanted to push further in the growth of star and how each differ in their appearance, but it was computationally too expensive, and could not be realized.
]]>Kristine and I created 2 interactive stories from the Bible since Christianity is something that we really value. We decided to create this as a method to teach children about the Bible while also letting them have fun.
Kristine worked on the “Feeding the 5000” story while I worked on the “Noah’s Ark” story. We met together throughout the week to make sure our two programs connected and worked smoothly which took the most time. I also took charge of securing of online images and creating the image arrays since I was working on the more image heavy portion and Kristine in turn worked on the menu screen and the character movement as well. We divided the work very evenly and made sure to consult with each other if we had problems or didn’t know how to do something.
The only thing you might need to know to play our game is to make sure to completely go to the end of the path to the end of canvas width, since it goes to the next screen automatically once the character gets to the end.
We had so much fun creating this project!
// Kristine Kim & Min Ji Kim Kim
// Section D & A
// younsook & mkimkim
// Final Project
// -------------------------------- VARIABLES --------------------------------
// GENERAL
var texts = [];
var people = [];
var peopleImages = [];
var character;
// MENU
var screen = "menu"; //screen always set to menu when first opened
var Bible;
var leftFrame;
var rightFrame;
//FEEDING THE 5000
var food = [];
var foodImages = [];
var disciple;
var crowd1;
var crowd2;
var crowd3;
// NOAH'S ARK
var ark;
var rain = [];
var animalImages = [];
var animals = [];
var offsetX; // offsets for mouse drag later
var offsetY;
// --------------------------- PRELOAD IMAGES ----------------------------------
function preload() {
var foodLinks = [];
foodLinks[0] = 'https://i.imgur.com/I2GtIHI.png'; // fish
foodLinks[1] = 'https://i.imgur.com/37fSZcK.png'; // bread
foodLinks[2] = 'https://i.imgur.com/U5WevzT.png'; // basket
for (var i = 0; i < foodLinks.length; i++) { // push urls into array
foodImages[i] = loadImage(foodLinks[i]);
}
var animalLinks = [];
animalLinks[0] = 'https://i.imgur.com/CBoFToW.png'; // giraffe
animalLinks[1] = 'https://i.imgur.com/mOTcpZg.png'; // koala
animalLinks[2] = 'https://i.imgur.com/cIjfUHk.png'; // monkey
animalLinks[3] = 'https://i.imgur.com/ucc7kcb.png'; // elephant
animalLinks[4] = 'https://i.imgur.com/n3MKNo5.png'; // lion
animalLinks[5] = 'https://i.imgur.com/fcfIkPJ.png'; // bird
animalLinks[6] = 'https://i.imgur.com/XhSjml7.png'; // turtle
animalLinks[7] = 'https://i.imgur.com/bq0OgoB.png'; // zebra
for (var i = 0; i < animalLinks.length; i++) { // push urls into array
animalImages[i] = loadImage(animalLinks[i]);
}
var textLinks = [];
textLinks[0] = 'https://i.imgur.com/JB4gpam.png'; // Andrew Intro
textLinks[1] = 'https://i.imgur.com/CTLxAP2.png'; // Andrew End
textLinks[2] = 'https://i.imgur.com/XIGb2J9.png'; // Noah Intro
textLinks[3] = 'https://i.imgur.com/uEHleCT.png'; // Noah End
textLinks[4] = 'https://i.imgur.com/ouDdHh0.png'; // Feed Instructions
textLinks[5] = 'https://i.imgur.com/84dBAhN.png'; // Ark Instructions
for (var i = 0; i < textLinks.length; i++) { // push urls into array
texts[i] = loadImage(textLinks[i]);
}
var peopleLinks = [];
peopleLinks[0] = 'https://i.imgur.com/jZVql8t.png'; // Noah
peopleLinks[1] = 'https://i.imgur.com/EDZROu3.png'; // Andrew
peopleLinks[2] = 'https://i.imgur.com/moPXqEi.png'; // Jesus
for (var i = 0; i < peopleLinks.length; i++) { // push urls into array
peopleImages[i] = loadImage(peopleLinks[i]);
}
Bible = loadImage('https://i.imgur.com/VKVcQg5.png');
leftFrame = loadImage('https://i.imgur.com/XyGYYj0.jpg');
rightFrame = loadImage('https://i.imgur.com/jpBO0LB.jpg');
character = loadImage('https://i.imgur.com/BiTQr7u.png');
ark = loadImage('https://i.imgur.com/kqvTedI.png');
crowd1 = loadImage('https://i.imgur.com/Gz2HLDi.png');
crowd2 = loadImage('https://i.imgur.com/l4SCJCo.png');
crowd3 = loadImage('https://i.imgur.com/JON4rd1.png');
}
// -----------------------------------------------------------------------------
function setup() {
createCanvas(600, 600);
strokeJoin(MITER); // turtle code stroke join & cap settings
strokeCap(PROJECT);
for(var i = 0; i < 300; i++) {
rain.push(drop()); // load raindrops into array (for Noah's ark story)
}
}
// DRAWING SCREENS
function draw() {
if(screen == "menu") {
menuScreen();
}
else if (screen == "feedIntro") {
feedIntroScreen();
}
else if (screen == "feed") {
feedScreen();
}
else if (screen == "feedEnd") {
feedEndScreen();
}
else if (screen == "arkIntro") {
arkIntroScreen();
}
else if (screen == "ark") {
arkScreen();
}
else if (screen == "arkEnd") {
arkEndScreen();
}
}
// ---------------------------------- MENU -------------------------------------
function menuScreen() {
background("#0F7B96");
//table
noStroke();
fill("#553C2A");
rect(0, height - 120, width, 120);
//book
image(Bible, 80, 320);
//draw & change frame color if selected
//left frame
fill(0);
if(mouseX < 270 & mouseX > 40 && mouseY > 140 && mouseY < 320) {
fill("#AEA4FA");
}
rect(40, 150, 230, 180);
image(leftFrame, 50, 160);
//right frame
fill(0);
if(mouseX < 560 & mouseX > 330 && mouseY > 140 && mouseY < 320) {
fill("#5DED79");
}
rect(330, 150, 230, 180);
image(rightFrame, 340, 160);
//text
fill(255);
textAlign(CENTER);
textFont("Trebuchet MS", 25);
text("Select a Bible story", width / 2, 60);
textSize(20);
text("Jesus feeds the 5000", 155, 130);
text("Noah's Ark", 450, 130);
}
// SELECT A STORY
function mouseClicked() {
if (screen == "menu") {
if(mouseX < 270 & mouseX > 40 && mouseY > 140 && mouseY < 320) {
screen = "feedIntro"; // click on left frame
}
if(mouseX < 560 & mouseX > 330 && mouseY > 140 && mouseY < 320) {
screen = "arkIntro"; // click on right frame
}
}
if (screen == "feedEnd" || screen == "arkEnd") {
if(mouseX > 500 & mouseY > 530 && mouseX < 600 && mouseY < 600) {
screen = "menu"; // click on "menu" to go back to menu
}
}
if (screen == "feedIntro") {
if (mouseX > 500 & mouseY > 530 && mouseX < 600 && mouseY < 600) {
screen = "feed"; // click "go help ->" to go to main story
}
}
if (screen == "arkIntro") {
if (mouseX > 500 & mouseY > 530 && mouseX < 600 && mouseY < 600) {
screen = "ark"; // click "go help ->" to go to main story
}
}
}
// --------------------------- JESUS FEEDS THE 5000 ----------------------------
//STORY INTRODUCTION
function feedIntroScreen() {
background(255);
//display Andrew, basket, text, and button to go to main story
image(peopleImages[1], 50, height / 4);
image(foodImages[2], 230, 350);
image(texts[0], 250, 120);
goHelpButton();
}
// MAIN STORY SCREEN
function feedScreen() {
background("#a9c75f");
maze1();
createMainChar(); //display character
image(peopleImages[2], 330, 280); //display Jesus
for (var i = 0; i < food.length; i++) { //draw food inside the array
food[i].draw();
}
//display basket at mouse location
var scaleWidth = foodImages[2].width * 0.4; //scale basket image
var scaleHeight = foodImages[2].height * 0.4;
var bkx = scaleWidth / 2; // offset from left corner
var bky = scaleHeight / 2;
image(foodImages[2], mouseX - bkx, mouseY - bky, scaleWidth, scaleHeight);
//display instructions and crowds
image(texts[4], 0, 530);
image(crowd1, 230, 380);
image(crowd2, 310, 5);
image(crowd3, 350, 40);
//when character reaches the end of the maze, reset character position
//clear food array and go to end screen
if (people[0].x > width) {
people[0].x = 10;
people[0].y = 410;
food = [];
screen = "feedEnd";
}
}
//CODE FOR FOOD IMAGES
// create an object for food images
function makeFood(x, y, type) {
var foods = {x: x,
y: y,
type: type,
draw: foodDraw}
return foods;
}
function foodDraw() {
if (this.type === 'fish') { //draw bread at mouse location
image(foodImages[0], this.x, this.y);
}
else if (this.type === 'bread') { //draw fish at mouse location
image(foodImages[1], this.x, this.y);
}
}
// interaction keys to make fish and bread on canvas at mouse location
function keyPressed() {
if(screen == "feed") { // create fish = press f
if (keyCode == 70) {
var fx = foodImages[0].width / 2; // offset from left corner
var fy = foodImages[0].height / 2;
newFood = makeFood(mouseX - fx, mouseY - fy, 'fish');
food.push(newFood);
}
if (keyCode == 66) { // create bread = press b
var bx = foodImages[1].width / 2; // offset from left corner
var by = foodImages[1].height / 2;
newFood = makeFood(mouseX - bx, mouseY - by, 'bread');
food.push(newFood);
}
}
}
// create maze path using turtle graphics
function maze1() {
var ttl1 = makeTurtle(20, 480);
ttl1.setColor(color("#a6927b"));
ttl1.setWeight(40);
ttl1.forward(150);
ttl1.left(90);
ttl1.forward(100);
ttl1.left(90);
ttl1.forward(100);
ttl1.right(90);
ttl1.forward(280);
ttl1.right(90);
ttl1.forward(240);
ttl1.right(90);
ttl1.forward(80);
ttl1.right(90);
ttl1.forward(120);
ttl1.left(90);
ttl1.forward(100);
ttl1.left(90);
ttl1.forward(250);
ttl1.right(90);
ttl1.forward(200);
ttl1.left(90);
ttl1.forward(120);
ttl1.left(90);
ttl1.forward(70);
ttl1.right(90);
ttl1.forward(20);
//stage for Jesus
fill("#a6927b");
rect(280, 250, 100, 100);
}
// STORY ENDING SCREEN
function feedEndScreen() {
background(169, 146, 119);
//display Andrew, text and menu button
image(peopleImages[1], 50, height / 4);
image(texts[1], 250, 100);
menuButton(); // go back to "menu" button
}
// ------------------------------ NOAH'S ARK -----------------------------------
// STORY INTRODUCTION
function arkIntroScreen() {
background(255);
//display Noah, text, ark and button to go to main story
image(peopleImages[0], 50, height / 4);
image(texts[2], 250, 130);
image(ark, 250, 250);
goHelpButton(); // button to go to main screen
}
// MAIN STORY SCREEN
function arkScreen() {
// display background gradient
var turquoise = color(16, 157, 172);
var navy = color(1,84,134);
gradient(turquoise, navy);
//display maze, ark, character and instructions
maze2();
image(ark, 370, 80);
createMainChar();
image(texts[5], 0, 550);
// display animals
for (var i = 0; i < animalImages.length; i++) {
animals.push(makeAnimal(animalImages[i])); //push images into array
animals[i].draw(); //draw animals
// if the animal is moved, adjust that image location
if (animals[i].moving) {
animals[i].x = mouseX + offsetX;
animals[i].y = mouseY + offsetY;
}
}
// make it rain when pressing "r"
if (keyIsDown(82)) {
for (var r = 0; r < rain.length; r++) {
rain[r].display();
rain[r].falling();
}
}
//when character reaches the end of the maze, reset character position,
//clear animals array and go to end screen
if (people[0].x > width) {
people[0].x = 10;
people[0].y = 410;
animals = [];
screen = "arkEnd";
}
}
// to render background gradient for main story
function gradient(c1, c2) {
noFill();
noStroke();
for (var x = 0; x < width; x++) {
var mapColor = map(x, 0, width, 0, 2);
var c = lerpColor(c1, c2, mapColor);
stroke(c);
line(x, 0, x, height);
}
}
// create maze path using turtle graphics
function maze2() {
var ttl2 = makeTurtle(20, 480);
ttl2.setColor(color("#AF9879"));
ttl2.setWeight(40);
ttl2.forward(80);
ttl2.left(90);
ttl2.forward(400);
ttl2.right(90);
ttl2.forward(180);
ttl2.right(90);
ttl2.forward(150);
ttl2.right(90);
ttl2.forward(100);
ttl2.left(90);
ttl2.forward(120);
ttl2.left(90);
ttl2.forward(180);
ttl2.right(90);
ttl2.forward(170);
ttl2.left(90);
ttl2.forward(120);
ttl2.left(90);
ttl2.forward(300);
ttl2.right(90);
ttl2.forward(100);
}
// CODE FOR ANIMALS
// to click and drag animal image
function mousePressed() {
for (var i = 0; i < animalImages.length; i++) {
if (animals[i] == undefined) { // terminate if animals[i] is undefined
return;
}
// check if mouse is on the animal image
if (mouseX > animals[i].x & mouseX < animals[i].x + animalImages[i].width &&
mouseY > animals[i].y && mouseY < animals[i].y + animalImages[i].height) {
animals[i].moving = true;
// if yes, track location of the mouse click to the corner of animal image
offsetX = animals[i].x - mouseX;
offsetY = animals[i].y - mouseY;
}
}
}
function mouseReleased() {
//stop dragging animal
for (var i = 0; i < animalImages.length; i++) {
if (animals[i] != undefined) { //check if animals[i] is defined
animals[i].moving = false;
}
}
}
// create an object for animal images
function makeAnimal(image) {
var animal = {img: image,
x: random(10, 550),
y: random(10, 490),
moving: false,
draw: drawAnimal}
return animal;
}
function drawAnimal() {
image(this.img, this.x, this.y);
}
// CODE FOR RAIN
// create rain drop object
function drop() {
var drop = {x: random(0, width),
y: random(-5, height),
len: random(5, 20),
thick: random(1, 3),
vel: random(5, 15),
display: dropDisplay,
falling: dropFalling}
return drop;
}
// display rain drop
function dropDisplay() {
noStroke();
fill(255, 90);
ellipse(this.x, this.y, this.thick, this.len);
}
// make raindrop fall
function dropFalling() {
this.y += this.vel;
if (this.y > height) {
this.y = -this.len;
}
}
//STORY END SCREEN
function arkEndScreen() {
background(178, 153, 116);
//display Noah, text and menu button
image(peopleImages[0], 50, height / 4);
image(texts[3], 250, 130);
menuButton(); // go back to "menu" button
}
// -------------------------- CHARACTER & MOVEMENT -----------------------------
function createMainChar () {
//create the character object
people.push(makeCharacter());
people[0].draw();
//MOVE CHARACTER BY PRESSING ARROW KEYS
if (keyIsPressed) {
if (keyCode === UP_ARROW) {
people[0].y -= 2;
}
else if (keyCode === DOWN_ARROW) {
people[0].y += 2;
}
else if (keyCode === LEFT_ARROW) {
people[0].x -= 2;
}
else if (keyCode === RIGHT_ARROW) {
people[0].x += 2;
}
}
}
function makeCharacter() {
var char = { x: 10, y: 410, draw: drawCharacter }
return char;
}
function drawCharacter() {
image(character, this.x, this.y);
}
// ----------------------------- EXTRA BUTTONS ---------------------------------
// create button to go back to menu after story ends
function menuButton() {
textSize(20);
fill(0)
if(mouseX > 500 & mouseY > 530 && mouseX < 600 && mouseY < 600) {
fill('#27AEE3'); // change color if mouse is hovering over
}
text('menu', 550, 550);
}
// create button to go to main story
function goHelpButton() {
textSize(20);
fill(0);
if(mouseX > 500 & mouseY > 530 && mouseX < 600 && mouseY < 600) {
fill('#27AEE3'); // change color if mouse is hovering over
}
text('go help -> ', 550, 550);
}
// ------------------------- TURTLE CODE FOR MAZES -----------------------------
function turtleLeft(d){this.angle-=d;}function turtleRight(d){this.angle+=d;}
function turtleForward(p){var rad=radians(this.angle);var newx=this.x+cos(rad)*p;
var newy=this.y+sin(rad)*p;this.goto(newx,newy);}function turtleBack(p){
this.forward(-p);}function turtlePenDown(){this.penIsDown=true;}
function turtlePenUp(){this.penIsDown = false;}function turtleGoTo(x,y){
if(this.penIsDown){stroke(this.color);strokeWeight(this.weight);
line(this.x,this.y,x,y);}this.x = x;this.y = y;}function turtleDistTo(x,y){
return sqrt(sq(this.x-x)+sq(this.y-y));}function turtleAngleTo(x,y){
var absAngle=degrees(atan2(y-this.y,x-this.x));
var angle=((absAngle-this.angle)+360)%360.0;return angle;}
function turtleTurnToward(x,y,d){var angle = this.angleTo(x,y);if(angle< 180){
this.angle+=d;}else{this.angle-=d;}}function turtleSetColor(c){this.color=c;}
function turtleSetWeight(w){this.weight=w;}function turtleFace(angle){
this.angle = angle;}function makeTurtle(tx,ty){var turtle={x:tx,y:ty,
angle:0.0,penIsDown:true,color:128,weight:1,left:turtleLeft,
right:turtleRight,forward:turtleForward, back:turtleBack,penDown:turtlePenDown,
penUp:turtlePenUp,goto:turtleGoTo, angleto:turtleAngleTo,
turnToward:turtleTurnToward,distanceTo:turtleDistTo, angleTo:turtleAngleTo,
setColor:turtleSetColor, setWeight:turtleSetWeight,face:turtleFace};
return turtle;}
]]>/*
Hyejo Seo
Section A
hyejos@andrew.cmu.edu
Final Project
*/
var ang = 0;
var doorX = 180;
var doorY = 55;
var arcX = 500;
var arcY = 85;
let active;
let activeB;
function setup() {
createCanvas(600, 400);
// loading image for green (palace)
green = loadImage("https://i.imgur.com/AA44Ncy.jpg");
// loading image for blue (flower field)
blue = loadImage("https://i.imgur.com/7prQtyF.jpg");
// loading image for red (sophie's hometown)
red = loadImage("https://i.imgur.com/puWmVDz.jpg");
// loading image for yellow (war scene)
black = loadImage("https://i.imgur.com/yZ2mKQJ.jpg");
active = 1;
activeB = 1;
}
function draw() {
angleMode(DEGREES);
activeBackground();
roomSetting();
activeElement();
wheel();
// arrow/pointer
noStroke();
fill('#32303A');
rect(arcX - 4, 0, 8, 30);
triangle(arcX - 8, 30, arcX + 8, 30, arcX, 45);
fill('#727072');
rect(arcX - 2.5, 0, 5, 30);
triangle(arcX - 6, 30, arcX + 6, 30, arcX, 45);
}
function wheel() {
// center of the wheel
fill(250, 204, 107);
circle(arcX, arcY, 17);
// highlight in the middle
fill(255, 233, 150);
noStroke();
beginShape();
curveVertex(494.5, 87);
curveVertex(494, 86);
curveVertex(494.2, 84);
curveVertex(495, 82);
curveVertex(497, 80);
curveVertex(499, 80);
curveVertex(497, 82);
curveVertex(496, 84);
curveVertex(495.5, 85);
curveVertex(495, 87);
curveVertex(495, 85);
endShape();
}
function mousePressed() {
// if user clicks inside of the wheel, it returns true
if ((mouseX >= arcX - 120 & mouseX <= arcX + 120) && (mouseY >= arcY - 120 & mouseY <= arcY + 120)) {
active = ((active % 4) + 1); // for the wheel to turn
activeB = active; // for the background to change
return true
} else {
return false
}
}
function roomSetting() {
//walls
noStroke();
fill("#E8E8E8");
rect(0, 0, width, 53);
rect(0, 53, 120, 107);
rect(0, 53 + 97, 15, 300);
rect(0, 290, 120, 200);
rect(415, 53, 190, 107);
rect(415, 160, 10, 240);
rect(575, 160, 30, 240);
rect(420, 300, 155, 100);
// left window
fill("#4C3D2E");
rect(15, 160, 120, 10);
rect(15, 170, 10, 120);
rect(15, 290, 120, 10);
rect(15, 225, 120, 8);
rect(90, 170, 8, 120);
// right window
rect(425, 160, 140, 10);
rect(425, 170, 10, 120);
rect(425, 290, 140, 10);
rect(565, 160, 10, 140);
rect(495, 170, 10, 120);
rect(435, 225, 140, 10);
// door frame
stroke("#72594E");
strokeWeight(5);
noFill();
rect(175, 55, 240, height);
// opened door
fill("#725B45");
noStroke();
quad(doorX, doorY, doorX - 50, doorY - 30, doorX - 50, height, doorX, height);
stroke("#4C3D2E");
strokeWeight(2);
line(doorX - 10, doorY - 5, doorX - 10, height);
line(doorX - 17, doorY - 9, doorX - 17, height);
line(doorX - 27, doorY - 15, doorX - 27, height);
line(doorX - 38, doorY - 21, doorX - 38, height);
noStroke();
// thickness of the door
fill("#4C3D2E");
rect(doorX - 60, doorY - 30, 10, height);
}
function blueTop() { // wheel with blue being pointed
stroke(0);
strokeWeight(1);
// blue
fill(39, 154, 241);
arc(arcX, arcY, 120, 120, 225, 315);
// black
fill(52, 46, 55);
arc(arcX, arcY, 120, 120, 315, 405);
//red
fill(255, 50, 50);
arc(arcX, arcY, 120, 120, 45, 135);
// green
fill(159, 211, 86);
arc(arcX, arcY, 120, 120, 135, 225);
}
function greenTop() { // wheel with green being pointed
stroke(0);
strokeWeight(1);
//green
fill(159, 211, 86);
arc(arcX, arcY, 120, 120, 225, 315);
// blue
fill(39, 154, 241);
arc(arcX, arcY, 120, 120, 315, 405);
//black
fill(52, 46, 55);
arc(arcX, arcY, 120, 120, 45, 135);
// red
fill(255, 50, 50);
arc(arcX, arcY, 120, 120, 135, 225);
}
function redTop() { // wheel with red being pointed
stroke(0);
strokeWeight(1);
//red
fill(255, 50, 50);
arc(arcX, arcY, 120, 120, 225, 315);
// green
fill(159, 211, 86);
arc(arcX, arcY, 120, 120, 315, 405);
//blue
fill(39, 154, 241);
arc(arcX, arcY, 120, 120, 45, 135);
// black
fill(52, 46, 55);
arc(arcX, arcY, 120, 120, 135, 225);
}
function blackTop() { // wheel with black being on pointed
stroke(0);
strokeWeight(1);
//black
fill(52, 46, 55);
arc(arcX, arcY, 120, 120, 225, 315);
// red
fill(255, 50, 50);
arc(arcX, arcY, 120, 120, 315, 405);
//green
fill(159, 211, 86);
arc(arcX, arcY, 120, 120, 45, 135);
// blue
fill(39, 154, 241);
arc(arcX, arcY, 120, 120, 135, 225);
}
function activeElement() {
if (active === 1) { // wheel starts with blue being pointed
return blueTop();
}
else if (active === 2) {
return greenTop();
}
else if (active === 3) {
return redTop();
}
else if (active === 4) {
return blackTop();
}
}
function activeBackground() {
if (activeB === 1) { //starts with the background for blue
return background(blue);
}
else if (activeB === 2) {
return background(green);
}
else if (activeB === 3) {
return background(red);
}
else if (activeB === 4) {
return background(black);
}
}
For this project, I recreated Howl’s door in the animation film, Howl’s Moving Castle. In this movie, the door leads to different countries/places based on the color the pointer is at (wheel). In order to see where this door can lead you to, you click anywhere inside the wheel. As the color the pointer is pointing at in the wheel changes, the background changes.
Blue – flower field
Green – palace
Red – Sophie’s hometown (train)
Black – a war scene
Press your mouse to add planets and nebulas and use your mouse to hover around the Canvas and explore the universe!!
//Steven Fei & Fanjie Mike Jin
//Section A & C
//Final Project
//zfei@andrew.cmu.edu & fjin@andrew.cmu.edu
var starNumber = 150;//number of the stars on the background
var starsize = 1.5;//size of the stars
var sx = [];//array to define the x position of the stars
var sy = [];//array to define the y position of the stars
var sz = [];//array to define the z position of the stars
var amplitude = 3.14 * 3;//define the moving margin of the stars
var waveSpeed;//define the moving speed of the stars on the background
var theta = 0;//define the moving angle of the stars
var glowDefiner = [];//define the true false value for whether to let the star glow
var glowSize = 22;//glowing size of the stars
var newStars = [];//array for making new stars
var mouseXList = [];//arrays to store mouseX value
var mouseYList = [];//arrays to store mouseY value
var img; //load image for the earth texture mapping
var w = 600 / 7 // devivded the canvas into seven regions and from left to right, the pitches of the piano sound will progressively become higher
var newExplod = [];//array for making new explosion at the background
var mouseXListEx = [];//arrays to store mouseX value
var mouseYListEx = [];//arrays to store mouseY value
function setup() {
//load the background image for the texture mapping of the earth
//coded by Mike
img = loadImage("https://i.imgur.com/lamlO83.jpg");
createCanvas(600, 600,WEBGL);
//create values for the positions of the stars on the background
//coded by Mike
for (var i = 0; i < starNumber; i++){
sx.push(random(-width * 0.75, width * 0.75));
sy.push(random(-height, height));
sz.push(random(-width, height/2));
var toggle = random(1.0);
//define whether the stars on the background will glow
if(toggle < 0.9){
glowDefiner.push(false);
}else{
glowDefiner.push(true);
}
}
for(var j = 0; j < glowDefiner.length; j++){
print(glowDefiner[j]);
}
}
function draw(){
background(0);
noStroke();
normalMaterial();
centerCube();//create a center star to give a sense of what perspective we are looking at
makeCamera();//use the makeCamera function to change the viewport angle
makeearth();
push();
//draw the stars on the background
for(var i = 0; i < starNumber; i++){
//coded by Mike
push();
waveSpeed = map(sz[i], -width, height/2, 15000, 60000);//define the moving speed of the stars
theta += (TWO_PI / waveSpeed);//define the moving angle of the stars
if(theta > amplitude){
theta = -theta;//set the moving margins of the stars
}
sy[i] += sin(theta);//set the moving value to the positions
sx[i] += cos(theta);//set the moving value to the positions
translate(sx[i], sy[i], sz[i]);
if(glowDefiner[i]){
fill(255, 200, 130, 4);
sphere(glowSize);//draw glow light of the sphere
}
fill("white");
smooth();
sphere(starsize);//draw the stars
pop();
}
pop();
//draw some new stars
//coded by Steven
if (mouseXList.length != 0){
for(var k = 0; k < newStars.length; k++){
newStars[k].updateStar();//animate the expansion of the stars
push();
translate(newStars[k].x, newStars[k].y,0);
rotateX(frameCount * 0.05 + k*2);//rotate the new star
rotateY(frameCount * 0.05 + k*2);//rotate the new star
newStars[k].draw();//animate the emergence of the stars
pop();
}
}
if(newStars.length > 4){
newStars.shift();
}
push();
//make the planet
if (mouseXListEx.length != 0){
for(var k = 0; k < newExplod.length; k++){
newExplod[k].updateExplo();//animate the expansion of the stars
push();
translate(newExplod[k].x, newExplod[k].y,0);
rotateX(frameCount * 0.05 + k*2);//rotate the new star
rotateY(frameCount * 0.05 + k*2);//rotate the new star
newExplod[k].draw();//animate the emergence of the stars
pop();
}
}
if(newExplod.length > 2){
newExplod.shift();
}
pop();
}
function makeCamera(){
//coded by Steven
camX = map(mouseX, 0, width, -width/2, width/2);//changing camera position x
camY = map(mouseY, 0, height, -height/2, height/2);//changing camera position y
camZ = height/2;//changing camera position z
camera(camX, camY, camZ,0,0,0,1,1,0);//allow the viewport angle to change
}
//make object to create new stars
function makeNewStar(x, y, radius){
//coded by Mike
var newstar = {x: x,
y: y,
r: radius,
updateStar: updateStar,
draw: drawNewStar};
return newstar;
}
function makeNewExplo(x, y, radius){
//coded by Mike
var newExplo = {x: x,
y: y,
r: radius,
updateExplo: updateExplo,
draw: drawNewExplo};
return newExplo;
}
//function to draw new star
function drawNewStar(){
//coded by Mike
var color1 = random(150, 255);
var color2 = random(100,180);
var color3 = random(100,200);
var density = random(14,20);//allow different numbers of the spheres to appear on the star
for(var i = 0; i < density; i++){
var lengthValue = map(i, 0, density, -PI, PI); //set longitudinal value
for(var j = 0; j< density; j++){
var widthValue = map(j, 0, density, -PI/2, PI/2);// set horizontal value
var pX = this.r * sin(lengthValue) * cos(widthValue);
var pY = this.r * sin(lengthValue) * sin(widthValue);
var pZ = this.r * cos(lengthValue);
push();
fill(color1, color2, color3);
translate(pX, pY, pZ);
sphere(1.6);
pop();
}
}
}
function drawNewExplo(){
//coded by Mike
var color4 = random(100, 255);
var color5 = random(100,180);
var color6 = random(100,200);
var density = random(12, 15);//allow different numbers of the spheres to appear for the explosion
for(var i = 0; i < density; i++){
var lengthValue = map(i, 0, density, -PI, PI); //set longitudinal value
for(var j = 0; j< density; j++){
var widthValue = map(j, 0, density, -PI/2, PI/2);// set horizontal value
var pX1 = this.r * sin(lengthValue) * cos(widthValue * 0.5) * 0.5;
var pY1 = this.r * sin(lengthValue * 0.5) * sin(widthValue) * 0.5;
var pZ1 = this.r * cos(lengthValue);
push();
fill(color4, color5, color6);
translate(pX1, pY1, pZ1);
box(2, 2, 2);
pop();
}
}
}
function updateStar(){
//coded by Mike
this.r += random(0.5,2);//allow the new star to expand
}
function updateExplo(){
//coded by Mike
this.r += random(1,2);//allow the new explosion to expand
}
function mousePressed(){
//coded by Steven
var newStarMaking = [];
var newMouseXList = [];
var newMouseYList = [];
var newExploMaking = [];
var newmouseXListEx = [];
var newmouseYListEx = [];
var clickEx;//check whether there is existing new stars
var click;//check whether there is existing new stars
if(mouseXList.length == 0){
click = 0;
newStarMaking.push(newStars[0]);
newMouseXList.push(mouseXList[0]);
newMouseYList.push(mouseYList[0]);
}
else{
for(var l = 0; l < newStars.length; l++){
var distance = dist(mouseX - width/3, mouseY - height/3, newStars[l].x, newStars[l].y);
if(distance <= 30){
click = 1;
}else{
click = 0;
newStarMaking.push(newStars[l]);
newMouseXList.push(mouseXList[l]);
newMouseYList.push(mouseYList[l]);
}
}
newStars = newStarMaking;
mouseXList = newMouseXList;
mouseYList = newMouseYList;
}
if(click == 0){
mouseXList.push(mouseX - width/3);
mouseYList.push(mouseY - width/3);
var newStar = makeNewStar(mouseX - width/3, mouseY-width/3, 30);
newStars.push(newStar);
}
//add value to empty list
if(mouseXListEx.length == 0){
clickEx = 0;
newExploMaking.push(newExplod[0]);
newmouseXListEx.push(mouseXListEx[0]);
newmouseYListEx.push(mouseYListEx[0]);
}
else{
//assign initiating position according to the mouse postion
for(var w = 0; w < newExplod.length; w++){
var distance = dist(mouseX - width/3, mouseY - height/3, newExplod[w].x, newExplod[w].y);
if(distance <= 30){
clickEx = 1;
}else{
clickEx = 0;
newExploMaking.push(newExplod[w]);
newmouseXListEx.push(mouseXListEx[w]);
newmouseYListEx.push(mouseYListEx[w]);
}
}
//assign values back to the list
newExplod = newExploMaking;
mouseXListEx = newmouseXListEx;
mouseYListEx = newmouseYListEx;
}
//avoid invalid value
if(clickEx == 0){
mouseXListEx.push(mouseX - width/3);
mouseYListEx.push(mouseY - width/3);
var newExplo = makeNewExplo(mouseX - width/3, mouseY-width/3, 300);
newExplod.push(newExplo);
}
}
//function to make a center planet to have some understanding of the perspective
//coded by Mike
function centerCube(){
//make sure the location of the center planet is always at the center of the canvas
push();
var locX = mouseX - height / 2;
var locY = mouseY - width / 2;
ambientLight(50);
directionalLight(255, 0, 0, 0.25, 0.25, 0);
pointLight(0, 0, 255, locX, locY, 250);
ambientMaterial(100);
strokeWeight(0.5);
stroke(255);
smooth();
sphere(40);
pop();
//first ring surronding the planet
push();
rotateZ(frameCount * 0.01);
rotateX(frameCount * 0.01);
rotateY(frameCount * 0.01);
strokeWeight(0.5);
smooth();
stroke(255);
torus(60, 0.5);
pop();
//second ring surronding the planet
push();
rotateZ((100+ frameCount) * 0.01);
rotateX((100 + frameCount) * 0.01);
rotateY((100+ frameCount) * 0.01);
smooth();
strokeWeight(0.5);
stroke(255);
torus(70, 0.5);
pop();
//third ring surronding the planet
push();
rotateZ((200+ frameCount) * 0.01);
rotateX((200 + frameCount) * 0.01);
rotateY((200+ frameCount) * 0.01);
smooth();
strokeWeight(0.5);
stroke(255);
torus(80, 0.5);
pop();
//fourth ring surronding the planet
push();
rotateZ((300+ frameCount) * 0.01);
rotateX((300 + frameCount) * 0.01);
rotateY((300+ frameCount) * 0.01);
smooth();
strokeWeight(0.5);
stroke(255);
torus(90, 1);
pop();
}
//function to make a earth adjacent to the center planet
//coded by Mike
function makeearth(){
push();
translate(width / 2, height / 3, -150);
rotateX(frameCount * 0.05);
rotateY(frameCount * 0.05);
texture(img);
sphere(20);
pop();
}
In this project, we aim to establish an interactive universe made possible by using the P5 3D geometry and 3D lighting. When you are hovering around in this universe, the stars and planets will move according to your mouse position. When you lower the mouse position, the screen will be zoomed out and when you higher the mouse, the screen will zoom in more. When the mouse is pressed, new “stars” which look like the colorful spheres composed of smaller spheres with galaxy-like explosion will happen randomly on the screen and would expand further until they can be seen no more. However, once you click on the screen, you will be able to see them again. The small spheres are glowing on the background to have an interstellar appearance. The center spindle-like sphere and an “Earth” like sphere are created to give us a general understanding of what perspective we are looking at the canvas.
]]>Please refer to Mike Jin’s latest post
]]>I looked at two people’s projects, Hannah Cai (2018 Fall) and Supawat Vitoorapakorn (2017 Fall). Hannah created an experience where you can select stars and connect them with different shapes, while Supawat created an environment to test out the process of evolution.
Above is Supawat’s evolution simulation
Above is Hannah’s interactive constellation
What I find very interesting in these two people’s projects is that they took completely different routes about what they want to convey. Hannah created a visually pleasing interaction while Supawat created a highly data-based visualization of constantly morphing information.
I wonder if I can take the middle ground of balance between these two.
]]>I am currently making a space for an experience for people to feel wonder and playfulness by creating stars shooting them into the night sky. Below is the sketch. The touch screen part will be substituted with the clicking motion and I want to create additive features that are activated in various conditions in relation to distance between different stars and their locations.
For this final project, I would really like to work with generative text. I am interested in working with books that are already in the public domain, and instead of using my program to generate new text or rearrange old text, I want to use my program to specify where the letters should exist on the page. I would like the letter placement to reflect ecological data on the rising temperatures due to the climate crisis. I would like to create a reconstruction of a cultural artifact / book where ever page signifies another year into the future, and the letters y placement slowly increases according to the amount of degrees the temperature in the place that book was written will rise. I am interested in the fragility of human existence and human culture, and how all of human memory and collective history is threatened by the climate crisis.. I want to display this vulnerability with this modified version of a book.
]]>https://www.itsnicethat.com/articles/bleed-blank-architects-graphic-design-201017
https://en.wikipedia.org/wiki/Georg_Nees
For my final project, I want to create generative placement of text letters based on data received from the projected temperature rise from different areas around the world. The data from the specific place which the classic book is from its fed into a program which determines its placement for each page of the book. Each page represents moving forward one year.
I was having trouble finding other artists who have worked with APIs to generate the placement of text, but I did find two artists whose work is of interest to me and relevant to my final project. The first is Georg Nees, who was an early pioneer of generative art. His piece, Gravel, provides a sort of visualization of the progressive instability I am envisioning for this work.
Bleed, a design consulting firm also has some projects that involve generative text and processes based within nature that are interesting to me and relevant to my work. For example, as quoted in the Its Nice That article, “Bleed took the Albert Einstein quote “look deeper into nature, and you will understand everything better,” as a concept but also a tool so that every time a character from the sentence is typed, a sphere is formed using a certain amount of triangles.”
I am interested in how the movement and placement of typography could be conceptually linked to broader ideas of nature.
]]>