Assignment 4 – Generative Text Output

Concept + references

 

This piece was inspired by the landscapes that are usually used for some songs when a person wants to look at the lyrics, and I thought it would be a nice idea to explore with the generative text output. Although the parameters and functions used are very similar to the ones we learned in class, I tried to make changes to the structure of the text, as well as its position in the canvas, the background, and the color of the text. Overall, the generative text output resulted from a combination of words which I found most “romantic” and appealing, while also integrating a sense of “discomfort” laced within the text.

Highlight code

As previously mentioned, most of the codes are drawn from the ones learned in class. Despite this, my favorite code I incorporated into this project was the use of random text color and the gradient color background. These codes allowed me to 1) set a random change of color of text that adjusts to the random changes of the words for each sentence, and 2) create a gradient color background to resemble a sunset.

// This function is to make the background colors gradient
let c1, c2;


function setup() {
  createCanvas(400,400);
   c1 = color(240, 0, 110); // Red
  c2 = color(240, 120, 0); // yellow
  // setting the function so that the colors are displayed 
  
  
  
  // Number of lines (2)
print('The number of lines:' + strings.length);
print(strings);
  
}


function draw() {
  background(255);
  
  
  // mapping the text from excel to the canvas
  for (let y = 0; y < height; y++) {
        let n = map(y, 0, height, 0, 1); // Scale y to a 0-1 range
        let newColor = lerpColor(c1, c2, n); // Interpolate between colors
        stroke(newColor);
        line(0, y, width, y); // Draw a horizontal line
      }

  // random function for text color
    // these are random RGB values
  let r = random(255);
  let g = random(255);
  let b = random(255);

 

Embedded sketch

 

Reflection and ideas for future work or improvements

While this project was able to fill the basic requirements for a generative text output, I wish I could have been more creative and explore a different and more interactive way of displaying the text. For future works, I will try to research in advance how to implement interactivity while also taking in consideration the time needed and if the techniques I found are accessible to my level of experience.  Nevertheless, I do appreciate the visual aspect of the work, and believe it adjusts to my initial vision of how I wanted the outcome to be.

Week 5 – reading

  • What’s something (not mentioned in the reading) that drives you crazy and how could it be improved?

I wis Norman’s analysis went deeper into economic incentives behind poor design. While he touches on cost-cutting measures, like companies using “the least expensive sound device” that can only beep, or single lights with confusing flash patterns instead of clear displays, he doesn’t fully address whether some companies intentionally create poor user experiences.

I suspect many businesses actually profit from user confusion. Think about subscription services with deliberately maze-like cancellation processes, or software that makes basic functions require premium upgrades (Dark UI/UX patterns). Norman notes that when people struggle with technology, “the people are blamed for not understanding the machine” – but this blame-shifting can be profitable through tech support fees, extended warranties, or forcing users toward expensive premium versions. Apple is notoriously known for doing this.

Norman hints at this when discussing cost reduction forcing designers to use inadequate feedback systems, but I wish he’d been more direct about the perverse economic incentives. Sometimes bad design isn’t just oversight – it’s strategy. Companies know users will adapt and memorise workarounds rather than switch products, especially when switching costs are high.

  • How can you apply some of the author’s principles of design to interactive media?

In my interactive media and web design work, I constantly rely on Norman’s concept of discoverability. Having built apps and websites, I’ve learnt there are established conventions most users already understand – the hamburger menu, colour changes indicating clickable text, or standard navigation patterns.

These conventions work as what Norman calls “signifiers”, they provide clues about what actions are possible and where to perform them. When I use a familiar icon or follow expected layout patterns, I’m leveraging users’ existing mental models rather than forcing them to learn arbitrary new systems in the hopes of a simpler smoother user experience.

Norman’s principle of natural mapping is also significant. Just as he advocates arranging light switches to match the pattern of the lights they control, I arrange interface elements to match users’ spatial expectations. Navigation goes where people expect it, buttons look like buttons with proper visual hierarchy, and interactive elements behave as they should.

The key insight I take from Norman is that good interactive design should feel invisible – users shouldn’t have to think about how to use it. I should be able to show my work to someone who hardly interacts with websites and be confident that they will able to navigate around my work without additional instructions. If I have to add text for something simple, it is a good indicator that I didn’t design my solution well.

Week 4 – Persian generative text

Inspiration

For this week, I was really struggling on what to do I was prompting with Claude AI and decided to go with the generative text option. I knew I wanted to do something with a different language and then decided to go with my mother-tongue, Farsi. Persian poetry is famous and so I wanted to choose a quote that had a theme, replicate that theme in p5.js with shapes and colours.

My name in Farsi ‘خاطره’ means memory, remembrance, longing – something along those lines. It was difficult to find old poetry with that word as it is more modern but I liked the theme of memories and love so I went with the following line from Rumi – Masnavi (مثنوی معنوی)

Rumi is a 13th century poet and was known for his work regarding mystical themes in Islam (Sufism). Majority of his work is in Persian and very famous.

Idea

This was the quote I went with.

let poem = {
persian: “بشنو از نی چون حکایت می‌کند، از جدایی‌ها شکایت می‌کند”,
transliteration: “Beshno az ney chon hekayat mikonad, Az jodayiha shekayat mikonad”,
english: “Listen to the reed flute, how it tells a tale, complaining of separations”,
};
I wanted the words to be floating around, referring to ‘separation’, and. I want the colours / shapes to be pink, hearts just to refer to love.
I also wanted the user to be able to see the quote altogether so that they can see the final image.

Heart

There is no heart shape in p5.js so I was looking at different examples with math function and came across this link. The artist uses sin and cos functions to connect the hearts.  https://editor.p5js.org/marlontenorio/sketches/M_BGUpfKL

I edited it to suit the image in my mind. I made it a function with the size parameter because I wanted the heart to have some sort of pounding effect.

drawHeart(size) {
        beginShape();
        let s = size * 0.5;
        for (let t = 0; t < TWO_PI; t += 0.1) {
            let x = s * (16 * pow(sin(t), 3)) * 0.03;
            let y = -s * (13 * cos(t) - 5 * cos(2*t) - 2 * cos(3*t) - cos(4*t)) * 0.03;
            vertex(x, y);
        }
        endShape(CLOSE);
    }

Interactivity

Click Mouse

I wanted the user to be able to add words or hearts when the mouse is pressed.

function mousePressed() {
    hearts.push(new Heart());
    texts.push(new Text(mouseX, mouseY));
    
    // Limit elements
    if (hearts.length > 15) hearts.shift();
    if (texts.length > 15) texts.shift();
}

I added a limit so the program won’t be too complex. The words added would be from either the Persian, transliteration, or English – and at the point of the mouse. The hearts would simply be added randomly on the canvas.

SpaceBar – pressed

I wanted a way for users to add more words to screen, but a bunch of words. So I added the keyPressed function for the spacebar so that they user can see more words at once.

function keyPressed() {
    if (key === ' ') {
        for (let i = 0; i < 3; i++) texts.push(new Text());
    }

 

A / a – pressed

I wanted a way for the user to see the 3 versions of the poem at once, so I just used the A button as that trigger.

I have a Text class that will choose random words from the 3 lines verses and then have the floating simulation similar to the hearts. I also wanted these words to have some lifespan and disappear into the background slowly to reference the theme of the separation and memory.

class Text {
    constructor(x = random(100, width-100), y = random(100, height-100)) {
        this.x = x;
        this.y = y;
        this.text = this.getRandomText();
        this.size = random(14, 20);
        this.life = 0;
        this.maxLife = random(400, 800);
        this.dx = random(-0.3, 0.3);
        this.dy = random(-0.2, 0.2);
    }

Here is the display function and how it uses alpha to dictate the opacity. Depending on the life value, the opacity of the text changes.

display() {
    let alpha = this.getAlpha();
    if (alpha <= 0) return;
    
    push();
    textAlign(CENTER, CENTER);
    textSize(this.size);
    fill(340, 50, 90, alpha);
    noStroke();
    text(this.text, this.x, this.y);
    pop();
}

// calculate the opacity value for fading 
getAlpha() {
    let ratio = this.life / this.maxLife; // value between 0 and 1
    // fade in at the first 20% of life
    if (ratio < 0.2) return map(ratio, 0, 0.2, 0, 0.8);
    // fade out at the last 20% of life
    if (ratio > 0.8) return map(ratio, 0.8, 1, 0.8, 0);
    // stay mostly visible in the middle
    return 0.8;
}

Complete poem texts

Whenever the ‘a’ button is pressed, I would add the whole lines of poetry to the texts variable so that it would float around exactly like the singular words. I also added the life parameter as the same so that they disappear at the same time.

function showCompletePoem() {
    texts = [];
    let centerX = width / 2;
    let startY = height / 2 - 60;
    
    // add complete poem texts
    let persian = new Text(centerX, startY);
    persian.text = poem.persian;
    persian.size = 24;
    persian.maxLife = 1200;
    texts.push(persian);
    
    let transliteration = new Text(centerX, startY + 50);
    transliteration.text = poem.transliteration;
    transliteration.size = 18;
    transliteration.maxLife = 1200;
    texts.push(transliteration);
    
    let english = new Text(centerX, startY + 100);
    english.text = poem.english;
    english.size = 20;
    english.maxLife = 1200;
    texts.push(english);
}

It is also important to remove ‘old’ texts from the array once their life is ‘complete’. This gets checked in the draw function.

// remove old texts
texts = texts.filter(text => text.life < text.maxLife);

Next time

Next time, I would definitely want to add some flute noises to really tie the piece together. Next time I should probably add some message to indicate which key / mouse action equates to each action.

Outcome

Week 4 – Post Response

Post Response: The Psychopathology of Everyday Things

One thing that drives me crazy, which wasn’t directly mentioned in Norman’s reading, is the “close door” button on elevators. It feels like a control I should have, but in most modern elevators, pressing it does absolutely nothing for ordinary passengers. The button is just there to give the illusion of control, which is frustrating when you actually want the doors to close faster. A simple improvement would be to either remove the button entirely or make it functional for real—perhaps by allowing it to slightly shorten the automatic door timer, while still respecting safety regulations. This would reduce the cognitive dissonance between what the interface suggests and what it actually does.

Another example is the volume slider on phones. While it looks linear, the actual increase in volume is logarithmic to match human perception. This hidden design is clever, but it highlights how designers are constantly manipulating reality to feel “natural.” I find it fascinating—and slightly maddening—how often interfaces are designed to trick our senses into thinking things are more intuitive than they are.

Applying Norman’s principles to interactive media, these insights are extremely valuable. For example, in a music app or video game, sliders for volume, brightness, or character speed should be perceptually adjusted so that changes feel smooth and intuitive. Similarly, buttons or controls should give honest feedback: if an action can’t actually happen (like the elevator door closing instantly), the interface should indicate that limitation rather than pretend otherwise. This reduces user frustration and improves overall satisfaction.

In general, understanding the psychopathology of everyday things encourages designers to consider the gap between perception and reality. By designing interactions that match how humans perceive the world, we can make digital interfaces feel more natural and enjoyable.

Week 4 – Text Art

Concept

My artwork “Can You Understand Me?” explores human connectedness through language and the barriers that can arise when communication breaks down. The phrase “Can you understand me?” is a simple but powerful question, expressing both the desire for connection and the frustration of being misunderstood. By placing this phrase in multiple world languages on the screen, I wanted to highlight the diversity of expression and the universality of the human need to be heard.

The floating words and question marks represent the fluid, sometimes chaotic nature of communication. They drift, interact, and repel—mirroring how language can bring people closer or push them apart, depending on understanding.


Code Highlight (what I’m most proud of)

One feature I’m especially proud of is the repelling effect from the mouse. I designed this so that when the mouse gets too close, the words push away. It represents the tension we sometimes feel in conversation—when misunderstanding or pressure creates distance, even when connection is desired.

Repel from mouse let mouse = createVector(mouseX, mouseY);
let d = dist(this.pos.x, this.pos.y, mouse.x, mouse.y);
if (d < 200) {
let force = p5.Vector.sub(this.pos, mouse);
force.setMag(8 / max(d, 1));
this.vel.add(force);
}

This snippet calculates the distance between each word and the mouse, then generates a force pushing the word away when the mouse is within 200 pixels. It’s a small detail but adds a lot of dynamic personality to the sketch.


Embedded Sketch


Reflection

Working on this project taught me how much movement and interaction can symbolize deeper human experiences. The floating words show how languages circulate and intermingle globally, while the mouse repulsion adds an element of friction, symbolizing the challenges of cross-cultural communication.


Reference

Week 4: Passing Moments (Data Visualization)

(higher amplitude = longer sleep; larger frequency = longer lifespan)

Conception

In this project I wanted to demonstrate the idea of passing moments and how your total lifespan affects how fast you may perceive each moment. Since I love animals, the project started with me just wanting to play around with some data regarding animals; however, I was struggling to find something interesting.

At first I had some data with brain mass and wanted to compare each animal’s brain mass to body mass ratio using circles but it ended up looking very bland so I completely scrapped that sketch.

Then I looked around online for some more databases until I found one that had both lifespan and sleep durations. I thought I could perhaps make something to visualize the impermanence of life and demonstrate the idea of “passing moments.” You could say it’s a bit of a memento mori in a way for both you and the animal mentioned on screen.

Development

I was thinking of how I could represent lifespan and I thought about the heart rate monitors beside hospital beds. I thought perhaps I could use sin waves to represent life span and have the amplitude and frequency be scaled with different things, so that’s what I went with.

I matched the frequency with their life span 

let frequency = map(chosenMammal.lifeSpan, 2, 80, 0.02, 0.08);
...
sin(x*frequency - frameCount * 0.1)

Then I matched the amplitude with hours of sleep per day

let sleepHours = chosenMammal.totalSleep;
let ampMult = 8;
...
let y = height/2 + sin(x*frequency - frameCount * 0.1) * sleepHours * ampMult;

Together, I was able to use the beginShape() and endShape() functions to create a continuous animated sine wave for the mammal. However, that felt like it lacked a frame of reference so I added another wave behind it in gray to represent humans. This way, it could really put into perspective just how fast each moment for us vs the chosen mammal was. I was quite proud of how this part turned out.

function drawSleepSpiral(chosenMammal, color){
  let sleepHours = chosenMammal.totalSleep;
  let ampMult = 8;
  let frequency = map(chosenMammal.lifeSpan, 2, 80, 0.02, 0.08);
  
  push();
  noFill();
  
  if (chosenMammal == allMammals[21]){ //21 is human
    stroke(200);
  } else{
    stroke(color);
  }
  
  strokeWeight(6);
  beginShape();
    for (let x = 0; x < width; x+=1){
      let y = height/2 + sin(x*frequency - frameCount * 0.1) * sleepHours * ampMult;
      vertex(x,y);
    }
  endShape();
  pop();
}

I wasn’t happy with how the default font looked so I loaded in a very beloved font, Helvetica, into the project with what we learned last week.

textFont("Helvetica");
textAlign(CENTER, CENTER);

I was also thinking of adding a text input for the user to put in how many hours they sleep and compare that to the mammal onscreen but I felt like that took away from the idea of lifespan and sounded more like I wanted the user to acknowledge how healthy their sleep schedule was, which I thought would greatly detract from the memento mori effect I was aiming for.

Lastly I added a mousePressed function to cycle through the database without having to hit the start button each time.

function mousePressed(){
  chosenMammal = random(allMammals); // switch to a new mammal on click
  randomColor = random(colorArray); //changes to a random color with the same click
}
Conclusion / Difficulties Endured

I didn’t even realize I could upload my own files and create folders in the sketch files until this past week so this production piece provided me with a lot more insight into what p5js is capable of.

I initially had some trouble figuring out how to get the data out from the CSV file in a natural and efficient way but then I remembered I could extract each column data as a separate characteristic of my object like this:

for (let i = 0; i < table.getRowCount(); i++) {
  let mammalObject = {
    species: table.getString(i, "Species of animal"),
    bodyMass: table.getNum(i, "Body Weight (kg)"),
    brainMass: table.getNum(i, "Brain Weight (g)"),
    totalSleep: table.getNum(i, "Total sleep (hrs/day)"),
    lifeSpan: table.getNum(i, "Maximum life span (years)")
  };
  allMammals.push(mammalObject) //now i can obtain mammalObject.bodyMass for instance
}//closes for() after appending all mammals

This made the process of finding specific attributes of the chosen mammal so much more convenient and efficient.

I also made sure credit the source of my database at the very end of my code: https://gist.github.com/yppmark/d907dc265a84cac76ba7

Week 4 Reading Response

Prompt:

  • What’s something (not mentioned in the reading) that drives you crazy and how could it be improved?
  • How can you apply some of the author’s principles of design to interactive media?

Response:

One of the inventions that drives me crazy on weekly basis is the washing machine. When I tried to do laundry, I am always confused on multiple options that are provided on the panel.

As demonstrated by the picture above, I am confused by the information presented. What is easy care? what is its difference with skin care? when should I choose easy care? When choosing the temperature, how will different temperature affect the washing effect? As a result, I need to go through multiple websites to look for my answer. To improve on this process, I believe the machine could be more interactive. For example, using a display screen to ask users to choose what type of clothes are they washing and then asking how long would they want to wait, etc.. To save the machine from asking repeated question, the screen could provide a default option for users if users have found the best washing mode.

I want to focus on HCD later on for my interactive media works. I always admire how Steve Jobs design the iPad. He successfully incorporated the touch screen technology with very intuitive human interaction as he stated that a 6-year-old could start playing games on iPad without any instruction(visual, text, etc.) (https://www.forbes.com/sites/michaelnoer/2010/09/08/the-stable-boy-and-the-ipad/). Everything should be intuitive and audience could receive very clear feedback after they interact.

Week 4 – Reading Response

One thing that drives me crazy is the overcomplicated interface of most modern microwaves. Even as someone who’s pretty tech-savvy, I groan every time I use a new one. 10+ buttons are there for “defrost poultry,” “bake potato,” “reheat pizza,” and more, when all I usually need is to heat up leftovers. Half the time when I use a new microwave, I end up pressing random buttons wasting an equal amount of time to set a basic 2-minute timer. It feels like designers prioritize “showing off” features over usability, exactly as Norman warns. They cram functions to make the microwave seem advanced, but they forget the core user need. Simplicity.

This frustration ties directly to Norman’s principles. The microwaves lack good signifiers, as there’s no clear visual cue (like a large, labeled “Quick Heat” button) to guide basic use. The mapping is muddled, too, as why is “Popcorn” next to “Sensor Cook” when most users reach for quick heating first? They are inherently all part of audience “affordances”—I don’t like this word, as we could simply call it design “friendliness”—which the author argues, sometimes contradicts with the designers’ desire to “show off”.

I agree to a certain extent. On the other hand, however, a designer IS capable of prioritizing human-centered design as their end goal—think of Steves Jobs or a random Apple designer—it is also a process to perfection to excel in design friendliness. How about this simple, intuitive microwave you might have seen: a large digital dial for time (natural mapping) and one “Start” button, plus a small “More Functions” menu for niche uses. This keeps discoverability high, because even a first-time user would know to twist the dial, and reserves extra features for those who need them, without cluttering the experience.

Design doesn’t have to choose between “impressive” and “usable.” Apple proves this by making complex tech feel intuitive, and microwaves could do the same, once designers focused on what users actually do instead of what they think looks good.

Week 4 – Torrent of Transience

For this week’s assignment, I wanted to take the NYC Leading Causes of Death data and turn it into generative text art on p5.js. Initially, I was torn between a “Data Rain” concept where statistics fall like a cascade, and an “Unraveling Text” idea where words literally dissolve, mirroring entropy. 

After some back-and-forth, I settled on combining the two into what I’m calling “Torrent of Transience”. The core idea is a continuous stream of disease names falling from the top of the screen. But it’s not just falling. Each word is actively dissolving, blurring, and fading as it descends, vanishing before it even reaches the bottom. It’s meant to evoke a waterfall of ink words, where the ink itself is dissolving as it flows.

The challenge was mapping the data in a way that felt intuitive and impactful. I decided that the Deaths count for each cause would determine the textSize – larger words for more fatalities, making their presence felt more strongly. The Age Adjusted Death Rate also became useful, as it controls both how fast the word falls and how quickly it dissolves. So, a cause with a high death rate will rush down the screen and disappear rapidly, a stark visual metaphor for its devastating impact.

I also made sure to clean up the data. Those ICD-10 codes in the Leading Cause column were a mouthful, so I’m stripping them out, leaving just the disease name for clarity. And I’m filtering for valid Deaths and Death Rate entries, because a null isn’t going to map to anything meaningful.

For the “unraveling” effect, I knew textToPoints() on every single particle would crash the sketch. My solution was a bit of a cheat, but effective: I draw each word a few times, with slight random offsets, and increase that offset as the word fades. This creates a ghosting, blurring effect that visually implies dissolution. Coupled with a semi-transparent background, it gives the impression of words literally melting into the ether.

Right now, the dataSample is a curated (i.e., selected) list of causes to get the demo running smoothly. If this were a full-blown project, I’d implement a way to dynamically load and parse the entire CSV, allowing the user to select a year and see a completely different torrent. That’s a future enhancement, but for now, the sample gives a good impression of the dynamic effect.

Assignment 4 – Generative text output

Concept

For this project, I wanted to challenge myself and experiment with generative text output. I thought it would be interesting to create a program that builds short messages by mixing different pieces of text together. I wrote sentence templates with placeholders and then filled those placeholders with random words from lists of activities, places, events, and more. This approach makes every message different, even though they all follow a similar style. Each click shows a new message, so the text keeps changing and never feels the same. After eight messages, the conversation refreshes and starts again, so it feels like a brand-new chat every time. I also made the layout look like a chat screen, with colored message bubbles and a date at the top, so it feels like you are reading a conversation.

Highlight of the code I am proud of

The part I am most proud of is making the messages switch sides and look like a real chat conversation. As a beginner, figuring out how to alternate the chat bubbles between the left and right side was tricky, but using nextMessageIndex %2 to alternate sides worked perfectly.

// Interaction: add new message when mouse is pressed

function mousePressed() {
  if (nextMessageIndex === 0) {
    messages = [];  // clear canvas after 8 messages
  }
  let side;
  if (nextMessageIndex%2==0){ // Alternate sides
    side = 'left';
  } 
  else{
    side= 'right';
  }
  messages.push({
    text: generateMessage(),
    side: side
  });

  nextMessageIndex+=1;
  if (nextMessageIndex >= 8) { // Reset counter after 8 messages
    nextMessageIndex = 0; 
  }
}

Another thing I am proud of is the way I handled text wrapping. At first, I didn’t know how to make long messages fit inside the bubbles, but I learned how to split the text into words and build lines that stay within the bubble’s width. It made the conversation look clean and easy to read.

// Text wrapping into lines

let words = m.text.split(" ");  // Split message into words
let lines = [];
let tempLine = "";
for (let w of words) {
  
   // Check if adding word exceeds bubble width
  if (textWidth(tempLine + w + " ") < bubbleMaxWidth - 20) { 
    tempLine += w + " ";  // Add word to current line
  } else {
    lines.push(tempLine); // Save current line
    tempLine = w + " ";  // Start new line with current word
  }
}
lines.push(tempLine); // Add last line

Sketch

Click the mouse to add a new message

Reflection

While making this project, I wanted to experiment with generative text output and see how random combinations of words could create a conversation. I am proud of how the messages alternate between left and right, making it feel like a real chat, and how the text wrapping keeps the messages neat inside the bubbles. For the improvements, I would like to add more templates and word lists to make the conversations even more interesting, maybe even including images in the chat bubbles. Also, one of the improvements would be adding a typing animation to make it feel more like a real conversation, and make it mobile-friendly so it works on smaller screens.