Week 4 – Generative Text

Concept:
This piece is meant to imitate a page turning, but instead of the expected behaviour it slides a new page down from the top. The text itself is pulled from a .txt file, which contains bits of placeholder text (Lorem ipsum dolor) as well as snippets of text from the p5.js reference that pertain to implementing text.

Highlight:
My highlight is still fairly simple, but I chose it since I often forget to include bounds checking or error handling in my code and end up causing myself problems down the road. This snippet checks to make sure that the newly created page is not receiving empty input for its inner text, and cleans up the pages array once a certain number of pages have been created while leaving only the most recent instance.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// // Create a new page on click
let newText = txt[floor(random(txt.length - 1))];
let tries = 0;
// // Make sure new page's text is not empty
while (!newText && tries < 10) {
newText = txt[floor(random(txt.length - 1))];
tries++;
}
// // Cull older pages at some upper limit
if (pages.length >= 10) {
pages = subset(pages, pages.length - 1, 1);
console.log("reset");
console.log(pages);
}
// // Create a new page on click let newText = txt[floor(random(txt.length - 1))]; let tries = 0; // // Make sure new page's text is not empty while (!newText && tries < 10) { newText = txt[floor(random(txt.length - 1))]; tries++; } // // Cull older pages at some upper limit if (pages.length >= 10) { pages = subset(pages, pages.length - 1, 1); console.log("reset"); console.log(pages); }
// // Create a new page on click
  let newText = txt[floor(random(txt.length - 1))];
  let tries = 0;
  // // Make sure new page's text is not empty
  while (!newText && tries < 10) {
    newText = txt[floor(random(txt.length - 1))];
    tries++;
  }
  // // Cull older pages at some upper limit
  if (pages.length >= 10) {
    pages = subset(pages, pages.length - 1, 1);
    console.log("reset");
    console.log(pages);
  }

Embed:

Reflection:
I’m not super satisfied with this piece, doubly so since I tried a few different concepts that I was unable to get to work properly. I had been having issues with getting the data to load from a file, and only managed to get it to work once I pivoted to this idea. I had also wanted to have the sliding direction change between the top, sides, and bottom, either changing randomly or going in a clockwise direction. This week was a bit rough in terms of workload so I was unable to spend as much time adding features to this piece as I would have liked.

Week 4 – Reading Response

This reading was both very illuminating and validating, especially in regards to the initial discussion of confusing doors. I had always found UI design to be an interesting topic, and this glimpse into the field of design as a whole was a lot more involved than I was prepared for. I was definitely impressed by how much work goes into properly designing a product, only for the bestowed ease-of-use resulting in users remaining completely oblivious to the effort put in. In that sense, it is similar to how good audio mixing in a song or film will go unnoticed, but bad audio will completely pull you out of the experience. There were also some good points made later on about having to carefully balance the different aspects of design, such as signals and feedback being informative yet unobtrusive, or products being feature-rich while remaining affordable.

As for applying these design principles to interactive media, I am at a bit of a loss. In the past few weeks I have experimented with using simple forms of interactivity like clicking or using arrow keys to move an object in the p5.js scene. These ended up being fairly intuitive in the sense that they are reasonable choices that one would expect when using a computer. However, if the user was not aware that these pieces were interactive to begin with, a huge chunk of the experience is lost. I had left comments at the top of the code detailing the viable inputs, but of course this requires navigating from the WordPress site to the p5.js editor. A straightforward way to deal with this would be to include text instructions in the piece itself, or having some sort of help menu, but I still feel like this would negatively impact the more artistic pieces.

Week 3 – Reading Response

I liked how the author took the vague concept of ‘interactivity’ and was able to neatly break it down into three simple parts. When I think of the word, I imagine a fairly basic system where an otherwise one-sided info dump is intentionally broken up by prompting the user to engage with it. For example, an educational application might have the user answer questions during or between readings/videos. The idea of a three-step process, where each stage requires effort and intent, makes things much more concrete to think about. The manner in which the author approaches each point was also very interesting. For example, they kept bringing up cases that were either too trivial or too exaggerated to fit into the initial argument, as well as mentioning that certain people would argue on behalf of those edge cases. This naturally led into the discussion of measuring interactivity through ‘degrees’ instead of as a yes/no, which made the argument even easier to digest. The abundance of anecdotes, similes, and metaphors also did a lot to illustrate their points while providing a source of entertainment that helped me get through the reading.

In my own work for this class, I have made some effort for all of my weekly production pieces to include some form of basic interactivity. The second week’s piece allowed the user to move their specific block around and paint in the gridlike canvas, along with some other functionality, and this week’s piece provides some ability to manipulate the layered shapes and essentially create new variations on the spot, or to focus on the appearance while the layers are in motion. I wouldn’t call these strong forms of interactivity, since it really caps out at moving what’s already in the scene around. A relevant quote that stood out to me was that “participation is not the same thing as interaction,” and in these cases the user is really just participating due to the very limited input and feedback.

Week 3 – OOP

Concept:
This generative artwork was inspired by kaleidoscopes, with specific regard to the shifting patterns they display as you rotate it. I used the OOP principles we covered to make a Hexagon class and relevant properties/methods for it, and combined it with a 2D array to create multiple layers of hexagonal grids. I implemented randomness by randomly setting the colour and opacity of each hexagon, with the latter being constrained between 30 and 80 to allow for some clear overlap and blending between layers. I initially planned to have three layers, being controlled by mouse/arrows/wasd respectively, but I ended up scrapping the mouse movement since I liked the imagery of peeling back the upper two layers to reveal the remaining one, plus using keys allowed me to set a specific speed value instead of being at the whim of the cursor’s movement.

Highlight:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// // Fill a specified layer with hexagons
function fillLayer(index) {
// // Loops to populate layer
let offsetCol = false;
for (let x = -(width/2); x < width*1.5; x += 1.5*hexSize) {
for (let y = -(height/2); y < height*1.5; y += 2*hexSize) {
// // Offset every other column --> interlocking pattern
if (offsetCol && y === -(height/2)) {
y += hexSize;
}
layers[index].push(new Hexagon(x, y, hexSize));
}
offsetCol = !offsetCol;
}
}
// // Fill a specified layer with hexagons function fillLayer(index) { // // Loops to populate layer let offsetCol = false; for (let x = -(width/2); x < width*1.5; x += 1.5*hexSize) { for (let y = -(height/2); y < height*1.5; y += 2*hexSize) { // // Offset every other column --> interlocking pattern if (offsetCol && y === -(height/2)) { y += hexSize; } layers[index].push(new Hexagon(x, y, hexSize)); } offsetCol = !offsetCol; } }
// // Fill a specified layer with hexagons
function fillLayer(index) {
  // // Loops to populate layer
  let offsetCol = false;
  for (let x = -(width/2); x < width*1.5; x += 1.5*hexSize) {
    for (let y = -(height/2); y < height*1.5; y += 2*hexSize) {
      // // Offset every other column --> interlocking pattern
      if (offsetCol && y === -(height/2)) {
        y += hexSize;
      }
      layers[index].push(new Hexagon(x, y, hexSize));
    }
    offsetCol = !offsetCol;
  }
}

Embed:

Reflection:
I’m pretty happy with how this piece turned out, in both the creative and programmatic aspects. I felt that I had a clear vision going in this time, and was able to actually realize it. My code itself was better contained after compartmentalizing and encapsulating into functions and methods, and I was successful in cutting down on needlessly making functions. On the creative side, I ran into a number of happy little accidents that ended up improving my end result, which was a breath of fresh air.

Despite this specific improvement, I still definitely need to plan things out more, since I found myself having to constantly readjust my code in order to deal with things like messing up the math for my hexagons or implementing the movement functionality with keyIsPressed() instead of keyIsDown().

Week 2 – Reading Response

The discussion on randomness by Casey Reas was a lot more profound than I had expected. I’m used to talking about randomness from a purely mathematical perspective, such as the use of random/psuedorandom numbers in computer security, so hearing the more artistic interpretations was a large change of pace. One point that stood out to me was how you could interpret randomness as a deviation from order, creating a sort of chaotic rebellion against the system, and yet there are countless applications of randomness that converge towards their own sort of order. Similarly, there was also some debate mentioned about whether the use of computers was draining the human aspect from art or giving birth to a brand new medium, and how introducing randomness into a strictly rational machine could impact things.
Another aspect that underscored the entire talk was the careful balance of randomness and control. Going all-in on one side or the other will often lead to either meaningless or soulless results, but the real magic comes when order and chaos come together. I have already found the importance of placing bounds on random values from my own experimentation in p5.js, which imposes some degree of order. Another programmatic aspect that interested me came from a class I took previously, where we discussed noise functions. Specifically, we discussed how one noise function creates randomness, but a combination of noise functions can create a sort of ordered randomness that can be used for things like image textures.

Week 2 – Loop Art

Concept:
I initially created the grid while experimenting with using for-loops in p5.js, and added in a single rect that could be controlled via the arrow keys. The whole thing was vaguely inspired by the genre of snake games, but I later came to think of it more as a canvas that the user would draw on at runtime once I reminded myself that the assignment was meant to be an art piece. I also wanted to see how the random() function could be applied to art, and ended up using it in a few places.

Highlight:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// // Traversed cells
for (let c = 0; c < filled.length; c++) {
fill(filled[c].colour);
rect(filled[c].x, filled[c].y, gridSize, gridSize);
}
// // Class for retaining pos/colour info of traversed cells
class filledCell {
constructor(x, y, colour) {
this.x = x;
this.y = y;
this.colour = colour;
}
}
// // Add a new cell instance to the relevant array
function addCell(oldX, oldY) {
let newC = new filledCell(oldX, oldY, mainColour);
filled.push(newC);
}
// // Traversed cells for (let c = 0; c < filled.length; c++) { fill(filled[c].colour); rect(filled[c].x, filled[c].y, gridSize, gridSize); } // // Class for retaining pos/colour info of traversed cells class filledCell { constructor(x, y, colour) { this.x = x; this.y = y; this.colour = colour; } } // // Add a new cell instance to the relevant array function addCell(oldX, oldY) { let newC = new filledCell(oldX, oldY, mainColour); filled.push(newC); }
// // Traversed cells
for (let c = 0; c < filled.length; c++) {
  fill(filled[c].colour);
  rect(filled[c].x, filled[c].y, gridSize, gridSize);
}

// // Class for retaining pos/colour info of traversed cells
class filledCell {
  constructor(x, y, colour) {
    this.x = x;
    this.y = y;
    this.colour = colour;
  }
}
// // Add a new cell instance to the relevant array
function addCell(oldX, oldY) {
  let newC = new filledCell(oldX, oldY, mainColour);
  filled.push(newC);
}

Embed:

  • Arrow keys = move
  • Spacebar = move to random cell
  • Click = change colour
  • r = clear canvas
  • R = randomize canvas

Reflection:
Overall, I’m a lot more satisfied with this piece than the self-portrait. I made sure to approach things more systematically, and achieved my goals of using variables more effectively and leaving comments in my code. One thing I would still like to improve on is ordering and grouping things together, since even though I had distinct sections (e.g. Globals, Interaction, Helpers) my code still ended up being rather messy. The section for helper functions was particularly bad, since I just threw things in there as I came up with them.

Another thing I both struggled and succeeded in was creating functions. There were a number of points where I saw an opportunity to move code from the main body into distinct functions, which was an improvement from last week, but I also had to stop myself from going overboard and creating more functions when I could just leave a few lines in the body to do the same thing. Lastly, while my work was more structured this time around, I still did not plan things out as thoroughly as I would like to. Most of what I wrote was done spontaneously, which resulted in plenty of backtracking to properly implement the new functionality in my existing code.

Week 1 – Self-Portrait

Concept:
I wanted to make my self-portrait in a minimalistic style that would accurately represent my appearance while being limited to the use of simple geometric primitives. I chose to not use outlines to add to that flat, minimalist aesthetic. I also wanted to add some simple interactivity, which came in the form of the background changing colours through a day-night palette when clicked.

Embed:

Highlight:
I was proud of this snippet, where I used an array of hex codes to implement my colour cycling feature. It is perhaps more simple than I had hoped for, but I’m happy with how it turned out overall.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// // Array containing possible background colours
let bgs = ["#fff2bd", "#f4d797", "#c9ebff", "#abb5ff", "#7475b6", "#5148b2"];
let curr_bg = 0;
function mouseClicked() {
// // Change to next bg colour on click
curr_bg = (curr_bg + 1) % bgs.length;
}
// // Array containing possible background colours let bgs = ["#fff2bd", "#f4d797", "#c9ebff", "#abb5ff", "#7475b6", "#5148b2"]; let curr_bg = 0; function mouseClicked() { // // Change to next bg colour on click curr_bg = (curr_bg + 1) % bgs.length; }
// // Array containing possible background colours
let bgs = ["#fff2bd", "#f4d797", "#c9ebff", "#abb5ff", "#7475b6", "#5148b2"];
let curr_bg = 0;

function mouseClicked() {
  // // Change to next bg colour on click
  curr_bg = (curr_bg + 1) % bgs.length;
}

Reflection:
I feel a bit conflicted about this assignment, since on the one hand it was an interesting change of pace to try and create art directly using code, but also very annoying. I found myself frequently trying to force coordinates or dimensions to be multiples of the canvas’ dimensions to allow it to scale, but often found it to be an exercise in frustration. Having to essentially guess-and-check all my numbers was another aspect I didn’t enjoy, since there were little quirks I wouldn’t expect such as circle’s being plotted by their center versus rectangles by their top-left corner.

In the future, I would like to try and plan things out more before starting, especially in regards to using custom variables. The built-in width and height variables made sense at first, but I quickly gave up on sticking to them and added pixel offsets instead. I think the most important thing for me is finding a way to streamline my workflow, since my struggle to put my concept on paper/screen caused me to fall short of where I wanted to be in terms of both artistic and programmatic aspects.