Chris Crawford reading – Afra Binjerais

The reading discusses the concept of interactivity, highlighting its overuse and misconceptions. The author defines interactivity as a conversational process involving listening, thinking, and speaking alternately. They note that despite interactivity being recognized as important in computing, it’s often misunderstood.

The author proposes viewing interactivity as a spectrum rather than a binary state, akin to measuring weight. They emphasize the importance of considering nuances and subjective evaluations when discussing interactivity. Additionally, the reading addresses misconceptions about interactivity, such as the belief that reading is interactive After reading the text, I find myself reflecting on the complexity of the concept of interactivity.

The author’s comparison of interactivity to a conversation resonated with me, as it captures the essence of genuine interaction. I appreciate the author’s call to view interactivity as a spectrum, which allows for a more nuanced understanding of its manifestations. Furthermore, the discussion on misconceptions about interactivity, particularly regarding reading, prompts me to reconsider my assumptions.

Assignment #3 – Click to spawn

For this assignment we had to use Object Oriented programming so I decided to combine classes, arrays and functions in a fun interactive way. It all started of with the idea of a moving car that was shown to us in class. I decided to replicate that with circles. It ended up looking pretty boring so I was looking for ideas of how I can make it fun, interactive with the user and at the same time look like an “art piece”.

What a better way to find inspiration than to look at Pi’s works (thank you Pi) where I noticed his particle work which spawns small particles in a circle and lets us as users disturb the harmony. My first complication was transforming the motion of the circles from a static one direction pathway to a rotation around the middle. In order to do that, I declared specific variables in the constructor like angle offset and circle radius. By defining the x and y positions using sin and cos i managed to get the drones going in a circle. It still seemed pretty simple so I added a little bit of noise to make the animation look a little bit randomized. It ended up looking pretty nice actually.

The challenge and code

Of course, like always Darko never thinks what he does is enough so he does extremely difficult things to sleep right. And guess what, that is what I did this time. Okay I’m maybe overreacting a little bit but I decided to make the circles spawn every time the mouse button is clicked and my code ended up looking like this:

let drones = []; // necessary global variables
let droneSpacing = 120;
let speed = 5;
let angle = 0;
let r, g, b;

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

function draw() {
  background(0, 15);

  for (let i = 0; i < drones.length; i++) {
    drones[i].run(); //spawning the drones
    drones[i].runDriving(); //making the drones rotate
  }
}

function mousePressed() {
  drones.push(new Drones(drones.length)); // add drones when the mouse button is pressed
}

class Drones {
  constructor(angleOffset) {
    //construtor for each drone
    this.angleOffset = angleOffset;
    this.droneRadius = 50;
    this.noiseOffsetX = random(1000);
    this.noiseOffsetY = random(1000);
  }

  run() {
    this.spawnDrones();
  }

  spawnDrones() {
    let noiseX = noise(this.noiseOffsetX); //setting the noise offsets for x and y
    let noiseY = noise(this.noiseOffsetY);
    let x =
      width / 2 +
      cos(angle + this.angleOffset) * droneSpacing +
      map(noiseX, 0, 1, -5, 5); //updating the x position based on the angle, spacing and noise
    let y =
      height / 2 +
      sin(angle + this.angleOffset) * droneSpacing +
      map(noiseY, 0, 1, -5, 5); //updating the y position based on the angle, spacing and noise
    fill(random(255), random(255), random(255)); //randomizing fill colors
    circle(x, y, this.droneRadius);
  }

  runDriving() {
    this.driveDrones();
  }

  driveDrones() {
    angle += 0.007; // rotation speed
    this.noiseOffsetX += 30; // x and y noise
    this.noiseOffsetY += 30;
  }
}

Final Product

The final product can be seen below. Enjoy and have fun 🙂

Week 3 – Reading Reflection: Chris Crawford’s The Art Of Interactive Design

Chris Crawford’s The Art Of Interactive Design was such an informative yet highly entertaining read. Touching on the meaning of interactivity, Crawford gave his definition of interactivity in which it is measured, and not as he puts it “a Boolean property”.

The piece was mostly very understandable and very informative in terms of understanding interactivity and what makes something interactive, at least in Crawford’s eyes. However, it is important to keep in mind that human conversation and interaction with machines such as fridges are completely different. I strongly believe that interactivity with humans, and art forms can be measured on a scale but not interactivity with fridges as they are solely tools or means of entertainment. Moreover, I do agree that books, films, and dancing aren’t interactive with users in the slightest which is pretty obvious.

What was highly entertaining to me was the fact that as the example of books not being interactive, he dedicated an entire paragraph to show us an active example of how it doesn’t fit his criteria of interactivity. And, the questions at the end were hilarious.

 

 

The Art of Interactive Design – Am I really interacting with my fridge?

To begin with, this reading was really fun and it showed me another dimension of the word “interactivity” and what interactive media really means. I have always struggled explaining to my friends and family back home when describing my major: soo you work with computers? programming? robotics? but wait you also design?

-Well yeah I kind of do it all 🙂

Nevertheless let’s get back on the subject. I really agree with the authors description of interactivity, a combination of subtasks (listening, thinking, speaking) or all in all a conversation between two and more people/objects…

Since its start in 1980 and its peak in 1990, the word interactive has really changed a lot and at the same time used in the wrong way. Take a look at this advertisement:

How can a chocolate almond coconut raisin bar be interactive? On the other side we have the fridge theory? – Is the opening and closing of the fridge while the light is turning on and off any kind of interaction.

To answer the question the author looks at interactivity as a combination of listening thinking and speaking and they all have to be present (none can be left out). On the scale of interactivity though we can have highly interactive, moderately interactive and so on. The fridge is a very low level interaction.

Important mention: things that are not interactive :

-Books

-Movies

-Dancing

-Performance art (or is it? I will let you think about it:)

Raya Tabassum: Reading Response 2

The first chapter of “The Art of Interactive Design” by Chris Crawford lays out the foundation for understanding what interaction is in the first place. On the other hand, Crawford distinguished between interaction and mere reaction by insisting on the two-way process of communication and stated that a cyclic process is necessary where two actors listen, think, and speak alternately. Crawford’s definition makes one start to question the extent to which the present technologies achieve real interaction versus offering sophisticated forms of reaction. For instance, if we look at voice-activated assistants or chatbots, how much do these systems actually engage in a listen-think-speak cycle, and how much is it just a pre-programmed set of responses to user input? The key question comes up here: can artificial intelligence, as it exists and will in all future products, actually ‘interact’ as Crawford has described interaction, or is it by necessity delegated to the simulation of interaction through a series of complex algorithms?
There are key lines of inquiry related to the ethics of designing for interaction. What, therefore, when the essence of interaction is meaningful exchange? How is it that designers ensure technologies really foster such positive interactions without the manipulation or exploitation of the user? This issue becomes very pertinent in the context of social media platforms in which interaction design can radically impact user behavior and mental health.

Moreover, Crawford’s focus on interaction as something cyclic challenges us to reason about user feedback loops in design. And his differentiation between interaction and reaction raises serious questions of how we categorize and value forms of digital engagement. This prompts us to critically reflect on whether, indeed, our daily engagements with technology are two-way interactions, that is, if as much as we respond to them, devices and platforms themselves also engage and respond to us—or whether, indeed, we are only responding to slick cues, designed by others.
I believe these questions are crucial for both designers and users as we navigate the increasingly complex landscape of interactive systems.

Reading Response – Week #3 Redha Al Hammad

The main point which stood out to me from this reading was the author’s definition of interactivity as clarified by the analogy of a conversation. I found the comparison of “input, process, output” to “listen, think, speak” to be effective in conveying interactivity today (especially since the piece was written two decades ago). On this same note, I found the mention of an interactive process requiring “two actors” to be interesting. As someone who grew up with digital technology, I subconsciously tend to either view it as a tool or an extension of myself and my actions – not as a separate active party that has the agency to “listen, think and speak” in conversation with me. I feel that the only time I consider technology’s agency is when it does not cooperate with my goal as a user as, for example, oftentimes when a website does not load or is difficult to use we place the blame on it and not the interaction itself.

Another point I found interesting was the misuse of interaction in varying different contexts. More specifically, the distinction between integration and reaction stood out to me as the author strongly claims that they have nothing to do with one another. However, I do feel that there is some element of reaction within interaction (on the human side at the very least). In the aforementioned example, a poorly constructed website will surely garner a specific reaction in the user and, in turn, will affect how they interact with it. As such, I feel that in certain cases, the two are interlinked and should not be considered entirely separate processes.

Assignment 3: State of Mind

Concept

The goal of this week’s assignment was to create a unique work of art through imagination and creativity. The original idea was to create a dynamic screensaver with a range of shapes that had different colors and speeds and interacted with the canvas and each other when they collided. However, this concept was disregarded because a more abstract art piece was needed.

So I used the original code as the template, and the project developed into a complex particle-mimicking display of forms. These particles used the idea of flow fields to mimic more organic and natural motions, leaving behind a vibrant trail as they moved. The chaos of these trails of particles is a representation of my “State of Mind” while thinking of ideas for the assignment.

Sketches


Code

The particles’ motion is directed by a grid of vectors called the flow field. Perlin noise is used in its generation to provide a fluid, flowing transition between the grid’s vectors.

for (let i = 0; i < cols; i++) {
    for (let j = 0; j < rows; j++) {
      let index = i + j * cols;
      let angle = noise(i * 0.1, j * 0.1, zoff) * TWO_PI * 4;
      flowField[index] = p5.Vector.fromAngle(angle);
    }
  }

The snippet is in the draw() loop that creates the flow field. It simulates a natural flow by using Perlin noise to generate vectors with smoothly shifting angles.

The shapes follow the flow field vectors, which guide their movement. This interaction is encapsulated in the follow() method of the BaseShape class.

follow(flowField) {
  let x = floor(this.pos.x / resolution);
  let y = floor(this.pos.y / resolution);
  let index = x + y * cols;
  let force = flowField[index];
  this.vel.add(force);
  this.vel.limit(2);
}

The shape’s position (this.pos) is used to determine its current cell in the flow field grid by dividing by the resolution. The index in the flowField array corresponding to the shape’s current cell is calculated using x + y * cols.
The vector (force) at this index is retrieved from the flowField array and added to the shape’s velocity (this.vel), steering it in the direction of the flow. this.vel.limit(2) ensures that the shape’s velocity does not exceed a certain speed, maintaining smooth, natural movement.

The trail effect is created by not fully clearing the canvas on each frame, instead drawing a semi-transparent background over the previous frame. This technique allows shapes to leave a fading trail as they move.

background(0, 0.3);

The purpose of the resetAnimation() method is to reset the animation setup and clean the canvas. To restart the flow field pattern, it first uses clear() to remove any existing shapes from the canvas, resets the shapes array to its initial state, initializeShapes() method to add a new set of randomly placed shapes, and resets the zoff variable for flow field noise.

function resetAnimation() {
  clear();
  // Clear existing shapes
  shapes = []; 
  // Repopulate with new shapes
  initializeShapes(); 
  // Reset the z-offset for flow field noise
  zoff = 0; 
 
}

The resetAnimation() method is called when the frameCount has reached 500 frames. This helps to see how the flow field changes every time it restarts.

Full Code

// array for shapes
let shapes = [];
// declare flow field variable
let flowField;
let resolution = 20;
// 2d grid for flow field
let cols, rows;
// noise increment variable
let zoff = 0;
// make the sketch again after this value
let resetFrameCount = 500;


function setup() {
  createCanvas(800, 600);
  colorMode(HSB, 255);
  blendMode(ADD);
  cols = floor(width / resolution);
  rows = floor(height / resolution);
  flowField = new Array(cols * rows);
  initializeShapes(); 
}

function draw() {
  
  if (frameCount % resetFrameCount === 0) {
    resetAnimation();
  } else {
    background(0, 0.3); 
  }

  // Flow field based on Perlin noise
  for (let i = 0; i < cols; i++) {
    for (let j = 0; j < rows; j++) {
      let index = i + j * cols;
      let angle = noise(i * 0.1, j * 0.1, zoff) * TWO_PI * 4;
      flowField[index] = p5.Vector.fromAngle(angle);
    }
  }
  
  // Increment zoff for the next frame's noise
  zoff += 0.01; 

  // Update and display each shape
  // For each shape in the array, updates its position according to the flow field, moves it, displays its trail, and display it on the canvas.
  shapes.forEach(shape => {
    shape.follow(flowField);
    shape.update();
    shape.displayTrail();
    shape.display();
    shape.particleReset();
    shape.finish();
  });

}

function resetAnimation() {
  clear();
  // Clear existing shapes
  shapes = []; 
  // Repopulate with new shapes
  initializeShapes(); 
  // Reset the z-offset for flow field noise
  zoff = 0; 
 
}

// Initialized 30 number of shapes in random and at random positions
function initializeShapes() {
  for (let i = 0; i < 30; i++) {
    let x = random(width);
    let y = random(height);
    // Randomly choose between Circle, Square, or Triangle
    let type = floor(random(3)); 
    if (type === 0) shapes.push(new CircleShape(x, y));
    else if (type === 1) shapes.push(new SquareShape(x, y));
    else shapes.push(new TriangleShape(x, y));
  }
}

class BaseShape {
  constructor(x, y) {
    this.pos = createVector(x, y);
    this.vel = p5.Vector.random2D();
    this.size = random(10, 20);
    this.rotationSpeed = random(-0.05, 0.05);
    this.rotation = random(TWO_PI);
    this.color = color(random(255), 255, 255, 50);
    this.prevPos = this.pos.copy();
  }

  follow(flowField) {
    let x = floor(this.pos.x / resolution);
    let y = floor(this.pos.y / resolution);
    let index = x + y * cols;
    let force = flowField[index];
    this.vel.add(force);
    // Smoother movement so velocity is limited
    this.vel.limit(2);  
  }

  update() {
    this.pos.add(this.vel);
    this.rotation += this.rotationSpeed;
  }

  display() {
    // Saves the current drawing state
    push();
    // Translates the drawing context to the shape's current position
    translate(this.pos.x, this.pos.y);
    // Rotates the shape's current rotation angle    
    rotate(this.rotation);
    fill(this.color);
    noStroke();
  }

  displayTrail() {
    strokeWeight(1);
    // Creates a semi-transparent color for the trail. It uses the HSB 
    let trailColor = color(hue(this.color), saturation(this.color), brightness(this.color), 20);
    stroke(trailColor);
    // Draws a line from the shape's current position to its previous position
    line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos.y);
  }

  finish() {
    this.updatePrev();
    pop();
  }

  updatePrev() {
    this.prevPos.x = this.pos.x;
    this.prevPos.y = this.pos.y;
  }

  particleReset() {
    if (this.pos.x > width) this.pos.x = 0;
    if (this.pos.x < 0) this.pos.x = width;
    if (this.pos.y > height) this.pos.y = 0;
    if (this.pos.y < 0) this.pos.y = height;
    this.updatePrev();
  }
}

class CircleShape extends BaseShape {
  display() {
    super.display();
    ellipse(0, 0, this.size);
    super.finish();
  }
}

class SquareShape extends BaseShape {
  display() {
    super.display();
    square(-this.size / 2, -this.size / 2, this.size);
    super.finish();
  }
}

class TriangleShape extends BaseShape {
  display() {
    super.display();
    triangle(
      -this.size / 2, this.size / 2,
      this.size / 2, this.size / 2,
      0, -this.size / 2
    );
    super.finish();
  }
}

Challenges

I spent a lot of time getting a grasp of noise functions and how to use them to mimic natural movements for my shapes and implement the flow field using Perlin noise. There was considerable time spent adjusting the noise-generating settings to produce a smooth, organic flow that seemed natural.

There was a small challenge to clear the canvas after a certain amount of frames. The logic of the code was fine however the previous shapes were not removed.

Reflections and Improvements

The overall experience was quite helpful. I learned to handle the different functions and classes using object-oriented programming concepts. It made it possible to use a modular. It even helped me to add more features to my code as I was creating my art piece.

I believe that there is one area of development where I could explore various noise offsets and scales to create even more varied flow fields. Playing around with these parameters might result in more complex and eye-catching visual effects.

References

I learned about flow fields through the resources provided to us. I discovered a YouTube channel, “The Coding Train“.

Raya Tabassum: Reading Response 1

Reas navigates through the historical and contemporary landscapes where chance operations have been utilized, underscoring the balance between unpredictability and control, chaos and order.
The concept of employing randomness in art is not new; it traces back to various movements and disciplines, including Dadaism’s use of arbitrary methods to challenge artistic norms and John Cage’s explorations in music that embraced indeterminacy. Reas’ talk prompts one to question: How do these historical instances of chance operations inform and enrich our current understanding of randomness in digital art?
Reas’ emphasis on the symbiosis between order and chaos, particularly in the realm of digital arts, brings to light the nuanced dynamics of control. The artist, through the use of algorithms and computational methods, sets the stage for randomness, yet within predefined constraints. This paradoxical relationship invites reflection on the nature of creativity itself. Is true creativity found in the meticulous planning and execution of an idea, or does it emerge from the serendipitous encounters with the unexpected? The talk challenges one to consider the role of the artist in the digital age: Are they the orchestrators of chaos, the curators of randomness, or simply collaborators with the computational processes they employ?
In conclusion, Casey Reas’ talk on chance operations serves as a profound catalyst for reflection on the intersections between art, technology, and randomness. It compels one to reconsider not just the methodologies of artistic creation but the very essence of creativity and its manifestations in the digital age.

Assignment 2: Ellipses

Loops… I wasn’t really sure how I could use a for, or while loop when the draw() function is itself a loop anyways. My previous experience with programming (which isn’t much) has taught me using for, or while loops in sorting algorithms but I didn’t know where to use loops when drawing an image in p5js. In any case, I looked through the magazines to see if there was anything I felt I could do.

 

When I saw the image above, I immediately began to think about how I could create it in p5js. I knew I could use ellipses to create what, in the image, looks rings around a tube. I also knew  that by making the background black, making the outline of the ellipses white, and removing the fill of the ellipses it could look almost exactly like the image. The only problem was that I didn’t really know how to make the shape without hardcoding all the values. So, instead of hardcoding all the x-coordinate, y-coordinate, width, and height values of all the ellipses I realized I could use a for loop.

When first testing out the idea I made a class and an array and made variables of that class which I put in the array and was just testing to see what worked and what didn’t since I wasn’t familiar with the syntax. In hindsight, I didn’t need to use a class or an array but it was good practice nonetheless. In any case, I ended up with the code below:

for (let i = 0; i < ellipseArray.length; i++) {
    
    
    let something = map(i, 0, ellipseArray.length, -1, 1);

    w = map(tan(frameCount * something * 0.025), -1, 1, 0, 100);

    y = map(i, 0, ellipseArray.length, 10, height);

    ellipseArray[i].make(width / 2 - 100, y, w, 20);

    ellipseArray[i].make(width / 2 + 100, y, w, 20);
    
    
  }

The method of the class which drew the ellipse was called make. Looking at it again I could have just had ellipse() in the place of ellipseArray[i].make … it would be easier to look at but I’ll just call it good practice. Despite that, I am happy with the code I wrote above. I was especially happy with my use of the map() function. At first I wasn’t sure how to use it, I also felt that the p5js references didn’t explain it very well but with a bit of trial and error it became obvious. I was also happy with how I used the frameCount variable to make the image move. I think it might be slightly obvious that I didn’t really know what I was doing throughout all of this as I named one of my variables something, I’m still not sure what to call it but the idea was that depending on where the ellipse was in the array it would have a different value from the tan() function.

At the end, I made the background slightly transparent so that it would leave a shadow of the previous ellipses, which I think makes a similar effect as the slightly fuzzy lines that can be seen in the image I took inspiration from.

 

Reflection

I mentioned this a few times before and it is that I should just use the ellipse() function alone rather than use a class and array to make the code more readable, and maybe even more efficient. I also think I could have added more comments to explain what each line or section did, I left most of it uncommented because I myself wasn’t sure what I was doing and was making changes fairly quickly. I feel with more practice and if I lay out my thought process with comments I can be more efficient when writing my code.

Future Ideas

For the future if I ever choose to come back to this style I could have a design where it uses a trigonometric function as I used it for this assignment but the ellipses are made around the cursor then it would look cool as you move the cursor. Also, I only varied the width of the ellipse, I could also vary both the height and width in the future.

Assignment 2, Loops

When I think of loops the first thing that comes to mind is the DVD screensaver that I used to see as a kid, a never-ending loop that managed to grab my attention until I saw the corner of the logo line up with the edge of a screen. If you still don’t know what I’m referring to, have a look at this iconic scene from the office:

I Tried to recreate the same loop using if statements, randomized the color change whenever the logo hit an edge, and redirected itself in the opposite direction by going into negatives.

I am particularly proud of this part of the code:

if (pos.x >= width – imgPos.width || pos.x < 0) {
speed.x *= -1;
getColorforImage();
}

I was intially overwhelmed by this task, however using the if statement really made it simpler, by making the image speed into the negatives to redirect and change color simultaneosly (repeated the same code for Y variable) I managed to recreate the OG dvd screensaver.

However, I did not use the for or while commands to create this loop so I started experimenting and managed to find a non traditional loop instead:

This was very surprisingly simple, although I wanted to involve more motion to the circles in the back initially, I felt content when I reached this final product. For the future, I would hope to have done something such as a color loop instead, blending or transforming colors into one another in hopes of making this loop more “traditional”, at least visually.