Day 31 - Art 1
Pixel sorting
Shifting Spectrum
Shifting Spectrum is a generative art piece where vibrant colors blend and shift across the canvas, creating a dynamic gradient animation. The artwork begins with random colors and evolves through phases of smooth transitions, where pixel positions are shuffled and colors are gradually sorted. The result is a fluid, ever-changing spectrum of colors that continuously morphs into new patterns, offering a captivating visual experience that evolves over time.
// Array to store pixel information (original and shuffled positions)
let pixelsArray = [];
// Controls the progress of the animation (0 = start, 1 = end)
let animationProgress = 0;
// Speed at which the animation progresses
let animationSpeed = 0.01;
// Current phase of the animation (either "generate", "sorting", or "waiting")
let phase = "generate";
// Reference to the canvas element
let canvas;
// Colors for the gradient
let startColor, endColorX, endColorY;
function setup() {
// Create a 400x400 canvas and attach it to the parent container
canvas = createCanvas(400, 400);
canvas.parent('canvas-container');
// Set pixel density to 1 for performance
pixelDensity(1);
// Start a new animation cycle
startNewCycle();
}
function draw() {
// If we are in the "sorting" phase, gradually transition the pixel positions
if (phase === "sorting") {
// Increase the animation progress
animationProgress += animationSpeed;
// Clamp the animation progress to a maximum value of 1
if (animationProgress >= 1) {
animationProgress = 1;
// Once the animation is complete, switch to the "waiting" phase
phase = "waiting";
// Start a new cycle after a brief delay (2000 ms)
setTimeout(startNewCycle, 2000);
}
}
// Load pixel data into the array
loadPixels();
// Loop through all stored pixels and interpolate their positions based on animation progress
for (let i = 0; i < pixelsArray.length; i++) {
let p = pixelsArray[i];
// Interpolate the x and y positions of each pixel
let x = lerp(p.sx, p.ox, animationProgress);
let y = lerp(p.sy, p.oy, animationProgress);
// Calculate the pixel index and update the pixel data with the correct RGB values
let index = (floor(x) + floor(y) * width) * 4;
pixels[index] = p.r;
pixels[index + 1] = p.g;
pixels[index + 2] = p.b;
pixels[index + 3] = 255;
}
// Apply the updated pixel data to the canvas
updatePixels();
}
// Function to initiate a new cycle, including generating a new gradient and starting the sorting animation
function startNewCycle() {
phase = "generate"; // Set phase to "generate"
animationProgress = 0; // Reset animation progress
// Randomly generate start and end colors for the gradient
startColor = color(random(255), random(255), random(255));
endColorX = color(random(255), random(255), random(255));
endColorY = color(random(255), random(255), random(255));
// Generate the gradient
generateGradient();
// Store the pixel information (positions and colors)
storePixels();
// Shuffle the pixel positions to create a dynamic effect
shufflePixels();
phase = "sorting"; // Set phase to "sorting" to begin the animation
}
// Function to generate a smooth gradient across the canvas
function generateGradient() {
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
// Interpolate colors based on the x and y coordinates
let cX = lerpColor(startColor, endColorX, x / width);
let cY = lerpColor(startColor, endColorY, y / height);
let finalColor = lerpColor(cX, cY, 0.5);
// Set the color of each pixel in the canvas based on the calculated gradient
set(x, y, finalColor);
}
}
updatePixels();
}
// Function to store the original pixel data (position and color)
function storePixels() {
pixelsArray = []; // Clear the pixels array
loadPixels(); // Load current pixel data into the array
// Loop through every pixel and store its position and color
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
let index = (x + y * width) * 4;
let r = pixels[index];
let g = pixels[index + 1];
let b = pixels[index + 2];
// Store the pixel's original position (ox, oy) and the shuffled position (sx, sy)
pixelsArray.push({
ox: x,
oy: y,
sx: x,
sy: y,
r,
g,
b,
});
}
}
}
// Function to shuffle the pixel positions to create a dynamic visual effect
function shufflePixels() {
// Shuffle the pixelsArray using Fisher-Yates algorithm
for (let i = pixelsArray.length - 1; i > 0; i--) {
let j = floor(random(i + 1));
// Swap the x and y positions of the pixels
[pixelsArray[i].sx, pixelsArray[j].sx] = [pixelsArray[j].sx, pixelsArray[i].sx];
[pixelsArray[i].sy, pixelsArray[j].sy] = [pixelsArray[j].sy, pixelsArray[i].sy];
}
}