Bezier 2:Dynamic Bezier Curves
written by reyrove
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=[];
- Canvas Dimensions : The variable e is dynamically set as the minimum of the screen’s width or height, ensuring the artwork is proportional across various devices. We then define the canvas dimensions (canvas.w and canvas.h) based on e.
- Mobile Detection : The variable isMob checks the user’s device for mobile detection, which will be useful later for optimizing pixel density.
- Points Array : Several global arrays (Points, DecidedRange, step, etc.) are initialized to store data like the points that form the Bezier curves, their ranges of movement, their step values for animation, and rotation angles.
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)
- Control Points Parameter : We define a control parameter (number_id1) using the $fxhash feature, allowing the user to input a number between 3 and 30. This determines the number of control points used to generate the Bezier curves, introducing a customizable complexity to the artwork.
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));
}
- Canvas Creation : The setup function creates the canvas and sets the frame rate to 30 for smooth animations.
- Color Arrays : Two arrays of background and foreground colors are defined. Each time the code runs, a random selection from these arrays will be used to determine the background and line gradient colors.
-
Number of Control Points
: The number of control points is set by the user’s input using
$fx.getParam('number_id1')
. -
Dynamic Data Generation
: Functions such as
generateRandomPoints
,generateRandomNumbers
, andgenerateRandomBinaryVector
populate arrays with random values used for animating the Bezier curves. - Line Width and Rotation : The line width and rotation speed are dynamically set, ensuring variety across iterations.
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;
}
-
Points Generation
: The
generateRandomPoints
function generates random points arranged in a circular pattern. The angle and radius are randomized for each point, ensuring that each iteration results in unique control points for the Bezier curves.
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;
}
-
Animation of Points
: This function updates the position of each point, creating a dynamic effect. The points "bounce" between defined ranges, and their movement is determined by
step
values.
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);
}
}
}
-
Drawing Curves
: This function creates smooth, connected Bezier curves between all control points, ensuring that the line gracefully transitions between points. The line color gradually transitions from
startColorHex
toendColorHex
.
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();
}
}
-
Frame-by-Frame Rendering
: The
draw
function rotates the entire scene usingrotate(Angle)
and updates the position of the control points by callingChangePointsLocation
. It then draws the animated Bezier curves and resets the transformation matrix for the next frame.
Saving the Animation as GIF
function keyPressed() {
if (key === 's' || 'S') {
saveGif('Bezier 2', 30);
}
}
- Saving GIF : By pressing the 'S' key, the user can save a 5-second animation of the generated Bezier curves as a GIF.
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