Live demo, running in your browser

Glass jellyfish

A giant gradient 'FLOW' wordmark on deep navy with a translucent jellyfish sprite that rises behind and in front of the letters, pulsing, swaying and flipping through sprite frames in WebGL, with a CSS-only fallback jellyfish if WebGL fails.

Assets

Code: MIT license. three.js 0.184.0 (MIT) · Imagery generated with Google Gemini

<!doctype html>
<html lang="en"
  ><head
    ><script>
      /* 6to9 pattern harness */ (function () {
        var parentPaused = false,
          hidden = document.hidden,
          p = (window.__pattern = { paused: false, reducedMotion: false, maxDpr: 2 });
        function sync() {
          p.paused = parentPaused || hidden;
        }
        sync();
        try {
          p.reducedMotion = matchMedia("(prefers-reduced-motion: reduce)").matches;
        } catch (e) {}
        document.addEventListener("visibilitychange", function () {
          hidden = document.hidden;
          sync();
        });
        addEventListener("message", function (e) {
          var d = e.data || {};
          if (d.pattern === "pause") {
            parentPaused = true;
            sync();
          }
          if (d.pattern === "play") {
            parentPaused = false;
            sync();
          }
        });
      })();</script
    ><meta charset="utf-8" /><meta
      name="viewport"
      content="width=device-width,initial-scale=1"
    /><title>Driftglass</title
    ><style>
      * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
      }
      html,
      body {
        height: 100%;
        background: #06122b;
        overflow: hidden;
      }
      body {
        font-family:
          system-ui,
          -apple-system,
          "Segoe UI",
          Roboto,
          "Helvetica Neue",
          Arial,
          sans-serif;
        color: #d6f7f3;
      }
      .hero {
        position: relative;
        width: 100vw;
        height: 100vh;
        height: 100dvh;
        background: #06122b;
        overflow: hidden;
      }
      canvas {
        position: absolute;
        inset: 0;
        width: 100%;
        height: 100%;
        pointer-events: none;
        display: block;
      }
      #back {
        z-index: 1;
      }
      .type {
        position: absolute;
        z-index: 2;
        left: 0;
        right: 0;
        top: 50%;
        transform: translateY(-52%);
        text-align: center;
        font-family: "Arial Black", "Helvetica Neue", Impact, system-ui, sans-serif;
        font-weight: 900;
        font-size: min(29vw, 60vh);
        line-height: 0.82;
        letter-spacing: -0.05em;
        color: #bdf3ec;
        background: linear-gradient(180deg, #d4fbf4 0%, #9fe6e2 100%);
        -webkit-background-clip: text;
        background-clip: text;
        -webkit-text-fill-color: transparent;
        user-select: none;
        animation: fadein 2.4s ease both;
      }
      .type span {
        display: inline;
      }
      #front {
        z-index: 3;
      }
      .ui {
        position: absolute;
        z-index: 4;
        left: 0;
        right: 0;
        top: 0;
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 28px 4vw;
        font-size: 14px;
        letter-spacing: 0.14em;
        text-transform: uppercase;
      }
      .ui b {
        font-weight: 800;
        letter-spacing: 0.22em;
      }
      .ui i {
        font-style: normal;
        opacity: 0.7;
      }
      .copy {
        position: absolute;
        z-index: 4;
        left: 4vw;
        bottom: 6vh;
        max-width: 330px;
      }
      .copy p {
        font-size: 17px;
        line-height: 1.45;
        color: #b6e9e6;
        margin-bottom: 20px;
      }
      .copy a {
        display: inline-block;
        padding: 14px 26px;
        border-radius: 40px;
        background: #bdf3ec;
        color: #06122b;
        font-weight: 800;
        font-size: 15px;
        text-decoration: none;
        letter-spacing: 0.02em;
      }
      .fb {
        display: none;
        position: absolute;
        z-index: 2;
        left: 50%;
        top: 50%;
        width: min(34vw, 300px);
        height: min(44vw, 380px);
        transform: translate(-50%, -50%);
      }
      body.nogl .fb {
        display: block;
        animation: bob 6s ease-in-out infinite;
      }
      body.nogl canvas {
        display: none;
      }
      .fb:before {
        content: "";
        position: absolute;
        left: 0;
        right: 0;
        top: 0;
        height: 55%;
        border-radius: 50% 50% 40% 40%;
        background: radial-gradient(
          ellipse at 40% 30%,
          rgba(255, 255, 255, 0.55),
          rgba(150, 230, 240, 0.25) 45%,
          rgba(255, 150, 190, 0.25) 80%
        );
        box-shadow:
          0 0 60px rgba(255, 170, 140, 0.35),
          inset 0 0 40px rgba(255, 255, 255, 0.25);
        animation: pulse 3.4s ease-in-out infinite;
      }
      .fb:after {
        content: "";
        position: absolute;
        left: 18%;
        right: 18%;
        top: 50%;
        bottom: 0;
        background: repeating-linear-gradient(
          90deg,
          rgba(255, 150, 190, 0.6) 0 3px,
          transparent 3px 14px,
          rgba(255, 190, 100, 0.55) 14px 16px,
          transparent 16px 26px
        );
        filter: blur(1px);
        mask-image: linear-gradient(#000, transparent);
        -webkit-mask-image: linear-gradient(#000, transparent);
      }
      @keyframes pulse {
        50% {
          transform: scale(1.1, 0.94);
        }
      }
      @keyframes bob {
        50% {
          transform: translate(-50%, -56%);
        }
      }
      @keyframes fadein {
        from {
          opacity: 0;
        }
        to {
          opacity: 1;
        }
      }
      @media (max-width: 700px) {
        .type {
          font-size: 50vw;
          top: 41%;
          line-height: 0.8;
        }
        .type span {
          display: block;
        }
        .ui {
          padding: 20px 6vw;
          font-size: 12px;
        }
        .ui i {
          display: none;
        }
        .copy {
          left: 6vw;
          right: 6vw;
          bottom: 5vh;
          max-width: none;
        }
        .copy p {
          font-size: 15px;
          margin-bottom: 16px;
        }
      }</style
    ><script type="importmap">
      { "imports": { "three": "https://cdn.jsdelivr.net/npm/three@0.184.0/build/three.module.js" } }
    </script></head
  ><body
    ><main class="hero"
      ><canvas id="back"></canvas
      ><h1 class="type" aria-label="Flow"><span>FL</span><span>OW</span></h1
      ><canvas id="front"></canvas><div class="fb"></div
      ><header class="ui"><b>Driftglass</b><i>Calm software, blown thin</i></header
      ><div class="copy"
        ><p>Interfaces that pulse, rise and settle, as gentle as glass in deep water.</p
        ><a href="#">Start flowing</a></div
      ></main
    ><script>
      window.__pattern = window.__pattern || { paused: false, reducedMotion: false, maxDpr: 2 };
      function fallback() {
        document.body.classList.add("nogl");
      }
      try {
        var c = document.createElement("canvas");
        if (!(c.getContext("webgl2") || c.getContext("webgl"))) fallback();
      } catch (e) {
        fallback();
      }</script
    ><script type="module">
      if (!document.body.classList.contains("nogl")) {
        import("three")
          .then(function (THREE) {
            var hero = document.querySelector(".hero");
            var VS = `uniform float uPulse;uniform float uT;varying vec2 vUv;void main(){vUv=uv;vec3 p=position;float bell=smoothstep(0.3,0.85,uv.y);float tail=1.0-bell;p.x*=1.0+0.09*uPulse*bell;p.y*=1.0-0.04*uPulse;p.x+=sin(uv.y*10.0-uT*1.8+uPulse)*0.035*pow(1.0-uv.y,1.5)*tail;gl_Position=projectionMatrix*modelViewMatrix*vec4(p,1.0);}`;
            var FS = `uniform sampler2D uMap;uniform float uFrame;uniform float uMode;uniform float uCut;varying vec2 vUv;vec4 pm(float i){vec2 uv=vec2((i+clamp(vUv.x,0.003,0.997))/8.0,vUv.y);vec4 s=texture2D(uMap,uv);return vec4(s.rgb*s.a,s.a);}void main(){float f0=floor(uFrame);float mf=smoothstep(0.35,1.0,fract(uFrame));vec4 a=mix(pm(mod(f0,8.0)),pm(mod(f0+1.0,8.0)),mf);float m=smoothstep(uCut-0.06,uCut+0.06,vUv.y);float k=uMode>0.5?m:1.0-m;a*=k;if(a.a<0.002)discard;gl_FragColor=vec4(a.rgb/max(a.a,0.001),a.a);}`;
            var tex = null;
            var layers = [];
            function mk(id, mode) {
              var canvas = document.getElementById(id);
              var r = new THREE.WebGLRenderer({ canvas: canvas, alpha: true, antialias: true });
              r.setClearColor(0x000000, 0);
              var scene = new THREE.Scene();
              var cam = new THREE.OrthographicCamera(-1, 1, 1, -1, -1000, 1000);
              cam.position.z = 10;
              var mat = new THREE.ShaderMaterial({
                vertexShader: VS,
                fragmentShader: FS,
                transparent: true,
                depthTest: false,
                depthWrite: false,
                uniforms: {
                  uMap: { value: null },
                  uFrame: { value: 0 },
                  uMode: { value: mode },
                  uCut: { value: 0.45 },
                  uPulse: { value: 0 },
                  uT: { value: 0 },
                },
              });
              var mesh = new THREE.Mesh(new THREE.PlaneGeometry(1, 1, 20, 28), mat);
              scene.add(mesh);
              var L = { r: r, scene: scene, cam: cam, mat: mat, mesh: mesh };
              layers.push(L);
              return L;
            }
            var lb = mk("back", 0),
              lf = mk("front", 1);
            var W = 1,
              H = 1;
            function resize() {
              var P = window.__pattern || {};
              var dpr = Math.min(window.devicePixelRatio || 1, P.maxDpr || 2);
              W = hero.clientWidth || innerWidth;
              H = hero.clientHeight || innerHeight;
              layers.forEach(function (L) {
                L.r.setPixelRatio(dpr);
                L.r.setSize(W, H, false);
                L.cam.left = -W / 2;
                L.cam.right = W / 2;
                L.cam.top = H / 2;
                L.cam.bottom = -H / 2;
                L.cam.updateProjectionMatrix();
              });
              draw(t);
            }
            var t = 0,
              ready = false;
            var PERIOD = 20,
              PULSE = 3.4;
            function draw(time) {
              if (!ready) return;
              var mob = W < 700;
              var ph = H * (mob ? 0.46 : 0.66);
              var pw = (ph * 266) / 338;
              if (pw > W * 0.8) {
                pw = W * 0.8;
                ph = (pw * 338) / 266;
              }
              var p = (time / PERIOD) % 1;
              var pe = p + 0.127 * Math.sin(Math.PI * 2 * p);
              var phase = (time * Math.PI * 2) / PULSE;
              var pulse = Math.sin(phase);
              var y = H * (-0.85 + 1.7 * pe) + Math.sin(phase) * H * 0.015;
              var x = Math.sin(time * 0.35) * W * 0.06;
              layers.forEach(function (L) {
                L.mesh.scale.set(pw, ph, 1);
                L.mesh.position.set(x, y, 0);
                L.mesh.rotation.z = Math.sin(time * 0.4) * 0.05;
                L.mat.uniforms.uFrame.value = time * 8;
                L.mat.uniforms.uPulse.value = pulse;
                L.mat.uniforms.uT.value = time;
                L.r.render(L.scene, L.cam);
              });
            }
            var loader = new THREE.TextureLoader();
            loader.setCrossOrigin("anonymous");
            loader.load(
              "https://agents-dev.6to9.ai/visuals/ed07adc0cf76470675e743f802b77ed2.png",
              function (tx) {
                tx.colorSpace = THREE.NoColorSpace;
                tx.minFilter = THREE.LinearFilter;
                tx.generateMipmaps = false;
                tex = tx;
                layers.forEach(function (L) {
                  L.mat.uniforms.uMap.value = tx;
                });
                ready = true;
                var P = window.__pattern || {};
                if (P.reducedMotion) t = 10;
                resize();
              },
              undefined,
              function () {
                fallback();
              },
            );
            window.addEventListener("resize", resize);
            resize();
            var last = performance.now();
            function loop(now) {
              requestAnimationFrame(loop);
              var P = window.__pattern || {};
              var dt = Math.min((now - last) / 1000, 0.1);
              last = now;
              if (P.paused) return;
              if (P.reducedMotion) {
                t = 10;
              } else {
                t += dt;
              }
              draw(t);
            }
            requestAnimationFrame(loop);
          })
          .catch(function () {
            document.body.classList.add("nogl");
          });
      }
    </script></body
  ></html
>

Made by 6to9. Back to all motion patterns.