← Mike Higgins Home
Custom Code Experiment •

Vanta JS - Clouds

Source Code View HTML / CSS / JavaScript
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vanta JS - Clouds</title>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vanta@0.5.24/dist/vanta.clouds.min.js"></script>

    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        html, body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            background: #000000;
        }

        #vantajs {
            position: fixed;
            inset: 0;
            width: 100%;
            height: 100%;
            background: #1488cc;
            filter: none;
            transition: filter 0.6s ease;
        }
        body.retro #vantajs {
            background: #04120a;
            filter: grayscale(1) sepia(1) hue-rotate(75deg) saturate(6) brightness(0.9) contrast(1.25);
        }

        .crt-overlay-group {
            position: fixed;
            inset: 0;
            pointer-events: none;
            opacity: 0;
            transition: opacity 0.6s ease;
        }
        body.retro .crt-overlay-group {
            opacity: 1;
        }

        .grain {
            position: fixed;
            top: -50%;
            left: -50%;
            width: 200%;
            height: 200%;
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
            opacity: 0.05;
            mix-blend-mode: overlay;
            animation: grainMove 0.5s steps(3) infinite;
        }

        .scanlines {
            position: fixed;
            inset: 0;
            background: repeating-linear-gradient(
                to bottom,
                rgba(0, 0, 0, 0) 0px,
                rgba(0, 0, 0, 0) 1px,
                rgba(0, 0, 0, 0.35) 2px,
                rgba(0, 0, 0, 0.35) 3px
            );
            mix-blend-mode: multiply;
        }

        .vignette {
            position: fixed;
            inset: 0;
            background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0) 50%, rgba(0, 0, 0, 0.7) 100%);
        }

        .beam {
            position: fixed;
            left: 0;
            right: 0;
            top: -3px;
            height: 3px;
            background: linear-gradient(to right, transparent, rgba(140, 255, 170, 0.55), transparent);
            filter: blur(1px);
            mix-blend-mode: screen;
            animation: sweep 9s linear infinite;
        }

        .crt-flicker {
            position: fixed;
            inset: 0;
            animation: flicker 6s infinite;
        }

        @keyframes sweep {
            0%   { top: -3px; }
            100% { top: 100%; }
        }

        @keyframes grainMove {
            0%   { transform: translate(0, 0); }
            33%  { transform: translate(-4%, 5%); }
            66%  { transform: translate(3%, -4%); }
            100% { transform: translate(0, 0); }
        }

        @keyframes flicker {
            0%, 100% { background: rgba(0, 0, 0, 0); }
            92%      { background: rgba(0, 0, 0, 0); }
            93%      { background: rgba(120, 255, 160, 0.05); }
            94%      { background: rgba(0, 0, 0, 0.08); }
            95%      { background: rgba(120, 255, 160, 0.03); }
            96%      { background: rgba(0, 0, 0, 0); }
        }

        /* ---- Enhanced Prominent Button ---- */
        #toggle-btn {
            position: fixed;
            bottom: 28px;
            right: 28px;
            z-index: 20;
            padding: 14px 28px;
            font-family: 'Courier New', monospace;
            font-size: 16px;
            font-weight: bold;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            border-radius: 6px;
            cursor: pointer;
            background: rgba(0, 0, 0, 0.65);
            color: #ffffff;
            border: 2px solid rgba(255, 255, 255, 0.9);
            backdrop-filter: blur(6px);
            box-shadow: 0 0 30px rgba(20, 136, 204, 0.5);
            transition: all 0.25s ease;
        }

        #toggle-btn:hover {
            background: rgba(255, 255, 255, 0.2);
            transform: scale(1.05);
            box-shadow: 0 0 50px rgba(20, 136, 204, 0.8);
        }

        /* Retro mode overrides for the button */
        body.retro #toggle-btn {
            background: rgba(0, 10, 0, 0.75);
            color: #8affa0;
            border-color: #8affa0;
            box-shadow: 0 0 30px rgba(138, 255, 160, 0.4);
        }

        body.retro #toggle-btn:hover {
            background: rgba(138, 255, 160, 0.15);
            transform: scale(1.05);
            box-shadow: 0 0 60px rgba(138, 255, 160, 0.7);
        }
    </style>
</head>
<body>
    <div id="vantajs"></div>

    <div class="crt-overlay-group">
        <div class="grain"></div>
        <div class="scanlines"></div>
        <div class="beam"></div>
        <div class="vignette"></div>
        <div class="crt-flicker"></div>
    </div>

    <button id="toggle-btn">Switch to Retroscope</button>

    <script>
        document.addEventListener('DOMContentLoaded', function () {
            if (typeof VANTA === 'undefined' || !VANTA.CLOUDS) {
                console.warn('VANTA.CLOUDS not available — check script loading.');
                return;
            }

            var NORMAL_OPTIONS = {
                skyColor: 0x1488cc,
                cloudColor: 0x6dd5fa,
                cloudShadowColor: 0x183550,
                sunColor: 0xff9919,
                sunGlareColor: 0xff6633,
                sunlightColor: 0xff9933
            };

            var RETRO_OPTIONS = {
                skyColor: 0x020805,
                cloudColor: 0x2fae55,
                cloudShadowColor: 0x000000,
                sunColor: 0x8affa0,
                sunGlareColor: 0xffffff,
                sunlightColor: 0x8affa0
            };

            var effect = VANTA.CLOUDS({
                el: "#vantajs",
                mouseControls: true,
                touchControls: true,
                gyroControls: false,
                minHeight: 200.00,
                minWidth: 200.00,
                speed: 1
            });
            effect.setOptions(NORMAL_OPTIONS);

            var isRetro = false;
            var btn = document.getElementById('toggle-btn');

            btn.addEventListener('click', function () {
                isRetro = !isRetro;
                document.body.classList.toggle('retro', isRetro);
                effect.setOptions(isRetro ? RETRO_OPTIONS : NORMAL_OPTIONS);
                btn.textContent = isRetro ? 'Switch to Normal' : 'Switch to Retroscope';
            });
        });
    </script>
</body>
</html>