overview
This generative artwork, inspired by Wassily Kandinsky’s “Circles in Circles,” showcases a vibrant and dynamic composition. The canvas size is set to 600×600 pixels with a beige background and a black-bordered transparent circle at the center. Colorful animated circles, each with random positions, sizes, colors, and movement patterns, create an ever-changing visual experience. Additionally, eight animated lines move horizontally, resetting when they go off-screen. The viewer can interact with the artwork by clicking on different areas, and changing the background color dynamically. This code combines randomness and structure to produce a captivating, abstract artwork reminiscent of Kandinsky’s geometric abstractions.
Who is Wassily Kandinsky?
Wassily Kandinsky (1866-1944) was a pioneering Russian painter and art theorist, often hailed as one of the founders of abstract art. He believed that art should evoke emotions and spiritual experiences through non-representational forms and colors. Kandinsky’s “Circles in Circles” is a seminal artwork created in 1923, during his Bauhaus period. It is a prime example of his abstract style, featuring geometric shapes and vibrant colors. In this work, a large red circle dominates the canvas, encompassing smaller circles in various hues, with each circle seemingly floating or orbiting within the composition. “Circles in Circles” embodies Kandinsky’s fascination with the spiritual and emotional power of abstract forms and color harmonies.
Code Details; Highlights of the code that I am particularly proud of
- To precisely replicate the colors found within the painting, I first extracted its color palette. Subsequently, I meticulously identified and stored the exact hexadecimal color codes in an array. These hex codes were then used to randomly assign colors to the circles in my artwork, ensuring an accurate representation of the original painting’s color scheme
-
// Array of hex colors for the circles let circleColors = ["#c7999b", "#b8bbaf", "#8e4040", "#82a596", "#e4c95b", "#585e3a", "#364664", "#694350", "#282927"];
- The original painting featured precisely 21 circles, and through the utilization of loops, I successfully replicated this exact count within my artwork. and just like the original painting the circles had random stroke weight and the circles have a certain sense of transperacy just as the original painting
-
for (let i = 0; i < 21; i++) { let x = random(width); // Random x-coordinate within canvas width let y = random(height); // Random y-coordinate within canvas height let radius = random(10, 80); // Random radius between 10 and 80 pixels // Randomly select a color from the circleColors array let fillColor = color(random(circleColors)); // Generate a random stroke weight for the circle (border thickness) let strokeWeightValue = random(1, 5); let xspeed = random(-2, 2); // Random horizontal speed let yspeed = random(-2, 2); // Random vertical speed
embedded sketch
problems I ran into:
While the code initially employed a reversal of direction (multiplying by -1) when circles encountered the canvas edges, it became apparent that certain circles exhibited shaky behavior. To mitigate this issue, a damping effect was introduced. Initially, there were reservations about this approach, as it seemed to halt the circles’ motion. However, upon further consideration, it was realized that the damping effect, while tempering the motion, also contributed to a smoother and less overwhelming overall movement.
After applying the damping effect
code (commented with the use of loops and classes as requested) :
// Batool AL Tameemi, Intro to IM Week 3 homework // Generative art work let circles = []; let backgroundColors = []; let lines = []; function setup() { createCanvas(600, 600); // Create a canvas with a size of 600x600 pixels noStroke(); // Disable stroke (borders) for shapes frameRate(60); // Set the frame rate to 30 frames per second // Add the RGB values of the colors from the painting to the backgroundColors array backgroundColors.push(color(226, 216, 203)); // Light beige backgroundColors.push(color(146, 125, 75)); // Dark beige backgroundColors.push(color(130, 165, 150)); // Greenish gray // Add more background colors as needed // Array of hex colors for the circles let circleColors = ["#c7999b", "#b8bbaf", "#8e4040", "#82a596", "#e4c95b", "#585e3a", "#364664", "#694350", "#282927"]; for (let i = 0; i < 21; i++) { let x = random(width); // Random x-coordinate within canvas width let y = random(height); // Random y-coordinate within canvas height let radius = random(10, 80); // Random radius between 10 and 80 pixels // Randomly select a color from the circleColors array let fillColor = color(random(circleColors)); // Generate a random stroke weight for the circle (border thickness) let strokeWeightValue = random(1, 5); let xspeed = random(-2, 2); // Random horizontal speed let yspeed = random(-2, 2); // Random vertical speed // Create an instance of AnimatedCircle and add it to the circles array circles.push(new AnimatedCircle(x, y, radius, fillColor, strokeWeightValue, xspeed, yspeed)); } // Create animated lines for (let i = 0; i < 8; i++) { let x1 = random(width); // Random x-coordinate for the starting point of the line let y1 = random(height); // Random y-coordinate for the starting point of the line let x2 = random(width); // Random x-coordinate for the ending point of the line let y2 = random(height); // Random y-coordinate for the ending point of the line let lineColor = color(0, 0, 0); // Black color for lines let lineWeight = random(1, 5); // Random stroke weight for lines // Create an instance of AnimatedLine and add it to the lines array lines.push(new AnimatedLine(x1, y1, x2, y2, lineColor, lineWeight)); } } function draw() { for (let i = 0; i < backgroundColors.length; i++) { fill(backgroundColors[i]); // Fill the background with one of the background colors noStroke(); rect(0, i * (height / backgroundColors.length), width, height / backgroundColors.length); // Draw a colored rectangle for each background color } for (let circle of circles) { circle.move(); // Move each animated circle circle.display(); // Display each animated circle } for (let line of lines) { line.move(); // Move each animated line line.display(); // Display each animated line } // Draw a single black-bordered transparent circle inside strokeWeight(8); // Set the stroke weight (border thickness) for the ellipse stroke(0); // Set the stroke color to black noFill(); // Don't fill the ellipse with color ellipse(width / 2, height / 2, 400, 400); // Draw the ellipse at the center of the canvas } function mousePressed() { // Calculate the index of the background color based on the mouse click position let index = int(mouseY / (height / backgroundColors.length)); fill(backgroundColors[index]); // Fill with the selected background color rect(0, index * (height / backgroundColors.length), width, height / backgroundColors.length); // Draw a colored rectangle based on the mouse click position } // AnimatedCircle class definition class AnimatedCircle { constructor(x, y, radius, fillColor, strokeWeightValue, xspeed, yspeed) { this.x = x; this.y = y; this.radius = radius; this.fillColor = fillColor; this.strokeWeightValue = strokeWeightValue; // Store stroke weight this.xspeed = xspeed; this.yspeed = yspeed; this.fillColor = color(red(fillColor), green(fillColor), blue(fillColor), 200); // Set the alpha value to 150 for transparency } move() { // Define a damping factor (adjust as needed) let damping = 0.95; // Update the x-coordinate based on speed this.x += this.xspeed; // Apply damping to reduce shaking near the edges this.xspeed *= damping; // Update the y-coordinate based on speed this.y += this.yspeed; // Apply damping to reduce shaking near the edges this.yspeed *= damping; if (this.x > width - this.radius || this.x < this.radius) { this.xspeed *= -1; // Reverse horizontal speed if the circle hits canvas edge } if (this.y > height - this.radius || this.y < this.radius) { this.yspeed *= -1; // Reverse vertical speed if the circle hits canvas edge } } display() { strokeWeight(this.strokeWeightValue); // Set the stroke weight stroke(0); // Set the stroke color to black fill(this.fillColor); // Fill with the specified color ellipse(this.x, this.y, this.radius * 2, this.radius * 2); // Draw the circle } } // AnimatedLine class definition class AnimatedLine { constructor(x1, y1, x2, y2, lineColor, lineWeight) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.lineColor = lineColor; this.lineWeight = lineWeight; this.speed = random(0.5, 2); // Random line animation speed } move() { // Move the lines horizontally this.x1 += this.speed; this.x2 += this.speed; // Reset lines when they go off-screen if (this.x1 > width) { this.x1 = 0; this.x2 = random(width); this.y1 = random(height); this.y2 = random(height); } } display() { strokeWeight(this.lineWeight); // Set the stroke weight stroke(this.lineColor); // Set the stroke color line(this.x1, this.y1, this.x2, this.y2); // Draw the line } }