Assignment 2: Loop-Based Digital Art

Concept

It took a little thought, but an image that soon sprung to mind for me was the pattern of multicolored rectangles that you see when a TV channel is off-air, the one that is accompanied by that awfully grating (and sometimes eerie) high-pitched beep. The one that looks like:

This pattern is called the SMPTE color bars (SMPTE stands for the Society of Motion Picture and Television Engineers). Image courtesy of its Wikipedia article: https://en.wikipedia.org/wiki/SMPTE_color_bars

I thought this would serve as good inspiration for my own artwork of patterns. After getting just a little invested in trivia (Did you know that that continuous beep is usually a 1000 Hz sine wave?), I set off to work.

Coding Highlights

I first sought to recreate the pattern. After a little tinkering, I was able to write up a function that would draw the pattern across the canvas when repeated.

//Set Variables
let x = 0;
let x2 = 0;
let i = 0;

//Function for Generating One Color Bar of Each Row
function colorBars(){
  noStroke();
  fill(random(255), random(255), random(255));
  rect(x, 0, 63, 220);
  fill(random(255), random(255), random(255));
  rect(x, 220, 63, 30);
  x = x + 63;
  fill(random(255));
  rect(x2, 250, 73.5, 80);
  x2 = x2 + 73.5;
}

This function is then embedded within a simple while() loop, which runs just enough times to make the pattern fill the canvas.

//Repeat for Pattern
function draw() {
  while (i < 7) {
    colorBars();
    i += 1;
  }

The x = x + 63; and x2 = x2 + 73.5; lines of code in the colorBars() function move the position of the future rectangles’ starting points to the end of the now-drawn rectangle, thus allowing for the pattern to be continued seamlessly when the function is repeated. I also chose to make the colors random (the bottom row is in grayscale for contrast and to match the feel of the reference image), which makes each iteration of my program unique. Here is the complete draft:

Draft in hand, I now wanted to add a layer of animation and make the bars change color (or more precisely, generate new bars over the preexisting ones). I also wanted to keep the animation from looking too stale by varying the cycle speeds of each row of bars—this meant that I had to break up the colorBars() function into three separate functions (one for each row) and establish separate variables for each function.

//Establish Variables

  let x1 = 0;
  let x2 = 0;
  let x3 = 0;
  let i1 = 0;
  let i2 = 0;
  let i3 = 0;

//Establish Functions for Each Row of Bars

function barTop(){
  noStroke();
  fill(random(255), random(255), random(255));
  rect(x1, 0, 63, 220);
  x1 = x1 + 63;
}

function barMid(){
  fill(random(255), random(255), random(255));
  rect(x2, 220, 63, 30);
  x2 = x2 + 63;
}


function barBot(){
  fill(random(255));
  rect(x3, 250, 73.5, 80);
  x3 = x3 + 73.5;
}

With the functions established, I could move on to the draw() function. First in line was the initial setup, which follows the same logic used for the while() loop in the draft (now with three functions looping within it).

//Initial Setup - This is in the draw() function.
while (i1 < 7) {
  barTop();
  barMid();
  barBot();
  i1 += 1;
  i2 += 1;
  i3 += 1;
}

The stage was set, and this was where the function separation came in handy. I was able to write three blocks of code that would determine the cycle speeds of each row, as well as reset their positions as needed:

//This is in the draw() function following the setup.
  //Top Bar Generation
  if (i1 % 5 == 0){
  barTop();
  }
  if (i1 % 35 == 0){
    x1= 0;
  }
  i1 += 1;
  
  //Middle Bar Generation
  if (i2 % 7 == 0){
    barMid();
  }
  if (i2 % 49 == 0){
    x2 = 0;
  }
  i2 += 1;
  
  //Bottom Bar Generation
  if (i3 % 6 == 0){    
    barBot();
  }
  if (i3 % 36 == 0){
    x3 = 0;
  }
  i3 += 1;

The i1, i2, and i3 here act as counters for the number of draw() loops the program has gone through—by pairing them with the % remainder operator, I was able to vary the speeds at which the new bars are drawn over the preexisting ones. The first if() function in each block controls the rate at which a new bar is generated, while the second if() function resets the position of generation back to the beginning when the new pattern has gone across the width of the canvas. And finally, the result:

Reflections

Overall, this assignment was a fun one to work on! I was especially satisfied with how I was able to separate the initial bar-drawing function into three and make them run at differing intervals using the loop counters and the remainder operator. Each feature I want to implement in a project is a puzzle of its own, and it feels rewarding when I successfully devise a solution (sometimes after much frustration).

One feature I would have liked to adjust is to have the bars scroll across the screen rather than (seemingly) just change color. This was the initial idea I had, but I soon realized that making all the bars move, especially with each row at different speeds, was a much more complicated task than I had imagined. A task for a different time, perhaps.

Exploring the capabilities of p5.js—and that of my own with the editor—has been an exciting journey thus far, and I look forward to what more may lie in store!

Leave a Reply