feat: enhance UI with glowing effects and visual improvements

- Added new MagicCard component for interactive hover effects with gradient lighting
- Enhanced CubeLight component with cyan glow effects and improved visual styling
- Added new GlowingEffect component for dynamic lighting animations
- Updated StackedCubesLight with ambient gradient background and smoother transitions
- Added tracking-wide property to CP text component for better readability
- Added new networkhero.png image asset
This commit is contained in:
2025-10-24 20:41:42 +02:00
parent 94f4e72e57
commit 68b2119c76
8 changed files with 430 additions and 109 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@@ -160,4 +160,4 @@ export const DownloadCardDescription = createTextComponent(
)
export const CT = createTextComponent('span', 'text-lg lg:text-xl font-semibold')
export const CP = createTextComponent('p', 'text-sm lg:text-sm leading-[1.525] font-light')
export const CP = createTextComponent('p', 'text-sm lg:text-sm tracking-wide leading-[1.525] font-light')

View File

@@ -0,0 +1,63 @@
'use client';
import { cn } from '@/lib/utils';
import { type ReactNode, useEffect, useRef, useState } from 'react';
interface MagicCardProps {
children: ReactNode;
className?: string;
gradientSize?: number;
gradientColor?: string;
}
export const MagicCard = ({ children, className, gradientSize = 200, gradientColor = '#262626' }: MagicCardProps) => {
const mouseX = useRef<number>(0);
const mouseY = useRef<number>(0);
const cardRef = useRef<HTMLDivElement>(null);
const [isHovering, setIsHovering] = useState(false);
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
if (cardRef.current) {
const rect = cardRef.current.getBoundingClientRect();
mouseX.current = e.clientX - rect.left;
mouseY.current = e.clientY - rect.top;
cardRef.current.style.setProperty('--mouse-x', `${mouseX.current}px`);
cardRef.current.style.setProperty('--mouse-y', `${mouseY.current}px`);
}
};
const currentCardRef = cardRef.current;
if (currentCardRef) {
currentCardRef.addEventListener('mousemove', handleMouseMove);
}
return () => {
if (currentCardRef) {
currentCardRef.removeEventListener('mousemove', handleMouseMove);
}
};
}, []);
return (
<div
ref={cardRef}
onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)}
className={cn(
'relative w-full h-full p-px rounded-2xl transition-all duration-300 ease-in-out',
'bg-neutral-900 hover:bg-neutral-800',
className
)}
style={{
background: isHovering
? `radial-gradient(var(--gradient-size, ${gradientSize}px) circle at var(--mouse-x) var(--mouse-y), var(--gradient-color, ${gradientColor}), transparent 100%)`
: 'transparent',
}}
>
<div className="relative w-full h-full bg-neutral-950/90 rounded-[15px] p-8">
{children}
</div>
</div>
);
};

View File

@@ -26,8 +26,11 @@ const CubeSvg: React.FC<React.SVGProps<SVGSVGElement> & { index: number }> = ({
<path
fill={`url(#cube-gradient-${index})`}
d="M491.651 144.747L287.198 227.339C265.219 236.22 241.783 236.22 219.802 227.339L15.3486 144.747C-5.11621 136.479 -5.11621 97.5191 15.3486 89.2539L219.802 6.65884C241.783 -2.21961 265.219 -2.21961 287.198 6.65884L491.651 89.2539C512.116 97.5191 512.116 136.479 491.651 144.747Z"
stroke="rgba(0,255,255,0.25)"
strokeWidth="0.5"
/>
<defs>
{/* Cyan-white soft gradient */}
<linearGradient
id={`cube-gradient-${index}`}
x1="185.298"
@@ -36,14 +39,24 @@ const CubeSvg: React.FC<React.SVGProps<SVGSVGElement> & { index: number }> = ({
y2="206.448"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#E5E7EB" />
<stop offset="1" stopColor="#9CA3AF" />
<stop offset="0%" stopColor="#DFFFFF" stopOpacity="0.75" />
<stop offset="40%" stopColor="#A5F4FF" stopOpacity="0.8" />
<stop offset="100%" stopColor="#FFFFFF" stopOpacity="0.9" />
</linearGradient>
</defs>
</svg>
);
export function CubeLight({ title, descriptionTitle, description, isActive, index, onHover, onLeave, onClick }: CubeProps) {
export function CubeLight({
title,
descriptionTitle,
description,
isActive,
index,
onHover,
onLeave,
onClick,
}: CubeProps) {
return (
<div className="relative flex flex-col items-center">
<motion.div
@@ -62,22 +75,34 @@ export function CubeLight({ title, descriptionTitle, description, isActive, inde
ease: "easeOut",
}}
>
{/* Glow aura behind cube */}
<div
className={`absolute inset-0 blur-3xl rounded-2xl transition-all duration-500 ${
isActive
? "bg-cyan-400/40 opacity-70"
: "bg-cyan-200/20 opacity-40"
}`}
/>
{/* SVG Cube */}
<CubeSvg
index={index}
className="w-48 sm:w-64 lg:w-80 h-auto drop-shadow-lg opacity-80"
className="w-48 sm:w-64 lg:w-80 h-auto relative"
style={{
filter: isActive ? 'brightness(1.1) drop-shadow(0 0 15px rgba(0, 0, 0, 0.2))' : 'brightness(1)',
filter: isActive
? "drop-shadow(0 0 25px rgba(0,255,255,0.4)) brightness(1.1)"
: "drop-shadow(0 0 10px rgba(0,255,255,0.15)) brightness(1)",
transition: "all 0.4s ease",
}}
/>
{/* Title overlay */}
<div className="absolute inset-0 flex items-center justify-center">
<h3
className="text-black text-sm lg:text-base font-medium text-center px-4 drop-shadow-sm"
className="text-cyan-900 text-sm lg:text-base font-medium text-center px-4"
style={{
transform: 'rotate(0deg) skewX(0deg)',
transformOrigin: 'center'
textShadow:
"0 0 15px rgba(255,255,255,0.8), 0 0 25px rgba(0,255,255,0.5)",
}}
>
{title}
@@ -106,26 +131,24 @@ export function CubeLight({ title, descriptionTitle, description, isActive, inde
y1="1"
x2="120"
y2="1"
stroke="black"
stroke="rgba(0,255,255,0.6)"
strokeWidth="1"
opacity="0.6"
opacity="0.8"
/>
</svg>
{/* Description text */}
<div className="ml-32 w-80">
<h4 className="text-black text-base font-semibold mb-2">
<h4 className="text-black text-base font-semibold mb-2 drop-shadow-[0_0_6px_rgba(255,255,255,0.6)]">
{descriptionTitle}
</h4>
<p className="text-gray-800 text-sm leading-relaxed font-light">
<p className="text-gray-800 text-sm leading-relaxed font-light drop-shadow-[0_0_4px_rgba(255,255,255,0.4)]">
{description}
</p>
</div>
</motion.div>
)}
{/* Description for Mobile - Below cube */}
</motion.div>
</motion.div>
</div>
);
}

View File

@@ -2,13 +2,14 @@
import { useState } from "react";
import { motion } from "framer-motion";
import { CubeLight } from "@/components/ui/CubeLight"
import { CubeLight } from "@/components/ui/CubeLight";
const stackData = [
{
id: "agent",
title: "Agent Layer",
descriptionTitle: "Your sovereign agent with private memory and permissioned data access—always under your control.",
descriptionTitle:
"Your sovereign agent with private memory and permissioned data access—always under your control.",
description:
"Choose from a wide library of open-source LLMs, paired with built-in semantic search and retrieval.\nIt coordinates across people, apps, and other agents to plan, create, and execute.\nIt operates inside a compliant legal & financial sandbox, ready for real-world transactions and operations.\nMore than just an assistant—an intelligent partner that learns and does your way.",
position: "top",
@@ -16,7 +17,8 @@ const stackData = [
{
id: "network",
title: "Network Layer",
descriptionTitle: "A global, end-to-end encrypted overlay that simply doesnt break.",
descriptionTitle:
"A global, end-to-end encrypted overlay that simply doesnt break.",
description:
"Shortest-path routing moves your traffic the fastest way, every time.\nInstant discovery with integrated DNS, semantic search, and indexing.\nA distributed CDN and edge delivery keep content available and tamper-resistant worldwide.\nBuilt-in tool services and secure coding sandboxes—seamless on phones, desktops, and edge.",
position: "middle",
@@ -24,7 +26,8 @@ const stackData = [
{
id: "cloud",
title: "Cloud Layer",
descriptionTitle: "An autonomous, stateless OS that enforces pre-deterministic deployments you define.",
descriptionTitle:
"An autonomous, stateless OS that enforces pre-deterministic deployments you define.",
description:
"Workloads are cryptographically bound to your private key—location and access are yours.\nNo cloud vendor or middleman in the path: end-to-end ownership and isolation by default.\nGeo-aware placement delivers locality, compliance, and ultra-low latency where it matters.\nEncrypted, erasure-coded storage, decentralized compute and GPU on demand—including LLMs.",
position: "bottom",
@@ -36,60 +39,74 @@ export function StackedCubesLight() {
const [selectedForMobile, setSelectedForMobile] = useState<string | null>("agent");
const handleCubeClick = (id: string) => {
setSelectedForMobile(prev => (prev === id ? null : id));
setSelectedForMobile((prev) => (prev === id ? null : id));
};
const selectedMobileLayer = stackData.find(layer => layer.id === selectedForMobile);
const selectedMobileLayer = stackData.find(
(layer) => layer.id === selectedForMobile
);
return (
<div className="flex flex-col items-center">
<div
className="relative w-full flex items-center justify-center lg:justify-center min-h-[450px] lg:min-h-[400px]"
onMouseLeave={() => setActive("agent")}
>
<motion.div
className="relative lg:pl-0 pl-6 h-[300px] lg:h-[400px] w-64 sm:w-80 lg:w-96 scale-120 lg:scale-100"
animate={{ y: ["-8px", "8px"] }}
transition={{
duration: 4,
repeat: Infinity,
repeatType: "reverse",
ease: "easeInOut",
}}
<div className="flex flex-col items-center relative">
{/* ✨ Ambient cyan-white gradient background */}
<div className="absolute inset-0 bg-gradient-to-b from-white via-cyan-50/40 to-white blur-3xl opacity-70 pointer-events-none" />
<div
className="relative w-full flex items-center justify-center lg:justify-center min-h-[450px] lg:min-h-[400px]"
onMouseLeave={() => setActive("agent")}
>
{stackData.map((layer, index) => (
<div
key={layer.id}
className="absolute"
style={{
top: `calc(${index * 30}% - ${index * 10}px)`,
zIndex: active === layer.id ? 20 : 10 - index,
}}
>
<CubeLight
title={layer.title}
descriptionTitle={layer.descriptionTitle}
description={layer.description}
isActive={active === layer.id}
index={index}
onHover={() => setActive(layer.id)}
onLeave={() => {}}
onClick={() => handleCubeClick(layer.id)}
/>
</div>
))}
</motion.div>
</div>
{selectedMobileLayer && (
<div className="lg:hidden w-full max-w-md p-6 -mt-8 bg-gray-200/50 rounded-lg">
<h4 className="text-black text-lg font-semibold mb-2 text-center">
{selectedMobileLayer.descriptionTitle}
</h4>
<p className="text-gray-700 text-sm leading-relaxed text-center">
{selectedMobileLayer.description}
</p>
<motion.div
className="relative lg:pl-0 pl-6 h-[300px] lg:h-[400px] w-64 sm:w-80 lg:w-96"
animate={{ y: ["-8px", "8px"] }}
transition={{
duration: 4,
repeat: Infinity,
repeatType: "reverse",
ease: "easeInOut",
}}
>
{stackData.map((layer, index) => (
<div
key={layer.id}
className="absolute transition-all duration-500"
style={{
top: `calc(${index * 30}% - ${index * 10}px)`,
zIndex: active === layer.id ? 20 : 10 - index,
}}
>
{/* 🌫 subtle glow behind each cube */}
<div
className={`absolute inset-0 blur-2xl rounded-3xl transition-all duration-500 ${
active === layer.id
? "bg-cyan-300/40 opacity-70"
: "bg-cyan-200/20 opacity-40"
}`}
/>
<CubeLight
title={layer.title}
descriptionTitle={layer.descriptionTitle}
description={layer.description}
isActive={active === layer.id}
index={index}
onHover={() => setActive(layer.id)}
onLeave={() => {}}
onClick={() => handleCubeClick(layer.id)}
/>
</div>
))}
</motion.div>
</div>
)}
{/* Mobile layer description */}
{selectedMobileLayer && (
<div className="lg:hidden w-full max-w-md p-6 -mt-8 bg-white/50 backdrop-blur-xl border border-cyan-100/40 rounded-xl shadow-[0_0_25px_rgba(0,255,255,0.15)]">
<h4 className="text-black text-lg font-semibold mb-2 text-center drop-shadow-[0_0_6px_rgba(255,255,255,0.6)]">
{selectedMobileLayer.descriptionTitle}
</h4>
<p className="text-cyan-900/80 text-sm leading-relaxed text-center drop-shadow-[0_0_4px_rgba(255,255,255,0.4)]">
{selectedMobileLayer.description}
</p>
</div>
)}
</div>
);
}

View File

@@ -0,0 +1,190 @@
"use client";
import { memo, useCallback, useEffect, useRef } from "react";
import { cn } from "@/lib/utils";
import { animate } from "motion/react";
interface GlowingEffectProps {
blur?: number;
inactiveZone?: number;
proximity?: number;
spread?: number;
variant?: "default" | "white";
glow?: boolean;
className?: string;
disabled?: boolean;
movementDuration?: number;
borderWidth?: number;
}
const GlowingEffect = memo(
({
blur = 0,
inactiveZone = 0.7,
proximity = 0,
spread = 20,
variant = "default",
glow = false,
className,
movementDuration = 2,
borderWidth = 1,
disabled = true,
}: GlowingEffectProps) => {
const containerRef = useRef<HTMLDivElement>(null);
const lastPosition = useRef({ x: 0, y: 0 });
const animationFrameRef = useRef<number>(0);
const handleMove = useCallback(
(e?: MouseEvent | { x: number; y: number }) => {
if (!containerRef.current) return;
if (animationFrameRef.current) {
cancelAnimationFrame(animationFrameRef.current);
}
animationFrameRef.current = requestAnimationFrame(() => {
const element = containerRef.current;
if (!element) return;
const { left, top, width, height } = element.getBoundingClientRect();
const mouseX = e?.x ?? lastPosition.current.x;
const mouseY = e?.y ?? lastPosition.current.y;
if (e) {
lastPosition.current = { x: mouseX, y: mouseY };
}
const center = [left + width * 0.5, top + height * 0.5];
const distanceFromCenter = Math.hypot(
mouseX - center[0],
mouseY - center[1]
);
const inactiveRadius = 0.5 * Math.min(width, height) * inactiveZone;
if (distanceFromCenter < inactiveRadius) {
element.style.setProperty("--active", "0");
return;
}
const isActive =
mouseX > left - proximity &&
mouseX < left + width + proximity &&
mouseY > top - proximity &&
mouseY < top + height + proximity;
element.style.setProperty("--active", isActive ? "1" : "0");
if (!isActive) return;
const currentAngle =
parseFloat(element.style.getPropertyValue("--start")) || 0;
let targetAngle =
(180 * Math.atan2(mouseY - center[1], mouseX - center[0])) /
Math.PI +
90;
const angleDiff = ((targetAngle - currentAngle + 180) % 360) - 180;
const newAngle = currentAngle + angleDiff;
animate(currentAngle, newAngle, {
duration: movementDuration,
ease: [0.16, 1, 0.3, 1],
onUpdate: (value) => {
element.style.setProperty("--start", String(value));
},
});
});
},
[inactiveZone, proximity, movementDuration]
);
useEffect(() => {
if (disabled) return;
const handleScroll = () => handleMove();
const handlePointerMove = (e: PointerEvent) => handleMove(e);
window.addEventListener("scroll", handleScroll, { passive: true });
document.body.addEventListener("pointermove", handlePointerMove, {
passive: true,
});
return () => {
if (animationFrameRef.current) {
cancelAnimationFrame(animationFrameRef.current);
}
window.removeEventListener("scroll", handleScroll);
document.body.removeEventListener("pointermove", handlePointerMove);
};
}, [handleMove, disabled]);
return (
<>
<div
className={cn(
"pointer-events-none absolute -inset-px hidden rounded-[inherit] border opacity-0 transition-opacity",
glow && "opacity-100",
variant === "white" && "border-white",
disabled && "!block"
)}
/>
<div
ref={containerRef}
style={
{
"--blur": `${blur}px`,
"--spread": spread,
"--start": "0",
"--active": "0",
"--glowingeffect-border-width": `${borderWidth}px`,
"--repeating-conic-gradient-times": "5",
"--gradient":
variant === "white"
? `repeating-conic-gradient(
from 236.84deg at 50% 50%,
var(--black),
var(--black) calc(25% / var(--repeating-conic-gradient-times))
)`
: `radial-gradient(circle, #dd7bbb 10%, #dd7bbb00 20%),
radial-gradient(circle at 40% 40%, #d79f1e 5%, #d79f1e00 15%),
radial-gradient(circle at 60% 60%, #5a922c 10%, #5a922c00 20%),
radial-gradient(circle at 40% 60%, #4c7894 10%, #4c789400 20%),
repeating-conic-gradient(
from 236.84deg at 50% 50%,
#dd7bbb 0%,
#d79f1e calc(25% / var(--repeating-conic-gradient-times)),
#5a922c calc(50% / var(--repeating-conic-gradient-times)),
#4c7894 calc(75% / var(--repeating-conic-gradient-times)),
#dd7bbb calc(100% / var(--repeating-conic-gradient-times))
)`,
} as React.CSSProperties
}
className={cn(
"pointer-events-none absolute inset-0 rounded-[inherit] opacity-100 transition-opacity",
glow && "opacity-100",
blur > 0 && "blur-[var(--blur)] ",
className,
disabled && "!hidden"
)}
>
<div
className={cn(
"glow",
"rounded-[inherit]",
'after:content-[""] after:rounded-[inherit] after:absolute after:inset-[calc(-1*var(--glowingeffect-border-width))]',
"after:[border:var(--glowingeffect-border-width)_solid_transparent]",
"after:[background:var(--gradient)] after:[background-attachment:fixed]",
"after:opacity-[var(--active)] after:transition-opacity after:duration-300",
"after:[mask-clip:padding-box,border-box]",
"after:[mask-composite:intersect]",
"after:[mask-image:linear-gradient(#0000,#0000),conic-gradient(from_calc((var(--start)-var(--spread))*1deg),#00000000_0deg,#fff,#00000000_calc(var(--spread)*2deg))]"
)}
/>
</div>
</>
);
}
);
GlowingEffect.displayName = "GlowingEffect";
export { GlowingEffect };

View File

@@ -4,6 +4,7 @@ import { Globe } from "@/components/ui/Globe"
import { motion } from "framer-motion"
import { P, CT, CP, SectionHeader, Eyebrow } from "@/components/Texts"
import { CountUpNumber } from '@/components/CountUpNumber'
import { MagicCard } from '@/components/magicui/magic-card'
export function WorldMap() {
return (
@@ -62,13 +63,18 @@ export function WorldMap() {
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true, amount: 0.3 }}
transition={{ duration: 0.5, delay: 0.4, ease: "easeOut" }}
className="lg:absolute lg:top-12 lg:-left-12 w-80 rounded-2xl border border-gray-300 p-8 transition-all duration-300 ease-in-out hover:scale-105 hover:border-cyan-500 hover:shadow-lg hover:shadow-cyan-500/20 bg-white/5 backdrop-blur-md"
className="lg:absolute lg:top-12 lg:-left-12 w-80"
>
<div><CT color="light" className="uppercase tracking-wide">CORES</CT></div>
<div><CountUpNumber end={54958} className="mt-2 text-3xl font-bold text-white" /></div>
<CP color="light" className="mt-2 text-sm">
Total Central Processing Unit Cores available on the grid.
</CP>
<MagicCard
gradientColor="#334155"
className="shadow-xl shadow-cyan-500/15 border border-gray-500/50 transition-all duration-300 ease-in-out hover:scale-105 hover:border-cyan-500 hover:shadow-xl hover:shadow-cyan-500/20"
>
<div><CT color="light" className="uppercase tracking-wide [text-shadow:0_0_12px_var(--color-cyan-500)]">CORES</CT></div>
<div><CountUpNumber end={54958} className="mt-2 text-3xl font-bold text-white [text-shadow:0_0_12px_var(--color-cyan-500)]" /></div>
<CP color="light" className="mt-2 text-sm">
Total Central Processing Unit Cores available on the grid.
</CP>
</MagicCard>
</motion.div>
<motion.div
@@ -76,13 +82,18 @@ export function WorldMap() {
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true, amount: 0.3 }}
transition={{ duration: 0.5, delay: 0.5, ease: "easeOut" }}
className="lg:absolute lg:-top-10 lg:right-0 w-80 rounded-2xl border border-gray-300 p-8 transition-all duration-300 ease-in-out hover:scale-105 hover:border-cyan-500 hover:shadow-lg hover:shadow-cyan-500/20 bg-white/5 backdrop-blur-md"
className="lg:absolute lg:-top-10 lg:right-0 w-80"
>
<div><CT color="light" className="uppercase tracking-wide">NODES</CT></div>
<div><CountUpNumber end={1493} className="mt-4 text-3xl font-bold text-white" /></div>
<CP color="light" className="mt-2 text-sm">
Total number of nodes on the grid.
</CP>
<MagicCard
gradientColor="#334155"
className="shadow-xl shadow-cyan-500/15 border border-gray-500/50 transition-all duration-300 ease-in-out hover:scale-105 hover:border-cyan-500 hover:shadow-xl hover:shadow-cyan-500/20"
>
<div><CT color="light" className="uppercase tracking-wide [text-shadow:0_0_12px_var(--color-cyan-500)]">NODES</CT></div>
<div><CountUpNumber end={1493} className="mt-4 text-3xl font-bold text-white [text-shadow:0_0_12px_var(--color-cyan-500)]" /></div>
<CP color="light" className="mt-2 text-sm">
Total number of nodes on the grid.
</CP>
</MagicCard>
</motion.div>
<motion.div
@@ -90,13 +101,18 @@ export function WorldMap() {
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true, amount: 0.3 }}
transition={{ duration: 0.5, delay: 0.6, ease: "easeOut" }}
className="lg:absolute lg:bottom-28 lg:-left-12 w-80 rounded-2xl border border-gray-300 p-8 transition-all duration-300 ease-in-out hover:scale-105 hover:border-cyan-500 hover:shadow-lg hover:shadow-cyan-500/20 bg-white/5 backdrop-blur-md"
className="lg:absolute lg:bottom-28 lg:-left-12 w-80"
>
<div><CT color="light" className="uppercase tracking-wide">SSD CAPACITY</CT></div>
<div><CountUpNumber end={5388956} className="mt-2 text-3xl font-bold text-white" /></div>
<CP color="light" className="mt-2 text-sm">
Total GB amount of storage (SSD, HDD, & RAM) on the grid.
</CP>
<MagicCard
gradientColor="#334155"
className="shadow-xl shadow-cyan-500/15 border border-gray-500/50 transition-all duration-300 ease-in-out hover:scale-105 hover:border-cyan-500 hover:shadow-xl hover:shadow-cyan-500/20"
>
<div><CT color="light" className="uppercase tracking-wide [text-shadow:0_0_12px_var(--color-cyan-500)]">SSD CAPACITY</CT></div>
<div><CountUpNumber end={5388956} className="mt-2 text-3xl font-bold text-white [text-shadow:0_0_12px_var(--color-cyan-500)]" /></div>
<CP color="light" className="mt-2 text-sm">
Total GB amount of storage (SSD, HDD, & RAM) on the grid.
</CP>
</MagicCard>
</motion.div>
<motion.div
@@ -104,13 +120,18 @@ export function WorldMap() {
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true, amount: 0.3 }}
transition={{ duration: 0.5, delay: 0.7, ease: "easeOut" }}
className="lg:absolute lg:top-47 lg:right-0 w-80 rounded-2xl border border-gray-300 p-8 transition-all duration-300 ease-in-out hover:scale-105 hover:border-cyan-500 hover:shadow-lg hover:shadow-cyan-500/20 bg-white/5 backdrop-blur-md"
className="lg:absolute lg:top-47 lg:right-0 w-80"
>
<div><CT color="light" className="uppercase tracking-wide">COUNTRIES</CT></div>
<div><CountUpNumber end={44} className="mt-2 text-3xl font-bold text-white" /></div>
<CP color="light" className="mt-2 text-sm">
Total number of countries with active nodes.
</CP>
<MagicCard
gradientColor="#334155"
className="shadow-xl shadow-cyan-500/15 border border-gray-500/50 transition-all duration-300 ease-in-out hover:scale-105 hover:border-cyan-500 hover:shadow-xl hover:shadow-cyan-500/20"
>
<div><CT color="light" className="uppercase tracking-wide [text-shadow:0_0_12px_var(--color-cyan-500)]">COUNTRIES</CT></div>
<div><CountUpNumber end={44} className="mt-2 text-3xl font-bold text-white [text-shadow:0_0_12px_var(--color-cyan-500)]" /></div>
<CP color="light" className="mt-2 text-sm">
Total number of countries with active nodes.
</CP>
</MagicCard>
</motion.div>
</div>
</div>

View File

@@ -4,25 +4,32 @@ import { motion } from "framer-motion";
import { StackedCubesLight } from "@/components/ui/StackedCubesLight";
import { P, SectionHeader, Eyebrow } from "@/components/Texts";
import { FadeIn } from "@/components/ui/FadeIn";
import { DottedGlowBackground } from '@/components/ui/dotted-glow-background';
export function StackSectionLight() {
return (
<section className="relative w-full overflow-hidden py-24 lg:py-40">
{/* === Background Layer === */}
<div className="absolute inset-0 -z-10 bg-transparent">
{/* Dotted Glow Background */}
<DottedGlowBackground
gap={15}
radius={2}
color="rgba(0,0,0,0.4)"
glowColor="rgba(0,170,255,0.85)"
opacity={0.2}
{/* === Center Radial Glow Aura === */}
<motion.div
className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[1200px] h-[1200px] rounded-full pointer-events-none"
style={{
background:
"radial-gradient(circle, rgba(173,255,255,0.5) 0%, rgba(0,220,255,0.3) 30%, rgba(255,255,255,0) 70%)",
filter: "blur(120px)",
}}
animate={{
opacity: [0.6, 0.8, 0.6],
scale: [1, 1.05, 1],
}}
transition={{
duration: 8,
repeat: Infinity,
ease: "easeInOut",
}}
/>
{/* Faint 3D grid floor */}
<div className="absolute inset-0 flex items-end justify-center overflow-hidden">
<div className="w-[200vw] h-[200vh] bg-[linear-gradient(to_right,rgba(0,0,0,0.03)_1px,transparent_1px),linear-gradient(to_bottom,rgba(0,0,0,0.03)_1px,transparent_1px)] bg-[size:60px_60px] [transform:perspective(800px)_rotateX(70deg)] origin-bottom opacity-50" />
</div>
</div>
{/* === Content === */}