<script type="x-shader/x-vertex" id="vertex">
     varying vec3 v_position;
    varying vec2 vUv;

  uniform float time;
  uniform float scroll;
  uniform float u_factor;

  mat3 rotation3dX(float angle) {
  float s = sin(angle);
  float c = cos(angle);

  return mat3(
    1.0, 0.0, 0.0,
    0.0, c, s,
    0.0, -s, c
  );
}

mat3 rotation3dY(float angle) {
  float s = sin(angle);
  float c = cos(angle);

  return mat3(
    c, 0.0, -s,
    0.0, 1.0, 0.0,
    s, 0.0, c
  );
}


  void main () {
    vUv = uv;
    vec3 new_position = position;

    float wave = 0.0;
    wave += 0.10 * sin(time + position.x) + 0.05 * sin(1.0 * time + position.x) + 0.05 * sin(0.25 * time + position.x);
    wave += 0.15 * sin(time + position.y) + 0.05 * sin(2.0 * time + position.y) + 0.05 * sin(0.25 * time + position.y);
    wave += 0.20 * sin(time + position.z) + 0.05 * sin(0.5 * time + position.z) + 0.05 * sin(0.25 * time + position.z);

    new_position *= mix(u_factor, 1.0, wave);

    new_position *= rotation3dX(scroll * 0.001);
    new_position *= rotation3dY(scroll * 0.002);

    gl_Position = projectionMatrix * modelViewMatrix * vec4( new_position, 1.0 );
    gl_PointSize = 1.5;

    v_position = new_position;
  }
</script>
<script type="x-shader/x-fragment" id="fragment">
      uniform float time;
      uniform float u_opacity;
      varying vec3 v_position;
      varying vec2 vUv;
    
          vec3 palette( in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d )
{
    return a + b*cos( 6.28318*(c*t+d) );
}

  void main () {
    vec3 position = v_position;
    vec3 col = palette(vUv.y, vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(2.0,1.0,0.0),vec3(0.5,0.20,0.25) );


    vec3 color = vec3(0.459,0.141,0.141);
    gl_FragColor = vec4(color, 0.5);
    
  }
</script>
<div class="overlay"></div>

<div class="left">
<nav>
    <h1>Projects</h1> 
    <ul>
        <li>
            <div>
                <span>Döse</span>
            </div>
        </li>
        <li>
            <div>
                <span>Architecture</span>
            </div>
        </li>
        <li>
            <div>
                <span>Out of space</span>
            </div>
        </li>
        <li>
            <div>
                <span>Relieve</span>
            </div>
        </li>
    </ul>
</nav>
    
</div>
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    height: 100vh;
    width: 100%;
}

body {
    background-color: #fffbf3;
    color: #414141;
    font-family: "IvyMode Reg";
    font-display: swap;
    font-style: normal;
    font-weight: normal;
    font-size: 56px;
    line-height: 1.5;
}

.left {
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    top: 0;
    left: 0;
    width: 50%;
    height: 100%;
}

nav {
    position: relative;
    width: 100%;
    
    h1 {
        position: absolute;
        top: -80px;
        left: 10%;
        font-size: 18px;
        opacity: 0;
    }
    
    ul {
        list-style: none;
        padding: 0 20%;
        width: 100%;
    }
}




canvas {
    position: fixed;
    top: 0;
    left: 50%;
    height: 100%;
    width: 50%;
    z-index: 2;
    outline: none;
    opacity: 0;
}

li {
    position: relative;
    cursor: pointer;
    opacity: 0;

    
    &::before {
        content: '';
        top: 55%;
        width: 32px;
        height: 2px;
        background: #930300;
        position: absolute;
        left: -48px;
        opacity: 0;
        pointer-events: none;
    }
    
    &:hover{
        transform: translateX(32px);
        font-family: "IvyMode It";
        
        &::before {
            opacity: 1;
        }
    }
    
    
    > span {
        display: block;    
    }
}

.overlay {
    background-color: #eadcc8;
    position: fixed;
    top: 0;
    left: 50%;
    width: 50%;
    height: 100%;
    z-index: 4;
    pointer-events: none;
    transform: scaleX(0);
    transform-origin: center right;
}
View Compiled
import { OrbitControls } from "https://threejsfundamentals.org/threejs/resources/threejs/r110/examples/jsm/controls/OrbitControls.js";

class THREEScene {
  constructor(container = document.body) {
    this.container = container;

    this.setup();
    this.camera();
    this.addObjects();
    this.eventListeners();
    this.settings();
    this.render();
    this.animate();
  }

  settings() {
    this.settings = {
      blur: 0,
      speed: 0.5,
      noiseFreq: 1.0
    };
  }

  setup() {
    this.clock = new THREE.Clock();
    this.mouse = new THREE.Vector2();
    this.scene = new THREE.Scene();
    this.renderer = new THREE.WebGLRenderer({
      antialias: true
    });
    this.renderer.setSize(this.viewport.width, this.viewport.height);
    this.renderer.setPixelRatio = window.devicePixelRatio;
    this.renderer.setClearColor(0xeadcc8, 1);
    this.container.appendChild(this.renderer.domElement);
  }

  camera() {
    const FOV = 50;
    const NEAR = 0.001;
    const FAR = 100;
    const ASPECT_RATIO = this.viewport.aspectRatio;

    this.camera = new THREE.PerspectiveCamera(FOV, ASPECT_RATIO, NEAR, FAR);
    this.camera.position.set(0, 0, 20);
    this.camera.aspect = this.viewport.width / this.viewport.height;
    this.camera.updateProjectionMatrix();
  }

  lights() {
    //const ambientLight = new THREE.AmbientLight(0x404040);
  }

  addObjects() {
    this.geometry = new THREE.IcosahedronGeometry(4, 32);
    this.material = new THREE.ShaderMaterial({
      uniforms: {
        time: { value: 0 },
        u_factor: { value: 0.5 },
        u_opacity: { value: 0 }
      },
      vertexShader: document.getElementById("vertex").textContent,
      fragmentShader: document.getElementById("fragment").textContent
    });

    this.cube = new THREE.Points(this.geometry, this.material);
    this.cube.scale.set(0.5, 0.5, 0.5);
    this.scene.add(this.cube);
  }

  render() {
    this.camera.lookAt(this.scene.position);
    this.renderer.render(this.scene, this.camera);

    this.material.uniforms.time.value = this.clock.getElapsedTime();
    this.cube.rotation.y += 0.005;
    this.cube.rotation.x += 0.003;

    requestAnimationFrame(() => {
      this.render();
    });
  }

  animate() {
    gsap.set(".overlay", { scaleX: 0, transformOrigin: "center right" });
    gsap.set("h1", { x: -24 });

    const tl = gsap.timeline({
      delay: 1
    });

    tl.to("h1", {
      x: 0,
      opacity: 1
    })
      .fromTo(
        "li",
        {
          opacity: 0,
          y: 32
        },
        {
          opacity: 1,
          y: 0,
          stagger: 0.15,
          ease: "power2.out"
        },
        0
      )
      .to(
        ".overlay",
        {
          scaleX: 1,
          duration: 2.5,
          ease: "expo.inOut"
        },
        0
      )
      .set("canvas", {
        opacity: 1
      })
      .to(
        this.camera.position,
        {
          duration: 4,
          ease: "power3.inOut",
          z: 7,
          y: 0,
          x: 0
        },
        1
      )
      .to(
        ".overlay",
        {
          opacity: 0,
          duration: 4
        },
        "-=2.5"
      );

    const nav = document.querySelector("ul");

    nav.addEventListener("mouseenter", () => {
      gsap.to(this.material.uniforms.u_factor, {
        value: 1.0
      });
    });

    nav.addEventListener("mouseleave", () => {
      gsap.to(this.material.uniforms.u_factor, {
        value: 0.5
      });
    });
  }

  eventListeners() {
    window.addEventListener("resize", this.onWindowResize.bind(this));
  }

  onWindowResize() {
    this.camera.aspect = this.viewport.aspectRatio;
    this.camera.updateProjectionMatrix();
    this.renderer.setSize(this.viewport.width, this.viewport.height);
  }

  get viewport() {
    const width = this.container.clientWidth / 2;
    const height = this.container.clientHeight;
    const aspectRatio = width / height;

    this.aspectRatio = aspectRatio;

    return {
      width,
      height,
      aspectRatio
    };
  }
}

const scene = new THREEScene();
View Compiled

External CSS

  1. https://unpkg.com/splitting/dist/splitting.css
  2. https://unpkg.com/splitting/dist/splitting-cells.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/three.js/r127/three.min.js
  2. https://unpkg.co/gsap@3/dist/gsap.min.js