DEV Community

Cover image for Creating an animated jellyfish in JS! πŸ‘€πŸ’₯
Medusa
Medusa

Posted on

Creating an animated jellyfish in JS! πŸ‘€πŸ’₯

It looks 3D right? The reality is that the animation is composed only of curves in a 2D plane, we are going to see in depth the steps that I have followed to create this effect that we can use on our websites and combine with user actions.

Setup

To start we will need to add the p5js library to our project and create a JS file where we will put all the necessary code. We will create a canvas with a black background through the setup function in this way:

function setup() {
  createCanvas(window.innerHeight, window.innerHeight);
  background(0);
  frameRate(100);
  stroke(255);
  strokeWeight(10);
  noFill();
}
Enter fullscreen mode Exit fullscreen mode

The correct way to draw a circle

At the end of the setup function we will create a circle of points through a for loop that iterates the angles of the circle, like this:

function setup() {
  ...
  const radius = 200;
  const centerX = width / 2;
  const centerY = height / 2;
  for (let angle = 1; angle <= 360; angle += 10) {
    const x = centerX + radius * cos(radians(angle));
    const y = centerY + radius * sin(radians(angle));
    point(x, y);
  }
}
Enter fullscreen mode Exit fullscreen mode

We will get something like this:

Circle of points

Adding lines

Now we will replace the points with lines that go from each point to the center. And we change the strokeWeight from 10 to 1:

function setup() {
  ...
    const y = centerY + radius * sin(radians(angle));
    beginShape();
    curveVertex(centerX, centerY);
    curveVertex(centerX, centerY);
    curveVertex(x, y);
    curveVertex(x, y);
    endShape();
  }
}
Enter fullscreen mode Exit fullscreen mode

Circle of lines

Moving the center and crushing the circle

Now we would be seeing our future "jellyfish" from above. To create a side view effect I have decided to move the center of the circle higher on the Y axis and flatten the circle creating this effect:

function setup() {
  ...
    const y = centerY + radius * sin(radians(angle));
    beginShape();
    curveVertex(centerX, centerY - 100);
    curveVertex(centerX, centerY - 100);
    curveVertex(x, y / 10 + 500);
    curveVertex(x, y / 10 + 500);
    endShape();
  }
}
Enter fullscreen mode Exit fullscreen mode

Flatten lines circle

Curving the lines

Now our experiment begins to take on more of a jellyfish shape by adding curvature to the lines we just created. To do this we will modify above all the first and last curveVertex that correspond to the anchor points of the curve.

function setup() {
  ...
    const y = centerY + radius * sin(radians(angle));
    beginShape();
    curveVertex(centerX, centerY + 80);
    curveVertex(centerX, centerY - 50);
    curveVertex(x, y / 10 + 500);
    curveVertex(x, y / 10 + 1200);
    endShape();
  }
}
Enter fullscreen mode Exit fullscreen mode

Curving lines

Adding lots of lines and noise 🀘🏿

Adding many lines, lowering the opacity of each line and adding perlin noise on the Y axis we get a more organic and natural effect that already reminds us of a jellyfish.

function setup() {
  createCanvas(window.innerHeight, window.innerHeight);
  background(0);
  frameRate(100);
  stroke(255, 20);
  strokeWeight(1);
  noFill();

  const radius = 200;
  const centerX = width / 2;
  const centerY = height / 2;
  for (let angle = 1; angle <= 360; angle += 0.2) {
    const x = centerX + radius * cos(radians(angle));
    const y = centerY + radius * sin(radians(angle));
    const noiseY = 50 - noise(angle / 200) * 100;
    beginShape();
    curveVertex(centerX, centerY + 80);
    curveVertex(centerX, centerY - 50);
    curveVertex(x, y / 10 + 500 + noiseY);
    curveVertex(x, y / 10 + 1200);
    endShape();
  }
}
Enter fullscreen mode Exit fullscreen mode

Many lines

More noise, color and movement 🀯

Playing with the values of our curves and with the stroke color of each line adding variation over time we created the complete effect we were looking for. I leave you the complete code of the animation and I encourage you to create your own jellyfish with new shapes and colors and adding user or sound interaction. Happy Coding! πŸ––πŸ»πŸ™ŒπŸΎ

Jellyfish

function setup() {
  createCanvas(window.innerHeight, window.innerHeight);
  background(0);
  frameRate(100);

  stroke(255, 20);
  strokeWeight(1);
  noFill();
}

let i = 0;
function draw() {
  i++;
  background(0);
  const centerX = width / 2;
  const centerY = height / 2;
  const radius = 200 * noise(i / 300) + 100;
  const radius2 = 20 * noise(i / 300) + 20;
  strokeWeight(1);
  translate(0, -150);
  for (let angle = 1; angle <= 360; angle += 0.2) {
    const x = centerX + radius * cos(radians(angle));
    const y = centerY + radius * sin(radians(angle)) + (200 - noise(radians(angle), i / 100) * 400);
    const noiseStrokeR = noise(radians(angle));
    const noiseStrokeG = noise(i / 100);
    const noiseStrokeB = noise(radians(angle), i / 100);
    stroke(
      Math.round(255 * noiseStrokeR + 10),
      Math.round(120 * noiseStrokeB + 40),
      Math.round(255 * noiseStrokeG),
      60
    );
    beginShape();
    const noiseY = noise(radius / 100) * 100;
    const noiseY2 = 50 - noise(radius / 100, i / 120) * 100;
    const noiseX = 500 - noise(radians(angle), i / 120) * 1000;
    curveVertex(centerX, centerY + 200);
    curveVertex(centerX, centerY - 120 + noiseY);
    curveVertex(x, y / 10 + 500 + noiseY2);
    curveVertex(x + noiseX, y / 10 + 1000);
    endShape();
  }

  for (let angle = 1; angle <= 360; angle += 20) {
    const x = centerX + radius2 * 3 * cos(radians(angle));
    const x2 = centerX + (radius2 / 2) * cos(radians(angle));
    const y = centerY + radius2 * sin(radians(angle));
    const noiseStrokeR = noise(angle / 200);
    const noiseStrokeG = noise(i / 100);
    const noiseStrokeB = noise(angle / 200, i / 100);
    stroke(
      Math.round(255 * noiseStrokeR + 10),
      Math.round(120 * noiseStrokeB + 40),
      Math.round(255 * noiseStrokeG),
      120
    );
    strokeWeight(2);
    beginShape();
    const noiseY = noise(radius / 100) * 100;
    const noiseY2 = 50 - noise(i / 200, angle) * 100;
    const noiseX = 1000 - noise(radians(angle), i / 200) * 2000;
    const noiseX2 = 100 - noise(radians(360 - angle), i / 200) * 200;
    curveVertex(x2, centerY + 200);
    curveVertex(x2, centerY - 120 + noiseY);
    curveVertex(x + noiseX2, y / 1.1 + 500 + noiseY2);
    curveVertex(x + noiseX, y / 10 + 1000);
    endShape();
  }
}

Enter fullscreen mode Exit fullscreen mode

Top comments (3)

Collapse
 
jacksonkasi profile image
Jackson Kasi

wow!

Collapse
 
emma_backmansmith_fff385 profile image
Emma Backman-Smith

Awesome! How would you have it move around on the screen? So it would look like its swimming

Collapse
 
mijim profile image
Medusa

You could use translate(x,y) and rotate()