Compare commits

...

2 Commits

Author SHA1 Message Date
Emre
f450d61ccf initial dev 2025-10-10 23:03:48 +03:00
Emre
43682f9fbe mission try 2025-10-10 22:20:13 +03:00
15 changed files with 360 additions and 409 deletions

View File

@@ -33,7 +33,7 @@ export const Header = () => {
transition={{ duration: 0.6, ease: 'easeOut' }} transition={{ duration: 0.6, ease: 'easeOut' }}
className={cn( className={cn(
'fixed inset-x-0 top-0 z-50 transition-all duration-500', 'fixed inset-x-0 top-0 z-50 transition-all duration-500',
isScrolled ? 'bg-white/95 shadow-lg backdrop-blur-sm' : 'bg-transparent', isScrolled ? 'bg-mist/95 shadow-lg backdrop-blur-sm' : 'bg-transparent',
)} )}
> >
<div className="mx-auto flex max-w-6xl items-center justify-between px-6 py-4 lg:px-8"> <div className="mx-auto flex max-w-6xl items-center justify-between px-6 py-4 lg:px-8">
@@ -101,7 +101,7 @@ export const Header = () => {
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -16 }} exit={{ opacity: 0, y: -16 }}
transition={{ duration: 0.25, ease: 'easeOut' }} transition={{ duration: 0.25, ease: 'easeOut' }}
className="border-t border-slate-100 bg-white/95 px-6 py-4 shadow-lg md:hidden" className="border-t border-slate-100 bg-mist/95 px-6 py-4 shadow-lg md:hidden"
> >
<div className="mx-auto flex max-w-6xl flex-col gap-4"> <div className="mx-auto flex max-w-6xl flex-col gap-4">
{navItems.map(({ label, to }) => ( {navItems.map(({ label, to }) => (

View File

@@ -1,24 +1,33 @@
import { type ReactNode } from 'react'; import { type ReactNode } from 'react';
import { useLocation } from 'react-router-dom';
import { Header } from './Header'; import { Header } from './Header';
import { Footer } from './Footer'; import { Footer } from './Footer';
import { ScrollToTop } from './ScrollToTop'; import { ScrollToTop } from './ScrollToTop';
import { cn } from '../../lib/cn';
type LayoutProps = { type LayoutProps = {
children: ReactNode; children: ReactNode;
}; };
export const Layout = ({ children }: LayoutProps) => { export const Layout = ({ children }: LayoutProps) => {
const { pathname } = useLocation();
const isHome = pathname === '/';
return ( return (
<div className="relative min-h-screen overflow-hidden bg-gradient-to-br from-slate-50 via-white to-brand-50/50"> <div className={cn('relative min-h-screen bg-mist text-ink', !isHome && 'overflow-hidden')}>
<ScrollToTop /> <ScrollToTop />
{/* Decorative gradient blurs */}
<div className="pointer-events-none fixed -top-32 left-6 h-80 w-80 rounded-full bg-brand-200/40 blur-3xl lg:left-24" />
<div className="pointer-events-none fixed top-1/3 right-10 h-96 w-96 rounded-full bg-indigo-200/30 blur-3xl lg:right-24" />
<div className="pointer-events-none fixed bottom-1/4 left-1/4 h-72 w-72 rounded-full bg-brand-200/30 blur-3xl" />
<Header /> <Header />
<main className="relative z-10 mx-auto max-w-6xl px-6 pb-24 pt-28 lg:px-8 lg:pt-32">{children}</main> <main
<Footer /> className={cn(
'relative z-10',
isHome
? 'h-screen overflow-x-hidden overflow-y-scroll scroll-smooth snap-y snap-mandatory'
: 'mx-auto max-w-6xl px-6 pb-24 pt-28 lg:px-8 lg:pt-32',
)}
>
{children}
</main>
{!isHome && <Footer />}
</div> </div>
); );
}; };

View File

@@ -5,8 +5,8 @@
@tailwind utilities; @tailwind utilities;
:root { :root {
color: #111827; color: #000000;
background-color: #f6f8fb; background-color: rgb(252 252 246);
} }
html, html,

View File

@@ -2,57 +2,42 @@ export const MissionVision = () => {
return ( return (
<section className="relative py-20 lg:py-28"> <section className="relative py-20 lg:py-28">
<div className="relative mx-auto max-w-6xl px-6 lg:px-12"> <div className="relative mx-auto max-w-6xl px-6 lg:px-12">
<div className="flex flex-col gap-12 rounded-[32px] bg-gradient-to-br from-white via-white to-brand-50/40 p-8 shadow-xl ring-1 ring-brand-100/40 sm:p-12 lg:grid lg:grid-cols-[minmax(0,0.9fr)_1fr] lg:items-center"> <div className="mx-auto max-w-3xl space-y-8">
<div className="order-1 lg:order-none"> <div className="flex items-center gap-4">
<figure className="relative mx-auto max-w-sm overflow-hidden rounded-[28px] bg-gradient-to-br from-emerald-100/50 via-white to-brand-100/40 p-6 shadow-lg ring-1 ring-brand-200/40"> <div className="h-px flex-1 bg-gradient-to-r from-brand-500/40 via-brand-300/40 to-transparent" />
<div className="absolute inset-0 rounded-[24px] bg-[radial-gradient(circle_at_20%_20%,rgba(56,189,248,0.22),transparent_55%),radial-gradient(circle_at_80%_40%,rgba(59,130,246,0.18),transparent_60%)]" /> <span className="text-xs font-semibold uppercase tracking-[0.35em] text-brand-600">
<img Technology with Purpose
src="/images/ceo-kristof.png" </span>
alt="Kristof De Spiegeleer, Founder and CEO of GeoMind"
className="relative z-10 mx-auto w-full max-w-xs object-cover"
/>
<figcaption className="relative z-10 mt-6 text-center text-sm font-medium text-slate-500">
Kristof De Spiegeleer &mdash; Founder &amp; CEO
</figcaption>
</figure>
</div> </div>
<div className="relative flex flex-col gap-8 rounded-3xl bg-white/90 p-8 shadow-inner ring-1 ring-brand-100/50 backdrop-blur"> <div className="relative">
<div className="flex items-center gap-4"> <span
<div className="h-px flex-1 bg-gradient-to-r from-brand-500/50 via-brand-300/50 to-transparent" /> aria-hidden="true"
<span className="text-xs font-semibold uppercase tracking-[0.35em] text-brand-600"> className="float-left mr-3 -mt-3 text-6xl font-serif text-brand-500/25 leading-none"
Technology with Purpose >
</span>
</div> </span>
<div className="relative"> <div className="space-y-6 text-base leading-8 text-slate-600 sm:text-lg sm:leading-8">
<span <p className="italic text-brand-700">
aria-hidden="true" When we first started, our goal was simple, to build the foundation for the worlds digital future.
className="float-left mr-3 -mt-3 text-6xl font-serif text-brand-500/25 leading-none" Over time, we realized that technology isnt just about performance or scale, its about purpose.
> Its about people, communities, and the planet we share.
</p>
</span> <p>
<div className="space-y-6 text-base leading-8 text-slate-600 sm:text-lg sm:leading-8"> Today, were creating the next generation of datacenters, designed not only for the AI era but for a
<p className="italic text-brand-700"> sustainable, inclusive future. Our mission is clear: to make digital decentralized infrastructure a
When we first started, our goal was simple, to build the foundation for the worlds digital future. universal right, accessible and responsible in equal measure.
Over time, we realized that technology isnt just about performance or scale, its about purpose. </p>
Its about people, communities, and the planet we share. <p>
</p> Weve spent decades pioneering technologies that power the internet. Now, were redefining what
<p> datacenters stand for, combining efficiency, sovereignty, and sustainability to serve both humanity and
Today, were creating the next generation of datacenters, designed not only for the AI era but for a innovation.
sustainable, inclusive future. Our mission is clear: to make digital decentralized infrastructure a </p>
universal right, accessible and responsible in equal measure.
</p>
<p>
Weve spent decades pioneering technologies that power the internet. Now, were redefining what
datacenters stand for, combining efficiency, sovereignty, and sustainability to serve both humanity and
innovation.
</p>
</div>
</div>
<div className="border-t border-slate-200 pt-6 text-sm">
<p className="font-semibold text-brand-700">Kristof De Spiegeleer</p>
<p className="text-slate-500">Founder &amp; CEO, GeoMind</p>
</div> </div>
</div> </div>
<div className="border-t border-slate-200 pt-6 text-sm">
<p className="font-semibold text-brand-700">Kristof De Spiegeleer</p>
<p className="text-slate-500">Founder &amp; CEO, GeoMind</p>
</div>
</div> </div>
</div> </div>
</section> </section>

View File

@@ -1,17 +1,64 @@
import { HomeHero } from './components/HomeHero'; import { HeroSection } from './components/HeroSection';
import { CoreTechnology } from './components/CoreTechnology'; import { ScrollLockedSection } from './components/ScrollLockedSection';
import { ImpactBanner } from './components/ImpactBanner'; import { CtaSection } from './components/CtaSection';
import { WhyGeomind } from './components/WhyGeomind'; import { FooterSection } from './components/FooterSection';
import { FinalCallToAction } from './components/FinalCallToAction';
const sections = [
{
id: 'deploy',
eyebrow: 'Deploy',
title: 'Launch seamlessly across your environments.',
description:
'Use this space to outline the deployment story. Highlight speed, reliability, or any differentiators that matter for your product rollout.',
},
{
id: 'plug_play',
eyebrow: 'Plug & Play',
title: 'Connect data sources without orchestration headaches.',
description:
'Describe how integrations work and communicate the ease of getting started. Keep the copy short and scannable.',
},
{
id: 'slice',
eyebrow: 'Slice',
title: 'Break complex geospatial datasets into digestible layers.',
description:
'Talk through the slicing concept in a sentence or two. This is placeholder text while the final story is drafted.',
},
{
id: 'global',
eyebrow: 'Global',
title: 'Stay synchronized across every region you operate in.',
description:
'Explain the global coverage or synchronization narrative you want to share. Replace this block with final messaging later.',
},
{
id: 'profit',
eyebrow: 'Profit',
title: 'Make the commercial case with defensible metrics.',
description:
'Use these lines to tease the ROI conversation. Mention efficiency, cost savings, or other proof points once they are ready.',
},
{
id: 'usecases',
eyebrow: 'Use Cases',
title: 'Show how teams activate the platform day-to-day.',
description:
'Imagine this section as a carousel or story. For now, it is a placeholder where future customer narratives will land.',
},
];
export const HomePage = () => { export const HomePage = () => {
return ( return (
<div className="space-y-12 lg:space-y-16"> <div className="flex min-h-screen flex-col bg-mist text-ink">
<HomeHero /> <div className="flex flex-col">
<CoreTechnology /> <HeroSection />
<ImpactBanner /> {sections.map((section) => (
<WhyGeomind /> <ScrollLockedSection key={section.id} {...section} />
<FinalCallToAction /> ))}
<CtaSection />
</div>
<FooterSection />
</div> </div>
); );
}; };

View File

@@ -1,57 +0,0 @@
import { motion } from 'framer-motion';
const features = [
{
title: 'Self Healing & Prederministic Deployments',
description:
"GeoMind nodes detect and fix issues automatically with zero downtime. Every deployment is verifiable and runs exactly the same anywhere, fully autonomous, resilient, and predictable.",
},
{
title: 'Unbreakable Storage',
description:
'Data is encrypted and encoded using forward-error-correction codes, not replication. Even if parts of the network fail, data can always be rebuilt, making it unhackable, permanent, and loss-proof.',
},
{
title: 'Unbreakable Network',
description:
'Runs on top of the internet, finding the fastest path for data. With end-to-end quantum-safe encryption and self-optimizing routing, it creates a layer that cannot be hacked or shut down.',
},
];
export const CoreTechnology = () => {
return (
<section className="py-16 lg:py-24">
<div className="mx-auto max-w-4xl text-center">
<p className="text-xs font-semibold uppercase tracking-[0.35em] text-brand-600">
Core Technology
</p>
<h2 className="mt-4 text-3xl font-semibold text-ink sm:text-4xl">
The Foundation of a New Datacenter Standard
</h2>
<p className="mt-5 text-base text-slate-600 sm:text-lg">
GeoMind is built on a modular, self-healing datacenter architecture designed for unmatched
efficiency, reliability, and sovereignty. Every component works autonomously yet integrates
seamlessly into a global, planet-scale infrastructure.
</p>
</div>
<div className="mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{features.map((feature, index) => (
<motion.div
key={feature.title}
initial={{ opacity: 0, y: 24 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.2 }}
transition={{ duration: 0.5, delay: index * 0.1 }}
className="flex flex-col rounded-3xl border border-slate-100 bg-white/80 p-8 shadow-subtle backdrop-blur"
>
<span className="inline-flex h-10 w-10 items-center justify-center rounded-full bg-brand-50 text-sm font-semibold text-brand-600">
{index + 1}
</span>
<h3 className="mt-6 text-lg font-semibold text-ink">{feature.title}</h3>
<p className="mt-4 text-sm leading-6 text-slate-600">{feature.description}</p>
</motion.div>
))}
</div>
</section>
);
};

View File

@@ -0,0 +1,48 @@
import { motion } from 'framer-motion';
export const CtaSection = () => {
return (
<section className="snap-start bg-mist">
<div className="mx-auto flex w-full max-w-5xl flex-col items-center gap-10 px-6 py-40 text-center sm:px-10">
<motion.span
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-20%' }}
transition={{ duration: 0.6, ease: 'easeOut' }}
className="text-xs font-semibold uppercase tracking-[0.4em] text-ink/60"
>
Ready when you are
</motion.span>
<motion.h3
initial={{ opacity: 0, y: 24 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-20%' }}
transition={{ duration: 0.7, ease: 'easeOut', delay: 0.15 }}
className="text-4xl font-medium leading-tight text-ink sm:text-5xl"
>
Drop in your call to action headline and invite people forward.
</motion.h3>
<motion.p
initial={{ opacity: 0, y: 16 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-20%' }}
transition={{ duration: 0.7, ease: 'easeOut', delay: 0.25 }}
className="max-w-2xl text-lg text-ink/70"
>
Use this block to reinforce the value proposition and give your visitor a clear next step.
Consider pairing it with a lead capture form or direct contact pathway later.
</motion.p>
<motion.button
type="button"
initial={{ opacity: 0, y: 12 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-20%' }}
transition={{ duration: 0.6, ease: 'easeOut', delay: 0.35 }}
className="rounded-full border border-ink/10 bg-ink px-10 py-4 text-sm font-semibold uppercase tracking-[0.35em] text-mist transition-transform duration-300 hover:-translate-y-0.5 hover:shadow-[0_16px_36px_-24px_rgba(0,0,0,0.65)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ink/40 focus-visible:ring-offset-2 focus-visible:ring-offset-mist"
>
Placeholder CTA
</motion.button>
</div>
</section>
);
};

View File

@@ -1,31 +0,0 @@
import { motion } from 'framer-motion';
import { PrimaryButton } from '../../../components/ui/PrimaryButton';
export const FinalCallToAction = () => {
return (
<section className="py-20 lg:py-32">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.3 }}
transition={{ duration: 0.7, ease: 'easeOut' }}
className="mx-auto max-w-4xl text-center"
>
<h2 className="text-3xl font-semibold text-ink sm:text-4xl lg:text-5xl">
{' '}
<span className="bg-gradient-to-r from-brand-500 via-brand-600 to-brand-700 bg-clip-text text-transparent">
The Datacenter Standard
</span>{' '}
<br />
for the next era of Cloud and AI.
</h2>
<p className="mt-6 text-lg leading-relaxed text-ink/70 sm:text-xl">
For years we've been pioneering infrastructure technologies that power the world's most demanding cloud workloads. Learn more about our team and expertise behind our mission.
</p>
<div className="mt-10 flex justify-center">
<PrimaryButton to="/about">About Us</PrimaryButton>
</div>
</motion.div>
</section>
);
};

View File

@@ -0,0 +1,50 @@
import { Link } from 'react-router-dom';
const footerLinks = [
{ label: 'About', to: '/about' },
{ label: 'Technology', to: '/technology' },
{ label: 'Use Cases', to: '/usecases' },
];
export const FooterSection = () => {
const year = new Date().getFullYear();
return (
<footer className="bg-mist px-6 pb-16 pt-12 sm:px-10 lg:px-20">
<div className="mx-auto flex w-full max-w-7xl flex-col gap-12 border-t border-ink/10 pt-12 md:flex-row md:items-center md:justify-between">
<div className="space-y-3">
<span className="text-xs font-semibold uppercase tracking-[0.35em] text-ink/60">
Geomind
</span>
<p className="max-w-sm text-sm text-ink/60">
Anchor your footer copy here. Add a short positioning line or compliance text once ready.
</p>
</div>
<nav className="flex flex-col items-start gap-4 text-sm font-medium uppercase tracking-[0.3em] text-ink/50 md:flex-row md:items-center md:gap-8">
{footerLinks.map(({ label, to }) => (
<Link key={to} to={to} className="transition-colors duration-300 hover:text-ink/80">
{label}
</Link>
))}
<a
href="mailto:support@threefold.tech"
className="rounded-full border border-ink/10 px-5 py-2 text-xs font-semibold tracking-[0.3em] text-ink transition-colors duration-300 hover:border-ink/40"
>
Contact
</a>
</nav>
</div>
<div className="mx-auto mt-12 flex w-full max-w-7xl items-center justify-between text-xs uppercase tracking-[0.3em] text-ink/40">
<span>© {year} Geomind</span>
<div className="flex gap-4">
<a href="#" className="transition-colors duration-300 hover:text-ink/70">
Privacy
</a>
<a href="#" className="transition-colors duration-300 hover:text-ink/70">
Terms
</a>
</div>
</div>
</footer>
);
};

View File

@@ -0,0 +1,48 @@
import { motion } from 'framer-motion';
export const HeroSection = () => {
return (
<section className="relative snap-start">
<div className="relative flex h-screen w-full flex-col overflow-hidden bg-mist">
<video className="absolute inset-0 h-full w-full object-cover" autoPlay muted loop playsInline>
<source src="/videos/hero.mp4" type="video/mp4" />
</video>
<div className="absolute inset-0 bg-mist/70 backdrop-blur-[2px]" />
<div className="relative z-10 mx-auto flex h-full w-full max-w-7xl flex-col justify-between px-6 pb-16 pt-32 sm:px-10 lg:px-20">
<motion.div
initial={{ opacity: 0, y: 40 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, ease: 'easeOut' }}
className="max-w-3xl space-y-6"
>
<span className="text-xs font-semibold uppercase tracking-[0.4em] text-ink/70">
Geomind
</span>
<h1 className="text-4xl font-medium leading-tight text-ink sm:text-5xl md:text-6xl">
Geospatial intelligence for real-world momentum.
</h1>
<p className="max-w-xl text-lg text-ink/80">
Introduce a compelling statement here that speaks to the transformation you deliver.
Keep it short, grounded, and ready for future storytelling.
</p>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, ease: 'easeOut', delay: 0.4 }}
className="flex items-center justify-between text-xs uppercase tracking-[0.3em] text-ink/60"
>
<span>Scroll to explore</span>
<div className="flex items-center gap-3">
<span className="h-px w-16 bg-ink/40" />
<span>Landing overview</span>
</div>
</motion.div>
</div>
</div>
</section>
);
};

View File

@@ -1,55 +0,0 @@
import { motion } from 'framer-motion';
import { PrimaryButton } from '../../../components/ui/PrimaryButton';
export const HomeHero = () => {
return (
<section className="relative overflow-hidden rounded-3xl bg-ink text-white">
<video
className="absolute inset-0 h-full w-full object-cover opacity-60"
autoPlay
muted
loop
playsInline
poster="/images/hometech.jpg"
>
<source src="/videos/hero.mp4" type="video/mp4" />
</video>
<div className="absolute inset-0 bg-gradient-to-br from-[#0f172a]/70 via-[#1e1b4b]/60 to-[#312e81]/80" />
<div className="relative z-10 px-6 py-20 sm:px-10 lg:px-16">
<motion.h1
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2, duration: 0.6 }}
className="text-3xl font-semibold leading-tight sm:text-4xl lg:text-5xl"
>
The planet&apos;s sovereign agentic cloud
</motion.h1>
<motion.p
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3, duration: 0.6 }}
className="mt-6 max-w-3xl text-base text-white/70 sm:text-lg"
>
A new generation of decentralized cloud and AI infrastructure,
secure, scalable, efficient, and sovereign by design. Deploy your own
datacenter, scale globally, and turn infrastructure into profit.
</motion.p>
<motion.div
className="mt-10 flex flex-wrap gap-4"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.4, duration: 0.6 }}
>
<PrimaryButton to="/technology">Technologies</PrimaryButton>
<PrimaryButton
to="/usecases"
variant="ghost"
className="border border-white/40 text-white hover:bg-white hover:text-brand-600"
>
Use Cases
</PrimaryButton>
</motion.div>
</div>
</section>
);
};

View File

@@ -1,120 +0,0 @@
import { motion } from 'framer-motion';
import { useEffect, useRef } from 'react';
import { PrimaryButton } from '../../../components/ui/PrimaryButton';
export const ImpactBanner = () => {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
if (!ctx) return;
// Set canvas size
const resizeCanvas = () => {
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
};
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// Grid configuration
const gridSpacing = 40;
const dotRadius = 2;
const glowRadius = 8;
const dots: Array<{
x: number;
y: number;
baseX: number;
baseY: number;
phase: number;
speed: number;
}> = [];
// Create grid of dots
for (let x = 0; x < canvas.width; x += gridSpacing) {
for (let y = 0; y < canvas.height; y += gridSpacing) {
dots.push({
x,
y,
baseX: x,
baseY: y,
phase: Math.random() * Math.PI * 2,
speed: 0.5 + Math.random() * 0.5,
});
}
}
let animationFrameId: number;
let time = 0;
const animate = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
time += 0.01;
dots.forEach((dot) => {
// Subtle floating animation
const offsetX = Math.sin(time * dot.speed + dot.phase) * 3;
const offsetY = Math.cos(time * dot.speed * 0.8 + dot.phase) * 3;
dot.x = dot.baseX + offsetX;
dot.y = dot.baseY + offsetY;
// Pulsing opacity
const opacity = 0.15 + Math.sin(time * dot.speed + dot.phase) * 0.1;
// Draw glow
const gradient = ctx.createRadialGradient(dot.x, dot.y, 0, dot.x, dot.y, glowRadius);
gradient.addColorStop(0, `rgba(99, 102, 241, ${opacity * 0.3})`);
gradient.addColorStop(1, 'rgba(99, 102, 241, 0)');
ctx.fillStyle = gradient;
ctx.fillRect(dot.x - glowRadius, dot.y - glowRadius, glowRadius * 2, glowRadius * 2);
// Draw dot
ctx.beginPath();
ctx.arc(dot.x, dot.y, dotRadius, 0, Math.PI * 2);
ctx.fillStyle = `rgba(99, 102, 241, ${opacity + 0.2})`;
ctx.fill();
});
animationFrameId = requestAnimationFrame(animate);
};
animate();
return () => {
window.removeEventListener('resize', resizeCanvas);
cancelAnimationFrame(animationFrameId);
};
}, []);
return (
<section className="relative overflow-hidden py-16 text-center lg:py-20">
{/* Animated background canvas */}
<canvas
ref={canvasRef}
className="absolute inset-0 h-full w-full"
style={{ opacity: 0.6 }}
/>
{/* Content */}
<motion.div
initial={{ opacity: 0, y: 28 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.3 }}
transition={{ duration: 0.6, ease: 'easeOut' }}
className="relative z-10 px-6 sm:px-10"
>
<h2 className="text-3xl font-semibold text-ink sm:text-4xl">Designed for Real-World Impact</h2>
<p className="mx-auto mt-5 max-w-3xl text-base text-slate-600 sm:text-lg">
GeoMind enables enterprises and infrastructure providers to run secure, profitable,
efficient, and sovereign clouds anywhere.
</p>
<div className="mt-8 flex justify-center">
<PrimaryButton to="/usecases">Use Cases</PrimaryButton>
</div>
</motion.div>
</section>
);
};

View File

@@ -0,0 +1,100 @@
import { motion, useScroll, useSpring, useTransform, useMotionValueEvent } from 'framer-motion';
import { useRef, useState } from 'react';
type ScrollLockedSectionProps = {
id: string;
eyebrow: string;
title: string;
description: string;
};
export const ScrollLockedSection = ({
id,
eyebrow,
title,
description,
}: ScrollLockedSectionProps) => {
const sectionRef = useRef<HTMLElement | null>(null);
const { scrollYProgress } = useScroll({
target: sectionRef,
offset: ['start start', 'end end'],
});
const smoothProgress = useSpring(scrollYProgress, { stiffness: 120, damping: 30, mass: 0.4 });
const cardFillWidth = useTransform(smoothProgress, [0, 1], ['12%', '100%']);
const cardFillOpacity = useTransform(smoothProgress, [0, 1], [0.25, 0.85]);
const barScale = useTransform(smoothProgress, [0, 1], [0.3, 1]);
const [percent, setPercent] = useState(0);
useMotionValueEvent(smoothProgress, 'change', (value) => {
setPercent(Math.round(value * 100));
});
return (
<section id={id} ref={sectionRef} className="relative h-[200vh] snap-start">
<div className="sticky top-0 flex h-screen flex-col">
<div className="mx-auto flex h-full w-full max-w-7xl flex-col justify-between px-6 py-24 sm:px-10 lg:px-20">
<div className="space-y-4">
<span className="text-xs font-semibold uppercase tracking-[0.45em] text-ink/50">
{eyebrow}
</span>
<div className="max-w-3xl space-y-4">
<h2 className="text-3xl font-medium leading-tight text-ink sm:text-4xl md:text-5xl">
{title}
</h2>
<p className="text-lg text-ink/75">{description}</p>
</div>
</div>
<div className="mt-16 flex flex-1 flex-col justify-end">
<div className="space-y-8 rounded-3xl border border-ink/10 bg-white/60 p-8 shadow-[0_22px_48px_-32px_rgba(0,0,0,0.28)] backdrop-blur">
<div className="space-y-4">
<div className="flex items-center justify-between">
<p className="text-sm font-semibold uppercase tracking-[0.35em] text-ink/60">
Animation Placeholder
</p>
<motion.span
className="text-xs font-medium uppercase tracking-[0.35em] text-ink/50"
style={{ opacity: smoothProgress }}
>
{percent}%
</motion.span>
</div>
<div className="h-1.5 w-full overflow-hidden rounded-full bg-ink/10">
<motion.div
className="h-full origin-left rounded-full bg-ink"
style={{ scaleX: smoothProgress }}
/>
</div>
</div>
<div className="relative h-56 w-full overflow-hidden rounded-2xl border border-ink/10 bg-mist/70">
<div className="absolute inset-0 grid grid-cols-12 gap-2 px-8 py-10">
{Array.from({ length: 12 }).map((_, index) => (
<motion.span
key={index}
className="flex h-full w-full origin-bottom items-end justify-center rounded-full bg-ink/15"
style={{ opacity: cardFillOpacity, scaleY: barScale }}
>
<span className="sr-only">Placeholder animation bar</span>
</motion.span>
))}
</div>
<div className="absolute bottom-8 left-1/2 flex w-11/12 -translate-x-1/2 items-center gap-3">
<div className="h-1 w-full rounded-full bg-ink/10">
<motion.div
className="h-full rounded-full bg-ink"
style={{ width: cardFillWidth, opacity: cardFillOpacity }}
/>
</div>
<motion.span className="text-[10px] font-semibold uppercase tracking-[0.3em] text-ink/50">
{percent}%
</motion.span>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
);
};

View File

@@ -1,73 +0,0 @@
import { motion } from 'framer-motion';
const pillars = [
{
title: 'Sovereign by Design',
points: [
'Stay compliant with in-country data requirements.',
'Each node operates independently or as part of a global, trusted network.',
'Maintain total ownership of your infrastructure and data.',
],
},
{
title: 'Efficient and Sustainable',
points: [
'Up to 10x less energy for specific workloads.',
'Removes layers of legacy software overhead.',
'Lower operational cost and carbon footprint.',
],
},
{
title: 'Profitable Infrastructure',
points: [
'Turn existing datacenters, offices, or parking lots into productive assets.',
'Use capacity for your workloads and sell the excess to the network.',
'ROI can be 3x higher than traditional models.',
],
},
];
export const WhyGeomind = () => {
return (
<section className="relative px-6 py-16 sm:px-10 lg:px-16 lg:py-24">
<div className="pointer-events-none absolute -left-32 top-0 h-56 w-56 rounded-full bg-brand-100 opacity-60 blur-3xl lg:-left-24" />
<div className="pointer-events-none absolute -right-24 bottom-0 h-64 w-64 rounded-full bg-brand-200 opacity-50 blur-3xl" />
<motion.div
initial={{ opacity: 0, y: 24 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.3 }}
transition={{ duration: 0.6, ease: 'easeOut' }}
className="relative z-10 max-w-3xl"
>
<h2 className="text-3xl font-semibold text-ink sm:text-4xl">Why GeoMind</h2>
<p className="mt-5 text-base text-slate-600 sm:text-lg">
Traditional datacenters are increasingly limited by geopolitics, inefficiency, and energy
waste. GeoMind eliminates those constraints with a resilient, autonomous infrastructure that
delivers planetary scalability and sovereign performance anywhere in the world.
</p>
</motion.div>
<div className="relative z-10 mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{pillars.map((pillar, index) => (
<motion.div
key={pillar.title}
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.25 }}
transition={{ duration: 0.5, delay: index * 0.1 }}
className="rounded-3xl border border-slate-100 bg-white/90 p-6 shadow-subtle"
>
<h3 className="text-lg font-semibold text-ink">{pillar.title}</h3>
<ul className="mt-4 space-y-3 text-sm text-slate-600">
{pillar.points.map((point) => (
<li key={point} className="flex gap-3">
<span className="mt-1 inline-block h-1.5 w-1.5 flex-shrink-0 rounded-full bg-brand-300" />
<span>{point}</span>
</li>
))}
</ul>
</motion.div>
))}
</div>
</section>
);
};

View File

@@ -20,8 +20,8 @@ export default {
800: '#343b8a', 800: '#343b8a',
900: '#2d336c', 900: '#2d336c',
}, },
ink: '#111827', ink: '#000000',
mist: '#f6f8fb', mist: '#fcfcf6',
}, },
boxShadow: { boxShadow: {
subtle: '0 20px 45px -25px rgba(18, 28, 132, 0.35)', subtle: '0 20px 45px -25px rgba(18, 28, 132, 0.35)',