Final Project: Reminders from the Room

finalproject-cb
//Caitlyn Baensch
//cbaensch@andrew.cmu.edu
//Section D

var shelf;
var bedroom;
var wind;
var steam;
var birds = [];
var fish = [];
var enter = false;
var phoneon = false;
var fadeg = 140;
var fadeb = 150;
var steamy = 266;
var steamdy = .5;

//load illustrations
function preload() {
    shelf = loadImage("https://i.imgur.com/FCmktLo.png");
    bedroom = loadImage("https://i.imgur.com/WVYB6XA.png");
    wind = loadImage("https://i.imgur.com/qjTV5Rs.png");
    steam = loadImage("https://i.imgur.com/k561c6E.png");
}

function setup() {
    createCanvas(600, 425);
    
    //setup for birds
    for(var i = 0; i < 6; i++) {
        birdsx = random(width);
        birds[i] = makeBirds(birdsx);
    }

    //setup for fish
    for (var i = 0; i < 12; i++) {
        fishx = random(325, 385);
        fish[i] = makeFish(fishx);
    }

    frameRate(12);
    angleMode(DEGREES);
}

function draw() {
    background(0);

    //show intro screen with instructions
    intro();

    //show the room when enter button is clicked
    if(enter == true) {
        room();
    }
}


//birds helper functions
//update the bird positions and display them
function displayBirds() {
    for (var i = 0; i < birds.length; i++) {
        birds[i].move();
        birds[i].draw();
    }
}

//remove birds that are off the canvas from the array
function removeBirds() {
    var birdsToKeep = [];
    for (var i = 0; i < birds.length; i++) {
        if (birds[i].x + birds[i].w > 0) {
            birdsToKeep.push(birds[i]);
        }
    }
    birds = birdsToKeep;
}

//with a small probability, add a new bird to end of the array
function addNewBirds() {
    var newBirdLikelihood = 0.12;
    if (random(0,1) < newBirdLikelihood) {
        birds.push(makeBirds(width+20));
    }
}

function moveBird() {
    this.x += this.speed;
}

function drawBird() {
    push();
    translate(this.x, this.y);
    fill(249, 228, 222);
    noStroke();
    triangle(0, 0, this.w, -this.h, this.w, 0);
    triangle(0, 0, this.w/2, -this.h, this.w/2, 0);
    pop();
}

//bird constructor (random location, size, and speed)
function makeBirds(birdsx) {
    var b = {x: birdsx, y: random(height),
            w: random(8, 16), h: random(4, 8),
            speed: random(-5, -10),
            move: moveBird,
            draw: drawBird
    }
    return b;
}


//fish helper functions
function displayFish() {
    for (var i=0; i<fish.length; i++) {
        fish[i].move();
        fish[i].draw();
    }
}

function moveFish() {
    this.x += this.dx;
    if (this.x > 385 || this.x < 325) {
        this.dx = -this.dx;
    }
}

function drawFish() {
    noStroke();
    fill(this.c);
    ellipse(this.x, this.y, this.w, this.h);
    if (this.dx < 0) {
        triangle(this.x+3, this.y, this.x+6, this.y-3, this.x+6, this.y+3);
    } else {
        triangle(this.x-3, this.y, this.x-6, this.y-3, this.x-6, this.y+3);
    }
}

//fish constructor (random location, size, speed, and color)
function makeFish(fishx) {
    var f = {x: fishx, y: random(195, 240),
        w: random(8, 12), h: random(3, 7),
        dx: random(-3, 3),
        c: color(random(100, 255), random(100, 255), random(100, 255)),
        move: moveFish,
        draw: drawFish
    }
    return f;
}


//wall clock function
function clock() {
    var hr = hour();
    var mn = minute();
    var sc = second();

    //second hand
    strokeWeight(2.15);
    var s = map(sc, 0, 60, 0, 360);
    push();
    rotate(s);
    stroke(255, 176, 148);
    line(0, 0, 16, 0);
    pop();

    //minute hand
    var m = map(mn, 0, 60, 0, 360);
    push();
    rotate(m);
    stroke(110, 160, 133);
    line(0, 0, 14, 0);
    pop();

    //hour hand
    var h = map(hr % 12, 0, 12, 0, 360);
    push();
    rotate(h);
    stroke(110, 160, 133);
    line(0, 0, 10, 0);
    pop();
}


//interactions for tip screens helper functions
//headphones: listen to music
function headphones() {
    if (mouseX > 22 & mouseX < 80 && mouseY > 150 && mouseY < 170) {
        tip('Listen to your favorite music.', 'Listening to music can help you focus, feel better, and relax.');
    }
}

//journals: reflect
function journals() {
    if (mouseX > 73 & mouseX < 102 && mouseY > 110 && mouseY < 122) {
        tip('Reflect on how you are feeling.', 'Try keeping a journal or taking some time each day to check in with yourself.');
    }
}

//tea: stay hydrated
function tea() {
    if (mouseX > 113 & mouseX < 134 && mouseY > 287 && mouseY < 308) {
        tip('Stay hydrated with water or a cup of hot tea.', 'Being well-hydrated improves sleep quality, cognition, and mood.');
    }
}

//phone: check in with friends
function phone() {
    if (mouseX > 137 & mouseX < 171 && mouseY > 303 && mouseY < 312) {
        tip('Check in with friends and family.', 'Catch up over text or phone call and see how everyone is doing.');
    }
}

//window: go for a walk
function win() {
    if (mouseX > 158.5 & mouseX < 268.5 && mouseY > 107 && mouseY < 217) {
        tip('Go outside for a 10-minute walk.', 'A walk can improve your mood and cognitive function as well as reduce stress.');
    }
}

//fish tank and cat: spend time with pets
function pets() {
    if ((mouseX > 313 & mouseX < 401 && mouseY > 187 && mouseY < 251) || (mouseX > 543 && mouseX < 594 && mouseY > 245 && mouseY < 274)) {
        tip('Spend time with pets.', 'Some quality time with your animal friends is sure to make you smile.');
    }
}

//books: read a book
function books() {
    if (mouseX > 325 & mouseX < 367 && mouseY > 278 && mouseY < 308) {
        tip('Get lost in a book.', 'Reading is the perfect way to unwind. Try it before bed instead of using your phone.');
    }
}

//yoga mat: stretch
function yoga() {
    if (mouseX > 318 & mouseX < 600 && mouseY > 378 && mouseY < 425) {
        tip('Take a break and stretch.', 'Doing yoga can help break up long periods of sitting at a desk and clear your mind.');
    }
}

//decorations: surround yourself with things that make you happy
function decoration() {
    if ((mouseX > 314 & mouseX < 378 && mouseY > 122 && mouseY < 174) || (mouseX > 468 && mouseX < 496 && mouseY > 182 && mouseY < 212)) {
        tip('Surround yourself with things you love.', 'Decorate your space with photos, art, and other meaningful items. Avoid clutter!');
    }
}

//clock: keep a daily routine
function time() {
    if (mouseX > 521 & mouseX < 572 && mouseY > 112 && mouseY < 163) {
        tip('Keep a daily routine.', 'Having a daily routine can reduce anxiety and create rhythm in your day.');
    }    
}


//text formatting for headers
function header() {
    textSize(24);
    textStyle(BOLD);
    textFont('Avenir');
}

//text formatting for body
function body() {
    textSize(14);
    textStyle(NORMAL);
    textFont('Avenir');
}


//tip screens formatting
function tip(line1, line2) {
    background(250, 227, 221, 230);
    fill(237, 122, 93);
    header();
    text(line1, 40, 250);
    body();     
    text(line2, 40, 285);
}


//intro opening screen with title and instructions
function intro() {
    background(255, 136, 108);
    fill(250, 227, 221);
    image(shelf, 40, 100, 286, 95);
    textSize(36);
    textStyle(BOLD);
    textFont('Avenir');
    text('Reminders from the Room', 40, 250);
    body();    
    text('Some quick tips for working from home during the pandemic.', 40, 285);
    text('Enter and hover over elements in the illustration to see relevant tips and info.', 40, 302);
    noStroke();
    fill(250, 227, 221);
    rect(456, 335, 100, 38, 38);
    fill(255, 136, 108);
    header();
    text('Enter', 476.5, 362);
    //if enter button is hovered over
    if (mouseX > 456 & mouseX < 555 && mouseY > 335 && mouseY < 373) {
        fill(244, 181, 161);
        rect(456, 335, 100, 38, 38);
        fill(237, 122, 93);
        header();
        text('Enter', 476.5, 362);
    }
}

//if enter button is pressed, enter the room
function mousePressed() {
    if (mouseX > 456 & mouseX < 555 && mouseY > 335 && mouseY < 373) {
        enter = true;
        room();
    }
}


//room environment
function room() {
    //landscape outside window
    image(wind, 146, 100, 125, 116);
    
    //birds flying outside window
    displayBirds();
    removeBirds();
    addNewBirds();

    //bedroom
    image(bedroom, 0, 0, width, height);

    //fish swimming in fish tank
    push();
    displayFish();
    fill(178, 190, 209, 50);
    rect(326, 187, 74, 56);
    pop();

    //wall clock by bed ticking
    push();
    translate(545, 138);
    rotate(-90);
    clock();
    pop();

    //phone screen new notifications
    push();
    noStroke();
    fill(37, 66, 52);
    quad(140, 303.5, 165, 303.5, 167, 308, 139, 308);
    if (frameCount % 90 == 0) {
        phoneon = true;
        if (phoneon == true) {
            fadeg = 240;
            fadeb = 240;
            fill(249, fadeg, fadeb);
            quad(140, 303.5, 165, 303.5, 167, 308, 139, 308);
        }
    } else {
        if (fadeg >= 140 & fadeb >= 150) {
            fadeg = fadeg - 3;
            fadeb = fadeb - 3;
            fill(249, fadeg, fadeb);
            quad(140, 303.5, 165, 303.5, 167, 308, 139, 308);
            phoneon = false;
        }
    }
    pop();

    //steam floats up over cup of tea
    image(steam, 115, steamy, 14, 24);
    steamy -= steamdy;
    if (steamy <= 257 || steamy > 267) {
        steamdy = -steamdy;
    }

    //show tip screens for user interaction
    headphones();
    journals();
    tea();
    phone();
    win();
    pets();
    books();
    yoga();
    decoration();
    time();
}

For my final project, I made an interactive illustration featuring tips for working from home during the pandemic. With hours spent locked up inside in endless Zoom meetings, I think that Zoom fatigue, a warped sense of time, and feelings of stress and anxiety are all common sentiments. I want to bring awareness to these challenges and offer simple strategies to combat fatigue and stress. I wanted my program to have a relaxing and calming feeling to it, so I chose a light, playful color palette for my illustrations as well as used an inviting typeface.

To interact with my program, follow the instructions on the intro screen. Click the “Enter” button to enter the room and explore the environment. Hover over different elements in the animated illustration to view relevant tips and information.

If I had more time, I might consider adding sound to some of the elements in the room. I would also maybe think about adding illustrations/animations to the advice screens and using p5.js to create patterns on objects or wallpaper.

Project 11: Generative Landscape

For my project, I decided to create a relaxing underwater scene. Although it was a bit challenging to figure out how to execute my ideas, I had fun making my landscape and adjusting properties to make it more interesting. To create my landscape, I combined concepts that we learned in the past, such as arrays, objects, loops, noise, images, and functions. I randomized properties such as the x/y positions, sizes, colors, and speeds of my objects.

landscape-cb
var terrain = [];
var coral;
var bubbles = [];
var fish = [];

var noiseParam = 0;
var noiseStep = 0.05;

function preload() {
    coral = loadImage("https://i.imgur.com/S5HGpZa.png");
}

function setup() {
    createCanvas(480, 300);
    //setup noise for terrain
    for(var i=0; i<=width/5; i++) {
        var n = noise(noiseParam);
        var value = map(n, 0, 1, 0, height);
        terrain.push(value);
        noiseParam += noiseStep;
    }
    //setup for fish
    for (var i = 0; i < 15; i++) {
        fishx = random(width);
        fish[i] = makeFish(fishx);
    }
    //setup for bubbles
    for (var i = 0; i < 10; i++) {
        bubblex = random(width);
        bubbley = random(height);
        bubbles[i] = makeBubble(bubblex, bubbley);
    }
    frameRate(10);
}

function draw() {
    background(0, 180, 200);

    noStroke();
    fill(0, 230, 255, 90);
    ellipse(240, 0, 600, 200);

    blueTerrain();
    
    updateAndDisplayFish();
    removeFish();
    addNewFish();
    
    displayBubbles();
}

//background terrain
function blueTerrain() {
    terrain.shift();
    var n = noise(noiseParam);
    var value = map(n, 0, 1, 0, height);
    terrain.push(value);
    noiseParam += noiseStep;
    
    //blue terrain
    noStroke();
    fill(0, 66, 115);
    beginShape();
    vertex(0, height);
    for(var i=0; i<width/4; i++) {
        vertex(i*5, terrain[i]);
        //placement of coral on terrain
        if(terrain[i] < terrain[i-1] & terrain[i] < terrain[i+1]) {
            drawCoral(i*5, terrain[i]);
        }
    }
    vertex(width, height);
    endShape(CLOSE);
}

//draws coral on terrain
function drawCoral(x, y) {
    imageMode(CENTER);
    image(coral, x, y-10, 65, 80);
}

//update the fish positions and display them
function updateAndDisplayFish() {
    for (var i = 0; i < fish.length; i++) {
        fish[i].move();
        fish[i].draw();
    }
}

//remove fish that are off the canvas from the array
function removeFish() {
    var fishToKeep = [];
    for (var i = 0; i < fish.length; i++) {
        if (fish[i].x + fish[i].w > 0) {
            fishToKeep.push(fish[i]);
        }
    }
    fish = fishToKeep;
}

//with a small probability, add a new fish to end of the array
function addNewFish() {
    var newFishLikelihood = 0.3;
    if (random(0,1) < newFishLikelihood) {
        fish.push(makeFish(width+20));
    }
}

function moveFish() {
    this.x += this.speed;
}

function drawFish() {
    push();
    translate(this.x, this.y);
    fill(this.color);
    ellipse(0, 0, this.w, this.h);
    strokeWeight(1.5);
    stroke(240);
    fill(50);
    ellipse(-15, -4, 8, 8);
    noStroke();
    fill(this.fincolor);
    triangle(0, -4, 0, 4, 15, 0);
    noFill();
    push();
    fill(this.color);
    triangle(this.w/2+20, -8, this.w/2+20, 8, (this.w/2)-2, 0);
    pop();
    pop();
}

//fish constructor
function makeFish(fishx) {
    var f = {x: fishx, y: random(height),
            w: random(40, 80), h: random(10, 45),
            color: color(random(100, 255), random(100, 255), random(100, 255)),
            fincolor: color(random(50, 200), random(50, 200), random(50, 200)),
            speed: random(-10, -20),
            move: moveFish,
            draw: drawFish
    }
    return f;
}

function displayBubbles() {
    for (var i = 0; i < bubbles.length; i++) {
        bubbles[i].move();
        bubbles[i].draw();
    }
}

//bubbles float upwards
function moveBubbles() {
    this.x += this.speed;
    this.y += this.speed;
    if (this.x <= 0) {
        this.x = width;
    }
    if (this.y <= 0) {
        this.y = height;
    }
}

function drawBubbles() {
    push();
    strokeWeight(1);
    stroke(255, 255, 255, 80);
    fill(100, 255, 255, 60);
    ellipse(this.x, this.y, this.size, this.size);
    noFill();
    strokeWeight(2);
    arc(this.x - this.size/12, this.y - this.size/12, 15, 15, PI, PI + HALF_PI);
    pop();
}

//bubbles constructor
function makeBubble(bubblex, bubbley) {
    var b = {x: bubblex, y: bubbley,
            size: random(20, 40),
            speed: random(-1, -6),
            move: moveBubbles,
            draw: drawBubbles
    }
    return b;
}

LO 11 – A Focus on Women Practitioners

When looking at the list of women in new media arts, I came across Camille Utterback and was intrigued by her project Text Rain (1990), which I remembered seeing last year at the Pittsburgh Children’s Museum. It is an interactive installation where participants use physical movement to play with digital falling letters. Participants stand in front of a large projection screen where they see a mirrored video projection of themselves, combined with an animation of falling letters. Similar to rain and snow, the falling letters land/accumulate on participant’s heads and arms as well as respond to their motions. I find it fascinating how this hybrid installation transforms the museum experience, inviting visitors to engage with the work in an immersive, thoughtful way.

Camille Utterback’s work explores the aesthetic and experiential potential of connecting computational systems to human movement. Utterback combines sensing and display technologies with the custom software she writes to produce her work. Architectural-scale projections, custom LED lighting, and intimate sculptures with embedded screens are just a few examples of the broad range of media which Utterback works with. Camille Utterback holds a BA in Art from Williams College, and a Masters from NYU’s Tisch School of the Arts.

video about Text Rain

Project 10: Sonic Sketch

For my project, I wanted to create a composition based on an illustration idea I had, so I created an illustration first in Illustrator and then exported the layers as images. In my project, I was able to practice using images and sound together and ended up using 7 images and 5 sounds total (meow, car, bicycle, wind, chirping). I wanted to make part of the sketch interactive, so I made the sun follow the user’s mouse. My story is as follows:

It is fall and the sun is setting. A cat sits on the windowsill and meows, watching the traffic outside. A car passes by, then a bicycle. The wind blows and leaves rustle. Birds chirp in the distance.

Illustrator drawing
sketch-cb
//Storyline: A cat sits on the windowsill and meows, watching
//traffic outside. A car passes by, then a bicycle. It is late
//fall and the sun is setting. Birds chirp in the distance.

//images
var cat;
var wind;
var leaf;
var bike;
var car;
var bird;
var mountains;

//sounds
var meow;
var engine;
var spinning;
var windblows;
var chirping;

//moving distances
var dx = 0;
var dy = 0;

function preload() {
    //loads images
    cat = loadImage("https://i.imgur.com/4Jqrrll.png");
    wind = loadImage("https://i.imgur.com/jYEWld7.png");
    leaf = loadImage("https://i.imgur.com/1rd8ozl.png");
    bike = loadImage("https://i.imgur.com/u3DeUeL.png");
    car = loadImage("https://i.imgur.com/4F1DaeZ.png");
    bird = loadImage("https://i.imgur.com/aEcelIZ.png");
    mountains = loadImage("https://i.imgur.com/kdIC817.png");

    //loads sounds
    meow = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/meow.wav");
    engine = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/engine.wav");
    spinning = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/spinning.wav");
    windblows = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/windblows.wav");
    chirping = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/chirping.wav");
}

function setup() {
    createCanvas(400, 400);
    frameRate(1);
    useSound();
    cat.loadPixels();
    wind.loadPixels();
    leaf.loadPixels();
    bike.loadPixels();
    car.loadPixels();
    bird.loadPixels();
    mountains.loadPixels();
}

function soundSetup() { 
    //setup for audio generation
    meow.setVolume(1);
    engine.setVolume(0.2);
    spinning.setVolume(0.5);
    windblows.setVolume(0.5);
    chirping.setVolume(0.75);
}

function draw() {
    background(204, 121, 84);

    //plays sounds at correct times
    switch (frameCount) {
        case 4: meow.play(); break;
        case 7: engine.play(); break;
        case 12: spinning.play(); break;
        case 18: windblows.play(); break;
        case 23: chirping.play(); break;
    }
    
    //sky
    noStroke();
    fill(151, 166, 221);
    ellipse(200, 180, 287);
    
    //sun and mountains
    fill(242, 113, 73);
    ellipse(mouseX, mouseY, 60);
    image(mountains, 57, 194);

    //car drives by
    if (frameCount >= 6 & frameCount < 13) {
        image(car, 240-dx, 235);
        dx+=25;
    }
    //bicycle passes by
    if (frameCount >= 11 & frameCount < 20) {
        image(bike, 15+dx, 240);
        dx+=30;
    }
    //wind blows leaves
    if (frameCount >= 17 & frameCount < 22) {
        image(leaf, 80, 80+dy);
        image(leaf, 280, 200+dy);
        dy+=40;
    }
    //birds fly in distance
    if (frameCount >= 23 & frameCount < 27) {
        image(bird, 216, 187);
        image(bird, 230, 175);
        image(bird, 232, 150);
        image(bird, 150, 155);
    }

    //window and cat
    image(wind, 0, 0);
    image(cat, 80, 230);
}

LO 10 – Computer Music

For this week’s Looking Outwards, I decided to take a look at the work of British singer-songwriter and audio engineer Imogen Heap. I specifically looked at her “MI.MU gloves” (2014) and the various ways that she uses this innovative computational musical instrument to compose and perform her music. MI.MU gloves are a wearable instrument that utilizes mapping technologies to translate hand movements into musical compositions. For instance, specific hand movements trigger changes in pitch, filters, and scales. The technical elements of the gloves include flex sensors, orientation sensors, a wifi device, and software that uses MIDI and OSC to coordinate movements and sounds.

I find this project fascinating and admire Heap’s work because of how revolutionary it is in bridging the gap between the analog and the digital through creating a more natural relationship between the artist and the computer. The gloves completely transform musical performance and experience, allowing artists to incorporate sound and movement seamlessly. They are also somewhat accessible, as they are available for purchase online, and many musical artists have used the gloves in their music/performances.

MI.MU gloves
how MI.MU gloves were developed
Imogen Heap performance; at 9:05, she describes and gives a demo with the gloves

Project 9: Portrait

portrait-cb
var myImg;

function preload() {
    var ImgURL = "https://i.imgur.com/6nqYPHi.jpg";
    myImg = loadImage(ImgURL);
}

function setup() {
    createCanvas(400, 400);
    background(0);
    myImg.resize(400, 400);
    myImg.loadPixels();
}

function draw() {
    //randomize positions of pixels and get color from image
    var x = floor(random(myImg.width));
    var y = floor(random(myImg.height));
    fill(myImg.get(x, y));
    pixel(x, y);

    //also draw pixels following mouse movement
    fill(myImg.get(mouseX, mouseY));
    pixel(mouseX, mouseY);
}

function pixel(x, y) {
    //custom star pixel
    push();
    noStroke();
    translate(x, y);
    //add random scale and rotation to each pixel drawn
    scale(random(.15, 1.85));
    rotate(random(radians(-90, 90)));
    beginShape();
    vertex(0, -5.39);
    vertex(1.55, -2.26);
    vertex(5, -1.75);
    vertex(2.5, 0.68);
    vertex(3.09, 4.12);
    vertex(0, 2.5);
    vertex(-3.09, 4.12);
    vertex(-2.5, 0.68);
    vertex(-5, -1.75);
    vertex(-1.55, -2.26);
    endShape(CLOSE);
    pop();
}

function mousePressed() {
    //reset the canvas to random color
    background(color(random(255), random(255), random(255)));
}

For my project, I chose a photo that my friend took of me at an art gallery installation called “Paraiso” in New York City. The installation consisted of a room with mirrors and many strings of stars hanging from the ceiling. I enjoyed seeing this artwork and wanted to reflect the stars and range of colors in the photo in my portrait, so I practiced using custom shapes to create a star-shaped pixel. To make the portrait more dynamic, I made the pixels to be randomly scaled and rotated. I also coded it so that the star pixels are drawn following the user’s mouse position. When the user clicks on the canvas, it resets to a random color.

LO 9 – On Looking Outwards

For this week’s LO, I looked at Holly’s Looking Outwards post from week 5 on 3D computer graphics. In this post, she examined the work of 3D designer Roman Bratschi, studying a piece from his “NONSENSE IN 3D N°191-200” collection from 2018. Similar to Holly, I am drawn to Bratschi’s work because of his highly detailed, realistic renders of complex textures. His strong sense of color is evident in his work, as he utilizes sophisticated color palettes to enhance his visual narratives. In addition to the elements that Holly pointed out in her post, I think that the compositions of his pieces play a significant role in their success, as they are quite dynamic and invite viewers to examine the intricacies of each render.

To learn more about Bratschi, I visited his website, where I read about his career path and past work. I was really intrigued by the way that although his work is extremely clean and polished, he is able to effectively manipulate texture, color, and composition to convey a range of emotions and narratives across the different pieces in his portfolio. While some renders come across as very elegant and satisfying, others feel dark and unsettling.

LO 8 – The Creative Practice of An Individual

Lauren McCarthy is an American artist and computer programmer whose work focuses on the impact of surveillance, automation, and network culture on social relationships. She is known for her performance, artificial intelligence, and programming/computer-based interaction work. McCarthy created p5.js, the version of JavaScript that we work with in class. She graduated from MIT, where she studied computer science and art and design.

McCarthy asks deep, thought-provoking questions in her work, such as “What is the purpose of art?” and “What is the relationship between attention and surveillance?” One of her projects that I find most intriguing, which I learned about in her Eyeo talk, was “Follower.” “Follower” is a service that provides a real-life follower for a day; you sign up, get an app, and wait to be matched, not knowing what will happen. Your assigned follower tracks you for a day (out of sight, but within your awareness) and takes a photo of you. While it seems very intrusive and scary to have a real-life follower, I think that this project raises some interesting questions and points to the complexities of human connection and desires.

Below I have included McCarthy’s Eyeo talk from 2019 as well as a video/images of her project “Follower.”

Lauren McCarthy’s 2019 Eyeo Video
“Follower”
“Follower” app interface

Project 7: Curves

curves cb
//global variables
var nPoints = 1000;
var angle = 0;

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

function draw() {
    background(mouseY, 100, mouseX); //change background color
    //draw 2 sets of 36 hypotrochoids 
    for (var x = 80; x <= 400; x += 64) {
        for (var y = 80; y <= 400; y += 64) {
            push();
            translate(x, y);
            drawHypotrochoid1();
            drawHypotrochoid2();
            pop();
        }
    }
}

function drawHypotrochoid1() {
    var a = map(mouseX, 0, 480, 0, 80); //radius of outside circle
    var b = map(mouseX, 0, 480, 0, 20); //radius of inside circle
    var h = map(mouseY, 0, 480, 0, 40); //point distance from center of inner circle

    strokeWeight(.5);
    stroke(mouseX, mouseY, 100); //change stroke color
    noFill();
    beginShape(); //create hypotrochoid
    for (var i=0; i<nPoints; i++) {
        var angle = map(i, 0, 100, 0, TWO_PI);
        x = (a-b) * cos(angle) + h * cos(((a-b)/b) * angle);
        y = (a-b) * sin(angle) - h * sin(((a-b)/b) * angle);
        vertex(x, y);
    }
    endShape();
}

function drawHypotrochoid2() {
    var a = map(mouseX, 0, 480, 2, 80); //radius of outside circle
    var b = map(mouseX, 0, 480, 2, 20); //radius of inside circle
    var h = map(mouseY, 0, 480, 2, 40); //point distance from center of inner circle

    strokeWeight(.35);
    stroke(mouseX, mouseX, mouseY); //change stroke color
    noFill();
    beginShape(); //create hypotrochoid
    for (var i=0; i<nPoints; i++) {
        var angle = map(i, 0, 100, 0, TWO_PI);
        x = (a-b) * cos(angle) + h * cos(((a-b)/b) * angle);
        y = (a-b) * sin(angle) - h * sin(((a-b)/b) * angle);
        vertex(x, y);
    }
    endShape();
}

After exploring the WolframMathWorld site, I found hypotrochoids and thought that they were very dynamic and interesting. I decided to create my project with two sets of overlapping hypotrochoids to create a field of growing flower-like shapes. To make the composition interactive, I coded the mouse position to control the variables and colors of the hypotrochoids as well as the background color.

top left, top right, bottom left, bottom right
other screenshots

LO 7 – Information Visualization

For this week’s LO, I decided to take a look at Periscopic‘s AgEvidence project (Dr. Lesley Atwood, Dr. Stephen Wood, Periscopic), which includes 16,000+ data points visualizing the impact of conservation agriculture in the US.

This project is quite inspirational not only because of the massive scale and data collected/visualized but also the impact of the way that the designers have presented data. The Periscopic data visualization firm collaborated with The Nature Conservancy on this project to help researchers from the Science for Nature and People Partnership team to synthesize and illustrate findings from over 40 years of agriculture research. AgEvidence displays the effects of conservation practices such as reduced tillage, early-season pest management, and cover crops on the environment and food production, as well as distinguishes research-rich and -sparse areas. I believe that the researchers first extracted and processed the data, then using percentage changes and nested levels to computationally visualize it.

I appreciate that the creators included key insights to highlight patterns in the data and make it more accessible to users. Moreover, they have allowed for easy data access and transparency through options to download filtered/holistic data sets so that users can discover even more nuances.

AgEvidence interactive tool: observations and map of study locations
detailed insights that make data more accessible