MIDTERM PROGRESS

Concept

ConceptFor my midterm project, I’m creating “Digital Kente,” a generative art system inspired by Ghana’s traditional Kente cloth. Kente originates from the Ashanti Kingdom and is deeply symbolic – each color represents something (gold for royalty, green for growth, red for passion) and the geometric patterns tell stories. Instead of creating organic, flowing generative art, I’m constraining the system to produce structured, geometric patterns that echo the woven textile tradition. The challenge is translating the craft of weaving into code while maintaining cultural authenticity.My system uses horizontal bands with different geometric motifs – zigzag diamonds, checkerboard patterns, diamond shapes, and horizontal stripes – all arranged like traditional Kente strips. Each band uses specific color combinations from authentic Kente palettes extracted from reference images. The patterns are grid-based and angular, mimicking how warp and weft threads create precise geometric designs through repetition and intersection.Cultural Context:
Kente isn’t just decorative – it carries meaning. The geometric patterns I’m implementing (zigzag diamonds, checkerboards) are traditional motifs with cultural significance. By bringing Kente into generative code, I’m exploring how traditional craft techniques can inform computational creativity while respecting the cultural heritage. Inspiration:

-Traditional Ghanaian Kente weaving patterns
-The geometric precision and bold color blocking of woven textiles
-How simple thread intersections create complex visual patterns
-Memo Akten’s approach to mathematical constraints creating variety

Some Kente Samples

Current Sketch

Milestones and Challenges
Milestones

-Researched traditional Kente patterns and extracted authentic color palettes
-Implemented grid-based system for geometric precision (20px cells)
-Created 4 distinct pattern types: zigzag diamonds, checkerboard, diamond motifs, and horizontal stripes
-Developed band system where each horizontal strip uses different patterns
-Added palette switching between Ashanti (warm) and Ewe (bold) color schemes
-Implemented texture lines to simulate woven thread appearance

Challenge 1: Maintaining Cultural Authenticity While Being Generative
My biggest struggle has been balancing algorithmic freedom with cultural respect. Early versions used smooth Perlin noise and organic curves – it looked generative but didn’t feel like Kente at all. Real Kente is precise, geometric, and structured. The breakthrough was realizing I needed to constrain the generative system rather than make it more random. By limiting patterns to grid-aligned shapes, sharp angles, and bold color blocks, the output finally started resembling actual woven cloth. The lesson: sometimes creative constraints (cultural traditions) produce better results than total freedom.

Challenge 2: Color Distribution Balance
Kente cloth doesn’t use colors randomly – certain colors dominate while others accent. My first attempts assigned random colors to each cell, which created visual noise rather than the bold color blocking you see in real Kente. I solved this by creating “band colors” – each horizontal band gets a curated subset of 2-3 colors from the full palette, not all 5. This mirrors how traditional weavers select specific thread colors for each strip. Now band 1 might use gold/orange/black, while band 2 uses green/red. This creates visual rhythm and hierarchy instead of chaos.

Current System Architecture
The system is organized into layers:
1. Color Palettes:

Extracted from actual Kente cloth samples
Two palettes: Warm Ashanti and Bold Ewe
Each band selects a 2-3 color subset for cohesion

2. Band System:

Canvas divided into horizontal bands (8 cells high)
Each band assigned one of 4 pattern types
Patterns cycle predictably: zigzag → checker → diamond → stripes → repeat

3. Pattern Functions:

drawZigzagBand() – Creates diagonal zigzag forming diamonds
drawCheckerBand() – 2×2 checkerboard with alternating colors
drawDiamondBand() – Concentric diamond shapes
drawStripeBand() – Horizontal color stripes with vertical texture

4. Animation:

Subtle time-based offsets in pattern calculations
Creates gentle “breathing” effect without losing structure
Can pause/resume with mouse click

 

Next Steps
Moving forward, I plan to:

-Implement multiple operational modes (particle weaving, harmonic oscillation, flow field variants)
-Add resolution scaling for A3 print size (2480 × 3508 px)
-Integrate traditional Ghanaian sounds (weaving sounds, drumming) for cultural immersion

Reflection So Far
The most valuable lesson from this project is understanding that constraint breeds creativity. By limiting myself to geometric shapes, grid alignment, and traditional color combinations, I’m forced to be more thoughtful about every design decision. This is similar to how real Kente weavers work within the constraints of their looms and thread colors yet produce infinite variety.
Working with cultural source material has changed my approach to generative art. Every design choice now asks: “Does this honor the tradition?” rather than “Does this look computationally interesting?” The planned audio integration will take this further – transforming the project from a purely visual experience into something that engages multiple senses with traditional weaving sounds and Ghanaian drumming.
The system already produces distinct looks depending on which patterns align, how colors distribute, and where the animation phase is captured. Once I add the additional modes and layer in traditional sounds, the generative space will expand while maintaining Kente’s visual and cultural language.

 

Assignment 4

Concept

For this assignment, as stated in the assignment prompt, I was inspired by Memo Akten’s Simple Harmonic Motion series, where he uses pure mathematical oscillation to create hypnotic, organic visuals. His work showed me that layering simple sine waves together can produce patterns of unexpected complexity and beauty. My concept, “Ripple Interference,” simulates what happens when you drop multiple stones into a still pond at the same time — each stone creates circular ripples, and where those ripples meet they either amplify or cancel each other out. This interference is pure Simple Harmonic Motion: every circle on the grid is oscillating up and down in size and color based on the sum of sine waves reaching it from multiple sources. The result is a constantly shifting, living pattern that feels organic despite being entirely mathematical.

SKETCH

Code Highlight

The section I’m most proud of is the wave interference calculation at the heart of the sketch:

let waveSum = 0;
 for (let src of waveSources) {
   let d = dist(x, y, src.x, src.y);

   // Each source creates a radial sine wave
   waveSum += sin(d * 0.04 * src.freq - time * src.speed);
 }

 // Normalize so value stays between -1 and 1
 waveSum /= waveSources.length;

This is the core of everything. For each point in the grid, I measure the distance to every wave source, then plug that into a sine function. The distance replaces the linear progress variable from the example we did in class, turning the flat wave into a circular ripple spreading outward. When multiple sources combine, their values add together — this is wave superposition, the same principle that creates interference patterns in real physics. Dividing by the number of sources at the end keeps the value normalized between -1 and 1, which feeds cleanly into the same map(sin(…)) color technique from the class example. What I love about this is that a single line of math creates emergent visual complexity from something simple.

Milestones and Challenges
Milestones

  • Extended the example we did in class from a single 1D wave row to a full 35×35 2D grid of oscillating circles
  • Successfully implemented radial wave propagation (circular ripples instead of flat waves)
  • Combined multiple wave sources using superposition to create interference patterns
  • Retained and extended the class example’s sine-based color mapping into 2D
  • Added interactive wave source placement with click

Challenge 1: Going from 1D to 2D
The example from class maps i linearly across the x-axis to get the wave position. When I first tried expanding this to a grid, I simply ran two nested loops and used the row number j for a second wave — but this just created a grid of identical horizontal waves stacked on top of each other, which looked flat and uninteresting. The breakthrough was switching from using the grid position directly to using the distance from a source point. Replacing width * progress with dist(x, y, src.x, src.y) inside the sin() function was what made the waves actually radiate outward like real ripples.

Challenge 2: Balancing the Interference Pattern
Once multiple wave sources were working, the interference looked chaotic — the colors and sizes were flickering too rapidly with no visual coherence. The problem was that summing multiple sine waves was pushing the total value well beyond -1 to 1, making the map() calls produce extreme values. Dividing waveSum by the number of sources normalized it back to a usable range. This small fix made a dramatic difference — the patterns became smooth, readable, and beautiful instead of noisy.

Reflection and Future Improvements
This assignment taught me how much complexity can emerge from a single mathematical operation repeated in different configurations. The sine function is doing all the real work here — everything else is just deciding where to sample it and what to do with the result. Memo Akten’s work resonates more deeply now because I understand how restraint in the tools you use forces you to be more creative with how you use them.
Below are some ideas I would implement in the future:

  • Moving wave sources – Sources that drift slowly across the canvas, constantly changing the interference pattern
  • Mouse-responsive waves – The mouse position acts as a live wave source that follows your cursor
  • Frequency controls – Sliders to adjust each source’s frequency in real time
  • Different grid shapes – Hexagonal or circular grids instead of square
  • Sound integration – Map wave amplitude to audio frequency for a visual synthesizer

Assignment 3

Concept

For this assignment, I chose to create a particle system where movers orbit multiple attractors while being affected by three competing forces: gravitational attraction, wind turbulence, and mutual repulsion. I was inspired by how celestial bodies orbit in space but also how flocking birds maintain spacing while moving together. The challenge was to balance these three forces so they create beautiful, flowing patterns rather than chaotic scattering or rigid clustering. Each mover has slightly different mass, giving them unique orbital behaviors – some get pulled strongly into tight orbits while others drift lazily at the edges. The combination of ordered attraction and chaotic turbulence creates movement that feels organic and alive, like watching a cosmic dance that’s constantly evolving but never repeating.

Sketch

Code Highlight

In my implementation, a section of my code that I am proud of is below:

//Wind/turbulence using Perlin noise
 applyWind(time) {
   //perlin noise to create flowing, organic wind
   let noiseVal = noise(this.pos.x * 0.01, this.pos.y * 0.01, time * 0.0001);
   let angle = noiseVal * TWO_PI * 2;
   let wind = createVector(cos(angle), sin(angle));
   wind.mult(WIND_STRENGTH);
   this.applyForce(wind);
 }

This creates the organic turbulence that pushes movers around. Instead of using random() which would make particles jitter randomly, I used 3D Perlin noise (x, y, and time) which gives smooth, flowing forces. By sampling the noise field at the particle’s position and the current time, nearby particles experience similar wind direction, creating swirling currents rather than chaos. The angle conversion means the noise controls which direction the wind blows, creating those beautiful flowing patterns you see in the trails. I’m also proud of this snippet that prevents particle clustering:

//repulsion from another mover
 repel(other) {
   let force = p5.Vector.sub(this.pos, other.pos);
   let distance = force.mag();
   
   //repel if close enough
   if (distance < REPULSION_DISTANCE && distance > 0) {
     let strength = (this.mass * other.mass) / (distance * distance);
     force.setMag(strength);
     this.applyForce(force);
   }
 }

This uses the same inverse-square physics as attraction, but only activates when movers get close. It’s what keeps the particles from all collapsing into a single clump and creates those satisfying spacing patterns in the orbits. It’s a small detail but makes a huge difference in creating visually interesting formations.

Challenges
Force Accumulation Bug
Early in development, I noticed that movers were only responding to one force at a time, even though I was calling applyForce() multiple times per frame. After debugging, I realized the class example’s applyForce() method was replacing acceleration instead of adding to it:

Version from class example:

applyForce(force) {
   this.acc = force.div(this.mass);}

My updated version:

//accumulates forces
applyForce(force) {
  let f = force.copy();
  f.div(this.mass);
  this.acc.add(f); //add to acceleration
}

Reflections and Future Improvements
Through this assignment, I discovered that emergent complexity comes from simple rules interacting. No single force creates the beautiful patterns – it’s the tension between attraction (pulling together), repulsion (pushing apart), and turbulence (stirring things up) that generates the endless variety. My biggest challenge was finding the right balance between these forces. Too many attractions and everything collapsed into the attractors. Too much repulsion and particles scattered. Too much wind and chaos took over. The sweet spot where all three forces balanced created the most interesting patterns. My biggest takeaway is that personality comes from variation. Giving each mover a random mass (between 0.5 and 2) meant they all respond differently to the same forces – heavy particles orbit tightly while light ones drift widely. This variation is what makes the system feel alive rather than mechanical. Below are some ideas I would implement in the future for improvement of what I have currently:

    1. Ability to drag attractors to new positions and see how the system responds in real-time.
    2. Make particles bounce off each other with momentum conservation.
    3. Slow motion or fast forward to study patterns at different speeds.
    4. Different colored particles with different masses or charge (attract some, repel others).

With my implementation so far, some features I believe work very well include the Perlin noise wind creating smooth organic turbulence, the speed-based coloring that immediately shows which particles are moving fast, the repulsion preventing unrealistic clustering, and most importantly, the combination of three different forces creating complex emergent behaviors from simple physical rules. The system creates genuinely unpredictable patterns while maintaining a cohesive aesthetic – each session is unique but always visually interesting.

Assignment 2

Concept

For this assignment, I chose to simulate drifting clouds moving across a sky. I was inspired by how clouds move so peacefully yet unpredictably – they have a gentle, steady drift from wind, but also bob up and down with air currents and occasionally get pushed by gusts. The challenge was to recreate this serene, organic movement using only acceleration to control the motion. No directly setting velocities or positions – everything had to come from forces acting on the clouds: wind, air currents, drag, and occasional gusts. Each cloud has its own “personality” through variations in drift speed, bobbing frequency, and size, making the scene feel more natural and alive rather than mechanical.

Code Highlight

In my implementation, a section of my code that i am proud of is below:

// Vertical bobbing using perlin noise for smooth, natural variation
this.time += 0.01;
let bobForce = map(noise(this.time), 0, 1, -this.bobFrequency, this.bobFrequency);
let bob = createVector(0, bobForce);
this.applyForce(bob);

This creates the gentle up-and-down bobbing motion of the clouds. Instead of using random() which would make the clouds jitter, I used Perlin noise which gives smooth, organic transitions. Each cloud has its own time value that increments, creating unique but natural bobbing patterns. The bobFrequency variable gives each cloud a different personality – some bob more dramatically while others are more subtle. I am also proud of this snippet that creates creates air resistance, that opposes the cloud’s velocity, preventing it from accelerating infinitely and giving it that slow, peaceful drift. It’s a small detail but makes a huge difference in the realism.

// Air resistance (drag)
let drag = this.vel.copy();
drag.mult(-0.05); // Drag coefficient
this.applyForce(drag);

Embedded Sketch

Reflections and Future Improvements

Through this assignment, I discovered that subtle forces acting over time can generate intricate, lifelike movement. In nature, nothing moves in perfectly straight lines or at constant speeds – everything is constantly being pushed and pulled by multiple forces. By combining simple acceleration vectors (wind, drag, turbulence), I could create movement that felt surprisingly alive and organic. My biggest takeaway is personality, which comes from imperfection and variation. Making every cloud slightly different in how it responds to forces was what made the scene feel natural rather than computational. Below are some ideas i would implement in the future for improvement of what i have currently:

  1. Multiple cloud layers – Add parallax depth by having clouds at different “distances” moving at different speeds.
  2. Dynamic wind – Instead of constant wind, have the wind direction and strength change slowly over time.
  3. Cloud morphing – Make clouds gradually change shape as they drift, growing and shrinking.
  4. Weather transitions – Clouds could darken and speed up before “rain,” then slow down and lighten afterward.
  5. Interactive elements – Mouse interaction could create temporary wind forces that push clouds around.
  6. Better visual design – Use gradients and transparency to make clouds look more three-dimensional and fluffy.
  7. Sound – Add gentle wind sounds that change based on cloud speed.

With my implementation so far some feature i believe work very well include, the drag force, bobbing through perlin noise, personality traits of each cloud and the combination of multiple forces which created complex behaviours from simple rules.

Assignment 1

Concept

For this assignment, just like the description suggested, I combined:

    • LIST 1: Random walker with motion experimentation
    • LIST 2: Walking through RGB color space

My sketch features a simple random walker that moves in four directions (up, down, left, right) across the canvas. Instead of being a fixed color, the walker’s color is determined by its position in space, creating a direct mapping between XY coordinates and RGB color values:

Red channel = X position (left edge = 0, right edge = 255)
Green channel = Y position (top edge = 0, bottom edge = 255)
Blue channel = Distance from center (center = 255, edges = 0)

As the walker moves randomly, it paints a trail of colors that visualize its journey through both physical space and color space simultaneously.

Code Highlight

Throughout my code, I am most proud of this snippet where I map the walker’s position to RGB values.

// Map position to RGB color
let r = map(x, 0, width, 0, 255);
let g = map(y, 0, height, 0, 255);

// Blue based on distance from center
let centerX = width / 2;
let centerY = height / 2;
let distFromCenter = dist(x, y, centerX, centerY);
let maximumDist = dist(0, 0, centerX, centerY);  // Changed from maxDist
let b = map(distFromCenter, 0, maximumDist, 255, 0);

// Set the color and draw
fill(r, g, b);
noStroke();
circle(x, y, 10);

In the code, the map() function translates position into color. The blue channel calculation is especially interesting because it uses the Pythagorean distance from the center, creating a radial gradient effect. When the walker is near the center, it’s more blue; when it’s at the edges, it loses blue and becomes more red/green/yellow.

Embedded Sketch

Reflection and Future Work

This project was a great way to visualize the connection between position and color. Watching the walker create organic, colorful patterns by pure randomness is mesmerizing! The RGB color space creates interesting gradients naturally – reds in the upper right, greens in the lower right, blues in the center. Ideas for future improvements:

  1. Add diagonal movement – Currently limited to 4 directions; adding diagonals would create smoother, more varied paths.
  2. Implement Gaussian random walk – Instead of equal probability in all directions, use a normal distribution for step sizes to create more organic movement patterns.
  3. Try HSB color mode – Experiment with Hue-Saturation-Brightness instead of RGB for different color relationships.
  4. Multiple walkers – Have several walkers moving simultaneously, each leaving their own colored trail.
  5. Fade trail effect – Instead of permanent marks, make older circles fade away over time for a ghostly trail effect.
  6. Add 50% mouse attraction – Implement the probability-based walker that has a 50% chance of moving toward the mouse (combining two LIST 1 options).
  7. Step size control – Add a slider to adjust how fast/far the walker moves.