Загрузка...

Анимированный hero-раздел для e-commerce: эффектный WebGL reveal, анимация текста, CTA. Создан с Tailwind CSS и JS.
<section
class="relative min-h-screen flex flex-col bg-[#F2EFEA] text-[#2C2824] antialiased selection:bg-[#2C2824] selection:text-[#F2EFEA] overflow-hidden"
style="font-family: 'Inter', sans-serif;">
<!-- Scripts & Styles -->
<script src="https://code.iconify.design/iconify-icon/1.0.7/iconify-icon.min.js"></script>
<script src="https://hoirqrkdgbmvpwutwuwj.supabase.co/storage/v1/object/public/exports/ascii-dither-background(3).js">
</script>
<link
href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600&family=Geist:wght@300;400;500&display=swap"
rel="stylesheet">
<style>
@keyframes slideDownLetter {
0% {
transform: translateY(-120%);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
.animate-letter {
display: inline-block;
transform: translateY(-120%);
opacity: 0;
animation: slideDownLetter 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.clip-text-container {
display: inline-flex;
overflow: hidden;
vertical-align: bottom;
}
@keyframes beam {
0% {
background-position: 0% 50%;
}
100% {
background-position: 200% 50%;
}
}
.btn-beam::before {
content: '';
position: absolute;
inset: -1px;
border-radius: inherit;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent);
background-size: 200% 100%;
animation: beam 2s linear infinite;
opacity: 0;
transition: opacity 0.3s ease;
z-index: -1;
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
padding: 1px;
}
.btn-beam:hover::before {
opacity: 1;
}
@keyframes sonar {
0% {
transform: scale(1);
opacity: 0.8;
}
100% {
transform: scale(2.5);
opacity: 0;
}
}
.sonar-ring {
position: absolute;
inset: 0;
border-radius: 50%;
border: 1px solid #C48C56;
animation: sonar 2s cubic-bezier(0, 0, 0.2, 1) infinite;
pointer-events: none;
}
</style>
<!-- Visual Overlays -->
<div data-ascii-dither-bg="" class="absolute inset-0 z-0 pointer-events-none opacity-40"></div>
<div class="fixed inset-0 pointer-events-none z-50 flex justify-center w-full mix-blend-multiply opacity-[0.04]">
<div class="w-full max-w-[88rem] h-full flex justify-between px-6 lg:px-12">
<div class="w-px h-full bg-current"></div>
<div class="w-px h-full bg-current hidden md:block"></div>
<div class="w-px h-full bg-current hidden lg:block"></div>
<div class="w-px h-full bg-current"></div>
</div>
</div>
<!-- Navigation -->
<nav class="relative z-40 py-8">
<div class="max-w-[88rem] mx-auto px-6 lg:px-12 flex items-center justify-between">
<a href="#" class="flex items-center gap-2 group">
<iconify-icon icon="solar:armchair-linear"
class="text-3xl transition-transform group-hover:scale-110"></iconify-icon>
<span class="text-xl tracking-tighter uppercase font-jakarta font-light" style="font-family: 'Plus Jakarta Sans';">Aura</span>
</a>
<div class="hidden md:flex items-center gap-10 text-sm font-medium tracking-tight opacity-70"
style="font-family: 'Geist';">
<a href="#" class="hover:opacity-100 transition-opacity">Collections</a>
<a href="#" class="hover:opacity-100 transition-opacity">Design Process</a>
<a href="#" class="hover:opacity-100 transition-opacity">Materials</a>
</div>
<div class="flex items-center gap-5">
<button class="opacity-70 hover:opacity-100"><iconify-icon icon="solar:magnifer-linear" class="text-2xl"></iconify-icon></button>
<button class="opacity-70 hover:opacity-100 relative">
<iconify-icon icon="solar:bag-linear" class="text-2xl"></iconify-icon>
<span class="absolute -top-1 -right-1 w-2 h-2 bg-[#C48C56] rounded-full"></span>
</button>
</div>
</div>
</nav>
<!-- Hero Content -->
<div class="relative z-10 flex-grow flex flex-col pt-12">
<div
class="max-w-[88rem] mx-auto px-6 lg:px-12 w-full flex-grow flex flex-col items-center justify-center text-center">
<h1
class="text-6xl md:text-8xl lg:text-[9rem] font-medium tracking-tighter leading-none mb-12 flex justify-center flex-wrap gap-x-4 md:gap-x-8"
style="font-family: 'Plus Jakarta Sans';">
<span class="flex">
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.1s;">E</span></span>
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.15s;">n</span></span>
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.2s;">g</span></span>
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.25s;">i</span></span>
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.3s;">n</span></span>
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.35s;">e</span></span>
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.4s;">e</span></span>
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.45s;">r</span></span>
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.5s;">e</span></span>
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.55s;">d</span></span>
</span>
<span class="flex text-black/20">
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.6s;">f</span></span>
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.65s;">o</span></span>
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.7s;">r</span></span>
</span>
<span class="flex">
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.75s;">R</span></span>
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.8s;">e</span></span>
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.85s;">s</span></span>
<span class="clip-text-container"><span class="animate-letter" style="animation-delay: 0.9s;">t</span></span>
</span>
</h1>
<!-- Hero Image with WebGL Reveal -->
<div class="absolute inset-0 z-[-1] flex items-center justify-center opacity-80 mt-10 pointer-events-none">
<img id="hero-gl-image" src="https://hoirqrkdgbmvpwutwuwj.supabase.co/storage/v1/object/public/assets/assets/687d701a-8748-4856-8c62-5627d113ee3e_1600w.webp" alt="Sculptural Chair" class="w-full max-w-4xl object-contain h-[65vh] mix-blend-multiply" style="mask-image: linear-gradient(black 80%, transparent 100%);">
</div>
<!-- Supporting Info -->
<div
class="w-full flex flex-col md:flex-row justify-between items-start md:items-end mt-auto pb-12 gap-8 text-left">
<div class="max-w-xs flex items-start gap-3">
<div class="relative mt-1 text-[#C48C56]">
<iconify-icon icon="solar:star-fall-minimalistic-bold-duotone" class="text-xl"></iconify-icon>
<div class="sonar-ring"></div>
</div>
<p class="text-lg opacity-80 font-normal leading-tight" style="font-family: 'Geist';">
Precision-engineered for those who demand architectural integrity.
</p>
</div>
<div class="max-w-sm flex flex-col items-start md:items-end text-left md:text-right gap-6">
<p class="text-lg opacity-80 font-normal leading-tight" style="font-family: 'Geist';">
Meticulously sculpted utilizing sustainable hardwoods and responsive composites.
</p>
<a href="#"
class="btn-beam relative inline-flex items-center gap-2 bg-[#2C2824] text-[#F2EFEA] px-8 py-4 rounded-full text-sm font-medium transition-transform hover:scale-105 active:scale-95"
style="font-family: 'Geist';">
<span>Configure Yours</span>
<iconify-icon icon="solar:arrow-right-up-linear" class="text-lg"></iconify-icon>
</a>
</div>
</div>
</div>
<!-- Footer Stats Bar -->
<div class="w-full border-t border-black/10 py-8">
<div
class="max-w-[88rem] mx-auto px-6 lg:px-12 grid grid-cols-1 md:grid-cols-3 gap-8 text-xs tracking-widest font-medium opacity-40 uppercase"
style="font-family: 'Geist';">
<div class="flex items-center gap-3"><span>01</span> KINETIC SUPPORT SYSTEM</div>
<div class="flex items-center gap-3 md:justify-center"><span>02</span> BESPOKE TEXTILE GRADIENTS</div>
<div class="flex items-center gap-3 md:justify-end"><span>03</span> ARCHITECTURAL CHASSIS</div>
</div>
</div>
</div>
<script>
(function() {
const canvas = document.createElement('canvas');
const img = document.getElementById('hero-gl-image');
const vs = `attribute vec2 p;varying vec2 u;void main(){u=p*0.5+0.5;gl_Position=vec4(p,0,1);}`;
const fs = `precision highp float;varying vec2 u;uniform sampler2D t;uniform float pr;void main(){float s=0.15;float d=floor(u.x*4.0)*s;float lp=clamp((pr*(1.0+3.0*s)-d),0.0,1.0);float e=1.0-pow(1.0-lp,3.0);if(u.y<1.0-e)discard;gl_FragColor=texture2D(t,u);}`;
img.onload = () => {
canvas.width = img.naturalWidth; canvas.height = img.naturalHeight;
canvas.className = img.className; canvas.style.cssText = img.style.cssText;
img.parentNode.insertBefore(canvas, img); img.style.display='none';
const gl = canvas.getContext('webgl');
const prog = gl.createProgram();
const sh = (t, s) => { const r=gl.createShader(t); gl.shaderSource(r,s); gl.compileShader(r); return r; };
gl.attachShader(prog, sh(gl.VERTEX_SHADER, vs)); gl.attachShader(prog, sh(gl.FRAGMENT_SHADER, fs));
gl.linkProgram(prog); gl.useProgram(prog);
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]), gl.STATIC_DRAW);
const pL = gl.getAttribLocation(prog, "p"); gl.enableVertexAttribArray(pL);
gl.vertexAttribPointer(pL, 2, gl.FLOAT, false, 0, 0);
const tex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, tex);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,img);
gl.texParameteri(gl.TEXTURE_2D,3317,33071);gl.texParameteri(gl.TEXTURE_2D,3317,33071);
gl.texParameteri(gl.TEXTURE_2D,10241,9729);gl.texParameteri(gl.TEXTURE_2D,10240,9729);
let start = null;
const draw = (t) => {
if(!start) start = t; let p = (t-start)/1200;
gl.clear(gl.COLOR_BUFFER_BIT); gl.uniform1f(gl.getUniformLocation(prog, "pr"), Math.min(p, 1));
gl.drawArrays(gl.TRIANGLES, 0, 6); if(p<1) requestAnimationFrame(draw);
};
requestAnimationFrame(draw);
};
if(img.complete) img.onload();
})();
</script>
</section>