Compare commits

...

26 Commits

Author SHA1 Message Date
602b78b5bd style: improve hero section layout and text positioning for better responsiveness 2025-09-19 16:22:26 +02:00
9a4f347ee8 ok 2025-09-19 14:14:04 +02:00
017fc41d2b refactor: consolidate navigation links into reusable NavLinks component with dynamic styling 2025-09-19 14:08:46 +02:00
ab14a5a8e5 feat: add email links and update navigation structure 2025-09-19 14:01:47 +02:00
41d4c3a054 feat: adjust mobile viewport margin and update company branding in footer 2025-09-19 01:21:11 +02:00
a362985d4c style: improve text component spacing and center CTA content on mobile 2025-09-19 01:09:08 +02:00
1d66fd60a4 chore: adjust mobile carousel gap from 100 to 110 pixels 2025-09-19 01:02:53 +02:00
43d995bbc2 feat: add responsive carousel with mobile-optimized layout and controls 2025-09-19 01:01:46 +02:00
0dedde3592 style: adjust vertical padding for Companies component on mobile and desktop views 2025-09-19 00:48:17 +02:00
d5b9303d94 style: adjust spacing and padding in Steps component for better responsive layout 2025-09-19 00:46:28 +02:00
3a240177c4 feat: add responsive layout for WorldMap component on mobile devices 2025-09-19 00:43:42 +02:00
0479b7330a feat: add mobile carousel view with auto-play for BentoReviews component 2025-09-19 00:39:00 +02:00
a78bc67ed3 style: add responsive padding to BentoReviews component for mobile devices 2025-09-19 00:30:38 +02:00
a035500c34 style: adjust spacing and responsive layout for stack section and cubes 2025-09-19 00:27:35 +02:00
2b5c502724 feat: add mobile-friendly cube descriptions with click interaction 2025-09-19 00:12:16 +02:00
a462afc8b2 fix mobile 2025-09-19 00:07:14 +02:00
bf78cde2d8 feat: add row height control to BentoGrid and remove gradient blobs from StackSection 2025-09-18 20:26:37 +02:00
cde6c90033 fx 2025-09-18 20:21:48 +02:00
f5ab743987 style: update button hover states and add white variant to docs button 2025-09-18 20:11:56 +02:00
45364a7452 ok 2025-09-18 20:09:48 +02:00
b7f25d712f fix gry 2025-09-18 19:43:04 +02:00
2fdcb3697d feat: add hover opacity transitions and bottom margin to bento grid components 2025-09-18 18:17:19 +02:00
204625b9a8 add 2025-09-18 18:14:18 +02:00
02557fcb82 ok 2025-09-17 18:32:20 +02:00
9277bc7105 feat: add BentoReviews component with responsive grid layout for AI stack features 2025-09-17 17:21:30 +02:00
3f6ffbe4ea ok 2025-09-17 17:21:23 +02:00
45 changed files with 734 additions and 297 deletions

View File

@@ -1,35 +1,83 @@
# Mycelium # Mycelium Cloud Website
Mycelium is a [Tailwind Plus](https://tailwindcss.com/plus) site template built using [Tailwind CSS](https://tailwindcss.com) and [Next.js](https://nextjs.org). This is the official website for Mycelium Cloud, built using Next.js and Tailwind CSS.
## Getting started ## Getting Started
To get started with this template, first install the npm dependencies: Follow these instructions to get a local copy up and running for development and testing purposes.
```bash ### Prerequisites
npm install
```
Next, run the development server: Make sure you have Node.js and npm installed on your machine. You can download them from [nodejs.org](https://nodejs.org/).
### Installation
1. Clone the repository to your local machine.
2. Install the NPM packages:
```bash
npm install
```
### Running the Application
To run the development server:
```bash ```bash
npm run dev npm run dev
``` ```
Finally, open [http://localhost:3000](http://localhost:3000) in your browser to view the website. Open [http://localhost:3000](http://localhost:3000) in your browser to see the result.
## Customizing ## Git Workflow
You can start editing this template by modifying the files in the `/src` folder. The site will auto-update as you edit these files. We follow a branching model to ensure code quality and a stable production environment. All new work should be done on a feature branch.
1. **Switch to the `development` branch** and make sure it's up to date:
```bash
git checkout development
git pull origin development
```
2. **Create a new feature branch** for your changes:
```bash
git checkout -b your-feature-name
```
3. **Make your changes and commit them**.
4. **Push your feature branch** to the remote repository:
```bash
git push origin your-feature-name
```
5. **Create a Pull Request** on GitHub from your feature branch to the `development` branch.
6. After the pull request is reviewed and merged, the changes will be on the `development` branch. To deploy to production, the `development` branch will be merged into `main`.
## Project Structure
Here is an overview of the key directories in the project:
- `src/app/(main)/page.tsx`
This is the main entry point for the homepage.
- `src/components/`
This directory contains all the reusable React components used throughout the site. The main components rendered on the homepage (`src/app/(main)/page.tsx`) are:
- `HomeHero.tsx`
- `StackSection.tsx` (as `StackSectionPreview`)
- `BentoReviews.tsx`
- `WorldMap.tsx`
- `Steps.tsx`
- `Companies.tsx`
- `ClickableGallery.tsx`
- `CallToAction.tsx`
- `public/images/`
All static images are stored here. You can find logos, gallery images, and other visual assets in this folder.
- `public/videos/`
This folder contains video assets used on the site.
## License ## License
This site template is a commercial product and is licensed under the [Tailwind Plus license](https://tailwindcss.com/plus/license). This site template is a commercial product and is licensed under the [Tailwind Plus license](https://tailwindcss.com/plus/license).
## Learn more
To learn more about the technologies used in this site template, see the following resources:
- [Tailwind CSS](https://tailwindcss.com/docs) - the official Tailwind CSS documentation
- [Next.js](https://nextjs.org/docs) - the official Next.js documentation
- [Headless UI](https://headlessui.dev) - the official Headless UI documentation

1
next-env.d.ts vendored
View File

@@ -1,5 +1,6 @@
/// <reference types="next" /> /// <reference types="next" />
/// <reference types="next/image-types/global" /> /// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />
// NOTE: This file should not be edited // NOTE: This file should not be edited
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. // see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.

27
package-lock.json generated
View File

@@ -11,6 +11,7 @@
"@headlessui/react": "^2.1.0", "@headlessui/react": "^2.1.0",
"@heroicons/react": "^2.2.0", "@heroicons/react": "^2.2.0",
"@lobehub/icons": "^1.97.2", "@lobehub/icons": "^1.97.2",
"@tabler/icons-react": "^3.35.0",
"@tailwindcss/forms": "^0.5.3", "@tailwindcss/forms": "^0.5.3",
"@types/node": "^20.10.8", "@types/node": "^20.10.8",
"@types/react": "^18.2.55", "@types/react": "^18.2.55",
@@ -2976,6 +2977,32 @@
"tslib": "^2.8.0" "tslib": "^2.8.0"
} }
}, },
"node_modules/@tabler/icons": {
"version": "3.35.0",
"resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.35.0.tgz",
"integrity": "sha512-yYXe+gJ56xlZFiXwV9zVoe3FWCGuZ/D7/G4ZIlDtGxSx5CGQK110wrnT29gUj52kEZoxqF7oURTk97GQxELOFQ==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/codecalm"
}
},
"node_modules/@tabler/icons-react": {
"version": "3.35.0",
"resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.35.0.tgz",
"integrity": "sha512-XG7t2DYf3DyHT5jxFNp5xyLVbL4hMJYJhiSdHADzAjLRYfL7AnjlRfiHDHeXxkb2N103rEIvTsBRazxXtAUz2g==",
"license": "MIT",
"dependencies": {
"@tabler/icons": "3.35.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/codecalm"
},
"peerDependencies": {
"react": ">= 16"
}
},
"node_modules/@tailwindcss/forms": { "node_modules/@tailwindcss/forms": {
"version": "0.5.10", "version": "0.5.10",
"resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.10.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.10.tgz",

View File

@@ -13,6 +13,7 @@
"@headlessui/react": "^2.1.0", "@headlessui/react": "^2.1.0",
"@heroicons/react": "^2.2.0", "@heroicons/react": "^2.2.0",
"@lobehub/icons": "^1.97.2", "@lobehub/icons": "^1.97.2",
"@tabler/icons-react": "^3.35.0",
"@tailwindcss/forms": "^0.5.3", "@tailwindcss/forms": "^0.5.3",
"@types/node": "^20.10.8", "@types/node": "^20.10.8",
"@types/react": "^18.2.55", "@types/react": "^18.2.55",

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
public/videos/agent.mp4 Normal file

Binary file not shown.

Binary file not shown.

BIN
public/videos/fungistor.mp4 Normal file

Binary file not shown.

BIN
public/videos/herodb.mp4 Normal file

Binary file not shown.

BIN
public/videos/mesh.mp4 Normal file

Binary file not shown.

BIN
public/videos/sandbox.mp4 Normal file

Binary file not shown.

BIN
public/videos/universal.mp4 Normal file

Binary file not shown.

View File

@@ -13,6 +13,7 @@ import { ScrollUp } from '@/components/ui/ScrollUp'
import { GridStats } from '@/components/GridStats' import { GridStats } from '@/components/GridStats'
import { WorldMap } from '@/components/WorldMap' import { WorldMap } from '@/components/WorldMap'
import { GetStarted } from '@/components/GetStarted' import { GetStarted } from '@/components/GetStarted'
import { BentoReviews } from '@/components/BentoReviews'
export default function Home() { export default function Home() {
return ( return (
@@ -20,9 +21,12 @@ export default function Home() {
<section id="home-hero"> <section id="home-hero">
<HomeHero /> <HomeHero />
</section> </section>
<section id="about"> <section id="technologies">
<StackSectionPreview /> <StackSectionPreview />
</section> </section>
<section id="bento-reviews">
<BentoReviews />
</section>
<section id="network"> <section id="network">
<WorldMap /> <WorldMap />
</section> </section>
@@ -32,15 +36,9 @@ export default function Home() {
<section id="llms"> <section id="llms">
<Companies /> <Companies />
</section> </section>
<section id="features">
<UseCases />
</section>
<section id="clickable-gallery"> <section id="clickable-gallery">
<ClickableGallery /> <ClickableGallery />
</section> </section>
<section id="get-started">
<GetStarted />
</section>
<section id="call-to-action"> <section id="call-to-action">
<CallToAction /> <CallToAction />
</section> </section>

View File

@@ -0,0 +1,172 @@
"use client";
import { cn } from "@/lib/utils";
import { H2, P } from "@/components/Texts";
import React, { useState, useEffect, useRef } from "react";
import { BentoGrid, MotionBentoGridItem } from "@/components/ui/bento-grid";
import { AnimatePresence, motion } from "framer-motion";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { FadeIn } from "./FadeIn";
const items = [
{
title: 'FungiStor',
subtitle: 'Long-Term AI Memory',
description: 'Quantum-safe permanent storage preserving AI knowledge forever. Zero-knowledge architecture with mathematical dispersal ensures immortality.',
video: "/videos/fungistor.mp4",
},
{
title: 'HeroDB',
subtitle: 'Active AI Memory',
description: 'High-performance datastore for AI working memory. Multi-modal indexing enables vector search with global accessibility.',
video: "/videos/herodb.mp4",
},
{
title: 'MOS Sandboxes',
subtitle: 'Secure Agent Workspaces',
description: 'Lightweight isolated environments deploying globally in five seconds. Hardware-level isolation ensures maximum security for agents.',
video: "/videos/sandbox.mp4",
},
{
title: 'Mycelium Mesh',
subtitle: 'Secure Communication Network',
description: 'Peer-to-peer overlay network with end-to-end encryption. Self-healing shortest-path routing creates resilient agentic communication.',
video: "/videos/mesh.mp4",
},
{
title: 'Deterministic Deployment',
subtitle: 'Verifiable Code Execution',
description: 'Cryptographic guarantee system ensuring deployed code matches specifications. Prevents supply-chain attacks with immutable trails.',
video: "/videos/deterministic.mp4",
},
{
title: 'Agent Coordination',
subtitle: 'Sovereign Workflow Management',
description: 'User-centric orchestration where HERO agents coordinate worker fleets. Planetary-scale coordination with instant spawning.',
video: "/videos/agent.mp4",
},
{
title: 'Universal Interface Layer',
subtitle: 'AI Service Gateway',
description: 'Unified broker connecting agents to LLMs, APIs, and services. Integrated micropayments simplify development.',
video: "/videos/universal.mp4",
},
];
export function BentoReviews() {
const [activeIndex, setActiveIndex] = useState(0);
const [isPaused, setIsPaused] = useState(false);
const intervalRef = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
if (!isPaused) {
intervalRef.current = setInterval(() => {
setActiveIndex((prevIndex) => (prevIndex + 1) % items.length);
}, 3000);
} else {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
}
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}, [isPaused]);
const handleCardTap = () => {
setIsPaused(true);
};
const handlePrev = () => {
setActiveIndex((prevIndex) => (prevIndex - 1 + items.length) % items.length);
setIsPaused(true);
};
const handleNext = () => {
setActiveIndex((prevIndex) => (prevIndex + 1) % items.length);
setIsPaused(true);
};
return (
<div>
<div className="relative isolate pt-24 pb-12 bg-black text-center w-full lg:px-0 px-4">
<FadeIn transition={{ duration: 0.8, delay: 0.1 }}>
<div className="mx-auto max-w-5xl ">
<H2 className="text-center">Mycelium Technologies</H2>
</div>
</FadeIn>
<FadeIn transition={{ duration: 0.8, delay: 0.2 }}>
<div className="mx-auto max-w-4xl mt-6 mb-8">
<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>
</div>
</FadeIn>
</div>
{/* Desktop Grid */}
<div className="hidden lg:block">
<BentoGrid className="max-w-8xl lg:px-12 px-4 pb-12 lg:grid-cols-3">
{items.map((item, i) => (
<MotionBentoGridItem
key={i}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: false, margin: '0px 0px -100px 0px' }}
transition={{ duration: 0.8, delay: 0.3 + i * 0.1 }}
className={cn(i === 3 || i === 6 ? "md:col-span-2" : "")}
rowHeight={i >= 3 ? "h-[22rem]" : ""}
title={item.title}
subtitle={item.subtitle}
description={item.description}
video={item.video}
/>
))}
</BentoGrid>
</div>
{/* Mobile Carousel */}
<div className="lg:hidden block px-4 pb-12">
<div className="relative h-[24rem] w-full overflow-hidden">
<div className="absolute inset-0" onTouchStart={handleCardTap} />
<AnimatePresence initial={false}>
<motion.div
key={activeIndex}
className="absolute h-full w-full"
initial={{ x: "100%", opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
exit={{ x: "-100%", opacity: 0 }}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
>
<MotionBentoGridItem
className="h-full"
title={items[activeIndex].title}
subtitle={items[activeIndex].subtitle}
description={items[activeIndex].description}
video={items[activeIndex].video}
/>
</motion.div>
</AnimatePresence>
<button
onClick={handlePrev}
className="absolute left-2 top-[58%] -translate-y-1/2 rounded-full bg-black/50 p-2 text-white z-10"
>
<ChevronLeft className="h-6 w-6" />
</button>
<button
onClick={handleNext}
className="absolute right-2 top-[58%] -translate-y-1/2 rounded-full bg-black/50 p-2 text-white z-10"
>
<ChevronRight className="h-6 w-6" />
</button>
</div>
</div>
</div>
);
}

View File

@@ -17,7 +17,7 @@ const variantStyles = {
}, },
outline: { outline: {
gray: 'border-gray-300 text-gray-700 hover:border-gray-400 active:bg-gray-100 active:text-gray-700/80', gray: 'border-gray-300 text-gray-700 hover:border-gray-400 active:bg-gray-100 active:text-gray-700/80',
white: 'border-gray-300 text-white hover:border-gray-400 active:bg-gray-100 active:text-white', white: 'border-gray-300 text-white hover:border-gray-400 hover:text-gray-300 active:bg-gray-100 active:text-gray-800',
}, },
} }

View File

@@ -13,12 +13,14 @@ export function CallTo() {
</P> </P>
<div className="mt-10 flex items-center justify-center gap-x-6"> <div className="mt-10 flex items-center justify-center gap-x-6">
<a <a
href="#" href="mailto:info@ourworld.tf"
target="_blank"
rel="noopener noreferrer"
className="rounded-md bg-[#2F3178] px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-[#2F3178]/80 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#2F3178]" className="rounded-md bg-[#2F3178] px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-[#2F3178]/80 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#2F3178]"
> >
Book a Meeting Book a Meeting
</a> </a>
<a href="#" className="text-sm/6 font-semibold text-[#2F3178] hover:text-[#2F3178]/80"> <a href="mailto:info@ourworld.tf" target="_blank" rel="noopener noreferrer" className="text-sm/6 font-semibold text-[#2F3178] hover:text-[#2F3178]/80">
Join the Waitlist <span aria-hidden="true"></span> Join the Waitlist <span aria-hidden="true"></span>
</a> </a>
</div> </div>

View File

@@ -1,12 +1,13 @@
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 (
<section <section
id="get-free-shares-today" id="get-free-shares-today"
className="relative overflow-hidden py-20 sm:py-28" className="relative overflow-hidden py-20 sm:py-28 border-t border-gray-800"
> >
<video <video
autoPlay autoPlay
@@ -18,11 +19,12 @@ export function CallToAction() {
<source src="/videos/cta.mp4" type="video/mp4" /> <source src="/videos/cta.mp4" type="video/mp4" />
</video> </video>
<div className="absolute top-0 left-0 w-full h-full bg-black opacity-40 z-10"></div> <div className="absolute top-0 left-0 w-full h-full bg-black opacity-40 z-10"></div>
<div className="absolute left-20 top-1/2 -translate-y-1/2 sm:left-1/2 sm:-translate-x-1/2 z-20"> <div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 sm:left-1/2 sm:-translate-x-1/2 z-20">
<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">
<div className="mx-auto max-w-md sm:text-center"> <FadeIn>
<div className="mx-auto max-w-md 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
</h2> </h2>
@@ -31,14 +33,21 @@ export function CallToAction() {
build your own. Ready to own your intelligence? build your own. Ready to own your intelligence?
</p> </p>
<div className="mt-8 flex justify-center gap-x-6"> <div className="mt-8 flex justify-center gap-x-6">
<Button variant="solid" color="cyan" href="#"> <Button
variant="solid"
color="cyan"
href="mailto:info@ourworld.tf"
target="_blank"
rel="noopener noreferrer"
>
Book a Meeting Book a Meeting
</Button> </Button>
<Button href="#" variant="outline" color="white"> <Button href="mailto:info@ourworld.tf" target="_blank" rel="noopener noreferrer" variant="outline" color="white">
Join the Waitlist Join the Waitlist
</Button> </Button>
</div> </div>
</div> </div>
</FadeIn>
</Container> </Container>
</section> </section>
) )

View File

@@ -1,41 +1,37 @@
'use client' 'use client'
import { useEffect, useMemo, useState, useRef } from 'react' import { useEffect, useMemo, useState } from 'react'
import { useResponsiveCarousel } from '@/hooks/useResponsiveCarousel';
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 } 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/interface.png' }, { text: 'Navigate and interact with any web interface', image: '/images/gallery/interface.jpg', width: 448, height: 277 },
{ text: 'Process documents across all formats', image: '/images/docs.png' }, { text: 'Process documents across all formats', image: '/images/gallery/docs.jpg', width: 448, height: 277 },
{ text: 'Execute multi-step workflows autonomously', image: '/images/flow.png' }, { text: 'Execute multi-step workflows autonomously', image: '/images/gallery/flow.jpg', width: 448, height: 277 },
{ text: 'Manage calendars, emails, and tasks', image: '/images/calendar.png' }, { text: 'Manage calendars, emails, and tasks', image: '/images/gallery/calendar.jpg', width: 448, height: 277 },
{ text: 'Perform deep semantic search across all data sources', image: '/images/data.png' }, { text: 'Perform deep semantic search across all data sources', image: '/images/gallery/data.jpg', width: 448, height: 277 },
{ text: 'Identify patterns in complex datasets', image: '/images/datasets.png' }, { text: 'Identify patterns in complex datasets', image: '/images/gallery/datasets.jpg', width: 448, height: 277 },
{ text: 'Provide real-time market intelligence', image: '/images/market.png' }, { text: 'Provide real-time market intelligence', image: '/images/gallery/market.jpg', width: 448, height: 277 },
{ text: 'Generate and debug code in multiple languages', image: '/images/code.png' }, { text: 'Generate and debug code in multiple languages', image: '/images/gallery/code.jpg', width: 448, height: 277 },
{ text: 'Create consistent branded content', image: '/images/branding.png' }, { text: 'Create consistent branded content', image: '/images/gallery/branding.jpg', width: 448, height: 277 },
{ text: 'Translate and localize materials', image: '/images/translate.png' }, { text: 'Translate and localize materials', image: '/images/gallery/translate.jpg', width: 448, height: 277 },
{ text: 'Transform and migrate data structures', image: '/images/structure.png' }, { text: 'Transform and migrate data structures', image: '/images/gallery/structure.jpg', width: 448, height: 277 },
] ]
// 🔧 Carousel Config // 🔧 Carousel Config
const VISIBLE = 4 const VISIBLE = 4;
const CARD_SIZE = 360 // square size on desktop const AUTOPLAY_MS = 3200;
const GAP = 300 // spacing for larger cards
const ROT_Y = 18
const DEPTH = 210
const SCALE_DROP = 0.12
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 { GAP, ROT_Y, DEPTH, SCALE_DROP } = useResponsiveCarousel();
const isInView = useInView(ref, { once: true });
// autoplay // autoplay
useEffect(() => { useEffect(() => {
@@ -53,98 +49,98 @@ 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="py-24 relative isolate pt-24 pb-0 bg-black 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 mt-12">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"> </div>
</FadeIn>
<FadeIn transition={{ duration: 0.8, delay: 0.2 }}>
<div className="mx-auto max-w-4xl mt-6 lg:px-0 px-4">
<P className="text-center" color="primary"> <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. 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> </P>
</motion.div>
</div> </div>
<motion.section </FadeIn>
initial={{ opacity: 0 }} </div>
animate={isInView ? { opacity: 1 } : { opacity: 0 }} <FadeIn transition={{ duration: 1, delay: 0.4 }}>
transition={{ duration: 1, delay: 0.4 }} <section
className="relative w-full flex items-center justify-center overflow-hidden bg-black pt-0 pb-32" className="relative w-full flex items-center justify-center overflow-hidden bg-transparent -mt-8 pt-0 pb-0"
onMouseEnter={() => setHovering(true)} onMouseEnter={() => setHovering(true)}
onMouseLeave={() => setHovering(false)} onMouseLeave={() => setHovering(false)}
> >
<div className="relative w-full max-w-[1800px] h-[300px] md:h-[500px]" style={{ perspective: '1600px' }}>
<div className="relative w-full max-w-[1800px] h-[500px]" style={{ perspective: '1600px' }}>
<div className="absolute inset-0" style={{ transformStyle: 'preserve-3d' }}> <div className="absolute inset-0" style={{ transformStyle: 'preserve-3d' }}>
<AnimatePresence initial={false}> <AnimatePresence initial={false}>
{indices.map((idx, i) => { {indices.map((idx, i) => {
const distance = i - VISIBLE const distance = i - VISIBLE;
const item = galleryItems[idx] const item = galleryItems[idx];
const x = distance * GAP const x = distance * GAP;
const z = -Math.abs(distance) * DEPTH const z = -Math.abs(distance) * DEPTH;
const r = distance * ROT_Y const r = distance * ROT_Y;
const s = 1 - Math.abs(distance) * SCALE_DROP const s = 1 - Math.abs(distance) * SCALE_DROP;
const o = distance === 0 ? 1 : 0.90 const o = distance === 0 ? 1 : 0.80;
const zIndex = 100 - Math.abs(distance) const zIndex = 100 - Math.abs(distance);
return ( return (
<motion.div <motion.div
key={`${idx}-${i}`} key={`${idx}-${i}`}
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 will-change-transform" 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 }} initial={{ opacity: 0 }}
animate={{ animate={{
transform: `translateX(${x}px) translateZ(${z}px) rotateY(${r}deg) scale(${s})`, transform: `translateX(${x}px) translateZ(${z}px) rotateY(${r}deg) scale(${s})`,
zIndex, zIndex,
opacity: o, opacity: o,
boxShadow: distance === 0 ? '0 0 20px 5px rgba(255, 255, 255, 0.2)' : 'none',
}} }}
exit={{ opacity: 0 }} exit={{ opacity: 0 }}
transition={{ type: 'spring', stiffness: 220, damping: 26 }} transition={{ type: 'spring', stiffness: 220, damping: 26 }}
onClick={() => setActive(idx)} onClick={() => setActive(idx)}
> >
{/* Square container, keeps image ratio inside */} <div className="relative bg-black flex items-center justify-center">
<div
className="relative rounded-2xl overflow-hidden bg-white flex items-center justify-center"
style={{ width: CARD_SIZE, height: CARD_SIZE }}
>
<Image <Image
src={item.image} src={item.image}
alt={item.text} alt={item.text}
fill width={item.width}
className="object-contain rounded-2xl text-black" height={item.height}
className="object-contain text-white"
priority={i === VISIBLE} priority={i === VISIBLE}
/> />
</div> </div>
</motion.div> </motion.div>
) );
})} })}
</AnimatePresence> </AnimatePresence>
</div> </div>
</div>
{/* Arrows */} {/* Arrows */}
<div className="absolute inset-y-0 left-8 flex items-center z-50"> {/* Arrows */}
<div className="absolute inset-y-0 left-8 hidden md:flex items-center z-50">
<button <button
onClick={prev} onClick={prev}
className="bg-white/70 hover:bg-white rounded-full p-3 shadow-lg backdrop-blur-md" className="bg-transparent rounded-full p-2 shadow-lg backdrop-blur-md"
aria-label="Previous" 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"/>' }} /> <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> </button>
</div> </div>
<div className="absolute inset-y-0 right-8 flex items-center z-50"> <div className="absolute inset-y-0 right-8 hidden md:flex items-center z-50">
<button <button
onClick={next} onClick={next}
className="bg-white/70 hover:bg-white rounded-full p-3 shadow-lg backdrop-blur-md" className="bg-transparent rounded-full p-2 shadow-lg backdrop-blur-md"
aria-label="Next" 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"/>' }} /> <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> </button>
</div> </div>
{/* Foreground pill */} {/* Foreground pill (Desktop) */}
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-[60]"> <div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-[60] hidden md:block">
<div className="flex items-center justify-between w-[1040px] gap-6 rounded-3xl bg-white/95 shadow-[0_8px_40px_rgba(0,0,0,0.15)] px-12 py-6 backdrop-blur"> <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">
<H4 as="h4" className="max-w-[820px] h-[72px] text-black"> <CT as="h4" className="max-w-[820px] h-[72px] text-white flex items-center">
<TypeAnimation <TypeAnimation
key={active} key={active}
sequence={[galleryItems[active].text]} sequence={[galleryItems[active].text]}
@@ -152,14 +148,32 @@ export function ClickableGallery() {
speed={50} speed={50}
repeat={0} repeat={0}
/> />
</H4> </CT>
<Button href="#" color="cyan" className="text-sm px-4 py-2 lg:text-base"> <Button href="#" color="cyan" className="text-sm px-4 py-2 lg:text-base whitespace-nowrap">
Start Start
</Button> </Button>
</div> </div>
</div> </div>
</section>
{/* Text box (Mobile) */}
<div className="md:hidden w-full px-4 -mt-12 mb-16">
<div className="flex flex-row items-center justify-between w-full gap-x-4 rounded-2xl bg-white/10 bg-opacity-80 p-4 backdrop-blur-md">
<CT as="h4" className="w-full text-left h-[72px] text-white leading-tight flex items-center">
<TypeAnimation
key={active}
sequence={[galleryItems[active].text]}
wrapper="span"
speed={50}
repeat={0}
/>
</CT>
<Button href="#" color="cyan" className="text-xs px-3 py-1.5 whitespace-nowrap">
Start
</Button>
</div> </div>
</motion.section>
</div> </div>
) </FadeIn>
</div>
);
} }

View File

@@ -40,7 +40,7 @@ const row2 = logos.slice(6);
export function Companies() { export function Companies() {
return ( return (
<div id="companies" className="relative bg-black flex flex-col items-center justify-center w-full overflow-hidden antialiased py-12 -top-20"> <div id="companies" className="relative bg-black flex flex-col items-center justify-center w-full overflow-hidden antialiased lg:py-12 py-4 -top-20">
<div className="relative z-10 mx-auto w-full max-w-6xl p-4"> <div className="relative z-10 mx-auto w-full max-w-6xl p-4">
{/* Heading */} {/* Heading */}

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

@@ -0,0 +1,28 @@
'use client'
import { motion, Transition } from 'framer-motion'
import React from 'react'
import { useMediaQuery } from '@/hooks/useMediaQuery'
type FadeInProps = {
children: React.ReactNode
transition?: Transition
className?: string
}
export function FadeIn({ children, transition, className }: FadeInProps) {
const isMobile = useMediaQuery('(max-width: 768px)')
return (
<motion.div
className={className}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: false, margin: isMobile ? '0px 0px -50px 0px' : '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,8 +24,9 @@ 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-16 pb-6 lg:flex-row lg:items-center lg:py-16"> <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>
<div className="flex items-center text-white"> <div className="flex items-center text-white">
<Logomark className="h-10 w-10 flex-none fill-cyan-500" /> <Logomark className="h-10 w-10 flex-none fill-cyan-500" />
@@ -56,7 +58,7 @@ export function Footer() {
</div> </div>
</div> </div>
<div className="flex flex-col items-center border-t border-gray-800 pt-8 pb-12 md:flex-row-reverse md:justify-between md:pt-6"> <div className="flex flex-col items-center border-t border-gray-800 pt-8 pb-12 md:flex-row-reverse md:justify-between md:pt-6">
<form className="flex w-full justify-center md:w-auto"> {/* <form className="flex w-full justify-center md:w-auto">
<TextField <TextField
type="email" type="email"
aria-label="Email address" aria-label="Email address"
@@ -70,12 +72,13 @@ export function Footer() {
<span className="hidden lg:inline">Join our newsletter</span> <span className="hidden lg:inline">Join our newsletter</span>
<span className="lg:hidden">Join newsletter</span> <span className="lg:hidden">Join newsletter</span>
</Button> </Button>
</form> </form> */}
<p className="mt-6 text-sm text-gray-400 md:mt-0"> <p className="mt-6 text-sm text-gray-400 md:mt-0 ">
&copy; Copyright ThreeFold {new Date().getFullYear()}. All rights reserved. &copy; Copyright OurWorld Holdings, {new Date().getFullYear()}. All rights reserved.
</p> </p>
</div> </div>
</Container> </Container>
</FadeIn>
</footer> </footer>
) )
} }

View File

@@ -48,7 +48,7 @@ function MobileNavLink(
return ( return (
<PopoverButton <PopoverButton
as={Link} as={Link}
className="block text-base/7 tracking-tight text-[#2F3178]" className="block text-base/7 tracking-tight text-white"
{...props} {...props}
/> />
) )
@@ -72,7 +72,7 @@ export function Header() {
{({ open }) => ( {({ open }) => (
<> <>
<PopoverButton <PopoverButton
className="relative z-10 -m-2 inline-flex items-center rounded-lg stroke-gray-900 p-2 hover:bg-gray-200/50 hover:stroke-gray-600 focus:not-data-focus:outline-hidden active:stroke-gray-900" className="relative z-10 -m-2 inline-flex items-center rounded-lg stroke-white p-2 hover:bg-gray-200/50 hover:stroke-gray-400 focus:not-data-focus:outline-hidden active:stroke-white"
aria-label="Toggle site navigation" aria-label="Toggle site navigation"
> >
{({ open }) => {({ open }) =>
@@ -104,25 +104,13 @@ export function Header() {
y: -32, y: -32,
transition: { duration: 0.2 }, transition: { duration: 0.2 },
}} }}
className="absolute inset-x-0 top-0 z-0 origin-top rounded-b-2xl bg-white px-6 pt-32 pb-6 shadow-2xl shadow-gray-900/20" className="absolute inset-x-0 top-0 z-0 origin-top rounded-b-2xl bg-gray-900 px-6 pt-32 pb-6 shadow-2xl shadow-gray-900/20"
> >
<div className="space-y-4"> <div className="space-y-4">
<MobileNavLink href="/#about"> <NavLinks className="block text-base/7 tracking-tight" />
About
</MobileNavLink>
<MobileNavLink href="/#benefits">
Benefits
</MobileNavLink>
<MobileNavLink href="/#features">
Features
</MobileNavLink>
<MobileNavLink href="/#usecases">
Use Cases
</MobileNavLink>
<MobileNavLink href="/#faqs">FAQs</MobileNavLink>
</div> </div>
<div className="mt-8 flex flex-col gap-4"> <div className="mt-8 flex flex-col gap-4">
<Button href="https://docs.ourworld.tf/mycelium_cloud/docs/" variant="outline" color="white"> <Button href="https://docs.ourworld.tf/mycelium_cloud/docs/" variant="outline" color="white" target="_blank" rel="noopener noreferrer">
Docs Docs
</Button> </Button>
<Button href="https://www.mycelium.threefold.io/download/" color="cyan">Get Started</Button> <Button href="https://www.mycelium.threefold.io/download/" color="cyan">Get Started</Button>
@@ -135,7 +123,7 @@ export function Header() {
)} )}
</Popover> </Popover>
<div className="flex items-center gap-6 max-lg:hidden"> <div className="flex items-center gap-6 max-lg:hidden">
<Button href="https://docs.ourworld.tf/mycelium_cloud/docs/" variant="outline"> <Button href="https://docs.ourworld.tf/mycelium_cloud/docs/" variant="outline" color="white" target="_blank" rel="noopener noreferrer">
Docs Docs
</Button> </Button>
<Button href="https://www.mycelium.threefold.io/download/" color="cyan">Get Started</Button> <Button href="https://www.mycelium.threefold.io/download/" color="cyan">Get Started</Button>

View File

@@ -5,7 +5,7 @@ import { motion } from 'framer-motion'
import { TypeAnimation } from 'react-type-animation' import { TypeAnimation } from 'react-type-animation'
import { Dialog, DialogPanel } from '@headlessui/react' import { Dialog, DialogPanel } from '@headlessui/react'
import { Bars3Icon, XMarkIcon, ChevronDoubleDownIcon } from '@heroicons/react/24/outline' import { Bars3Icon, XMarkIcon, ChevronDoubleDownIcon } from '@heroicons/react/24/outline'
import { H1, PL } from '@/components/Texts' import { H1, H2, PL } from '@/components/Texts'
const navigation = [ const navigation = [
{ name: 'Product', href: '#' }, { name: 'Product', href: '#' },
@@ -32,8 +32,9 @@ export function HomeHero() {
<div className="absolute inset-0 bg-black/60" /> <div className="absolute inset-0 bg-black/60" />
</div> </div>
<div className="relative px-6 lg:px-8"> <div className="relative px-6 lg:px-8">
<div className="relative -top-15 mx-auto max-w-8xl h-screen flex items-center justify-center"> <div className="relative mt-4 mx-auto flex h-screen max-w-8xl items-center justify-center">
<div className="text-center max-w-5xl"> <div className="text-center">
<div className="max-w-6xl">
<H1 color="light"> <H1 color="light">
<TypeAnimation <TypeAnimation
sequence={[ sequence={[
@@ -46,17 +47,33 @@ export function HomeHero() {
/> />
</H1> </H1>
</div> </div>
{/* Mobile-only PL */}
<motion.div <motion.div
initial={{ opacity: 0 }} initial={{ opacity: 0 }}
animate={{ opacity: 1 }} animate={{ opacity: 1 }}
transition={{ duration: 1, delay: 1 }} transition={{ duration: 1, delay: 1 }}
className="lg:hidden"
> >
<PL className="absolute bottom-0 left-0 max-w-xl text-left text-gray-100" color="light"> <PL className="mt-12 max-w-3xl text-center text-gray-100" color="light">
Mycelium's advancements in Agentic infrastructure supports private, secure and autonomous Agents that connect, learn and grow with you.
</PL>
</motion.div>
{/* Desktop-only PL */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 1, delay: 1 }}
className="hidden lg:block"
>
<PL className="mt-12 max-w-4xl text-center text-gray-100 mx-auto" color="light">
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.
</PL> </PL>
</motion.div> </motion.div>
</div> </div>
</div> </div>
</div> </div>
</div>
) )
} }

View File

@@ -3,8 +3,9 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import Link from 'next/link' import Link from 'next/link'
import { AnimatePresence, motion } from 'framer-motion' import { AnimatePresence, motion } from 'framer-motion'
import clsx from 'clsx'
export function NavLinks() { export function NavLinks({ className }: { className?: string }) {
let [hoveredIndex, setHoveredIndex] = useState<number | null>(null) let [hoveredIndex, setHoveredIndex] = useState<number | null>(null)
let timeoutRef = useRef<number | null>(null) let timeoutRef = useRef<number | null>(null)
@@ -23,17 +24,18 @@ export function NavLinks() {
}; };
return [ return [
['About', '/#about'], ['Technologies', '/#technologies'],
['Network', '/#network'], ['Network', '/#network'],
['Deploy', '/#deploy'], ['How it Works', '/#how-it-works'],
['LLMs', '/#llms'],
['Features', '/#features'],
['Get Started', '/#get-started'], ['Get Started', '/#get-started'],
].map(([label, href], index) => ( ].map(([label, href], index) => (
<Link <Link
key={label} key={label}
href={href} href={href}
className="relative -mx-3 -my-2 rounded-lg px-3 py-2 text-sm text-white transition-colors delay-150 hover:text-gray-300 hover:delay-0" className={clsx(
'relative -mx-3 -my-2 rounded-lg px-3 py-2 text-sm text-white transition-colors delay-150 hover:text-gray-300 hover:delay-0',
className,
)}
onClick={(e) => handleClick(e, href)} onClick={(e) => handleClick(e, href)}
onMouseEnter={() => { onMouseEnter={() => {
if (timeoutRef.current) { if (timeoutRef.current) {

View File

@@ -1,63 +1,34 @@
"use client"; "use client";
import { StackedCubes } from "@/components/ui/StackedCubes"; import { StackedCubes } from "@/components/ui/StackedCubes";
import { Button } from "@/components/Button"; import { H1, H2, P } from '@/components/Texts';
import { motion, useInView } from 'framer-motion'; import { FadeIn } from "./FadeIn";
import { H2, P } from '@/components/Texts';
import { useRef } from "react";
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-12 lg:py-24 px-6 relative">
{/* Gradient Blob Component */}
<motion.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"
/>
<motion.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"
/>
<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-center 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 mt-8 lg:mt-0">
<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

@@ -42,7 +42,7 @@ export function Steps() {
<H2 className="text-3xl font-medium tracking-tight" color="light"> <H2 className="text-3xl font-medium tracking-tight" color="light">
Deploy Scalable LLMs and AI Agents in Seconds Deploy Scalable LLMs and AI Agents in Seconds
</H2> </H2>
<P className="mt-6 text-lg" color="light"> <P className="mt-6" color="light">
Launch and scale intelligence on your own terms. Mycelium Cloud makes it simple to deploy models, integrate knowledge, and run everything on a network you control. Launch and scale intelligence on your own terms. Mycelium Cloud makes it simple to deploy models, integrate knowledge, and run everything on a network you control.
</P> </P>
</motion.div> </motion.div>
@@ -50,7 +50,7 @@ export function Steps() {
initial={{ opacity: 0 }} initial={{ opacity: 0 }}
animate={isInView ? { opacity: 1 } : { opacity: 0 }} animate={isInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 0.5, delay: 0.2, staggerChildren: 0.2 }} transition={{ duration: 0.5, delay: 0.2, staggerChildren: 0.2 }}
className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-x-8 gap-y-16 text-base/7 sm:grid-cols-2 lg:mx-0 lg:max-w-none lg:grid-cols-3" className="mx-auto lg:mt-12 mt-8 grid max-w-2xl grid-cols-1 gap-x-8 gap-y-8 text-base/7 sm:grid-cols-2 sm:gap-y-16 lg:mx-0 lg:max-w-none lg:grid-cols-3"
> >
{features.map((feature, index) => ( {features.map((feature, index) => (
<motion.li <motion.li
@@ -58,7 +58,7 @@ export function Steps() {
initial={{ opacity: 0, y: 20 }} initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }} animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
transition={{ duration: 0.5, delay: 0.3 + index * 0.2 }} transition={{ duration: 0.5, delay: 0.3 + index * 0.2 }}
className="rounded-2xl border border-white/20 bg-black/20 p-8 backdrop-blur-sm transition-all duration-300 ease-in-out hover:scale-105 hover:border-white/40 hover:bg-black/40" className="rounded-2xl border border-white/20 bg-black/20 lg:py-8 lg:px-8 py-6 px-6 backdrop-blur-sm transition-all duration-300 ease-in-out hover:scale-105 hover:border-white/40 hover:bg-black/40"
> >
<feature.icon className="h-8 w-8 mb-4 text-white" /> <feature.icon className="h-8 w-8 mb-4 text-white" />
<CT as="span" className="font-semibold" color="light">{feature.name}</CT> <CT as="span" className="font-semibold" color="light">{feature.name}</CT>

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 = {
@@ -53,9 +53,9 @@ const createTextComponent = <DefaultElement extends React.ElementType>(
export const H1 = createTextComponent('h1', 'text-5xl font-medium tracking-tight text-balance lg:text-8xl') export const H1 = createTextComponent('h1', 'text-5xl font-medium tracking-tight text-balance lg:text-8xl')
export const PL = createTextComponent('p', 'text-2xl font-medium text-pretty leading-[1.2] lg:text-3xl') export const PL = createTextComponent('p', 'text-2xl font-medium text-pretty leading-[1.2] lg:text-3xl')
export const H2 = createTextComponent('h2', 'text-3xl font-medium text-pretty lg:text-4xl') export const H2 = createTextComponent('h2', 'text-3xl font-medium text-pretty lg:text-4xl')
export const P = createTextComponent('p', 'text-lg font-normal text-pretty lg:text-xl') export const P = createTextComponent('p', 'text-lg font-normal text-pretty leading-snug lg:text-xl lg:leading-normal')
export const H3 = createTextComponent('h3', 'text-2xl lg:text-3xl font-medium') export const H3 = createTextComponent('h3', 'text-2xl lg:text-3xl font-medium')
export const H4 = createTextComponent('h4', 'text-xl lg:text-2xl font-semibold leading-tight') export const H4 = createTextComponent('h4', 'text-xl lg:text-2xl font-semibold leading-[1.15]')
export const CT = createTextComponent('span', 'text-lg lg:text-xl font-semibold text-center') export const CT = createTextComponent('span', 'text-lg lg:text-xl font-semibold text-center')
export const CP = createTextComponent('p', 'text-sm lg:text-base leading-relaxed font-light') export const CP = createTextComponent('p', 'text-sm lg:text-base leading-[1.525] font-light')
export const NL = createTextComponent('span', 'text-lg font-semibold leading-6') export const NL = createTextComponent('span', 'text-lg font-semibold leading-[1.23]')

View File

@@ -7,7 +7,7 @@ import { CountUpNumber } from './CountUpNumber'
export function WorldMap() { export function WorldMap() {
return ( return (
<div className="relative min-h-screen w-full overflow-hidden -top-20 flex flex-col"> <div className="relative min-h-screen w-full overflow-hidden top-0 flex py-12 flex-col">
{/* Background video */} {/* Background video */}
<video <video
autoPlay autoPlay
@@ -48,18 +48,18 @@ export function WorldMap() {
className="flex-1 flex items-center justify-center" className="flex-1 flex items-center justify-center"
> >
<div className="relative w-[450px] h-[450px] md:w-[600px] md:h-[600px]"> <div className="relative w-[450px] h-[450px] md:w-[600px] md:h-[600px]">
<Globe className="absolute inset-0 w-full h-full -left-24" /> <Globe className="absolute inset-0 w-full h-full left-0 lg:-left-24" />
</div> </div>
</motion.div> </motion.div>
{/* Cards Right Column */} {/* Cards Right Column */}
<div className="relative flex-1"> <div className="relative flex-1 lg:h-auto h-[700px] flex flex-col lg:block items-center gap-y-4 mt-8 lg:mt-0">
<motion.div <motion.div
initial={{ opacity: 0, x: -20 }} initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }} animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.5, delay: 0.4 }} transition={{ duration: 0.5, delay: 0.4 }}
whileHover={{ scale: 1.05 }} whileHover={{ scale: 1.05 }}
className="absolute top-12 -left-12 rounded-2xl bg-white/5 backdrop-blur-md border border-white/10 px-4 py-8 shadow-md w-80" className="lg:absolute lg:top-12 lg:-left-12 rounded-xl bg-white/5 backdrop-blur-md border border-white/10 px-4 lg:py-8 py-6 shadow-md w-80"
> >
<CT color="light" className="uppercase tracking-wide">CORES</CT> <CT color="light" className="uppercase tracking-wide">CORES</CT>
<CountUpNumber end={54958} color="light" className="mt-2 text-3xl font-bold" /> <CountUpNumber end={54958} color="light" className="mt-2 text-3xl font-bold" />
@@ -73,7 +73,7 @@ export function WorldMap() {
animate={{ opacity: 1, x: 0 }} animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.5, delay: 0.5 }} transition={{ duration: 0.5, delay: 0.5 }}
whileHover={{ scale: 1.05 }} whileHover={{ scale: 1.05 }}
className="absolute -top-10 right-0 rounded-2xl bg-white/5 backdrop-blur-md border border-white/10 px-4 py-8 shadow-md w-80" className="lg:absolute lg:-top-10 lg:right-0 rounded-xl bg-white/5 backdrop-blur-md border border-white/10 px-4 lg:py-8 py-6 shadow-md w-80"
> >
<CT color="light" className="uppercase tracking-wide">NODES</CT> <CT color="light" className="uppercase tracking-wide">NODES</CT>
<CountUpNumber end={1493} color="light" className="mt-2 text-3xl font-bold" /> <CountUpNumber end={1493} color="light" className="mt-2 text-3xl font-bold" />
@@ -87,12 +87,12 @@ export function WorldMap() {
animate={{ opacity: 1, x: 0 }} animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.5, delay: 0.6 }} transition={{ duration: 0.5, delay: 0.6 }}
whileHover={{ scale: 1.05 }} whileHover={{ scale: 1.05 }}
className="absolute bottom-28 -left-12 rounded-2xl bg-white/5 backdrop-blur-md border border-white/10 px-4 py-8 shadow-md w-80" className="lg:absolute lg:bottom-28 lg:-left-12 rounded-xl bg-white/5 backdrop-blur-md border border-white/10 px-4 lg:py-8 py-6 shadow-md w-80"
> >
<CT color="light" className="uppercase tracking-wide">SSD CAPACITY</CT> <CT color="light" className="uppercase tracking-wide">SSD CAPACITY</CT>
<CountUpNumber end={5388956} color="light" className="mt-2 text-3xl font-bold" /> <CountUpNumber end={5388956} color="light" className="mt-2 text-3xl font-bold" />
<CP color="light" className="mt-2 text-sm"> <CP color="light" className="mt-2 text-sm">
Total amount of storage (SSD, HDD, & RAM) on the grid. Total GB amount of storage (SSD, HDD, & RAM) on the grid.
</CP> </CP>
</motion.div> </motion.div>
@@ -101,7 +101,7 @@ export function WorldMap() {
animate={{ opacity: 1, x: 0 }} animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.5, delay: 0.7 }} transition={{ duration: 0.5, delay: 0.7 }}
whileHover={{ scale: 1.05 }} whileHover={{ scale: 1.05 }}
className="absolute top-44 right-0 rounded-2xl bg-white/5 backdrop-blur-md border border-white/10 px-4 py-8 shadow-md w-80" className="lg:absolute lg:top-44 lg:right-0 rounded-xl bg-white/5 backdrop-blur-md border border-white/10 px-4 lg:py-8 py-6 shadow-md w-80"
> >
<CT color="light" className="uppercase tracking-wide">COUNTRIES</CT> <CT color="light" className="uppercase tracking-wide">COUNTRIES</CT>
<CountUpNumber end={44} color="light" className="mt-2 text-3xl font-bold" /> <CountUpNumber end={44} color="light" className="mt-2 text-3xl font-bold" />

View File

@@ -11,6 +11,7 @@ interface CubeProps {
index: number; index: number;
onHover: () => void; onHover: () => void;
onLeave: () => void; onLeave: () => void;
onClick: () => void;
} }
const CubeSvg: React.FC<React.SVGProps<SVGSVGElement> & { index: number }> = ({ index, ...props }) => ( const CubeSvg: React.FC<React.SVGProps<SVGSVGElement> & { index: number }> = ({ index, ...props }) => (
@@ -42,13 +43,14 @@ const CubeSvg: React.FC<React.SVGProps<SVGSVGElement> & { index: number }> = ({
</svg> </svg>
); );
export function Cube({ title, descriptionTitle, description, isActive, index, onHover, onLeave }: CubeProps) { export function Cube({ title, descriptionTitle, description, isActive, index, onHover, onLeave, onClick }: CubeProps) {
return ( return (
<div className="relative flex flex-col items-center"> <div className="relative flex flex-col items-center">
<motion.div <motion.div
className="relative cursor-pointer" className="relative cursor-pointer"
onMouseEnter={onHover} onMouseEnter={onHover}
onMouseLeave={onLeave} onMouseLeave={onLeave}
onClick={onClick}
style={{ style={{
zIndex: 10 - index, zIndex: 10 - index,
}} }}
@@ -123,24 +125,6 @@ export function Cube({ title, descriptionTitle, description, isActive, index, on
)} )}
{/* Description for Mobile - Below cube */} {/* Description for Mobile - Below cube */}
{isActive && (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 10 }}
transition={{ duration: 0.3 }}
className="lg:hidden absolute top-full left-1/2 -translate-x-1/2 mt-8 z-50"
>
<div className="w-64 sm:w-80 px-4">
<h4 className="text-white text-base font-semibold mb-2 text-center">
{descriptionTitle}
</h4>
<p className="text-white text-sm leading-relaxed font-light text-center">
{description}
</p>
</div>
</motion.div>
)}
</motion.div> </motion.div>
</div> </div>
); );

View File

@@ -33,14 +33,22 @@ const stackData = [
export function StackedCubes() { export function StackedCubes() {
const [active, setActive] = useState<string | null>("agent"); const [active, setActive] = useState<string | null>("agent");
const [selectedForMobile, setSelectedForMobile] = useState<string | null>("agent");
const handleCubeClick = (id: string) => {
setSelectedForMobile(prev => (prev === id ? null : id));
};
const selectedMobileLayer = stackData.find(layer => layer.id === selectedForMobile);
return ( return (
<div className="flex flex-col items-center">
<div <div
className="relative w-full flex items-center justify-center lg:justify-start min-h-[600px] sm:min-h-[700px] lg:min-h-[600px]" className="relative w-full flex items-center justify-center lg:justify-center min-h-[450px] lg:min-h-[400px]"
onMouseLeave={() => setActive("agent")} onMouseLeave={() => setActive("agent")}
> >
<motion.div <motion.div
className="relative ml-0 sm:ml-4 lg:ml-8 h-[600px] w-96" 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"] }} animate={{ y: ["-8px", "8px"] }}
transition={{ transition={{
duration: 4, duration: 4,
@@ -54,7 +62,7 @@ export function StackedCubes() {
key={layer.id} key={layer.id}
className="absolute" className="absolute"
style={{ style={{
top: `${index * 140}px`, top: `calc(${index * 30}% - ${index * 10}px)`,
zIndex: active === layer.id ? 20 : 10 - index, zIndex: active === layer.id ? 20 : 10 - index,
}} }}
> >
@@ -66,10 +74,22 @@ export function StackedCubes() {
index={index} index={index}
onHover={() => setActive(layer.id)} onHover={() => setActive(layer.id)}
onLeave={() => {}} onLeave={() => {}}
onClick={() => handleCubeClick(layer.id)}
/> />
</div> </div>
))} ))}
</motion.div> </motion.div>
</div> </div>
{selectedMobileLayer && (
<div className="lg:hidden w-full max-w-md p-6 -mt-8 bg-gray-800/50 rounded-lg">
<h4 className="text-white text-lg font-semibold mb-2 text-center">
{selectedMobileLayer.descriptionTitle}
</h4>
<p className="text-gray-300 text-sm leading-relaxed text-center">
{selectedMobileLayer.description}
</p>
</div>
)}
</div>
); );
} }

View File

@@ -0,0 +1,79 @@
import { cn } from "@/lib/utils";
import { CT, CP } from "@/components/Texts";
import Image from 'next/image';
import React from 'react';
import { motion } from 'framer-motion';
export const BentoGrid = ({
className,
children,
}: {
className?: string;
children?: React.ReactNode;
}) => {
return (
<div
className={cn(
"mx-4 grid max-w-6xl grid-cols-1 gap-4 lg:grid-cols-3",
className,
)}
>
{children}
</div>
);
};
interface BentoGridItemProps {
className?: string;
title?: string | React.ReactNode;
subtitle?: string | React.ReactNode;
description?: string | React.ReactNode;
img?: string;
video?: string;
rowHeight?: string;
}
export const BentoGridItem = React.forwardRef<HTMLDivElement, BentoGridItemProps>(
({ className, title, subtitle, description, img, video, rowHeight }, ref) => {
return (
<div
ref={ref}
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",
rowHeight ? rowHeight : "h-full",
className
)}
>
<div className="relative w-full h-[65%] min-h-[6rem] bg-transparent overflow-hidden">
{video ? (
<video
src={video}
autoPlay
loop
muted
playsInline
className="w-full h-full object-cover opacity-90 group-hover/bento:opacity-100 transition-opacity duration-300"
/>
) : img ? (
<Image
src={img}
alt={title as string}
width={300}
height={300}
className="w-full h-full object-cover opacity-90 group-hover/bento:opacity-100 transition-opacity duration-300"
/>
) : null}
</div>
<div className="p-4 transition bg-white/5 hover:bg-white/7 backdrop-blur-md duration-200 group-hover/bento:translate-x-2 ">
<CT>{title}</CT>
<CP className="font-medium">{subtitle}</CP>
<CP className="mt-2">{description}</CP>
</div>
</div>
);
}
);
BentoGridItem.displayName = "BentoGridItem";
export const MotionBentoGridItem = motion(BentoGridItem);

View File

@@ -0,0 +1,21 @@
'use client'
import { useState, useEffect } from 'react'
export function useMediaQuery(query: string) {
const [matches, setMatches] = useState(false)
useEffect(() => {
const media = window.matchMedia(query)
if (media.matches !== matches) {
setMatches(media.matches)
}
const listener = () => {
setMatches(media.matches)
}
media.addEventListener('change', listener)
return () => media.removeEventListener('change', listener)
}, [matches, query])
return matches
}

View File

@@ -0,0 +1,39 @@
'use client'
import { useState, useEffect } from 'react';
// 🔧 Carousel Config
const desktopConfig = {
GAP: 300,
ROT_Y: 18,
DEPTH: 210,
SCALE_DROP: 0.12,
};
const mobileConfig = {
GAP: 110, // Smaller gap for mobile
ROT_Y: 0, // Flatter view on mobile
DEPTH: 150, // Less depth
SCALE_DROP: 0.1, // Less aggressive scaling
};
export const useResponsiveCarousel = () => {
const [config, setConfig] = useState(desktopConfig);
useEffect(() => {
const checkScreenSize = () => {
if (window.innerWidth < 768) {
setConfig(mobileConfig);
} else {
setConfig(desktopConfig);
}
};
checkScreenSize();
window.addEventListener('resize', checkScreenSize);
return () => window.removeEventListener('resize', checkScreenSize);
}, []);
return config;
};

13
src/pages/_document.tsx Normal file
View File

@@ -0,0 +1,13 @@
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}