Mini Project 4: Generative Landscapes & Patterns
Project Link
https://editor.p5js.org/King-Raphael/sketches/dnzQIlztr
Brief Description and Concept
This project generates a dynamic incense stick pattern using p5.js, inspired by the traditional art of arranging incense sticks and a blooming flower. The visual complexity of the pattern adapts based on the number of layers and sticks, creating either a dense or loose arrangement. The background gradient is randomly generated, which adds a unique touch to each output as well.
Visual Documentation
Coding
function setup() { createCanvas(800, 500); // Create a canvas with 800x500 dimensions noLoop(); // Stop draw from looping // Create random colors for the gradient let c1 = color(random(100, 255), random(100, 255), random(100, 255), random(50, 150)); // Random start color let c2 = color(random(0, 100), random(0, 100), random(150, 255),80); // Draw the gradient background drawGradient(0, 0, width, height, c1, c2, 1); translate(width / 2, height / 2); // Center the pattern let layers = floor(random(5, 10)); // Number of layers of incense sticks let sticksPerLayer = floor(random(10, 22)); // Sticks in each layer // Adjust maxRadius based on the number of layers and sticksPerLayer let densityFactor = map(layers * sticksPerLayer, 50, 220, 1.5, 0.5); let maxRadius = 200 * densityFactor; // Adjust max radius based on density factor let minRadius = 50 * densityFactor; // Adjust min radius based on density factor for (let i = 0; i < layers; i++) { let layerRadius = map(i, 0, layers, minRadius, maxRadius); // Gradual increase in radius let hue = map(i, 0, layers, 0, 255); // Vary color along the layer let angleOffset = random(0, TWO_PI); // Random rotation for each layer drawIncenseLayerWithArcs(layerRadius, sticksPerLayer, hue, angleOffset); } saveCanvas('Raphael', 'png'); // saves the canvas as a png image } // Function to draw a single layer of incense sticks with connecting arcs function drawIncenseLayerWithArcs(radius, numSticks, hueValue, angleOffset) { strokeWeight(2); let prevX, prevY; // Variables to store the previous stick's coordinates for (let j = 0; j < numSticks; j++) { let angle = map(j, 0, numSticks, 0, TWO_PI) + angleOffset; // Distribute around the circle let x = cos(angle) * radius; let y = sin(angle) * radius; let length = random(20, 120); // Random length for each stick let colorHue = hueValue + random(-20, 20); // Slight variation in color stroke(colorHue, 80, 200); // Stroke color with variation line(x, y, x + cos(angle) * length, y + sin(angle) * length); // Draw the incense stick // If there is a previous point, draw an arc between the previous and current points if (j > 0) { noFill(); stroke(colorHue, 150, 255, 150); // Softer stroke for the arc let midX = (prevX + x) / 2; let midY = (prevY + y) / 2; arc(midX, midY, radius, radius, atan2(prevY - midY, prevX - midX), atan2(y - midY, x - midX)); } // Store the current point as the previous point for the next iteration prevX = x; prevY = y; // Optional: Draw circles at the base for added texture fill(colorHue, 80, 100); noStroke(); ellipse(x, y, random(5, 10)); } } // Function to draw the gradient background with random colors function drawGradient(x, y, w, h, c1, c2, axis) { noFill(); for (let i = y; i <= y + h; i++) { let inter = map(i, y, y + h, 0, 1); let c = lerpColor(c1, c2, inter); stroke(c); line(x, i, x + w, i); } }
Coding Explanation:
- Gradient Background:
let c1 = color(random(100, 255), random(100, 255), random(100, 255), random(50, 150));
This code generates a gradient background with two randomly chosen colors (
let c2 = color(random(0, 100), random(0, 100), random(150, 255),80);
drawGradient(0, 0, width, height, c1, c2, 1);c1
andc2
). ThedrawGradient
function fills the canvas with a smooth gradient transition. - Pattern Density Control:
let densityFactor = map(layers * sticksPerLayer, 50, 220, 1.5, 0.5);
The
let maxRadius = 200 * densityFactor;
let minRadius = 50 * densityFactor;densityFactor
scales the radius of the pattern based on the number of layers and sticks per layer. A higher density leads to a more compact pattern, while a lower density spreads it out. - Incense Sticks and Arcs:
if (j > 0) {stroke(colorHue, 80, 200);
line(x, y, x + cos(angle) * length, y + sin(angle) * length);
stroke(colorHue, 150, 255, 150);
arc(midX, midY, radius, radius, atan2(prevY – midY, prevX – midX), atan2(y – midY, x – midX));
}Each incense stick is drawn using the
line
function. If there is a previous stick, an arc is drawn between the current and previous stick to create a visual connection. - Adjusting the Pattern: I can further experiment with the
densityFactor
, color variations, and lengths of the sticks to produce different visual styles.
Findings / Lessons Learned
- Using randomness in colors and positions adds a unique flavor to each generation.
- Managing visual density is crucial to maintaining the aesthetic appeal of generative patterns.
- Experimenting with visual elements like arcs and gradient backgrounds can elevate a basic pattern to an intricate piece of art.
Reflection Prompts
1. How is drawing by hand from observation different from programming the computer to draw for you? Can you think of some commonalities as well?
Drawing by hand allows for intuitive and immediate adjustments based on visual feedback and personal expression. In contrast, programming requires logical structuring and pre-defined rules. However, both share a process of iterative refinement and require a keen sense of composition and aesthetics.
2. What properties have you manipulated in the repetition? Describe your observations and visual outcomes during the process.
The number of layers, sticks per layer, stick lengths, and angles were manipulated. Changing these properties affected the visual density, pattern complexity, and overall feel of the artwork. Denser configurations resulted in a more clustered pattern, while fewer layers created a minimalist, expansive look.
3. What makes a good generative pattern?
A good generative pattern balances randomness and order, creating a visually pleasing composition while maintaining a sense of unpredictability. It should have an underlying structure that can surprise the viewer with unexpected variations in color, form, or arrangement.