AquaStudios Intro

by Sharxxy

HTML

<div class="intro-root" id="intro">
    <div class="vignette"></div>
    <div class="rays"></div>
    <div class="ripple" id="ripple"></div>
    <canvas id="bubbles"></canvas>

    <div class="logo-wrap">
      <!-- Wave sweep in front of the logo -->
      <div class="wave-mask">
        <div class="wave" id="wave">
          <svg viewBox="0 0 1440 320" preserveAspectRatio="none" aria-hidden>
            <defs>
              <linearGradient id="waveGrad" x1="0" x2="1" y1="0" y2="0">
                <stop offset="0%" stop-color="#53d3f3" stop-opacity="0.0"/>
                <stop offset="30%" stop-color="#53d3f3" stop-opacity="0.6"/>
                <stop offset="70%" stop-color="#47b0f0" stop-opacity="0.8"/>
                <stop offset="100%" stop-color="#0ea5e9" stop-opacity="0.0"/>
              </linearGradient>
            </defs>
            <path d="M0,192L60,197.3C120,203,240,213,360,213.3C480,213,600,203,720,176C840,149,960,107,1080,117.3C1200,128,1320,192,1380,224L1440,256L1440,0L1380,0C1320,0,1200,0,1080,0C960,0,840,0,720,0C600,0,480,0,360,0C240,0,120,0,60,0L0,0Z" fill="url(#waveGrad)"/>
          </svg>
        </div>
      </div>

      <!-- AQUASTUDIOS LOGO (stroke draw + fill) -->
      <div class="logo" aria-label="AquaStudios">
        <svg viewBox="0 0 1200 280" role="img">
          <defs>
            <linearGradient id="aquaGrad" x1="0" x2="1">
              <stop offset="0%" stop-color="#a0f0ff"/>
              <stop offset="50%" stop-color="#53d3f3"/>
              <stop offset="100%" stop-color="#47b0f0"/>
            </linearGradient>
            <filter id="gel">
              <feGaussianBlur in="SourceGraphic" stdDeviation="1.2" result="b"/>
              <feMerge>
                <feMergeNode in="b"/><feMergeNode in="SourceGraphic"/>
              </feMerge>
            </filter>
          </defs>
          <!-- Stylised rounded logotype drawn with paths (quick custom type) -->
          <g...

CSS

/* -----------------------------
       AQUASTUDIOS INTRO - STYLES
       (Single-file demo; you can split into styles.css later)
    ------------------------------ */
    :root{
      --bg-deep:#03121c;
      --bg-deeper:#010b11;
      --aqua:#53d3f3;
      --cyan:#47b0f0;
      --white:#e9f7ff;
    }
    *{box-sizing:border-box}
    html,body{height:100%;}
    body{
      margin:0; background:radial-gradient(1200px 800px at 50% 20%, #072639 0%, var(--bg-deep) 35%, var(--bg-deeper) 100%);
      color:var(--white); font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji";
      overflow:hidden;
    }

    /* Container */
    .intro-root{
      position:fixed; inset:0; display:grid; place-items:center; isolation:isolate;
    }

    /* Subtle vignette */
    .vignette{position:absolute; inset:-10%; pointer-events:none; z-index:1;
      background:radial-gradient(80% 60% at 50% 40%, transparent 0% 60%, rgba(0,0,0,.4) 100%);
    }

    /* God rays */
    .rays{position:absolute; inset:0; overflow:hidden; z-index:2; mix-blend-mode:screen; opacity:.25;}
    .rays::before{content:""; position:absolute; inset:-50% -20% -20% -20%;
      background: conic-gradient(from 200deg, rgba(83,211,243,.18), rgba(83,211,243,0) 20% 60%, rgba(83,211,243,.18));
      filter: blur(12px);
      transform: rotate(-12deg) translateY(-8%);
      animation: sway 10s ease-in-out infinite alternate;
    }
    @keyframes sway{to{transform: rotate(8deg) translateY(6%);}}

    /* Water surface ripple opening */
    .ripple{
      position:absolute; inset:0; z-index:3; pointer-events:none; opacity:0;
      background: radial-gradient(ellipse at 50% 30%, rgba(83,211,243,.35) 0 2%, rgba(83,211,243,.15) 3%, rgba(83,211,243,0) 25%);
      transform: scale(0.6);
      transition: opacity 1200ms ease, transform 1800ms ease;
    }
    .ripple.active{opacity:1; transform: scale(1.4);}  

...

JavaScript

/* -----------------------------
       AQUASTUDIOS INTRO - SCRIPT
       (Single-file demo; you can split into app.js later)
    ------------------------------ */
    const intro = document.getElementById('intro');
    const canvas = document.getElementById('bubbles');
    const ctx = canvas.getContext('2d');
    const wave = document.getElementById('wave');
    const ripple = document.getElementById('ripple');
    const flash = document.getElementById('flash');
    const fadeout = document.getElementById('fadeout');
    const skipBtn = document.getElementById('skipBtn');

    // Resize canvas to full viewport
    function fit(){
      const dpr = Math.min(window.devicePixelRatio || 1, 2);
      const {innerWidth:w, innerHeight:h} = window;
      canvas.width = Math.floor(w * dpr);
      canvas.height = Math.floor(h * dpr);
      canvas.style.width = w + 'px';
      canvas.style.height = h + 'px';
      ctx.setTransform(dpr,0,0,dpr,0,0);
    }
    window.addEventListener('resize', fit); fit();

    // Bubble particles
    const bubbles = [];
    const MAX = 140;
    function spawn(){
      if (bubbles.length > MAX) return;
      const x = Math.random()*window.innerWidth;
      const r = Math.random()*3+1.2;
      const y = window.innerHeight + r + Math.random()*100;
      const s = Math.random()*0.6 + 0.3; // speed
      const drift = (Math.random() - 0.5) * 0.6;
      bubbles.push({x,y,r,s,drift,alpha: Math.random()*0.35+0.25});
    }

    // Caustic shimmer
    let t = 0;
    function draw(){
      t += 0.016;
      ctx.clearRect(0,0,canvas.width,canvas.height);
      // subtle caustics
      const g = ctx.createLinearGradient(0,0,0,canvas.height);
      g.addColorStop(0, 'rgba(83,211,243,0.08)');
      g.addColorStop(1, 'rgba(83,211,243,0.0)');
      ctx.fillStyle = g;
      const bars = 10;
      for(let i=0;i<bars;i++){
        const y = (i/bars)*canvas.height + Math.sin(t*0.6 + i)*8;
       ...