Final Project – Polarization & Authoritarianism

I interpreted the 2020 theme as part of our ongoing political crisis. The Republican party has begun to show their true colors as authoritarians, so I tried to explain what that process means in this project using simple particle visualizations.

Users can learn some basic political science, and have fun screwing over democracy in the process.

For the most part, the project acts as a sort of slideshow, moving between animations. The last slide, however, allows users to manipulate the system directly for themselves. The particle simulation code we used extensively in class was used & heavily modified for this simulation. The program also relies heavily on for-loops, objects, and if-statements.

-Robert

sketch
var slide = 0;  //variable that keeps track of which slide is being displayed. 0 corresponds to the title screen.

var democrat    //these four are color variables, used to keep track of each type of voter
var rep
var auth    //authoritarians
var orange  //orange represents 'the strongman leader'.
var voters  //'neutral', or persuadable voters

var vPart = []; //particle array representing "generic" voters
var dPart = []; //particle array representing democrat voters
var rPart = []; //particle array representing republican voters
var aPart = []; //particle array representing authoritarian voters
var dict = [];

//hard boundaries are on by default for all particles so that they can be put in boxes.

function createVParticles(n, x, y, w, h, v) {   //creates voters given a quantity n, position range defined by x, y, w, & h, and a velocity range -v to v
    for(i=0; i<n; i++) {
        newP = makeParticle(random(x, x+w), random(y, y+h), random(-v, v), random(-v, v));
        newP.bHardBoundaries = true;
        append(vPart, newP);
    }
}

function createDParticles(n, x, y, w, h, v) {   //creates democrat particles within a given rectangle & velocity range
    for(i=0; i<n; i++) {
        newP = makeParticle(random(x, x+w), random(y, y+h), random(-v, v), random(-v, v));
        newP.bHardBoundaries = true;
        append(dPart, newP);
    }
}

function createRParticles(n, x, y, w, h, v) {   //creates republican particles within a given rectangle & velocity range
    for(i=0; i<n; i++) {
        newP = makeParticle(random(x, x+w), random(y, y+h), random(-v, v), random(-v, v));
        newP.bHardBoundaries = true;
        append(rPart, newP);
    }
}

function createAParticles(n, x, y, w, h, v) {   //creates authoritarian particles within a given rectangle & velocity range
    for(i=0; i<n; i++) {
        newP = makeParticle(random(x, x+w), random(y, y+h), random(-v, v), random(-v, v));
        newP.bHardBoundaries = true;
        append(aPart, newP);
    }
}

function makeDictator(x, y, d) {    //makes a dynamic orange circle
    var d = {tx: x, ty: y, diameter: d, force: 1, drawFunction: drawDictator};

    dict[0] = d;
}

function drawDictator() {   //draws the circle, maps it to the mouse
    var left = this.tx - this.diameter/2;
    var right = this.tx + this.diameter/2;
    var top = this.ty - this.diameter/2;
    var bottom = this.ty + this.diameter/2;

        this.tx = mouseX;
        this.ty = mouseY;

    push();
    noStroke();
    fill(orange);
    circle(this.tx, this.ty, this.diameter);
    pop();
}

function setup() {
    createCanvas(950, 500);   //multiplication is used to keep the canvas the same w/h ratio as the american flag. This setup is 950 x 500
    background(255);+
    text("p5.js vers 0.9.0 test.", 10, 15);
    frameRate(60);

    dem = color(70, 70, 240);
    rep = color(240, 70, 70);
    auth = color(25);   
    voter = color(200);
    orange = color(255, 140, 25);

    noStroke();
}

var count = 0;  //used to make stuff move

function draw() {
    if (slide == 0) {   //title screen. Each slide is coded separately here, and simply clicking will advance the slide.
        push();
            background(255);
            if (count < width/64) { //displays the moving title screen intro, then the interactive title screen
                titleIntro();
            } else {
                titleScreen();
            }
        pop();
    }

    if (slide == 1) {   //Explainer screen, explains the diagrams, what the particles mean, and gives context
        push();
            background(65);

            push();
            rectMode(CENTER);
            textAlign(CENTER, CENTER);
            textSize(30);
            fill(255);
            text('These particles represent voters. Each color represents a political leaning, and each box represents a grouping.',width/2, 100, width/2, 300);
            
            textStyle(BOLD);    //labels for each voter box
            textSize(25);
            fill(dem);
            text('Liberal', 157.5, 400);

            fill(rep)
            text('Conservative', 367.5, 400);

            fill(voter);
            text('Moderate', 577.5, 400);

            fill(auth);
            text('Authoritarian', 787.5, 400);
            pop();            

            for(i=0; i < dPart.length; i++) {   //these for loops update the position of each particle & draws them
                dPart[i].draw(dem, 15);         //dems
                dPart[i].update(105*1, 250, 105, 105);
            }  
            for(i=0; i < rPart.length; i++) {   //reps
                rPart[i].draw(rep, 15);
                rPart[i].update(105*3, 250, 105, 105);
            }
            for(i=0; i < vPart.length; i++) {   //swing voters
                vPart[i].draw(voter, 15);
                vPart[i].update(105*5, 250, 105, 105);
            }
            for(i=0; i < aPart.length; i++) {   //authoritarians
                aPart[i].draw(auth, 15);
                aPart[i].update(105*7, 250, 105, 105);
            }

            noStroke();
            stroke(255);
            strokeWeight(10);
            noFill();
            for(i=1; i<=7; i+=2) {
                rect(105*i-10, 250-10, 105+20, 105+20);
            }
        pop();
        slideOut(); //slideOut creates a fade-in transition for the slide. It needs to be put last so that it can fade in ON TOP of everything else.
    }

    if (slide == 2) {   //Geographic polarization, civil war thru WWII
        push();
            background(65);
            push();
                fill(255);
                textAlign(CENTER, CENTER);
                textSize(30);
                text('Since before the civil war through the 60s, Americans are divided sharply by geography & slavery. Regional loyalties are strong, and the glacial pace of information keeps regions separate.', 50, 50, 850, 150);
            pop();

            push();
                textStyle(BOLD);

                fill(255);
                textAlign(RIGHT, TOP);
                textSize(25);
                text('Republican (North)', 50, 235, 150, 200);

                textAlign(LEFT, TOP);
                textSize(25);
                text('Democrat (South)', 750, 235, 150, 200);
            pop();

            for(i=0; i < dPart.length; i++) {   //these for loops update the position of each particle & draws them
                dPart[i].draw(dem, 15);         //dems
                if(i < dPart.length/2) {
                    dPart[i].update(225, 250, 200, 200);    //because there are two boxes with the same kind of voter
                } else {                                    //doing updates has to be divided in half
                    dPart[i].update(525, 250, 200, 200);
                }
            }  
            for(i=0; i < rPart.length; i++) {   //reps
                rPart[i].draw(rep, 15);
                if(i < rPart.length/2) {
                    rPart[i].update(225, 250, 200, 200);
                } else {
                    rPart[i].update(525, 250, 200, 200);
                }
            }
            for(i=0; i < vPart.length; i++) {   //swing voters
                vPart[i].draw(voter, 15);
                if(i < vPart.length/2) {
                    vPart[i].update(225, 250, 200, 200);
                } else {
                    vPart[i].update(525, 250, 200, 200);
                }
            }

            push();
                noFill();
                stroke(255);
                strokeWeight(10);
                rect(525-10, 250-10, 200+20, 200+20);   //right rect
                rect(225-10, 250-10, 200+20, 200+20);   //left rect
            pop();
        pop();
        slideOut();
    }

    if (slide == 3) {   //ideological consolidation, WWII thru 1990s.
        push();
            background(65);

            push();
                fill(255);
                textAlign(CENTER, CENTER);
                textSize(30);
                text('Later, mass media allowed disparate people to connect. Conservative Republicans & liberal Democrats consolidated, creating idealogically distinct parties - with fewer swing voters.', 50, 50, 850, 150);
            pop();

            push();
                textStyle(BOLD);

                fill(255);
                textAlign(RIGHT, TOP);
                textSize(25);
                text('Democrat', 50, 235, 150, 200);

                textAlign(LEFT, TOP);
                textSize(25);
                text('Republican', 750, 235, 150, 200);
            pop();

            for(i=0; i < rPart.length; i++) {   //these for loops update the position of each particle & draws them
                rPart[i].draw(rep, 15);         //reps (now on the right)
                rPart[i].update(225, 250, 500, 200);
                rPart[i].vx += .015                              //slowly alters particle velocties so they fall to the right
                rPart[i].vx = constrain(rPart[i].vx, -2, 5)     //constrains their velocities so they stay generally on the right
            }  
            for(i=0; i < dPart.length; i++) {   //dems (now on the left)
                dPart[i].draw(dem, 15);
                dPart[i].update(225, 250, 500, 200);
                dPart[i].vx -= .015                              //slowly fall to the left
                dPart[i].vx = constrain(dPart[i].vx, -5, 2)     //constrains to the left
            }
            for(i=0; i < vPart.length; i++) {   //swing voters
                vPart[i].draw(voter, 15);       //swing voters float free
                vPart[i].update(225, 250, 500, 200);
            }
            push();
                noFill();
                stroke(255);
                strokeWeight(10);
                
                beginShape();   //left box
                    vertex(435, 240);
                    vertex(215, 240);
                    vertex(215, 460);
                    vertex(435, 460);
                endShape();

                beginShape();   //left box
                    vertex(515, 240);
                    vertex(735, 240);
                    vertex(735, 460);
                    vertex(515, 460);
                endShape();
            pop();
        pop();
        
        slideOut();
    }

    if (slide == 4) {   //Something strange has happened recently
        background(65);
        push();
            for (i=0; i<9; i++) {
                for (j=0; j<9; j++) {
                    fill(auth);
                    circle(375+20*(j+1) + random(-2, 2), 250+20*(i+1) + random(-2, 2), 15); //Because these 'voters' are supposed to be in lockstep, I presented them here as circles instead of particles
                }   //it makes the code simpler
            }

            push();
                fill(255);
                textAlign(CENTER, TOP);
                textSize(30);
                text('Recently, something strange has happened: the emergence of a new kind of voter. A minority of voters, mostly conservative, became afraid of losing power - and looked to strongman leaders.', 50, 50, 850, 150);
            pop();

            noFill();   //the authoritarian box (appropriately orange)
            stroke(255);
            strokeWeight(10);
            rect(375-10, 250-10, 200+20, 200+20);

            push();
                fill(orange);   //the 'leader' circle, whose location will act as an attractor point
                noStroke();
                ellipse(width/2, 350, 40, 40);

                fill(255);
                textAlign(LEFT, TOP);
                textSize(22);
                text('Authoritarians dont act like normal voters. What is most important to them is group loyalty. They value safety & order, and look for leaders that make them feel strong.', 650, 235, 250, 220);
            pop();
        pop();

        slideOut();
    }

    if (slide == 5) { //the authoritarian consolidation
        background(65);
        push();
            push();
                fill(255);
                textAlign(CENTER, TOP);
                textSize(30);
                text('In 2016, authoritarian voters became activated in response to demographic change. They consolidated around a leader in the republican party, pushing out or converting other conservatives.', 50, 50, 850, 150);
            pop();

            push();
                textStyle(BOLD);

                fill(255);
                textAlign(RIGHT, TOP);
                textSize(25);
                text('Democrat', 50, 235, 150, 200);

                textAlign(LEFT, TOP);
                textSize(25);
                text('Republican', 750, 235, 150, 200);
            pop();

            for(i=0; i < rPart.length; i++) {   //these for loops update the position of each particle & draws them
                rPart[i].draw(rep, 15);         //reps (now on the right)
                rPart[i].update(225, 250, 500, 200);
                rPart[i].vx += .01              //slowly alters particle velocties so they fall to the right
                if (rPart[i].px > 585) {        //if they go TOO FAR to the right, then they get pushed back
                    rPart[i].vx -= .5
                }                                               
                rPart[i].vx = constrain(rPart[i].vx, -2, 5)     //constrains their velocities so they stay generally on the right
            }  
            for(i=0; i < dPart.length; i++) {   //dems (now on the left)
                dPart[i].draw(dem, 15);
                dPart[i].update(225, 250, 500, 200);
                dPart[i].vx -= .02                              //slowly fall to the left
                dPart[i].vx = constrain(dPart[i].vx, -5, 2)     //constrains to the left
            }
            for(i=0; i < vPart.length; i++) {   //swing voters
                vPart[i].draw(voter, 15);       //swing voters float free
                vPart[i].update(225, 250, 300, 200);

                if (vPart[i].px >= 585) {        //if they go TOO FAR to the right, then they get pushed back
                    vPart[i].vx -= .5
                }
                vPart[i].vx = constrain(rPart[i].vx, -2, 2)     //constrains their velocities so they don't go too fast
            }
            for(i=0; i < aPart.length; i++) {   //dems (now on the left)
                aPart[i].draw(auth, 15);
                aPart[i].update(600, 250, 125, 200);
            }

            push();
                noFill();
                stroke(255);
                strokeWeight(10);
                
                beginShape();   //left box
                    vertex(435, 240);
                    vertex(215, 240);
                    vertex(215, 460);
                    vertex(435, 460);
                endShape();

                beginShape();   //left box
                    vertex(515, 240);
                    vertex(735, 240);
                    vertex(735, 460);
                    vertex(515, 460);
                endShape();
            pop();
        pop();
        slideOut();
    }

    if (slide == 6) { //authoritarian simulation
        background(65);
        push();
            push();
                fill(255);
                textAlign(CENTER, TOP);
                textSize(30);
                text('Even an otherwise stable political system can be disrupted by strongman demagogues.', 50, 50, 850, 150);

                //textStyle(BOLD);
                textSize(20);
                text('Move the mouse to disrupt democracy.', 50, 175, 850, 150);
            pop();

            for(i=0; i < rPart.length; i++) {   //these for loops update the position of each particle & draws them
                rPart[i].draw(rep, 15);         //reps are attracted to the dictator weakly
                rPart[i].update(225, 250, 500, 200);

                if (rPart[i].px > dict[0].tx) {rPart[i].vx -= .05}
                if (rPart[i].px < dict[0].tx) {rPart[i].vx += .05}
                if (rPart[i].py > dict[0].ty) {rPart[i].vy -= .05}
                if (rPart[i].py < dict[0].ty) {rPart[i].vy += .05}

                rPart[i].vx = constrain(rPart[i].vx, -5, 5);
                rPart[i].vy = constrain(rPart[i].vy, -5, 5);
            }  
            for(i=0; i < dPart.length; i++) {   //dems get pushed away by the circle strongly
                dPart[i].draw(dem, 15);
                dPart[i].update(225, 250, 500, 200);

                if (dPart[i].px > dict[0].tx) {dPart[i].vx += .2}
                if (dPart[i].px < dict[0].tx) {dPart[i].vx -= .2}
                if (dPart[i].py > dict[0].ty) {dPart[i].vy += .2}
                if (dPart[i].py < dict[0].ty) {dPart[i].vy -= .2}

                dPart[i].vx = constrain(dPart[i].vx, -5, 5);
                dPart[i].vy = constrain(dPart[i].vy, -5, 5);
            }
            for(i=0; i < vPart.length; i++) {   //swing voters get pushed away by the circle weakly
                vPart[i].draw(voter, 15);
                vPart[i].update(225, 250, 500, 200);

                if (vPart[i].px > dict[0].tx) {vPart[i].vx += .1}
                if (vPart[i].px < dict[0].tx) {vPart[i].vx -= .1}
                if (vPart[i].py > dict[0].ty) {vPart[i].vy += .1}
                if (vPart[i].py < dict[0].ty) {vPart[i].vy -= .1}

                vPart[i].vx = constrain(vPart[i].vx, -5, 5);
                vPart[i].vy = constrain(vPart[i].vy, -5, 5);
            }
            for(i=0; i < aPart.length; i++) {   //authoritarians move towards the circle strongly
                aPart[i].draw(auth, 15);
                aPart[i].update(225, 250, 500, 200);

                if (aPart[i].px > dict[0].tx) {aPart[i].vx -= .2}
                if (aPart[i].px < dict[0].tx) {aPart[i].vx += .2}
                if (aPart[i].py > dict[0].ty) {aPart[i].vy -= .2}
                if (aPart[i].py < dict[0].ty) {aPart[i].vy += .2}

                aPart[i].vx = constrain(aPart[i].vx, -5, 5);
                aPart[i].vy = constrain(aPart[i].vy, -5, 5);
            }

            push();
                noFill();
                stroke(255);
                strokeWeight(10);
                
                beginShape();   //left box
                    vertex(435, 240);
                    vertex(215, 240);
                    vertex(215, 460);
                    vertex(435, 460);
                endShape();

                beginShape();   //left box
                    vertex(515, 240);
                    vertex(735, 240);
                    vertex(735, 460);
                    vertex(515, 460);
                endShape();
            pop();
            dict[0].drawFunction();
        pop();
        slideOut();
    }

    if (slide == 7) {
        background(65);
        push();
                fill(255);
                textAlign(CENTER, TOP);
                textSize(20);
                text('- Benjamin Franklin', 50, 175, 850, 150);

                textSize(30);
                text('Thank You for Playing', 50, 350, 850, 150);


                textStyle(BOLD);
                textSize(30);
                text('“Those who would give up essential liberty to purchase a little temporary safety, deserve neither liberty nor safety.”', 50, 50, 850, 150);

        pop();
        slideOut();
    }

}

function titleIntro() { //Provides the introduction to the title screen, where the rectangles fly in
        push();
            fill(dem);
            rect(0, 0, count*32, height);
        pop();

        push();
            fill(rep);
            rect(width, 0, -count*32, height);
        pop();

        if(count < width/64) {
                count++
        }
}

function titleScreen() {    //Displays the title screen
    push();
        noStroke();
        fill(dem);
        rect(0, 0, width/2, height);
    pop();

    push();
        noStroke();
        fill(rep);
        rect(width/2, 0, width, height);
    pop();

    if (mouseX > width/2 & mouseY > 0 && mouseY < height) {
        push();
            fill(auth);
            rect(width/2, 0, constrain(mouseX-width/2-25, 0, width/2-25), height);
        pop();
        

        push();
            noStroke();
            fill(rep);
            textAlign(RIGHT, CENTER);
            textSize(40);
            text('POLARIZATION & AUTHORITARIANISM', (width/2 + constrain(mouseX-width/2-50, 0, width/2-25))/2, 0, constrain(mouseX, 0, width/2-25), height);
            textSize(10);
            text('CLICK TO PROCEED', (width/2 + constrain(mouseX-width/2-50, 0, width/2-45))/2, 60, constrain(mouseX, 0, width/2-25), height);
        pop();

        push();
            noStroke();
            fill(dem);
            rect(0, 0, width/2, height);
        pop();
    }   
}

function slideOut() {   //Runs on top of each slide, creating the illusion of a smooth fade-in
    push();
        fill(65, 255-count);
        rect(0, 0, width, height);
    pop();
    if (count <= 255) {
        count+=3
    }
}

function mousePressed() {   //advances which simulation is shown. Also used to instance functions which need to run exactly once for a slide.
    slide++


    vPart = []; //empties all the arrays whenever the slide changes, giving a fresh slate.
    dPart = [];
    rPart = [];
    aPart = [];
    dictator = [];
    count = 0;

    if (slide == 1) {
        createDParticles(1, 105*1, 250, 105, 105, 2);
        createRParticles(1, 105*3, 250, 105, 105, 2);
        createVParticles(1, 105*5, 250, 105, 105, 2);
        createAParticles(1, 105*7, 250, 105, 105, 2);
    }

    if (slide == 2) {
        createDParticles(5, 225, 250, 200, 200, 2);
        createRParticles(5, 225, 250, 200, 200, 2);
        createVParticles(5, 225, 250, 200, 200, 2);

        createDParticles(5, 525, 250, 200, 200, 2);
        createRParticles(5, 525, 250, 200, 200, 2);
        createVParticles(5, 525, 250, 200, 200, 2);
    }

    if (slide == 3) {
        createDParticles(6, 225, 250, 200, 200, 2);
        createRParticles(6, 225, 250, 200, 200, 2);
        createVParticles(3, 225, 250, 200, 200, 2);

        createDParticles(6, 525, 250, 200, 200, 2);
        createRParticles(6, 525, 250, 200, 200, 2);
        createVParticles(3, 525, 250, 200, 200, 2);
    }

    if (slide == 4) {
        //just a placeholder in case I wanted to put stuff here later
    }

    if (slide == 5) {
        createDParticles(10, 225, 250, 200, 200, 2);
        createRParticles(6, 585, 250, 140, 200, 2);

        createVParticles(4, 365, 250, 200, 200, 2);

        createAParticles(14, 585, 250, 140, 200, 5);
    }

    if (slide == 6) {
        createDParticles(10, 225, 250, 200, 200, 0);
        createRParticles(10, 525, 250, 200, 200, 0);

        createVParticles(10, 225, 250, 200, 200, 0);
        createAParticles(10, 525, 250, 200, 200, 0);

        makeDictator(width/2, height/2, 40);
    }


    if (slide > 7) {    //wraps the whole program around if the last slide is reached
        slide = 0;
    }
}

//start particle code [CODE BELOW IS MODIFIED FROM EARLIER EXAMPLES TO MAKE IT MORE GENERAL & FLEXIBLE]
function makeParticle(x, y, dx, dy) {
    var p = {px: x, py: y, vx: dx, vy: dy,
             bFixed: false,
             bLimitVelocities: false,
             bPeriodicBoundaries: false,
             bHardBoundaries: false,
             update: particleUpdate,
             handleBoundaries: particleHandleBoundaries,
             draw: particleDraw
            }
    return p;
}

// Update the position based on force and velocity. x, y, w, h define a rectangle within which the particle bounces around.
function particleUpdate(x, y, w, h) {
        this.handleBoundaries(x, y, w, h);
        this.px += this.vx;
        this.py += this.vy;
}

// do boundary processing if enabled. Modified to process bounds within a given rectangle instead of the canvas. x, y, w, h are passed off from te particleUpdate function
function particleHandleBoundaries(x, y, w, h) {
    if (this.bPeriodicBoundaries) {
        if (this.px > x + w) this.px -= width;
        if (this.px < x) this.px += width;
        if (this.py > y + h) this.py -= height;
        if (this.py < y) this.py += height;
    } else if (this.bHardBoundaries) {
        if (this.px >= x + w) {
            this.vx = -abs(this.vx);
        }
        if (this.px <= x) {
            this.vx = abs(this.vx);
        }
        if (this.py >= y + h) {
            this.vy = -abs(this.vy);
        }
        if (this.py <= y) {
            this.vy = abs(this.vy);
        }
    }
}

//Draws the particle, given a color & size
function particleDraw(c, s) {
    fill(c);
    ellipse(this.px, this.py, s, s);
}

Project-11

sketch
//Robert Rice
//rdrice
//section c

var sun = {filename:'https://i.imgur.com/74H6zli.png', //original URL https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/7bcda634-15a0-43a8-9de8-2800412220c0/datjxhn-b3b3c9fa-946d-43e2-b2b4-28dc84b56ca0.png/v1/fit/w_150,h_150,strp/retrowave_sun_with_alpha_background_by_robilo_datjxhn-150.png?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7ImhlaWdodCI6Ijw9MTAyNCIsInBhdGgiOiJcL2ZcLzdiY2RhNjM0LTE1YTAtNDNhOC05ZGU4LTI4MDA0MTIyMjBjMFwvZGF0anhobi1iM2IzYzlmYS05NDZkLTQzZTItYjJiNC0yOGRjODRiNTZjYTAucG5nIiwid2lkdGgiOiI8PTEwMjQifV1dLCJhdWQiOlsidXJuOnNlcnZpY2U6aW1hZ2Uub3BlcmF0aW9ucyJdfQ.sdt5sozezYuJLi-b3ecAoqszmafFkXh8VGg3G1-YSqE
            x:300,
            y:175,
            drawFunc: drawImg}

var mustang = {filename:'https://i.imgur.com/ZQ6wSq5.png', //I DREW THIS (i traced it but still)
            x:100,
            y:279,
            drawFunc: drawImg}

var wheels = {filename:'https://i.imgur.com/5edjrVN.png', //I DREW THIS (okay i traced but still its technically original)
            x:103,
            y:289,
            drawFunc: drawImg}


var dx = 2; //the speed at which the furthest background objects pass by

var marketvalue = [];   //Reusing my code from assignment 07-a to make an undulating middleground
var noiseParam = 0;
var noiseStep = 0.005;
var n;  //end reused code, appears as DUNES below

var hills=[];

var sign = 1    //the value that the car is pushed up/down by
var pushCount = 0   //keeps track of how far the car has bumped up/down


function preload() {
    // call loadImage() and loadSound() for all media files here
    sun.image = loadImage(sun.filename);
    mustang.image = loadImage(mustang.filename);
    wheels.image = loadImage(wheels.filename);
}

function setup() {
    createCanvas(500, 300);
    background(0);
    imageMode(CENTER);

    strokeWeight(5);
    stroke(119, 179, 0);

    n = (width / 5) + 1 //sets up initial points for the dunes
    for(i = 0; i <= n; i++) {
        noiseParam = noiseStep*i
        marketvalue[i] = (noise(noiseParam) * 150)+150;
    }
}

function draw() {
    //BEGIN BACKGROUND

    push();
    background(38, 0, 77);  //gradient background
    for(i=0; i<300; i++) {
        strokeWeight(1);
        stroke(255-(0.723*i), 77-(0.256*i), 196-(0.396*i))
        line(0, 299-i, 500, 299-i);
    }
    sun.drawFunc(150, 150); //background Sun
    pop();

    //END BACKGROUND
    //BEGIN HILLS. makes some hills/mesas that lazily move along in the background
    
    push();
    if(random(1) > 0.99) {
        makeHill(random(50, 200), random(50, 125), color(random(169, 189), random(49, 69), random(0, 10)));
    }

    var numH = hills.length;
    if (numH > 0) {
        for (i=0; i<numH; i++) {
            hills[i].drawFunc();
            hills[i].upFunc();
        }

        if (hills[0].x+hills[0].r < 0) {
            hills.shift();
        }
    }
    pop();

    //END HILLS
    //BEGIN DUNES (the 07-a reused code i mentioned)

    push();
    marketvalue.shift();    //gets rid of the first value in the list in order to make room for a new one

    strokeWeight(5);
    stroke(179, 119, 0);
    fill(204, 170, 0);
    beginShape();
    vertex(0, height);
    for(i=0; i<n; i++) {
        vertex(5*i, marketvalue[i])
    }
    vertex(width, height);
    endShape(CLOSE);
    
    noiseParam = noiseParam + noiseStep;    //increases the noise paramter, generates a new rolling value
    marketvalue.push(noise(noiseParam)*150+150); //appends the new value
    pop();

    //END DUNES
    //BEGIN ROAD
    push();
    strokeWeight(20);
    stroke(150);
    line(0, 295, 499, 295)
    stroke(75);
    line(0, 299, 499, 299);
    pop();
    //END ROAD
    //BEGIN CAR
    push();
        mustang.y += sign/4
        wheels.drawFunc(77, 15);
        mustang.drawFunc(100, 35);

    pushCount++
    if (pushCount > 8) {
        sign = -sign
        pushCount = 0
    }
    pop();
    //END CAR
}

//END CODE
//BEGIN HELPERFUNCTIONS

function drawImg(w, h) {
    image(this.image, this.x, this.y, w, h);
}

function makeHill(r, h, c) {
    var newHill = {r: r,
        h: h,
        x: 499,
        y: 299,
        drawFunc: drawHill,
        upFunc: updateHill,
        color: c,
        speed: dx}

    hills.push(newHill);
}

function drawHill() {
    noStroke();
    fill(this.color);
    rect(this.x, this.y, this.r, -this.h);
    ellipse(this.x+this.r/2, this.y-this.h, this.r, this.r);
}

function updateHill() {
    this.x -= this.speed;
}

Looking Outwards 11

ANGELA WASHKO
THE GAME: THE GAME, VIDEO GAME, 2018

play The Game: the Game

https://angelawashko.com/section/437138-The-Game-The-Game.html

The game: the game is exactly what it sounds like: a video game about ‘the game’ – a euphemism for the formalized male practice of ‘seducing’ or ‘picking up’ women. The game: the game takes the form of a dating sim where ‘pick-up gurus’ vie for the player’s attention using strategies and techniques taken straight from their own instructional materials.

A still from ‘The Game: The Game’

I really admire this work for how direct it is. It directly tackles the inherent chauvinism & absurdity of ‘pick up artists’ and their objectification of women. Most interestingly, it uses the interactive nature of video games to the fullest. While other artworks might convey the same message, only a game could provide you with a facsimile of first-hand experience.

Angela Washko is currently a tenure-track Assistant Professor of Art at CMU.

-Robert

LO-10 Computer Sound

Star Wars Blaster Sound Effect

Ben Burtt, who did sound design for the original star wars movies, also made the class blaster sound effect. A combination of digital & analog techniques, it has been remade and remixed countless times over the years as the franchise is adapted and updated.

As demonstrated in the video, the sound was originally recorded using steel cable under tension (or a slinky, in this case) & a wrench. The classic PEW PEW was then saved, isolated from background noise, layered with other sounds, and edited into the movie. In the same way that Star Wars has defined what a good sci-fantasy movie SHOULD be, its iconic blaster sound has also cemented into our cultural consciousness what a laser gun SHOULD sound like. That iconic sound would not be possible without a combination of analog & digital processes.

-Robert

Project-10 Sound Story

This is a story about a duck, a duckling, a cloud, and lightning bolt.

sketch
//Robert Rice
//rdrice
//Section C


// sketch.js template for sound and DOM
//
// This is the 15104 Version 1 template for sound and Dom.
// This template prompts the user to click on the web page
// when it is first loaded.
// The function useSound() must be called in setup() if you
// use sound functions.
// The function soundSetup() is called when it is safe
// to call sound functions, so put sound initialization there.
// (But loadSound() should still be called in preload().)

var mama = {filename:'https://i.imgur.com/z44s88k.png', //https://images.dailykos.com/images/214263/story_image/Duck-37.png?1456291242
            x:0,
            y:0,
            playFunc: playOsc,
            stopFunc: stopOsc,
            drawFunc: drawImg}
var duckling = {filename:'https://i.imgur.com/X5iYcio.png', //https://purepng.com/public/uploads/large/91508076238ploll99zx4ifi35p6b1qrontiecfaivclrqbiz0gfg0rru6qtj7qmlw2qmvrthjbk3sj2wgiwa12pz4n00nufufllybyth2akpcx.png
            x:0,
            y:0,
            playFunc: playOsc,
            stopFunc: stopOsc,
            drawFunc: drawImg}
var cloud = {filename:'https://i.imgur.com/igVfind.png', //https://clipground.com/images/clipart-cloud-png-10.png
            x:-50,
            y:100,
            playFunc: playOsc,
            stopFunc: stopOsc,
            drawFunc: drawImg}
var lightning = {filename:'https://i.imgur.com/9RODxMu.png', //https://asr4u.files.wordpress.com/2013/06/lightning-bolt-hi1.png
            x:150,
            y:150,
            playFunc: playOsc,
            stopFunc: stopOsc,
            drawFunc: drawImg}
var tScale = 1; //used later for scaling stuff down. 1 == 100%


function preload() {
    // call loadImage() and loadSound() for all media files here

    mama.image = loadImage(mama.filename);
    duckling.image = loadImage(duckling.filename);
    cloud.image = loadImage(cloud.filename);
    lightning.image = loadImage(lightning.filename);
    //loadSound();
}


function setup() {
    // you can change the next 2 lines:
    createCanvas(300, 300);
    createDiv("p5.dom.js library is loaded.");
    frameRate(30);
    imageMode(CENTER);
    //======== call the following to use sound =========
    useSound();
}


function soundSetup() { // setup for audio generation
    // you can replace any of this with your own audio code:
    mama.osc = new p5.Oscillator();
    mama.trem = new p5.Oscillator();    //mama duck's voice
    mama.trem.freq(10);
    mama.osc.setType('sawtooth');
    mama.osc.freq(midiToFreq(60));
    mama.osc.amp(mama.trem);

    duckling.osc = new p5.Oscillator();
    duckling.trem = new p5.Oscillator();    //baby duck's voice
    duckling.trem.freq(30);
    duckling.osc.setType('sawtooth');
    duckling.osc.freq(midiToFreq(70));
    duckling.osc.amp(mama.trem);

    cloud.osc = new p5.Oscillator();
    cloud.trem = new p5.Oscillator();   //makes cloud go brrrrrrr
    cloud.trem.freq(10);
    cloud.osc.setType('sawtooth');
    cloud.osc.freq(midiToFreq(31));
    cloud.osc.amp(cloud.trem);

    lightning.osc = new p5.Oscillator();    //lightning sound
    lightning.trem = new p5.Oscillator();  //makes it go pew pew
    lightning.trem.freq(10000);
    lightning.osc.setType('square');
    lightning.osc.amp(lightning.trem);
    lightning.osc.freq(midiToFreq(90));
}


function draw() {
    // you can replace any of this with your own code:
    background(200);    
    
    if (frameCount >= 0 & frameCount <= 150) {     //act I the status quo
        mama.x = 50;
        mama.y = 250;
        mama.drawFunc(100, 100);

        duckling.x = 100;
        duckling.y = 275;
        duckling.drawFunc(40, 50);

        if (frameCount == 30) {mama.playFunc();
            mama.drawFunc(200, 200);}
        if (frameCount == 50) {mama.stopFunc();}

        if (frameCount == 60) {duckling.playFunc();
            duckling.drawFunc(80, 100);}
        if (frameCount == 70) {duckling.stopFunc();}

        if (frameCount == 90) {mama.playFunc();
            mama.drawFunc(200, 200);}
        if (frameCount == 150) {mama.stopFunc();}

        if (frameCount == 120) {duckling.playFunc();}
        if (frameCount > 120 & frameCount < 150) {duckling.drawFunc(200, 200);}
        if (frameCount == 150) {duckling.stopFunc();}
    }

    if (frameCount >= 150 & frameCount <= 300) {   //act II a cloud arrives
        mama.drawFunc(100, 100);
        duckling.drawFunc(40, 50);

        var cDX = 2 //the speed at which the cloud will move across the screen


        cloud.drawFunc(100, 50);

        cloud.x += cDX;
        if (cloud.x > 150) {cloud.x = 150;} //will move across the screen, before settling in the middle

        if (frameCount == 250) {cloud.playFunc();}
        if (frameCount > 250 & frameCount < 300) {cloud.drawFunc(300, 150);}
        if (frameCount == 300) {cloud.stopFunc();}
    }

    if (frameCount >= 300 & frameCount <= 450) {   //act III the cloud brings forth lightning
        mama.drawFunc(100, 100);
        duckling.drawFunc(40, 50);
        cloud.drawFunc(300, 150);

        if (frameCount == 325) {lightning.playFunc(); lightning.drawFunc(100, 100);}
        if (frameCount == 330) {lightning.stopFunc(); lightning.drawFunc(50, 50);}

        if (frameCount == 355) {lightning.playFunc(); lightning.drawFunc(100, 100);}
        if (frameCount == 360) {lightning.stopFunc(); lightning.drawFunc(50, 50);}

        if (frameCount == 385) {lightning.playFunc(); lightning.drawFunc(100, 100);}
        if (frameCount == 390) {lightning.stopFunc(); lightning.drawFunc(50, 50);}

        if (frameCount == 415) {lightning.playFunc(); lightning.drawFunc(100, 100);}
        if (frameCount == 420) {lightning.stopFunc(); lightning.drawFunc(50, 50);}
    }

    if (frameCount >= 450 & frameCount <= 600) {   //act IV mama duck defends her child
        mama.drawFunc(100, 100);
        duckling.drawFunc(40, 50);
        cloud.drawFunc(200, 100);

        if (frameCount == 510) {mama.playFunc();}
        if (frameCount > 510 & frameCount < 600){
            mama.drawFunc(300, 300);
            mama.x += random(-10, 10);
            mama.y += random(-10, 10);
        }
        if (frameCount == 600) {mama.stopFunc(); mama.x = 50; mama.y = 250;}
    }

    if (frameCount >= 600 & frameCount <= 750) {   //act V the attackers rejected
        if (frameCount == 600) {
            lightning.x = 250
        }

        mama.drawFunc(100, 100);
        duckling.drawFunc(40, 50);

        push();
        scale(tScale, tScale);
        cloud.drawFunc(200, 100);
        lightning.drawFunc(75, 75);
        pop();

        tScale = tScale * 0.95
    }

    if (frameCount >= 750 & frameCount <= 900) {   //act VI return to status quo
        mama.x = 50;
        mama.y = 250;
        mama.drawFunc(100, 100);

        duckling.x = 100;
        duckling.y = 275;
        duckling.drawFunc(40, 50);

        if (frameCount == 780) {mama.playFunc();
            mama.drawFunc(200, 200);}
        if (frameCount == 800) {mama.stopFunc();}

        if (frameCount == 810) {duckling.playFunc();
            duckling.drawFunc(80, 100);}
        if (frameCount == 820) {duckling.stopFunc();}

        if (frameCount == 840) {mama.playFunc();
            mama.drawFunc(200, 200);}
        if (frameCount == 900) {mama.stopFunc();}

        if (frameCount == 870) {duckling.playFunc();}
        if (frameCount > 870 & frameCount < 900) {duckling.drawFunc(200, 200);}
        if (frameCount == 900) {duckling.stopFunc();}
    }
}

function playOsc() {
    this.trem.start();
    this.osc.start();//plays the sound
}

function stopOsc() {
    this.osc.stop();
    this.trem.stop();//stops the sound
}

function drawImg(w, h) {    //draws the picture at the specified scale
    image(this.image, this.x, this.y, w, h);
}

Looking Outwards – 09

Tree Growth by Her Thorp, 2006

“Tree Growth” is a very simple piece that I find really intriguing. Like Alyssa mentions, the process of painting a tree comes down a lot to muscle memory and random brushstrokes to give it enough “noise” to be lifelike. This program does the exact same thing, replicating the process of painting or growing a tree through computational means.

The leaves even change color by the seasons! The piece, fundamentally, is simulating natural growth within the confines of code. By roughly replicating the natural process, the piece takes the first step towards growing a “real” digital tree.

-Robert

Looking Outwards 08

Blacki Migliozzi is a programmer, science communicator, experimental biotechnologist, and data visualizer for the New York Times, based out of New York City. They have worked on small-scale biotechnologies involving fungus, tardigrades, and CRISPR. More recently, after joining Bloomberg graphics & the New York Times, he has worked to communicate information – especially about climate change – to the public. Working with data across centuries and from all over the world he has created visualizations that clearly mark the precipice we have launched ourselves towards.

His Eyeo 2018 talk

His visualizations utilize clean, graphic lines and takes advantage of our natural tendency to notice outliers to bring the most alarming data to the forefront. Rather than being lost in a sea of data, his visualizations make the conclusion unquestionable.

-Robert

Project-07 Curves

sketch

//Robert Rice
//rdrice
//Section C

var x=[];       //bucket of x-coordinates for the vertices
var y=[];       //bucket of y-coordinates for the vertices
var a = 26.5;   //The scale of the curve
var n = 200;    //The curve's "resolution". How many vertexes are used to form the curves.
var q = 3;      //the number of petals

var rStart = 0;
var angle = 0;  //variable that contains the slow, global rotation
var dr = .1;    //speed of slow rotation

function setup() {
    createCanvas(480, 480);
    background(220);
    angleMode(DEGREES);  //me dum dum no like radians
}

function draw() {
    background(0);
    translate(width/2, height/2);   //sets center of the drawng to the center of the canvas
    stroke(255);
    strokeWeight(1);
    noFill();

    q = map(mouseY, 0, height, 3, 30, true);
    a = map(mouseX, 0, width, -26.5, 26.5, true);
    rStart = map(mouseY, 0, height, 0, 360);

    for (i= 0; i < n; i++) {    //calculates the base curve x and y-values
        let t = -10 + (20/n)*i  //calculates 't' values that are used to evaluate x and y components
        x[i] = 3*a*((t**2) - 3);
        y[i] = a*t*((t**2) - 3);
    }

    for (let i = 0; i < q; i+=1) {
        petal(0, 0, rStart+angle+i*(360/q));
    }

    angle = angle + dr  //drives the rotation of the drawing
}

function petal(v, w, r) {
    push();
    translate(v, w);
    rotate(r);

    beginShape()
    for (i=0; i < n; i++) {
        vertex(x[i], y[i]);
    }
    endShape();
    pop(); //forms a petal at v(x-coord) and w(y-coord) with rotation r based on the curve defined in line 25
}

Looking Outwards 07 – Notabilia

This week I’m discussing Moritz Stefaner’s “Notabilia”, a visual exploration of the most controversial corners of wikipedia. The diagram takes data from Wikipedia’s longest “deletion discussions”: arguments over whether to delete a page or not. Ranging from the absurd – “Object validity of Astrology” – to the hilarious – “List of similarities between Canada and New Zealand”.

Categorized into ‘the deleted’ and ‘the kept’, for whether the article in question was deleted or not, these threads visually show the rough, warped, messy work of distinguishing knowledge from misinformation. The artist managed to represent this highly abstract data in a comprehensible tangle, an impressive management of contradiction that makes it particularly interesting.

-Robert