JSFiddle - React, Tailwind, and code Playground

HTML

<canvas id="webgl"></canvas>
<script type="importmap">
      {
        "imports":
        {
          "three": "https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js",
          "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/"
        }
      }
    </script>
    <script>
      var brushFile = "https://i.imgur.com/ycQeaAb.png";
      var bgImage = "https://images.unsplash.com/photo-1437482078695-73f5ca6c96e2?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D";
    </script>

JavaScript

import * as THREE from 'three';

// Canvas and sizes
const canvas = document.getElementById('webgl');
const sizes = { width: window.innerWidth, height: window.innerHeight };

// Track mouse position and movement
const mousePos = { x: 0, y: 0 };
const prevMousePos = { x: 0, y: 0 };
let currentWave = 0;
window.addEventListener('mousemove', (e) => {
    mousePos.x = e.clientX - sizes.width / 2;
    mousePos.y = sizes.height / 2 - e.clientY;
});

// Three.js scene setup
const scene = new THREE.Scene();
const scene2 = new THREE.Scene();
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);

// Orthographic camera
const aspect = sizes.width / sizes.height;
const frustumSize = sizes.height;
const camera = new THREE.OrthographicCamera(
    (frustumSize * aspect) / -2, (frustumSize * aspect) / 2,
    frustumSize / 2, frustumSize / -2, -1000, 1000
);
camera.position.set(0, 0, 5);
camera.lookAt(0, 0, 0);

// Load brush texture
const brushTexture = new THREE.TextureLoader().load(brushFile);

// Shader setup
const vertexShader = `
    varying vec2 vUv;
    void main() {
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
`;
const fragmentShader = `
    uniform sampler2D uImage;
    uniform sampler2D uDisplacement;
    varying vec2 vUv;
    void main() {
        vec2 displacement = texture2D(uDisplacement, vUv).rg * 0.1;
        vec2 uv = vUv + displacement;
        gl_FragColor = texture2D(uImage, uv);
    }
`;

// Wave planes setup
const maxCount = 200;
const meshes = [];
const planeGeometry = new THREE.PlaneGeometry(100, 100, 1, 1);
for (let i = 0; i < maxCount; i++) {
    const material = new THREE.MeshBasicMaterial({
        map: brushTexture, transparent: true, blending: THREE.AdditiveBlending,
        depthTest: false, depthWrite: false
    });
    const plane =...