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.