library / particles & systems / envato-quantum-mesh
live - 60fps 1920 x 1080
envato-quantum-mesh.html - self-contained
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Quantum Node Mesh</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background-color: #0b0f19;
            font-family: sans-serif;
        }

        canvas {
            display: block;
            width: 100vw;
            height: 100vh;
        }
    </style>
</head>

<body>
    <canvas id="quantumCanvas"></canvas>

    <script>
        const canvas = document.getElementById('quantumCanvas');
        const ctx = canvas.getContext('2d', { alpha: false });

        let width, height;
        let particles = [];

        // Configuration
        const config = {
            particleCount: 150,
            baseColor: '#00e5ff',
            accentColor: '#bd00ff',
            connectionDistance: 130,
            mouseRadius: 180,
            speed: 1.0
        };

        let mouse = { x: -1000, y: -1000 };

        function resize() {
            width = canvas.width = window.innerWidth;
            height = canvas.height = window.innerHeight;
        }

        class Particle {
            constructor() {
                this.x = Math.random() * width;
                this.y = Math.random() * height;
                this.vx = (Math.random() - 0.5) * 1.5 * config.speed;
                this.vy = (Math.random() - 0.5) * 1.5 * config.speed;
                this.radius = Math.random() * 2 + 1;
                this.isAccent = Math.random() > 0.8;
            }

            update() {
                this.x += this.vx;
                this.y += this.vy;

                // Bounce off edges
                if (this.x < 0 || this.x > width) this.vx *= -1;
                if (this.y < 0 || this.y > height) this.vy *= -1;

                // Mouse interaction (elastic repulsion)
                const dx = mouse.x - this.x;
                const dy = mouse.y - this.y;
                const dist = Math.sqrt(dx * dx + dy * dy);

                if (dist < config.mouseRadius) {
                    const force = (config.mouseRadius - dist) / config.mouseRadius;
                    this.x -= dx * force * 0.05;
                    this.y -= dy * force * 0.05;
                }
            }

            draw() {
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
                ctx.fillStyle = this.isAccent ? config.accentColor : config.baseColor;
                ctx.fill();
            }
        }

        function init() {
            resize();
            particles = [];
            let count = window.innerWidth < 768 ? config.particleCount / 2 : config.particleCount;
            for (let i = 0; i < count; i++) {
                particles.push(new Particle());
            }
        }

        function animate() {
            ctx.fillStyle = '#0b0f19';
            ctx.fillRect(0, 0, width, height);

            ctx.lineWidth = 1;

            for (let i = 0; i < particles.length; i++) {
                particles[i].update();
                particles[i].draw();

                for (let j = i + 1; j < particles.length; j++) {
                    const dx = particles[i].x - particles[j].x;
                    const dy = particles[i].y - particles[j].y;
                    const dist = Math.sqrt(dx * dx + dy * dy);

                    if (dist < config.connectionDistance) {
                        ctx.beginPath();
                        ctx.strokeStyle = particles[i].isAccent
                            ? `${config.accentColor}${Math.floor((1 - dist / config.connectionDistance) * 255).toString(16).padStart(2, '0')}`
                            : `${config.baseColor}${Math.floor((1 - dist / config.connectionDistance) * 255).toString(16).padStart(2, '0')}`;
                        ctx.moveTo(particles[i].x, particles[i].y);
                        ctx.lineTo(particles[j].x, particles[j].y);
                        ctx.stroke();
                    }
                }
            }
            requestAnimationFrame(animate);
        }

        window.addEventListener('resize', () => {
            resize();
            if (particles.length === 0) init();
        });

        window.addEventListener('mousemove', (e) => {
            mouse.x = e.clientX;
            mouse.y = e.clientY;
        });

        window.addEventListener('mouseout', () => {
            mouse.x = -1000;
            mouse.y = -1000;
        });

        window.addEventListener('touchmove', (e) => {
            mouse.x = e.touches[0].clientX;
            mouse.y = e.touches[0].clientY;
        });

        init();
        animate();
    </script>
</body>

</html>

About this animation

A high-performance interactive particle mesh simulating quantum entanglement networks.

Under the hood

Elastic Node Repulsion

This canvas animation tracks the mathematical hypotenuse distance via Math.hypot between 150 independent nodes. When the user's cursor intersects a node's proximity radius, a physics-based elastic repulsion formula recalculates the velocity vectors, driving the node out of the way.

Source Code
Source copied
Partner hosting options for the copied effect:
Vercel Netlify Hostinger