casher-Viewing04

Spectacle: art that has some kind of intentional aesthetic appeal, mainly to impress the viewer/consumer and introduce new technological advancements; technical, straightforward, and unidimensional.

Speculation: art that intends to bring awareness to a specific topic of societal concern; metaphorical, critical, and self-aware.

I decided to explore to work of Warburton himself, and I found that he tends to test the limits of software while also questioning reality and societal conventions -- in doing so, he often blends spectacle and speculation in his projects. One that struck me in particular was Primitives, an exploration and experimentation with crowd simulation. In this project, he worked with a dancer to highlight the nuance and relevance of crowd simulation in today's graphics; how such algorithms have made it so easy for designers to manipulate multiple "beings" and their parameters in the same way, all at once, at the click of a button. Crowd simulation is useful for effortless but accurate creations of conflict, disaster, and death in films and TV.

At first thought, this is merely technical. However, Warburton dives deeper into speculation by questioning how crowd simulation software could be challenging our definitions of freedom and agency -- that a computer having such power over "human" entities with so much ease of manipulation could be representational of the future we may have, with artificial intelligence eventually gaining control over us and finding ways to manipulate our own daily "parameters." In the project videos, he tries to simultaneously individualize and humanize the dancers while testing the limits of the software, illustrating how core standards of life are being called into question.

casher-clock

 

For my clock, I made a graphic that increases the number of sides in the shape according to the hour, has an increasing number of rings according to the minute, and pulses according to the second. The color also changes according to the specific time. I really wished I had had more time to work on this because there were some cool effects that I didn't get the chance to code. I had a lot of other work this week so I actually couldn't find a time to truly start it until tonight; nevertheless, I worked hard, and as you can see my third GIF render is from right now -- 2:10am. Gotta love coding.

I was stuck for a while at the beginning on how to actually generate shapes with sides according to the hour, so that it changes without me having to draw 12 different shapes and call them individually using if statements. Golan told me about beginShape(), so that new function with a bit of trig helped me generate the hourly shapes. And of course, Char came along and aided with the pulsing. However, this code is 100% my own! There were no templates from Golan or chunks from the internet. I am proud of that. Learning is cool!

casher-Reading03

In my senior year of high school (last year), I was a visual design major. In most of the years before that, the teacher had her students do a few big projects each year; however, in my year, we got a huge proposal from the principal to create a piece of public art that represents our mission statement to hang in the school. It was very important to the principal that a lot of work went into its production, so before any sketching, we spent the whole first semester doing market research on how to create the perfect piece. We had to make sure that it would not only represent our large body of students, but "stand the test of time." That exact quote was written on every brainstorm sheet.

I bring this up because Naimark's student's remark about surviving time reminded me of how true it is (in my opinion) that artists cannot only make art for the now -- after researching for so long, I learned that we have to predict how people will interpret our pieces in the future, and strategically plan around that so they aren't forgotten. If the piece won't have cultural or social significance come the next generation of artists, is it worth making at all? Artists shape artists; first word art depends on last word art, and vice versa. I agree that when work is technologically novel, it can age poorly, but that's only if people aren't willing to accept that this is the direction our cultures and societies are moving toward. It's important for artists themselves to be adaptable to changing times, and as a result they learn how to make their art robust. I think it's ultimately more important for artists to make first word than last word because we will no longer learn anything if we stop experimenting and innovating.

casher-LookingOutwards02

I have chosen to look at Tentasho (2016), a work of Lia, a generative software artist based in Austria. It is a procedural installation on a touchscreen, and it can either be interactive, where the user touches the screen to drag a path in the application, or it is automatic (and completely generative) when there is no user and the application draws paths itself. These paths are randomly calculated but follow a specific algorithm that creates "tentacle"-like splines coming off the main spline. The drawings end up looking similar to caterpillars, or like some kind of many-legged creatures.

As mentioned in the description on the main website, I too appreciate the minimalist design. There are only three colors, and every image only consists of lines on a white background. I can tell that Lia has a good eye for clean design and aesthetics. It gives the piece a sense of simplicity.  Therefore, I would say that it has a moderate amount of effective complexity -- the lines follow a general order, or what seems to be algorithmic "rules," but the paths in total are somewhat disordered. I suppose that the algorithm simultaneously generates the main center line and the smaller spline lines as the path gets larger, but the length limit of the splines gets smaller as the path is drawn.

https://www.liaworks.com/theprojects/tentasho/

casher-AnimatedLoop

https://editor.p5js.org/cassiescheirer/sketches/SknMGG_O7

I don't know why but my computer was having an incredibly hard time exporting my frames -- some were being skipped, and everything was patchy. I had Char help me export and the GIF still ended up being way too slow. Click the link above it or here (https://editor.p5js.org/cassiescheirer/sketches/SknMGG_O7) to see it in the p5.js editor. Sorry about this.

Anyway, I am mostly happy with this project. I wish I had had more time to make it more fancy, and a better laptop so that I wouldn't have gotten so frustrated at the lag, but overall I am proud. It took a little while to come up with the idea, but once I knew what I wanted to do, I had to make it happen. Again I had Char talk through the syntax I didn't know, but a lot of it I figured out myself this time. For the easing function, I knew that I was probably going to need one to simulate the "bouncing" of the ball, so I looked for one that matched that motion the most. I went through a couple of them before concluding that the doubleExponentialSigmoid, which Golan had already used in the template, was actually the best one. Having that as a guide was helpful.

I'm proud of myself for having a set idea in mind and then putting in the effort to execute it, even though it was hard. I also really like the simplicity of my GIF. At one point I was about to add some flashing circles in the background, but Char told me that the minimalist-ness of it was what made it so nice. However, I think it is only that way because I hadn't allotted enough time to make it super grand. If I had more time and had known more of the p5.js syntax, I definitely would have made it more complicated.  As you can see in my sketch (bottom left), I started an idea that branched off of the flipping square -- a skillet flipping a pancake. I stopped myself there though, as I knew I probably didn't know enough to do that. I hope I can come back to this project when I have time and make the pancake idea.

 

//===================================================
// User-modifiable global variables. 
var myNickname = "Cassie";
var nFramesInLoop = 120;
var bEnableExport = true;
 
// Other global variables you don't need to touch.
var nElapsedFrames;
var bRecording;
var theCanvas;
 
var canvaswidth = 645;
var canvasheight = 645;
 
var flipper = false;
 
//===================================================
function setup() {
  theCanvas = createCanvas(canvaswidth, canvasheight);
  bRecording = false;
  nElapsedFrames = 0;
  rectMode(CENTER);
}
 
//===================================================
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
  var x = abs(cos(percent*TWO_PI))
  var y = doubleExponentialSigmoid(x, 0.25);
  var squish =  map(y, 0, 1, 10, 30);
 
  background(0);
  rectMode(CENTER);
  strokeWeight(2);
  stroke(255);
 
  // flipping base
  push();
  translate(width / 2 + 20*sin(TWO_PI*percent), height-250);
  rotate(sin(TWO_PI*percent));
  var flipx = map(-cos(frameCount/9.5), -1, 1, 0, 200);
 
  if (frameCount % 120 >= 60) {
		fill(200, 100, 200);
  }
  else {
    fill(200,200,100);
  }
  rect(0, 20, flipx, 200);
  pop();
 
  translate(width / 2, height / 2);
 
  // ball shadow
  push();
  var shadowbounce = map(y, 0, 1, 100, 40);
  fill(0);
  noStroke();
  rotate(-abs(cos(TWO_PI*percent)));
  ellipse(0, shadowbounce, cos(frameCount/20)*20, cos(frameCount/20)*15);
  pop();
 
  // ball
  push();
  fill(255);
	var ballbounce = map(-y,0,1,100,360);
  distance = height - ballbounce;
  ellipse(0, ballbounce, 30, squish);
  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);
	}
}

casher-Scope

Since I am still new to Javascript/p5.js, I didn't totally understand what the code in the template meant when I began this assignment. As a result, most of my design is from experimentation. I started out by writing some groups of statements similar to the template's, and then I just started changing values of variables and parameters, testing the limits of the application. I spent a long time perfecting everything so it looked aesthetic.

There's not much else to explain, but I love the way it turned out! And I am pleased with the effort I put in because now I definitely better understand how the code works.

/*
// 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 bRecordingPNG = false;
 
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;
 
//-------------------------------------------------------
function setup() {
  createCanvas(792, 612); // 11x8.5" at 72DPI
  frameRate(20);
  smooth();
} 
 
 
//-------------------------------------------------------
function draw() {
  background(255); 
 
  // Do all the drawing. 
  push(); 
  translate(width/2, height/2);
  drawCutLines(); 
  //drawGuides(); 
  drawAllFrames();
  pop();
 
 
  if (bRecordingPNG) {
    saveCanvas('myPraxinoscope.png', 'png');
    bRecordingPNG = 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 PNG for the Praxinoscope.
    bRecordingPNG = 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;
 
      if (bExportFrameImages) {
        var recordFramerate = 1.0;
        var recordDuration = nFrames * 1.01; 
        frameRate(recordFramerate); // 1 FPS baby
        saveFrames('Praxinoscope_', 'png', recordDuration, recordFramerate); 
        bExportFrameImages = false;
      }
 
      break;
  }
}
 
//-------------------------------------------------------
function drawCutLines() {
  fill(0); 
  textAlign(CENTER, BOTTOM); 
  text("Praxinoscope Template", 0, 0-diamCutOuter/2-6); 
 
  stroke(0); 
  strokeWeight(1.0);
 
  noFill(); 
  if (!bRecordingPNG) {
    fill(255); 
  }
  ellipse(0, 0, diamCutOuter, diamCutOuter);
 
  noFill(); 
  if (!bRecordingPNG) {
    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 (!bRecordingPNG) {
 
    noFill(); 
    stroke(128); 
    strokeWeight(0.2); 
    ellipse(0, 0, diamArtInner, diamArtInner); 
    ellipse(0, 0, diamArtOuter, diamArtOuter);
 
    for (var i=0; i<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<=(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<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<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 ) { 
 
  //ellipses
  fill(random(0, 255), random(150,200), random(200,230));
  stroke(255);
  strokeWeight(2);
  for (var i = 0; i < nFrames; i++)
  {
    var t = map(whichFrame, 1, nFrames, 1, i*.38);
  	var diam = map(cos(t*TWO_PI*.22), -1, 1, -i*8, i*8);
  	ellipse(0,i*7-10,diam*.7,diam*0.4);
  }
 
  //lines
  p1 = -45;
  p2 = 70;
  p3 = -0;
  p4 = 54;
  stroke(100);
  strokeWeight(1.2);
  line2 = map(whichFrame, -1, 1, -50, 50);
  for (var i = 0; i < nFrames; i++) {
    line(p1+8*whichFrame,p2,p3,p4);
  }
 
  //triangles
  var p1x = 50;
  var p1y = -25;
  var p2x = 60;
  var p2y = -60;
  var p3x = -40;
  var p3y = -10;
  strokeWeight(2);
  stroke(255);
  for (var i = 0; i < nFrames; i++) {
    fill(25*whichFrame);
    triangle(p1x/(whichFrame*-1)-10, p1y-40, p2x/(whichFrame**2)+20, p2y+20, p3x+whichFrame*10, p3y);
    fill(30*whichFrame);
    triangle(p1x/(whichFrame*2)-3, p1y-30, p2x/(whichFrame)+20, p2y+20, p3x+whichFrame*-2+15, p3y);
  }
 
  //circles
  var p1 = -50;
  var p2 = 0;
  noFill();
  stroke(50);
  strokeWeight(1);
  for (var i = 0; i < nFrames-4; i+=2) {
    stroke(2**whichFrame);
    ellipse(p1-whichFrame*5, p2+20, 10, 10);
    p1 = 0;
    p2 = 0;
  }
}

casher-Reading02

1A: One family of things I like that exhibits effective complexity is snowflakes, which lie almost in the middle of total order and total randomness. Snowflakes as a whole are technically just small pieces of ice, which means at a molecular level they are completely ordered, exhibiting crystal lattice-type structures.  The unique look of each snowflake, however, is completely influenced by the flow of heat in the air at that moment, which is ultimately unpredictable; heat itself is random at a molecular level, so it is impossible to know beforehand the rate at which the temperature will microscopically change. Therefore, the outcome of each snowflake is random.

1B: In response to The Problem of Creativity:

I feel like creativity applies the most to me as an artist, but it is hard for me to agree with one "side" or the other because I don't really see sides. I don't think creativity should be considered a problem in the first place -- there is no way to prove that any certain expression of creativity is wrong. Something is creative if it can create. And technically, all generative art is obviously creative at some point -- a human had to create the ideas in their mind before it was computed. I guess it's just a matter of whether one considers using a computer to execute the ideas to be progressive or inauthentic.

casher-interruptions

  1. All the lines are the same length.
  2. The lines are small.
  3. The lines are black and the background is white.
  4. Their placings seem to have some kind of pattern.
  5. There are holes where there aren't any lines.
  6. Some of the lines create triangles or other shapes.
  7. Not all of the lines intersect with another line.
  8. There are around 50-60 lines per side.
  9. Most of the lines are vertical.
  10. Each line is rotated around its center.

 

I started out by writing some pseudocode on paper. I knew the general steps were to 1) create a grid of many small lines, all equal in length, and then 2) rotate each line with some kind of randomly calculated value (which I would soon learn is noise). Next I took to the p5.js editor and re-purposed some of the logic from my Intersections code: using two nested for loops, I began to create some lines. Using the i and j indices as x1 and y1 values, and assigning modified versions of those values to x2 and y2, the lines could stay the same length.

After that point, I got stuck. I understood that the rotations of the lines were not totally random, in that they depended on some kind of mathematical pattern, so I called Char over. She introduced noise fields, explained noise them in depth, and outlined all of the constants, variables, and parameters that I would need when using one in my code. After a lot of toying around with values, I came up with this version of Interruptions. It is not terribly similar to Molnar's versions, but I believe it is equally interesting. By trudging through this activity, I've learned that noise fields are super fascinating when visualized in this way, and that Molnar was an incredibly epic woman.

 

casher-intersections

 

var boolDoRefresh = true;
var lines = [];
 
function setup() {
  createCanvas(720, 480);
}
 
function draw() {
  if (boolDoRefresh) {
 
    // set design values
    background(201, 239, 255);
    strokeWeight(1.5);
    stroke(140, 81, 200);
    lines = [];
 
    // assign random values to points of each line
    for (var k = 0; k < 12; k++) 
    {
      x1 = random(720);
      y1 = random(480);
      x2 = random(720);
      y2 = random(480);
      var newLine = [x1, y1, x2, y2];
      lines.push(newLine);
    }
 
    // double loop takes points from line[] to make a line
    // and forms an ellipse at the points from findIntersection()
    for (var i = 0; i < 12; i++)
    {
      for (var j = 0; j < 12; j++)
      {
        line(lines[i][0], lines[i][1], lines[i][2], lines[i][3])
        var steve = findIntersection(lines[i][0], lines[i][1], lines[i][2], lines[i][3], lines[j][0], lines[j][1], lines[j][2], lines[j][3])
 
        ellipse(steve[0],steve[1],20,20)
      }
    }
  }
	boolDoRefresh = false;
}
 
//adapted from Paul Bourkes/Leo Bottaro http://paulbourke.net/geometry/pointlineplane/javascript.txt
function findIntersection(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]
}
 
function mousePressed() {
  boolDoRefresh = true;
}

casher-lookingoutwards01

Last summer, I had the chance to attend SIGGRAPH, the world's largest computer graphics conference. While I was there I saw some of the coolest art and tech projects I've ever seen -- one that stood out to me was a projection art project called INORI-PRAYER (https://vimeo.com/209356195). A small group of Japanese developers from WOW collaborated with the University of Tokyo and two dancers, AyaBambi, to create this interesting performance, which uses real-time face tracking and projection mapping at 1000fps. The girls dance to the song, and dark, creepy images that reflect the sad themes of the song are mapped on their faces. I love how the images enhance the mood of the music, especially because the song doesn't have words. I think the software and scripts of the project were mostly custom-made, which is impressive -- they developed both the projection technology and the face mapping technology. Projection mapping is destined to become a very useful tool for both artists and scientists. It is helpful for AR, so it is a cool way to incorporate interactivity into pieces, especially when combined with a camera. It provides a new medium for artists, but it can also help with data visualization, and it is very popular in the advertisement industry.