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
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);
}
//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;
}
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.
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
]]>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
]]>This is a story about a duck, a duckling, a cloud, and lightning bolt.
//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);
}
For this portrait I wanted the snaking lines to help give the portrait depth perception. Over time, as more and more tiny lines are added, the portrait slowly evolves into an increasingly recognizable face.
The photo I used is the famous “Migrant Mother”, taken by Dorothea Lange in 1936.
]]>“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
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 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
]]>//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
}
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
]]>