Week 4 – Reading Response

Reading Don Norman’s The Psychopathology of Everyday Things made me completely rethink how I interact with technology on a daily basis. One line that really stayed with me was Norman’s insistence that “the relevant components must be visible, and they must communicate the correct message” (pg. 3). I realized how often I silently blame myself when I struggle with a poorly designed interface, whether it’s an oven with cryptic icons, an elevator with unlabeled buttons, or even a website with a confusing layout. Norman flips that perspective and argues that it is the designer’s responsibility to make the user successful. That shift felt empowering. It reminded me that confusion is not a personal failing but often the result of flawed design.

One example that drives me crazy, which Norman doesn’t mention, is airplane in-flight entertainment systems. The touchscreens frequently misregister input, and there’s rarely any immediate feedback. Even on otherwise advanced planes like the Emirates A380, the interface feels outdated and uninspired. Sure, it plays movies and basic games, but there is so much room for innovation. Applying Norman’s principle of feedback could solve part of this problem: a simple progress indicator would reassure me that my action registered and prevent the endless cycle of frustrated tapping. Beyond that, design could take a leap forward by enabling features like screen-mirroring from passengers’ devices, turning the system into a productive and personalized workspace. As Norman argues, “discoverability” should make it obvious what is happening and how to proceed, even in a stressful environment like an airplane cabin.

I also saw direct parallels between Norman’s ideas and my own work in interactive media. His discussion of signifiers felt especially relevant. In my p5.js projects, I often rely on subtle cues like highlight effects, error messages, or color changes to guide the user’s next step without lengthy instructions. This reading made me more intentional about those choices: I now see them as part of creating a coherent conceptual model that helps users immediately understand what actions are possible. For instance, in my recent race-car animation project, I could add small speedometer icons that signal users to click the cars and make them go faster instead of just writing instructions on the screen which feels bland. This would transform the interaction from guesswork into an intuitive and engaging experience, exactly what Norman argues good design should do.

For class discussion, I keep wondering whether “invisible design” can actually go too far. Minimalism may look sleek, but as Norman points out, interfaces still need to guide users toward the right actions. I’m curious whether making an experience completely over-simplified might strip away the sense of play and discovery that makes interacting with technology satisfying in the first place.

Overall, I really enjoyed this reading because it challenged the way I usually think about design. I found myself agreeing with most of Norman’s arguments, especially his claim that bad design, not user error, is often the root of frustration. This idea resonated with me because it takes some of the pressure off the user and reframes design as a partnership between human and object. I also liked how approachable and almost conversational Norman’s writing style was, it made the large concepts and conceptual models feel accessible rather than overly academic. If I had to critique anything, it would be that at times the examples felt a bit dated (doors and washing machines don’t feel as urgent as today’s complex digital interfaces), but even so, the principles were timeless. Rather than feeling frustrated, I came away from this reading motivated to pay more attention to how things around me communicate their use, and to design my own projects with more empathy for the user.

Week 3 – OOP Assignment

Of course! Here is a well-structured response perfect for a class discussion board or homework submission. It’s written from your perspective, explains the concepts clearly, and highlights the collision code as you requested.

Hi everyone,

For this week’s work on OOP, I wanted to build on what we did last time implementing a bouncing ball with OOP. I wanted to make it kinds more interactive this time. I wanted to take a familiar p5.js example and make it more dynamic by implementing proper OOP principles, allowing the balls to not only bounce off the walls but also collide realistically with each other.

I created a `Ball` class that bundles together all the data (properties like `x`, `y`, `xspeed`, `radius`) and the functions (methods like `move()`, `display()`, `bounceWalls()`) that define what a ball is and what it can do. This makes the main `sketch.js` file much cleaner and more manageable. Instead of tracking dozens of separate variables for each ball, I can simply create an array of `Ball` objects and let each object manage its own state. And this what gave me the freedom of creating a lot of new balls whenever the mouse is clicked.

One of the most interesting parts of this project was implementing the collision detection between the balls. A simple approach where every ball checks against every other ball can lead to a glitch where they get stuck. When Ball A collides with Ball B, they reverse direction. But in the same frame, when Ball B checks against Ball A, it reverses direction *again*, undoing the bounce.

The highlight of my code is the solution to this problem in the main `draw()` loop. By using a nested loop where the inner loop starts at `j = i + 1`, I can ensure that every pair of balls is checked for collision exactly once per frame. This prevents the double-bounce glitch and is much more efficient.

Here is the snippet for the collision logic:

for (let i = 0; i < balls.length; i++) {
for (let j = i + 1; j < balls.length; j++) {
let ball1 = balls[i];
let ball2 = balls[j];
// Check the distance between the two balls
let distance = dist(ball1.x, ball1.y, ball2.x, ball2.y);
// If they overlap, trigger the collision resolution function
if (distance < ball1.radius + ball2.radius) {
resolveCollision(ball1, ball2);
}
}
}

Week 3 – Exquisite Candidate

Inspiration

I found myself thinking about the current state of political discourse—how it often feels chaotic, random, and almost nonsensical. Arguments and personas could go totally random, as if different parts have been stitched together to form a strange new whole.

This immediately brought to mind ancient myths, like the 人头马身 (the centaur), a creature with the head and torso of a human and the body of a horse. This became my core visual metaphor: what if I could create political “centaurs”? I could randomly pair the heads of recognizable political figures with symbolic, abstract bodies to represent the absurdity and randomness of political rhetoric.

The project needed a name that captured this idea. I was inspired by the Surrealist parlor game, “Exquisite Corpse,” where artists collaboratively draw a figure without seeing the other sections. My program does something similar, but with political figures, or “candidates.” The name clicked almost instantly: Exquisite Candidate.

Description

Exquisite Candidate is an interactive artwork that explores the chaotic nature of political identity. By clicking the mouse, the viewer generates a new “candidate”—a hybrid figure composed of a randomly selected head and a randomly selected body.

The heads are abstract but recognizable vector drawings of political figures. The bodies are symbolic and thematic, representing concepts like power (“suit”), vulnerability (“stripped_down”), foolishness (“sheep”), or emotional immaturity (“baby with tears”). The resulting combinations are surprisingly (at least for me the creator) humorous or poignant, creating a visual commentary on the fragmented and performative nature of public personas. To bring these abstract figures to life, Gemini helped me generate part of the many vector-based drawing functions for the assets.

Code

The program is built on an Object-Oriented structure with three main classes: HeadBody, and Creature. This keeps the code clean, organized, and easy to expand.

The most interesting challenge I encountered was with the “baby with tears” body. My initial design was simple: the Body object would draw itself, and the Head object would draw itself. But the tears needed to be drawn on the face, which is part of the Head object. How could the Body object know where the head was going to be drawn? Unfortunately, until submission, I haven’t figured out how to implement this successfully.

Week 3 – Digital Art

Unlike week 2, which lacked user interaction, I wanted this project to focus on having user interaction project an artwork. However, at the same time I didnt want user to think to much in producing the result. So I arrived at the conclusion of making the user press random keys to produce a sort of a simple artwork.

The artwork I was inspired by is from our video.

I noticed that if I have grids of the canvas with each grid having a random diagonal value, it can produce something like this. Of course, the same direction meant the same color.

 

The random colors are stored in an array that looks like this:

this.palettes = [
      ["#fefae0", "#606c38", "#bc6c25"],
      ["#0f0f0f", "#e63946", "#f1faee"],
      ["#f1f1f1", "#118ab2", "#ef476f"],
      ["#22223b", "#f2e9e4", "#c9ada7"],
      ["#faf3dd", "#2a9d8f", "#e76f51"]
    ];

The first is for the background of the canvas, the second one is for the left diagonal and the third one is for the right diagonal. I did no mention how to change the colors randomly. Feel free to explore and find out how to change colors. Pressing randomly keys might help.

placeRandomDiagonal() {
    //wait if full
    if (this.gridFull()) {
      return;
    }
    //get randomindex to palce the diagonal line
    const randIndex = floor(random(this.emptyIndices.length));
    const i = this.emptyIndices.splice(randIndex, 1)[0];
    
    //get random direction 1 is left 2 is right diagonal
    const dir = random([1, 2]); 
    //get random strokeWeight
    const w = random(1, 5);
    this.cells[i] = { dir, w };
    //call reset to check if its full
    this.scheduleAutoResetIfFull();
  }

This is the code that I wanted to share. This is the place Random Diagonal function, It first gets the random Index to palce the diagonal lines and chooses the random direction and random stroke weight. At the end the of the function it calls another function which simply checks if the grid is full. If it is, it calls the reset function.

//grid cells are stored in 1D array while canvas is 2D so this is to conver linear index to 2D position
//const x is column number
const x = (i % this.cols) * this.cellSize;
//row number
const y = floor(i / this.cols) * this.cellSize;

//each are multiplied by cell size to get pixel coordinates 
//ex cellsize is 20, col is 5 anat i =7. that means 7%5 = 2 column 2 which is 40, row is at 7/5 = 1 at 20, so index 7 maps to position 40,20


The hardest part about this code was the transition of 1D arrays to 2D canvas. Since the information that stores the grid cells are in 1D array, I had to find a method to map each index to a coordinate in the grid. This is done here, the specifics are explained in the comments.

For future Improvements, I think that making mouse clicks have another action on the artwork. Maybe changing the diagonal lines can make the artwork more interactive. Rather than diagonal, it can try different angles with each mouse click.

Week 3: PING (Objects & Arrays)

(up to two players! WASD for top side and IJKL/arrow keys for bottom side)

I thought about how I wanted to build upon what I had last week and I arrived at the idea of using something to interact with the bouncing ball mechanic. At first, I thought about making an air hockey game where you could drag the paddle but I didn’t know how to create an opponent that could respond to what you do. And it couldn’t be multiplayer since there’s only one mouse, which led me to using keyboard keys to control the paddles.

I began to build two separate objects that can be controlled by wasd and arrow keys respectively– a lot like the old web games I would secretly play in my computer science class with my classmates back in elementary school.

Using Classes and this.

Last week when I presented my project to professor Aya, she suggested that I learn how to use class so I could make it easier on myself to organize my code and objects. So this week I delved into classes and have a pretty good grasp on it now. Here are two classes I made– the ball and the top paddle.

class ball { //class creates a re usable template: let ball1 = new ball(x,y,r)
  constructor(xPos, yPos, radius){ //creates the initial state
    //this referes to the object currently being created
    this.xPos = xPos;
    this.yPos = yPos;
    this.radius = radius;
    
    this.ballXspeed = ballXspeed;
    this.ballYspeed = ballYspeed;
    this.ballMoving = false; //boolean to help reset ball
    
  }
  move() { //this is a method, a function that belongs to just one object
    if (!this.ballMoving) return; //if ball is still then do nothing
    
    this.xPos += constrain(ball1.ballXspeed, -maxSpeed, maxSpeed)
    this.yPos += constrain(ball1.ballYspeed, -maxSpeed, maxSpeed)
    
    //BOUNCE: CHECKS LEFT AND RIGHT EDGE
    if (this.xPos > width - this.radius || this.xPos < 0 + this.radius) { 
      this.ballXspeed *= -1;
    }  
  }
  
  reset(){
    this.xPos = width/2;
    this.yPos = height/2;
    this.ballMoving = false;
    
    //setTimeout(function, delay) delay is in milliseconds
    setTimeout(() => { //the arrow =>
      this.ballXspeed = random([-ballXspeed, ballXspeed]);
      this.ballYspeed = random([-ballYspeed, ballYspeed]);
      this.ballMoving = true;
    }, 2000);
  }
  
  scoreDetection(){
    //CHECKS TOP AND BOTTOM EDGES
    if (this.yPos > height - this.radius) {
      adjustScore(1,0); //top side scores 1
      this.reset();
    }
    if (this.yPos < 0 + this.radius) {
      adjustScore(0,1); //bottom side scores 1
      this.reset();
    }
  }//closes score detection
  
  display(){
    ellipse(this.xPos, this.yPos, this.radius *2);
  }
} //ends class ball
class topPaddle {
  constructor (xPos, yPos, paddleWidth, paddleHeight, xSpeed, ySpeed){
    this.xPos = xPos;
    this.yPos = yPos;
    this.baseY = yPos; //initial yPos 
    this.paddleWidth = paddleWidth;
    this.paddleHeight = paddleHeight;
    this.xSpeed = xSpeed;
    this.ySpeed = ySpeed;
  }
  
  display(){
    fill(255)
    rect(this.xPos,this.yPos,this.paddleWidth,this.paddleHeight);
  }
  
  move(){
    /* Keycodes
    W = 87
    A = 65
    S = 83
    D = 68
    */
    if (keyIsDown(87)){ //TOP
      this.yPos += this.ySpeed * -1; //negative because 0 counts down
    }
    if (keyIsDown(65)){ //LEFT
      this.xPos += this.xSpeed * -1;
    }
    if (keyIsDown(83)){ //BOTTOM
      this.yPos += this.ySpeed ;
    }
    if (keyIsDown(68)){ 
      this.xPos += this.xSpeed;
    }

    //RESTRICTIONS 
    this.xPos = constrain(this.xPos, xBoundary, width-xBoundary)
    this.yPos = constrain(this.yPos, this.baseY-yBoundary, this.baseY+yBoundary)
    
  } //closes move()
}

I really enjoyed using methods to help organize my code and operate on an object-oriented basis. 

 

Not too far into writing the classes for the paddles, I realized I was recreating the game pong. This is literally how pong was made– someone wanted to test bouncy ball physics and moving paddle collision and made pong.

 

Implementing Arrays

I already experimented with arrays last week when dealing with for() loops so this week I wanted to use them in a different way: to track scores for each side. I made two arrays– one called topCounter and one called bottomCounter. If the top side won round 1, they would have 1 added to their array and have it console.log’d into the console.

 

Designing with Variables

Since we learned push() and pop() in class last week, I’ve been wanting to use these techniques to make more organized stroke() and strokeWeight() functions. 

 

Beyond that, I used a lot of variables to help with the numbers so changing the variable number in the top of the code would change all of the related values throughout the code conveniently and often symmetrically. For instance, I would get the midpoints between the two ends of the lines to have the score number displayed there.

//LEFT CENTER LINE
    line(
      0,height/2, 
      0+sideLineMargin,height/2
    )
    //CENTER LINE
    line(
      (width/2)-centerLineMargin,height/2, 
      (width/2)+centerLineMargin,height/2
    )

//lots of code inbetween

// TOP SIDE SCORE
    text(topScore, 
        ((width/2)-centerLineMargin + 0+sideLineMargin)/2,
        height/2
        )

I also found the rectMode() and textAllign() functions to be incredibly helpful.

 

Adjust Gameplay Parameters

Initially, the back and forth between the two players felt very predictable and un-engaging. It was slow and ran at a consistent speed, which also meant there was only so many things you could do to change the trajectory of the bounce.

 

So I did two things, I made the paddles have way more vertical movement than it did initially, and I added a speed multiplier that really shaked the game at its core. 

 

Every time a player would collide their paddle with the ball now, the ball would speed up by 4%, which is seemingly small, but builds up very quickly to overwhelm players.

//BALL ATTRIBUTE
let ballXspeed = 6;
let ballYspeed = 5;
let speedUpFactor = 1.04; //105% each time it collides with paddle
let maxSpeed = 14; //limits the speed of the ball

//lots of code inbetween

if (ballCollidePaddle(ball1,topPaddle1,"Bottom")){
    ball1.ballYspeed *= -1;
    ball1.ballXspeed *= speedUpFactor;
    ball1.ballYspeed *= speedUpFactor;
}

However, it would get to a point where p5js wouldn’t really render it at a high enough fps for it to be fair to the players, so I added a max speed cap of 14-ish into the move() method for the ball to make sure it would be fast but not too the point of absurdity.

 

Difficulties Endured

 

Thankfully p5js didn’t crash half a dozen times during the development like it did last week, but I had some technical struggles.

 

When I built the second paddle object in the bottom, I completely forgot to constrain the y-value of the paddle which created quite a humorous moment when my girlfriend wanted to test the paddle movement with me.

 

The math behind colliding a circle with a rectangle was pretty confusing to figure out, but I also didn’t want to use circles as paddles so I tried a lot of methods until I made it work by checking the x-edges overlapping.

let xOverlap = 
    (ball.xPos + ball.radius > paddle.xPos - paddle.paddleWidth/2) &&
    (ball.xPos - ball.radius < paddle.xPos + paddle.paddleWidth/2);
  
  if (!xOverlap) return false; //checks if ball collided with paddle early

When I tried to embed it onto wordpress, the arrow keys kept trying to scroll the embed for me so I had to add another set of controls on IJKL.

Gameplay Strategy & Technique

In testing my friends and I found a few strategies and techniques that help with winning rounds. One of the strategies is to back up as the ball approaches max speed; this really helps by giving you more time to react and save the ball. 

 

Another technique we accidentally found out was double-tapping the ball to have it gain the speed multiplier several times on the same receive.

 

My friends and I had jolly fun playing against each other even if they thought the game was incredibly difficult.

 

Conclusion

I had a lot of fun making this project and learning how to use more tools in JavaScript. Making classes felt like an essential part of JS coding that I finally understood today. I can really feel my progress growing every week with every assignment.

 

I really hope I can repurpose the work I did in this project sometime in the future or even just play it with my friends whenever I open my p5js account.

Week 3 Reading Response

The reading defines interaction to be a cyclic process in which two actors alternately listen, think, and speak. Building on this, I see a strongly interactive system as one that sustains this cycle in a meaningful way, where the user feels their input is not only received but also interpreted in a way that shapes the system’s future responses. In other words, the system doesn’t just react once, but continues to evolve as the user engages with it. I think of strong interactivity as creating a sense of dialogue, where the user’s actions feel acknowledged and the system “remembers” or adapts over time. However, I don’t think strength alone guarantees a good interaction; too much responsiveness without clarity can overwhelm or confuse the user.

I am in the process of choosing my next interactive project for week 3. While I am still brainstorming, unlike week 2’s project that lacked user interaction, I want to create a project where user’s mouse interaction and possibly keyboard interactivity produces an artistic outcome. For example, I could design the sketch so that keyboard inputs that change the “rules of the system,” such as altering font sizes or styles, to produce something like looks like a digital caligraphy. This would make the sketch feel more like an ongoing exchange rather than a one-time reaction. Instead of static outputs, the artwork would emerge from the combination of system logic and user decisions. The key idea is to create a system where user’s input results in a artistic product. I’ll try to take this idea in a direct matter.

Week 3: Reading Response

 

During marhaba week I was being trained as a Weyak facilitator. The drill was simple: one person speaks, the other listens really listens and then reflects back what they understood. I tried using that outside the training too, with friends. I noticed something uncomfortable: I’m decent at the first two moves, listening and interpreting, but I stumble on the third one that is speaking back clearly and on time. Reading Crawford snapped that pattern into focus. His “listen, think, speak” cycle didn’t feel like theory only. 

Also, I don’t agree with everything. He says reading a book isn’t interactive. I get his point (a book can’t answer back), but as a reader I still feel a kind of inner talk with the text. For design work, his strict rule helps; for real life, it feels a bit narrow. Still, his main idea don’t confuse reaction with real back-and-forth was very useful.

The book also made me think about control. Sometimes a system looks interactive, but the user is just pressing “next” while the program forces its path. That’s not a real conversation. It also somehow reminds me of home: there’s a lot of noise and movement during the protest against corruption, but the direction is being set by a few people with their own goals. Everyone is acting, but very few are actually listening. It’s busy, not interactive exactly the difference Crawford talks about.

 

While reflecting on all this, I realized something about my own art. The digital sketch I had been working on suddenly looked lifeless—beautiful in pieces but, to me, dead. It wasn’t listening to the user; it just sat there. That recognition pushed me to start over. I stripped out the old smoke elements and rebuilt the scene around the burning parliament building, designing an interaction where a single click can pause the fire and wash the frame in blue. In the process, Crawford’s idea of a true “listen–think–speak” loop came alive for me: my sketch now responds instead of merely flashing back.

 

Lastly, what I appreciated in the book is how stubbornly he refuses to call every flashy response “interactive.” He cares about the quality of the loop: how precisely the system listens, how intelligently it processes, and how meaningfully it responds.

Week 3: Assignment

My concept:

This week my mind has been heavy with news from home. There are protests happening in my country, and instead of bringing hope, some of them have turned destructive. Bad actors disguised as protesters are setting fire to public property, using a genuine Gen-Z movement against corruption as cover to erase their own crimes. Several police stations were burned, letting prisoners escape. Thousands of criminals are now roaming free, which makes me constantly worry about my family’s safety.

This piece of art is my response to that chaos. The base of the picture shows fire representing the burning buildings and the anger on the streets. Above it, thick smoke rises and spreads, like the dark energy that hangs over everything. In the middle there’s a shape that at first was meant to be drifting smoke, but as I worked, it began to look like a person. So later I decided to embrace that.

That smoky figure stands for the opportunists, the gangs, and the political players who twist the protest for their own gain. Just like smoke, their hearts are gray. They walk on fire because they don’t fear destruction; they only care about their own benefit, even as the country suffers.

Through this piece I wanted to capture both the physical reality of fires and smoke and the deeper feeling of a society clouded by selfishness and violence.

After I thought I was done with the art I started to read The Art of Interactive Design. This made me see that an earlier sketch I had made felt dull and not interactive at all. I removed the original smoke class and all its elements and began drawing the parliament building once Asia’s most luxurious and one of the largest palaces before it was destroyed by fire. I worked to mimic its structure and sweeping rooflines.

For the interactive element, when a viewer clicks on the building, the flames stop and a wash of blue appears, symbolizing calm and happiness. Releasing the click reignites the fire. Each time I clicked to halt the burning, I felt a rush of conflicting emotions an almost physical wish that I could do the same in real life, to save the parliament and, in some way, my country itself.

Process and Reflection:

When I first started this piece, I pictured thick smoke clouds spreading across the top of the canvas. I spent a long time trying to build that effect by dropping bubble after bubble, checking their spots with console.log(mouseX, mouseY), and trying to make the shapes feel alive. But after a while it turned into a slow, repetitive task. The more I worked, the less it looked like the smoky sky I had imagined.

In the middle of that frustration, something unexpected happened. One cluster of bubbles began to form a faint human shape. At first I thought it was just a glitch in my layout, but the longer I looked, the more it felt right. It reminded me of how, in real life, people with hidden motives were blending into the protests. That was the moment the “smoke man” was born.

The background went through a similar transformation. I had started with a grayish color to match the idea of smoke, but the fire didn’t stand out. On a whim I tried a deep black, and suddenly the flames glowed with an intensity that felt closer to the real scene. Black made the fire look alive, and it captured the mood of a night filled with tension and danger when prisoners were set free.

Looking back, the way this piece evolved feels close to the story I wanted to tell. Plans I was sure about like a full smoky sky kept falling apart, and new shapes kept appearing out of nowhere. The smoke man, which began as a small accident, became the heart of the artwork, just like how unexpected figures can change the course of a protest.

If I had more time, I would push the scene even further: let the smoke drift and curl like real fumes, add buildings, maybe even small moving figures to suggest the chaos on the ground. But even without those details, this process showed me how art sometimes leads rather than follows. What started as a careful plan turned into a piece shaped by chance, change, and the very uncertainty I was trying to capture.

My Sketch:

Week 3 – Reading Reflection

For me, a strongly interactive system is one that goes beyond just reacting. Crawford’s point about how books, movies, or even a refrigerator light don’t really “interact” stuck with me; true interactivity for me now, means both sides listen, think, and respond. It isn’t enough for a system to grab attention or look slick; it has to feel like a conversation. That’s why I think of interactivity less as a switch (on/off) and more as a spectrum. The strongest systems respect the user: they acknowledge input in meaningful ways, they adapt, and they make the user feel like their actions actually matter.

When I think about my own p5 sketches, I realize they often stop at reaction. They respond to a click or a key press but don’t really “listen” deeply. To push them toward stronger interactivity, I could design them to recognize patterns in user input, remember past actions, or even surprise the user with responses that aren’t strictly predictable (sort of something we did for the production in week 2; baby steps but still). For example, instead of a sketch where shapes simply follow the mouse, I could create one where the system builds a visual “memory” of how the user has drawn before and adapts its behavior over time. Though that sounds ambitious, it would turn it from a basic reaction into more of a dialogue.

Ultimately, I think the goal is to make my sketches less like a refrigerator light and more like a partner in conversation. The best interactive systems respect the user’s role, and if my work in p5js can manage to give users that sense of being heard, then I’ll know I’m moving in the right direction.

Week 3 – Moon Phase

Concept

I wanted to build something that felt alive but also structured, and the lunar cycle is a great mix of both. The project simulates the eight phases of the moon, from New Moon to Waning Crescent, with randomized textures (spots) and stars to make each redraw unique. The idea is that every click reveals a new “night sky,” giving the viewer a sense of time passing without relying on animation loops.

How It Works

  • Moon.js defines a Moon class. Each moon has a position, size, and current phase index. The phase controls how much of the circle is lit and how much is in shadow.

  • The surface spots are stored in an array of objects, each with its own position, size, and shade of gray. This randomness makes the moon look organic rather than like a flat white circle.

  • I also made sure spots only show up in the “visible” lit portion of the moon, so the shadows aren’t just cosmetic.

  • Sketch.js handles the overall scene: the canvas, the star field (also an array of little objects), and the interaction. Every mouse click moves the moon forward by one phase, regenerates its surface spots, and refreshes the stars.

What I’m Proud Of

The hardest and most satisfying part was getting crescents and gibbous phases to look right. p5.js doesn’t have a neat intersection() or shape-clipping tool for arcs, so I had to improvise using combinations of ellipses, arcs. It was like solving a puzzle with the wrong pieces, but in the end it worked.

Another “aha” moment came with the order of drawing. For example, if I drew the stars last, they’d sit awkwardly on top of the moon. If I drew spots before clipping, they’d spill into the shadows. It’s such a small detail, but the sequence of draw calls makes or breaks the illusion.

Aesthetic Choices

  • The moon is a soft gray (230) while shadows are much darker, to keep things simple but still distinguishable.

  • Stars are randomized each time you click, which makes the scene feel less static.

  • The phase name and “day” number are displayed in monospace above the moon to mimic an old-school astronomy chart.

Problems Along the Way

  • Figuring out crescents and gibbous shapes took the most trial-and-error. I tried a bunch of naive arc overlaps before landing on my ellipse-mask workaround.

  • Getting the spots to fit entirely inside the circle (without spilling over the edge) was trickier than expected; I had to add a distance check plus a little buffer zone.