Citrus Mosaic
written by reyrove
Let's break down the code line by line to explore how this beautiful chaos comes to life.
Setting Up Key Variables
const ratio = 1 / 1;
const prefix = 'Citrus Mosaic';
const features = {};
let resizeTmr = null;
let thumbnailTaken = false;
-
ratio = 1 / 1
: This sets the aspect ratio for our canvas, ensuring a perfect square. -
prefix
: Defines the prefix used for naming the downloaded images. -
features
: An object used to store dynamic attributes, like the foreground color and the number of divisions in the pattern. -
resizeTmr
: A timer for handling responsive resizing of the canvas. -
thumbnailTaken
: A flag to ensure the thumbnail is captured only once.
Handling URL Parameters and Animation
const urlSearchParams = new URLSearchParams(window.location.search);
const urlParams = Object.fromEntries(urlSearchParams.entries());
let forceDownloaded = false;
const animated = false;
let nextFrame = null;
- URL Parameters : We extract any URL parameters, like forced download requests, using URLSearchParams.
- forceDownloaded : Ensures we only download the image once, even if the user refreshes the page.
- animated : A flag to determine if the canvas should be animated (in this case, it’s set to false).
- nextFrame : Keeps track of animation frames if needed.
setup Function
This function is where the magic begins. We define colors, calculate divisions for the pattern, and set up features.
const setup = () => {
const readableFeaturesObj = {};
const ForegroundColours = ['#F5F5F5', '#98AFC7', '#728FCE', '#1E90FF', '#95B9C7', '#3BB9FF', '#C2DFFF'];
const ForegroundNames = ['WhiteSmoke (W3C)', 'Blue Gray', 'Light Purple Blue', 'DodgerBlue', 'Baby Blue', 'Midday Blue', 'Sea Blue'];
const ForegroundIndex = Math.floor($fx.rand() * ForegroundColours.length);
features.ForegroundColour = ForegroundColours[ForegroundIndex];
readableFeaturesObj['Foreground Color'] = ForegroundNames[ForegroundIndex];
-
Foreground Colors: We define arrays of color options, both in hexadecimal values (
ForegroundColours
) and human-readable names (ForegroundNames
). -
Random Selection: The color for each foreground is randomly selected using
$fx.rand()
and stored in the features.ForegroundColour
.
Next, we define the number of divisions in the pattern and randomly select square colors:
features.numofDivision = Math.floor($fx.rand() * 13) + 2;
features.numofSquares = features.numofDivision ** 2;
const Colors = [];
for (i = 0; i < features.numofSquares; i++) {
Colors[i] = Squarecolors[Math.floor($fx.rand() * Squarecolors.length)];
}
features.SquareColor = Colors;
readableFeaturesObj['Number of Squares'] = features.numofSquares;
$fx.features(readableFeaturesObj);
-
numofDivision
: This determines how many divisions (or squares) the canvas will have, calculated randomly between 2 and 15. -
SquareColor
: An array of colors for each square in the grid, randomly chosen from theSquarecolors
array.
Creating the Repeating Pattern
The function createRepeatingArcPattern
is responsible for the intricate arc patterns in each square.
function createRepeatingArcPattern(ctx, X, Y, W, H, fillColor, arcfill) {
// Set up canvas context and position
ctx.translate(X, Y);
ctx.fillStyle = fillColor;
ctx.fillRect(0, 0, W, H);
const A = Math.floor($fx.rand() * 22);
if (A == 0) {
ctx.beginPath();
ctx.arc(0, 0, W, 0, 0.5 * Math.PI);
ctx.lineTo(0, 0);
}
// ... additional pattern drawing logic ...
ctx.shadowColor = arcfill;
ctx.shadowBlur = W / 2;
ctx.strokeStyle = arcfill;
ctx.stroke();
ctx.fillStyle = arcfill;
ctx.fill();
}
-
translate(X, Y)
: Positions the square on the canvas. -
Random Arc Patterns: Based on a random number (
A
), the function generates a variety of arcs and shapes. This randomness creates the dynamic and chaotic appearance of the pattern. -
Shadow and Fill Effects: To add a 3D feel, shadows and gradients are applied using
shadowColor
,shadowBlur
, and thefillStyle
property.
Drawing the Canvas
The drawCanvas
function stitches everything together.
const drawCanvas = async () => {
window.cancelAnimationFrame(nextFrame);
const canvas = document.getElementById('target');
const ctx = canvas.getContext('2d');
const w = canvas.width;
const h = canvas.height;
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, w, h);
const numCols = features.numofDivision;
const numRows = features.numofDivision;
for (let row = 0; row < numRows; row++) {
for (let col = 0; col < numCols; col++) {
createRepeatingArcPattern(ctx, col * (w / numCols), row * (h / numCols), w / numCols, h / numCols, features.SquareColor[j], features.ForegroundColour);
}
}
- Filling the Background : The entire canvas is initially filled with black.
-
Looping Through Squares
: Using two nested loops, we fill the grid with squares and call
createRepeatingArcPattern
to create a unique design for each one.
Resizing and Downloading
Finally, we have helper functions to handle resizing and saving the canvas as an image.
const autoDownloadCanvas = async () => {
const canvas = document.getElementById('target');
const element = document.createElement('a');
const filename = `${prefix}_${$fx.hash}`;
element.setAttribute('download', filename);
const imageBlob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png'));
element.setAttribute('href', window.URL.createObjectURL(imageBlob));
element.click();
document.body.removeChild(element);
};
autoDownloadCanvas
: Downloads the canvas as a PNG file using the randomly generated $fx.hash
for the filename.
With this code, you can explore the beauty of randomness and geometry in digital art. Each refresh of the page brings a new mosaic to life, featuring an eclectic mix of colors, shapes, and arcs. A delightful experiment in generative art! for full code, click HERE!
With love, sass, and digital flair by Frostbond Coders✨