For this artwork, I wanted to use the ball example that we did in class and talked about. I wanted to take the basic idea and make it more interactive by giving the user more ways to interact with the artwork. Basically, when the user presses the screen, a new ball is created at the position where they clicked. Each ball has its own different properties, such as its speed, size, gravity, bounce, and color. Because these properties are randomly generated, every ball is slightly different from the others. I also added another interaction where the user can press C to change the color of all the balls. This makes the artwork change even after the balls have already been created. I wanted the artwork to feel like something the user is creating themselves rather than something that is completely automatic.
References and Inspiration
I first got my idea from this video from The Coding Train: [LINK]. I liked the concept of creating and moving objects, and I wanted to use a similar idea but add more interactivity to it. I also used the W3Schools website to understand more about arrays and references and to learn about things that I could use to improve my Object-Oriented Programming: [LINK][LINK].
Code
//array for balls
let balls = [];
function setup() {
createCanvas(500, 500);
}
function draw() {
background(240);
//some instructions
fill(0, 0, 0, 40);
textAlign(CENTER);
textSize(16);
text("Click the screen to create a ball!", 250, 30);
textSize(10);
text("Press C to change color", 250, 60);
line(0, 450, 500, 450);
// Update every ball in the array
for (let ball of balls) {
ball.update();
ball.display();
}
}
// Click the mouse to create a new ball
function mousePressed() {
let newBall = new Ball(mouseX, mouseY);
balls.push(newBall);
console.log("New ball:", newBall.color, newBall.speed);
}
// Press C to change the color of all the balls
function keyPressed() {
if (key == 'c' || key == 'C') {
for (let ball of balls) {
ball.changeColor();
}
}
}
//Ball Class
class Ball {
constructor(x, y) {
this.x = x;
this.y = y;
this.size = random(20, 60);
this.speed = 0;
this.gravity = random(0.1, 0.3);
this.bounce = random(0.85, 0.95);
this.color = color(
random(255),
random(255),
random(255),
128
);
}
//updates the balls movements
update() {
this.speed = this.speed + this.gravity;
this.y = this.y + this.speed;
if (this.y + this.size / 2 >= 450) {
this.y = 450 - this.size / 2;
this.speed = -this.speed * this.bounce;
}
}
display() {
noStroke();
fill(this.color);
circle(this.x, this.y, this.size);
}
//change the color of the ball
changeColor() {
this.color = color(
random(255),
random(255),
random(255),
128
);
}
}
Embedded Sketch
Problems I Ran Into
One of the main things I had to figure out was how to make every ball have its own properties while still using the same Ball class. I solved this by giving each new ball random values for its size, gravity, bounce, speed, and color inside the constructor. I also had to figure out how to change the color of all the balls at the same time. Since all of the balls are stored inside an array, I used a loop to go through every ball and call the changeColor() function when the user presses C. Another part I had to understand was how the balls could keep updating and displaying themselves while being stored in the array. I used the update() and display() functions for this, which made the code more organized.
For this week’s generative artwork, I decided to create a fireworks effect. The idea was inspired by something that happened recently back home in Fiji. My home football team, Ba FA, won the league, and my dad was showing me videos of the fireworks that were happening that night to celebrate the win. With that in mind, I thought it would be interesting to create my own digital version of fireworks using p5.js.
I wanted the artwork to feel active and unpredictable, so instead of having the fireworks appear in the exact same way every time, I used randomness to control their position, size, colour, and speed. I also added a mouse interaction so the user can click anywhere on the canvas to create a firework.
Code I Am Proud Of
The part of my code that I am most proud of is how I implemented the Firework class and made each firework have its own properties. Doing object oriented programming particularly in p5.js was new to me but with the help of Coding Train tutorials, I managed to pull this off. Each firework has its own position, size, maximum size, colour, and speed. This allowed me to create multiple fireworks that behave slightly differently from each other.
// Firework Class
class Firework {
constructor(x, y) {
this.x = x;
this.y = y;
// Starting size and the maximum size of the firework
this.size = 5;
this.maxSize = random(40, 100);
// Random color for the firework
this.r = random(100, 255);
this.g = random(100, 255);
this.b = random(100, 255);
// For random speed of the fireworks
this.speed = random(0.5, 2);
}
// Method for making the firework bigger
update() {
this.size += this.speed;
}
// Method for displaying the firework
display() {
noFill();
stroke(this.r, this.g, this.b);
strokeWeight(3);
circle(this.x, this.y, this.size);
// Small center of the firework
fill(this.r, this.g, this.b);
noStroke();
circle(this.x, this.y, 5);
}
// Returns true when the firework reaches its maximum size, otherwise false
finished() {
return this.size >= this.maxSize;
}
I am also really proud of how I made the fireworks finish and then get removed from the array. I used a finished() method to check when a firework reaches its maximum size:
function draw() {
// Goes backwards through the array and removes any fireworks that have finished
for (let i = fireworks.length - 1; i >= 0; i--) {
if (fireworks[i].finished()) {
fireworks.splice(i, 1);
}
}
}
This part took me quite a while to figure out. I initially found it really tough to remove fireworks from the array while also going through the array. I eventually realized that I could go through the array backwards. This allows me to safely remove a firework . The finished method checks whether the firework has reached its maximum size. Once it has, the loop removes it from the array.
Implementation
I used an array called fireworks to store all of the firework objects. New fireworks are automatically created at random positions, and the user can also create one by clicking on the canvas.
I also used a transparent background to create the fading effect: background(10, 10, 30, 25);
The 25 is the alpha value, so the background is partially transparent rather than completely covering the previous frame. This allows parts of the previous frames to remain visible and gradually fade away, creating a trail effect behind the fireworks.
I also used random() throughout the program so that the fireworks do not all look or behave exactly the same. Their colours, speeds, maximum sizes, and positions can all be different, which makes the artwork generative.
Reflection
I enjoyed making this artwork because I was able to connect a personal experience from home with what I have been learning in p5.js. It also helped me understand object-oriented programming and arrays better.
The most challenging part was figuring out how to remove finished fireworks from the array. I initially found this confusing, but going through the array backwards and using splice() helped me understand better how fireworks with different speeds that finish at different times can be removed correctly.
If I were to improve this artwork in the future, I would like to make the fireworks look more realistic by adding individual particles that explode outward instead of just making the circle grow. I would also like to experiment with different shapes, sounds, and more mouse interactions to make the celebration feel more dynamic.
The idea came from jet skiing, which I do casually, so I already had a clear picture in my head of what the water looks like from the seat, the way the surface keeps moving underneath you and the horizon never sits still. I also took inspiration from the car example that was posted for the class. That example uses a simple object moving across the screen against a background, and I used the same basic structure here, but replaced the car with a jet ski and the road with a moving sea.
I extended the idea in two ways. The first is the water itself; instead of one flat background, the ocean is built from four Wave objects stored in an array, each one drawn lower, darker and moving at a slightly different speed. Drawing them in order means the closer waves cover the ones behind, which gives a sense of depth, and the topmost wave doubles as the horizon so the sky meets the sea along a curve rather than a straight line. The second addition is time of day. Clicking the canvas switches the whole scene between daytime and nighttime, changing the sky and water colours and swapping the sun for a crescent moon with stars behind it. I wanted the piece to have more than one state so there was a reason for the viewer to interact with it rather than just watch it.
How it was made
The sketch is built from four classes: Wave handles one band of water, Bubble is a small circle that floats upwards, Star is a dot in the sky, and Jet ski draws the craft and its rider. Each class stores its own values in the constructor and has its own move and display methods, so the draw function stays short; it just loops through the arrays and tells each object to move and draw itself.
The objects are created once in setup using for loops and stored in three arrays: waves, bubbles and stars. Doing it this way means I can change how busy the scene is by editing a single number. Asking for seventy stars instead of twenty is one character in a loop condition, not seventy lines of code, and this is the main reason the program uses objects and arrays.
The most important part of the code
beginShape();
vertex(0, height);
for (let x = 0; x <= width; x += 10) {
vertex(x, this.y + sin(x * 0.02 + this.offset) * this.waveHeight);
}
vertex(width, height);
endShape(CLOSE);
This builds one wave as a single filled shape. The loop walks across the canvas and places a point every ten pixels. The height of each point comes from sin, which rises and falls smoothly between -1 and 1, so multiplying it by the wave height turns that into a rise and fall measured in pixels. Adding the offset shifts where the curve starts, and because the move method increases that offset a little every frame, the whole wave appears to travel sideways. The two extra vertex calls at the bottom corners close the shape off so it fills downwards instead of being just a line.
What makes this the key part is that everything else in the artwork depends on it. Each Wave object is given its own wave height, speed and starting offset, so the same six lines produce four waves that all look different and move at different rates. That difference in speed is what creates the sense of depth, since the nearer waves move faster than the ones further away. Without this one piece of code the scene would just be flat blocks of color.
Reflection
The hardest part of this project was not writing the classes themselves but getting the layers to sit correctly on top of each other. My first version drew the sky as a plain rectangle ending at a fixed height, and the result looked wrong straight away; there was a hard straight line cutting across the middle of the canvas where the sky stopped, which broke the illusion completely. I fixed this by changing how the background is built. Instead of drawing a sky rectangle and a water rectangle, the sky color now fills the entire canvas and the waves are drawn over the bottom half of it, with the topmost wave acting as the horizon. Because that wave is made with sin like all the others, the edge between the sky and the sea is a curve rather than a straight line, and the whole scene reads as one thing instead of two blocks stacked on top of each other.
Looking back, most of my difficulties were about order and timing rather than logic; which order things are drawn in, when the canvas gets cleared, and when an object is moved relative to when it is visible. The classes and arrays were the straightforward part once I understood that a class is written once and an object is created from it many times. If I were to take this further I would like the jet ski to actually sit on the surface of the wave and tilt with it, rather than bobbing independently, since that is the one part of the scene that still gives away that the jet ski and the water are not really connected.
I really liked this text because of the way Crawford approaches interactivity as a whole and gives it a more three-dimensional aspect. I especially liked how he shows that there are different levels of interactivity, from low to high rather than treating something as simply interactive or not interactive. I think this gives a clearer way of understanding interactivity. Based on Crawford’s idea of listening, thinking and speaking, I think a strongly interactive system should have all three, but I would consider thinking and speaking especially important. The more the user can think, make decisions and respond to the system through their actions, the more interactive the object becomes. At the same time the system should listen and respond to what the user is doing. I also think a strong interactive system should give the user something back, whether that is learning something new, being influenced by the system or simply having fun.
When I think about my own p5 sketches, I feel like they suffer from a lack of interactivity because they sometimes fall into the same kind of low interaction Crawford describes with his refrigerator example. Usually, the interaction is limited to following a rule, such as pressing a button to see something else or moving the cursor to see a new colour. I could improve my p5 sketches by moving away from simple mouse clicks and allowing the system to respond differently based on what the user has already done. For example, instead of choosing colours randomly from a fixed array, the sketch could remember previous interactions and use that information to create different responses. This would make the system feel more responsive rather than just random. I also want to experiment with more complicated forms of interaction such as storing information from the users previous actions. Overall, this reading made me think about interactivity as more than just making something respond to the user. It made me think about whether the system is actually listening, thinking and responding in a way that gives the user a reason to continue interacting with it.
I think that a strongly interactive system is one where the user feels involved and where there is a continuous exchange between the user and the system. Crawford describes interaction as a process where two actors “listen, think, and speak.” I found this interesting because it means that a system should not just react to an action, but should take the user’s input, process it, and then respond in a meaningful way. This makes the interaction feel more like a conversation between the user and the system. Based on the examples given by Crawford, I understood that a strongly interactive system needs all three parts working together, not just one or two of them.
For improving the degree of user interaction in my p5.js sketches, I could make the system behave according to the user’s actions. For example, I could add mouse functionalities where objects change depending on where the user moves the mouse or what they click on. I could also use keyboard inputs to let the user control different parts of the sketch. Instead of having the same response every time, I could make the sketch respond differently depending on the user’s actions. This would make the user feel like they have more control over what happens.
In the future, I would like to make these interactions more complex and meaningful. Animations or transitions could be added to make it clear how a specific user action led to a specific outcome. I could also make the system remember previous user actions and use them to affect what happens later, such as in a game where the user’s previous choices change the experience. This would make my sketches feel less like animations that the user is simply watching and more like interactive systems where the user and the program are continuously responding to each other.
For this OOP project, since I have never done this before, I just wanted to test if I understand the class, the constructor, the array, and how to push new items into an array, and so I decided to create some “atoms” that bounce around in the canvas.
They are called atoms, because my original concept that I wanted to make was atoms, that are red and are following a certain path on the screen but it got lost in translation, and started to look more like confetti, so I decided to leave it for that day.
I have astigmatism, which just means that especially in the dark light sources seem a little weird (the photo demonstrates it better) and weirdly, I got inspired by that on Saturday, when I was with a friend out at night. I think the balls in the end were just much easier to make than those lights that I usually see, but it just clicked something in my brain. So I moved on from my initial idea and started to work on something else.
The concept that I used in the end was kind of a mixture of the two: I made some ellipses that are going around but not on a predetermined route but randomly, and from my astigmatism came the idea to make them almost vibrating and very very colourful.
The Code
(click on the canvas as many times as you want)
So the code was very hard to do, and I was struggling a lot with it not working. To start with, I created the basics, I made an array to store my atoms in, and then in the draw function I made a for loop to loop that array and its elements. In the for loop, there are three other functions that I am going to explain later in the class.
let atoms = []; //setting the array
function setup() {
createCanvas(400, 400);
}
function draw() {
background('black');
//for loop goes throught the array, checks the index of each element and displays all of them
for (let i = 0; i < atoms.length; i++){
//called function from class, updates their position
atoms[i].atomMotion();
//called function from class, determining how the atoms look like
atoms[i].display();
//called function from class, recognising the borders of the screen
atoms[i].checkEdge();
}
}
After this, I made a mouseClicked function to add elements to my array. I tried to explain what it does inside of the code.
//when mouse is clicked a new atom will appear at the point of click, in the this.x and this.y the coordinates of the click get saved for that specific new atom as the mouseX and mouseY coordinated were given for the new one, and then the new atom gets pushed into the array with a new index (i)
function mouseClicked(){
atoms.push(new Atom(mouseX, mouseY));
}
And then I created the Atom class. I wanted to make it fun, so I added randomisation to quite a few attributes of the atoms, such as their diameter and how fast they will be moving around the screen. I decided to name their attributes only x and y because any other name just confused me, since these are referring to where the mouse was clicked and so where the atom formed.
class Atom{
//x and y are defined as the coordinates of center of the atom, the mouse position at the time of the click, and so each atoms gets assigned that value at the start
constructor(x, y){
this.x = x;
this.y = y;
//each atom gets assigned a random diameter
this.diameter = random(10, 80);
//each atom gets assigned a random speed
this.velocityX = random(-4, 4);
this.velocityY = random(-4, 4);
}
After this was the hardest part of the whole code, but also what I am most proud of because I wanted them to not move out of the canvas, so I had to make them bounce back from the walls. To do this I needed some videos explaining to me the “science behind it”, for example, how to change the atoms’ motion once they detect the sides of the canvas: in the end I ended up multiplied their current velocity with -1 to reverse them back once they detected the edge. I also had to understand HOW it can detect the edge, but once I saw a video about it I understood and made my own code.
Basically what I did, is I divided the (randomly) assigned diameter of each atom to get the radius of each. The this.x and this.y are the midpoints of the atoms, so I checked if their leftmost and top points (so the midpoint minus the radius) are < 0, so past the canvas’ borders. (this is the example of the left side’s code)
The second part of the if statement snaps the atoms back to the canvas in case they moved too fast and went a few pixels out of frame by putting their midpoint back at where they used to be. This was what took me a very long time, because sometimes they would just glitch into the wall. And lastly came the switching direction.
The else if statements do the exact same thing, with the only difference that they check the rightmost and the bottom parts, that is why here the radius is plus not minus.
Here is the full code of the bouncing:
checkEdge(){
let radius = this.diameter / 2;
//first it checks the LEFT side, if the leftmost edge of the ball (center minus its radius) reaches x = 0, so the left side of the screen, it snaps it back, and then reverses the direction
if (this.x - radius < 0) {
this.x = radius,
this.velocityX *= -1;
}
//first else if checks the RIGHT side the same way
else if (this.x + radius > width) {
this.x = width - radius;
this.velocityX *= -1;
console.log('this works');
}
//second if checks the TOP of the screen the same way
if (this.y - radius < 0) {
this.y = radius;
this.velocityY *= -1;
}
//second else if checks the BOTTOM of the screen the same way
else if (this.y + radius > height) {
this.y = height - radius;
this.velocityY *= -1;
console.log('this works too');
}
}
After this was relatively easy to finish the code. I am lying though a little, because I finished this earlier than I did the previous checkEdge part. But regardless, this part I was able to relatively quickly. Most of hówhat I did is explained in the code itself.
But just to add on a litte, I love playing with the random function, so I also decided to make the colours and oppacity of the atoms randomised, and so they no longer look like atoms but confetti. However, at this point I had too many functions and variables connected to and named atom that I didn’t dare change anything.
//this function updtaes the atoms' position after the click has happened, and the new atom is added to the array, its temporary position, so the one saved into the this.x and this.y parameters gets added to a randomised velocity value give above
atomMotion(){
this.x = this.x + this.velocityX;
this.y = this.y + this.velocityY;
}
//defines how the atoms actually look on the screen, and updates it every time
display(){
noStroke();
//fills in the circles, but the colours and the transparency is randomised
fill(random(0, 255), random(0, 255), random(0, 255), random(90, 200));
//actually drawing the ellipse or circle
ellipse(this.x, this.y, this.diameter, this.diameter);
}
}
And lastly here is the full code in one:
let atoms = []; //setting the array
function setup() {
createCanvas(400, 400);
}
function draw() {
background('black');
//for loop goes throught the array, checks the index of each element and displays all of them
for (let i = 0; i < atoms.length; i++){
//called function from class, updates their position
atoms[i].move();
//called function from class, determining how the atoms look like
atoms[i].show();
//called function from class, recognising the borders of the screen
atoms[i].checkEdge();
}
}
//when mouse is clicked a new atom will appear at the point of click, in the this.x and this.y the coordinates of the click get saved for that specific new atom as the mouseX and mouseY coordinated were given for the new one, and then the new atom gets pushed into the array with a new index (i)
function mouseClicked(){
atoms.push(new Atom(mouseX, mouseY));
}
class Atom{
//x and y are defined as the coordinates of center of the atom, the mouse position at the time of the click, and so each atoms gets assigned that value at the start
constructor(x, y){
this.x = x;
this.y = y;
//each atom gets assigned a random diameter
this.diameter = random(10, 80);
//each atom gets assigned a random speed
this.velocityX = random(-4, 4);
this.velocityY = random(-4, 4);
}
checkEdge(){
let radius = this.diameter / 2;
//first if checks the LEft side, if the leftmost edge if the ball (center minus its radius) reaches x = 0, so the left side of the screen, it snaps it back, and then reverses the direction
if (this.x - radius < 0) {
this.x = radius,
this.velocityX *= -1;
}
//first else if checks the RIGHT side the same way
else if (this.x + radius > width) {
this.x = width - radius;
this.velocityX *= -1;
console.log('this works');
}
//second if checks the TOP of the screen the same way
if (this.y - radius < 0) {
this.y = radius;
this.velocityY *= -1;
}
//second else if checks the BOTTOM of the screen the same way
else if (this.y + radius > height) {
this.y = height - radius;
this.velocityY *= -1;
console.log('this works too');
}
}
//this function updtaes the atoms' position after the click has happened, and the new atom is added to the array, its temporary position, so the one saved into the this.x and this.y parameters gets added to a randomised velocity value give above
move (){
this.x = this.x + this.velocityX;
this.y = this.y + this.velocityY;
}
//defines how the atoms actually look on the screen, and updates it every time
show (){
noStroke();
//fills in the circles, but the colours and the transparency is randomised
fill(random(0, 255), random(0, 255), random(0, 255), random(90, 200));
//actually drawing the ellipse or circle
ellipse(this.x, this.y, this.diameter, this.diameter);
}
}
Problems
Problems I ran into in the code was mainy with the bouncing: in the beginning it wouldn’t work, then it worked but only on two sides, then only on three and all atoms disappeared on the bottom, but in the end I did manage to make it all work. It also glitched sometimes into the wall.
I think I have already mentioned this, but the main problems I ran into were that I needed to catch up on the elements of a class, of OOP as a whole, and I didn’t realise this until AFTER I started working on the code, so I had to pause and watch some tutorials and explaining videos.
References:
I got the main idea from this video:
These two helped to understand the bouncing technique more:
Helped to understand how to push an object into array:
I think a strongly interactive system has to respond quickly and meaningfully to whatever the user does. Speed matters a lot, because if there is a noticeable delay between my action and the system’s reaction, the loop breaks and it stops feeling like a conversation. It should also accept a wide range of inputs rather than just one, and produce output that is fun and exciting to receive: sound effects, motion, color, and visuals that reward the user for engaging. Using Crawford’s framework, a strong system has to do all three steps well. It has to listen properly by capturing what the user is actually doing, think by shaping its response to that input rather than repeating itself, and speak clearly so the user can tell their action caused the result. Reliability belongs here too, since bugs and crashes break the cycle completely and a system that stops responding has stopped interacting altogether.
The other characteristic is the user’s own willingness to explore. Someone eager to poke at a system will have a far richer experience than someone who isn’t in the mood, even with identical software. A good system invites exploration by making its possibilities visible and by rewarding the first thing the user tries, which is what pulls them into trying the second.
For my own p5 sketches, my main idea is to widen the range of inputs they accept. At the moment I rely on a narrow set, so I want to make more use of the cursor; not just clicking, but position, speed, and dragging, so the sketch is continuously responding rather than waiting for one discrete event. I also want to use clicks to transform the artwork, so that each click shifts the sketch into a different look or state and gives the user a reason to keep going. Beyond that, I would like to experiment with 3D, since being able to rotate and look around a shape hands the user real control rather than just something to look at, and to play with motion that reacts to the user instead of looping on its own; if the direction or speed of movement responds to where the cursor is, the sketch is listening continuously instead of just performing.
After reading the chapter, I kind of agree with the author’s definition of interactivity, and I liked how he used conversation as an example. I also think the author put into consideration the different perspectives on what interactivity means. I understand why some definitions may seem subjective because people find it easier to relate one meaning to another word, but by doing that, the meaning can become more vague and less accurate. This can cause people to misunderstand or misuse the word in different contexts.
One of the things that grabbed my attention was the difference between reaction and interaction. A reaction is more of one action responding to another action, while there is no real ongoing exchange between the two. For instance, the branch-breaking example in the chapter, something happens, you do another action in response, and then it ends. Interactivity, on the other hand, is a give-and-take relationship where influence is an important part of the process. The user influences the computer, but the computer also influences what the user does next.
I think to build a successful interactive system, you need to have clear guidelines so both the user and the computer can understand one another. What are they communicating? How is the computer listening to the user, and how is it responding? With all of that comes the idea of influence: how is the user influencing the computer’s behavior, and how does the computer influence the user in return? You cannot just add a random interaction and call it a day. There needs to be a purpose behind it. Are you trying to get across a message? Is the program dependent on the user’s choices? For my p5 sketches, I think I could make the interaction more meaningful by letting the user’s actions actually influence how the artwork develops, and also give the user more control over what they can influence.
In his book, Crawford critiques the manifold ways we tend to ‘wrongly’ define interactivity. For him, it is more of a “conversation: a cyclic process in which two actors alternately listen, think and speak” (8). I really appreciated how he explained this idea using an analogy of two people conversing. While this helped me understand why the elements of this process are not substitutable, what really struck me was the difference he highlighted between interaction and reaction. He notes the sensation we get from reading, for instance, as describing an “intense reaction, and [that] interaction is not reaction on a higher plane of existence” (13). This can be very useful when it comes to designing for people. It allows us to take a step back and wonder whether our product is actually interactive or just a really well-dressed trigger. He cautions that, in this case, he is “not arguing that interactivity is the sole gauge of merit” (14).
However, this is where I find his language to not really match his claim. While he does mention that not everything needs to be highly interactive to be good, he introduces an interactivity spectrum, arguing that things like the refrigerator light are still technically interactive, just at a very low level. He even calls the fridge interaction “silly and beneath the intellectual dignity of almost everybody” (11). If interactivity were truly just one dimension among many, as he insists, there would be no reason for him to give low interactivity scores to certain things and dismiss them. This brings me to the question he raises in the chapter: “Does interactivity exist in the eye of the interactor?” (11). Saying something is low interactivity instead of not interactive still requires someone to decide where exactly it falls on that 0-to-10 scale, and Crawford never really explains who gets to make that call or by what standard. I think that his own examples suggest the answer is just him (his judgement), hence the name: “Crawford Scale” (15). So while I agree his framework gives us a much richer vocabulary than a strict binary, I do not think it earns the objectivity he implies it has. Nonetheless, this reading helped me ground what we mean by an interactive design, which I will use as a heuristic to evaluate my designs henceforth.
I often find myself wondering: beneath all the sleek design and high-definition media, what is the internet really made of? At its core, it’s nothing more than basic lines of text, numbers, and code.
This project is my exploration of that idea. By using basic alphanumeric characters (a-z, 0-9,@#%?&) as the fundamental “atoms” of my digital canvas, I let them generate randomly while using code to keep them organized and separated. It’s my way of turning raw, invisible data into a visual piece of art.
How this was made?
One problem I met at first is how to prevent the letters from overlap.instead of writing super long and confusing if statements to prevent letters from crashing into each other, I used a return;. If a new letter gets too close to an old one, the code just stops right away and tries again next time. It’s super simple and keeps the code clean.
for (let i = 0; i < charCount; i = i + 1) {
let c = chars[i];
let d = dist(x, y, c.x, c.y);
if (d < (size + c.size) * 0.45) {
return;
}
}
I didn’t just store the letter itself in the array. I packed its X/Y positions, size, letter type, and RGB colors together into one object. This makes it super easy later—my drawCharacter() function knows exactly how to paint it.
When I was setting up the object properties, my instinct was to write something simple like “color:rgb” or directly grab an entry from color palette I thought, “Why can’t I just store the whole color array together and hand it to fill()?” But when I tried that, p5.js didn’t handle the color array the way I expected inside fill(). I was so confused until I realized I had to unpack the array and store the RGB values as three separate properties (r, g, b) inside each object so fill(c.r, c.g, c.b) could read them smoothly.
Reflection
To be completely honest, my code went wrong a million times before it finally worked. Going into this project, I knew using an array was a strict requirement, but I didn’t actually have a deep understanding of how arrays function under the hood.
I spent a huge amount of time just trying to wrap my head around one fundamental question: Why couldn’t I just pick a random letter and a position inside AddCharacter() and paint it right onto the screen? Why did I have to save everything into an array first, and then write a completely separate for loop inside draw() just to repaint it every single frame? Wrestling with this concept and breaking down p5.js’s frame-by-frame rendering loop was easily the biggest learning curve for me.
Looking back, there are definitely things I wish I could have added: I wanted to experiment with cooler typography effects, like adding soft ghosting or motion shadows behind the characters, but it felt a bit too complex for my current skill level, so I decided to keep the visuals simple for now.And I’d love to explore adding interactivity in future versions—such as letting users click anywhere on the canvas to spawn specific words, using mouse clicks to control the generation order, or adding a click-to-clear button to reset the canvas and start over.