Create Psychedelic jellyfish shader from single icosahedron from scratch using HTML, CSS and JavaScript.

AVvXsEhC7 C7PQXt9DC4yo4Zlbi7IC QR0HPETaSxo2pdun8FRzhnXrHDVg5ptS LqOiJMCwBfLTgKugpJBLnBwnkjDhn5T21W3wPQiGyC5OPqREviTxODuvzf68IJtw0mhBKJZpXuXtEceoaHwGZjeCBVCfs7zl


Hello Developer, In this article I teach you how to create jellyfish psychedelic jellyfish shader from single icosahedron from scratch using HTML, CSS and JavaScript. Now let’s get’s started. 

HTML CODE HERE :-


<!DOCTYPE html>
<html lang="en" >
<head>
  <meta charset="UTF-8">
  <title>Bihari Graphic Psychedelic Jellyfish </title>
  <link rel="stylesheet" href="./style.css">

</head>
<body>
<!-- partial:index.partial.html -->
<canvas id="canvas" />

<script type="x-shader" id="shader_vertex">
#define PI 3.1415926535897932384626433832795

const float TAU = PI * 2.0;

uniform float u_time;

varying vec3 v_mod_pos;
varying vec3 v_orig_pos;
varying float v_tail_bumps;
varying float v_head_swirl;
varying float v_head_bumps;

float get_area(float begin, float end, float value) {
  return step(begin, value) - step(end, value);
}

float get_normalized_range(float begin, float end, float value) {
  float range = end - begin;
  return value / range;
}

void main() {

  vec4 model_position = modelMatrix * vec4(position, 1.0);

  // the original position of the vertices
  vec3 orig_pos = model_position.xyz;
  // the modified position of the vertices
  vec3 mod_pos = model_position.xyz;

  // scale down bottom part
  mod_pos.xz *= 1.0 - smoothstep(0.05, -0.4, orig_pos.y) * 0.2;
  // pinch tail
  mod_pos.xz *= 1.0 - smoothstep(0.05, -1.0, orig_pos.y);
  // stretch tail
  mod_pos.y *= 1.0 + smoothstep(0.0, -1.0, orig_pos.y) * 2.0;

  // curl tail in beneath head
  float area_curled_under_head = smoothstep(0.1, 0.0, orig_pos.y) - smoothstep(-0.1, 0.0, orig_pos.y);
  float area_curled_under_head_position = clamp(get_normalized_range(0.1, -0.1, orig_pos.y), 0.0, 1.0);
  mod_pos.y += sin(area_curled_under_head_position * PI * 0.5) * area_curled_under_head * 0.5;

  float swim_speed = u_time * 2.0 + sin(u_time * 2.0 + PI) * 0.5 + snoise2(vec2(u_time * 0.02, 0.0));

  // entire swimming motion
  mod_pos.y += sin(swim_speed + mod_pos.y + PI * 0.4) * 0.15;

  // wiggly head swimming motion
  mod_pos.x += sin(swim_speed * 0.5 + mod_pos.y * 3.5) * 0.15 * clamp(orig_pos.y - 0.3, 0.0, 1.0) * smoothstep(-0.6,-0.4, orig_pos.y);
  mod_pos.z += cos(swim_speed * 0.5 + mod_pos.y * 3.7) * 0.15 * clamp(orig_pos.y - 0.3, 0.0, 1.0) * smoothstep(-0.6,-0.4, orig_pos.y);

  // head swimming motion
  float swimming_head_area = 1.0 - smoothstep(-0.2, -0.4, orig_pos.y);
  mod_pos.x *= 1.0 + sin(swim_speed + orig_pos.y) * (swimming_head_area * 0.15 + (0.1 * orig_pos.y));
  mod_pos.z *= 1.0 + sin(swim_speed + orig_pos.y) * (swimming_head_area * 0.15 + (0.1 * orig_pos.y));
  mod_pos.y *= 1.0 + sin(swim_speed + orig_pos.y + PI * 0.75) * swimming_head_area * 0.1;

  // head swirl
  float head_swirl_angle = atan(orig_pos.x, orig_pos.z);
  float head_swirl = head_swirl_angle;
  head_swirl += PI;
  head_swirl /= TAU;
  head_swirl = 0.5 + sin(head_swirl * TAU * 8.0) * 0.5;
  head_swirl *= smoothstep(1.0, 0.75, orig_pos.y) - smoothstep(0.4, 0.0, orig_pos.y);
  mod_pos *= 1.0 + 0.05 * head_swirl;
  v_head_swirl = head_swirl;

  // head bumps
  vec4 head_bumps_vector = vec4(orig_pos.xz * 8.0 * (2.0 - orig_pos.y), orig_pos.y * 4.0 + mod_pos.y * 0.25, swim_speed * 0.1);
  float head_bumps_noise = snoise4(head_bumps_vector);
  float head_bumps = abs(head_bumps_noise) * smoothstep(0.1, 0.125, orig_pos.y);
  v_head_bumps = head_bumps;
  mod_pos *= 1.0 + head_bumps * 0.025;

  // tail swimming motion
  float swimming_tail_area = smoothstep(-0.3, -1.0, orig_pos.y);
  mod_pos.y *= 1.0 + sin(swim_speed + orig_pos.y + PI) * swimming_tail_area * 0.1;

  float spin_amount = 0.5 + sin(swim_speed + orig_pos.y - PI) * 0.5;

  // spin tail
  mod_pos.x += sin(exp(orig_pos.y * 0.25) * PI * 24.0 + u_time * 4.0) * smoothstep(0.0, -1.0, orig_pos.y) * 0.3 * spin_amount;
  mod_pos.z += cos(exp(orig_pos.y * 0.25) * PI * 16.0 + u_time * 4.0) * smoothstep(0.0, -1.0, orig_pos.y) * 0.3 * spin_amount;

  float tail_noise_amount = smoothstep(0.0, -0.5, orig_pos.y);

  // make the spin more unpredictable and WaVy
  vec4 spin_noise_vector = vec4(mod_pos.xz + spin_amount, mod_pos.y + spin_amount + u_time * 0.5, u_time * 0.05);
  float spin_noise = snoise4(spin_noise_vector) * tail_noise_amount * mod_pos.y;
  mod_pos.xz *= 1.0 + spin_noise;

  // add some bumps to the tail
  vec4 tail_bump_vector = vec4(orig_pos.xz * 8.0, orig_pos.y * 2.0, u_time * 0.2);
  float tail_bump_noise = snoise4(tail_bump_vector);
  float tail_bumps = abs(tail_bump_noise * tail_noise_amount);
  mod_pos.x += sin(tail_bumps * PI) * 0.02;
  mod_pos.z += cos(tail_bumps * PI) * 0.02;

  // entire swimming motion
  mod_pos.y += sin(swim_speed + mod_pos.y + PI * 0.4) * 0.25;

  vec4 view_position = viewMatrix * vec4(mod_pos, 1.0);
  vec4 projected_position = projectionMatrix * view_position;

  gl_Position = projected_position;

  v_mod_pos = mod_pos;
  v_orig_pos = orig_pos;
  v_tail_bumps = tail_bumps;

}
</script>

<script type="x-shader" id="shader_fragment">
uniform float u_time;

varying vec3 v_mod_pos;
varying vec3 v_orig_pos;
varying float v_tail_bumps;
varying float v_head_swirl;
varying float v_head_bumps;

#define PI 3.1415926535897932384626433832795

const float TAU = PI * 2.0;

const vec3 center = vec3(0.0, 0.0, 0.0);

float get_area(float begin, float end, float value) {
  return step(begin, value) - step(end, value);
}
 
float get_normalized_range(float begin, float end, float value) {
  float range = end - begin;
  return value / range;
}

void main() {

  vec3 color = vec3(0.0, 0.0, 0.0);
  float alpha = 1.0;

  // head gradient
  float head_area = smoothstep(0.2, 0.25, v_orig_pos.y);
  float head_area_position = get_normalized_range(0.2, 1.0, v_orig_pos.y);
  float clamped_head_area_position = clamp(head_area_position, 0.0, 1.0);
  color += clamped_head_area_position;

  // threads
  // float threads_area = (
  //   smoothstep(0.1, 0.05, v_orig_pos.y) - 
  //   smoothstep(-0.05, -0.1, v_orig_pos.y)
  // );
  // float threads_area_position = get_normalized_range(-0.1, 0.1, v_orig_pos.y);
  // float clamped_threads_area_position = clamp(threads_area_position, 0.0, 1.0);
  // color += threads_area;
  
  color *= v_head_swirl * 0.75;
  color += v_head_bumps * 0.25;

  // threads
  float threads_area = smoothstep(0.15, 0.1, v_orig_pos.y) - smoothstep(0.0, -0.1, v_orig_pos.y);
  vec3 threads_vector = vec3(
    v_orig_pos.x * 16.0,
    v_orig_pos.z * 16.0,
    v_orig_pos.y
  );
  float threads_noise = (1.0 - abs(snoise3(threads_vector))) * threads_area * smoothstep(-0.1, 0.15, v_orig_pos.y);
  color += threads_noise * 0.5;

  color.b += threads_noise;
  color.g += threads_noise * sin(v_mod_pos.y) * threads_area;
  color.b += (smoothstep(0.75, 0.1, v_orig_pos.y) - smoothstep(0.1, 0.0, v_orig_pos.y)) * 0.25;

  // tail bump gradients
  float tail_bumps_area = smoothstep(0.0, -0.2, v_orig_pos.y);
  color += v_tail_bumps * 1.25 * smoothstep(-1.5, -0.5, v_mod_pos.y) * tail_bumps_area;


  // color.r += 0.2 + sin(v_orig_pos.y + u_time * 0.2) * 0.2;

  float lighten_on_top = smoothstep(-0.5, 1.5, max(0.0, v_mod_pos.y) * max(0.0, v_orig_pos.y));
  color.r += lighten_on_top * 0.8;
  color.g += lighten_on_top * 0.2;
  color.b += lighten_on_top * 0.4;

  color.r *= 1.0 + sin(smoothstep(0.5, 1.0, v_mod_pos.y) * PI) * 0.75;
  color.g *= 1.0 + sin(smoothstep(0.5, 1.0, v_mod_pos.y) * PI) * 0.25;

  color.b *= 1.0 + v_head_bumps * 2.0;
  color.g *= 1.0 + v_head_bumps * (1.65 + max(0.0, v_orig_pos.y));

  color.b += smoothstep(0.7, 0.0, distance(v_mod_pos.xz, v_orig_pos.xz)) * (v_tail_bumps + 2.0) * tail_bumps_area;
  color.g += smoothstep(0.5, 0.0, distance(v_mod_pos.xz, v_orig_pos.xz)) * (v_tail_bumps + 1.0) * tail_bumps_area;
  color.r += smoothstep(0.5, 0.0, distance(v_mod_pos.xz, v_orig_pos.xz)) * (v_tail_bumps * 4.0) * tail_bumps_area;

  color.rgb += v_mod_pos.y * 0.1 * tail_bumps_area;

  color.r += v_tail_bumps * 0.25;
  color.b += v_tail_bumps * 0.55;
  color.g += v_tail_bumps * 0.35;
  // color.b *= 1.0 + tail_bumps_area * abs(min(v_mod_pos.y, 0.0));
  // color.r -= tail_bumps_area * v_mod_pos.y * 0.5;
  // color.g *= 1.0 + tail_bumps_area * distance(v_mod_pos.xz, vec2(0.0,0.0));

  alpha = clamp(exp(color.b - 0.2), 0.0, 1.0);
  // alpha *= 1.0 - smoothstep(-0.3, -0.8, v_orig_pos.y) + tail_bumps_area * v_tail_bumps * 2.0;

  gl_FragColor = vec4(color, alpha);
}
</script>

<script type="x-shader" id="simplexNoise">
	
vec3 permute2(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }

float snoise2(vec2 v){
  const vec4 C = vec4(0.211324865405187, 0.366025403784439,
           -0.577350269189626, 0.024390243902439);
  vec2 i  = floor(v + dot(v, C.yy) );
  vec2 x0 = v -   i + dot(i, C.xx);
  vec2 i1;
  i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
  vec4 x12 = x0.xyxy + C.xxzz;
  x12.xy -= i1;
  i = mod(i, 289.0);
  vec3 p = permute2( permute2( i.y + vec3(0.0, i1.y, 1.0 ))
  + i.x + vec3(0.0, i1.x, 1.0 ));
  vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy),
    dot(x12.zw,x12.zw)), 0.0);
  m = m*m ;
  m = m*m ;
  vec3 x = 2.0 * fract(p * C.www) - 1.0;
  vec3 h = abs(x) - 0.5;
  vec3 ox = floor(x + 0.5);
  vec3 a0 = x - ox;
  m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
  vec3 g;
  g.x  = a0.x  * x0.x  + h.x  * x0.y;
  g.yz = a0.yz * x12.xz + h.yz * x12.yw;
  return 130.0 * dot(m, g);
}
	
	//	Simplex 3D Noise 
vec4 permute3(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);}
vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;}

float snoise3(vec3 v){ 
  const vec2  C = vec2(1.0/6.0, 1.0/3.0) ;
  const vec4  D = vec4(0.0, 0.5, 1.0, 2.0);

// First corner
  vec3 i  = floor(v + dot(v, C.yyy) );
  vec3 x0 =   v - i + dot(i, C.xxx) ;

// Other corners
  vec3 g = step(x0.yzx, x0.xyz);
  vec3 l = 1.0 - g;
  vec3 i1 = min( g.xyz, l.zxy );
  vec3 i2 = max( g.xyz, l.zxy );

  //  x0 = x0 - 0. + 0.0 * C 
  vec3 x1 = x0 - i1 + 1.0 * C.xxx;
  vec3 x2 = x0 - i2 + 2.0 * C.xxx;
  vec3 x3 = x0 - 1. + 3.0 * C.xxx;

// Permutations
  i = mod(i, 289.0 ); 
  vec4 p = permute3( permute3( permute3( 
             i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
           + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) 
           + i.x + vec4(0.0, i1.x, i2.x, 1.0 ));

// Gradients
// ( N*N points uniformly over a square, mapped onto an octahedron.)
  float n_ = 1.0/7.0; // N=7
  vec3  ns = n_ * D.wyz - D.xzx;

  vec4 j = p - 49.0 * floor(p * ns.z *ns.z);  //  mod(p,N*N)

  vec4 x_ = floor(j * ns.z);
  vec4 y_ = floor(j - 7.0 * x_ );    // mod(j,N)

  vec4 x = x_ *ns.x + ns.yyyy;
  vec4 y = y_ *ns.x + ns.yyyy;
  vec4 h = 1.0 - abs(x) - abs(y);

  vec4 b0 = vec4( x.xy, y.xy );
  vec4 b1 = vec4( x.zw, y.zw );

  vec4 s0 = floor(b0)*2.0 + 1.0;
  vec4 s1 = floor(b1)*2.0 + 1.0;
  vec4 sh = -step(h, vec4(0.0));

  vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
  vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;

  vec3 p0 = vec3(a0.xy,h.x);
  vec3 p1 = vec3(a0.zw,h.y);
  vec3 p2 = vec3(a1.xy,h.z);
  vec3 p3 = vec3(a1.zw,h.w);

//Normalise gradients
  vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
  p0 *= norm.x;
  p1 *= norm.y;
  p2 *= norm.z;
  p3 *= norm.w;

// Mix final noise value
  vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
  m = m * m;
  return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), 
                                dot(p2,x2), dot(p3,x3) ) );
}
	
	//	Simplex 4D Noise 
vec4 permute4(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);}
float permute4(float x){return floor(mod(((x*34.0)+1.0)*x, 289.0));}
vec4 taylorInvSqrt4(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;}
float taylorInvSqrt4(float r){return 1.79284291400159 - 0.85373472095314 * r;}

vec4 grad4(float j, vec4 ip){
  const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0);
  vec4 p,s;

  p.xyz = floor( fract (vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0;
  p.w = 1.5 - dot(abs(p.xyz), ones.xyz);
  s = vec4(lessThan(p, vec4(0.0)));
  p.xyz = p.xyz + (s.xyz*2.0 - 1.0) * s.www; 

  return p;
}

float snoise4(vec4 v){
  const vec2  C = vec2( 0.138196601125010504,  // (5 - sqrt(5))/20  G4
                        0.309016994374947451); // (sqrt(5) - 1)/4   F4
// First corner
  vec4 i  = floor(v + dot(v, C.yyyy) );
  vec4 x0 = v -   i + dot(i, C.xxxx);

// Other corners

// Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI)
  vec4 i0;

  vec3 isX = step( x0.yzw, x0.xxx );
  vec3 isYZ = step( x0.zww, x0.yyz );
//  i0.x = dot( isX, vec3( 1.0 ) );
  i0.x = isX.x + isX.y + isX.z;
  i0.yzw = 1.0 - isX;

//  i0.y += dot( isYZ.xy, vec2( 1.0 ) );
  i0.y += isYZ.x + isYZ.y;
  i0.zw += 1.0 - isYZ.xy;

  i0.z += isYZ.z;
  i0.w += 1.0 - isYZ.z;

  // i0 now contains the unique values 0,1,2,3 in each channel
  vec4 i3 = clamp( i0, 0.0, 1.0 );
  vec4 i2 = clamp( i0-1.0, 0.0, 1.0 );
  vec4 i1 = clamp( i0-2.0, 0.0, 1.0 );

  //  x0 = x0 - 0.0 + 0.0 * C 
  vec4 x1 = x0 - i1 + 1.0 * C.xxxx;
  vec4 x2 = x0 - i2 + 2.0 * C.xxxx;
  vec4 x3 = x0 - i3 + 3.0 * C.xxxx;
  vec4 x4 = x0 - 1.0 + 4.0 * C.xxxx;

// Permutations
  i = mod(i, 289.0); 
  float j0 = permute4( permute4( permute4( permute4(i.w) + i.z) + i.y) + i.x);
  vec4 j1 = permute4( permute4( permute4( permute4 (
             i.w + vec4(i1.w, i2.w, i3.w, 1.0 ))
           + i.z + vec4(i1.z, i2.z, i3.z, 1.0 ))
           + i.y + vec4(i1.y, i2.y, i3.y, 1.0 ))
           + i.x + vec4(i1.x, i2.x, i3.x, 1.0 ));
// Gradients
// ( 7*7*6 points uniformly over a cube, mapped onto a 4-octahedron.)
// 7*7*6 = 294, which is close to the ring size 17*17 = 289.

  vec4 ip = vec4(1.0/294.0, 1.0/49.0, 1.0/7.0, 0.0) ;

  vec4 p0 = grad4(j0,   ip);
  vec4 p1 = grad4(j1.x, ip);
  vec4 p2 = grad4(j1.y, ip);
  vec4 p3 = grad4(j1.z, ip);
  vec4 p4 = grad4(j1.w, ip);

// Normalise gradients
  vec4 norm = taylorInvSqrt4(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
  p0 *= norm.x;
  p1 *= norm.y;
  p2 *= norm.z;
  p3 *= norm.w;
  p4 *= taylorInvSqrt4(dot(p4,p4));

// Mix contributions from the five corners
  vec3 m0 = max(0.6 - vec3(dot(x0,x0), dot(x1,x1), dot(x2,x2)), 0.0);
  vec2 m1 = max(0.6 - vec2(dot(x3,x3), dot(x4,x4)            ), 0.0);
  m0 = m0 * m0;
  m1 = m1 * m1;
  return 49.0 * ( dot(m0*m0, vec3( dot( p0, x0 ), dot( p1, x1 ), dot( p2, x2 )))
               + dot(m1*m1, vec2( dot( p3, x3 ), dot( p4, x4 ) ) ) ) ;

}

</script>
<!-- partial -->
  <script type="module" src="./script.js"></script>

</body>
</html>

CSS CODE HERE :-


html, body {
  margin: 0;
  overflow: hidden;
}

#canvas {
  display: block;
  width: 100vw;
  height: 100vh;
}

JavaScript CODE HERE :-


import * as THREE from "https://cdn.skypack.dev/three@0.133.1";
import { OrbitControls } from "https://cdn.skypack.dev/three@0.133.1/examples/jsm/controls/OrbitControls";

const getAspectRatio = () => canvas.offsetWidth / canvas.offsetHeight;

const renderer = new THREE.WebGLRenderer({
  antialias: true,
  powerPreference: 'high-performance',
  canvas });


const scene = new THREE.Scene();
scene.background = new THREE.Color(0x000000);

const camera = new THREE.PerspectiveCamera(45, getAspectRatio(), 0.01, 1000);
camera.position.set(0, -2, 8);
camera.lookAt(0, -1, 0);
scene.add(camera);

const controls = new OrbitControls(camera, canvas);

const geometry = new THREE.IcosahedronGeometry(1, 64);

const material = new THREE.ShaderMaterial({
  vertexShader: simplexNoise.textContent + shader_vertex.textContent,
  fragmentShader: simplexNoise.textContent + shader_fragment.textContent,
  uniforms: {
    u_time: { value: 0.0 } } });



const mesh = new THREE.Mesh(geometry, material);
mesh.position.y = .15;
scene.add(mesh);

const clock = new THREE.Clock();
clock.start();
const loop = () => {
  const delta = clock.getDelta();
  material.uniforms.u_time.value += delta;
  renderer.render(scene, camera);
  requestAnimationFrame(loop);
};
loop();

const update_size = () => {
  renderer.setSize(canvas.offsetWidth, canvas.offsetHeight, false);
  camera.aspect = getAspectRatio();
  camera.updateProjectionMatrix();
};

window.addEventListener('resize', update_size);

update_size();

Notes:
To get the password to download the code on Telegram
join

Download Codes

Bihari Graphic:

BihariGraphic
Join our Telegram Channel and Discussion Group to get Daily Update’s and Idea’s

Scroll to Top