8 Commits

49 changed files with 2441 additions and 120 deletions

25
components.json Normal file
View File

@@ -0,0 +1,25 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/styles/tailwind.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {
"@aceternity": "https://ui.aceternity.com/registry/{name}.json",
"@magicui": "https://magicui.design/r/{name}.json"
}
}

View File

@@ -8,12 +8,6 @@
<meta name="description" content="Discover Mycelium, an end-to-end encrypted IPv6 overlay network. The future of secure, efficient, and scalable networking." /> <meta name="description" content="Discover Mycelium, an end-to-end encrypted IPv6 overlay network. The future of secure, efficient, and scalable networking." />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<style>
:root {
--font-inter: 'Inter', sans-serif;
}
</style>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

718
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -13,6 +13,8 @@
"@headlessui/react": "^2.2.9", "@headlessui/react": "^2.2.9",
"@heroicons/react": "^2.2.0", "@heroicons/react": "^2.2.0",
"@lobehub/icons": "^1.97.2", "@lobehub/icons": "^1.97.2",
"@react-three/drei": "^9.89.2",
"@react-three/fiber": "^8.15.12",
"@tabler/icons-react": "^3.35.0", "@tabler/icons-react": "^3.35.0",
"@tailwindcss/forms": "^0.5.10", "@tailwindcss/forms": "^0.5.10",
"@types/node": "^20.19.23", "@types/node": "^20.19.23",
@@ -22,10 +24,12 @@
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cobe": "^0.6.5", "cobe": "^0.6.5",
"dotted-map": "^2.2.3",
"framer-motion": "^10.18.0", "framer-motion": "^10.18.0",
"lucide-react": "^0.544.0", "lucide-react": "^0.544.0",
"motion": "^12.23.24", "motion": "^12.23.24",
"next": "^14.2.33", "next": "^14.2.33",
"next-themes": "^0.4.6",
"popmotion": "^11.0.5", "popmotion": "^11.0.5",
"react": "^18.3.1", "react": "^18.3.1",
"react-countup": "^6.5.3", "react-countup": "^6.5.3",
@@ -35,11 +39,13 @@
"react-type-animation": "^3.2.0", "react-type-animation": "^3.2.0",
"tailwind-merge": "^3.3.1", "tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.15", "tailwindcss": "^4.1.15",
"three": "^0.151.0",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"use-debounce": "^10.0.6" "use-debounce": "^10.0.6"
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/postcss": "^4.1.15", "@tailwindcss/postcss": "^4.1.15",
"@types/three": "^0.151.0",
"@vitejs/plugin-react": "^5.0.4", "@vitejs/plugin-react": "^5.0.4",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"eslint": "^8.57.1", "eslint": "^8.57.1",

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 KiB

BIN
public/images/cloud.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
public/images/cloud1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 757 KiB

BIN
public/images/cloudimg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1024 KiB

BIN
public/images/mchip.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 KiB

View File

@@ -214,7 +214,7 @@
</filter> </filter>
<radialGradient id="b" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" <radialGradient id="b" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0 727 -642 0 184 1)"> gradientTransform="matrix(0 727 -642 0 184 1)">
<stop stop-color="#FAFAFA" /> <stop stop-color="#FFFFFF" />
<stop offset="1" stop-color="#E6E6E6" /> <stop offset="1" stop-color="#E6E6E6" />
</radialGradient> </radialGradient>
<radialGradient id="c" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" <radialGradient id="c" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse"

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/videos/cloud.mp4 Normal file

Binary file not shown.

View File

@@ -1,12 +1,13 @@
import { useRef } from 'react' import { useRef } from 'react'
import { motion, useInView } from 'framer-motion' import { motion, useInView } from 'framer-motion'
export function AnimatedSection({ children }: { children: React.ReactNode }) { export function AnimatedSection({ children, id }: { children: React.ReactNode; id?: string }) {
const ref = useRef(null) const ref = useRef(null)
const isInView = useInView(ref, { once: true, margin: '-20% 0px -20% 0px' }) const isInView = useInView(ref, { once: true, margin: '-20% 0px -20% 0px' })
return ( return (
<motion.section <motion.section
id={id}
ref={ref} ref={ref}
initial={{ opacity: 0, y: 50 }} initial={{ opacity: 0, y: 50 }}
animate={{ animate={{

View File

@@ -3,9 +3,9 @@ import clsx from 'clsx'
const baseStyles = { const baseStyles = {
solid: solid:
'inline-flex justify-center rounded-lg py-2 px-3 text-sm font-semibold transition-colors', 'inline-flex justify-center rounded-full py-2 px-4 text-sm font-semibold transition-colors',
outline: outline:
'inline-flex justify-center rounded-lg border py-[calc(--spacing(2)-1px)] px-[calc(--spacing(3)-1px)] text-sm transition-colors', 'inline-flex justify-center rounded-full border py-[calc(--spacing(2)-1px)] px-[calc(--spacing(4)-1px)] text-sm transition-colors',
} }
const variantStyles = { const variantStyles = {

View File

@@ -1,44 +1,67 @@
'use client'
import { useEffect, useRef, useState } from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { Container } from './Container' import { AnimatePresence, motion } from 'framer-motion'
import clsx from 'clsx'
import { Button } from './Button' import { Button } from './Button'
export function Header() {
function NavLinks() {
let [hoveredIndex, setHoveredIndex] = useState<number | null>(null)
let timeoutRef = useRef<number | null>(null)
return ( return (
<header> <div className="flex items-center gap-x-5">
<nav>
<Container className="relative z-50 flex justify-between py-8">
<div className="relative z-10 flex items-center gap-16">
<Link to="/" aria-label="Home"> <Link to="/" aria-label="Home">
<img src="/src/images/logomark.svg" alt="Mycelium" className="h-10 w-auto" /> <img src="/src/images/logomark.svg" alt="Mycelium" className="h-10 w-auto" />
</Link> </Link>
<div className="hidden lg:flex lg:gap-10"> <div className="flex items-center gap-x-5 border-l border-white/10 pl-5">
{[
['Home', '/'],
['Cloud', '/cloud'],
['Network', '/network'],
['Agents', '/agents'],
].map(([label, href], index) => (
<Link <Link
to="/" key={label}
className="text-base/7 tracking-tight text-gray-700 hover:text-cyan-500 transition-colors" to={href}
className={clsx(
'relative rounded-lg px-3 py-2 text-sm text-black transition-colors delay-150 hover:text-cyan-500 hover:delay-0',
)}
onMouseEnter={() => {
if (timeoutRef.current) {
window.clearTimeout(timeoutRef.current)
}
setHoveredIndex(index)
}}
onMouseLeave={() => {
timeoutRef.current = window.setTimeout(() => {
setHoveredIndex(null)
}, 200)
}}
> >
Home <AnimatePresence>
</Link> {hoveredIndex === index && (
<Link <motion.span
to="/cloud" className="absolute inset-0 rounded-lg bg-white/10"
className="text-base/7 tracking-tight text-gray-700 hover:text-cyan-500 transition-colors" layoutId="hoverBackground"
> initial={{ opacity: 0 }}
Cloud animate={{ opacity: 1, transition: { duration: 0.15 } }}
</Link> exit={{
<Link opacity: 0,
to="/network" transition: { duration: 0.15 },
className="text-base/7 tracking-tight text-gray-700 hover:text-cyan-500 transition-colors" }}
> />
Network )}
</Link> </AnimatePresence>
<Link <span className="relative z-10">{label}</span>
to="/agents"
className="text-base/7 tracking-tight text-gray-700 hover:text-cyan-500 transition-colors"
>
Agents
</Link> </Link>
))}
</div> </div>
</div> <div className="flex items-center gap-8">
<div className="flex items-center gap-6">
<div className="flex items-center gap-6 max-lg:hidden"> <div className="flex items-center gap-6 max-lg:hidden">
<Button <Button
to="https://threefold.info/mycelium_network/docs/" to="https://threefold.info/mycelium_network/docs/"
@@ -54,8 +77,48 @@ export function Header() {
</Button> </Button>
</div> </div>
</div> </div>
</Container> </div>
</nav> )
</header> }
export function Header() {
const [isVisible, setIsVisible] = useState(true);
const [lastScrollY, setLastScrollY] = useState(0);
const controlHeader = () => {
if (typeof window !== 'undefined') {
if (window.scrollY > lastScrollY && window.scrollY > 100) { // Hides when scrolling down past 100px
setIsVisible(false);
} else { // Shows when scrolling up
setIsVisible(true);
}
setLastScrollY(window.scrollY);
}
};
useEffect(() => {
if (typeof window !== 'undefined') {
window.addEventListener('scroll', controlHeader);
return () => {
window.removeEventListener('scroll', controlHeader);
};
}
}, [lastScrollY]);
return (
<motion.header
className="fixed top-4 left-0 right-0 z-50 flex justify-center"
initial={{ y: 0, opacity: 1 }}
animate={{ y: isVisible ? 0 : -100, opacity: isVisible ? 1 : 0 }}
transition={{ duration: 0.3, ease: 'easeInOut' }}
>
<div className="rounded-full bg-white/10 px-5 py-3 shadow-lg ring-1 ring-white/10 backdrop-blur-sm">
<NavLinks />
</div>
</motion.header>
) )
} }

View File

@@ -1,10 +1,18 @@
import { Outlet } from 'react-router-dom' import { Outlet } from 'react-router-dom'
import { Header } from './Header' import { FloatingNav } from './ui/floating-navbar'
import { Footer } from './Footer' import { Footer } from './Footer'
import { Header } from './Header'
export function Layout() { export function Layout() {
const navItems = [
{ name: 'Home', link: '/' },
{ name: 'Cloud', link: '/cloud' },
{ name: 'Network', link: '/network' },
{ name: 'Agents', link: '/agents' },
];
return ( return (
<div className="bg-gray-50 antialiased" style={{ fontFamily: 'var(--font-inter)' }}> <div className="bg-white antialiased" style={{ fontFamily: 'var(--font-inter)' }}>
<Header /> <Header />
<main> <main>
<Outlet /> <Outlet />

View File

@@ -0,0 +1,22 @@
'use client'
import { ChevronDown } from 'lucide-react'
export function ScrollDownArrow() {
const scrollToNextSection = () => {
const nextSection = document.querySelector('#next-section') // Assuming the next section has this id
if (nextSection) {
nextSection.scrollIntoView({ behavior: 'smooth' })
}
}
return (
<button
onClick={scrollToNextSection}
className="animate-bounce text-gray-500 hover:text-gray-700"
aria-label="Scroll to next section"
>
<ChevronDown size={32} />
</button>
)
}

View File

@@ -3,6 +3,11 @@
import React from 'react' import React from 'react'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
const fontVariants = {
sans: 'font-sans',
neuton: 'font-neuton',
} as const
const colorVariants = { const colorVariants = {
primary: 'text-gray-900', primary: 'text-gray-900',
secondary: 'text-gray-600', secondary: 'text-gray-600',
@@ -15,6 +20,7 @@ const colorVariants = {
} as const } as const
type TextOwnProps = { type TextOwnProps = {
font?: keyof typeof fontVariants
color?: keyof typeof colorVariants color?: keyof typeof colorVariants
className?: string className?: string
} }
@@ -34,6 +40,7 @@ const createTextComponent = <DefaultElement extends React.ElementType>(
> >
function Text<E extends React.ElementType = DefaultElement>({ function Text<E extends React.ElementType = DefaultElement>({
font = 'sans',
as, as,
color = 'primary', color = 'primary',
className, className,
@@ -43,7 +50,12 @@ const createTextComponent = <DefaultElement extends React.ElementType>(
const Tag = (as || defaultElement) as React.ElementType const Tag = (as || defaultElement) as React.ElementType
return ( return (
<Tag <Tag
className={cn(defaultClassName, colorVariants[color], className)} className={cn(
defaultClassName,
fontVariants[font],
colorVariants[color],
className
)}
{...props} {...props}
> >
{children} {children}
@@ -87,7 +99,7 @@ export const Subtle = createTextComponent(
) )
export const H5 = createTextComponent( export const H5 = createTextComponent(
'h5', 'h5',
'text-xl lg:text-2xl font-semibold leading-snug tracking-tight' 'text-xl lg:text-2xl font-light leading-snug tracking-normal'
) )
export const Eyebrow = createTextComponent( export const Eyebrow = createTextComponent(
'h2', 'h2',

View File

@@ -0,0 +1,81 @@
"use client";
import * as THREE from "three";
import { Canvas, useFrame } from "@react-three/fiber";
import { OrbitControls, useTexture } from "@react-three/drei";
import { useRef } from "react";
function Globe() {
const groupRef = useRef<THREE.Group>(null);
const cloudTexture = useTexture("/images/cloud1.png");
// Rotate the globe slowly
useFrame(() => {
if (groupRef.current) {
groupRef.current.rotation.y += 0.002;
}
});
// Coordinates for markers (half-globe)
const points = [
[0, 1, 0],
[0.7, 0.5, 0.2],
[-0.5, 0.4, 0.5],
[0.4, 0.3, -0.7],
[-0.6, -0.1, 0.3],
[0.3, -0.2, 0.8],
];
return (
<group ref={groupRef}>
{/* Cyan arcs */}
{Array.from({ length: 8 }).map((_, i) => {
const radius = 2.5;
const curve = new THREE.EllipseCurve(
0,
0,
radius,
radius / 2,
0,
Math.PI,
false,
0
);
const points = curve.getPoints(100);
const geometry = new THREE.BufferGeometry().setFromPoints(
points.map((p) => new THREE.Vector3(p.x, Math.sin(p.x / radius) * 0.5, p.y))
);
return (
<line key={i} geometry={geometry}>
<lineBasicMaterial color="#00e5ff" linewidth={1} transparent opacity={0.5} />
</line>
);
})}
{/* Cloud markers */}
{points.map(([x, y, z], i) => (
<mesh key={i} position={[x * 2.5, y * 2.5, z * 2.5]}>
<planeGeometry args={[0.3, 0.3]} />
<meshBasicMaterial
map={cloudTexture}
transparent
opacity={1}
side={THREE.DoubleSide}
/>
</mesh>
))}
</group>
);
}
export function HalfGlobe() {
return (
<div className="w-full h-[500px] bg-white flex items-center justify-center">
<Canvas camera={{ position: [0, 1.5, 4], fov: 45 }}>
<ambientLight intensity={0.8} />
<Globe />
<OrbitControls enableZoom={false} enablePan={false} />
</Canvas>
</div>
);
}

View File

@@ -13,7 +13,7 @@ export function ScrollDown() {
return ( return (
<button <button
onClick={scrollToNext} onClick={scrollToNext}
className="fixed bottom-8 right-8 z-50 flex items-center gap-x-2 text-2xl font-medium text-white lg:text-3xl animate-blink" className="fixed bottom-8 right-8 z-50 flex items-center gap-x-2 rounded-full bg-black/20 p-2 text-2xl font-medium text-white backdrop-blur-sm lg:text-3xl animate-blink"
> >
<span>scroll</span> <span>scroll</span>
<ChevronDoubleDownIcon className="h-6 w-6" /> <ChevronDoubleDownIcon className="h-6 w-6" />

View File

@@ -13,7 +13,7 @@ export function ScrollUp() {
return ( return (
<button <button
onClick={scrollToTop} onClick={scrollToTop}
className="fixed bottom-8 right-8 z-50 flex items-center gap-x-2 text-2xl font-medium text-[#1c1c49] lg:text-3xl animate-blink" className="fixed bottom-8 right-8 z-50 flex items-center gap-x-2 rounded-full bg-white/20 p-2 text-2xl font-medium text-[#1c1c49] backdrop-blur-sm lg:text-3xl animate-blink"
> >
<span>top</span> <span>top</span>
<ChevronDoubleUpIcon className="h-6 w-6" /> <ChevronDoubleUpIcon className="h-6 w-6" />

View File

@@ -0,0 +1,64 @@
"use client";
import { cn } from "@/lib/utils";
import React, { ReactNode } from "react";
interface AuroraBackgroundProps extends React.HTMLProps<HTMLDivElement> {
children: ReactNode;
showRadialGradient?: boolean;
}
export const AuroraBackground = ({
className,
children,
showRadialGradient = true,
...props
}: AuroraBackgroundProps) => {
return (
<main>
<div
className={cn(
"transition-bg relative flex h-[110vh] flex-col items-center justify-center bg-cover bg-center",
className
)}
style={{
backgroundImage: "url('/images/mchip.webp')",
}}
{...props}
>
<div
className="absolute inset-0 overflow-hidden"
style={
{
"--aurora":
"repeating-linear-gradient(100deg,#3b82f6_10%,#a5b4fc_15%,#93c5fd_20%,#ddd6fe_25%,#60a5fa_30%)",
"--dark-gradient":
"repeating-linear-gradient(100deg,#000_0%,#000_7%,transparent_10%,transparent_12%,#000_16%)",
"--white-gradient":
"repeating-linear-gradient(100deg,#fff_0%,#fff_7%,transparent_10%,transparent_12%,#fff_16%)",
"--blue-300": "#93c5fd",
"--blue-400": "#60a5fa",
"--blue-500": "#3b82f6",
"--indigo-300": "#a5b4fc",
"--violet-200": "#ddd6fe",
"--black": "#000",
"--white": "#fff",
"--transparent": "transparent",
} as React.CSSProperties
}
>
<div
// I'm sorry but this is what peak developer performance looks like // trigger warning
className={cn(
`after:animate-aurora pointer-events-none absolute -inset-[10px] [background-image:var(--white-gradient),var(--aurora)] [background-size:300%,_200%] [background-position:50%_50%,50%_50%] opacity-50 blur-[10px] invert filter will-change-transform [--aurora:repeating-linear-gradient(100deg,var(--blue-500)_10%,var(--indigo-300)_15%,var(--blue-300)_20%,var(--violet-200)_25%,var(--blue-400)_30%)] [--dark-gradient:repeating-linear-gradient(100deg,var(--black)_0%,var(--black)_7%,var(--transparent)_10%,var(--transparent)_12%,var(--black)_16%)] [--white-gradient:repeating-linear-gradient(100deg,var(--white)_0%,var(--white)_7%,var(--transparent)_10%,var(--transparent)_12%,var(--white)_16%)] after:absolute after:inset-0 after:[background-image:var(--white-gradient),var(--aurora)] after:[background-size:200%,_100%] after:[background-attachment:fixed] after:mix-blend-difference after:content-[""] dark:[background-image:var(--dark-gradient),var(--aurora)] dark:invert-0 after:dark:[background-image:var(--dark-gradient),var(--aurora)]`,
showRadialGradient &&
`[mask-image:radial-gradient(ellipse_at_100%_0%,black_10%,var(--transparent)_70%)]`,
)}
></div>
</div>
{children}
</div>
</main>
);
};

View File

@@ -0,0 +1,106 @@
"use client";
import { useMotionValue } from "motion/react";
import React, { useState, useEffect } from "react";
import { useMotionTemplate, motion } from "motion/react";
import { cn } from "@/lib/utils";
export const EvervaultCard = ({
children,
className,
}: {
children?: React.ReactNode;
className?: string;
}) => {
let mouseX = useMotionValue(0);
let mouseY = useMotionValue(0);
const [randomString, setRandomString] = useState("");
useEffect(() => {
let str = generateRandomString(1500);
setRandomString(str);
}, []);
function onMouseMove({ currentTarget, clientX, clientY }: any) {
let { left, top } = currentTarget.getBoundingClientRect();
mouseX.set(clientX - left);
mouseY.set(clientY - top);
const str = generateRandomString(1500);
setRandomString(str);
}
return (
<div
className={cn(
"p-0.5 bg-transparent aspect-square flex items-center justify-center w-full h-full relative",
className
)}
>
<div
onMouseMove={onMouseMove}
className="group/card rounded-3xl w-full relative overflow-hidden bg-transparent flex items-center justify-center h-full"
>
<CardPattern
mouseX={mouseX}
mouseY={mouseY}
randomString={randomString}
/>
<div className="relative z-10 flex items-center justify-center">
<div className="relative p-4">
{children}
</div>
</div>
</div>
</div>
);
};
export function CardPattern({ mouseX, mouseY, randomString }: any) {
let maskImage = useMotionTemplate`radial-gradient(250px at ${mouseX}px ${mouseY}px, white, transparent)`;
let style = { maskImage, WebkitMaskImage: maskImage };
return (
<div className="pointer-events-none">
<div className="absolute inset-0 rounded-2xl [mask-image:linear-gradient(white,transparent)] group-hover/card:opacity-50"></div>
<motion.div
className="absolute inset-0 rounded-2xl bg-gradient-to-r from-green-500 to-blue-700 opacity-0 group-hover/card:opacity-100 backdrop-blur-xl transition duration-500"
style={style}
/>
<motion.div
className="absolute inset-0 rounded-2xl opacity-0 mix-blend-overlay group-hover/card:opacity-100"
style={style}
>
<p className="absolute inset-x-0 text-xs h-full break-words whitespace-pre-wrap text-white font-mono font-bold transition duration-500">
{randomString}
</p>
</motion.div>
</div>
);
}
const characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
export const generateRandomString = (length: number) => {
let result = "";
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
};
export const Icon = ({ className, ...rest }: any) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="1.5"
stroke="currentColor"
className={className}
{...rest}
>
<path strokeLinecap="round" strokeLinejoin="round" d="M12 6v12m6-6H6" />
</svg>
);
};

View File

@@ -0,0 +1,90 @@
"use client";
import { useState } from "react";
import {
motion,
AnimatePresence,
useScroll,
useMotionValueEvent,
} from "motion/react";
import { Link } from "react-router-dom";
import { cn } from "@/lib/utils";
import { Button } from "../Button";
export const FloatingNav = ({
navItems,
className,
}: {
navItems: {
name: string;
link: string;
icon?: JSX.Element;
}[];
className?: string;
}) => {
const { scrollYProgress } = useScroll();
const [visible, setVisible] = useState(true);
useMotionValueEvent(scrollYProgress, "change", (current) => {
if (typeof current === "number") {
const previous = scrollYProgress.getPrevious();
// Check if previous is a number to avoid errors
if (typeof previous === "number" && current > previous) {
setVisible(false); // Scrolling down
} else {
setVisible(true); // Scrolling up or at the top
}
}
});
return (
<AnimatePresence mode="wait">
<motion.div
initial={{
opacity: 1,
y: -100,
}}
animate={{
y: visible ? 0 : -100,
opacity: visible ? 1 : 0,
}}
transition={{
duration: 0.2,
}}
className={cn(
"flex max-w-fit fixed top-10 inset-x-0 mx-auto border border-transparent dark:border-white/[0.2] rounded-xl dark:bg-black bg-gray-700/50 shadow-[0px_2px_3px_-1px_rgba(0,0,0,0.1),0px_1px_0px_0px_rgba(25,28,33,0.02),0px_0px_0px_1px_rgba(25,28,33,0.08)] z-[5000] pr-4 pl-8 py-2 items-center justify-center space-x-12",
className
)}
>
{navItems.map((navItem, idx: number) => (
<Link
key={`link=${idx}`}
to={navItem.link}
className={cn(
"relative dark:text-neutral-50 items-center flex space-x-1 text-neutral-200 dark:hover:text-neutral-300 hover:text-cyan-500"
)}
>
<span className="block sm:hidden">{navItem.icon}</span>
<span className="hidden sm:block text-sm">{navItem.name}</span>
</Link>
))}
<div className="flex items-center gap-6">
<a
href="https://threefold.info/mycelium_network/docs/"
target="_blank"
rel="noopener noreferrer"
className={cn(
"relative dark:text-neutral-50 items-center flex space-x-1 text-neutral-200 dark:hover:text-neutral-300 hover:text-cyan-500"
)}
>
<span className="hidden sm:block text-sm">Docs</span>
</a>
<Button to="/download" variant="solid" color="cyan">
Get Mycelium
</Button>
</div>
</motion.div>
</AnimatePresence>
);
};

View File

@@ -0,0 +1,158 @@
"use client";
import React, { useEffect, useRef, useState } from "react";
import { AnimatePresence, motion } from "motion/react";
import { cn } from "@/lib/utils";
export const GlowingStarsBackgroundCard = ({
className,
children,
}: {
className?: string;
children?: React.ReactNode;
}) => {
const [mouseEnter, setMouseEnter] = useState(false);
return (
<div
onMouseEnter={() => {
setMouseEnter(true);
}}
onMouseLeave={() => {
setMouseEnter(false);
}}
className={cn(
"bg-[linear-gradient(110deg,#333_0.6%,#222)] p-4 max-w-md max-h-[20rem] h-full w-full rounded-xl border border-[#eaeaea] dark:border-neutral-600",
className
)}
>
<div className="flex justify-center items-center">
<Illustration mouseEnter={mouseEnter} />
</div>
<div className="px-2 pb-6">{children}</div>
</div>
);
};
export const GlowingStarsDescription = ({
className,
children,
}: {
className?: string;
children?: React.ReactNode;
}) => {
return (
<p className={cn("text-base text-white max-w-[16rem]", className)}>
{children}
</p>
);
};
export const GlowingStarsTitle = ({
className,
children,
}: {
className?: string;
children?: React.ReactNode;
}) => {
return (
<h2 className={cn("font-bold text-2xl text-[#eaeaea]", className)}>
{children}
</h2>
);
};
export const Illustration = ({ mouseEnter }: { mouseEnter: boolean }) => {
const stars = 108;
const columns = 18;
const [glowingStars, setGlowingStars] = useState<number[]>([]);
const highlightedStars = useRef<number[]>([]);
useEffect(() => {
const interval = setInterval(() => {
highlightedStars.current = Array.from({ length: 5 }, () =>
Math.floor(Math.random() * stars)
);
setGlowingStars([...highlightedStars.current]);
}, 3000);
return () => clearInterval(interval);
}, []);
return (
<div
className="h-48 p-1 w-full"
style={{
display: "grid",
gridTemplateColumns: `repeat(${columns}, 1fr)`,
gap: `1px`,
}}
>
{[...Array(stars)].map((_, starIdx) => {
const isGlowing = glowingStars.includes(starIdx);
const delay = (starIdx % 10) * 0.1;
const staticDelay = starIdx * 0.01;
return (
<div
key={`matrix-col-${starIdx}}`}
className="relative flex items-center justify-center"
>
<Star
isGlowing={mouseEnter ? true : isGlowing}
delay={mouseEnter ? staticDelay : delay}
/>
{mouseEnter && <Glow delay={staticDelay} />}
<AnimatePresence mode="wait">
{isGlowing && <Glow delay={delay} />}
</AnimatePresence>
</div>
);
})}
</div>
);
};
const Star = ({ isGlowing, delay }: { isGlowing: boolean; delay: number }) => {
return (
<motion.div
key={delay}
initial={{
scale: 1,
}}
animate={{
scale: isGlowing ? [1, 1.2, 2.5, 2.2, 1.5] : 1,
background: isGlowing ? "#fff" : "#666",
}}
transition={{
duration: 2,
ease: "easeInOut",
delay: delay,
}}
className={cn("bg-[#666] h-[1px] w-[1px] rounded-full relative z-20")}
></motion.div>
);
};
const Glow = ({ delay }: { delay: number }) => {
return (
<motion.div
initial={{
opacity: 0,
}}
animate={{
opacity: 1,
}}
transition={{
duration: 2,
ease: "easeInOut",
delay: delay,
}}
exit={{
opacity: 0,
}}
className="absolute left-1/2 -translate-x-1/2 z-10 h-[4px] w-[4px] rounded-full bg-blue-500 blur-[1px] shadow-2xl shadow-blue-400"
/>
);
};

104
src/components/ui/lamp.tsx Normal file
View File

@@ -0,0 +1,104 @@
"use client";
import React from "react";
import { motion } from "motion/react";
import { cn } from "@/lib/utils";
export default function LampDemo() {
return (
<LampContainer>
<motion.h1
initial={{ opacity: 0.5, y: 100 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{
delay: 0.3,
duration: 0.8,
ease: "easeInOut",
}}
className="mt-8 bg-gradient-to-br from-gray-300 to-gray-500 py-4 bg-clip-text text-center text-4xl font-medium tracking-tight text-transparent md:text-7xl"
>
Build lamps <br /> the right way
</motion.h1>
</LampContainer>
);
}
export const LampContainer = ({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) => {
return (
<div
className={cn(
"relative flex h-screen flex-col items-center justify-start pt-32 overflow-hidden bg-gray-950 w-full z-0",
className
)}
>
<div className="relative flex w-full flex-1 scale-y-125 items-center justify-center isolate z-0 ">
<motion.div
initial={{ opacity: 0.5, width: "15rem" }}
whileInView={{ opacity: 1, width: "30rem" }}
transition={{
delay: 0.5,
duration: 1.0,
ease: "easeInOut",
}}
style={{
backgroundImage: `conic-gradient(var(--conic-position), var(--tw-gradient-stops))`,
}}
className="absolute inset-auto right-1/2 h-56 overflow-visible w-[30rem] bg-gradient-conic from-cyan-500 via-transparent to-transparent text-white [--conic-position:from_70deg_at_center_top]"
>
<div className="absolute w-[100%] left-0 bg-gray-950 h-40 bottom-0 z-20 [mask-image:linear-gradient(to_top,white,transparent)]" />
<div className="absolute w-40 h-[100%] left-0 bg-gray-950 bottom-0 z-20 [mask-image:linear-gradient(to_right,white,transparent)]" />
</motion.div>
<motion.div
initial={{ opacity: 0.5, width: "15rem" }}
whileInView={{ opacity: 1, width: "30rem" }}
transition={{
delay: 0.3,
duration: 0.8,
ease: "easeInOut",
}}
style={{
backgroundImage: `conic-gradient(var(--conic-position), var(--tw-gradient-stops))`,
}}
className="absolute inset-auto left-1/2 h-56 w-[30rem] bg-gradient-conic from-transparent via-transparent to-cyan-500 text-white [--conic-position:from_290deg_at_center_top]"
>
<div className="absolute w-40 h-[100%] right-0 bg-gray-950 bottom-0 z-20 [mask-image:linear-gradient(to_left,white,transparent)]" />
<div className="absolute w-[100%] right-0 bg-gray-950 h-40 bottom-0 z-20 [mask-image:linear-gradient(to_top,white,transparent)]" />
</motion.div>
<div className="absolute top-1/2 h-48 w-full translate-y-12 scale-x-150 bg-gray-950 blur-2xl"></div>
<div className="absolute top-1/2 z-50 h-48 w-full bg-transparent opacity-10 backdrop-blur-md"></div>
<div className="absolute inset-auto z-50 h-36 w-[28rem] -translate-y-1/2 rounded-full bg-cyan-500 opacity-50 blur-3xl"></div>
<motion.div
initial={{ width: "8rem" }}
whileInView={{ width: "16rem" }}
transition={{
delay: 0.3,
duration: 0.8,
ease: "easeInOut",
}}
className="absolute inset-auto z-30 h-36 w-64 -translate-y-[6rem] rounded-full bg-cyan-400 blur-2xl"
></motion.div>
<motion.div
initial={{ width: "15rem" }}
whileInView={{ width: "30rem" }}
transition={{
delay: 0.3,
duration: 0.8,
ease: "easeInOut",
}}
className="absolute inset-auto z-50 h-0.5 w-[30rem] -translate-y-[7rem] bg-cyan-400 "
></motion.div>
<div className="absolute inset-auto z-40 h-44 w-full -translate-y-[12.5rem] bg-gray-950 "></div>
</div>
<div className="relative z-50 flex -translate-y-32 flex-col items-center px-5">
{children}
</div>
</div>
);
};

View File

@@ -0,0 +1,58 @@
"use client";
import React, { useState, useEffect } from "react";
import { motion, AnimatePresence } from "motion/react";
import { cn } from "@/lib/utils";
export const LayoutTextFlip = ({
text = "Build Amazing",
words = ["Landing Pages", "Component Blocks", "Page Sections", "3D Shaders"],
duration = 1500,
}: {
text: string;
words: string[];
duration?: number;
}) => {
const [currentIndex, setCurrentIndex] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCurrentIndex((prevIndex) => (prevIndex + 1) % words.length);
}, duration);
return () => clearInterval(interval);
}, []);
return (
<>
<motion.span
layoutId="subtext"
className="text-2xl font-bold tracking-tight drop-shadow-lg md:text-4xl"
>
{text}
</motion.span>
<motion.span
layout
className="relative w-fit overflow-hidden px-2 py-2 font-neuton font-medium italic tracking-tight"
>
<AnimatePresence mode="popLayout">
<motion.span
key={currentIndex}
initial={{ y: -40, filter: "blur(10px)" }}
animate={{
y: 0,
filter: "blur(0px)",
}}
exit={{ y: 50, filter: "blur(10px)", opacity: 0 }}
transition={{
duration: 0.5,
}}
className={cn("inline-block whitespace-nowrap")}
>
{words[currentIndex]}
</motion.span>
</AnimatePresence>
</motion.span>
</>
);
};

View File

@@ -0,0 +1,119 @@
"use client";
import { cn } from "@/lib/utils";
import { motion } from "motion/react";
import { useRef, useEffect, useState } from "react";
export function PointerHighlight({
children,
rectangleClassName,
pointerClassName,
containerClassName,
}: {
children: React.ReactNode;
rectangleClassName?: string;
pointerClassName?: string;
containerClassName?: string;
}) {
const containerRef = useRef<HTMLDivElement>(null);
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
useEffect(() => {
if (containerRef.current) {
const { width, height } = containerRef.current.getBoundingClientRect();
setDimensions({ width, height });
}
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
const { width, height } = entry.contentRect;
setDimensions({ width, height });
}
});
if (containerRef.current) {
resizeObserver.observe(containerRef.current);
}
return () => {
if (containerRef.current) {
resizeObserver.unobserve(containerRef.current);
}
};
}, []);
return (
<div
className={cn("relative w-fit", containerClassName)}
ref={containerRef}
>
{children}
{dimensions.width > 0 && dimensions.height > 0 && (
<motion.div
className="pointer-events-none absolute inset-0 z-0"
initial={{ opacity: 0, scale: 0.95, originX: 0, originY: 0 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.5, ease: "easeOut" }}
>
<motion.div
className={cn(
"absolute inset-0 border border-neutral-800 dark:border-neutral-200",
rectangleClassName,
)}
initial={{
width: 0,
height: 0,
}}
whileInView={{
width: dimensions.width,
height: dimensions.height,
}}
transition={{
duration: 1,
ease: "easeInOut",
}}
/>
<motion.div
className="pointer-events-none absolute"
initial={{ opacity: 0 }}
whileInView={{
opacity: 1,
x: dimensions.width + 4,
y: dimensions.height + 4,
}}
style={{
rotate: -90,
}}
transition={{
opacity: { duration: 0.1, ease: "easeInOut" },
duration: 1,
ease: "easeInOut",
}}
>
<Pointer
className={cn("h-5 w-5 text-blue-500", pointerClassName)}
/>
</motion.div>
</motion.div>
)}
</div>
);
}
const Pointer = ({ ...props }: React.SVGProps<SVGSVGElement>) => {
return (
<svg
stroke="currentColor"
fill="currentColor"
strokeWidth="1"
strokeLinecap="round"
strokeLinejoin="round"
viewBox="0 0 16 16"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path d="M14.082 2.182a.5.5 0 0 1 .103.557L8.528 15.467a.5.5 0 0 1-.917-.007L5.57 10.694.803 8.652a.5.5 0 0 1-.006-.916l12.728-5.657a.5.5 0 0 1 .556.103z"></path>
</svg>
);
};

View File

@@ -0,0 +1,170 @@
"use client";
import { useRef } from "react";
import { motion } from "motion/react";
import DottedMap from "dotted-map";
import { useTheme } from "next-themes";
interface MapProps {
dots?: Array<{
start: { lat: number; lng: number; label?: string };
end: { lat: number; lng: number; label?: string };
}>;
lineColor?: string;
}
export default function WorldMap({
dots = [],
lineColor = "#06b6d4",
}: MapProps) {
const svgRef = useRef<SVGSVGElement>(null);
const map = new DottedMap({ height: 100, grid: "diagonal" });
const { theme } = useTheme();
const svgMap = map.getSVG({
radius: 0.22,
color: theme === "dark" ? "#FFFFFF40" : "#00000040",
shape: "circle",
backgroundColor: theme === "dark" ? "black" : "white",
});
const projectPoint = (lat: number, lng: number) => {
const x = (lng + 180) * (800 / 360);
const y = (90 - lat) * (400 / 180);
return { x, y };
};
const createCurvedPath = (
start: { x: number; y: number },
end: { x: number; y: number }
) => {
const midX = (start.x + end.x) / 2;
const midY = Math.min(start.y, end.y) - 50;
return `M ${start.x} ${start.y} Q ${midX} ${midY} ${end.x} ${end.y}`;
};
return (
<div className="w-full aspect-[2/1] dark:bg-black bg-white rounded-lg relative font-sans">
<img
src={`data:image/svg+xml;utf8,${encodeURIComponent(svgMap)}`}
className="h-full w-full [mask-image:linear-gradient(to_bottom,transparent,white_10%,white_90%,transparent)] pointer-events-none select-none"
alt="world map"
height="495"
width="1056"
draggable={false}
/>
<svg
ref={svgRef}
viewBox="0 0 800 400"
className="w-full h-full absolute inset-0 pointer-events-none select-none"
>
{dots.map((dot, i) => {
const startPoint = projectPoint(dot.start.lat, dot.start.lng);
const endPoint = projectPoint(dot.end.lat, dot.end.lng);
return (
<g key={`path-group-${i}`}>
<motion.path
d={createCurvedPath(startPoint, endPoint)}
fill="none"
stroke="url(#path-gradient)"
strokeWidth="1"
initial={{
pathLength: 0,
}}
animate={{
pathLength: 1,
}}
transition={{
duration: 1,
delay: 0.5 * i,
ease: "easeOut",
}}
key={`start-upper-${i}`}
></motion.path>
</g>
);
})}
<defs>
<linearGradient id="path-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stopColor="white" stopOpacity="0" />
<stop offset="5%" stopColor={lineColor} stopOpacity="1" />
<stop offset="95%" stopColor={lineColor} stopOpacity="1" />
<stop offset="100%" stopColor="white" stopOpacity="0" />
</linearGradient>
</defs>
{dots.map((dot, i) => (
<g key={`points-group-${i}`}>
<g key={`start-${i}`}>
<circle
cx={projectPoint(dot.start.lat, dot.start.lng).x}
cy={projectPoint(dot.start.lat, dot.start.lng).y}
r="2"
fill={lineColor}
/>
<circle
cx={projectPoint(dot.start.lat, dot.start.lng).x}
cy={projectPoint(dot.start.lat, dot.start.lng).y}
r="2"
fill={lineColor}
opacity="0.5"
>
<animate
attributeName="r"
from="2"
to="8"
dur="1.5s"
begin="0s"
repeatCount="indefinite"
/>
<animate
attributeName="opacity"
from="0.5"
to="0"
dur="1.5s"
begin="0s"
repeatCount="indefinite"
/>
</circle>
</g>
<g key={`end-${i}`}>
<circle
cx={projectPoint(dot.end.lat, dot.end.lng).x}
cy={projectPoint(dot.end.lat, dot.end.lng).y}
r="2"
fill={lineColor}
/>
<circle
cx={projectPoint(dot.end.lat, dot.end.lng).x}
cy={projectPoint(dot.end.lat, dot.end.lng).y}
r="2"
fill={lineColor}
opacity="0.5"
>
<animate
attributeName="r"
from="2"
to="8"
dur="1.5s"
begin="0s"
repeatCount="indefinite"
/>
<animate
attributeName="opacity"
from="0.5"
to="0"
dur="1.5s"
begin="0s"
repeatCount="indefinite"
/>
</circle>
</g>
</g>
))}
</svg>
</div>
);
}

BIN
src/images/cloudlayer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

BIN
src/images/kubernetes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1024 KiB

View File

@@ -214,7 +214,7 @@
</filter> </filter>
<radialGradient id="b" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" <radialGradient id="b" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0 727 -642 0 184 1)"> gradientTransform="matrix(0 727 -642 0 184 1)">
<stop stop-color="#FAFAFA" /> <stop stop-color="#FFFFFF" />
<stop offset="1" stop-color="#E6E6E6" /> <stop offset="1" stop-color="#E6E6E6" />
</radialGradient> </radialGradient>
<radialGradient id="c" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" <radialGradient id="c" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse"

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,5 +1,8 @@
@import url('https://fonts.googleapis.com/css2?family=Neuton&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Mulish:wght@400;500;700&display=swap');
:root { :root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; font-family: 'Mulish', system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5; line-height: 1.5;
font-weight: 400; font-weight: 400;

View File

@@ -1,5 +1,5 @@
import { type ClassValue, clsx } from 'clsx' import { clsx, type ClassValue } from "clsx"
import { twMerge } from 'tailwind-merge' import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)) return twMerge(clsx(inputs))

View File

@@ -48,7 +48,7 @@ export function GallerySection() {
const prev = () => setActive((i) => wrap(0, galleryItems.length, i - 1)) const prev = () => setActive((i) => wrap(0, galleryItems.length, i - 1))
return ( return (
<div className="bg-[#FAFAFA]"> <div className="bg-white">
<div className="relative isolate pt-8 pb-0 text-center w-full"> <div className="relative isolate pt-8 pb-0 text-center w-full">
<FadeIn transition={{ duration: 0.8, delay: 0.1 }}> <FadeIn transition={{ duration: 0.8, delay: 0.1 }}>
<div className="mx-auto max-w-5xl lg:mt-12"> <div className="mx-auto max-w-5xl lg:mt-12">

View File

@@ -0,0 +1,65 @@
import { H2, P } from '@/components/Texts'
import { Button } from '@/components/Button'
import { LayoutTextFlip } from '@/components/ui/layout-text-flip' // make sure this import path is correct
export function HomeAgent() {
return (
<div className="relative isolate overflow-hidden bg-white">
<div className="px-6 py-24 sm:py-32 lg:px-8">
<div className="mx-auto max-w-4xl text-center">
<H2>
Deploy your own{" "}
<span className="font-neuton text-left text-black font-medium text-7xl italic bg-clip-text bg-gradient-to-r from-blue-400 via-cyan-400 to-violet-400">
<LayoutTextFlip
text=""
words={[
"GPT-5",
"Claude 3.5",
"Gemini 1.5",
"Mistral 7B",
"Llama 3.1",
"AI Agents",
]}
/>
</span>
</H2>
<P className="mx-auto mt-6 max-w-xl text-lg/8 text-pretty text-gray-600">
Mycelium delivers enterprise-grade AI agents with unmatched customizability and the fastest time to production all in the agent platform designed for real business use cases.
</P>
<div className="mt-10 flex items-center justify-center gap-x-6">
<Button variant="solid" color="cyan" href="/signup">
Get started
</Button>
<a href="/agents" className="text-sm/6 font-semibold text-gray-900 hover:text-gray-600">
Learn more <span aria-hidden="true"></span>
</a>
</div>
</div>
</div>
<svg
viewBox="0 0 1024 1024"
aria-hidden="true"
className="absolute top-1/2 left-1/2 -z-10 size-256 -translate-x-1/2 mask-[radial-gradient(closest-side,white,transparent)]"
>
<circle
r={512}
cx={512}
cy={512}
fill="url(#8d958450-c69f-4251-94bc-4e091a323369)"
fillOpacity="0.7"
/>
<defs>
<radialGradient id="8d958450-c69f-4251-94bc-4e091a323369" cx="50%" cy="50%" r="50%">
<stop offset="0%" stopColor="#60A5FA" /> {/* blue-400 */}
<stop offset="50%" stopColor="#06B6D4" /> {/* cyan-500 */}
<stop offset="100%" stopColor="#A78BFA" /> {/* violet-400 */}
</radialGradient>
</defs>
</svg>
</div>
)
}

View File

@@ -0,0 +1,34 @@
"use client";
import { motion } from "motion/react";
import { H1, H2, H3, H4, H5 } from "@/components/Texts";
import { AuroraBackground } from "@/components/ui/aurora-background";
import { ScrollDownArrow } from '@/components/ScrollDownArrow';
export function HomeAurora() {
return (
<AuroraBackground>
<motion.div
initial={{ opacity: 0.0, y: 40 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{
delay: 0.5,
duration: 1,
ease: "easeInOut",
}}
className="relative mb-20 flex flex-col items-center justify-center gap-4 px-4 max-w-5xl"
>
<div className="text-center text-gray-800">
<H1>Decentralized Autonomous <span className="font-neuton text-bold lg:text-8xl italic">Agentic Cloud.</span></H1>
</div>
<div className="pt-8 text-center font-light text-gray-500 max-w-4xl">
<H5>Mycelium Project is a decentralized platform for autonomous AI, powered by distributed compute, sovereign memory, encrypted networking, and stateless GPU orchestration.</H5>
</div>
<div className="pt-8">
<ScrollDownArrow />
</div>
</motion.div>
</AuroraBackground>
);
}

View File

@@ -0,0 +1,66 @@
import { CheckCircleIcon } from '@heroicons/react/20/solid'
import { H2, P } from '@/components/Texts'
const benefits = [
'Decentralized Infrastructure',
'End-to-End Encryption',
'Sovereign Data Control',
'Scalable Kubernetes Clusters',
'Censorship-Resistant',
'Peer-to-Peer Networking',
]
export function HomeCloud() {
return (
<div className="overflow-hidden bg-white py-24">
<div className="relative isolate">
<div className="mx-auto max-w-7xl sm:px-6 lg:px-8">
<div className="mx-auto flex max-w-2xl flex-col gap-16 bg-white px-6 py-16 shadow-lg ring-1 ring-gray-200/5 sm:rounded-3xl sm:p-8 lg:mx-0 lg:max-w-none lg:flex-row lg:items-center lg:py-20 xl:gap-x-20 xl:px-20">
<img
alt=""
src="/images/kubernetes.png"
className="h-96 w-full flex-none rounded-2xl object-cover lg:aspect-square lg:h-auto lg:max-w-sm"
/>
<div className="w-full flex-auto">
<H2 className="">
Mycelium <span className="font-neuton font-medium text-7xl italic">Cloud</span>
</H2>
<P className="mt-6 text-lg/8 text-pretty text-gray-600">
A comprehensive platform for deploying and managing Kubernetes clusters on the decentralized Mycelium Grid infrastructure
</P>
<ul
role="list"
className="mt-10 grid grid-cols-1 gap-x-8 gap-y-3 text-base/7 text-gray-950 sm:grid-cols-2"
>
{benefits.map((benefit) => (
<li key={benefit} className="flex gap-x-3">
<CheckCircleIcon aria-hidden="true" className="h-7 w-5 flex-none text-cyan-500" />
{benefit}
</li>
))}
</ul>
<div className="mt-10 flex">
<a href="/cloud" className="text-sm/6 font-semibold text-cyan-600 hover:text-cyan-500">
Learn more
<span aria-hidden="true"> &rarr;</span>
</a>
</div>
</div>
</div>
</div>
<div
aria-hidden="true"
className="absolute inset-x-0 -top-16 -z-10 flex transform-gpu justify-center overflow-hidden blur-3xl"
>
<div
style={{
clipPath:
'polygon(73.6% 51.7%, 91.7% 11.8%, 100% 46.4%, 97.4% 82.2%, 92.5% 84.9%, 75.7% 64%, 55.3% 47.5%, 46.5% 49.4%, 45% 62.9%, 50.3% 87.2%, 21.3% 64.1%, 0.1% 100%, 5.4% 51.1%, 21.4% 63.9%, 58.9% 0.2%, 73.6% 51.7%)',
}}
className="aspect-1318/752 w-329.5 flex-none bg-linear-to-r from-[#9fe8fc] to-[#c6c4fa] opacity-50"
/>
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,77 @@
import { InboxIcon, TrashIcon, UsersIcon } from '@heroicons/react/24/outline'
import { H2, P } from '@/components/Texts'
const features = [
{
name: 'Mycelium Network',
description:
"A global, end-to-end encrypted overlay that simply doesn't break.",
href: '/network',
icon: UsersIcon,
image: '/images/network_icon.png',
},
{
name: 'Mycelium Cloud',
description:
'An autonomous, stateless OS that enforces pre-deterministic deployments you define.',
href: '/cloud',
icon: TrashIcon,
image: '/images/cloud_icon.png',
},
{
name: 'Mycelium Agents',
description:
'Your sovereign agent with private memory and permissioned data access—always under your control.',
href: '/agents',
icon: InboxIcon,
image: '/images/agent_icon.png',
},
]
export function HomeFeatures() {
return (
<div className="">
<div className="relative bg-transparent py-24 overflow-hidden">
{/* --- Soft background gradients --- */}
<div
aria-hidden="true"
className="absolute inset-x-0 -top-16 -z-10 flex transform-gpu justify-center overflow-hidden blur-3xl"
>
<div
style={{
clipPath:
'polygon(73.6% 51.7%, 91.7% 11.8%, 100% 46.4%, 97.4% 82.2%, 92.5% 84.9%, 75.7% 64%, 55.3% 47.5%, 46.5% 49.4%, 45% 62.9%, 50.3% 87.2%, 21.3% 64.1%, 0.1% 100%, 5.4% 51.1%, 21.4% 63.9%, 58.9% 0.2%, 73.6% 51.7%)',
}}
className="aspect-1318/752 w-329.5 flex-none bg-linear-to-r from-[#9fd6fc] to-[#c6c4fa] opacity-40"
/>
</div>
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-2xl lg:mx-0">
<H2 className="">
The Building Blocks of <span className="font-neuton font-medium text-7xl italic">Decentralized Future</span>
</H2>
<P className="mt-6 ">
From compute and networking to intelligent automation, these components work together to empower users, developers, and organizations to build freely, without intermediaries.
</P>
</div>
<div className="mx-auto mt-16 max-w-2xl lg:max-w-7xl">
<div className="grid grid-cols-1 gap-x-12 gap-y-12 lg:grid-cols-3">
{features.map((feature) => (
<div key={feature.name} className="relative flex flex-col p-8 rounded-3xl border border-gray-100 bg-white backdrop-blur-lg overflow-hidden shadow-lg hover:shadow-xl hover:border-cyan-500 hover:scale-105 transform transition-all duration-300">
<div className="w-30 h-30 bg-white/80 rounded-full flex items-center justify-center">
<img src={feature.image} alt="" className="w-25 h-25" />
</div>
<h3 className="mt-6 text-xl font-semibold text-black">{feature.name}</h3>
<p className="mt-4 text-base text-gray-800">{feature.description}</p>
<a href={feature.href} className="mt-6 text-base font-semibold text-black">Learn more <span aria-hidden="true"> &rarr;</span></a>
<div className="absolute -bottom-10 -right-10 h-50 w-50 -z-10" style={{ background: 'radial-gradient(circle, rgba(173, 239, 255, 0.6) 0%, rgba(115, 207, 255, 0.4) 100%)', filter: 'blur(80px)' }}></div>
</div>
))}
</div>
</div>
</div>
</div>
</div>
)
}

View File

@@ -1,36 +1,37 @@
import { motion } from 'framer-motion' 'use client'
import { TypeAnimation } from 'react-type-animation'
import { Container } from '../../components/Container' import { H1, P } from '@/components/Texts'
import { FadeIn } from '@/components/FadeIn'
import { Button } from '@/components/Button'
export function HomeHero() { export function HomeHero() {
return ( return (
<section className="relative bg-white py-20 lg:py-32"> <div
<Container> className="relative isolate overflow-hidden bg-white"
<div className="mx-auto max-w-4xl text-center"> style={{
<h1 className="text-4xl lg:text-6xl font-medium tracking-tight text-gray-900"> backgroundImage: 'url(/images/cloud.png)',
<TypeAnimation backgroundSize: 'cover',
sequence={[ backgroundPosition: 'center',
'Decentralized Autonomous Agentic Cloud.', }}
1000,
]}
wrapper="span"
speed={50}
repeat={0}
/>
</h1>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 1, delay: 1 }}
className="mt-8"
> >
<p className="text-lg lg:text-xl text-gray-600"> <div className="mx-auto max-w-7xl px-6 py-24 lg:py-32 lg:flex lg:px-8">
<div className="mx-auto max-w-2xl shrink-0 lg:mx-0 lg:pt-8">
<H1 color="primary" className="mt-10 text-5xl font-semibold tracking-tight text-pretty sm:text-7xl">
Decentralized Autonomous Agentic Cloud.
</H1>
<P color="secondary" className="mt-8 text-lg font-medium text-pretty sm:text-xl/8">
Mycelium's advancements in Agentic infrastructure supports private, secure and autonomous Agents that connect, learn and grow with you. Mycelium's advancements in Agentic infrastructure supports private, secure and autonomous Agents that connect, learn and grow with you.
</p> </P>
</motion.div> <div className="mt-10 flex items-center gap-x-6">
<Button variant="solid" color="cyan" href="#">
Get started
</Button>
<a href="#" className="text-sm/6 font-semibold text-gray-50">
Learn more <span aria-hidden="true"></span>
</a>
</div>
</div>
</div>
</div> </div>
</Container>
</section>
) )
} }

View File

@@ -0,0 +1,35 @@
"use client";
import React from "react";
import { motion } from "motion/react";
import { LampContainer } from "@/components/ui/lamp";
export function HomeHeroDark() {
return (
<LampContainer>
<motion.h1
initial={{ opacity: 0.5, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{
delay: 0.3,
duration: 0.8,
ease: "easeInOut",
}}
className="bg-gradient-to-br from-slate-300 to-slate-500 py-4 bg-clip-text text-center text-4xl font-medium tracking-tight text-transparent md:text-7xl max-w-4xl"
>
Decentralized Autonomous Agentic Cloud.
</motion.h1>
<motion.p
initial={{ opacity: 0.5, y: 60 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{
delay: 0.5,
duration: 0.8,
ease: "easeInOut",
}}
className="mt-8 bg-gradient-to-br from-slate-300 to-slate-500 py-4 bg-clip-text text-center text-lg font-medium tracking-tight text-transparent md:text-xl max-w-3xl"
>
Mycelium Project is a decentralized platform for autonomous AI, powered by distributed compute, sovereign memory, encrypted networking, and stateless GPU orchestration.
</motion.p>
</LampContainer>
);
}

View File

@@ -0,0 +1,69 @@
'use client'
import { useRef, useEffect } from 'react'
import { H1, H5 } from '@/components/Texts'
export function HomeHeroLight2() {
const videoRef = useRef<HTMLVideoElement>(null);
useEffect(() => {
const video = videoRef.current;
if (video) {
video.playbackRate = 0.4;
const playPromise = video.play();
if (playPromise !== undefined) {
playPromise.catch(error => {
console.error("Video autoplay was prevented:", error);
});
}
}
}, []);
return (
<section className="relative h-screen overflow-hidden">
{/* Background video */}
<video
ref={videoRef}
src="/videos/cloud.mp4"
autoPlay
loop
muted
playsInline
className="absolute inset-0 h-full w-full object-cover z-[-10]"
/>
{/* Global soft wash + blur (Temporarily commented out for debugging) */}
{/* <div className="absolute inset-0 bg-white opacity-30 backdrop-blur-md z-0" /> */}
{/* Center “halo” for text legibility (Temporarily commented out for debugging) */}
{/* <div
className="absolute inset-0 z-0"
style={{
background:
'radial-gradient(ellipse at center, rgba(255,255,255,0.96) 0%, rgba(255,255,255,0.88) 15%, rgba(255,255,255,0.72) 35%, rgba(255,255,255,0.08) 75%)'
}}
/> */}
{/* Content */}
<div className="relative z-10 h-full flex items-center justify-center">
<div className="mx-auto max-w-4xl text-center px-6 lg:px-8">
<H1
className="pt-6"
style={{ textShadow: '0 2px 8px rgba(0,0,0,0.08)' }}
>
Decentralized Autonomous Agentic Cloud.
</H1>
<H5
className="mt-8"
style={{ textShadow: '0 1px 4px rgba(0,0,0,0.06)' }}
>
Mycelium&apos;s advancements in Agentic infrastructure support private, secure, and
autonomous Agents that connect, learn, and grow with you.
</H5>
</div>
</div>
</section>
)
}

View File

@@ -0,0 +1,69 @@
"use client";
import WorldMap from "@/components/ui/world-map";
import { motion } from "motion/react";
import { H2, P } from "@/components/Texts";
export function HomeMapSection() {
return (
<div className=" py-24 dark:bg-black bg-white w-full">
<div className="max-w-7xl mx-auto text-center">
<H2 className="font-medium text-xl md:text-4xl dark:text-white text-gray-800">
Mycelium Network is{" "}
<span className="text-black font-neuton text-bold italic">
{"Live.".split("").map((word, idx) => (
<motion.span
key={idx}
className="inline-block"
initial={{ x: -10, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
transition={{ duration: 0.5, delay: idx * 0.04 }}
>
{word}
</motion.span>
))}
</span>
</H2>
<P className="text-sm md:text-lg text-neutral-500 max-w-2xl mx-auto py-4">
Mycelium Network's advancement technology enables anyone to deploy
their own Internet infrastructure, anywhere.
</P>
</div>
<div className="max-w-5xl mx-auto">
<WorldMap
dots={[
{
start: {
lat: 64.2008,
lng: -149.4937,
}, // Alaska (Fairbanks)
end: {
lat: 34.0522,
lng: -118.2437,
}, // Los Angeles
},
{
start: { lat: 64.2008, lng: -149.4937 }, // Alaska (Fairbanks)
end: { lat: -15.7975, lng: -47.8919 }, // Brazil (Brasília)
},
{
start: { lat: -15.7975, lng: -47.8919 }, // Brazil (Brasília)
end: { lat: 38.7223, lng: -9.1393 }, // Lisbon
},
{
start: { lat: 51.5074, lng: -0.1278 }, // London
end: { lat: 28.6139, lng: 77.209 }, // New Delhi
},
{
start: { lat: 28.6139, lng: 77.209 }, // New Delhi
end: { lat: 43.1332, lng: 131.9113 }, // Vladivostok
},
{
start: { lat: 28.6139, lng: 77.209 }, // New Delhi
end: { lat: -1.2921, lng: 36.8219 }, // Nairobi
},
]}
/>
</div>
</div>
);
}

View File

@@ -2,21 +2,37 @@ import { AnimatedSection } from '../../components/AnimatedSection'
import { HomeHero } from './HomeHero' import { HomeHero } from './HomeHero'
import { WorldMapSection } from './WorldMapSection' import { WorldMapSection } from './WorldMapSection'
import { StackSection } from './StackSection' import { StackSection } from './StackSection'
import { HomeHeroLight2 } from './HomeHeroLight2'
import { HomeHeroDark } from './HomeHeroDark'
import { HomeAurora } from './HomeAurora'
import { HomeMapSection } from './HomeMap'
import { HomeFeatures } from './HomeFeatures'
import { HomeCloud } from './HomeCloud'
import { HomeAgent } from './HomeAgent'
export default function HomePage() { export default function HomePage() {
return ( return (
<div> <div>
<AnimatedSection> <AnimatedSection>
<HomeHero /> <HomeAurora />
</AnimatedSection>
<AnimatedSection id="next-section">
<HomeFeatures />
</AnimatedSection>
<AnimatedSection >
<HomeMapSection />
</AnimatedSection> </AnimatedSection>
<AnimatedSection> <AnimatedSection>
<WorldMapSection /> <HomeCloud />
</AnimatedSection> </AnimatedSection>
<AnimatedSection> <AnimatedSection>
<StackSection /> <HomeAgent />
</AnimatedSection> </AnimatedSection>
</div> </div>
) )
} }

View File

@@ -24,7 +24,7 @@ const stackData = [
export function StackSection() { export function StackSection() {
return ( return (
<section className="relative bg-white py-20 lg:py-32"> <section className="relative bg-black py-20 lg:py-32">
<Container> <Container>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-12 items-start"> <div className="grid grid-cols-1 lg:grid-cols-3 gap-12 items-start">
{/* Left Column - Text */} {/* Left Column - Text */}
@@ -35,7 +35,7 @@ export function StackSection() {
transition={{ duration: 0.5 }} transition={{ duration: 0.5 }}
className="lg:col-span-1" className="lg:col-span-1"
> >
<h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900"> <h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-white">
The Mycelium Stack The Mycelium Stack
</h2> </h2>
<p className="mt-6 text-lg text-gray-600"> <p className="mt-6 text-lg text-gray-600">

View File

@@ -1,4 +1,7 @@
@import 'tailwindcss'; @import 'tailwindcss';
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
@theme { @theme {
--animate-scroll: scroll var(--animation-duration, 40s) var(--animation-direction, forwards) linear infinite; --animate-scroll: scroll var(--animation-duration, 40s) var(--animation-direction, forwards) linear infinite;
@@ -70,7 +73,10 @@
--color-gray-900: oklch(0.205 0 0); --color-gray-900: oklch(0.205 0 0);
--color-gray-950: oklch(0.145 0 0); --color-gray-950: oklch(0.145 0 0);
--font-sans: var(--font-inter); --font-sans: 'Mulish', system-ui, Avenir, Helvetica, Arial, sans-serif;
--font-neuton: 'Neuton', serif;
--font-family-neuton: var(--font-neuton);
--container-2xl: 40rem; --container-2xl: 40rem;
@@ -91,10 +97,127 @@
@theme inline { @theme inline {
--animate-marquee: marquee var(--marquee-duration) linear infinite; --animate-marquee: marquee var(--marquee-duration) linear infinite;
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-border: var(--border);
--color-destructive: var(--destructive);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-muted-foreground: var(--muted-foreground);
--color-muted: var(--muted);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary: var(--secondary);
--color-primary-foreground: var(--primary-foreground);
--color-primary: var(--primary);
--color-popover-foreground: var(--popover-foreground);
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
--color-foreground: var(--foreground);
--color-background: var(--background);
@keyframes marquee { @keyframes marquee {
100% { 100% {
transform: translateY(-50%); transform: translateY(-50%);
} }
} }
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px)
}
:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
} }

View File

@@ -1,4 +1,10 @@
{ {
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"files": [], "files": [],
"references": [ "references": [
{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.app.json" },