art
generative
fxhash
Bezier 2:Dynamic Bezier Curves

Bezier 2:Dynamic Bezier Curves

written by reyrove

06 Oct 2024100 EDITIONS
1 TEZ

Canvas and Global Variables Setup

const e = Math.min(innerWidth, innerHeight);
const canvas = {};
canvas.w = e;
canvas.h = e;
const mm = e * 0.001;
let nextFrame = null;
const features = {};
const isMob = /Android|webOS|iPhone|iPad|IEMobile|Opera Mini/i.test(navigator.userAgent);

var Points = [];
var DecidedRange=[];
var step = [];
var coeff = [];
var LiNewidth=[];
var Angle=0;
var Rot=[];

Feature Definitions and Parameter Input

definitions = [
  {
    id: "number_id1",
    name: "Number of Control Points",
    type: "number",
    options: {         
      min: 3,
      max: 30,
      step: 1,
    },
  }
]

$fx.params(definitions)

Setup Function

function setup() {
  createCanvas(e, e);
  frameRate(30);

  const backgroundColours = ['#B6B6B4', '#F5F5F5', '#728FCE', '#2F539B', '#0909FF', ...];
  const backgroundNames = ['Gray Cloud', 'WhiteSmoke (W3C)', 'Light Purple Blue', 'Estoril Blue', ...];
  const backgroundIndex = Math.floor($fx.rand() * backgroundColours.length);

  const foregroundColours = ['#16E2F5', '#01F9C6', '#2E8B57', '#50C878', ...];
  const foregroundNames = ['Bright Turquoise', 'Bright Teal', 'SeaGreen (W3C)', 'Emerald', ...];
  const foregroundIndex1 = Math.floor($fx.rand() * foregroundColours.length);
  const foregroundIndex2 = Math.floor($fx.rand() * foregroundColours.length);

  features.backgroundColour = backgroundColours[backgroundIndex];
  features.foregroundColour1 = foregroundColours[foregroundIndex1];
  features.foregroundColour2 = foregroundColours[foregroundIndex2];

  const numberOfPoints = $fx.getParam('number_id1');
  Points = generateRandomPoints(numberOfPoints);
  DecidedRange = generateRandomNumbers(numberOfPoints, e/10, 2*e/5);
  step = generateRandomNumbers(numberOfPoints, -e/100, e/100);
  coeff = generateRandomBinaryVector(numberOfPoints);
  LiNewidth = $fx.rand() * e / 200 + e / 200;
  Rot = Math.PI / Math.floor($fx.rand() * 160 + 20) * ($fx.rand() < 0.5 ? -1 : 1);

  console.table({
    'Background Color': backgroundNames[backgroundIndex],
    'Number of Control Points': numberOfPoints,
    'Line Gradient Color 1': foregroundNames[foregroundIndex1],
    'Line Gradient Color 2': foregroundNames[foregroundIndex2],
  });

  (isMob) ? pixelDensity(1) : pixelDensity(Math.min(window.devicePixelRatio, 2));
}

Generating Random Points

function generateRandomPoints(n) {
  if (n <= 2) {
    console.error("Input number must be greater than 2.");
    return [];
  }

  let points = [];
  let angleIncrement = TWO_PI / n;
  let centerX = 0;
  let centerY = 0;
  let maxRadius = canvas.w / 3;

  for (let i = 0; i < n; i++) {
    let startAngle = i * angleIncrement;
    let angle = $fx.rand() * angleIncrement + startAngle;
    let radius = $fx.rand() * maxRadius;
    let x = centerX + radius * cos(angle);
    let y = centerY + radius * sin(angle);
    let rangeOfPoint = 0;
    points.push([x, y, angle, rangeOfPoint]);
  }
  return points;
}

Change Points Location for Animation

function ChangePointsLocation(Points, step, decidedRange) {
  for (let i = 0; i < Points.length; i++) {
    if (Points[i][3] >= decidedRange[i]) {
      Points[i][3] = 0;
      coeff[i] = -coeff[i];
    }

    if (Points[i][3] <= decidedRange[i]) {
      Points[i][0] = Points[i][0] + coeff[i] * step[i] * Math.cos(Points[i][2]);
      Points[i][1] = Points[i][1] + coeff[i] * step[i] * Math.sin(Points[i][2]);
      Points[i][3] = Points[i][3] + Math.abs(step[i]);
    }
  }
  return Points;
}

Drawing Smooth Bezier Curves

function drawSmoothClosedBezierCurve(points, lineWidth, startColorHex, endColorHex) {
  noFill();
  strokeWeight(lineWidth);
  let startColor = color(startColorHex);
  let endColor = color(endColorHex);
  let totalSegments = (points.length + 1) * 100;
  let midSegment = totalSegments / 2;

  for (let i = 0; i < points.length; i++) {
    let nextIndex = (i + 1) % points.length;
    let xc1 = (points[i][0] + points[nextIndex][0]) / 2;
    let yc1 = (points[i][1] + points[nextIndex][1]) / 2;

    let prevIndex = (i - 1 + points.length) % points.length;
    let xc0 = (points[i][0] + points[prevIndex][0]) / 2;
    let yc0 = (points[i][1] + points[prevIndex][1]) / 2;

    for (let j = 0; j < 100; j++) {
      let t = j / 100;
      let x0 = lerp(xc0, points[i][0], t);
      let y0 = lerp(yc0, points[i][1], t);
      let x1 = lerp(points[i][0], xc1, t);
      let y1 = lerp(points[i][1], xc1, t);
      let x = lerp(x0, x1, t);
      let y = lerp(y0, y1, t);

      let nextT = (j + 1) / 100;
      let nextX0 = lerp(xc0, points[i][0], nextT);
      let nextY0 = lerp(yc0, points[i][1], nextT);
      let nextX1 = lerp(points[i][0], xc1, nextT);
      let nextY1 = lerp(points[i][1], xc1, nextT);
      let nextX = lerp(nextX0, nextX1, nextT);
      let nextY = lerp(nextY0, nextY1, nextT);

      let segmentIndex = i * 100 + j;
      let interColor;
      if (segmentIndex < midSegment) {
        interColor = lerpColor(startColor, endColor, segmentIndex / midSegment);
      } else {
        interColor = lerpColor(endColor, startColor, (segmentIndex - midSegment) / midSegment);
      }

      stroke(interColor);
      line(x, y, nextX, nextY);
    }
  }
}

Main Animation and Rendering

function draw() {
  Angle = Angle + Rot;
  background(features.backgroundColour);
  translate(e / 2, e / 2);
  rotate(Angle);

  Points = ChangePointsLocation(Points, step, DecidedRange);
  drawSmoothClosedBezierCurve(Points, LiNewidth, features.foregroundColour1, features.foregroundColour2);

  resetMatrix();
  if (frameCount === 1) {
    $fx.preview();
  }
}

Saving the Animation as GIF

function keyPressed() {
  if (key === 's' || 'S') {
    saveGif('Bezier 2', 30);
  }
}

This artwork blends creativity with code, relying on randomization and user interaction to generate unique and dynamic visuals every time it is run.

Click here to get your hands on the full code for these spectacular dynamic Bezier curves. But that’s not all — feel free to tweak the parameters to your heart’s desire. Want more points, wilder color transitions, or curvier curves? It’s all yours to play with!

The canvas, darling, is your playground. Experiment with the number of control points, or go wild with the gradients and lines! Oh, and let’s not forget the shimmering rotation that’ll take your visual creation to another dimension. Every refresh will birth something fresh, something new, something utterly magnificent!

Once you’re done, share your work with me! Let me marvel at your creative genius and we can bask in the glory of these mesmerizing animations together! 🥂💖

Now go on, unleash the magic ✨ and don’t be shy to show off that beauty you create!

With all my love,

Frostbond Coders

stay ahead with our newsletter

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

feedback