A deep dive into building Digital Rain — a cinematic AI landing page template with falling math symbols, liquid glass UI, and GSAP scroll animations using Next.js 15 and Tailwind CSS.
Most AI landing pages look the same.
Hero section. Features grid. Pricing table. Footer.
I wanted to build something different — something that makes visitors stop scrolling and say "wow, what is this?"
The result is Digital Rain — a cinematic AI landing page with falling mathematical symbols, liquid glass UI, and GSAP-powered scroll animations.
Here's exactly how I built it.
The concept came from the Matrix — that iconic falling green code effect. But instead of random characters, I wanted mathematical symbols falling and reacting to a simulated liquid surface.
The goal was simple: make your AI product feel like a funded startup from day one.
Live demo: https://og-ai-next.vercel.app/
The heart of the template is the custom rain animation engine. Here's how it works:
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
Instead of random characters, I used mathematical symbols for a more premium feel:
const symbols = [
'∑', 'π', '∆', '∫', '√', 'Ω', 'λ', 'φ',
'∞', 'θ', 'α', 'β', 'γ', 'δ', 'ε', 'ζ',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
];
js
const fontSize = 14;
const columns = Math.floor(canvas.width / fontSize);
const drops: number[] = new Array(columns).fill(1);
function drawRain() {
// Fade effect — creates trail
ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw symbols
ctx.fillStyle = '#14b575'; // brand green
ctx.font = `${fontSize}px monospace`;
drops.forEach((drop, i) => {
const symbol = symbols[Math.floor(Math.random() * symbols.length)];
const x = i * fontSize;
const y = drop * fontSize;
ctx.fillStyle = `rgba(20, 181, 117, ${Math.random() * 0.8 + 0.2})`;
ctx.fillText(symbol, x, y);
// Reset drop randomly
if (y > canvas.height && Math.random() > 0.975) {
drops[i] = 0;
}
drops[i]++;
});
}
// Animate at 30fps
setInterval(drawRain, 33);
This is the part that makes it feel interactive. When the mouse moves, nearby symbols react:
let mouseX = 0;
let mouseY = 0;
window.addEventListener('mousemove', (e) => {
mouseX = e.clientX;
mouseY = e.clientY;
});
// In drawRain function — add proximity effect
drops.forEach((drop, i) => {
const x = i * fontSize;
const y = drop * fontSize;
const distance = Math.sqrt(
Math.pow(x - mouseX, 2) + Math.pow(y - mouseY, 2)
);
// Symbols near cursor glow brighter
const opacity = distance < 100
? 1.0
: Math.random() * 0.8 + 0.2;
ctx.fillStyle = `rgba(20, 181, 117, ${opacity})`;
ctx.fillText(symbol, x, y);
});
Glassmorphism is everywhere but most implementations look cheap. Here's how to make it look premium:
.glass-card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
The key differences from cheap glassmorphism:
GSAP makes scroll animations smooth and performant. Here's the pattern I used for every section:
import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
// Fade up animation on scroll
gsap.fromTo('.feature-card',
{
opacity: 0,
y: 60
},
{
opacity: 1,
y: 0,
duration: 0.8,
stagger: 0.15,
ease: 'power3.out',
scrollTrigger: {
trigger: '.features-section',
start: 'top 80%',
end: 'bottom 20%',
}
}
);
The stagger: 0.15
is what makes multiple cards animate in sequence rather than all at once. This small detail makes the whole thing feel much more polished.
export function Hero() {
return (
<section className="relative min-h-screen flex items-center">
{/* Canvas background */}
<canvas
ref={canvasRef}
className="absolute inset-0 w-full h-full opacity-40"
/>
{/* Gradient overlay */}
<div className="absolute inset-0 bg-gradient-to-b
from-transparent via-black/20 to-black/80"
/>
{/* Content */}
<div className="relative z-10 max-w-6xl mx-auto px-6">
<div className="glass-card p-8 rounded-2xl max-w-2xl">
<h1 className="text-5xl font-bold text-white mb-4">
Build Smarter Workflows with AI
</h1>
<p className="text-slate-300 text-lg mb-8">
OG-AI helps teams automate repetitive tasks
</p>
<button className="bg-brand-500 text-black
px-8 py-4 rounded-xl font-semibold">
Get Started
</button>
</div>
</div>
</section>
);
}
The best decision I made was putting all customization in a single config file:
// src/config.ts
export const config = {
brand: {
name: "Your AI Product",
tagline: "Build Smarter Workflows with AI",
color: "#14b575",
},
hero: {
title: "Build Smarter Workflows with AI",
subtitle: "Automate tasks, generate content, unlock insights",
cta: "Get Started Free",
},
nav: {
links: ["Features", "How It Works", "Pricing", "Testimonials", "FAQ"],
},
pricing: {
monthly: [
{ name: "Starter", price: 9, features: ["100 generations", "API access"] },
{ name: "Pro", price: 29, features: ["Unlimited", "Priority support"] },
]
}
}
No digging through components. Just update this file and everything changes.
The demo speaks for itself: https://og-ai-next.vercel.app/
If you're building an AI product and want your landing page to feel like a funded startup from day one — I turned this into a template you can grab and customize in hours.
Get the template: https://pixelanas.gumroad.com/l/digital-rain
Building this taught me that the difference between a good landing page and a cinematic one is:
If you have questions about any part of the implementation, drop them in the comments. Happy to go deeper on any section.
🔗 Demo → https://og-ai-next.vercel.app/
🛒 Get it → https://pixelanas.gumroad.com/l/digitalrain
Built by Anas — full-stack developer specializing in Next.js, animations, and premium UI. Find me on X: @pixelanas