All Posts

Featured

Retro ASCII Art

Concept: Retro 3D Art

Retro Computer Graphics from Behance

I was inspired by old school computer graphics that you would see in movies like The Matrix. Because of this, I knew that I wanted to make some ASCII art in the signature green color that most retro graphics used. After some experimenting, I decided to make an ASCII representation of a Menger Sponge, which is a fractal geometry that I thought would be very interesting to look at.

Process

I began by creating a sample video that I could use to turn into ASCII art. To do this, I created a 3D cube in Processing, which is a predecessor of P5.js. I attempted to do this in P5.js, but found the saveFrame() function too limiting. I created a simple box using the 3D renderer in Processing, and added some lighting to give the sketch some dynamic range. This is important as I needed to use the difference in brightness later on when converting the video to ASCII, and the greater the dynamic range is the easier it is to perceive the ASCII video.

void setup() {
  size(600, 600, P3D);
}

float a = 0;
void draw() {
  background(0);
  noStroke();
  spotLight(10, 80, 240, width/2, height/2, 400, 0, 0, -1, PI/4, 2);
  pointLight(255, 0, 0, width/2, height/2, height/2);
  ambientLight(100, 0, 100);
  fill(255);

  translate(width/2, height/2);
  rotateX(a/2);
  rotateY(a/2);
  rotateZ(a/3);
  box(280);

  a+=PI/100;

  saveFrame("src/box-######.png");
}

I incremented the rotation angle by a fraction of pi because I wanted to be able to count when the cube resets to its original position. This made it easier to create a video that could be looped seamlessly.

Once I had the output frames, I combined them together using Microsoft Movie Maker. The final result was this video:

Next, I wanted to work on converting this footage to ASCII art. I followed Daniel Schiffman’s coding challenge on creating ASCII text images. After experimenting with the video size and character density arrays, the following sketch was the result I got:

However, I wanted to create something a bit more complex. This is when I remembered an old project that I worked on by following another one of The Coding Train‘s challenges, which was the Menger Sponge coding challenge.  After generating the frames and compiling them into a video, this was the result:

All I had to do then is to insert this video into the original code and play around with different parameters until I got the desired result.

Code Highlights

I’m really proud of the code that makes the animation look like its being built up slowly using ASCII characters. The way I achieved this is basically by filtering out the highlights on the Menger sponge. When I compiled the video, I saw that the lower right corner of the sponge had a bright highlight on it that was blocky.

//finding the right character based on brightness of pixel
let len = charArray.length;
let charIndex;

//playing with map values for the building up effect
charIndex = floor(map(apparentBrightness, 0, 100, len, 0));

When I filtered the brightest points of the sponge out, I essentially removed the lower left corner until it got a bit darker later in the animation, which created the building-up effect.

Reflection

Compared to the first assignment, I had a more solid idea of what I wanted to achieve. Because of this, I had planned out my workflow beforehand and that streamlined the entire creative process. I knew I had to create source animation and then convert it to ASCII characters. This made my code more readable, and I had better control of the sketch overall.

However, the building-up animation that I am most proud of is dependent on the source video. It looks the way it is because in the source animation the highlights are blocky as well. If I wanted to recreate this project, I want to work on some logic that allows the effect to be more generalizable. Maybe I could filter out sections of the object based on a distance function instead of the brightness levels. That way I can substitute different source videos and still get the cool effect.

Sources

 

 

Featured

Analog Musical Instrument

const int blueButton = 6;
const int servoPin = 9;
const int songLength = 8;
const int tempo = 115;

const int noteC3 = 130;
const int noteD3 = 146;
const int noteE3 = 164;
const int noteF3 = 174;
const int noteG3 = 196;
const int noteA3 = 220;
const int noteB3 = 246;


const int noteC4 = 261;
const int noteD4 = 293;
const int noteE4 = 329;
const int noteF4 = 349;
const int noteG4 = 392;
const int noteA4 = 440;
const int noteB4 = 493;
const int noteC5 = 523;

const int noteD5 = 587;
const int noteE5 = 659;
const int noteF5 = 698;
const int noteG5 = 784;
const int noteA5 = 880;
const int noteB5 = 987;


//int musicNotes[] = {noteC4, noteD4, noteE4, noteF4, noteG4, noteA4, noteB4, noteC5};
int musicNotes[] = {noteC5, 0, noteE5, 0, noteG5, 0, noteB5, 0};
int musicNotes2[] = {noteC4, 0, noteE4, 0, noteG4, 0, noteB4, 0};
int musicNotes3[] = {noteC3, 0, noteE3, 0, noteG3, 0, noteB3, 0};
int noteDuration[] = {2, 4, 2, 4, 4, 2, 4, 2};

void setup() {
  pinMode(servoPin, OUTPUT);
  pinMode(blueButton, INPUT_PULLUP);
  Serial.begin(9600);
}
void loop() {
 lightSensor();
  button();



}

//new tab: button
void button() {

  
  bool bluebuttonState = digitalRead(blueButton);
  if (bluebuttonState == HIGH) {
    for (int i = 0; i < songLength; i++) {

      int duration =   noteDuration[i] * tempo;

      tone(servoPin, musicNotes2[i], duration);
      delay(duration); //make the length of the time = length of the musical note(frequency)
      delay(15);

    }
  }    else {
    for (int i = 0; i < songLength; i++) {

      int duration =   noteDuration[i] * tempo;

      tone(servoPin, musicNotes[i], duration);
      delay(duration); //make the length of the time = length of the musical note(frequency)
      delay(15);


    };


  };

};
//new tab light sensor
void lightSensor() {
  int analogValue = analogRead(A0);
 Serial.print(analogValue);
  if (analogValue < 10) {
   Serial.println(" - Dark");
//   //add music note here
  } else if (analogValue < 200) {
   Serial.println(" - Dim");
    for (int i = 0; i < songLength; i++) {

     int duration =   noteDuration[i] * tempo;

     tone(servoPin, musicNotes3[i], duration);
     delay(duration); //make the length of the time = length of the musical note(frequency)
     delay(15);

    }

  }  };


Documentation:

Idea: Create sound directly from Arduino, like a musical drone sound by changing the musical notes from C4 to C5 when you click on the button or change from either to a 3rd octave when you dim the light sensor (all by changing the frequency from within the motor).

Positives:

I like how I could manipulate the motor sound based on its frequency to create a tone and tempo.In addition to that I was able to play around with that frequency within the motor to create an array of musical notes with different octaves. Once I could adjust the tempo and time spacing between notes through looping the array, I was able to integrate that into different parts of the code.

I like that I was able to introduce different noises from the motor by adding in different components that trigger different sounds like the button and sensor.

This was also surprisingly fun compared to other assignments for me because I learned that Arduino could be used for more than just LED circuits etc but you can incorporate and manipulate other media like sound.

Negatives:

I don’t think its particularly musical, however I think it follows the rules of music in terms of octaves and musical notes.

 

 

Featured

Candy colored spiral visual effect

This has gone through many iterations of trial and error to get the coolest effect.

Im using spiraled ellipses as a main element for my mid term, so I have been experimenting with it.

Code for creating the spiral:

float angle;

float x;
float y;
void setup() {
  size(800, 800);
  noFill();
  shapeMode(CENTER);
}

void draw() {

  //fill(255);
   fill(255,200,200); //pale rose, change the color of the candy.
  ellipse(height/2, width/2, 600, 600);
  
  int hundred=100;
  //rotate(angle);

  for (int i=0; i<500; i+=100)

  { 
    strokeWeight(20);
    stroke(0); //change the color of the spiral
    noFill();
    ;
    arc(height/2, width/2, hundred+i, hundred+i, radians(180), radians(360) );
    arc(height/2-25, width/2, hundred*1.5+i, hundred*1.5+i, radians(0), radians(180));
  }
  //angle=angle+0.1;
  //save("mySpiral.jpg");
};

I exported the code above to a .jpg format to use as an image in the sketch below.

Code for the animation:

float angle;
PImage img;
void setup() {
  size(900, 900);
  img = loadImage("mySpiral.png");
};
void draw() {
    background(255);
  for (int i=0; i<width; i++) {
 
     translate(width/2+i, height/2+i);
  imageMode(CENTER);
  rotate(angle);
  image(img, 0, 0,300,300);
  
 
  }
 angle=angle+1*1;
}

 

Next step :

I would like each candy spiral to go through several colored versions of itself:

 

  for (int a= 0; a<1; a++) {
     save(random(20)+"spiral");
  }

This code allows different colored versions from random to be saved as a new version of itself , I plan on using the saved photos as part of a sprite sheet to add to the animation above.

Featured

Psychedelic Geometry :)

float angle;
float grid= 400;
float i=0; 
void setup() {
  size(1080, 900,P3D);
};

void draw() {
 
  for(int x=0;x<=width;x+=grid){
    for(int y=0;y<=height;y+=grid){
  translate(mouseX,mouseY);
rotateX(radians(angle));
rotateY(radians(angle));
i=0; 
  while(i<width){
    i=i+20;
  beginShape();
vertex(i+100,100);
vertex(i+175,50);
vertex(i+250,100);
vertex(i+250,200);
vertex(i+175,250);
vertex(i+100,200);
vertex(i+100,100);
vertex(i+100,200);

endShape();
  };
  
  };
  };
//rotateX(radians(angle));
angle+=1; //does a full rotation
};

For this assignment,

I went through A LOT of experimentation,

at first, I wanted to recreate this pattern:

I almost got there:

Then, I didn’t really know what to do with it in terms of animation….

I  discovered the built in P3D  and started different experiments, but  I didn’t know how to integrate more effects while using the While loop, so I experimented further and created the animation at the top of the post.

The inspiration of this post for me was to experiment as much as possible, since it’s been helping me understand the mechanics of the code. And to save different blocks of code on GitHub if I find something interesting I could integrate in a different art piece later.

Week 1 – Self Portrait

My look-alike animal I chose to portray myself is an owl. It didn’t have to be an animal, but I chose it simply because I like cute animals. It was tough trying to pick between an owl and a raccoon, but I stuck with an owl because when I during my military service, my teammates called me “angry bird” because of my sharp-looking eyebrows. The fact that I was bold probably made it worse. I combined both “angry bird” and owl to create “angry owl”.

Simplistic, but straight to the point. I added 2 animations during my work on this project. Please feel free to find both of them.

I love working at night because it’s quiet and it’s the time of day when I feel most focused. So if you try to get the owl’s attention by clicking, it will lift its eyebrow as a warning. It’s a do-not-disturb signal.

//eyebrow only moves at night
 if (!morning && eyebrow) {
   move += direction * 1.2; //speed of animation

   if (move <= -20) { //moved distance is max 20, if greater, change direction to go down
     direction = 1;     
   }
   if (move >= 0) { //when it reaches its original position
     move = 0;
     eyebrow = false;   //stop animation
     direction = -1;    //reset direction
   }
 }

That is the animation code for the eyebrows. One of the hardest parts of this code was changing the direction of the movement. If the position changes by 20 pixels, then it changes the sign of the direction so that it goes in the opposite direction. It was also difficult to trigger the animation. I have two animations that are played in different conditions: night and day. So coordinating the timing was probably the most difficult part of coding. I will explain the coordinating part after showing the code for morning animation.

(Explanation of Code, Skip this if this is a bit boring)

move+= direction is for the speed of the animation. But the sign of the direction indicates whether it goes up or down. If the animation moves for 20 pixels upwards, it satisfies the first condition, and the sign is changed. It was set to -1 before. So now, the eyebrow moves downward back to its original position. Since the sign has flopped, move slowly turns positive as it goes through the move+=direction line. At some point, it will reach 0, where the variable named eyebrow, which is set to true when the user clicks on the owl, turns false, and the direction changes to positive.

As you could guess, if you click on the moon, it changes the time of day. Also, if you click on the owl during the day, it will show the ZZZ animation.

function mousePressed() {
  //if position of sun/moon is pressed
  if (dist(mouseX, mouseY, X, Y) <= D) {
    //change day/night
    morning = !morning;
    //stop eyebrow
    eyebrow = false; move = 0; direction = -1;
    return;
  }

  // start Z animation in morning
  if (morning) {
    zActive = true;
    zStart = millis();
    return; // don't trigger eyebrows
  }

  //night means eyebrows haha
  if (!eyebrow){
    eyebrow = true;
  } 
}

I used two flags to trigger the animation: zActive and eyebrow. I set these values to true when the screen was clicked based on the time of day. I also had to carefully coordinate so that the flags were triggered where I wanted them to be.

(Explanation of Code)

When the mouse is pressed, it first checks if the user clicks on the area where the sun and moon are placed. If it is, then moring = !morning changes from day to night, vice versa. When the time of day changed, I made sure once again to reset variables just in case the animation plays. Now, if that was not the case, and the user clicks, it checks if it is morning or night. If it is morning, the zActive variable is set to true, and this sets off the ZZZ animation. If it is not morning, then it sets the eyebrow flag to true, which triggers the eyebrow animation. Figuring out this logic was probably the most difficult part of the code.

Finally, this is my ZZZ animation. 

/ZZZ animation
if (morning && zActive) { //only when morning and user clicked
  const elapsed = millis() - zStart; //measure time

  //number of Zs
  let visible = 0;
  if (elapsed >= 0){
    visible = 1;
  }
  if (elapsed >= 300){ //basically every 300ms, add one
    visible = 2;
  }
  if (elapsed >= 600){
    visible = 3;
  }

  ZZZ(width/2 + 70, height/2 - 120, visible);

  // after all Zs have appeared and held, hide all at once
  if (elapsed >= 3 * 300 + 600) { //600 is extra time just in case
    zActive = false; // disappears together
  }
}

I used millis(), which is used to measure the timing of animation. I wanted the Zs to play out one by one, so I had to time them by 300ms. The logic here is quite straightforward. 

function ZZZ(x, y, count) {
  noStroke();
  fill(0);                
  textAlign(LEFT, BASELINE); //aligns text to left and at baseline of font
  
  if (count >= 1) {
    textSize(20); 
    text('z', x, y); 
  }
  if (count >= 2) { 
    textSize(24); 
    text('z', x + 12, y - 12); 
  }
  if (count >= 3) { 
    textSize(28); 
    text('z', x + 28, y - 26); 
  }
}

This is the helper function to create the ZZZ effect. visible and count shows how many Zs are present, and it is incremented with time elapsed, measured with the millis function. Any further explanation of the code can be provided in class. 

For improvements, I was thinking about adding another condition. For now, when the owl is disturbed, it just repeats the animation. However, adding another animation when the owl is disturbed more than 10 times might be interesting. Owl spreading its wings and flying away sounds good. 

P.S. I was scrolling through the posts and found a post that is quite similar to mine (haha), although the contents were totally different. It was nice to see a fellow owl.

Self Portrait – Guli

https://editor.p5js.org/Guli/full/cmL7dFMrF

Our hometask for the first week was to create a self portrait to practice using the simple drawing functions in p5js. For the assignment, I had an idea to use my avatar in Duolingo as a refernce. I really liked my Duolingo avatar — the colors, the shape, and the style, thus recreated it while adding more ideas.

The colors in the avatar are yellow for the background and orange for the dress. The avatar has smiling eyes that are curved at the bottom, along with sparkles. For the body, I simplified the design by making the head float, rather than directly being attached to the body. The idea of a floating head came from one of my chilhood cartoons Phineas and Ferb.

The curls and the curious expression with sparkles in the eyes are the highlights of the portrait. I am proud of myself for thinking off using human face color circles under the eyes to give the impression of smiling eyes. Drawing the curls also proved to be not a straightforward task, with me adjusting and readjusting the position and size of each brown circle untl  achieved the look I wanted.

In my future works, I could make the design interactive, so the art changes color or moves as the viewer comes into contact with the work. In terms of the design itself, I can use codes like arc() and  rotate(), adding more creativity to the work.

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

function draw() {
  background(255, 241, 167); // yellow bg

  // Face --------------------------------------------------->
  fill(255, 226, 214); // face color
  rect(200, 120, 200, 150, 40); // face shape
  
  
  // Eyes --------------------------------------------------->
  fill("white"); 
  ellipse(width/2 - 40, height/2 - 20, 75, 70); // left eye
  ellipse(width/2 + 40, height/2 - 20, 75, 70); // right eye

  // Pupils
  fill(61, 61, 61); // dark pupil
  ellipse(width/2 - 40, height/2 - 20, 45, 45); // left
  ellipse(width/2 + 40, height/2 - 20, 45, 45); // right

  // Blue part of pupil
  fill(57, 94, 130, 200); 
  ellipse(width/2 - 40, height/2 - 10, 35, 30); // left
  ellipse(width/2 + 40, height/2 - 10, 35, 30); // right

  // Sparkles
  drawSparkle(width/2 - 35, height/2 - 27, 15); // left eye sparkle
  drawSparkle(width/2 + 35, height/2 - 27, 15); // right eye sparkle

  // Under-eye curves 
  fill(255, 226, 214); 
  ellipse(width/2 - 40, height/2 + 20, 90, 60); // left
  ellipse(width/2 + 40, height/2 + 20, 90, 60); // right

  // Nose --------------------------------------------------->
  fill(248, 172, 148); // nose color 
  beginShape(); 
  vertex(width/2, height/2 - 10); // top 
  vertex(width/2 - 7, height/2 + 10); // left 
  vertex(width/2, height/2 + 17); // bottom 
  vertex(width/2 + 7, height/2 + 10); // right 
  endShape(CLOSE);

  // Mouth --------------------------------------------------->
  fill(179, 93, 110); // lip color
  ellipse(width/2, height/2 + 45, 20, 20); // lip position
}

// sparkle in the eye function ---->
function drawSparkle(cx, cy, size) {
  fill("white"); // sparkle color
  quad(
    cx, cy - size/2, // top
    cx + size/2, cy, // right
    cx, cy + size/2, // bottom
    cx - size/2, cy  // left
  );
  
  // circular sparkle
  fill("white"); // circle sparkle color 
  ellipse(width/2 - 50, height/2 - 15, 8); // left 
  ellipse(width/2 + 50, height/2 - 15, 8); // right
  
  // HAIR --------------------------------------------------->
  fill(84, 54, 41); // hair color
  // Top
  ellipse(width/2, height/2 - 120, 120, 90); // top middle
  ellipse(width/2 + 60, height/2 - 115, 110, 85); // top right 
  ellipse(width/2 - 60, height/2 - 115, 110, 85); // top left 

  // Left 
  ellipse(width/2 - 120, height/2 - 60, 90, 100); // left top 
  ellipse(width/2 - 140, height/2 + 10, 95, 110); // left bottom 
  

  // Right 
  ellipse(width/2 + 120, height/2 - 60, 90, 100); // right top 
  ellipse(width/2 + 140, height/2 + 10, 95, 110); // right bottom 
 

  // BODY --------------------------------------------------->
  fill(243, 161, 63); 
  ellipse(width/2, height - 10, 170, 200); // body position 
}

 

 

CONCEPT:
For this assignment, I built a self-portrait entirely out of shapes in p5.js. I wasn’t trying to make something realistic, instead, I went for a cartoon version of myself: a round face, messy hair, glasses, and a simple smile. The idea was to see how much “me” I could get across with just ellipses, arcs, and lines. The output is far from realistic; come on, I am not trying to replace my passport photo with this. The portrait is simple, but I like how it balances between looking generic and still recognizably like me.

HIGHLIGHTED CODE:
The glasses ended up being my favorite part. Without them, the face felt empty, but adding two circles and a line suddenly made it feel right:
  noFill();
  stroke(0);
  strokeWeight(3);
  ellipse(167, 170, 60, 60);
  ellipse(233, 170, 60, 60);
  line(200, 170, 200, 170); // bridge

REFLECTION AND FUTURE WORK:
This was my first attempt at drawing myself, and that too using code; and it showed me how powerful even basic shapes can be. It doesn’t need shading or complex details to read as a face, and luckily identify a person if the components are placed right.

However, if I had more time, I’d like to:
– Make the eyes blink or move with the cursor (saw many do that, i can’t just yet)
– Give the background more personality
– Fix the hair so it looks less like a helmet and more like actual messy hair (pretty doable with multiple ellipses but i reckon there are more efficient ways)
Even with its simplicity, I like how it turned out, it’s definitely not a mirror image, but it’s “me” enough.

Week 1 – self portrait

Concept

For the self portrait I decided to show not exactly my picture, but the picture of my inner animal.

Initially, I drew a sketch of myself, holding a camera, because photography is on of my favorite hobbies. However, I then thought of giving more meaning to my portrait, because I had a call with my mom and remembered how she always called me an owl when I was a child (reason being my sleep schedule that is still very bad). So I thought, if my sleep schedule harms my health, let me at least use it to benefit my academics.


my initial sketch

what I decided to create

Creation

It was a little challenging for me to get started on p5.js, because of my limited coding skills, but after some experiments I was able to actually create something using simple circles, triangles and lines. One of the most challenging parts was creating the feathers on my Owl’s body, so I used some help from AI. I tried not to simply copy the code, but learn how to do it on my own as well. And because this was one of the most confusing part for me, I am proud because I eventually created it.

Interactivity

I made my drawing clickable: the owl sleeps during the day but if you click it, night comes and it wakes up (just like me).

Improvements

There are a lot of things I would like to improve in my project, one of them being enhanced interactivity. I would love to add moving clouds, more complex shapes for the owl, stars at night, and many others things that could make my owl more “likable”.

Week 1 – Self-Portrait

Project Overview

For this assignment, I created an interactive self-portrait that represents me both visually and personally. The portrait includes:

  • My cartoonish face with long straight hair, eyebrows, eyelashes, nose, and mouth.
  • Interactive eyes that follow the user’s mouse, which I am especially proud of.
  • A background of colorful circles that symbolize “yarn cakes,” reflecting my love for crocheting.
  • A small bunny plushie on the side, inspired by one of my crochet projects, including tiny stitched details to mimic real crochet stitches.

    Visual Documentation

    I started with an extremely rough sketch to plan what I wanted my self-portrait to look like and the placement of facial features, hair, and background elements. I also noted a couple of interactive elements I hoped to achieve. 

    I watched a YouTube tutorial to  learn the mouse-following pupil technique, which became the most interactive and technically exciting part of my sketch: YouTube tutorial. Honestly, I struggled a lot with this part, but I was determined to get it right. I tried to make the pupils move without leaving the eyes, and after lots of trial and error, I finally figured it out.

    The circles in the background represent yarn cakes, inspired by my hobby. Crocheting is similar to knitting, but instead of using two needles, I use a hook to create loops and form fabric.

    The little bunny in the corner represents one of my actual crochet projects, and I tried to include stitch details to mimic crochet.

    Interactive Features

    • The eyes follow the user’s mouse, giving the portrait a sense of life.
    • Users can move their mouse around the canvas to see how the pupils track it.

    Technical Notes

    • Eyes: Pupil positions are calculated by taking the difference between the mouse coordinates and the center of each eye, multiplied by a scaling factor to keep pupils inside the eyeball. This took me some time to get the hang of.
    • Hair & Face: Used basic shapes (rectangles, ellipses, arcs).
    • Background Yarn Cakes: Multiple overlapping circles of different sizes and colors, inspired by real crochet yarn balls.
    • Bunny Plushie: Ellipses for the head and ears, with short lines to simulate crochet stitches.

    Research, Tutorials, and Inspirations

    • YouTube tutorials helped with  the eye-following technique.
    • Crocheting inspired the yarn cakes and bunny, making the project personal.
    • I was inspired by examples given in class and wanted to create cartoon-style self-portraits similar to them.

    Coding I Am Proud Of

    I am most proud of the eye-following interaction, which made the portrait feel alive. My code for this feature is well-commented and included below. 

    //eyes
     stroke(0);
     fill("#FCC7D9");
     ellipse(170, 120, 30, 35); //left eye
     ellipse(230, 120, 30, 35); //right eye
     fill(255);
     ellipse(170, 130, 25, 20); //left eye
     ellipse(230, 130, 25, 20); //right eye
    
     fill(0);
     let leftPupilX = 170 + (mouseX - 170) / 40; // small movement toward mouse
     let leftPupilY = 130 + (mouseY - 130) / 40;
     ellipse(leftPupilX, leftPupilY, 10, 15); // left pupil
    
     let rightPupilX = 230 + (mouseX - 230) / 40;
     let rightPupilY = 130 + (mouseY - 130) / 40;
     ellipse(rightPupilX, rightPupilY, 10, 15); // right pupil
    

    Reflection

    I am really proud of myself because this is my first time ever coding. I learned a lot of new things and hope to improve along the way.

    I wish I could have animated the yarn cakes so they floated gently in the background while the eyes moved around, making the portrait even more dynamic. Linking the yarn cake movement to the eye-following interaction could create a more immersive experience, where the background reacts to the user.

    This would enhance the interactive and playful feel of the portrait, connecting personal elements to user engagement.

Self Portrait – Week 1

Overview

For this first assignment, this was actually my very first time coding. Because of that, I wanted to keep things simple, but also try something that I thought was cool and interesting. I decided to make a portrait in a scene that could change from day to night. The feature I liked the most was being able to switch the background from morning to night with a single click, it felt like a big achievement for me and made the project more fun. Overall, I kept the shapes and details simple, but I made sure that I could still change and experiment with the code.

https://editor.p5js.org/hajarr.alkhaja/full/

https://editor.p5js.org/hajarr.alkhaja/sketches/YawBFYuSj

 

Process

We started with a warm-up in class where we learned how to make a simple circle. That gave an idea on how to code for different shapes. We also learned how to make shapes change with a mouse click, and this inspired me to add the day and night feature. I watched the tutorial videos from YouTube, which helped me understand how to use shapes like ellipses, arcs, and triangles. From there, I built my project step by step, first the background, then the grass and sky, and finally the girl. I kept it simple, using a different shape and color for each feature, and added a night variable so everything could change between day and night.

Code Highlights

At first, I really struggled with the code because I didn’t fully understand how the night variable and the if (night) statements worked. It was confusing to me how to make something happen only in the day or only in the night. Slowly, I started to get the hang of it, and once I understood the logic, it became much easier. In the end, most of my code was just repeating the same pattern in different ways, for example, changing colors, showing the sun or the moon, or opening and closing the eyes.

Another challenge I faced was figuring out where to place each shape. I had to keep adjusting the positions, running the code, and moving things again until I found the right spots. This took a lot of trial and error, but it also helped me learn how the coordinate system works.

At one point my code even stopped working completely and gave me errors I didn’t understand. I couldn’t figure out why, so I used AI to help me find the mistake. Once I fixed it, everything started working again, and I was able to continue building my portrait. Overall, I feel like I learned a lot about both the logic of coding and the patience it takes to position and test shapes.

Week 1 Self-portrait Joy

Concept

I started the idea of pixel art with this piece of wooden pixel art that we mentioned in our first class(Wooden Segment Mirror). I’m also recently obsessed with Perler Beads(plastic fusible beads to form patterns and fuse together with an iron). So, I pixelated one of my self-portraits and created a canvas of 10 * 12 colored squares.

To make it more interactive, I also use the mouseClicked function to add a more immersive version to get rid of the pixel stroke.

Code Highlight

I’m particularly proud of the color list. When I just started, I wanted to do an automatic color picker program to create the list for me. However, after a few trials, all the available auto ones cannot handle many colors, either giving a fake hex code or a single palette with a maximum of 10. Then, I did some research on manual color pickers, and I found this one(https://colorpickerfromimage.com/) to be the best hex color picker shortcut among all. Since I had to manually picking up all the colors, it also pushes me to optimize other parts of my code to use less repeated manual calls but using the loop to create all the squares.

let colors = ["#9194a6","#7d7d8f","#c29c8e","#e8bc9e","#ebbe9e","#dcac8c","#a38572","#5b585a","#5b585a","#c0cc66","#767787","#736f79","#c19a88","#e7b691","#edbb93","#daa884","#a5846d","#5b5350","#685d56","#dfe1b5","#676672","#6c6266","#ab8273","#ab8273","#e5af83","#927466","#7c6258","#544944","#665a52","#bea7a9","#5c5258","#6c5554","#a17d68","#db9f7e","#e8b08a","#5e4540","#785145","#544139","#665c56","#cecccf","#5c4b4a","#b57b64","#de9b79","#e5aa8a","#e6a68d","#d09375","#c18067","#5c443a","#6a5c57","#ccc7c9","#674e46","#cd8e6a","#eaa67d","#e1a286","#e7ab93","#e6a880","#d8946e","#5c4035","#544b47","#cdcdd3","#543d36","#d7996a","#e9ae7e","#e0a17b","#d08b5d","#e0a46d","#d39560","#3b2922","#49423b","#ccc7c4","#372623","#c28b5c","#d5936e","#c6735c","#c67255","#d59761","#7f5535","#34231c","#3a2c23","#625c43","#33221e","#644430","#e4a976","#da8667","#da7c5e","#af794d","#341d13","#39261d","#3b281e","#3b281e","#39251e","#5d402d","#d29e74","#d59d6d","#a6754b","#2b1810","#2b1b14","#422c1e","#4c3626","#28190a","#4d372d","#694735","#d09c74","#d29d72","#7c593e","#362822","#3a2b24","#442f21","#78614d","#4d3b26","#4e382f","#6a4833","#d69a74","#c99874","#49362d","#2f221f","#3c2f2b","#402d20","#876e51","#83735c"]

I also think the way p5.js displays these hex codes is another piece of art that breaks down the color of me into hex code pieces.

Reflection

For my future works, this work reminded me the importance of planning before starting. Digital art is a more well-planned process compared to free-form drawing on papers. This time, I began by creating all the squares manually, but soon I realized how redundant that was. So, I turned back to a draft note to jot down the ratio calculations. Overall, the process of choosing colors and planning turned out to be quite meditative.

Assignment 1: Self-portrait

 

Fullscreen Sketch

Concept

For this assignment, I made a self-portrait using p5.js, the online editor, with codes learned in class. I started by placing an ellipse at the center of the canvas and added smaller ellipses to make the eyes, circles for the irises, a rectangle and two circles for the nose, and thinned arcs for the eyebrows and eyelashes. Then, I used ellipses to make the shirt and a circle to show the flesh connecting the neck and shoulders, and two ellipses for the ears. After this, I created a series of arcs, all with different radians and sizes, to create the curls on the front  and the rest of the hair in the back. At last, I used the “noStroke” code and added color to the background and all the shapes.

        • Favorite Codes
        • Although it isn’t the most creative or incredible code, I felt proud when I assembled the codes to create the structure of the face. I like the way the face, the neck, and the collarbone follow the founding shapes usually used for drawing sketches. While I am used to add more texture when I draw a person by hand or digitally, it is nice to see these shapes in a raw form, without any details or realism, and instead have a similar composition to a cartoon character. It was also fun to create the curls with the different variations of radians of the arcs.
           
          fill('#DA9758')
           circle(275, 333, 23);
           circle(325, 333, 23);
           rect(282, 258, 35, 85);
           circle(300, 338, 28);
           
           fill('white')
           ellipse(205, 250, 80, 30);
           ellipse(385, 250, 80, 30);

           

Embedded Sketch – Self Portrait

Reflection and Ideas for Future Improvement

One of the steps I struggled the most with was finding the right coordinates for the different shapes, especially when each shape had a different amount of values (for example, the circle only had three and the arc could have more than five). This was especially hard when I had to consider where in the canvas I wanted them and details such as height, width, etc. However, the more I practiced, the easier it became to mark said coordinates and sizes.

For the future I would like to learn how to further mold the different shapes to create more varied and distinct shapes. For example, instead of having to use the ellipses and the rectangle to make a neck and shoulders, I would like to understand how to create connected dots or merging shapes that can create this structure in a smoother, slightly more realistic way.

Week 1: Made this While I was Hungry (Self-Portrait)

(Try Clicking on the Mouth when it’s Open!)

I had a few ideas of how I wanted to depict myself, none of which included a real depiction of my face, but more or less characters that I resonated with. I quickly scrapped that idea when I felt like it wouldn’t really be challenging me if I drew a depiction of an already existing illustration.

With my limited coding experience it would be certainly difficult to go from concept into actualization using just my keyboard and the funny colored words on screen, but I was committed to making something worth looking at.

One of the first things I tried to understand coming from a long photoshop/graphic design background was how layers would work on p5.js. Understanding this early gave me a lot of confidence that I wasn’t going to make something uncanny-looking. I made each body segment its own function and called it in the order from the lowest layer to the highest layer in draw()

function draw() { //draw runs on loop 60/sec
  background(110,40,80);//change later?
  
  //Draws Body Parts in Layers
  drawHair();
  drawTorso(90);
  drawHead();
  drawLeftEye(6.7);//parameter is for gap between lines
  drawRightEye(6.7)
  drawMouth();
  drawHands();
  drawBangs();
}

As I learned more about p5.js through tutorials, I wrote down lots of notes and reminders to myself. One tip that really helped me out initially was putting fill() before the shape I wanted to draw. When I was listening to the demonstration in class I thought it would make more sense for fill() to have parameters for what you wanted to fill, but after working with the shapes today I realized that would’ve caused a big confusing wall of text very quickly. Putting notes next to how many parameters and what each parameter did for each function was also really helpful in my learning process.

I wasn’t quite sure how to depict the face at first with just simple geometry but by removing the outline “strokes” and blending shapes I started sculpting some much nicer shapes.

I really wanted my avatar’s arms to be interactable with the user’s mouse values so I initially allowed the top Y-positions of the arm segments to be controlled using the mouse. I obviously didn’t want it to go out of bounds so I looked through the p5js reference until I found the constrain() function. This was a huge lifesaver for both this aspect of the self-portrait and some other aspects I worked on after this.

let armY = constrain(mouseY, 430, 500); //restricted value, min, max
  let armX = constrain(mouseX, 200, 350); 
  
  //LEFT
  quad( 
    armX-60, armY, //top left 220~
    armX-10, armY+20, //top right 280~
    220, 600, //bottom right
    100, 600  //bottom left
  );
  //RIGHT ARM
  quad( 
    armX+110, armY, //top left 380~
    armX+60, armY+20, //top right 320~
    width-220, 600, //bottom right
    width-100, 600  //bottom left
  );

This snippet was taken as I was working out the arm animation and tracking. Mini-me was very deprived of any type of hair back then. He was also very gray.

Fig 1. Snapshot Right After Figuring Out Arm Animations

I feel like the hand movements made the avatar feel so much more alive and responsive, making good use of p5.js in ways beyond just turning code into still images. This would go a step beyond when I added the cookie into mini-me’s hands then another step beyond when the mouth would respond to having a cookie in front of it.

//COOKIE
fill(210, 180, 140);
stroke(190, 160, 120);
cookieX = armX+25
//main cookie area
if (cookieEaten) {
  arc(cookieX,armY,150,75,5.7,3.5) //cookie missing the top corner
  console.log("Cookie was Eaten")
} else {
  arc(cookieX,armY,150,75,0,2*PI) //a full cookie
}
//chocolate chips
fill(90, 60, 40);
noStroke();
//top left to bottom right
ellipse(cookieX-50,armY-10,19,14)
ellipse(cookieX-21,armY-2,16,10)
ellipse(cookieX-37,armY+10,12,7)
ellipse(cookieX+3,armY+8,17,12)
ellipse(cookieX+22,armY-6,12,8)
ellipse(cookieX+29,armY+20,15,10)
ellipse(cookieX+38,armY+2,18,13)

At first I didn’t have any chocolate chips on the cookie and my friend thought it was holding an empty plate so I decided to add some chocolate chips even though the way I did it was probably not very efficient. I considered using random variables like I’ve seen some previous projects utilize for their backgrounds but the choco chips needed to avoid a very specific area of the cookie that would be “bitten” into while looking well balanced.

One of my goals with the cookie in hand was to let the user be able to eat it by clicking on the mouth of mini-me, but I didn’t know how to program a bite mark into the ellipse so I decided to change it into an arc() halfway through and use the arc’s unique properties to cut out a portion of it near the mouth, making it appear like it had been bitten into. I was pretty proud of how I worked with my limited knowledge here.

cookieEaten = false
function mouseClicked() {
    console.log(mouseX,mouseY)
    if (mouseX > 280 && mouseX < 320 && mouseY > 330 && mouseY < 400){
      cookieEaten = true; 
      console.log("clicked mouth");
     }  
  }

//lots of stuff here in between in the real code...

if (cookieEaten) {
    arc(cookieX,armY,150,75,5.7,3.5) //cookie missing the top corner
    console.log("Cookie was Eaten")
  } else {
    arc(cookieX,armY,150,75,0,2*PI) //a full cookie
  }

By far the most unsatisfying part to me was definitely the way I did my hair. There were just so little polygons to work with to properly express what type of hairstyle I wanted for mini-me. However, a lot of my friends said they actually really liked how I depicted the hair so perhaps I’m fixating on it too much.

My biggest regret was that I only learned after I was nearly done with my self-portrait that I could’ve changed the angleMode() to degrees the whole time… I spent so much time trying to remember middle school math just to work out the PI angles for certain arcs.

//the upper lip
arc(cenX - 210/4, faceCenY, 150, 150, PI/4, PI/2); //left side
arc(cenX + 210/4, faceCenY, 150, 150, PI/2, 3*PI/4);//right side

If I were to do this exercise again, I would probably create more variables to make certain parameters look a little more organized and efficient. I changed a few parts to stuff like “width-X” rather than calculating it myself but there was definitely more I could’ve done to make everything look cleaner.

Overall for my first experience with p5.js and my limited experience with JavaScript , I think I would be proud of myself even later down the line.

Week 1 Self-Portrait (Asma)

The moment a friend joked that I’m “basically a flower,” while I was brainstorming ideas for this task, I knew exactly what I wanted to draw! A happy, cartoon daisy standing in for my portrait. Instead of wrestling with a realistic self-portrait, I leaned into something more playful and honest, something that resembled me in being bright, a little goofy, and imperfect in the best way. That choice took the pressure off and made the assignment fun, I wasn’t proving I could render a realistic portrait, but rather show a bit of personality.

Color was deliberate in this portrait. I picked a soft pink background (`#fae`) because it feels light and friendly, like a page from a sketchbook. The petals are white with a clean black outline because daisies are my favorite and that crisp edge gives a bold, sticker-like cartoon look. The center is a warm yellow (classic daisy!), and the stem is a saturated green so it reads immediately even at a glance. Together, the palette stays simple, cheerful, and high-contrast, perfect for for clarity on screen.

There were two small decisions that made a big difference. First, was the draw order: I coded the petals before the center so the yellow circle sits neatly on top. p5.js applies fill and stroke at the exact moment you draw, so layering matters, getting that step right eliminated messy overlaps without extra code. Second, the smiley face: two tiny circle calls for eyes and a single arc for the smile gave the flower a personality however this was probably the hardest part. I watched a few YouTube videos about coordinates which is how I learned to use “cx” and “cy” so I wasn’t typing magic numbers everywhere (much easier to tweak).

The smiley face was the specific piece of code that I was proud of. I know it looks very simple but it definitely took me the longest time to get right without looking completely wonky!

// Smiley
 const cx = 300, cy = 200;
 fill(0); noStroke();
 circle(cx - 20, cy - 15, 12); // left eye
 circle(cx + 20, cy - 15, 12); // right eye
 noFill(); stroke(0); strokeWeight(4);
 arc(cx, cy + 15, 60, 40, 0,PI);

What went well: I kept the geometry minimal (lines, ellipses, and circles). The result feels cohesive: the color palette, the outlines, and the proportions all read “cartoon daisy” immediately. What I could have done better: the petals aren’t perfectly placed since I originally wanted to do 5, and they look kind of odd, some spacing could be cleaner. I wish I had more time to work on this so I could adjust the shapes to my liking.

Looking ahead,  I’d also like to add motion, a subtle stem sway maybe or a smile that reacts on hover/click. Or perhaps, adding clouds or a sun in the background. For now, I’m happy that it isn’t perfect, neither am I, and that’s kind of the point. I’m still getting into the rhythm of JavaScript, and this little daisy felt like the right way to bloom.