Week 3 – Generated Artwork

Concept:

For this week’s production assignment, we had to use arrays and object oriented programming to create a generated artwork. So, I decided to take inspiration from Van Gogh’s painting “Starry Night” (picture taken from Wikipedia) and create a similar piece using OOP. So it would basically be a night scene, with yellow and blue dotted swirls in the sky, a moon and the iconic cypress tree.

To use arrays and OOP in my artwork, I decided to make the sky “swirls” using classes, with the colours from an array. It was a bit tricky to make the classes, and I had to debug the code several times, especially when creating the instances of the class. However, the comments in the console bar and Perplexity helped me figure out what went wrong.

A part of the code I’m particularly proud of :

This is definitely the code for the class. It was a bit hard, especially because it was the first time I was trying Object Oriented Programming, so I am super proud of how the sky turned out!!

class drawSwirl {
  
 constructor(a, angle, scalar, speed, colours) {
   this.a = a;
   this.angle = angle;
   this.scalar = scalar;
   this.speed = speed;
   this.colours = colours;
 }

  draw() {
  
  var x = this.a + cos(this.angle) * this.scalar;
  var y = this.a + sin(this.angle) * this.scalar;
  fill(random(this.colours));
  stroke('#ffffc5');
  strokeWeight(0.5);
  ellipse(x, y, 5, 5);
  this.angle += this.speed;
  this.scalar += this.speed;
  
  }

}

Embedded sketch :

Challenges I faced and the room for improvement :

I could’ve definitely added some interactivity to it. The cypress tree had to be made using beginShape(), which was extremely hard, especially with so many plot points. For this, I used Geogebra to plot points, calculated them and added it in.

Overall, I’m pretty happy with result of this artwork. There are definitely some things which I could add, maybe the village in the original painting, or some form of interactivity. But I also loved the challenge of using classes, and I’m proud of the swirly sky!

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:

// // 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 3 – Functions, Arrays, and Object-Oriented Programming

Concept

In this p5.js sketch, my main objective was to practice the use of classes and arrays. In my sketch, little objects called “walkers” wander randomly across the canvas, leaving behind the trail that slowly fades away. Each walker has its properties (see below in Code Highlight part), which are determined randomly at the moment of creation (user click).

Demo (Click on canvas)

Code Highlight:

The core of this sketch is the Walker class. It encapsulates everything each walker needs to function:

// Walker class definition
class Walker {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    // Give each Walker a random color
    this.col = color(random(255), random(255), random(255));
    // Control how quickly it moves around
    this.stepSize = random(1, 3);
  }

  update() {
    // Randomly move the walker in x & y directions
    this.x += random(-this.stepSize, this.stepSize);
    this.y += random(-this.stepSize, this.stepSize);

    // Keep the walker within the canvas boundaries
    this.x = constrain(this.x, 0, width);
    this.y = constrain(this.y, 0, height);
  }

  show() {
    noStroke();
    fill(this.col);
    ellipse(this.x, this.y, 8, 8);
  }
}

Inside this class, the update() method adjusts the walker’s position in small random increments, while show() draws a small ellipse at its current location.

The background(0, 13) call in the draw() loop is also important because it uses transparency to slowly erase the walkers’ paths, creating the glowing trails of each walker (I think it looks kinda cool).

Reflection & Improvements for Future Work

First of all, it was really entertaining to watch each walker wander around, leaving a trail. By simply changing parameters like number of walkers, their step size, or fade value in the background, one could produce unique versions of this piece.

In the future, I would love to make sure that the walkers of the same color would interact with each other (mixing together and creating a bigger walker). Another interesting idea would be to incorporate music in this piece (maybe 90s like Jungle beat) -> this way each walker would change its size/movement speed/direction based on the song.

If one would think long enough, the possibilities for making this piece more immersive and dynamic are essentially limitless.

Maybe one could make a game out of this piece, who knows?

Reading Response 2 – What Exactly Is Interactivity? (Week 3)

Chris Crawford’s idea of interactivity as a conversation between two participants came as a novelty to me. Before reading this, I assumed that any program that reacted to user input was interactive in its nature, but after reading this I was convinced that an interactive system must possess these three elements; listening, thinking and responding/speaking. 

I feel like Crawford’s example of the refrigerator light was brilliant, it made me rethink what it means for a system to be truly interactive. I began examining the apps and websites I use every day and noticed that many of them only react to user input without actually processing information in a meaningful way. They operate on predefined rules, responding to clicks and taps but not truly engaging with the user. This made me question whether these systems, despite their responsiveness, can really be considered interactive in the way Crawford describes. 

This reading also made me reflect on how I can make my own p5 sketches feel more interactive. Right now, they mostly respond to simple inputs like mouse clicks, but what if I could design interactions that feel more like a two-way conversation?

Instead of just reacting instantly, the system could analyze patterns in user input, adapt its responses based on context, or even introduce an element of unpredictability to keep the interaction dynamic. For example, it could recognize different drawing styles over time and subtly adjust its behavior to match the user’s preferences. Of course, achieving this level of interactivity would likely require more advanced tools than p5.js (Maybe use of LLMs/AI).

I would love to create something beyond basic cause-and-effect responses and explore ways to create a more engaging.

Week 2 – Reading response

How are you planning to incorporate random elements into your work?

Well, I myself have am not used to the idea of producing something random, although there is beauty in the idea of randomness it’s not as alluring as the idea of systematic approach. When it’s random, it’s likely only to be produced once like that and twice if you can beat the odds. Although Casey, with in the video showed how these random elements can prove to not only provide an unique appearance, he also presents its limitations on how once done can’t be done agin, the idea of having to repeat a process to hopefully create something similar can be infuriating, but also fascinating as the random elements could go beyond expectation or never reach the expectations sent. I intend to incorporate this kind of thinking into future works, I might not be happy in the beginning due to my rigid thinking but over time I could change and will change in how to balance the randomness that can only produced once and the control of the scope in which it happens.

Where do you feel is the optimum balance between total randomness and complete control?

I think that when theres a start of a systematic approach too randomness. All randomness has to be born with in a confined space, whether by the laws of science that govern the way things move or how systems have an algorithm that will produce a random sequence based off the a equation thats been written before hand. You can’t escape, it but you can confine it with in a space. Like a science experiment you might have the tools, and test it out and then an outcome that works. You have your controlled variables and uncontrolled variables. Sometimes we are the uncontrolled variables but our way of thinking is the controlled variable. The way we move and do things, the laws of the universe these are controlled, set in stone in that moment, but once we release it without being able to calculate or speculate the outcome it then becomes random.

Week 2 Assignment

Introduction:

While looking through the same art, I thought that its actually far from what I could create at least at this point. I wanted it to simple yet something that reminds me of home. I ended up then thinking about what makes home, home? Was it the people that I missed? Was it the seas and mountains? Was it the seasons? Well, it was a bit of everything, the way the mountain changed its vegetation across the seasons, the way I’d travel to those mountains with those very precious people. The way the seasons or the feel of the seasons could not be replicated here with in the UAE.

Concept:

My concept for the post had to do with mountains and seasons. The reflection on something not season as clearly or with in the country as abundantly as my own country. I didn’t really use any references from the document but it’s essence rather gave me something I’d rather implement.

 

Production and Completion:

Although I had to go through many trials, like getting the color scheme, the clouds, the sun and moon, the mountains, as well as the time switch to show the seasons. I wasn’t satisfied, because I had a dream of how it should have made me felt. I hadn’t gotten close but I had gotten somewhere, starting with what can represent the seasons? the time? The way things change. If you look at the code you will notice that the frame rate changes at about every 3 seconds like the months. The sun changes into the after 1.6 seconds and the moon to the sun at 0.8 seconds, match 16 hours of sun and 8 hours of moon.

 

let sunAngle = 0;
let showMoon = false;
let seasonProgress = 0;
let currentSeason = "spring";
let mountainProgress = 0;
let seasons = ["spring", "summer", "autumn", "winter"];
let brushColors;
let icons = [];
let clouds = [];

function setup() {
    createCanvas(800, 600);
    brushColors = [
        color(139, 69, 19),  // Brown (Autumn)
        color(34, 139, 34),  // Green (Spring)
        color(255, 165, 0),  // Yellow-orange (Summer)
        color(173, 216, 230) // **Distinctive icy blue for Winter**
    ];
    frameRate(30);
    generateIcons();
    generateClouds();
}

function draw() {
    if (currentSeason === "spring") {
        background(144, 238, 144);
    } else if (currentSeason === "summer") {
        background(255, 223, 186);
    } else if (currentSeason === "autumn") {
        background(255, 165, 0);
    } else if (currentSeason === "winter") {
        background(100, 150, 200); // **Deeper Frost Blue for Winter**
    }

    drawMountain();
    drawClouds();
    if (!showMoon) {
        drawSun();
    } else {
        drawMoon();
    }
    displayIcons();
    updateIcons();
    updateClouds();

    if (frameCount % 90 === 0) {
        changeSeason();
        generateIcons();
    }
}

function drawMountain() {
    let layerHeight = 50;
    let numLayers = 6;
    for (let i = 0; i < numLayers; i++) {
        let layerColor = getMountainColor(i);
        stroke(layerColor);
        strokeWeight(15 + (sin(mountainProgress + i * 0.5) * 5));
        noFill();
        beginShape();
        for (let x = 0; x < width; x++) {
            let y = sin(x * 0.02 + mountainProgress + i * 0.5) * (100 + i * layerHeight) + 400;
            vertex(x, y);
        }
        endShape();
    }
    mountainProgress += 0.02;
}

function getMountainColor(layerIndex) {
    let seasonIndex = seasons.indexOf(currentSeason);
    if (currentSeason === "spring") {
        return lerpColor(brushColors[1], color(255, 255, 255), layerIndex * 0.1);
    } else if (currentSeason === "summer") {
        return lerpColor(brushColors[2], color(255, 255, 255), layerIndex * 0.1);
    } else if (currentSeason === "autumn") {
        return lerpColor(brushColors[0], color(255, 255, 255), layerIndex * 0.1);
    } else if (currentSeason === "winter") {
        return lerpColor(brushColors[3], color(255, 255, 255), layerIndex * 0.2); // **Stronger white contrast for winter**
    }
}

function drawSun() {
    fill(255, 204, 0, 150);
    noStroke();
    let size = 100 + sin(sunAngle) * 30;
    ellipse(650, 100, size, size);
    sunAngle += 0.02;

    if (sunAngle > TWO_PI) {
        sunAngle = 0;
        showMoon = true;
    }
}

function drawMoon() {
    let moonSize = map(sin(frameCount * 0.1), -1, 1, 50, 100);
    fill(255, 255, 255, 150);
    noStroke();
    ellipse(650, 100, moonSize, moonSize);
    if (frameCount % 24 === 0) {
        showMoon = false;
    }
}

function changeSeason() {
    let nextSeasonIndex = (seasons.indexOf(currentSeason) + 1) % seasons.length;
    currentSeason = seasons[nextSeasonIndex];
    generateClouds();
}

function generateIcons() {
    icons = [];
    let iconSymbol = "";
    if (currentSeason === "spring") {
        iconSymbol = "🌸";
    } else if (currentSeason === "summer") {
        iconSymbol = "☀️";
    } else if (currentSeason === "autumn") {
        iconSymbol = "🍂";
    } else if (currentSeason === "winter") {
        iconSymbol = "❄️";
    }
    for (let i = 0; i < 5; i++) {
        icons.push({
            x: random(width),
            y: random(100, 300),
            speed: random(0.2, 0.5),
            symbol: iconSymbol
        });
    }
}

function updateIcons() {
    for (let icon of icons) {
        icon.y += icon.speed;
        if (icon.y > height) {
            icon.y = random(100, 300);
        }
    }
}

function displayIcons() {
    textSize(32);
    textAlign(CENTER, CENTER);
    for (let icon of icons) {
        text(icon.symbol, icon.x, icon.y);
    }
}

function generateClouds() {
    clouds = [];
    for (let i = 0; i < 6; i++) {
        clouds.push({
            x: random(width),
            y: random(50, 200),
            size: random(60, 100),
            opacity: random(100, 200),
            speed: random(0.5, 1.5)
        });
    }
}

function drawClouds() {
    for (let cloud of clouds) {
        fill(255, 255, 255, cloud.opacity);
        noStroke();
        ellipse(cloud.x, cloud.y, cloud.size, cloud.size * 0.6);
        ellipse(cloud.x + 30, cloud.y, cloud.size * 0.8, cloud.size * 0.5);
        ellipse(cloud.x - 30, cloud.y, cloud.size * 0.9, cloud.size * 0.6);
    }
}

function updateClouds() {
    for (let cloud of clouds) {
        cloud.x += cloud.speed;
        cloud.size += sin(frameCount * 0.01) * 0.5;
        cloud.opacity = map(sin(frameCount * 0.01), -1, 1, 100, 200);
        if (cloud.x > width + 50) {
            cloud.x = -50;
            cloud.y = random(50, 200);
        }
    }
}

Sketch:

Improvements:

I think I can improve a lot with more dynamic visuals and smoother transitions. I will try to include more user interaction that can allow them to do more than just have a ‘watch’ experience. They should be able to have ‘active’ experience as a participant. I could include sounds that mimic the ambiance achieved in  places in South African to make it further immersive.

 

Reading Reflection: Week #3

In “The Art of Interactive Design” interactivity is defined as “a cyclic process in which two actors alternately listen, think, and speak”.  This approach suggests that the quality of interaction depends on the effectiveness of each subtask. It seems to me then that a strongly interactive system is great in perceiving input, processing it meaningfully, and providing feedback right on time, creating a conversation between user and system.

In my opinion, to create a better user interaction involvement, the artist should be designing elements that not only react to user inputs but also adapt and evolve based on user behavior. For example, incorporating real-time feedback mechanisms can make the interaction feel more engaging.

Apart from that, allowing for user customization and providing clear and simple visual cues can guide users through the interactive experience. This aligns with Crawford’s vision of interactive design as an art form creating meaningful digital exchanges, where the interaction feels like a real conversation between the user and the digital environment.

Reading Reflection – Week 3

I appreciate that Crawford made the differentiation between reaction, participation and interaction. I may or may not have used reaction and interaction to mean the same things before, and now I know to do better 😉. I also liked the point that he made about interactivity existing on a continuum, rather than as a binary property, which in turn allows people to approach it in a subjective manner. In the web that we know today, interactivity exists in some form or another and in varying magnitudes, from the use of simple buttons to complex reciprocal elements. And those that incorporate interactions in meaningful and interesting ways capture attention and attract user traffic. So in this way, one could argue that there now exists a certain threshold for interactivity that applications on the web have to meet to ensure the work gets to the audience.

Building on top of Crawford’s definition of interaction – a cyclic process in which two actors alternately listen (input), think (process), and speak (output) – I think a strongly interactive system could be one that has exposed to the user multiple areas for sending input, listens carefully through those channels, and once it receives input, reciprocates by sending back a meaningful response that satisfies its purpose. It is important that the “speaking” part of the cycle conforms or relates to the “listening” and that it’s not just gibberish; if I ask a local person for directions to the Eiffel Tower in French, I expect exactly what I asked for, and not, for instance, directions to the Shibuya crossing in Japanese. In other words, it is not sufficient to just have all three segments of the cycle present for a system to be strongly interactive, and the content and quality of each is just as important in ensuring user satisfaction.

Week 2 – Reading Response

After watching Casey Reas talk about randomness, it got me thinking about how I usually approach design. When working I’ve always been about control, and making sure every element has a purpose and fits just right. But Reas kind of pushed me to reflect on how it’s not about giving up control but rather just letting a little unpredictability into the process to keep things from becoming flat and boring. When things are too ordered, they lose their spark and this idea made me realize that maybe I’ve been too focused on precision and could benefit from creating space for randomness to breathe a little life into the work im making. I’m now thinking of ways to incorporate small random elements, like little shifts in color, shape, or spacing, so that my designs feel alive without losing the structured feel I love.

As for the balance between randomness and control, I think it’s about finding that perfect place where the two can interact with each other.  Things that are too rigid can become very static, while too much randomness can feel directionless. In my opinion the perfect balance happens when you have a solid structure but let randomness subtly influence the details. Whether it’s adjusting spacing, throwing in a surprise texture, or letting a color shift unexpectedly, it makes the work feel slightly more dynamic. The goal isn’t to pick one or the other but to let control and randomness work together to create something that keeps the viewer engaged and constantly evolving.