<!
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Mouse Trail</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            background-color: black;
            overflow: hidden;
        }
        canvas {
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            pointer-events: none;
            mix-blend-mode: difference;
        }
        h1 {
           color: white;
        }
    </style>
</head>
<body>
  <h1>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nostrum,
corporis.</h1>
    <canvas id="mouseTrail"></canvas>
    <script>
        const PARAMS = {
             POINTS_NUMBER: 30,
             WIDTH_FACTOR: 0.3,
             SPRING: 0.4,
             FRICTION: 0.5,
        };
        const OFFSET = { X: 0, Y: 0 };
        const canvas = document.getElementById("mouseTrail");
        const ctx = canvas.getContext("2d");
        let animationFrame;
        let mouseMoved = false;
        const pointer = { x: window.innerWidth / 2, y: window.innerHeight / 2 };
        const trail = new Array(PARAMS.POINTS_NUMBER).fill(null).map(() => ({
             x: pointer.x,
             y: pointer.y,
             dx: 0,
             dy: 0,
        }));
        function resizeCanvas() {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        }
        function updateMousePosition(clientX, clientY) {
            pointer.x = clientX + OFFSET.X;
            pointer.y = clientY + OFFSET.Y;
        }
        function animate(t) {
            if (!mouseMoved) {
                pointer.x = (0.5 + 0.3 * Math.cos((Math.random() * (0.009-0.002) +
0.002) * t) * Math.sin(0.005 * t)) * window.innerWidth + OFFSET.X;
                pointer.y = (0.5 + 0.2 * Math.cos(0.005 * t) + 0.1 * Math.cos(0.01
* t)) * window.innerHeight + OFFSET.Y;
            }
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            trail.forEach((p, i) => {
                const prev = i === 0 ? pointer : trail[i - 1];
                const spring = i === 0 ? 0.4* PARAMS.SPRING : PARAMS.SPRING;
                p.dx += (prev.x - p.x) * spring;
                p.dy += (prev.y - p.y) * spring;
                p.dx *= PARAMS.FRICTION;
                p.dy *= PARAMS.FRICTION;
                p.x += p.dx;
                p.y += p.dy;
            });
            ctx.lineCap = "round";
            ctx.beginPath();
            ctx.moveTo(trail[0].x, trail[0].y);
            for (let i = 1; i < trail.length - 1; i++) {
                const xc = 0.5 * (trail[i].x + trail[i + 1].x);
                const yc = 0.5 * (trail[i].y + trail[i + 1].y);
                ctx.quadraticCurveTo(trail[i].x, trail[i].y, xc, yc);
                ctx.lineWidth = PARAMS.WIDTH_FACTOR * (PARAMS.POINTS_NUMBER - i);
                ctx.strokeStyle = "#ffffff";
                ctx.stroke();
            }
            ctx.lineTo(trail[trail.length - 1].x, trail[trail.length - 1].y);
            ctx.stroke();
            animationFrame = requestAnimationFrame(animate);
        }
        function handleMouseMove(e) {
            mouseMoved = true;
            updateMousePosition(e.clientX, e.clientY);
        }
        function handleTouchMove(e) {
            mouseMoved = true;
            const touch = e.targetTouches[0];
            updateMousePosition(touch.clientX, touch.clientY);
        }
        window.addEventListener("resize", resizeCanvas);
        window.addEventListener("mousemove", handleMouseMove);
        window.addEventListener("touchmove", handleTouchMove);
        resizeCanvas();
        animationFrame = requestAnimationFrame(animate);
    </script>
</body>
</html>