breep-LookingOutwards03

The eyewriter is a collaborative project that allows individuals who are paralyzed but still retain full brain function and eye movement to draw with the movement of their eyes. Initially teaming up with LA graffiti artist TEMPTONE, who was diagnosed with ALS in 2003, the project aimed to get the artist to be create again despite his condition. I love how the vast respect for this singular artist and the empathy for his condition inspires a hugely impactful project.

I find this project exceptionally praise worthy for its aim to get those who have been given a horrible card in life to fully realize their creative desires and share their creativity with the world. Along with this, I find the parallels between the emotional range that eyes can present in relation to the creation of projects entirely with eyes vastly intriguing its potential. This is one element of the project that I wish was explored more, but given the circumstance and what the EyeWriter accomplishes that is a very minor aspect. The notion of turning this project into a wide bracing international framework is also hugely admirable, sharing this wonderful technology with the world. I find that a-lot of the time we expect the viewer to be able to interact with a work of interactive art, but in this case the viewer interacts with the work through a larger social context which amazed me about this work.

 

breep-clock

Clock:

 

Using The Dot For Every Second In The Day as a launching platform, I wanted to create a clock that helped/reminded the user to optimize their time, through reminding them about the amount they have left. I imagine it to be permanently on the user, and I see it primarily in situ as a digital tattoo which acts as a constant moving reminder (part of me also hates the clunkiness of watches so the unburdened element of a clock tattoo also resonates with me strongly).

While I like the minimalist aesthetic of the clock in terms of its readability, I also feel that a greater graphic quality/style to it would act to help with the element of constantly being reminded as it's quality of being pleasurable to look at would certainly factor into that. I also feel that greater individuality/personally connected tasks would help with a more unique individual experience with the clock.

GIF:

Images:

 

 

Sketches:

 
var prevSec;
var millisRolloverTime;
var loopRunning; 
var button;
var ClockMode = false; 
var AdviceMode = false;
var Width = 800; 
var Height = 300; 
 
var monthAmountTable = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] 
 
var minutesIndex = 0; 
var hoursIndex = 0; 
var daysIndex = 0; 
var monthsIndex = 0;
var yearsIndex = 0; 
var decadesIndex = 0; 
var lifetimesIndex = 0; 
 
var minuteActs = ["Stretching\nyour legs",
                  "Telling\nyour parents\nyou love\nthem", 
                  "Messaging\na friend", 
                  "Asking\nthat person\nout",
                  "Brainstorming\nthat idea", 
                  "Taking\nsome time\nfor yourself",
                  "Sketching\na stranger"] 
 
var hourActs = ["Going\n to the\ngym", 
                "Grabbing\nfood with\na friend"]
 
var dayActs = ["Finishing\na piece\nof work", 
               "Getting\nGroceries", 
               "Making a new playlist", 
               "Watching\n a film"]
 
var monthActs = ["Making\na Website", 
                 "Getting\nover that\nbreakup", 
                 "Finding a new hobby"] 
 
var yearActs = ["Learning\n10 songs\non an\ninstrument", 
                "Writing\na book"] 
 
var decadeActs = ["Working\non your\nmental health", 
                  "Forgiving\nyour parents"] 
 
var lifetimeActs = ["Raising\nHell", 
                    "Living a\nfulfilled life"] 
 
var lastChangeSeconds = 0; 
var waitTimeSeconds = 60000; 
 
var lastChangeMinutes = 0;
var waitTimeMinutes = 60; 
 
var lastChangeHours = 0; 
var waitTimeHours = 24; 
 
var lastChangeMonths = 0; 
 
var lastChangeYears = 0; 
var waitTimeYears = 12; 
 
var lastChangeDecade = 0; 
var waitTimeDecades = 10; 
 
//--------------------------
function setup() {
  createCanvas(800, 300);
  background(0); 
  millisRolloverTime = 0;
 
  loopRunning = false; 
  getInput(); 
	var waitTimeMonths = monthAmountTable[month() -1]; 
}
 
//-------------------------
 
function getInput() { 
 
  input = createInput();
  input.position((Width/2) - 125, Height/2);
 
  button = createButton('Your Time Left');
  button.position(input.x + input.width + 20, Height/2);
 
 
  fill(255); 
  textFont("Futura"); 
  textAlign(CENTER);
  textSize(25);
  text("Your Age in this lifetime", Width/2, Height/2 - 50);  
 
 
  button.mousePressed(modeChange); 
}
 
function modeChange(){
  ClockMode = true;}
 
function keyPressed(){ 
  if (ClockMode == true && keyCode == RIGHT_ARROW) {
    ClockMode = false; 
    AdviceMode = true;}
 
  else if (AdviceMode == true && keyCode == LEFT_ARROW){
    AdviceMode = false;
    ClockMode = true;}
}
 
function changeIndex(){ 
  if (minutesIndex < 4){ 
      minutesIndex += 1}
  else if ( minutesIndex > 4){
      minutesIndex = 0;}
 
} 
 
//--------------------------
function draw() {
 
  if (ClockMode == true) { 
 
  button.remove();
  input.remove();
 
 
  background(0);
 
  var monthKeyTable = [0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6] 
  var dayOfWeekTable = [6, 7, 0, 1, 2, 3, 4, 5] 
 
 
 
  var weekDay = ((year() % 100) / 4 ) - (((year() % 100) / 4 ) % 1) + day() + monthKeyTable[month()] + 6 + 18
 
  var LifeExpectancy =  72.74 - input.value(); 
 
 
 
  var De = 10 / (year() % 10);  
  var Y = (month() / 12);
  var Mo = (day() / monthAmountTable[month() -1]); 
  var W = (weekDay / 7) % 1 ;
  var D = ((hour()+1) / 24); 
  var H = hour();
  var M = minute();
  var S = second();
 
 
 
  // Reckon the current millisecond, 
  // particularly if the second has rolled over.
  // Note that this is more correct than using millis()%1000;
  if (prevSec != S) {
    millisRolloverTime = millis();
  }
  prevSec = S;
  var mils = floor(millis() - millisRolloverTime);
 
  noStroke();
  textAlign(CENTER);
  textSize(15); 
  fill(255); ///////////////////////////////////
  text("seconds left", (56.25 + 25), 65); 
  text("in this minute", (56.25 + 25), 85);   
  text( 60 - second(), (56.25 + 25), 45); 
 
 
  text("minutes left", (56.25 + 25) * 2 + 25, 65); 
  text("in this hour", (56.25 + 25) * 2 + 25, 85); 
  text( 60 - minute(), (56.25 + 25) * 2 + 25, 45); 
 
 
  text("hours left", (56.25 + 25) * 3 + 50, 65); 
  text("in this day", (56.25 + 25) * 3 + 50, 85); 
  text(24 - hour() - 1 , (56.25 + 25) * 3 + 50, 45); 
 
  text("days left", (56.25 + 25) * 4 + 75, 65); 
  text("in this month", (56.25 + 25) * 4 + 75, 85);
  text((monthAmountTable[month() -1] - day()) + 1, (56.25 + 25) * 4 + 75, 45); 
 
 
  text("months left", (56.25 + 25) * 5 + 100, 65);
  text("in this year", (56.25 + 25) * 5 + 100, 85); 
  text((12 - month())+ 1, (56.25 + 25) * 5 + 100, 45); 
 
  text("years left", (56.25 + 25) * 6 + 125, 65); 
  text("in this decade", (56.25 + 25) * 6 + 125, 85); 
  text((10 / (year() % 10)), (56.25 + 25) * 6 + 125, 45); 
 
 
  text("years left\n" + "on average", (56.25 + 25) * 7 + 150, 65); 
  text(round(72.74 - input.value()) - 1, (56.25 + 25) * 7 + 150, 45); 
 
  text("press right key to get some suggestions to fill this time", Width/2, Height - 15); 
 
 
  var lifeExpectancyBarWidth = map(LifeExpectancy, 72.74, 0, 0, 160); 
 
  var decadeBarWidth = map(De, 10, 0, 0, 160); 
 
  var yearBarWidth = map(Y, 1/12, 1, 0, 160); 
 
  var monthBarWidth = map(Mo, 0, 1, 0, 160); 
 
  var dayBarWidth = map(D, (1/24), 1, 0, 160); 
 
  var hourBarWidth   = map(H, 0, 23, 0, 160);
 
  var minuteBarWidth = map(M, 0, 59, 0, 160);
 
  var secondBarWidth = map(S, 0, 59, 0, 160);
 
  // Make a bar which *smoothly* interpolates across 1 minute.
  // We calculate a version that goes from 0...60, 
  // but with a fractional remainder:
  var secondsWithFraction = S + (mils / 1000.0);
  var secondsWithNoFraction = S;
  var secondBarWidthChunky = map(secondsWithNoFraction, 0, 60, 0, width);
  var secondBarWidthSmooth = map(secondsWithFraction,   0, 60, 0, 160);
 
  fill(150); 
  rect((56.25 * 3) + (50 * 2), 100, 50, 160);      //h
  rect((56.25 * 2) + 50, 100, 50, 160);   //m
  rect(56.25, 100, 50,  160); //s
 
 
  rect((56.25 * 4) + (50 * 3), 100, 50, 160); 
  rect((56.25 * 5) + (50 * 4), 100, 50, 160); 
  rect( (56.25 * 6) + (50 * 5), 100, 50, 160); 
 
  rect((56.25 * 7) + (50 * 6), 100, 50, 160);     
 
 
  fill(170, 1, 20);
  rect((56.25 * 3) + (50 * 2), 100, 50, 160 - hourBarWidth);      //h
  rect((56.25 * 2) + 50, 100, 50, 160 - minuteBarWidth);   //m
  rect(56.25, 100, 50,  160 - secondBarWidthSmooth); //s
 
 
  rect((56.25 * 4) + (50 * 3), 100, 50, 160 - monthBarWidth); 
  rect((56.25 * 5) + (50 * 4), 100, 50, 160 - yearBarWidth); 
  rect( (56.25 * 6) + (50 * 5), 100, 50, 160 - decadeBarWidth); 
 
  rect((56.25 * 7) + (50 * 6), 100, 50, 160 - lifeExpectancyBarWidth); 
 
 
  }
 
  else if ( AdviceMode == true){
 
 
 
  var nowSeconds = millis() 
  var elapsedSeconds = nowSeconds - lastChangeSeconds; 
 
  var nowMinutes = minute(); 
  var elapsedMinutes = nowMinutes - lastChangeMinutes; 
 
  var nowHours = hour();
  var elapsedHours = nowHours - lastChangeHours; 
 
  var nowMonths = month();
  var elapsedMonths = nowMonths - lastChangeMonths; 
 
  var nowYears = year(); 
  var elapsedYears = nowYears - lastChangeYears; 
 
  var nowDecade = year() % 10;
  var elapsedDecades = nowDecade - lastChangeDecade; 
 
 
  if (elapsedSeconds > waitTimeSeconds){
    lastChangeSeconds = nowSeconds; 
    minutesIndex = (minutesIndex + 1) % minuteActs.length;}
 
  if (elapsedMinutes > waitTimeMinutes){
    lastChangeMinutes = nowMinutes; 
    hoursIndex = (hoursIndex + 1) % hourActs.length;}
 
  if (elapsedHours > waitTimeHours){
    lastChangeMinutes = nowMinutes; 
    hoursIndex = (hoursIndex + 1) % hourActs.length;}  
 
 
  fill(0); 
  rect(0, 0, 800, 800); 
 
  noStroke();
  textAlign(CENTER);
  textSize(15); 
  fill(255); 
 
 
  text(minuteActs[minutesIndex], (56.25 + 25), Height * (2/5)); 
  text("in this minute", (56.25 + 25), Height -65);   
  //text( 60 - second(), (56.25 + 25), 45); 
 
 
  text(hourActs[hoursIndex], (56.25 + 25) * 2 + 25, Height * (2/5)); 
  text("in this hour", (56.25 + 25) * 2 + 25, Height - 65); 
  //text( 60 - minute(), (56.25 + 25) * 2 + 25, 45); 
 
 
  text(dayActs[daysIndex], (56.25 + 25) * 3 + 50, Height * (2/5));
  text("in this day", (56.25 + 25) * 3 + 50, Height -65); 
  //text(24 - hour() - 1 , (56.25 + 25) * 3 + 50, 45); 
 
  text("try", (56.25 + 25) * 4 + 75, 45); 
 
 
  text(monthActs[monthsIndex], (56.25 + 25) * 4 + 75, Height * (2/5)); 
  text("in this month", (56.25 + 25) * 4 + 75, Height - 65);
  //text((monthAmountTable[month() -1] - day()) + 1, (56.25 + 25) * 4 + 75, 45); 
 
 
  text(yearActs[yearsIndex], (56.25 + 25) * 5 + 100, Height * (2/5)); 
  text("in this year", (56.25 + 25) * 5 + 100, Height - 65); 
  //text((12 - month())+ 1, (56.25 + 25) * 5 + 100, 45); 
 
  text(decadeActs[decadesIndex], (56.25 + 25) * 6 + 125, Height * (2/5));
  text("in this decade", (56.25 + 25) * 6 + 125, Height - 65); 
  //text(10 / (year() % 10), (56.25 + 25) * 6 + 125, 45); 
 
 
  text(lifetimeActs[lifetimesIndex], (56.25 + 25) * 7 + 150, Height * (2/5)); 
  text("in this lifetime", (56.25 + 25) * 7 + 150, Height - 65); 
  //text(round(72.74 - input.value()) - 1, (56.25 + 25) * 7 + 150, 45);   
 
  text("press left key to look at your time", Width/2, Height - 15);  
  } 
}

 

 

breep-LookingOutwards02

I decided to talk about The Binding Of Isaac as my choice of generative art, mostly because its one of the few generated games that I have found myself play over and over and over again, and with my general propensity to not replay games I find this significant to me.

The game follows the story of Isaac, a young boy whose mother is asked by God to sacrifice him as a test of her faith. Upon trying to murder him, Isaac flees to their basement where he must fight for his life against a cohort of monster's and manifestations of traditionally evil elements that faith challenges.  It is this element that I so admire about this work, the complete freedom to enjoy it's gameplay or read into the dense subplot about conflicts over religion and how evil manifests itself within the stereotypes we associate with certain qualities of character (eg Greed, Envy etc).

The floors are generated from a library of rooms, with certain fixed rooms (like the starting room and the boss fight room) acting as cruxes for the rest of the rooms. What makes the game so replay are the endless combinations of items, enemies and rooms which makes every individual room a unique experience, as well as each instance of the game. The system as a whole is very ordered, as multiple replays will make apparent, but its the chaotic nature of every individual room that really makes the game.  It was heavily inspired by the first Legend of Zelda, with the gameplay following a very similar format. The art style of the game stands bold as well, with the combination of the algorithm and the design of the rooms combining to build the overall experience.

Website

Creation: Edmund McMillen and Florian Himsl, initially released in 2011, with a remake (The Binding of Isaac: Rebirth) in 2014

 

 

 

 

breep-Reading03

I find my relationship to technology and art somewhat tenuous. I came into CMU deeply interested in art, and not so much technology and as I have been here those two have swapped, and are swapping back again. For awhile I've viewed technology as a toolkit for art separating the two, but being at CMU has made be realise that in this niche of combining the two, they are one and the same. Advances in technology are advances in art, and art advances technology through experimentation. I compare this to the inception of ideas. Our clock project provides the same baseline, with the same technology available to all of us who undertake it, and yet each of us find new ways to piece together what we are given into entirely different and new manifestations.

However, I've also been struggling with the novelty of what we make. This concept of the first word art really jars with me. I fully accept and acknowledge the experimentation, but at the same time my conception of art/my interest in art history is framed by completed works that leave an impact on the timeline of art. But I also recognize that each novel thing we make leaves an impact on us as creators, something I forget far too often as I make work for assignments rather than for growing myself as an artist.

breep-Scope

My design largely stemmed off the idea of conveying circles within circles. I wanted to show how the movement of the black circle within the larger unit conveys the movement of a larger black circle that is made by the sum of its parts. This was a notion that I wanted to explore in my gif, but never really got round to integrating it, so this was a kind of nod to that idea.

/*
// Template for KidzLabs/4M/Toysmith Animation Praxinoscope
// https://www.amazon.com/4M-3474-Animation-Praxinoscope/dp/B000P02HYC
// https://www.walmart.com/ip/Animation-Praxinoscope-Science-Kits-by-Toysmith-3474/45681503
// Developed for p5.js, September 2018 * Golan Levin 
 
*/
 
 
 
var inch = 72.0; 
var diamArtInner = inch * 1.50; 
var diamArtOuter = inch * 4.80; 
var diamCutInner = inch * 1.41; 
var diamCutOuter = inch * 4.875; 
var holeDy = inch * 0.23;
var holeDx = inch * 0.20;
var holeD = inch * 0.1;
 
var nFrames = 10; 
var myFrameCount = 0;
var exportFrameCount = 0; 
 
var bAnimate = true;
var bExportFrameImages = false;
var bRecordingSinglePNG = false;
 
//-------------------------------------------------------
function setup() {
  createCanvas(792, 612); // 11x8.5" at 72DPI
  frameRate(20);
  smooth();
} 
 
 
//-------------------------------------------------------
function draw() {
  background(240); 
 
  // Do all the drawing. 
  push(); 
  translate(width/2, height/2);
  drawCutLines(); 
  drawGuides(); 
  drawAllFrames();
  pop();
 
 
  if (bExportFrameImages){
    // Note that myFrameCount is incremented elsewhere.
    var filename = "myZoetrope_" + nf(myFrameCount,2) + ".png";
    saveCanvas(filename, 'png');
    if (myFrameCount &gt;= nFrames){
      bExportFrameImages = false;
    }
  }
 
 
  if (bRecordingSinglePNG) {
    saveCanvas('myPraxinoscope.png', 'png');
    bRecordingSinglePNG = false;
  }
}
 
 
//-------------------------------------------------------
function keyPressed() {
  switch (key) {
  case ' ': 
    // Press spacebar to pause/unpause the animation. 
    bAnimate = !bAnimate;
    break;
 
  case 'p':
    case 'P':
      // Press 'p' to export a single PNG for the Zoetrope. 
      // Note: This is for 17x11" paper! 
      // Be sure to print at 100%!
      bRecordingSinglePNG = true;
      break;
 
    case 'f':
    case 'F':
      // Press 'f' to export multiple frames 
      // (in order to make an animated .GIF)
      // such as with http://gifmaker.me/
      myFrameCount = 0;
      exportFrameCount = 0;
      bExportFrameImages = true;
      bAnimate = true;
      break;
  }
}
 
//-------------------------------------------------------
function drawCutLines() {
  fill(0); 
  textAlign(CENTER, BOTTOM); 
  text("Praxinoscope Template", 0, 0-diamCutOuter/2-6); 
 
  stroke(0); 
  strokeWeight(1.0);
 
  noFill(); 
  if (!bRecordingSinglePNG) {
    fill(255); 
  }
  ellipse(0, 0, diamCutOuter, diamCutOuter);
 
  noFill(); 
  if (!bRecordingSinglePNG) {
    fill(240); 
  }
  ellipse(0, 0, diamCutInner, diamCutInner);
 
  noFill(); 
  ellipse(diamCutOuter/2 - holeDx, 0-holeDy, holeD, holeD); 
 
  line (diamCutInner/2, 0, diamCutOuter/2, 0);
}
 
//-------------------------------------------------------
function drawGuides() {
  // This function draws the guidelines. 
  // Don't draw these when we're exporting the PNG. 
  if (!bRecordingSinglePNG) {
 
    noFill(); 
    stroke(128); 
    strokeWeight(0.2); 
    ellipse(0, 0, diamArtInner, diamArtInner); 
    ellipse(0, 0, diamArtOuter, diamArtOuter);
 
    for (var i=0; i&lt;nFrames; i++) {
      var angle = map(i, 0, nFrames, 0, TWO_PI); 
      var pxi = diamArtInner/2 * cos(angle);
      var pyi = diamArtInner/2 * sin(angle);
      var pxo = diamArtOuter/2 * cos(angle);
      var pyo = diamArtOuter/2 * sin(angle);
      stroke(128); 
      strokeWeight(0.2);
      line (pxi, pyi, pxo, pyo);
    }
 
    // Draw the red wedge outline, highlighting the main view.
    var redWedge = 7; // assuming nFrames = 10
    for (var i=redWedge; i&lt;=(redWedge+1); i++) {
      var angle = map(i, 0, nFrames, 0, TWO_PI); 
      var pxi = diamArtInner/2 * cos(angle);
      var pyi = diamArtInner/2 * sin(angle);
      var pxo = diamArtOuter/2 * cos(angle);
      var pyo = diamArtOuter/2 * sin(angle);
      stroke(255, 0, 0); 
      strokeWeight(2.0);
      line (pxi, pyi, pxo, pyo);
    }
    noFill(); 
    stroke(255, 0, 0); 
    strokeWeight(2.0);
    var startAngle = redWedge*TWO_PI/nFrames;
    var endAngle = (redWedge+1)*TWO_PI/nFrames;
    arc(0, 0, diamArtInner, diamArtInner, startAngle, endAngle); 
    arc(0, 0, diamArtOuter, diamArtOuter, startAngle, endAngle); 
 
 
    for (var i=0; i&lt;nFrames; i++) {
      var angle = map(i, 0, nFrames, 0, TWO_PI); 
 
      push();
      rotate(angle); 
      var originY = ((diamArtOuter + diamArtInner)/2)/2;
      translate(0, 0-originY); 
 
      noFill(); 
      stroke(128); 
      strokeWeight(0.2);
      line (-inch/2, 0, inch/2, 0); 
      line (0, -inch/2, 0, inch/2); 
 
      pop();
    }
  }
}
 
//-------------------------------------------------------
function drawAllFrames() {
  for (var i=0; i&lt;nFrames; i++) {
    var angle = map(i, 0, nFrames, 0, TWO_PI); 
    var originY = ((diamArtOuter + diamArtInner)/2)/2;
 
    push();
    rotate(angle); 
    translate(0, 0-originY); 
    scale(0.8, 0.8); // feel free to ditch this 
 
    var whichFrame = i; 
    if (bAnimate) {
      whichFrame = (i+myFrameCount)%nFrames;
    }
    drawArtFrame (whichFrame); 
    // drawArtFrameAlternate (whichFrame); 
 
    pop();
  }
  myFrameCount++;
}
 
 
//-------------------------------------------------------
function drawArtFrame ( whichFrame ) { 
  // Draw the artwork for a generic frame of the Praxinoscope, 
  // given the framenumber (whichFrame) out of nFrames.
  // NOTE #1: The "origin" for the frame is in the center of the wedge.
  // NOTE #2: Remember that everything will appear upside-down!
 
   var nCircles = 10 
   for (var i=0; i &lt;= nCircles; i++) {
     var radius = 20 
     if (whichFrame != i){
       fill(255);}
 
     else {
       fill(0);}
 
     var cx = radius * cos((TWO_PI/10) * i); 
     var cy = radius * sin((TWO_PI/10) * i);
     ellipse(cx, cy, 20, 20);
   }
 
}
 
//-------------------------------------------------------
function drawArtFrameAlternate( whichFrame ) { 
  // An alternate drawing test. 
  // Draw a falling object. 
 
 
  // Draw a little splat on the frame when it hits the ground. 
  if (whichFrame == (nFrames-1)) {
    stroke(0, 0, 0); 
    strokeWeight(0.5); 
    var nL = 10;
    for (var i=0; i&lt;nL; i++) {
      var a = HALF_PI + map(i, 0, nL-1, 0, TWO_PI);
      var cx = 12 * cos(a);
      var cy = 10 * sin(a); 
      var dx = 16 * cos(a);
      var dy = 13 * sin(a); 
      line (cx, 45+cy, dx, 45+dy);
    }
  }
 
  // Draw a little box frame
  fill(255); 
  stroke(0, 0, 0);
  strokeWeight(1); 
  rect(-5, -50, 10, 100); 
 
  // Make the puck accelerate downward
  var t = map(whichFrame, 0, nFrames-1, 0, 1); 
  var t2 = pow(t, 2.0); 
  var rh = 8 + whichFrame * 0.5; // wee stretch
  var ry = map(t2, 0, 1, 0, 100-rh) - 50; 
 
  noStroke(); 
  fill(0, 0, 0);
  rect(-5, ry, 10, rh);
}

 

 

breep-AnimatedLoop

I ended up using the double exponential sigmoid as I wanted the squares to be able to tend toward the centre point from both sides. I initially had blocked out the squares on rectangles which highlighted where the squares would appear and re-appear, but I didn't like how busy they made the image. Once this had been laid out, I had to adjust the percentage amounts of each square on the sigmoid so that they all paused at that common central point. Once this was done I wanted to incorporate some form of spiral motion, but I wanted it to also be somewhat bi-parted as well to go with the squares, hence the two spiralling arms.

I felt I succeeded with the sigmoid nature of the squares, and am pretty proud of how they as a unit follow a curve, but also individually do. I still think the image is a bit too busy, and I still would've liked to incorporate more circular motion but it would have oversaturated the gif with content I think. The squares don't line up as well as I would like, given that I had to adjust the percentages of the sigmoids by eye so a more mathematic approach to that would make it appear that bit more fluid.

 
// Template used from 60-212 Website 
 
// This is a template for creating a looping animation in p5.js (JavaScript). 
// When you press the 'F' key, this program will export a series of images into
// your default Downloads folder. These can then be made into an animated gif. 
// This code is known to work with p5.js version 0.6.0
// Prof. Golan Levin, 28 January 2018
 
// INSTRUCTIONS FOR EXPORTING FRAMES (from which to make a GIF): 
// 1. Run a local server, using instructions from here:
//    https://github.com/processing/p5.js/wiki/Local-server
// 2. Set the bEnableExport variable to true.
// 3. Set the myNickname variable to your name.
// 4. Run the program from Chrome, press 'f'. 
//    Look in your 'Downloads' folder for the generated frames.
// 5. Note: Retina screens may export frames at twice the resolution.
 
 
//===================================================
// User-modifiable global variables. 
var myNickname = "nickname";
var nFramesInLoop = 120;
var bEnableExport = false;
 
// Other global variables you don't need to touch.
var nElapsedFrames;
var bRecording;
var theCanvas;
 
 
 
//===================================================
function setup() {
  theCanvas = createCanvas(640, 640);
  bRecording = false;
  nElapsedFrames = 0;
  frameRate(120); 
}
 
//===================================================
function keyTyped() {
  if (bEnableExport) {
    if ((key === 'f') || (key === 'F')) {
      bRecording = true;
      nElapsedFrames = 0;
    }
  }
}
 
//===================================================
 
function draw() {
 
  // Compute a percentage (0...1) representing where we are in the loop.
  var percentCompleteFraction = 0;
  if (bRecording) {
    percentCompleteFraction = float(nElapsedFrames) / float(nFramesInLoop);
  } else {
    percentCompleteFraction = float(frameCount % nFramesInLoop) / float(nFramesInLoop);
  }
 
  // Render the design, based on that percentage. 
  // This function renderMyDesign() is the one for you to change. 
  renderMyDesign (percentCompleteFraction);
 
  // If we're recording the output, save the frame to a file. 
  // Note that the output images may be 2x large if you have a Retina mac. 
  // You can compile these frames into an animated GIF using a tool like: 
  if (bRecording && bEnableExport) {
    var frameOutputFilename = myNickname + "_frame_" + nf(nElapsedFrames, 4) + ".png";
    print("Saving output image: " + frameOutputFilename);
    saveCanvas(theCanvas, frameOutputFilename, 'png');
    nElapsedFrames++;
 
    if (nElapsedFrames >= nFramesInLoop) {
      bRecording = false;
    }
  }
} 
 
//===================================================
function renderMyDesign (percent) {
  //
  // THIS IS WHERE YOUR ART GOES. 
  // This is an example of a function that renders a temporally looping design. 
  // It takes a "percent", between 0 and 1, indicating where we are in the loop. 
  // Use, modify, or delete whatever you prefer from this example. 
  // This example uses several different graphical techniques. 
  // Remember to SKETCH FIRST!
 
  //----------------------
  // here, I set the background and some other graphical properties
  background(0);
  smooth();
  stroke(0, 0, 0);
  strokeWeight(0);
 
  //----------------------
  // Here, I assign some handy variables. 
  var cx = 100;
  var cy = 100;
 
  //----------------------
 
  // COLOUR NUMBERS FROM BOTTOM
 
  // ORANGE 1 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(192, 576, 384, 32);   
 
  var eased = doubleExponentialSigmoid (percent, 0.9); 
  eased = (eased + 0.319)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 192, 544); 
  fill (253, 106, 2); 
  rect (xPosition1, 576, 32, 32);     
 
  // ORANGE 2 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(160, 512, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.8); 
  eased = (eased + 0.45)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 160, 480); 
  fill (253, 106, 20); 
  rect (xPosition1, 512, 32, 32);  
 
  // ORANGE 3 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(128, 448, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.6); 
  eased = (eased + 0.5)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 128, 480); 
  fill (253, 106, 2); 
  rect (xPosition1, 448, 32, 32);    
 
  // ORANGE 4 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(192, 384, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.4); 
  eased = (eased + 0.3)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 192, 544); 
  fill (253, 106, 20); 
  rect (xPosition1, 384, 32, 32);     
 
  // ORANGE 5 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(64, 320, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.2); 
  eased = (eased + 0.66)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 64, 416); 
  fill (253, 106, 20); 
  rect (xPosition1, 320, 32, 32);  
 
  // ORANGE 6 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(128, 256, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.2); 
  eased = (eased + 0.47)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 128, 480); 
  fill (253, 106, 20); 
  rect (xPosition1, 256, 32, 32);  
 
  // ORANGE 7 
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(224, 192, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.4); 
  eased = (eased + 0.19)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 224, 576); 
  fill (253, 106, 20); 
  rect (xPosition1, 192, 32, 32);  
 
  // ORANGE 8
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(156, 128, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.6); 
  eased = (eased + 0.39)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 156, 508); 
  fill (253, 106, 20); 
  rect (xPosition1, 128, 32, 32);   
 
  // ORANGE 9
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(32, 64, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.8); 
  eased = (eased + 0.73)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 32, 384); 
  fill (253, 106, 20); 
  rect (xPosition1, 64, 32, 32);   
 
  // ORANGE 10
  //strokeWeight(0);
  //fill(60, 170, 230);
  //rect(128, 0, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.9); 
  eased = (eased + 0.47)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 128, 480); 
  fill (253, 106, 2); 
  rect (xPosition1, 0, 32, 32);        
 
  push();
  translate(320, 320);
  var orange = true; 
  for (var squareX = 0; squareX <= width; squareX += 32){
 
   // Here's a linearly-moving square
   var eased = doubleExponentialSigmoid (percent, 0.5); 
   eased = (eased)%1.0; // shifted by a half-loop, for fun
   var yPosition = map(eased, 0, 1, topY, botY);    
 
   var rotatingSquareAngle = percent * TWO_PI
   rotate(rotatingSquareAngle);  
 
   var squareSize = 20;
   var topY = 0 - squareSize - 2;
   var botY = height + 2;
   var sPercent = (percent)%1.0; // shifted by a half-loop
   // var yPosition = map(sPercent, 0, 1, topY, botY);
 
   if (orange == true){
     fill(253, 106, 2);
     orange = false;}
   else{
    fill(60, 170, 230);
    orange = true;}
 
   rect(squareX, yPosition, 20, 20);}   
  pop();  
 
 
  // BLUE 1 
  // strokeWeight(0);
  // fill(120, 253, 106, 2);
  // rect(128, 608, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.2); 
  eased = (eased + 0.5)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 128, 480); 
  fill (60, 170, 230); 
  rect (xPosition1, 608, 32, 32);   
 
  // BLUE 2 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(64, 544, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.4); 
  eased = (eased + 0.682)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 64, 416); 
  fill (60, 170, 230); 
  rect (xPosition1, 544, 32, 32);     
 
  // BLUE 3 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(224, 480, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.6); 
  eased = (eased + 0.23)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 224, 576); 
  fill (60, 170, 230); 
  rect (xPosition1, 480, 32, 32);  
 
  // BLUE 4 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(32, 416, 384, 32);    
 
  var eased = doubleExponentialSigmoid (percent, 0.8); 
  eased = (eased + 0.77)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 32, 384); 
  fill (60, 170, 230); 
  rect (xPosition1, 416, 32, 32);    
 
  // BLUE 5 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(160, 352, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.9); 
  eased = (eased + 0.39)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 160, 512); 
  fill (60, 170, 230); 
  rect (xPosition1, 352, 32, 32);     
 
  // BLUE 6 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(256, 288, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.9); 
  eased = (eased + 0.115)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 256, 608); 
  fill (60, 170, 230); 
  rect (xPosition1, 288, 32, 32);    
 
  // BLUE 7 
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(96, 224, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.8); 
  eased = (eased + 0.56)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 96, 448); 
  fill (60, 170, 230); 
  rect (xPosition1, 224, 32, 32);    
 
 
  // BLUE 8
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(64, 160, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.6); 
  eased = (eased + 0.65)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 64, 416); 
  fill (60, 170, 230); 
  rect (xPosition1, 160, 32, 32);    
 
  // BLUE 9 
  //strokeWeight(0);
  //fill(253, 106, 2);
  // rect(192, 96, 384, 32); 
 
  var eased = doubleExponentialSigmoid (percent, 0.4); 
  eased = (eased + 0.284)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 192, 544); 
  fill (60, 170, 230); 
  rect (xPosition1, 96, 32, 32);    
 
 
  // BLUE 10
  //strokeWeight(0);
  //fill(253, 106, 2);
  //rect(192, 32, 384, 32);     
 
  var eased = doubleExponentialSigmoid (percent, 0.2); 
  eased = (eased + 0.27)%1.0; // shifted by a half-loop, for fun
  var xPosition1 = map(eased, 0, 1, 192, 544); 
  fill (60, 170, 230); 
  rect (xPosition1, 32, 32, 32);   
 
 
 
  push();
  translate(320, 320);
  var orange = true; 
  for (var squareX = 0; squareX <= width; squareX += 32){
 
   // Here's a linearly-moving square
   var eased = doubleExponentialSigmoid (percent, 0.5); 
   eased = (eased)%1.0; // shifted by a half-loop, for fun
   var yPosition = map(eased, 0, 1, topY, botY);    
 
   var rotatingSquareAngle = percent * TWO_PI
   rotate(-rotatingSquareAngle);  
 
   var squareSize = 20;
   var topY = 0 - squareSize - 2;
   var botY = height + 2;
   var sPercent = (percent)%1.0; // shifted by a half-loop
   // var yPosition = map(sPercent, 0, 1, topY, botY);
 
   if (orange == true){
     fill(253, 106, 2);
     orange = false;}
   else{
    fill(60, 170, 230);
    orange = true;}
 
   rect(squareX, yPosition, 20, 20);}   
  pop();      
 
}
 
// Symmetric double-element sigmoid function ('_a' is the slope)
// See https://github.com/IDMNYU/p5.js-func/blob/master/lib/p5.func.js
// From: https://idmnyu.github.io/p5.js-func/
//===================================================
function doubleExponentialSigmoid (_x, _a){
  if(!_a) _a = 0.75; // default
 
  var min_param_a = 0.0 + Number.EPSILON;
  var max_param_a = 1.0 - Number.EPSILON;
  _a = constrain(_a, min_param_a, max_param_a);
  _a = 1-_a;
 
  var _y = 0;
  if (_x<=0.5){
    _y = (pow(2.0*_x, 1.0/_a))/2.0;
  }
  else {
    _y = 1.0 - (pow(2.0*(1.0-_x), 1.0/_a))/2.0;
  }
  return(_y);
}

 

 

breep-Reading02

1A

I was immediately reminded of Ian Cheng's work Emissaries in relation to efficient Complexity. The work seems entirely arbitrary, and in some ways his design of it is, but the underlying relationships between his avatars organize this system in a way that is simultaneously perceptible as both ordered and chaotic. I would say that it tends toward the randomness as a viewer unaware in the skills required for generative making, but the underlying narrative and relationship structure is what makes it ordered.

gif courtesy of : http://www.contemporaryartdaily.com/2017/09/ian-cheng-at-moma-ps1/

1B

The Problem of Uniqueness: Given that alot of my work before CMU was primarily in the medium of print making, the idea of the uniqueness of prints strongly echoed for me in this statement. Through this, I fully agree that generative art creates completely new and unique artifacts, which contribute to a larger body that comes together to make that work of art. In a way this problem explores how the same idea can also evolve rapidly with the smallest of changes that generative systems inherently produce.

breep-Interruptions

Observations:

  1. The background is white, all the lines are black
  2. Lines are arranged in a square lattice
  3. The lines are rotated around their centre point on the lattice
  4. The lattice is 56 x 56
  5. Some lines are missing
  6. If a line is missing, the probability that one of its neighbours is missing is high (Missing in groups)
  7. There are many more lines present than missing
  8. The length of each line is twice the distance between the centre points of each line on the lattice
  9. All the lines are the same length
  10. There is a margin around the piece
  11. The angles of rotation of the lines are within a rough normal distribution (the vast majority have only a small amount of rotation, and the more extreme the rotation the less of them there are)

I started out my figuring out how to formulate the lattice, starting with circles with their centre at the lattice points. This was done with a nested for loop. Once this was created, I set about replacing every circle with a vertical line with the appropriate pixel measurements/separations. At this point I had 56 vertical long lines. I then set about figuring out how to randomly rotate each of the lines. I initially just did this purely randomly, using random(). However, displeased by this I looked at possibilities for getting the rotations more normally distributed, and found randomGaussian(). Using this I was able to more normally distribute the angles. This was definitely a saving grace, and I massive appreciated it's existence, and it also alerted me to the extent of built in functions within p5.js.

I then set about working on the spaces, and felt that I would need two cases of probability of a space. My first probability was the base overall probability of their being a blank space, which I set to be relatively low. I then set about creating an array to store whether a line was there or not, with 0 representing the presence of a line and 1 being a blank space. Then with this, as the lines were created I checked whether a line's neighbour was blank (its left, above and left top angled neighbours). If this was the case the probability that it would be blank became higher. I then tinkered with both probabilities until I got a result that I felt resembled the original Interruptions.  Getting this element of the neighbours working was the most difficult element of the app for me, with the formatting of the neighbour checking proving challenging.

 

breep-Intersections

// Generating random lines and highlighting intersections
var boolDoRefresh;
var slider;
var totalLines;
 
 
function setup() {
  createCanvas(720, 480);
  background(255, 117, 102);
  boolDoRefresh = true;
  slider = createSlider(1, 100, 12)
  slider.position(10, 10)
}
 
function draw() {
 
 
  if (boolDoRefresh) {
    lines = [];
    background(255, 179, 102);
 
    for ( i = 0; i < slider.value(); i ++){
      var x1 = random(width);
      var x2 = random(width);
      var y1 = random(height);
      var y2 = random(height);
      lines[i] = [x1, y1, x2, y2] 
    }
 
    // Line intersections
    for ( i = 0; i < slider.value(); i++){
      for ( j = 0; j < slider.value(); j++){
 
 
         var intersection = findingIntersection(lines[i][0], lines[i][1], lines[i][2], lines[i][3], 
                                               lines[j][0], lines[j][1], lines[j][2], lines[j][3]); 
         if ( intersection != false) {
           stroke(0);
           fill(173, 216, 230);
           ellipse(intersection.x, intersection.y, 20, 20);
          }
         }
        }
 
 
    // Line drawing
    for (i = 0; i < slider.value(); i ++){
      strokeWeight(1);
      line( lines[i][0], lines[i][1], lines[i][2], lines[i][3])
    }
  fill(0);
  text(slider.value(), 150, 27)
  boolDoRefresh = false;
}
}
 
function mousePressed() {
  boolDoRefresh = true 
}
 
// Function implementation inspired by Paul Bourke's algorithm
// http://paulbourke.net/geometry/pointlineplane/function
// And implemented by Leo Bottaro
// http://paulbourke.net/geometry/pointlineplane/javascript.txt  
 
function findingIntersection(x1, y1, x2, y2, x3, y3, x4, y4) {
 
  // Check if none of the lines are of length 0
	if ((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) {
		return false
	}
 
	denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))
 
  // Lines are parallel
	if (denominator === 0) {
		return false
	}
 
	let ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator
	let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator
 
  // is the intersection along the segments
	if (ua < 0 || ua > 1 || ub < 0 || ub > 1) {
		return false
	}
 
  // Return a object with the x and y coordinates of the intersection
	let x = x1 + ua * (x2 - x1)
	let y = y1 + ua * (y2 - y1)
 
	return {x, y}
}

breep-IterationExercise

// Starter Code for "Embedded Iteration + Randomness" used from Woodpress site
var boolDoRefresh;
function setup() {
createCanvas(400, 400);
background(255, 128, 0);
noStroke();
boolDoRefresh = true;
}
function draw() {
var squareSpacing = 40
if (boolDoRefresh) {
clear();
background(255, 128, 0);
 
for (var x = 5; x &lt;= width - 10; x += squareSpacing) {
 
for (var y = 5; y &lt;= height - 10; y += squareSpacing) {
var shape = random(0, 100);
fill(0, 111, 255);
 
if (shape &gt; 95) {
fill(0, 255, 31);
ellipse(x + 15, y + 15, 30, 30);
}
 
else {
rect(x, y, 30, 30);
}
}
}
boolDoRefresh = false;
}
}
 
function mousePressed() {
boolDoRefresh = true;
}