Creating an animated jellyfish in JS! 👀💥
Tags: p5js, frontend, generativeart, creativecoding
Published: 2022-06-06 12:06:35

---
title: Creating an animated jellyfish in JS! 👀💥
published: true
description: Steps on how I have created an animated jellyfish in javascript using only perlin noise & curve lines with the p5js library.
tags: p5js, FrontEnd, generativeart, creativecoding
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2imeoas9u5xvr6n1t1i3.gif
 
# Use a ratio of 100:42 for best results.
---

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();
}
```

## 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);
  }
}
```

We will get something like this:

![Circle of points](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oy0ezyyacpntbm95n5qu.png)


## 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();
  }
}
```

![Circle of lines](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/arzb1hr3f1jmioptwj0e.png)
 
## 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();
  }
}
```

![Flatten lines circle](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5k6ovjhay288w0e7sicb.png)

## 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();
  }
}
```

![Curving lines](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x752imqk3c3kp2y1ejo6.png)
 
## 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();
  }
}
```

![Many lines](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8imzki6xc1if9wt14017.png)
 

## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jlnwvey9i7jqawv0qb7v.gif)
 

```
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();
  }
}

```