.p-summary
  .p-summary__wrap
    p

canvas(id="canvas-webgl", class="p-canvas-webgl")
View Compiled
@import url('https://fonts.googleapis.com/css?family=Homenaje');

.p-canvas-webgl {
  position: fixed;
  z-index: 1;
  top: 0; left: 0;
}

.p-summary {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: 0; left: 0;
  z-index: 2;
  color: #fff;
  font-family: 'Homenaje', sans-serif;
  text-align: center;
  h1 {
    margin: 0 0 0.1em;
    font-size: 18vh;
    font-weight: 400;
  }
  p {
    margin: 0;
    font-size: 3vh;
    text-transform: uppercase;
    letter-spacing: 0.1em;
  }
  a {
    color: #fff;
  }
}
View Compiled
const debounce = (callback, duration) => {
  var timer;
  return function(event) {
    clearTimeout(timer);
    timer = setTimeout(function(){
      callback(event);
    }, duration);
  };
};

const loadTexs = (imgs, callback) => {
  const texLoader = new THREE.TextureLoader();
  const length = Object.keys(imgs).length;
  const loadedTexs = {};
  let count = 0;

  texLoader.crossOrigin = 'anonymous';  
  
  for (var key in imgs) {
    const k = key;
    if (imgs.hasOwnProperty(k)) {
      texLoader.load(imgs[k], (tex) => {
        tex.repeat = THREE.RepeatWrapping;
        loadedTexs[k] = tex;
        count++;
        if (count >= length) callback(loadedTexs);
      });
    }
  }
}

class Fog {
  constructor() {
    this.uniforms = {
      time: {
        type: 'f',
        value: 0
      },
      tex: {
        type: 't',
        value: null
      }
    };
    this.num = 200;
    this.obj = null;
  }
  createObj(tex) {
    // Define Geometries
    const geometry = new THREE.InstancedBufferGeometry();
    const baseGeometry = new THREE.PlaneBufferGeometry(1100, 1100, 20, 20);

    // Copy attributes of the base Geometry to the instancing Geometry
    geometry.addAttribute('position', baseGeometry.attributes.position);
    geometry.addAttribute('normal', baseGeometry.attributes.normal);
    geometry.addAttribute('uv', baseGeometry.attributes.uv);
    geometry.setIndex(baseGeometry.index);

    // Define attributes of the instancing geometry
    const instancePositions = new THREE.InstancedBufferAttribute(new Float32Array(this.num * 3), 3, 1);
    const delays = new THREE.InstancedBufferAttribute(new Float32Array(this.num), 1, 1);
    const rotates = new THREE.InstancedBufferAttribute(new Float32Array(this.num), 1, 1);
    for ( var i = 0, ul = this.num; i < ul; i++ ) {
      instancePositions.setXYZ(
        i,
        (Math.random() * 2 - 1) * 850,
        0,
        (Math.random() * 2 - 1) * 300,
      );
      delays.setXYZ(i, Math.random());
      rotates.setXYZ(i, Math.random() * 2 + 1);
    }
    geometry.addAttribute('instancePosition', instancePositions);
    geometry.addAttribute('delay', delays);
    geometry.addAttribute('rotate', rotates);

    // Define Material
    const material = new THREE.RawShaderMaterial({
      uniforms: this.uniforms,
      vertexShader: `
        attribute vec3 position;
        attribute vec2 uv;
        attribute vec3 instancePosition;
        attribute float delay;
        attribute float rotate;

        uniform mat4 projectionMatrix;
        uniform mat4 modelViewMatrix;
        uniform float time;

        varying vec3 vPosition;
        varying vec2 vUv;
        varying vec3 vColor;
        varying float vBlink;

        const float duration = 200.0;

        mat4 calcRotateMat4Z(float radian) {
          return mat4(
            cos(radian), -sin(radian), 0.0, 0.0,
            sin(radian), cos(radian), 0.0, 0.0,
            0.0, 0.0, 1.0, 0.0,
            0.0, 0.0, 0.0, 1.0
          );
        }
        vec3 convertHsvToRgb(vec3 c) {
          vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
          vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
          return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
        }

        void main(void) {
          float now = mod(time + delay * duration, duration) / duration;

          mat4 rotateMat = calcRotateMat4Z(radians(rotate * 360.0) + time * 0.1);
          vec3 rotatePosition = (rotateMat * vec4(position, 1.0)).xyz;

          vec3 moveRise = vec3(
            (now * 2.0 - 1.0) * (2500.0 - (delay * 2.0 - 1.0) * 2000.0),
            (now * 2.0 - 1.0) * 2000.0,
            sin(radians(time * 50.0 + delay + length(position))) * 30.0
            );
          vec3 updatePosition = instancePosition + moveRise + rotatePosition;

          vec3 hsv = vec3(time * 0.1 + delay * 0.2 + length(instancePosition) * 100.0, 0.5 , 0.8);
          vec3 rgb = convertHsvToRgb(hsv);
          float blink = (sin(radians(now * 360.0 * 20.0)) + 1.0) * 0.88;

          vec4 mvPosition = modelViewMatrix * vec4(updatePosition, 1.0);

          vPosition = position;
          vUv = uv;
          vColor = rgb;
          vBlink = blink;

          gl_Position = projectionMatrix * mvPosition;
        }
      `,
      fragmentShader: `
        precision highp float;

        uniform sampler2D tex;

        varying vec3 vPosition;
        varying vec2 vUv;
        varying vec3 vColor;
        varying float vBlink;

        void main() {
          vec2 p = vUv * 2.0 - 1.0;

          vec4 texColor = texture2D(tex, vUv);
          vec3 color = (texColor.rgb - vBlink * length(p) * 0.8) * vColor;
          float opacity = texColor.a * 0.36;

          gl_FragColor = vec4(color, opacity);
        }
      `,
      transparent: true,
      depthWrite: false,
      blending: THREE.AdditiveBlending,
    });
    this.uniforms.tex.value = tex;

    // Create Object3D
    this.obj = new THREE.Mesh(geometry, material);
  }
  render(time) {
    this.uniforms.time.value += time;
  }
}

const resolution = new THREE.Vector2();
const canvas = document.getElementById('canvas-webgl');
const renderer = new THREE.WebGLRenderer({
  alpha: true,
  antialias: true,
  canvas: canvas,
});
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera();
const clock = new THREE.Clock();

camera.far = 50000;
camera.setFocalLength(24);

const texsSrc = {
  fog: 'https://ykob.github.io/sketch-threejs/img/sketch/fog/fog.png'
};
const fog = new Fog();

const render = () => {
  const time = clock.getDelta();
  fog.render(time);
  renderer.render(scene, camera);
};
const renderLoop = () => {
  render();
  requestAnimationFrame(renderLoop);
};
const resizeCamera = () => {
  camera.aspect = resolution.x / resolution.y;
  camera.updateProjectionMatrix();
};
const resizeWindow = () => {
  resolution.set(window.innerWidth, window.innerHeight);
  canvas.width = resolution.x;
  canvas.height = resolution.y;
  resizeCamera();
  renderer.setSize(resolution.x, resolution.y);
};
const on = () => {
  window.addEventListener('resize', debounce(resizeWindow), 1000);
};

const init = () => {
  loadTexs(texsSrc, (loadedTexs) => {
    fog.createObj(loadedTexs.fog);

    scene.add(fog.obj);

    renderer.setClearColor(0x111111, 1.0);
    camera.position.set(0, 0, 1000);
    camera.lookAt(new THREE.Vector3());
    clock.start();

    on();
    resizeWindow();
    renderLoop();
  });
}
init();
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/three.js/86/three.min.js