YouieCho-FinalProject

I created an interactive clock that includes two modes that the user can switch between: normal, and Christmas. Each of the two modes draws a green tree and a snowy Christmas tree. In the beginning, the user wouldn’t know what the wiggly lines are drawing, but as they wait, the tree images begin to appear. The drawing refreshes when they switch between the two modes.

The time is displayed quantitatively as numbers and more visually with bars on the tree trunk, and mouse movement creates variant colors for certain features.

sketch

/* Youie Cho
   Section E
   minyounc@andrew.cmu.edu
   Final-Project*/

// Set up turtles to draw paths. Two draw their own paths simultaneously.
var ttl;
var ttl2;
var currIter = 0;

// Sets color for tree, outside area, text, and background
var rTree = 0;
var gTree = 100;
var bTree = 0;
var rOutside = 64;
var gOutside = 147;
var bOutside = 255;
var rText = 255;
var gText = 255;
var bText = 255;
var backgroundCol = 255;

// Ball colors (Christmas mode)
var ballcolors = ["red", "green", "pink", "orange", 'rgb(18, 89, 52)',
                'rgb(140, 0, 0)', 'rgb(252, 186, 3)', 'rgb(217, 86, 30)'];

// Coordinates and opacity for drawing star at top (Christmas mode)
var x = [300, 311, 333, 319, 321, 300, 279, 281, 267, 289];
var y = [48, 67, 73, 90, 112, 103, 112, 90, 73, 67];

// Opacity for star (Christmas mode)
var opacity = 0;

function setup() {
    createCanvas(600, 600);
    background("white");

    // Create turtles
    ttl = makeTurtle(0, 300);
    ttl.setWeight(1);
    ttl2 = makeTurtle(600, 300);
    ttl2.setWeight(1);
}

function draw() {
    time(); // Displays time witn numbers
    trunk(); // Trunk displays time with bars
    star(); // Star displays in Christmas mode
    ttl1Mvt(); // ttl1 settings
    ttl2Mvt(); // ttl2 settings

    // Turtle movement per frame
    currIter ++;
    ttl.forward(10);
    ttl.right(random(-50, 50));
    ttl2.forward(10);
    ttl2.left(random(-50, 50));

    buttons(); // Buttons used to switch between modes
}

function time() {
    // Text box
    noStroke();
    fill(rTree, gTree, bTree);
    rectMode(CENTER);
    rect(width / 2, 293, 140, 32);

    // Display hours with AM/PM mode, minutes, and seconds
    noStroke();
    fill(rText, gText, bText);
    if (hour() > 12) {
        textSize(20);
        text(hour() - 12, 245, 300);
        textSize(10);
        text("PM", 345, 300);
    } else {
        textSize(20);
        text(hour(), 245, 300);
        textSize(10);
        text("AM", 345, 300);
    }
    textSize(20);
    text(minute(), 280, 300);
    text(second(), 315, 300);
}

function trunk() {
    rectMode(CORNER);
    strokeWeight(0.5);
    stroke(128, 70, 13);
    fill(backgroundCol, backgroundCol, backgroundCol);
    rect(259.5, 370, 81, 120);
    fill(128, 70, 13);

    // Progression of brown bars display time
    var prgH = map(hour(), 0, 23, 0, 120);
    rect(259.5, 370, 25, prgH);
    var prgM = map(minute(), 0, 59, 0, 120);
    rect(287.5, 370, 25, prgM);
    var prgS = map(second(), 0, 59, 0, 120);
    rect(315.5, 370, 25, prgS);
}

function star() {
    var nPoints = x.length;
    noStroke();

    // Star color changes according to mouseX
    var starCol = map(mouseX, 0, width, 130, 220);
    fill(255, starCol, 100, opacity);
    beginShape();
    for (var i = 0; i < nPoints; i++) {
        vertex(x[i], y[i]);
    }
    endShape(CLOSE);
    noStroke();
}

function ttl1Mvt() {
    // Turtle does not go outside of the canvas
    if (ttl.x >= width || ttl.x <= 0 || ttl.y >= height || ttl.y <= 0) {
        ttl.penUp();
        ttl.goto(300, 300);
        ttl.penDown();
    }

    // Color settings for tree area and outside area
    if ((ttl.x > 280 & ttl.x < 320 && ttl.y > 90 && ttl.y < 110) ||
        (ttl.x > 260 && ttl.x < 340 && ttl.y > 110 && ttl.y < 150) ||
        (ttl.x > 240 && ttl.x < 360 && ttl.y > 150 && ttl.y < 200) ||
        (ttl.x > 200 && ttl.x < 400 && ttl.y > 200 && ttl.y < 260) ||
        (ttl.x > 150 && ttl.x < 450 && ttl.y > 260 && ttl.y < 370)) {
        ttl.setColor(color(rTree, gTree, bTree));
    } else {
        ttl.setColor(color(rOutside, gOutside, bOutside));
    }
}

function ttl2Mvt() {
    // Turtle does not go outside of the canvas
    if (ttl2.x >= width || ttl2.x <= 0 || ttl2.y >= height || ttl.y <= 0) {
        ttl2.penUp();
        ttl2.goto(300, 300);
        ttl2.penDown();
    }

    // Color settings for tree area and outside area
    if ((ttl2.x > 280 & ttl2.x < 320 && ttl2.y > 90 && ttl2.y < 110) ||
        (ttl2.x > 260 && ttl2.x < 340 && ttl2.y > 110 && ttl2.y < 150) ||
        (ttl2.x > 240 && ttl2.x < 360 && ttl2.y > 150 && ttl2.y < 200) ||
        (ttl2.x > 200 && ttl2.x < 400 && ttl2.y > 200 && ttl2.y < 260) ||
        (ttl2.x > 150 && ttl2.x < 450 && ttl2.y > 260 && ttl2.y < 370)) {
        ttl2.setColor(color(rTree, gTree, bTree));
    } else {
        ttl2.setColor(color(rOutside, gOutside, bOutside));
    }
}

function buttons() {
    noStroke();
    fill(mouseY / 5 + 200, mouseX / 5 + 200, mouseX / 5 + 100);
    rect(13, 558, 100, 33);
    rect(487, 558, 100, 33);
    strokeWeight(0.5);
    fill(rOutside, gOutside, bOutside);
    textSize(15);
    text("Normal", 40, 580);
    text("Christmas", 505, 580);
}

function mousePressed() {
    // NORMAL MODE ////////////////////////////////////////////////////////////
    if (mouseX >= 13 & mouseX <= 113 && mouseY >= 558 && mouseY <= 691) {
        // Turtle drawing refreshes upon cliking the button
        noStroke();
        clear();
        backgroundCol = 255;
        background(backgroundCol, backgroundCol, backgroundCol);
        opacity = 0;

        // Color settings
        rTree = 0; // Green tree
        gTree = 100;
        bTree = 0;
        rOutside = 64; // Blue outside
        gOutside = 147;
        bOutside = 255;
        rText = 240; // Light green text
        gText = 247;
        bText = 218;
    }

    // CHRISTMAS MODE /////////////////////////////////////////////////////////
    if (mouseX >= 487 & mouseX <= 587 && mouseY >= 558 && mouseY <= 691) {
        // Turtle drawing refreshes upon cliking the button
        clear();
        backgroundCol = 0;
        background(backgroundCol, backgroundCol, backgroundCol);
        opacity = 100; // Displays star only in Christmas mode

        // Color settings
        rTree = 255; // White tree
        gTree = 255;
        bTree = 255;
        rOutside = 255; // Yellow outside
        gOutside = 213;
        bOutside = 28;
        rText = 248; // Dark yellow text
        gText = 178;
        bText = 41;

        // Ornaments (Christmas mode)
        noStroke();
        for (var i = 0; i < ballcolors.length; i++) {
            for (var j = 0; j < ballcolors.length; j++) {
            fill(ballcolors[i]);
            }
        ellipse(random(280, 320), random(150, 250), 12, 12);
        ellipse(random(170, 450), random(250, 370), 18, 18);
        }
    }
}

// TURTLE FUNCTIONS ///////////////////////////////////////////////////////////
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 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 turtleSetColor(c) {
    this.color = c;
}

function turtleSetWeight(w) {
    this.weight = w;
}

function makeTurtle(tx, ty) {
    var turtle = {x: tx, y: ty,
                  angle: 0.0,
                  penIsDown: true,
                  color: color(128),
                  weight: 1,
                  left: turtleLeft, right: turtleRight,
                  forward: turtleForward,
                  penDown: turtlePenDown, penUp: turtlePenUp,
                  goto: turtleGoTo,
                  setColor: turtleSetColor, setWeight: turtleSetWeight,
                 };
    return turtle;
}

Christmas mode / short time elapsed
Christmas mode / long time elapsed
Normal mode

Sammie Kim – Final Project – 12

For this project, I wanted to create a recycling game that educates all age levels upon proper recycling, which is one of the basic ways that we can all contribute to protect our environment. Through the process, I learned a lot, especially how there are a lot of trash items that are not recyclable—this emphasized the importance of reusing items and reducing waste in general. The user can simply explore the environment, drag any waste item and drop it in any of the waste bins below. If the waste is thrown in the wrong bin, information will automatically show up on the top to guide the user, while also giving extra tips for reducing such trash. 

sketch

//Sammie Kim
//Section D
//sammiek@andrew.cmu.edu
//Final Project

//Global Variables
var FOOD = 0; //Index number within the waste bin type array
var PLASTIC = 1;
var PAPER = 2;
var TRASH = 3;
var score = 0;
var styrofoamBox = createStyrofoamBox();
var tissue = createTissue();
var hanger = createHanger();
var newspaper = createNewspaper();
var pizzaBox = createPizzaBox();
var plasticBag = createPlasticBag();
var plasticBottle = createPlasticBottle();
var paperBag = createPaperBag();
var appleCore = createApple();
var coffeeCup = createCoffee();
var fishbones = createFishbones();
var toothpaste = createToothpaste();
var mirror = createMirror();
var bubblewrap = createBubbleWrap();
var foodBin = createFoodBin();
var plasticBin = createPlasticBin();
var paperBin = createPaperBin();
var trashBin = createTrashBin();
var wastes = [styrofoamBox, tissue, hanger, newspaper, pizzaBox, plasticBag,
              plasticBottle, paperBag, appleCore, coffeeCup, fishbones,
              toothpaste, mirror, bubblewrap];
var wasteBins = [foodBin, plasticBin, paperBin, trashBin];
//Boolean Variables
var correct = false;
var selected = false;

//Use objects to create different wastes and wastebins with specific traits
function createStyrofoamBox() {
    var styrofoamBox = {
        url: "https://i.imgur.com/Lb1P88W.png",
        initX: 78,
        initY: 102,
        x: 78,
        y: 102,
        selected: false,
        stay: true,
        dragging: false,
        informing: false,
        type: TRASH,
        note: "Styrofoam is a non-recyclable material because it contains "
              + "polysteryene, which is non-biodegradable."
        }
    return styrofoamBox;
}

function createTissue() {
    var tissue = {
        url: "https://i.imgur.com/s6rZAJu.png",
        initX: 145,
        initY: 95,
        x: 145,
        y: 95,
        selected: false,
        stay: true,
        dragging: false,
        informing: false,
        type: TRASH,
        note: "Dirty tissues should be thrown in trash."
        }
    return tissue;
}

function createHanger() {
    var hanger = {
        url: "https://i.imgur.com/dE1sDsn.png",
        initX: 253,
        initY: 163,
        x: 253,
        y: 163,
        selected: false,
        stay: true,
        dragging: false,
        informing: false,
        type: TRASH,
        note: "Plastic hangers are not purely plastic, and their curved ends "
              + "can be problematic in recycling equipment. "
        }
    return hanger;
}

function createNewspaper() {
    var newspaper = {
        url: "https://i.imgur.com/FkD5sJK.png",
        initX: 0,
        initY: 253,
        x: 0,
        y: 253,
        selected: false,
        stay: true,
        dragging: false,
        informing: false,
        type: PAPER,
        note: "Newspapers should be recycled in paperbin."
        }
    return newspaper;
}

function createPizzaBox() {
    var pizzaBox = {
        url: "https://i.imgur.com/ZRjCbEW.png",
        initX: 172,
        initY: 102,
        x: 172,
        y: 102,
        selected: false,
        stay: true,
        dragging: false,
        informing: false,
        type: TRASH,
        note: "Pizzabox cannot be recycled due to its wet and greasy cardboard "
              + "that cannot be processed in recycling equipment. "
              + "It can also attract insects and rodents."
        }
    return pizzaBox;
}

function createPlasticBag() {
    var platicBag = {
        url: "https://i.imgur.com/PDtsB6D.png",
        initX: 94,
        initY: 172,
        x: 94,
        y: 172,
        selected: false,
        stay: true,
        dragging: false,
        informing: false,
        type: PLASTIC,
        note: "Most recycling facilities can only handle rigid materials that can "
              + "be separated, so plastic bags and wraps are generally not accepted. "
              + "But we can always reuse them for collecting trash."
        }
    return platicBag;
}

function createPlasticBottle() {
    var plasticBottle = {
        url: "https://i.imgur.com/6OEa9bA.png",
        initX: 393,
        initY: 95,
        x: 393,
        y: 95,
        selected: false,
        stay: true,
        dragging: false,
        informing: false,
        type: PLASTIC,
        note: "Empty plastic bottles belong in the plastic bin. "
        + "The better option is to carry reusable waterbottles."
        }
    return plasticBottle;
}

function createPaperBag() {
    var paperBag = {
        url: "https://i.imgur.com/QsPO9ph.png",
        initX: 364,
        initY: 153,
        x: 364,
        y: 153,
        selected: false,
        stay: true,
        dragging: false,
        informing: false,
        type: PAPER,
        note: "Clean paper bags belong in the paper bin. Still, the best "
        + "option would be to reuse them."
        }
    return paperBag;
}

function createApple() {
    var appleCore = {
        url: "https://i.imgur.com/QX98sKU.png",
        initX: 274,
        initY: 258,
        x: 274,
        y: 258,
        selected: false,
        stay: true,
        dragging: false,
        informing: false,
        type: FOOD,
        note: "Any type of leftover food belong in the organic waste bin."
        }
    return appleCore;
}

function createCoffee() {
    var coffeeCup = {
        url: "https://i.imgur.com/sys0QnS.png",
        initX: 351,
        initY: 87,
        x: 351,
        y: 87,
        selected: false,
        stay: true,
        dragging: false,
        informing: false,
        type: TRASH,
        note: "Unlike most paper items, paper cups are usually coated in platic "
              + "to hold liquid to prevent leaking. "
              + "Although many cafes are beginning to use compostable cups, "
              + "the best option is carrying coffee mugs or reusable bottles."
        }
    return coffeeCup;
}

function createFishbones() {
    var fishbones = {
        url: "https://i.imgur.com/wju8gLe.png",
        initX: 205,
        initY: 264,
        x: 205,
        y: 264,
        selected: false,
        stay: true,
        dragging: false,
        informing: false,
        type: FOOD,
        note: "Any type of leftover food belong in the organic waste bin."
        }
    return fishbones;
}

function createToothpaste() {
    var toothpaste = {
        url: "https://i.imgur.com/na3BnTw.png",
        initX: 104,
        initY: 260,
        x: 104,
        y: 260,
        selected: false,
        stay: true,
        dragging: false,
        informing: false,
        type: PLASTIC,
        note: "Toothpaste tubes should be properly cleaned out before "
              + "being placed in the plastic recycling bin."
        }
    return toothpaste;
}

function createMirror() {
    var mirror = {
        url: "https://i.imgur.com/NAh1S2x.png",
        initX: 142,
        initY: 130,
        x: 142,
        y: 130,
        selected: false,
        stay: true,
        dragging: false,
        informing: false,
        type: TRASH,
        note: "Mirrors cannot be recycled due to the coating used on glass "
              + "to make it reflective. Be sure to wrap broken mirror pieces "
              + "before throwing them in the garbage."
        }
    return mirror;
}

function createBubbleWrap() {
    var bubblewrap = {
        url: "https://i.imgur.com/cvJ1Iou.png",
        initX: 336,
        initY: 245,
        x: 336,
        y: 245,
        selected: false,
        stay: true,
        dragging: false,
        informing: false,
        type: TRASH,
        note: "Although many plastics are recylable, bubble wraps and bags "
              + "cannot be recyled due to their thin films that can get tangled "
              + "in recycling machines."
        }
    return bubblewrap;
}

function createPaperBin() {
    var paperBin = {
        url: "https://i.imgur.com/AgJIG61.png",
        x: 229,
        y: 342,
      }
    return paperBin;
}

function createPlasticBin() {
    var plasticBin = {
        url: "https://i.imgur.com/6x6FPJW.png",
        x: 117,
        y: 342,
    }
    return plasticBin;
}

function createFoodBin() {
    var foodBin = {
        url: "https://i.imgur.com/sSve89v.png",
        x: 8,
        y: 342,
    }
    return foodBin;
}

function createTrashBin() {
    var trashBin = {
        url: "https://i.imgur.com/jm4NMB8.png",
        x: 343,
        y: 342,
    }
    return trashBin;
}

function setup() {
    createCanvas(450, 480);
}

function draw() {
    //load images for background, wastes, and waste bins
    background(220);
    image(backgroundPic, 0, 0);
    for (var i = 0; i < wasteBins.length; i++) {
        image(wasteBinsPics[i], wasteBins[i].x, wasteBins[i].y);
    }
    //Show explanation on top of the canvas if informing is true
    for (var i = 0; i < wastes.length; i++) {
        if (wastes[i].informing) {
            fill(220);
            noStroke();
            rect(0, 0, 450, 60);
            fill(0);
            text(wastes[i].note, 10, 10, 440, 480);//wrapping text within canvas
        }
        if (wastes[i].stay) { //if stay is true, images are all shown on canvas
            image(wastePics[i], wastes[i].x, wastes[i].y);
            if (wastes[i].dragging) {
                //update waste with current mouse locations
                wastes[i].x = mouseX - wastePics[i].width / 2;//offset amount
                wastes[i].y = mouseY - wastePics[i].height / 2;
        }
      }
    }
    if (correct) {
        text("Correct!", 10, 20); //shows up when answer is correct
    }
    fill(255);
    text("Score: " + score, 10, 90); //show scoreboard
}

function preload() {
    //Preload all the images by pushing the objects' URL into new array
    var backgroundURL = "https://i.imgur.com/4jWCbcI.png"
    backgroundPic = loadImage(backgroundURL);
    wastePics = [];
    for (var i = 0; i < wastes.length; i++) {
        wastePics.push(loadImage(wastes[i].url));
    }
    wasteBinsPics = []
    for (var i = 0; i < wasteBins.length; i++) {
        wasteBinsPics.push(loadImage(wasteBins[i].url));
    }
}

function mousePressed() {
    //Use mousePressed to drag each trash item within the canvas
    //I created parameters for each trash image, so that the mouse can click
    //within the area of each trash image.
    for (var i = 0; i < wastes.length; i++) {
        wastes[i].informing = false; //Clear information when mouse is pressed.
        var x0 = wastes[i].x; //top left X coordinate
        var y0 = wastes[i].y; //top right Y coordinate
        var x1 = wastes[i].x + wastePics[i].width; //top right X coordinate
        var y1 = wastes[i].y + wastePics[i].height; //bottom y coordinate
        if (!selected & x0 < mouseX && mouseX < x1 && y0 < mouseY && mouseY < y1) {
            selected = true; //trash is selected within the image boundaries
            wastes[i].dragging = true;
        }
    }
}

function mouseReleased() {
    //Use mouseReleased to evaluate whether the chosen trash is
    //dropped into the correct bin.
    //Like previously, I created specific parameters for trashbin images.
    selected = false;
    for (var i = 0; i < wastes.length; i++) {
        if (wastes[i].dragging) {
            wastes[i].dragging = false;
            var corrBin = wasteBins[wastes[i].type];
            var corrBinPic = wasteBinsPics[wastes[i].type];
            var x0 = corrBin.x;
            var y0 = corrBin.y;
            var x1 = corrBin.x + corrBinPic.width;
            var y1 = corrBin.y + corrBinPic.height;
            if (y0 < mouseY & mouseY < y1) {
                //Since all trashbins have the same Y height, I differentiated
                //the correct bin by determining the X locations
                if (x0 < mouseX && mouseX < x1) { //Correct Bin
                    correct = true;
                    wastes[i].stay = false; //waste will disappear
                    wastes[i].informing = false; //information will not show
                    score += 1; //score is updated by one when answer is correct
                } else {
                    //if incorrect, information will show up, and
                    //the waste image will go back to its initial location
                    correct = false;
                    wastes[i].informing = true;
                    wastes[i].x = wastes[i].initX; //initial X coordinate
                    wastes[i].y = wastes[i].initY; //initial Y coordinate
                }
            } else {
                correct = false; //the default status
            }
        }
    }
}

Joseph Zhang – Final Project -12

sketch

// Joseph Zhang
// 15-104 Final Project
// Section E

var rectangles = [];
var gutter = 30;
var totalRows = 15;
var totalCols = 15;
var centerCol = totalCols / 2;
var centerRow = totalRows / 2;
var rectH = 70;

function setup() {
    createCanvas(450, 450, WEBGL);
    // PUT RECTANGLES INTO ARRAY
    for( x = 0; x < totalRows; x++) {
        for ( y = 0; y < totalCols; y++) {
            rectangles.push(createCube(x * gutter, y * gutter, x, y));
        }
    }
}

var bgColor;
var bg = 0;

function draw() {

    rotateY(map(mouseX, 0, height, -.15, .15));
    rotateX(map(mouseY, 0, height, .15, -.15));
    translate(map(mouseX / 10 , 0, width / 10, -10, 10), map(mouseY / 10 , 0, height / 10, -10, 10), 0);

    //INTERACTIVE CONTROLS - UP AND DOWN
    if( keyIsPressed &  keyCode === LEFT_ARROW) {
        if( rectH > -200) {
            rectH -= 3;
            print(rectH);
        }
    }

    else if( keyIsPressed &  keyCode === RIGHT_ARROW) {
        if( rectH < 100) {
            rectH += 3;
            print(rectH);
        }
    }

    // COLOR BACKGROUND
    if(bgColor) {
        if ( bg > 0) {
            bg -= 20;
        }
    }

    else{
        if( bg < 255) {
            bg += 20;
        }
    }
    background(bg);

    rectMode(CENTER);  
    rotateX(radians(40));
    translate( - width / 2, - height / 2 + 15, 0);

    // REPEATEDLY DRAW EVERY PRISM IN DRAW
    for( i = 0; i < rectangles.length; i++) {
        rectangles[i].drawRect();
        rectangles[i].raiseRect();
    }
}

// CUBE OBJECT
function createCube(row, col, r, c) {
    var rectObj = {
        w: 19,
        xPos: row,
        yPos: col,
        offset: dist(r, c, centerCol, centerRow),
        currentHeight: this.offset,
        // UPDATES THE HEIGHT OF RECTANGLE
        drawRect: function() {
            if (this.currentHeight > 0) {
                fill(map(this.currentHeight, 10, 70, 0, 255));
            }
            else{
                fill(map(this.currentHeight, 10, 70, 0, -255));
            }

            push();
            translate(this.xPos, this.yPos , this.currentHeight);
            box(this.w, this.w, this.currentHeight);
            pop();
        },
        // CHANGES THE HEIGHT THROUGH MAPPING CANVAS
        raiseRect: function() {
            this.currentHeight = map( sin(this.offset), -1, 1, 10, rectH);
            this.offset += .1;
        }  
    }
    return rectObj;
}

// IF ENTER KEY IS PRESSED, CHANGE BACKGROUND
function keyPressed() {
        if( keyCode === ENTER) {
            bgColor = !bgColor;
        }
}

INTERACTIVE CONTROLS (click on canvas first):

LEFT ARROW: Decrease wave amplitude

RIGHT ARROW: Decrease wave amplitude

ENTER: Change background color

***IF LAGGING, VISIT https://editor.p5js.org/jxsephz/sketches/9Dqxil-1P

————————

For this project, I wanted to experiment with manipulating forms in three dimensional space. As someone who loves mathematical patterns, I explored ways that I could utilize the oscillation of a Sine wave.

Jamie Park – Final Project

My project was inspired by single-line drawings and line-drawing tools, like etch a sketch. I always had a desire to draw something only using one line, but I did not have the talent to do so. I also never had the patience to draw using etch a sketch. Therefore, I created a p5js drawing tool that allows you to create single-line drawings. In order to draw, use the arrow keys. You can change the color of the line by pressing on the space bar (the circle on the bottom will indicate the current color status), change the line weight by clicking on the arrows (numbers indicate the line weight), and clear canvas by clicking on the “clear” button. I hope you have fun as much as I had while I was coding for this project!

Plus, try drawing a diagonal line by pressing onto two arrow keys at the same time! 🙂

sketch

/* Jamie Park (jiminp)             Section E
   15 - 104                     Final Project */

var ttl; //global variable for the turtle
var colors = ["Coral", "DarkTurquoise", "DarkGrey", "blue",
"FireBrick", "Gold", "Lavender", "LightPink", "PowderBlue"]; //global variable for color values
var col = 0; //color index value
var strokeThickness = 2; //strokethickness as global value
var bgCol = 255;

function preload(){
    //preload image into the canvas
    var overlayURL = "https://i.imgur.com/5dpuHCX.png";
    overlay = loadImage(overlayURL);
}

function setup(){
    //creates a canvas
    createCanvas(500, 400);
    //sets the background color on white
    background(250);
    //makes the turtle at random parts of the canvas
    ttl = makeTurtle(random(150, 300), random(100, 300));
    ttl.setWeight(strokeThickness);
    ttl.setColor("coral");
}

function draw(){
    //display the image on the canvas
    image(overlay, 0, 0, 500, 400);
    //allows the user to draw the lines
    drawLines();
    //allows the user to change the color of lines
    displayStrokeWeight();
    drawTriangleButtons();
    displayCurrentColor();
    clearButton();
    boundTurtle();

}

function mousePressed(){
    //redraw when clicked on clear button
    clearCanvas();
    //when tou click the buttons, the thickness of the turtle stroke changes
    changeThickness();
}

function boundTurtle(){
    //set up local variables that wound bound the turtles
    var boundaries = 28;
    var bottomBoundaries = 58;

    //if turtle x is smaller than a set number, the turtle is the set number
    //set number due to the frame around the canvas
    if(ttl.x < boundaries){
        ttl.x = boundaries;
    }
    //if turtle y is smaller than a set number...
    if(ttl.y < boundaries + 2){
        ttl.y = boundaries + 2;
    }
    //if turtle x is greater than the set number...
    if(ttl.x > width - boundaries - 5){
        ttl.x = width - boundaries - 5;
    }
    //if turtle y is greater than the set number...
    if(ttl.y > height - bottomBoundaries){
        ttl.y = height - bottomBoundaries;
    }
}

function keyPressed(){
    //when spacebar is pressed, the color of the turtle changes
    //you can "find" your desired color by pressing on the space bar multiple times
    changeColor();
}

function changeColor(){
    if(keyCode === 32){
        //keyCode 32 is the space bar
        col = (col + 1) % colors.length;
        //you change the color by adding one into the color index above
        ttl.setColor(colors[col]);
    }
}

function drawLines(){
    //function that draws the lines when key is pressed accordingly
    //local variable that goes forward by 1.5 pixels every time key is pressed
    var distDraw = 1.5;
        //draws the line leftwards
    if(keyIsDown(LEFT_ARROW)){
        ttl.face(180);
        ttl.forward(distDraw);
    }
        //draws the line rightwards
    if(keyIsDown(RIGHT_ARROW)){
        ttl.face(0);
        ttl.forward(distDraw);
    }
        //draws an upward line
    if(keyIsDown(UP_ARROW)){
        ttl.face(270);
        ttl.forward(distDraw);
    }
        //draws a downward line
    if(keyIsDown(DOWN_ARROW)){
        ttl.face(90);
        ttl.forward(distDraw);
    }
}

function changeThickness(){
    //thickness of the stroke increases / decreases when the button is clicked
    if(mouseX < 450 & mouseX > 430 && mouseY > 280 && mouseY < 300){
        strokeThickness = strokeThickness + 1;
        //strokeweight increases by 1
    }
        //when mouseisPressed within the range of the triangular buttons, reduce the stroke weight by 0.05
    if(mouseX < 450 & mouseX > 430 && mouseY > 310 && mouseY < 340){
        strokeThickness = strokeThickness - 1;
        //strokeweight decreases by 1
    }
    //constrains the thickness of the stroke in value between 1 and 13
    strokeThickness = constrain(strokeThickness, 1, 13);
    //implements the weight to the turtle
    ttl.setWeight(strokeThickness);
}

function drawTriangleButtons(){
    //draws the triangle buttons on the bottm right corner of the canvas
    noStroke();
    fill("LightSalmon");
    //local variables that set height and width of the triangle to avoid magic nunbers
    var triangleW = 430;
    var triangleH = 300;
    //top triangle that increases the thickness
    triangle(triangleW, triangleH, triangleW + 20, triangleH, triangleW + 10, triangleH - 20);
    //bottom triangle to reduce the thickness
    triangle(triangleW, triangleH + 10, triangleW + 20, triangleH + 10, triangleW + 10, triangleH + 30);
}

function clearButton(){
    //draws the "clear" button on the top left corner
    fill("orange");
    noStroke();
    ellipse(50, 50, 25, 25);
    fill("white");
    text("clear", 40, 53);
    //informative text
    fill("gray");
    text("press on arrow keys to draw & space bar to change color,", 73, 50);
    text("and click on the arrow to change stroke thickness", 73, 60);
}

function clearCanvas(){
    //if mouse is within the proximity of the clear button, the canvas is cleared
    if(mouseX > 37.5 & mouseX < 62.5 && mouseY > 37.5 && mouseY < 62.5){
        clear();
        background(255);
        //strokeThickness and color index restart
        strokeThickness = 2;
        col = 8;
    }
}

function displayCurrentColor(){
    //displays current turtle color in a circle
    fill(colors[col]);
    ellipse(width * .815, height * .8, 10, 10)
}

function displayStrokeWeight(){
    //displays the strokeweight
    noStroke();
    fill("white");
    rect(430, 300, 18, 10);
    textSize(10);
    fill("SlateGray")
    textFont("GillSans");
    text(strokeThickness, 435, 308.5);
}

//------------------------------turtle code--------------------------------
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: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;}

Emma N-M — Final Project


My project is a spirograph application. You can move the two radius sliders, and vary the line length to change the design the math equation will create (the radii must be different values for the DRAW button to work). There are three different math equations you can use to create different designs (spirograph, epitrochoid, or another cool equation). The square in the top right hand corner allows you to set the pen color when you click on the box. This will open up a color gradient. Click anywhere and the box in the bottom righthand will show you a preview of the color you clicked on. Once you are happy with your pen color, hit “ENTER”. This will take you back to the set up screen. Hit the DRAW button to watch your design be created. When watching your drawing, you may hit the back arrow button or press “LEFT ARROW” key to go back to the set up screen. That’s it! Enjoy being mesmerized by art created with math.

finalProject-ENM

/* Emma Nicklas-Morris
enicklas
Section B
Final Project
*/ 

// radius1 46, radius2 31, LL 30 -- cool design

// point to draw the lines for the design
var x1;
var y1;
var x2 = x1;
var y2 = y1;

// used in sprigraph equations
var scaleN = 2.8;
var i = 0; // counter
var r1 = 10;
var r2 = 11;
var p = 2; // length of line from center

// used in other cool math equation
var l = p / r1;
var k = r1 / r2;

// epitrochoid equation variables
var a;
var b;

// drawing button
var drawing = false;
var justClicked = false; 
// back button
var backB = 30;
var backBX = 21;

var buttons = [];
var buttonText = [];
var equationText = [];
var equationCount = 1; // counts times the equation button is clicked
var e; // index to get the right equation displayed

var r1x = 25; // x position of radius 1 slider
var ry = 50; // y position for slider
var r2x = 175; // x position of radius 2 slider
var r1Min = 25; // min x position for radius 1
var r1Max = 125; // max x position for radius 1 
var r2Min = 175; // min x position for radius 2
var r2Max = 275; // max x position for radius 2
var radMin = 10; // user min for radii
var rad2Max = 70; // user radius 2 max
var rad1Max = 100; // user radius 1 max
var llMin = 2; // user line length min
var llMax = 65; // user line length max
var px = 315; // x position of line length (p)
var pMin = 315; // min x position of line length (p)
var pMax = 415; // max x position of line length (p)
var dragging = false;
var sliderCol = 170;

// which radius slider is clicked
var rad1 = false; 
var rad2 = false;
var lineL = false;
var rd = 12; // ball slider diameter
var r1Num = 10; // radius1 number displayed to user
var r2Num = 10; // radius2 number displayed to user
var lineNum = 5; // line length number displayed to user
var r12;        // radius1 - radius2
var diffRadii = false; // can't have the same radii

var backCol = 240; // background color
var userCol = 100; // intializes pen color
var gradSection = 84; // max width of each gradient section
var choosing = false;

var radius2; // object text for radius 2
var lineLen; // object text for line length

// location for elements on the screen
var diffRadX = 150;
var diffRadY = 100;
var eqX = 20;
var eqY = 30;
var rad2X = 190;
var llX = 320;
var colorX = 445;
var colorY = 25;
var colorMid = 165;
var colorPink = 147;
var eqW = 120;


function setup() {
	createCanvas(500, 400);
	background(backCol);
	frameRate(40);

}

function draw() {
	// stroke(cos(i/10)*(255/2), 0, sin(i/20)*(255/2), i);
	
	// screen mode: draws the spirograph
	if ((drawing) & (diffRadii)) {

		// back button on draw screen
		drawBackButton();

		// hide all setting buttons when in draw mode
		if (justClicked) {
            fill(backCol);
            rect(0, 0, width, height);
            justClicked = false; 
		}
		
        x1 = width / 2;
        y1 = height / 2;

        // spirograph
        if (e === 0) {
            spirograph();
            
        }

        // Epitrochoid
        else if (e === 1) {
            epitrochoid();
        }

        // other cool math equation
        else if (e === 2) {
            other();
        }

	}

	// screen mode: set the settings
	else {
		noStroke();
		// new screen -- hides drawing
		fill(backCol);
		rect(0, 0, width, height);

        // draws the buttons
		makeAndDrawButtons();
        makeTextForButtons();
        drawText();
        displayEquation();
        
        // which slider user is dragging
        checkDragging();

        // draw choose color button
        chooseColor();

        // draw radius sliders
        radiusSliders();

        // draws the example circles for the math
        exampleCircles();

        // line length (p)
        drawLineLength();

        // can't draw using the same radii
        checkRadii();

        // choosing pen color
        choosePenColor();

		// reset equation variables
		x1 = width / 2;
		y1 = height / 2;
		x2 = undefined;
		y2 = undefined;
		i = 0;   

	}

    i += 0.1;

}

function checkDragging() {
    if (dragging) {
        if (rad1) {
            r1x = mouseX;
        }
        else if (rad2) {
            r2x = mouseX;
        }

        else if (lineL) {
            px = mouseX;
        }
    }
}

function drawLineLength() {
    if (e === 0) { // spirograph color pallete
        stroke("#65cdca");
    }

    else if (e === 1) { // epitrochoid color pallete
        stroke("#c26571");
    }

    else if (e === 2) { // other cool equation color pallete
        stroke("#a0e3b9")
    }

    line(width/2 + r12, height/2, width/2 + r12 - lineNum, height/2);
    ellipse(width/2 + r12, height/2, 2, 2);
    ellipse(width/2 + r12 - lineNum, height/2, 3, 3);
}

function exampleCircles() {
    strokeWeight(2);
    noFill();
    // radius 1 circle
    stroke(0);
    ellipse(width/2, height/2, 2*r1Num, 2*r1Num);

    // radius 2 circle
    if (e === 0) { // spirograph
        stroke("#3f807e");
    }

    else if (e === 1) { // epitrochoid
        stroke("#82444c");
    }

    else if (e === 2) { // other cool equation
        stroke("#3d5747")
    }

    
    if ((e === 0) || (e === 2)) { // spirograph -- circles inside
        r12 = r1Num - r2Num;
    }

    else { // epitrochoid -- cirlces outside
        r12 = r1Num + r2Num;
    }

    ellipse(width/2 + r12, height/2, 2*r2Num, 2*r2Num);
    
}

function choosePenColor() {
    if (choosing) {
        noStroke();
        fill(255);
        rect(0 ,0, width, height);
        
        // the six color gradients
        gradient();

        // color box to see which color is clicked
        stroke(0);
        strokeWeight(2);
        fill(userCol);
        rect(445, 350, 30, 30);
    }
}

function checkRadii() {
    if (diffRadii == false) {
        noStroke();
        if (e === 0) { // spirograph
            fill("#65cdca");
        }

        else if (e === 1) { // epitrochoid
            fill("#c26571");
        }

        else if (e === 2) { // other cool equation
            fill("#a0e3b9");
        }
        
        textSize(18);
        text("Please choose two different radii", diffRadX, diffRadY);
    }
}

function spirograph() {
    // update spirograph variables according to user input
    r1 = r1Num;
    r2 = r2Num;
    p = lineNum;
    k = r2 / r1;

    x1 += scaleN*(r1 - r2)*cos(k*i) + p * cos((1-k)*i);
    y1 += scaleN*(r1-r2)*sin(k*i) - p * sin((1-k)*i);
    
    
    strokeWeight(2);
    stroke(userCol);
    // draw small portion of design
    line(x2, y2, x1, y1);
    noStroke();

    x2 = x1;
    y2 = y1;
}

function epitrochoid() {
    r1 = r1Num;
    r2 = r2Num;
    p = lineNum;
    a = r1 + r2;
    b = a / r2;
    scaleN = .9;

    x1 += scaleN*a*cos(i) - p * cos(b*i);
    y1 += scaleN*a*sin(i) + p * sin(b*i);

    stroke(userCol);
    strokeWeight(2);
    line(x2, y2, x1, y1); // draw small portion of design
    noStroke();
    x2 = x1;
    y2 = y1;
}

function other() {
    // update spirograph variables according to user input
    r1 = r1Num;
    r2 = r2Num;
    p = lineNum;
    l = p / r1;
    k = r2 / r1;
    scaleN = 2;

    x1 += scaleN*r1*((1-k)*Math.cos(i) + l*k*cos(i*((1-k)/k)));
    y1 += scaleN*r1*((1-k)*Math.sin(i) + l*k*sin(i*((1-k)/k)));
    
    stroke(userCol);
    strokeWeight(2);
    line(x2, y2, x1, y1); // draw small portion of design
    noStroke();
    x2 = x1;
    y2 = y1;
}

function makeAndDrawButtons() {
    // make the buttons
        var drawButton = makeButton(7/9 * width, 6/7 * height, 4 * eqX, eqY, "rect");
        drawButton.color(0);
        buttons.push(drawButton);

        var equationB = makeButton(eqX, 7/8 * height, diffRadX, eqY - 5, "rect");
        equationB.color(0);
        buttons.push(equationB);

        // draw all the buttons
        for (var b = 0; b < buttons.length; b++) {
            buttons[b].draw();  
        }
}

function makeTextForButtons() {
    // make text for buttons
        var textOnButton = makeText("DRAW", 7/9 * width + 9, height - eqY - 5, eqX);
        textOnButton.color(240);
        buttonText.push(textOnButton);

        var spiro = makeText("SPIROGRAPH", eqX * 2, height - eqY - 1, 16);
        spiro.color("#65cdca");
        equationText.push(spiro);

        var epi = makeText("EPITROCHOID", eqX * 2, height - eqY - 1, 16);
        epi.color("#c26571");
        equationText.push(epi);

        var other = makeText("COOL EQUATION 3", eqX + 6, height - eqY - 1, 15);
        other.color("#a0e3b9");
        equationText.push(other);

        var radius1 = makeText("Radius 1", eqX * 2, eqY, 18);
        radius1.color(0);
        buttonText.push(radius1);

        radius2 = makeText("Radius 2", rad2X, eqY, 18);
        radius2.color("#3f807e");
        buttonText.push(radius2);

        lineLen = makeText("Line Length", llX, eqY, 18);
        lineLen.color("#65cdca");
        buttonText.push(lineLen);
        
}

function drawText() {
    textAlign(LEFT);

    // change color pallete based on math equation
    
    if (e === 1) { // purple-pink: epitrochoid
        lineLen.color("#c26571");
        radius2.color("#753d45")
    }

    else if (e === 2) {
        lineLen.color("#a0e3b9");
        radius2.color("#3d5747");
    }

    // draw the button's text
    for (var t = 0; t < buttonText.length; t++) {
        buttonText[t].draw();
    }
}

function radiusSliders() {
    ellipseMode(CENTER);
    stroke(sliderCol);
    strokeWeight(3);
    // radius 1
    line(r1Min, ry, r1Max, ry);
    noStroke();
    fill(0);
    r1x = constrain(r1x, r1Min, r1Max);
    ellipse(r1x, ry, rd, rd);
    textAlign(CENTER);
    r1Num = floor(map(r1x, r1Min, r1Max, radMin, rad1Max));
    text(str(r1Num), r1x, ry + 2 * rd);

    // radius 2
    stroke(sliderCol);
    strokeWeight(3);
    line(r2Min, ry, r2Max, ry);
    noStroke();
    fill(0);
    r2x = constrain(r2x, r2Min, r2Max);
    ellipse(r2x, ry, rd, rd);
    r2Num = floor(map(r2x, r2Min, r2Max, radMin, rad2Max));
    text(str(r2Num), r2x, ry + 2 * rd);

    // line length
    stroke(sliderCol);
    strokeWeight(3);
    line(pMin, ry, pMax, ry);
    noStroke();
    fill(0);
    px = constrain(px, pMin, pMax);
    ellipse(px, ry, rd, rd);
    lineNum = floor(map(px, pMin, pMax, llMin, llMax));
    text(str(lineNum), px, ry + 2 * rd);

    // radii can't be same size
    if (r1Num === r2Num) {
        diffRadii = false;
    }
    
    else {
        diffRadii = true;
    }
}


// button for the user to chose their pen color
function chooseColor() {
    stroke(0);
    strokeWeight(2);
    fill(userCol);
    rect(colorX, colorY, eqY, eqY);
}

function gradient() {
    //gradient red to orange
    for (var r = 0; r < gradSection; r += 2) {
        var startR = color(255, 0, 0); // red
        var endO = color(255, colorMid, 0); // orange
        for (var c = 0; c < height; c += 2) {
            var interCol1 = lerpColor(startR, endO, r/(width/6));
            var white = color(255);
            var interLight1 = lerpColor(interCol1, white, c/height);
            fill(interLight1);
            rect(r, c, 2, 2);
        }
    }

    // gradient orange to yellow
    for (var r = 0; r < gradSection; r += 2) {
        var startO = color(255, colorMid, 0); // orange
        var endY = color(255, 255, 0); // yellow
        for (var c = 0; c < height; c += 2) {
            var interCol2 = lerpColor(startO, endY, r/(width/6));
            var interLight2 = lerpColor(interCol2, white, c/height);
            fill(interLight2);
            rect(r + gradSection, c, 2, 2);                
        }
    }

    // gradient yellow to green
    for (var r = 0; r < gradSection; r += 2) {
        var startY = color(255, 255, 0); // yellow
        var endG = color(0, 255, 0); // green
        for (var c = 0; c < height; c += 2) {
            var interCol3 = lerpColor(startY, endG, r/(width/6));
            var interLight3 = lerpColor(interCol3, white, c/height);
            fill(interLight3);
            rect(r + 2 * gradSection, c, 2, 2);               
        }
    }

    // gradient green to blue
    for (var r = 0; r < gradSection; r += 2) {
        var startG = color(0, 255, 0); // green
        var endB = color(0, 0, 255); // blue
        for (var c = 0; c < height; c += 2) {
            var interCol4 = lerpColor(startG, endB, r/(width/6));
            var interLight4 = lerpColor(interCol4, white, c/height);
            fill(interLight4);
            rect(r + 3 * gradSection, c, 2, 2);               
        }
    }

    // gradient blue to purple
    for (var r = 0; r < gradSection; r += 2) {
        var startB = color(0, 0, 255); // blue
        var endPp = color(colorMid, 0, colorMid); // purple
        for (var c = 0; c < height; c += 2) {
            var interCol5 = lerpColor(startB, endPp, r/(width/6));
            var interLight5 = lerpColor(interCol5, white, c/height);
            fill(interLight5);
            rect(r + 4 * gradSection, c, 2, 2);               
        }
    }

    // gradient purple to pink
    for (var r = 0; r < gradSection; r += 2) {
        var startPp = color(colorMid, 0, colorMid); // purple
        var endPk = color(255, eqX, colorPink); // pink
        for (var c = 0; c < height; c += 2) {
            var interCol6 = lerpColor(startPp, endPk, r/(width/6));
            var interLight6 = lerpColor(interCol6, white, c/height);
            fill(interLight6);
            rect(r + 5 * gradSection, c, 2, 2);               
        }
    }
}

function displayEquation() {
    // switch between the 2 equations

        if (equationCount % 3 === 1) {
            e = 0; // spirograph
        }

        else if (equationCount % 3 === 2) {
            e = 1; // Epitrochoid
        }

        else if (equationCount % 3 === 0) {
            e = 2;
        }

        // draw the equation name
        eText = equationText[e];
        fill(eText.tColor);
        textSize(eText.size);
        text(eText.t, eText.x, eText.y);
}

// back button to setting screen
function drawBackButton() {
	var backButton = makeButton(backB, backB, backB, backB, "ellipse");
		backButton.color(0);
        noStroke();
		backButton.draw();
		stroke(255);
		strokeWeight(2);
        // arrow
		line(backBX, backB, backB, backB + 8);
		line(backBX, backB, backB, backBX + 1);
		line(backBX, backB, backB + 9, backB);
}

// Object: Creates Buttons
function makeButton(bx, by, bw, bh, bShape) {
	var button = {x: bx, y: by, bColor: color(0),
				  shape: bShape, w: bw, h: bh,
				  draw: displayButton, color: setbColor}
	return button
}

// draws the buttons
function displayButton() {
	fill(this.bColor);
	if (this.shape == "rect") {
		rect(this.x, this.y, this.w, this.h);
	}
	else if (this.shape === "ellipse") {
		ellipse(this.x, this.y, this.w, this.h);
	}
}

// sets the button color
function setbColor(c) {
	this.bColor = color(c);
}

// Object: Creates text
function makeText(input, tx, ty, tSize) {
	var textForButton = {x: tx, y: ty, size: tSize, tColor: color(backCol),
						 t: input, draw: displayText, color: setTColor}
	return textForButton;
}

// draw the text
function displayText() {
	fill(this.tColor);
	textSize(this.size);
	text(this.t, this.x, this.y);
}

// set the text color
function setTColor(c) {
	this.tColor = color(c);
}

function mousePressed() {

	// click draw button to go to draw mode
	if ((mouseX > 7/9 * width) & (mouseX < 7/9 * width + 80) 
		&& (mouseY > 6/7 * height) && (mouseY < 6/7 * height + 30)
		&& (drawing == false) && (diffRadii)) {
		drawing = ! drawing;
		justClicked = true;
	}

    // back button -- send to settings screen
	else if (dist(mouseX, mouseY, backB, backB) <= backB / 2) {
		drawing = false;
	}

    // 3 math equations -- button to rotate the math equations
    else if ((mouseX > eqX) & (mouseX < eqX + eqW) 
        && (mouseY > 7/8 * height) && (mouseY < 7/8 * height + eqY - 5)
        && (drawing == false)) {
        equationCount += 1;
    }

    // drag radius 1 slider
    if (dist(r1x, ry, mouseX, mouseY) < rd / 2) {
        dragging = true;
        rad1 = true;
        justClicked = false;
        drawing = false;

    }

    // drag radius 2 slider
    else if (dist(r2x, ry, mouseX, mouseY) < rd / 2) {
        dragging = true;
        rad2 = true;
        justClicked = false;
        drawing = false;
    }

    // drag line length slider
    else if (dist(px, ry, mouseX, mouseY) < rd / 2) {
        print("t");
        dragging = true;
        lineL = true;
        justClicked = false;
        drawing = false;

    }

    // click inside color box
    if ((mouseX <= colorX + eqY) & (mouseX >= colorX)
        && (mouseY <= colorY + eqY) && (mouseY >= colorY) 
        && drawing === false) {
        choosing = true;
    }

    // set pen color to user's click
    if (choosing) {
        userCol = color(get(mouseX, mouseY));
    }
}

function mouseReleased() {
    dragging = false;
    rad1 = false;
    rad2 = false;
    lineL = false;
}

function keyPressed() {
    // use left arrow key to go back to the settings screen
    if ((drawing) & (keyCode === LEFT_ARROW)) {
        drawing = false;
    }

    // set pen color by hitting enter key
    if ((choosing) & (keyCode === ENTER)) {
        choosing = false;
    }
}

Sean Meng-Final Project

hmeng-final project

//Sean Meng
//hmeng@andrew.cmu.edu
//Section C
//Final Project

var mySoundA;
var amp;
var vol = [];

function preload() {
    //Load music Love Lockdown
    mySoundA = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/Love_Lockdown-online-audio-converter.com.wav");
    mySoundA.setVolume(2);
}

function setup() {
    createCanvas(500, 500);
    //define amplitude and frequency to visualize
    amplitude = new p5.Amplitude();
    fft = new p5.FFT();
    mySoundA.amp(0.2);    
    frameRate(200);
}

function draw() {
    //size of the button
    var bSize = 20;
    background(218, 227, 226);
    noStroke();

//Album art background
    fill(250);
    rect(0, 0, 100, 500);

    fill(128, 15, 120);
    rect(85, 0, 15, 45);
    
    fill(34, 32, 99);
    rect(85, 45, 15, 45);  
    
    fill(242, 235, 97);
    rect(85, 90, 15, 45);   

    fill(141, 214, 204);
    rect(85, 135, 15, 45); 

    fill(92, 182, 224);
    rect(85, 180, 15, 45); 

    fill(53, 156, 120);
    rect(85, 225, 15, 45); 

    fill(242, 182, 241);
    rect(85, 270, 15, 45); 
    
    fill(197, 204, 124);
    rect(85, 315, 15, 45); 

    fill(181, 103, 180);
    rect(85, 360, 15, 45); 

    fill(184, 44, 116);
    rect(85, 405, 15, 45);  
    
    fill(49, 6, 92);
    rect(85, 450, 15, 50);      

//PAUSE button
    fill(0);
    rect(10, height - 30, bSize, bSize);

//PLAY button
    fill(0);
    triangle(10, height - 60, 10, height - 40, 30, height - 50);

//Spectrum represents amplitude
    let spectrum = fft.analyze();
    noStroke();
    fill(255); 
    for (var i = 0; i< spectrum.length; i++){
        let x4 = map(i, 0, spectrum.length, 100, width * 3.5);
        let h4 = -height + map(spectrum[i], 0, 255, height * 0.95, 0);
        rect(x4, height, width / spectrum.length, h4 )
    }

//Beating heart graphic represents amplitude
    let level = amplitude.getLevel();
    let offset = map(level, 0, 1, 0, 80);

//draw first half of the heart    
    strokeWeight(2);
    stroke(220, 30, 30);
    fill(220, 30, 30);
    beginShape();
    vertex(240 - offset, 180 - offset);
    vertex(270 - offset, 165 - offset);
    vertex(300, 180 - offset);
    vertex(330 + offset, 160 - offset);
    vertex(355 + offset, 170 - offset);   
    vertex(375 + offset, 200);
    vertex(355 + offset, 240);
    vertex(330 + offset, 270);
    vertex(290, 335 + offset);
    vertex(275 - offset, 280);
    vertex(240 - offset, 240);    
    vertex(220 - offset, 210);
    vertex(240 - offset, 180 - offset);
    endShape();

//Draw second half of the heart
    strokeWeight(2);    
    stroke(115, 20, 15);
    fill(115, 20, 15);
    beginShape();
    vertex(300, 180 - offset);
    vertex(330 + offset, 160 - offset);
    vertex(355 + offset, 170 - offset);   
    vertex(375 + offset, 200);
    vertex(355 + offset, 240);
    vertex(330 + offset, 270);
    vertex(290, 335 + offset);
    vertex(305 + offset, 270);
    vertex(290 - offset, 245); 
    vertex(300 + offset, 215);        
    vertex(275 - offset, 200);
    vertex(300, 180 - offset);
    endShape();

//Five waveform that visualzie frequency
    //wave A
    let waveform = fft.waveform();
    noFill();
    beginShape(POINTS);
    stroke(150, 10, 10);
    strokeWeight(2);
    for(var i = 0; i < waveform.length; i++){
        let x0 = map(i, 0, waveform.length, 100, width);
        let y0 = map(waveform[i], - 3, 3, 0, height);
        vertex(x0, y0);
    }
    endShape();

    //wave B
    beginShape(POINTS);
    stroke(180, 10, 10);
    strokeWeight(2);
    for(var i = 0; i < waveform.length; i++){
        let x0 = map(i, 0, waveform.length, 100, width);
        let y0 = map(waveform[i], - 1.5, 1.5, 0, height);
        vertex(x0, y0);
    }
    endShape();
    
    //Wave C
    beginShape(POINTS);
    stroke(220, 30, 30);
    strokeWeight(2);
    for(var i = 0; i < waveform.length; i++){
        let x1 = map(i, 0, waveform.length, 100, width);
        let y1 = map(waveform[i], - 0.7, 0.7, 0, height);
        vertex(x1, y1);
    }
    endShape();

    //Wave D
    beginShape(POINTS);
    stroke(230, 50, 50);
    strokeWeight(1);
    for(var i = 0; i < waveform.length; i++){
        let x2 = map(i, 0, waveform.length, 100, width);
        let y2 = map(waveform[i], - 0.4, 0.4, 0, height);
        vertex(x2, y2);
    }
    endShape();

    //Wave E
    beginShape(POINTS);
    stroke(230, 90, 90);
    strokeWeight(0.5);
    for(var i = 0; i < waveform.length; i++){
        let x2 = map(i, 0, waveform.length, 100, width);
        let y2 = map(waveform[i], - 0.2, 0.2, 0, height);
        vertex(x2, y2);
    }
    endShape();

    //Title of the album
    push();
    translate(75, 250);
    rotate(- PI / 2);
    stroke(65);
    fill(65);
    textStyle(BOLDITALIC);
    textSize(25);
    text('808s & Heartbreaks', 0, 0);
    pop();
}

function mousePressed() {
    //play the song when buttonA is clicked
    if(mouseX > 10 & mouseX < 30 && mouseY > height - 60 && mouseY < height - 40){
        mySoundA.play();
    } 
    //pause the song when buttonB is clicked
    if(mouseX > 10 & mouseX < 30 && mouseY > height - 30 && mouseY < height - 10){
        mySoundA.pause();
    }     
}    

In this project, I intend to homage to my favorite artist of all time Kanye West. The project represents a visualization of his song Love Lockdown from his renowned album 808’s & Heartbreaks. The representation and graphic elements are inspired by the original album cover that designed by artist Kaws. While the beating heart visualizes the amplitude of the music, the waveforms which has a gradient of both color and stroke weight visualizes the frequency of the song. As the song goes, the frequency gets increasingly complicated and generates intriguing pattern.

The original album cover by Kaws
Visualization at 02:37
Concept sketches

Siwei Xie – Final Project

sketch

//Siwei Xie
//Section B
//sxie1@andrew.cmu.edu
//Final Project

var size = 10;//original size of brush stroke

function setup() {
    createCanvas(480, 480);
    background("white");
    frameRate(500);//speed of drawing balls
}

function draw() {
    //fill unwanted borders with purple rectangels
	noStroke();
	fill(194, 192, 216);
	rect(0, 0, 480, 70);
    rect(0, 0, 150, 480);
    rect(450, 0, 30, 480);
    rect(0, 450, 480, 30);

    //titles & functions of drawing pad
	textStyle(NORMAL);
    textStyle(BOLD);
    textSize(27);
    fill("white");
    text('My Drawing Pad', 200, 50);

    textSize(15);
    fill(101, 67, 89);
    text('1. Drag mouse', 9, 115);
    text('to draw', 25, 133);
    text('2. Click buttons', 15, 220);
    text('to add patterns', 20, 235); 

    //notes for buttons
    textSize(12);
    fill("black");
    textStyle(ITALIC);
    text('Press B for big brush', 15, 153);
    text('Press S for small brush', 15, 168);

    //buttons for BACKGROUND 
    fill(185, 88, 84);//maroon square
    square(20, 250, 20); 

    fill("gray");//gray square
    square(60, 250, 20);

    fill("yellow");//yellow square
    square(100, 250, 20);

    //button for ERASE
    fill("white");
    rect(40, 360, 60, 40);
    fill("black");
    text('ERASE', 50, 385);
    
    //draw by using BRUSH
    if (mouseIsPressed) {
        fill(random(255), random(255), random(255));
        ellipse(mouseX, mouseY, size);
    }
} 

function keyPressed(){
    if (key === "B" || key === "b") {
        size += 10;//increase width of stroke
    }

    if (key === "S" || key === "s") {
        size -= 10;//decrease width of stroke
    }
}

function mouseClicked(){
    //PATTERN 1: use nested Loop to create shapes
    if(mouseX > 20 & mouseX < 40 && 
        mouseY > 250 && mouseY < 270){
    for (var j = 0; j < 12; j++) {
        for (var i = 0; i < 8; i++) {

        //maroon circles
        noStroke();
        fill(185, 88, 84);
        circle(i * 40 + 160, j * 30 + 95, 20);
        
        //white verticle lines
        fill("white");
        rect(i * 40 + 155, 80, 3, 370);
        }
    }
    noLoop();
    }

    //PATTERN 2: 
    if(mouseX > 60 & mouseX < 80 && 
        mouseY > 250 && mouseY < 270){
        fill("white");
        rect(150, 70, 300, 380);
        for (var y = 0; y < 360; y += 45) {
            for (var x = 0; x < 270; x += 45) {
                fill(182, 182, 182);
                circle(x + 180, y + 105, 45);
        }
    }
    noLoop();
    }

    //PATTERN 3: 
    if(mouseX > 100 & mouseX < 120 && 
        mouseY > 250 && mouseY < 270){
        for (var a = 0; a < 280; a = a + 1) {
        strokeWeight(20);
        stroke("yellow");
        //curve's starting point, height - curving extent * direction
        point(a + 160, 250 - 100 * sin(radians(a)));
        stroke(253, 241, 161);
        point(a + 160, 250 - 100 * cos(radians(a)));
        }
    noLoop();
    }

    //ERASE:
    if(mouseX > 40 & mouseX < 100 && 
        mouseY > 360 && mouseY < 400){
        noStroke();
        fill("white");
        rect(150, 70, 300, 380);
    }
}

In my final project, I created an “Interactive drawing pad.” Firstly, users can drag mouse on the white drawing pad to draw colorful stroke. They can change width of stroke by pressing S or B. Secondly, users can click on the 3 buttons on the left to select different patterns to fill the pad. Finally, they can use ERASE function to erase previously drawn strokes or patterns.

Sean Leo – Project Proposal

Often during installations as a media designer, you work in unique environments where the technical demands of a system are very specific. I’ve come to find that many programs supply their own stock branded test card that doesn’t reflect the complexity or scope of the project. As I’ve built custom systems and done shows with multiple outputs I’ve realized a need for more customization with the test cards I use.

For my final project in 15104, I’d like to create a test card generator of my own design. Essentially this entails creating a responsive template that accounts for size, and having custom inputs; text, color, maybe even image. My list of features for this project are:

  • Custom resolution as an input field.
  • Custom color palette
  • Scalable grid sizing
  • Text input
  • Export as an image file.