<script src="sketch.js"></script>
html, body {
  margin: 0;
  padding: 0;
  text-align: center;
}

// Define the number of points and create an array to store shape vertices.
let shapeVerts = [];
const numPoints = 20;

function setup() {
  createCanvas(250, 250); //500, 500
  rectMode(CENTER);
  colorMode(HSB, 360, 100, 100, 100);

  initialiseCustomShape();
}

// Initialise the custom shape's points with number defined in the numPoints variable.
function initialiseCustomShape() {
  for (let i = 0; i < numPoints; i++) {
    shapeVerts.push(createPoint());
  }
}

function draw() {
  background(50);
  fill(0);

  // Calculate the center point of the custom shape.
  let centerPoint = calculateCenter();

  // Draw the main custom shape with its vertices connected by bezier curves.
  drawCustomShape(shapeVerts, 10);

  push();
  noFill();
  strokeCap(SQUARE);
  strokeWeight(2.5);

  // Draw a second custom shape with its outline varying in opacity.
  stroke(0, 0, 100, abs(sin(frameCount * 0.01)) * random(90, 100));
  drawCustomShape(shapeVerts.slice(10), shapeVerts.length - 10);
  pop();

  drawGlasses(centerPoint);

  // Adjust the positions of custom shape vertices over time.
  adjustCustomShapePoints();
}

// Calculate the center point of the custom shape.
function calculateCenter() {
  let count = 0;
  let totalX = 0;
  let totalY = 0;
  for (let i = 0; i < shapeVerts.length; i++) {
    let pt = shapeVerts[i];
    count++;

    let shapeScale = 0;
    let ang = noise(pt.x * shapeScale, pt.y * shapeScale, 0.75) * 0.02;
    let off =
      noise(pt.x * shapeScale, pt.y * shapeScale, 0.75) * random(25, 50); //speed of movement of the shapes

    // Update the totalX and totalY values based on the noise-generated movement.
    totalX += pt.x +=
      cos(ang / 2) * off * noise(0.1) * abs(sin(frameCount % 0.0001)) * width;
    totalY += pt.y +=
      sin(ang / 2) * off * noise(0.1) * abs(sin(frameCount % 0.0001)) * height;
  }

  // Return the average position of the shape's vertices.
  return createVector(totalX / count, totalY / count);
}

// Draw the custom shape by connecting vertices with bezier curves.
function drawCustomShape(points, numVertices) {
  beginShape();
  for (let i = 0; i < numVertices; i++) {
    if (i === 0) {
      vertex(points[(i.x, i.y)]);
    } else {
      bezierVertexP(points[i], points[i], points[i + 1]);
      i += 2; // Skip two points for the bezier
    }
  }
  endShape();
}

// Define a custom function for the bezierVertex.
function bezierVertexP(a, b, c) {
  bezierVertex(a.x, a.y, b.x, b.y, c.x, c.y);
}

// Create a point with random co-ords then adjust.
function createPoint(tx, ty) {
  return {
    x: tx || random(width),
    y: ty || random(height),
    adjust(d) {
      if (d >= width) {
        //calculateCenter();
        this.adjustX();
        this.adjustY();
      }
    },
    adjustX() {
      this.x = abs(sin(frameCount * 0.01)) * random(width * 1.5);
    },
    adjustY() {
      this.y = abs(sin(frameCount * 0.01)) * random(height * 1.5);
    },
  };
}

// Adjust the positions of custom shape points based on distance from a random point.
function adjustCustomShapePoints() {
  for (let i = 0; i < shapeVerts.length; i++) {
    let pt = shapeVerts[i];
    let d = dist(pt.x, pt.y, random(width), random(height));
    pt.adjust(d); // Adjust the point's position
  }
}

function drawGlasses(centerPoint) {
  push();
  stroke(0);
  fill(50);
  // Draw glasses frames
  rect(centerPoint.x + 50, centerPoint.y, 50, 20);
  rect(centerPoint.x - 50, centerPoint.y, 50, 20);
  noStroke();
  fill(0);

  // Draw glasses arms
  rect(centerPoint.x + 50, centerPoint.y, 2.5);
  rect(centerPoint.x - 50, centerPoint.y, 2.5);

  // Draw glasses bridge
  stroke(196, 75, 100);
  line(centerPoint.x - 25, centerPoint.y, centerPoint.x + 25, centerPoint.y);
  pop();
}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.