art
generative
fxhash
Ephemeral Whirls – Generative Art through Loops and Motion

Ephemeral Whirls – Generative Art through Loops and Motion

written by reyrove

07 Oct 2024100 EDITIONS
1 TEZ

The Initial Setup: Creating the Canvas

const e = Math.min(innerWidth, innerHeight);
const canvas = {};
canvas.w = e;
canvas.h = e;
  • Defining the canvas size : The variable e is set to the smaller of the screen's width and height. This ensures that the canvas is always a square, regardless of your browser window's aspect ratio. It becomes the stage where our shapes will dance.

Features and Global Variables

const features = {};
var loopers;
var backgroundColor;
  • ``** object**: This is where we’ll store the various properties of the art, such as background color, loop colors, and the number of loopers.
  • Global variables : loopers will store our shapes, while backgroundColor sets the stage for each drawing.

The Setup Function: Laying the Groundwork

function setup() {
  createCanvas(e, e);
  • setup() : This function initializes the canvas, drawing it to the size of e (set earlier to the smaller screen dimension), ensuring that the artwork is responsive across different devices.

Choosing Colors: Palette of Pastels and Vibrancy

const backgroundColours =  ['#F5F5F5','#9AFEFF','#AAF0D1', ...];
const backgroundNames = ['WhiteSmoke (W3C)','Electric Blue','Magic Mint', ...];
const backgroundIndex = Math.floor($fx.rand() * backgroundColours.length);
features.backgroundColour = backgroundColours[backgroundIndex];
  • Background colors : A beautiful palette of pastel colors is prepared to form the canvas’s backdrop. Each time the code runs, a random color from this list is chosen, setting a unique mood for the visual experience.
  • Random background : The backgroundIndex variable selects a random color from the list, ensuring that no two artworks look alike.
const LooperColor = [['#9F21DE','#60DE21'], ['#F20DB2','#0DF24D'], ...];
features.LooperColors = LooperColor[Math.floor($fx.rand() * LooperColor.length)];
  • Looper colors : Each "looper" (a swirling, moving line) gets its own color scheme. The LooperColor array holds multiple color pairs or groups, and just like with the background, a random set is chosen every time.

Building the Loopers: Our Dancing Shapes

features.NumberOfLoopers = Math.floor($fx.rand() * 2 + 23);
features.Time = Math.floor($fx.rand() * 2000 + 2000);
  • Number of loopers : Each drawing will feature between 23 and 25 loopers, the swarming entities that will move and paint across the canvas.
  • Duration of loops : The Time feature controls how long the loopers will animate, creating variations in the density and complexity of the final artwork.
loopers = [];
for (let i = 0; i < features.NumberOfLoopers; i++) {
  loopers.push(new Looper(0, $fx.rand() * e));
}
  • Creating the loopers : The loopers are stored in an array, each one positioned randomly along the canvas’s height. These loopers will later define the motion, each with its own speed, heading, and color.

Drawing the Scene: Orienting and Setting the Stage

if (features.side == 0) {
  rotate(Math.PI / 2);
  translate(0, -e);
} else if (features.side == 1) {
  rotate(-Math.PI / 2);
  translate(-e, 0);
}
  • Side rotation : The canvas is rotated based on a random selection from four possible sides ( up , down , left , or right ). This adds an additional layer of randomness to the composition, tilting the viewer’s perspective.
background(features.backgroundColour);
strokeWeight(e / ($fx.rand() * 200 + 200));
  • Setting the background and stroke weight : Once the canvas is oriented, the background color is applied. The stroke weight determines the thickness of the lines drawn by the loopers, varying based on random values to add depth and richness to the composition.

The Magic of Motion: Loopers Take Their Step

for (let i = 0; i < features.Time; i++) {
  drawOnce();
}
  • Animating the loopers : For the duration defined in the setup, the loopers move and draw. This ensures that the artwork evolves over time, with each frame contributing to the overall image.
for (const looper of loopers) {
  looper.step();
  looper.draw1();
}
  • Stepping and drawing : Each looper has its own step() and draw1() methods, which define their movement and drawing behaviors. As they move, they leave behind a colorful trail, forming intricate patterns.

The Looper Class: The Heart of Motion

class Looper {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.heading = 0.1;
    this.speed = $fx.rand() * (e / 1000);
    this.sinOffset = $fx.rand() * 1000;
    this.loopingSpeed = $fx.rand() * (0.025, 0.1) * ($fx.rand() < 0.5 ? 1 : -1);
  }
  • Creating a looper : The Looper class defines the properties of each looper—its position, speed, heading, and even the "looping speed" that determines how it moves across the canvas.
  • Sinusoidal motion : By incorporating sine functions ( sinOffset ), the looper’s path becomes wavy, creating a natural, organic flow in the artwork.
step() {
  if (this.looping) {
    this.heading += this.loopingSpeed + sin(this.sinOffset + 100 * 0.1) * 0.05;
    this.constrainHeading();
    if (this.maybeDoneLooping && (this.heading < TAU * 0.05 || this.heading > TAU * 0.95)) {
      this.looping = false;
    }
  }
  • Motion logic : Each looper’s heading (direction) is updated as it moves, with the possibility of entering or exiting a "looping" state. When looping, the looper moves in a curved path, adding complexity to the image.
draw1() {
  stroke(this.c);
  line(this.prevX, this.prevY, this.x, this.y);
}
  • Drawing the path : As each looper moves, it leaves a trail by drawing a line between its previous position ( prevX , prevY ) and its new position ( x , y ). This is where the visual patterns emerge, forming the signature swirls and whirls.

Saving the Canvas: A Moment Captured

function keyPressed() {
  if (key === 's' || key === 'S') {
    saveCanvas('Ephemeral Whirls', 'png');
  }
}
  • Saving the artwork : By pressing 'S', the artwork is saved as a PNG file. This ensures that each ephemeral creation, though fleeting in code, can be captured and cherished.

Conclusion

The "Ephemeral Whirls" project is more than just code—it’s a symphony of motion and color, where each looper dances across the screen, leaving behind trails of beauty. The randomness ensures that every execution generates a new, unique work of art, just like the natural unpredictability of life itself. This generative piece celebrates the interplay between control and chaos, inviting you to watch, play, and create in the digital world.

Click here for the full code, and let the art flow. Let’s explore these ephemeral whirls together and share our creations with the world!

*With all our creativity, love, and the code that brings this art to life,*🌸💻

_Frostbond Coders

feedback

stay ahead with our newsletter

receive news on exclusive drops, releases, product updates, and more