This commit is contained in:
2025-09-18 20:21:48 +02:00
parent f5ab743987
commit cde6c90033
8 changed files with 193 additions and 192 deletions

View File

@@ -1,10 +1,10 @@
"use client"; "use client";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { H1, H2, H3, H4, P, CT, CP, NL } from "@/components/Texts"; import { H2, P } from "@/components/Texts";
import React, { useRef } from "react"; import React from "react";
import { BentoGrid, BentoGridItem } from "@/components/ui/bento-grid"; import { BentoGrid, MotionBentoGridItem } from "@/components/ui/bento-grid";
import { motion, AnimatePresence, useInView } from 'framer-motion' import { FadeIn } from "./FadeIn";
const items = [ const items = [
{ {
@@ -53,44 +53,39 @@ const items = [
]; ];
export function BentoReviews() { export function BentoReviews() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
return ( return (
<div ref={ref}> <div>
<div className="relative isolate pt-24 pb-12 bg-black text-center w-full"> <div className="relative isolate pt-24 pb-12 bg-black text-center w-full">
<motion.div <FadeIn transition={{ duration: 0.8, delay: 0.1 }}>
initial={{ opacity: 0, y: 20 }} <div className="mx-auto max-w-5xl">
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }} <H2 className="text-center">Mycelium Technologies</H2>
transition={{ duration: 0.8, delay: 0.1 }} </div>
className="mx-auto max-w-5xl" </FadeIn>
> <FadeIn transition={{ duration: 0.8, delay: 0.2 }}>
<H2 className="text-center">Mycelium Technologies</H2> <div className="mx-auto max-w-4xl mt-6 mb-8">
</motion.div> <P className="text-center" color="primary">
<motion.div A robust infrastructure layer for autonomous AI agents, our technology stack
initial={{ opacity: 0, y: 20 }} delivers a secure, efficient, and intuitive platform for deploying and managing AI agents at scale.
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }} </P>
transition={{ duration: 0.8, delay: 0.2 }} </div>
className="mx-auto max-w-4xl mt-6 mb-8" </FadeIn>
>
<P className="text-center" color="primary">
A robust infrastructure layer for autonomous AI agents, our technology stack
delivers a secure, efficient, and intuitive platform for deploying and managing AI agents at scale.
</P>
</motion.div>
</div> </div>
<BentoGrid className="max-w-8xl px-12 pb-12 lg:grid-cols-3"> <BentoGrid className="max-w-8xl px-12 pb-12 lg:grid-cols-3">
{items.map((item, i) => ( {items.map((item, i) => (
<BentoGridItem <MotionBentoGridItem
key={i} key={i}
title={item.title} initial={{ opacity: 0, y: 20 }}
subtitle={item.subtitle} whileInView={{ opacity: 1, y: 0 }}
description={item.description} viewport={{ once: false, margin: '0px 0px -100px 0px' }}
video={item.video} transition={{ duration: 0.8, delay: 0.3 + i * 0.1 }}
className={i === 3 || i === 6 ? "md:col-span-2" : ""} className={cn(i === 3 || i === 6 ? "md:col-span-2" : "", "h-full")}
/> title={item.title}
))} subtitle={item.subtitle}
</BentoGrid> description={item.description}
video={item.video}
/>
))}
</BentoGrid>
</div> </div>
); );
} }

View File

@@ -1,6 +1,7 @@
import { CircleBackground } from '@/components/CircleBackground' import { CircleBackground } from '@/components/CircleBackground'
import { Container } from '@/components/Container' import { Container } from '@/components/Container'
import { Button } from '@/components/Button' import { Button } from '@/components/Button'
import { FadeIn } from '@/components/FadeIn'
export function CallToAction() { export function CallToAction() {
return ( return (
@@ -22,6 +23,7 @@ export function CallToAction() {
<CircleBackground color="#fff" className="animate-spin-slower" /> <CircleBackground color="#fff" className="animate-spin-slower" />
</div> </div>
<Container className="relative z-20"> <Container className="relative z-20">
<FadeIn>
<div className="mx-auto max-w-md sm:text-center"> <div className="mx-auto max-w-md sm:text-center">
<h2 className="text-3xl font-medium tracking-tight text-white sm:text-4xl"> <h2 className="text-3xl font-medium tracking-tight text-white sm:text-4xl">
Decentralized AI Agents that are Truly Yours Decentralized AI Agents that are Truly Yours
@@ -39,6 +41,7 @@ export function CallToAction() {
</Button> </Button>
</div> </div>
</div> </div>
</FadeIn>
</Container> </Container>
</section> </section>
) )

View File

@@ -2,11 +2,12 @@
import { useEffect, useMemo, useState, useRef } from 'react' import { useEffect, useMemo, useState, useRef } from 'react'
import Image from 'next/image' import Image from 'next/image'
import { motion, AnimatePresence, useInView } from 'framer-motion' import { motion, AnimatePresence } from 'framer-motion'
import { wrap } from 'popmotion' import { wrap } from 'popmotion'
import { Button } from '@/components/Button'; import { Button } from '@/components/Button';
import { H2, P, H4, CT, CP } from '@/components/Texts'; import { H2, P, CT } from '@/components/Texts';
import { TypeAnimation } from 'react-type-animation' import { TypeAnimation } from 'react-type-animation'
import { FadeIn } from './FadeIn';
const galleryItems = [ const galleryItems = [
{ text: 'Navigate and interact with any web interface', image: '/images/gallery/interface.jpg', width: 448, height: 277 }, { text: 'Navigate and interact with any web interface', image: '/images/gallery/interface.jpg', width: 448, height: 277 },
@@ -33,8 +34,6 @@ const AUTOPLAY_MS = 3200
export function ClickableGallery() { export function ClickableGallery() {
const [active, setActive] = useState(0) const [active, setActive] = useState(0)
const [hovering, setHovering] = useState(false) const [hovering, setHovering] = useState(false)
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
// autoplay // autoplay
useEffect(() => { useEffect(() => {
@@ -52,113 +51,112 @@ export function ClickableGallery() {
const prev = () => setActive((i) => wrap(0, galleryItems.length, i - 1)) const prev = () => setActive((i) => wrap(0, galleryItems.length, i - 1))
return ( return (
<div ref={ref}> <div>
<div className="relative isolate pt-8 pb-0 bg-transparent text-center w-full "> <div className="relative isolate pt-8 pb-0 bg-transparent text-center w-full">
<motion.div initial={{ opacity: 0, y: 20 }} animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }} transition={{ duration: 0.8, delay: 0.1 }} className="mx-auto max-w-5xl"> <FadeIn transition={{ duration: 0.8, delay: 0.1 }}>
<H2 className="text-center">One Agent, Endless Possibilities.</H2> <div className="mx-auto max-w-5xl">
</motion.div> <H2 className="text-center">One Agent, Endless Possibilities.</H2>
<motion.div initial={{ opacity: 0, y: 20 }} animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }} transition={{ duration: 0.8, delay: 0.2 }} className="mx-auto max-w-4xl mt-6">
<P className="text-center" color="primary">
The future isnt about more tools. Its about one intelligent partner that can do it all. This is your gateway to creativity, automation, and discovery.
</P>
</motion.div>
</div>
<motion.section
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 1, delay: 0.4 }}
className="relative w-full flex items-center justify-center overflow-hidden bg-transparent -mt-8 pt-0 pb-0"
onMouseEnter={() => setHovering(true)}
onMouseLeave={() => setHovering(false)}
>
<div className="relative w-full max-w-[1800px] h-[500px]" style={{ perspective: '1600px' }}>
<div className="absolute inset-0" style={{ transformStyle: 'preserve-3d' }}>
<AnimatePresence initial={false}>
{indices.map((idx, i) => {
const distance = i - VISIBLE
const item = galleryItems[idx]
const x = distance * GAP
const z = -Math.abs(distance) * DEPTH
const r = distance * ROT_Y
const s = 1 - Math.abs(distance) * SCALE_DROP
const o = distance === 0 ? 1 : 0.80
const zIndex = 100 - Math.abs(distance)
return (
<motion.div
key={`${idx}-${i}`}
className={`absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 will-change-transform overflow-hidden ${distance === 0 ? 'rounded-xl' : ''}`}
initial={{ opacity: 0 }}
animate={{
transform: `translateX(${x}px) translateZ(${z}px) rotateY(${r}deg) scale(${s})`,
zIndex,
opacity: o,
boxShadow: distance === 0 ? '0 0 20px 5px rgba(255, 255, 255, 0.2)' : 'none',
}}
exit={{ opacity: 0 }}
transition={{ type: 'spring', stiffness: 220, damping: 26 }}
onClick={() => setActive(idx)}
>
<div
className="relative bg-black flex items-center justify-center"
>
<Image
src={item.image}
alt={item.text}
width={item.width}
height={item.height}
className="object-contain text-white"
priority={i === VISIBLE}
/>
</div>
</motion.div>
)
})}
</AnimatePresence>
</div>
{/* Arrows */}
<div className="absolute inset-y-0 left-8 flex items-center z-50">
<button
onClick={prev}
className="bg-transparent rounded-full p-2 shadow-lg backdrop-blur-md"
aria-label="Previous"
>
<svg className="size-8" viewBox="0 0 24 24" fill="none" dangerouslySetInnerHTML={{ __html: '<path d="M15 19L8 12l7-7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>' }} />
</button>
</div>
<div className="absolute inset-y-0 right-8 flex items-center z-50">
<button
onClick={next}
className="bg-transparent rounded-full p-2 shadow-lg backdrop-blur-md"
aria-label="Next"
>
<svg className="size-8" viewBox="0 0 24 24" fill="none" dangerouslySetInnerHTML={{ __html: '<path d="M9 5l7 7-7 7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>' }} />
</button>
</div>
{/* Foreground pill */}
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-[60]">
<div className="flex items-center justify-between w-[1040px] gap-6 rounded-2xl bg-black/30 shadow-[0_8px_40px_rgba(0,0,0,0.15)] px-12 backdrop-blur">
<CT as="h4" className="max-w-[820px] h-[72px] text-white flex items-center">
<TypeAnimation
key={active}
sequence={[galleryItems[active].text]}
wrapper="span"
speed={50}
repeat={0}
/>
</CT>
<Button href="#" color="cyan" className="text-sm px-4 py-2 lg:text-base">
Start
</Button>
</div> </div>
</div> </FadeIn>
<FadeIn transition={{ duration: 0.8, delay: 0.2 }}>
<div className="mx-auto max-w-4xl mt-6">
<P className="text-center" color="primary">
The future isnt about more tools. Its about one intelligent partner that can do it all. This is your gateway to creativity, automation, and discovery.
</P>
</div>
</FadeIn>
</div> </div>
</motion.section> <FadeIn transition={{ duration: 1, delay: 0.4 }}>
<section
className="relative w-full flex items-center justify-center overflow-hidden bg-transparent -mt-8 pt-0 pb-0"
onMouseEnter={() => setHovering(true)}
onMouseLeave={() => setHovering(false)}
>
<div className="relative w-full max-w-[1800px] h-[500px]" style={{ perspective: '1600px' }}>
<div className="absolute inset-0" style={{ transformStyle: 'preserve-3d' }}>
<AnimatePresence initial={false}>
{indices.map((idx, i) => {
const distance = i - VISIBLE;
const item = galleryItems[idx];
const x = distance * GAP;
const z = -Math.abs(distance) * DEPTH;
const r = distance * ROT_Y;
const s = 1 - Math.abs(distance) * SCALE_DROP;
const o = distance === 0 ? 1 : 0.80;
const zIndex = 100 - Math.abs(distance);
return (
<motion.div
key={`${idx}-${i}`}
className={`absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 will-change-transform overflow-hidden ${distance === 0 ? 'rounded-xl' : ''}`}
initial={{ opacity: 0 }}
animate={{
transform: `translateX(${x}px) translateZ(${z}px) rotateY(${r}deg) scale(${s})`,
zIndex,
opacity: o,
boxShadow: distance === 0 ? '0 0 20px 5px rgba(255, 255, 255, 0.2)' : 'none',
}}
exit={{ opacity: 0 }}
transition={{ type: 'spring', stiffness: 220, damping: 26 }}
onClick={() => setActive(idx)}
>
<div className="relative bg-black flex items-center justify-center">
<Image
src={item.image}
alt={item.text}
width={item.width}
height={item.height}
className="object-contain text-white"
priority={i === VISIBLE}
/>
</div>
</motion.div>
);
})}
</AnimatePresence>
</div>
</div>
{/* Arrows */}
<div className="absolute inset-y-0 left-8 flex items-center z-50">
<button
onClick={prev}
className="bg-transparent rounded-full p-2 shadow-lg backdrop-blur-md"
aria-label="Previous"
>
<svg className="size-8" viewBox="0 0 24 24" fill="none" dangerouslySetInnerHTML={{ __html: '<path d="M15 19L8 12l7-7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>' }} />
</button>
</div>
<div className="absolute inset-y-0 right-8 flex items-center z-50">
<button
onClick={next}
className="bg-transparent rounded-full p-2 shadow-lg backdrop-blur-md"
aria-label="Next"
>
<svg className="size-8" viewBox="0 0 24 24" fill="none" dangerouslySetInnerHTML={{ __html: '<path d="M9 5l7 7-7 7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>' }} />
</button>
</div>
{/* Foreground pill */}
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-[60]">
<div className="flex items-center justify-between w-[1040px] gap-6 rounded-2xl bg-black/30 shadow-[0_8px_40px_rgba(0,0,0,0.15)] px-12 backdrop-blur">
<CT as="h4" className="max-w-[820px] h-[72px] text-white flex items-center">
<TypeAnimation
key={active}
sequence={[galleryItems[active].text]}
wrapper="span"
speed={50}
repeat={0}
/>
</CT>
<Button href="#" color="cyan" className="text-sm px-4 py-2 lg:text-base">
Start
</Button>
</div>
</div>
</section>
</FadeIn>
</div> </div>
) );
} }

24
src/components/FadeIn.tsx Normal file
View File

@@ -0,0 +1,24 @@
'use client'
import { motion, Transition } from 'framer-motion'
import React from 'react'
type FadeInProps = {
children: React.ReactNode
transition?: Transition
className?: string
}
export function FadeIn({ children, transition, className }: FadeInProps) {
return (
<motion.div
className={className}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: false, margin: '0px 0px -100px 0px' }}
transition={transition || { duration: 0.5 }}
>
{children}
</motion.div>
)
}

View File

@@ -6,6 +6,7 @@ import { Container } from '@/components/Container'
import { TextField } from '@/components/Fields' import { TextField } from '@/components/Fields'
import { Logomark } from '@/components/Logo' import { Logomark } from '@/components/Logo'
import { NavLinks } from '@/components/NavLinks' import { NavLinks } from '@/components/NavLinks'
import { FadeIn } from '@/components/FadeIn'
import qrCode from '@/images/qr-code.svg' import qrCode from '@/images/qr-code.svg'
function QrCodeBorder(props: React.ComponentPropsWithoutRef<'svg'>) { function QrCodeBorder(props: React.ComponentPropsWithoutRef<'svg'>) {
@@ -23,6 +24,7 @@ function QrCodeBorder(props: React.ComponentPropsWithoutRef<'svg'>) {
export function Footer() { export function Footer() {
return ( return (
<footer id="footer" className="border-t border-gray-800"> <footer id="footer" className="border-t border-gray-800">
<FadeIn>
<Container> <Container>
<div className="flex flex-col items-start justify-between gap-y-12 pt-12 pb-6 lg:flex-row lg:items-center lg:py-12"> <div className="flex flex-col items-start justify-between gap-y-12 pt-12 pb-6 lg:flex-row lg:items-center lg:py-12">
<div> <div>
@@ -76,6 +78,7 @@ export function Footer() {
</p> </p>
</div> </div>
</Container> </Container>
</FadeIn>
</footer> </footer>
) )
} }

View File

@@ -1,63 +1,41 @@
"use client"; "use client";
import { StackedCubes } from "@/components/ui/StackedCubes"; import { StackedCubes } from "@/components/ui/StackedCubes";
import { Button } from "@/components/Button";
import { motion, useInView } from 'framer-motion';
import { H2, P } from '@/components/Texts'; import { H2, P } from '@/components/Texts';
import { useRef } from "react"; import { FadeIn } from "./FadeIn";
export function StackSectionPreview() { export function StackSectionPreview() {
const ref = useRef(null);
const isInView = useInView(ref);
return ( return (
<section ref={ref} className="w-full bg-transparent lg:px-0 py-24 px-6 relative"> <section className="w-full bg-transparent lg:px-0 py-24 px-6 relative">
{/* Gradient Blob Component */} {/* Gradient Blob Component */}
<motion.div <div
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 0.4 } : { opacity: 0 }}
transition={{ duration: 1, delay: 0.1 }}
className="absolute w-[400px] h-[200px] bg-gradient-to-br from-[#505050] to-[#7e7e7e] rounded-full blur-[150px] bottom-[200px] left-[-150px] z-0" className="absolute w-[400px] h-[200px] bg-gradient-to-br from-[#505050] to-[#7e7e7e] rounded-full blur-[150px] bottom-[200px] left-[-150px] z-0"
/> />
<motion.div <div
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 0.5 } : { opacity: 0 }}
transition={{ duration: 1, delay: 0.15 }}
className="absolute w-[200px] h-[100px] bg-gradient-to-br from-[#505050] to-[#7e7e7e] rounded-full blur-[150px] top-[200px] right-[-150px] z-0" className="absolute w-[200px] h-[100px] bg-gradient-to-br from-[#505050] to-[#7e7e7e] rounded-full blur-[150px] top-[200px] right-[-150px] z-0"
/> />
<div className="mx-auto max-w-7xl"> <div className="mx-auto max-w-7xl">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4 lg:gap-16 items-center lg:items-start"> <div className="grid grid-cols-1 lg:grid-cols-3 gap-4 lg:gap-16 items-center lg:items-start">
{/* Left Column - Text (1/3 width) */} {/* Left Column - Text (1/3 width) */}
<div className="text-left lg:text-left lg:col-span-1 order-1 lg:order-1"> <div className="text-left lg:text-left lg:col-span-1 order-1 lg:order-1">
<motion.div <FadeIn>
initial={{ opacity: 0, y: 30 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }}
transition={{ duration: 0.8, delay: 0.2 }}
>
<H2 className=""> <H2 className="">
The Mycelium Stack The Mycelium Stack
</H2> </H2>
</motion.div> </FadeIn>
<motion.div <FadeIn>
initial={{ opacity: 0, y: 30 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }}
transition={{ duration: 0.8, delay: 0.6 }}
>
<P className="mx-auto mt-8 max-w-3xl" color="light"> <P className="mx-auto mt-8 max-w-3xl" color="light">
Built with Mycelium technology, our AI infrastructure ensures unbreakable networks, complete data sovereignty, ultra-secure agent-human communication, and unhackable data storage systems. Built with Mycelium technology, our AI infrastructure ensures unbreakable networks, complete data sovereignty, ultra-secure agent-human communication, and unhackable data storage systems.
</P> </P>
</motion.div> </FadeIn>
</div> </div>
{/* Right Column - Stacked Cubes (2/3 width) */} {/* Right Column - Stacked Cubes (2/3 width) */}
<div className="lg:col-span-2 flex items-center justify-center lg:justify-start order-2 lg:order-2"> <div className="lg:col-span-2 flex items-center justify-center lg:justify-start order-2 lg:order-2">
<motion.div <FadeIn>
initial={{ opacity: 0, y: 30 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }}
transition={{ duration: 0.8, delay: 0.3 }}
>
<StackedCubes /> <StackedCubes />
</motion.div> </FadeIn>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -7,7 +7,7 @@ const colorVariants = {
primary: 'text-[#fffff]', primary: 'text-[#fffff]',
secondary: 'text-gray-200', secondary: 'text-gray-200',
custom: 'text-[#015eff]', custom: 'text-[#015eff]',
light: 'text-white', light: '[#fcfcfc]',
} as const } as const
type TextOwnProps = { type TextOwnProps = {

View File

@@ -1,6 +1,8 @@
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { H1, H2, H3, H4, P, CT, CP, NL } from "@/components/Texts"; import { CT, CP } from "@/components/Texts";
import Image from 'next/image'; import Image from 'next/image';
import React from 'react';
import { motion } from 'framer-motion';
export const BentoGrid = ({ export const BentoGrid = ({
className, className,
@@ -21,23 +23,17 @@ export const BentoGrid = ({
); );
}; };
export const BentoGridItem = ({ export const BentoGridItem = React.forwardRef<HTMLDivElement, {
className,
title,
subtitle,
description,
img,
video,
}: {
className?: string; className?: string;
title?: string | React.ReactNode; title?: string | React.ReactNode;
subtitle?: string | React.ReactNode; subtitle?: string | React.ReactNode;
description?: string | React.ReactNode; description?: string | React.ReactNode;
img?: string; img?: string;
video?: string; video?: string;
}) => { }>(({ className, title, subtitle, description, img, video }, ref) => {
return ( return (
<div <div
ref={ref}
className={cn( className={cn(
"group/bento shadow-input row-span-1 flex flex-col justify-between rounded-xl border border-black bg-black/10 backdrop-blur-md transition-all duration-300 ease-in-out hover:scale-105 hover:border-black hover:bg-black/40", "group/bento shadow-input row-span-1 flex flex-col justify-between rounded-xl border border-black bg-black/10 backdrop-blur-md transition-all duration-300 ease-in-out hover:scale-105 hover:border-black hover:bg-black/40",
className, className,
@@ -64,4 +60,8 @@ export const BentoGridItem = ({
</div> </div>
</div> </div>
); );
}; });
BentoGridItem.displayName = 'BentoGridItem';
export const MotionBentoGridItem = motion(BentoGridItem);