Web Pages Medium
PageService — Growth & Product Studio
A modern growth and product studio portfolio website featuring Three.js halo field background, smooth scroll animations with Lenis, GSAP-powered transitions, and a data-driven service showcase.
Open in Lab
MCP
html css javascript threejs gsap lenis webgl
Targets: JS HTML
Code
:root {
color-scheme: dark;
--bg: #090812;
--panel: rgba(12, 16, 28, 0.85);
--stroke: rgba(255, 255, 255, 0.12);
--text: #f7f6f1;
--muted: rgba(247, 246, 241, 0.65);
--accent: #ffb347;
--accent-2: #5ce1e6;
--accent-3: #ff5e8e;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
font-family: "Urbanist", sans-serif;
background: radial-gradient(circle at 10% 10%, rgba(255, 179, 71, 0.2), transparent 55%),
radial-gradient(circle at 90% 10%, rgba(92, 225, 230, 0.18), transparent 60%),
radial-gradient(circle at 20% 80%, rgba(255, 94, 142, 0.16), transparent 60%), #07070f;
color: var(--text);
overflow-x: hidden;
}
a {
color: inherit;
text-decoration: none;
}
#bg {
position: fixed;
inset: 0;
z-index: 0;
}
.loader {
position: fixed;
inset: 0;
background: #07070f;
display: grid;
place-items: center;
gap: 24px;
z-index: 999;
color: var(--text);
font-family: "Syne", sans-serif;
letter-spacing: 0.2em;
text-transform: uppercase;
}
.loader-orbit {
width: 90px;
height: 90px;
border-radius: 50%;
border: 2px solid rgba(255, 179, 71, 0.5);
border-top-color: var(--accent-2);
animation: spin 1.2s linear infinite;
}
.loader-core {
position: absolute;
width: 24px;
height: 24px;
border-radius: 50%;
background: var(--accent-3);
box-shadow: 0 0 20px rgba(255, 94, 142, 0.6);
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.topbar {
position: sticky;
top: 0;
z-index: 5;
display: flex;
align-items: center;
justify-content: space-between;
gap: 32px;
padding: 24px clamp(20px, 6vw, 80px);
background: transparent;
backdrop-filter: none;
-webkit-backdrop-filter: none;
border-bottom: none;
transition: all 0.3s ease;
}
.topbar::before {
display: none;
}
.brand {
display: flex;
align-items: center;
gap: 8px;
}
.brand-text {
font-family: "Syne", sans-serif;
font-size: 1.1rem;
font-weight: 600;
color: var(--text);
letter-spacing: 0.05em;
}
.brand-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--text);
display: inline-block;
}
.nav {
display: flex;
align-items: center;
gap: 32px;
flex: 1;
justify-content: center;
}
.nav-item {
color: var(--text);
text-decoration: none;
font-size: 0.95rem;
font-weight: 400;
position: relative;
padding: 8px 16px;
border-radius: 20px;
transition: all 0.3s ease;
}
.nav-item::before {
content: "";
position: absolute;
inset: 0;
background: rgba(255, 255, 255, 0.15);
border-radius: 20px;
opacity: 0;
transition: opacity 0.3s ease;
z-index: -1;
}
.nav-item:hover::before,
.nav-item.active::before {
opacity: 1;
}
.nav-right {
display: flex;
align-items: center;
gap: 24px;
}
.nav-login {
color: var(--text);
text-decoration: none;
font-size: 0.95rem;
font-weight: 400;
transition: opacity 0.3s ease;
}
.nav-login:hover {
opacity: 0.7;
}
.btn-get-started {
display: none;
}
.topbar.is-compact {
transform: translateY(-6px);
box-shadow: 0 18px 40px rgba(0, 0, 0, 0.35);
border-color: rgba(255, 255, 255, 0.2);
}
.burger {
display: none;
width: 44px;
height: 44px;
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.15);
background: rgba(255, 255, 255, 0.08);
cursor: pointer;
position: relative;
}
@media (max-width: 640px) {
.burger {
display: inline-flex;
align-items: center;
justify-content: center;
position: fixed;
top: 20px;
right: 20px;
z-index: 10;
}
}
.burger span {
position: absolute;
left: 10px;
right: 10px;
height: 2px;
background: var(--text);
transition: transform 0.3s ease, opacity 0.3s ease;
}
.burger span:nth-child(1) {
top: 14px;
}
.burger span:nth-child(2) {
top: 21px;
}
.burger span:nth-child(3) {
top: 28px;
}
.burger.is-open span:nth-child(1) {
transform: translateY(7px) rotate(45deg);
}
.burger.is-open span:nth-child(2) {
opacity: 0;
}
.burger.is-open span:nth-child(3) {
transform: translateY(-7px) rotate(-45deg);
}
.page {
position: relative;
z-index: 2;
padding: 0 clamp(20px, 6vw, 80px) 80px;
}
.hero {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 40px;
padding: 80px 0 40px;
}
.eyebrow {
text-transform: uppercase;
letter-spacing: 0.35em;
font-size: 0.7rem;
color: var(--accent-2);
font-family: "Syne", sans-serif;
}
.hero-copy h1 {
font-family: "Syne", sans-serif;
font-size: clamp(2.7rem, 5vw, 4.8rem);
margin: 16px 0;
}
.lead {
color: var(--muted);
line-height: 1.7;
max-width: 55ch;
}
.hero-actions {
display: flex;
gap: 14px;
flex-wrap: wrap;
margin-top: 24px;
}
.btn {
padding: 0.85rem 1.6rem;
border-radius: 999px;
border: 1px solid rgba(255, 255, 255, 0.2);
background: transparent;
color: var(--text);
text-transform: uppercase;
letter-spacing: 0.2em;
font-size: 0.65rem;
cursor: pointer;
}
.btn.primary {
background: linear-gradient(120deg, rgba(255, 179, 71, 0.25), rgba(92, 225, 230, 0.3));
border-color: rgba(255, 179, 71, 0.6);
}
.btn.ghost {
border-color: rgba(92, 225, 230, 0.5);
}
.hero-metrics {
margin-top: 24px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 12px;
}
.hero-metrics div {
background: var(--panel);
border: 1px solid var(--stroke);
border-radius: 14px;
padding: 14px;
}
.hero-panel {
display: grid;
gap: 18px;
}
.panel-card {
background: var(--panel);
border: 1px solid var(--stroke);
border-radius: 18px;
padding: 20px;
box-shadow: 0 0 30px rgba(255, 179, 71, 0.15);
}
.panel-title {
text-transform: uppercase;
letter-spacing: 0.2em;
font-size: 0.65rem;
color: var(--muted);
}
.panel-stat {
display: flex;
justify-content: space-between;
margin-top: 14px;
color: var(--muted);
}
.marquee {
overflow: hidden;
border-top: 1px solid rgba(255, 255, 255, 0.08);
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.marquee-track {
display: flex;
gap: 48px;
padding: 16px 0;
text-transform: uppercase;
letter-spacing: 0.35em;
font-size: 0.65rem;
color: var(--muted);
white-space: nowrap;
}
.section {
padding: 64px 0;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: baseline;
gap: 24px;
}
.section-header p {
color: var(--muted);
}
.service-grid,
.work-grid {
display: grid;
gap: 24px;
margin-top: 28px;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.service-card,
.work-card {
background: rgba(12, 16, 24, 0.86);
border: 1px solid var(--stroke);
border-radius: 18px;
padding: 22px;
}
.service-card h3,
.work-card h3 {
margin: 14px 0 10px;
}
.service-card p,
.work-card p {
color: var(--muted);
line-height: 1.6;
}
.service-meta {
display: flex;
justify-content: space-between;
color: var(--muted);
font-size: 0.85rem;
}
.split {
display: grid;
gap: 28px;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.panel {
padding: 26px;
background: rgba(10, 12, 20, 0.8);
border-radius: 18px;
border: 1px solid rgba(255, 179, 71, 0.2);
}
.panel ul {
margin: 16px 0 0;
padding-left: 18px;
color: var(--muted);
line-height: 1.7;
}
.chips {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-top: 18px;
}
.chips span {
padding: 0.45rem 0.9rem;
border-radius: 999px;
border: 1px solid rgba(92, 225, 230, 0.45);
font-size: 0.75rem;
}
.stats {
display: grid;
gap: 24px;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
text-align: center;
}
.stats h2 {
font-family: "Syne", sans-serif;
font-size: 2.4rem;
margin: 0 0 8px;
color: var(--accent);
}
.contact {
display: grid;
gap: 32px;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.contact-form {
display: grid;
gap: 16px;
}
.contact-form input,
.contact-form textarea {
background: rgba(8, 10, 18, 0.85);
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 12px;
padding: 12px 14px;
color: var(--text);
font-size: 0.95rem;
}
.contact-form input:focus,
.contact-form textarea:focus {
outline: none;
border-color: var(--accent-2);
box-shadow: 0 0 18px rgba(92, 225, 230, 0.3);
}
.footer {
padding: 24px clamp(20px, 6vw, 80px) 40px;
display: flex;
justify-content: space-between;
color: var(--muted);
font-size: 0.85rem;
}
@media (max-width: 900px) {
.nav {
gap: 20px;
}
.nav-item {
font-size: 0.85rem;
padding: 6px 12px;
}
.nav-right {
gap: 16px;
}
.btn-get-started {
padding: 8px 20px;
font-size: 0.85rem;
}
}
@media (max-width: 640px) {
.topbar {
padding: 20px;
justify-content: center;
}
.nav {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
flex-direction: column;
align-items: center;
gap: 16px;
padding: 24px;
background: rgba(7, 8, 14, 0.95);
backdrop-filter: blur(20px);
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.1);
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease, transform 0.3s ease;
z-index: 100;
}
.nav.is-open {
opacity: 1;
pointer-events: auto;
}
.page {
padding: 0 18px 80px;
}
}const services = [
{
title: "Growth Marketing",
copy: "Paid media, lifecycle strategy, and multi-channel acquisition.",
meta: "Performance",
},
{
title: "Web + App Development",
copy: "Full-stack product builds with scalable infrastructure.",
meta: "Engineering",
},
{
title: "Conversion Optimization",
copy: "A/B testing, funnel audits, and pricing experimentation.",
meta: "CRO",
},
{
title: "Brand + Positioning",
copy: "Narratives, identity systems, and launch storytelling.",
meta: "Strategy",
},
];
const work = [
{
title: "Helio Analytics",
copy: "Rebuilt onboarding and growth loops for a B2B SaaS.",
meta: "+57% activation",
},
{
title: "Flux Commerce",
copy: "Performance storefront and retention playbooks.",
meta: "-32% churn",
},
{
title: "Orbit Health",
copy: "HIPAA-ready platform with marketing automation.",
meta: "Series B launch",
},
];
const capabilities = [
"Go-to-market planning",
"Experimentation frameworks",
"Full-funnel analytics",
"Design systems + UI engineering",
];
const stack = ["Figma", "Webflow", "React", "Next.js", "GSAP", "Three.js", "HubSpot", "GA4"];
const stats = [
{ value: "120+", label: "Growth sprints shipped" },
{ value: "$48M", label: "Pipeline influenced" },
{ value: "4.9", label: "Client satisfaction" },
];
const serviceGrid = document.getElementById("serviceGrid");
const workGrid = document.getElementById("workGrid");
const capabilitiesList = document.getElementById("capabilities");
const stackChips = document.getElementById("stackChips");
const statsGrid = document.getElementById("stats");
if (serviceGrid) {
serviceGrid.innerHTML = services
.map(
(item) => `
<article class="service-card">
<span class="card-meta">${item.meta}</span>
<h3>${item.title}</h3>
<p>${item.copy}</p>
</article>
`
)
.join("");
}
if (workGrid) {
workGrid.innerHTML = work
.map(
(item) => `
<article class="work-card">
<span class="card-meta">${item.meta}</span>
<h3>${item.title}</h3>
<p>${item.copy}</p>
</article>
`
)
.join("");
}
if (capabilitiesList) {
capabilitiesList.innerHTML = capabilities.map((item) => `<li>${item}</li>`).join("");
}
if (stackChips) {
stackChips.innerHTML = stack.map((item) => `<span>${item}</span>`).join("");
}
if (statsGrid) {
statsGrid.innerHTML = stats
.map(
(stat) => `
<div>
<h2>${stat.value}</h2>
<p>${stat.label}</p>
</div>
`
)
.join("");
}
const lenis = window.Lenis
? new Lenis({
smoothWheel: true,
smoothTouch: false,
lerp: 0.08,
})
: null;
let scrollVelocity = 0;
let marqueeX = 0;
function raf(time) {
if (lenis) lenis.raf(time);
scrollVelocity *= 0.9;
if (topbar) {
topbar.classList.toggle("is-compact", Math.abs(scrollVelocity) > 1.5);
}
requestAnimationFrame(raf);
}
requestAnimationFrame(raf);
if (lenis) {
lenis.on("scroll", ({ velocity }) => {
scrollVelocity = Math.max(Math.min(velocity, 40), -40);
});
}
const marquee = document.getElementById("marqueeTrack");
if (marquee) {
const loop = () => {
marqueeX -= 0.35 + Math.abs(scrollVelocity) * 0.03;
marquee.style.transform = `translateX(${marqueeX}px)`;
if (Math.abs(marqueeX) > marquee.scrollWidth / 2) {
marqueeX = 0;
}
requestAnimationFrame(loop);
};
loop();
}
if (window.gsap) {
gsap.to("#loader", {
opacity: 0,
duration: 0.6,
delay: 1.2,
pointerEvents: "none",
});
gsap.from(".hero-copy", { opacity: 0, y: 30, duration: 1, ease: "power3.out" });
gsap.from(".hero-panel", { opacity: 0, x: 30, duration: 1, delay: 0.2, ease: "power3.out" });
gsap.utils.toArray(".service-card, .work-card, .panel, .stats div").forEach((item, index) => {
gsap.from(item, {
opacity: 0,
y: 24,
duration: 0.8,
delay: index * 0.05,
ease: "power2.out",
});
});
}
const topbar = document.getElementById("topbar");
const mainNav = document.getElementById("mainNav");
const burger = document.getElementById("burger");
const navRight = document.querySelector(".nav-right");
const navItems = document.querySelectorAll(".nav-item");
// Update active nav item on scroll
function updateActiveNav() {
const sections = document.querySelectorAll("section[id]");
const scrollPos = window.scrollY || (lenis ? lenis.scroll : 0);
sections.forEach((section) => {
const sectionTop = section.offsetTop - 100;
const sectionHeight = section.offsetHeight;
const sectionId = section.getAttribute("id");
if (scrollPos >= sectionTop && scrollPos < sectionTop + sectionHeight) {
navItems.forEach((item) => {
item.classList.remove("active");
if (item.getAttribute("href") === `#${sectionId}`) {
item.classList.add("active");
}
});
}
});
}
if (lenis) {
lenis.on("scroll", updateActiveNav);
} else {
window.addEventListener("scroll", updateActiveNav);
}
// Smooth scroll for nav links
navItems.forEach((link) => {
link.addEventListener("click", (e) => {
e.preventDefault();
const targetId = link.getAttribute("href");
if (targetId.startsWith("#")) {
if (lenis) {
lenis.scrollTo(targetId, { duration: 1.5, offset: -80 });
} else {
const target = document.querySelector(targetId);
if (target) {
target.scrollIntoView({ behavior: "smooth", block: "start" });
}
}
}
// Close mobile menu
if (window.innerWidth <= 640) {
burger.classList.remove("is-open");
mainNav.classList.remove("is-open");
burger.setAttribute("aria-expanded", "false");
}
});
});
if (burger && mainNav) {
burger.addEventListener("click", () => {
const isOpen = burger.classList.toggle("is-open");
mainNav.classList.toggle("is-open", isOpen);
if (navRight) {
navRight.classList.toggle("is-open", isOpen);
}
burger.setAttribute("aria-expanded", String(isOpen));
});
mainNav.querySelectorAll("a").forEach((link) => {
link.addEventListener("click", () => {
if (window.innerWidth <= 640) {
burger.classList.remove("is-open");
mainNav.classList.remove("is-open");
if (navRight) {
navRight.classList.remove("is-open");
}
burger.setAttribute("aria-expanded", "false");
}
});
});
}
class HaloField {
constructor(container) {
this.container = container;
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.1, 200);
this.camera.position.z = 26;
this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
container.appendChild(this.renderer.domElement);
this.clock = new THREE.Clock();
this.group = new THREE.Group();
this.scene.add(this.group);
this.createRings();
this.createParticles();
this.bindEvents();
this.animate();
}
createRings() {
const ringMat = new THREE.MeshBasicMaterial({
color: 0xffb347,
transparent: true,
opacity: 0.35,
wireframe: true,
});
for (let i = 0; i < 5; i++) {
const geometry = new THREE.TorusGeometry(6 + i * 2.4, 0.18, 16, 120);
const ring = new THREE.Mesh(geometry, ringMat.clone());
ring.rotation.x = Math.PI / 2;
ring.position.y = -2 + i * 0.6;
this.group.add(ring);
}
}
createParticles() {
const count = 220;
const positions = new Float32Array(count * 3);
for (let i = 0; i < count; i++) {
positions[i * 3] = (Math.random() - 0.5) * 40;
positions[i * 3 + 1] = (Math.random() - 0.5) * 20;
positions[i * 3 + 2] = (Math.random() - 0.5) * 40;
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
const material = new THREE.PointsMaterial({ color: 0x5ce1e6, size: 0.12 });
this.particles = new THREE.Points(geometry, material);
this.scene.add(this.particles);
}
bindEvents() {
window.addEventListener("resize", () => this.onResize());
}
onResize() {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
}
animate() {
const t = this.clock.getElapsedTime();
this.group.rotation.z = t * 0.1;
this.group.rotation.x = t * 0.05;
this.particles.rotation.y = t * 0.08;
this.renderer.render(this.scene, this.camera);
requestAnimationFrame(() => this.animate());
}
}
const bg = document.getElementById("bg");
if (bg && window.THREE) {
new HaloField(bg);
}<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>PageService — Growth & Product Studio</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Urbanist:wght@300;400;500;600;700&family=Syne:wght@400;500;600;700;800&display=swap"
rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="loader" id="loader">
<div class="loader-orbit"></div>
<div class="loader-core"></div>
<p>Spinning up growth systems…</p>
</div>
<div id="bg"></div>
<header class="topbar" id="topbar">
<div class="brand">
<span class="brand-text">pageService</span>
<span class="brand-dot">•</span>
</div>
<nav class="nav" id="mainNav">
<a href="#services" class="nav-item">Services</a>
<a href="#work" class="nav-item active">Work</a>
<a href="#stack" class="nav-item">Stack</a>
<a href="#contact" class="nav-item">Contact</a>
</nav>
<div class="nav-right">
<a href="#login" class="nav-login">Login</a>
<button class="btn-get-started">Get Started</button>
</div>
<button class="burger" id="burger" aria-label="Open menu" aria-expanded="false">
<span></span>
<span></span>
<span></span>
</button>
</header>
<main class="page">
<section class="hero">
<div class="hero-copy">
<p class="eyebrow">Growth + Product Systems</p>
<h1>Launch-ready marketing, product, and web systems that convert.</h1>
<p class="lead">
We’re a hybrid studio blending brand strategy, full-stack development, and performance marketing.
Think of us as your on-call growth team—ready to prototype, build, and scale.
</p>
<div class="hero-actions">
<button class="btn primary">Book a kickoff</button>
<button class="btn ghost">View case study</button>
</div>
<div class="hero-metrics">
<div>
<span>Avg. Lift</span>
<strong>+42%</strong>
</div>
<div>
<span>Ship Time</span>
<strong>3–5 weeks</strong>
</div>
<div>
<span>Retention</span>
<strong>93%</strong>
</div>
</div>
</div>
<div class="hero-panel">
<div class="panel-card">
<p class="panel-title">Live Pulse</p>
<h3>Q1 Growth Sprint</h3>
<p>Paid media + CRO overhaul for a SaaS analytics team.</p>
<div class="panel-stat">
<span>Pipeline</span>
<strong>$1.4M</strong>
</div>
</div>
<div class="panel-card">
<p class="panel-title">Signal</p>
<h3>Product + Brand</h3>
<p>Identity refresh and performance landing pages for launch.</p>
</div>
</div>
</section>
<section class="marquee" aria-hidden="true">
<div class="marquee-track" id="marqueeTrack">
<span>Marketing Systems</span>
<span>Full-Stack Development</span>
<span>Conversion Optimization</span>
<span>Product Strategy</span>
</div>
</section>
<section class="section" id="services">
<div class="section-header">
<h2>Services</h2>
<p>Everything needed to launch, scale, and sustain.</p>
</div>
<div class="service-grid" id="serviceGrid"></div>
</section>
<section class="section" id="work">
<div class="section-header">
<h2>Selected Work</h2>
<p>Highlights from recent growth sprints and product builds.</p>
</div>
<div class="work-grid" id="workGrid"></div>
</section>
<section class="section split" id="stack">
<div class="panel">
<h2>Capabilities</h2>
<ul id="capabilities"></ul>
</div>
<div class="panel">
<h2>Stack</h2>
<div class="chips" id="stackChips"></div>
</div>
</section>
<section class="section stats" id="stats"></section>
<section class="section contact" id="contact">
<div>
<h2>Let’s Build</h2>
<p>Tell us about your product, timeline, and growth goals.</p>
</div>
<form class="contact-form">
<input type="text" placeholder="Name" />
<input type="email" placeholder="Email" />
<input type="text" placeholder="Company" />
<textarea rows="4" placeholder="Project Brief"></textarea>
<button class="btn primary" type="button">Send Request</button>
</form>
</section>
</main>
<footer class="footer">
<span>© 2026 pageService Studio</span>
<span>Brand • Growth • Product</span>
</footer>
<script src="https://cdn.jsdelivr.net/npm/@studio-freight/lenis@1.0.42/bundled/lenis.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js"></script>
<script src="script.js"></script>
</body>
</html>PageService — Growth & Product Studio
A modern portfolio website for a growth and product studio, featuring a Three.js halo field background with animated rings and particles, smooth scroll animations powered by Lenis, GSAP transitions, and a data-driven service showcase.
How it works
The portfolio combines business-focused design with advanced web technologies:
- Three.js Halo Field — Animated 3D background with rotating torus rings and particle system
- Lenis Smooth Scroll — Buttery-smooth scrolling with velocity tracking
- GSAP Animations — Fade-in animations for hero content, cards, and sections
- Scroll-Velocity Reactive UI — Topbar compacts based on scroll velocity
- Marquee Animation — Continuous scrolling marquee that speeds up with scroll velocity
- Data-Driven Content — Services, work, capabilities, and stats generated from JavaScript arrays
Features
- Service Grid — Dynamic service cards with metadata
- Work Showcase — Case study cards with performance metrics
- Stack & Capabilities — Technology stack chips and capability lists
- Stats Section — Key performance indicators
- Contact Form — Lead capture form
- Responsive Navigation — Mobile-friendly burger menu
- Loading Animation — GSAP-powered loader with orbital animation
Technologies
- Three.js — 3D background with torus rings and particles
- GSAP — Animation library for smooth transitions
- Lenis — Smooth scroll library with velocity tracking
- Custom CSS — Dark theme with gradient backgrounds and glassmorphism effects
Use cases
- Growth marketing agency portfolios
- Product studio websites
- Business service showcases
- Professional service landing pages