Merge branch 'development'

This commit is contained in:
2025-09-15 18:14:48 +02:00
47 changed files with 1372 additions and 304 deletions

24
components.json Normal file
View File

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

126
package-lock.json generated
View File

@@ -15,8 +15,12 @@
"@types/node": "^20.10.8",
"@types/react": "^18.2.55",
"@types/react-dom": "^18.2.18",
"clsx": "^2.1.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cobe": "^0.6.4",
"framer-motion": "^10.15.0",
"lucide-react": "^0.544.0",
"motion": "^12.23.12",
"next": "^14.0.4",
"popmotion": "^11.0.5",
"react": "^18.2.0",
@@ -35,7 +39,8 @@
"eslint-config-next": "^14.0.4",
"prettier": "^3.3.2",
"prettier-plugin-tailwindcss": "^0.6.11",
"sharp": "0.33.1"
"sharp": "0.33.1",
"tw-animate-css": "^1.3.8"
}
},
"node_modules/@alloc/quick-lru": {
@@ -1728,6 +1733,15 @@
"integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==",
"license": "MIT"
},
"node_modules/@lobehub/fluent-emoji/node_modules/lucide-react": {
"version": "0.469.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.469.0.tgz",
"integrity": "sha512-28vvUnnKQ/dBwiCQtwJw7QauYnE7yd2Cyp4tTTJpvglX4EMpbflcdBgrgToX2j71B3YvugK/NH3BGUk+E/p/Fw==",
"license": "ISC",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/@lobehub/icons": {
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/@lobehub/icons/-/icons-1.97.2.tgz",
@@ -1746,6 +1760,15 @@
"react-dom": "^18.0.0 || ^19.0.0"
}
},
"node_modules/@lobehub/icons/node_modules/lucide-react": {
"version": "0.469.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.469.0.tgz",
"integrity": "sha512-28vvUnnKQ/dBwiCQtwJw7QauYnE7yd2Cyp4tTTJpvglX4EMpbflcdBgrgToX2j71B3YvugK/NH3BGUk+E/p/Fw==",
"license": "ISC",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/@lobehub/ui": {
"version": "1.171.0",
"resolved": "https://registry.npmjs.org/@lobehub/ui/-/ui-1.171.0.tgz",
@@ -5037,6 +5060,15 @@
"node": ">=6"
}
},
"node_modules/cobe": {
"version": "0.6.4",
"resolved": "https://registry.npmjs.org/cobe/-/cobe-0.6.4.tgz",
"integrity": "sha512-huuGFnDoXLy/tsCZYYa/H35BBRs9cxsS0XKJ3BXjRp699cQKuoEVrvKlAQMx0DKXG7+VUv4jsHVrS7yPbkLSkQ==",
"license": "MIT",
"dependencies": {
"phenomenon": "^1.6.0"
}
},
"node_modules/collapse-white-space": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz",
@@ -9007,9 +9039,9 @@
"license": "ISC"
},
"node_modules/lucide-react": {
"version": "0.469.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.469.0.tgz",
"integrity": "sha512-28vvUnnKQ/dBwiCQtwJw7QauYnE7yd2Cyp4tTTJpvglX4EMpbflcdBgrgToX2j71B3YvugK/NH3BGUk+E/p/Fw==",
"version": "0.544.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.544.0.tgz",
"integrity": "sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw==",
"license": "ISC",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
@@ -10317,6 +10349,32 @@
"pathe": "^2.0.1"
}
},
"node_modules/motion": {
"version": "12.23.12",
"resolved": "https://registry.npmjs.org/motion/-/motion-12.23.12.tgz",
"integrity": "sha512-8jCD8uW5GD1csOoqh1WhH1A6j5APHVE15nuBkFeRiMzYBdRwyAHmSP/oXSuW0WJPZRXTFdBoG4hY9TFWNhhwng==",
"license": "MIT",
"dependencies": {
"framer-motion": "^12.23.12",
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/motion-dom": {
"version": "11.18.1",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz",
@@ -10332,6 +10390,48 @@
"integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==",
"license": "MIT"
},
"node_modules/motion/node_modules/framer-motion": {
"version": "12.23.12",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.12.tgz",
"integrity": "sha512-6e78rdVtnBvlEVgu6eFEAgG9v3wLnYEboM8I5O5EXvfKC8gxGQB8wXJdhkMy10iVcn05jl6CNw7/HTsTCfwcWg==",
"license": "MIT",
"dependencies": {
"motion-dom": "^12.23.12",
"motion-utils": "^12.23.6",
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/motion/node_modules/motion-dom": {
"version": "12.23.12",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.12.tgz",
"integrity": "sha512-RcR4fvMCTESQBD/uKQe49D5RUeDOokkGRmz4ceaJKDBgHYtZtntC/s2vLvY38gqGaytinij/yi3hMcWVcEF5Kw==",
"license": "MIT",
"dependencies": {
"motion-utils": "^12.23.6"
}
},
"node_modules/motion/node_modules/motion-utils": {
"version": "12.23.6",
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz",
"integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==",
"license": "MIT"
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -10858,6 +10958,12 @@
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"license": "MIT"
},
"node_modules/phenomenon": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/phenomenon/-/phenomenon-1.6.0.tgz",
"integrity": "sha512-7h9/fjPD3qNlgggzm88cY58l9sudZ6Ey+UmZsizfhtawO6E3srZQXywaNm2lBwT72TbpHYRPy7ytIHeBUD/G0A==",
"license": "MIT"
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -13546,6 +13652,16 @@
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/tw-animate-css": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.3.8.tgz",
"integrity": "sha512-Qrk3PZ7l7wUcGYhwZloqfkWCmaXZAoqjkdbIDvzfGshwGtexa/DAs9koXxIkrpEasyevandomzCBAV1Yyop5rw==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/Wombosvideo"
}
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",

View File

@@ -17,8 +17,12 @@
"@types/node": "^20.10.8",
"@types/react": "^18.2.55",
"@types/react-dom": "^18.2.18",
"clsx": "^2.1.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cobe": "^0.6.4",
"framer-motion": "^10.15.0",
"lucide-react": "^0.544.0",
"motion": "^12.23.12",
"next": "^14.0.4",
"popmotion": "^11.0.5",
"react": "^18.2.0",
@@ -37,6 +41,7 @@
"eslint-config-next": "^14.0.4",
"prettier": "^3.3.2",
"prettier-plugin-tailwindcss": "^0.6.11",
"sharp": "0.33.1"
"sharp": "0.33.1",
"tw-animate-css": "^1.3.8"
}
}

BIN
public/images/benefits.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

15
public/images/logo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 120 KiB

BIN
public/images/m.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

View File

@@ -11,6 +11,7 @@ import { CallTo } from '@/components/CallTo'
import { ScrollDown } from '@/components/ui/ScrollDown'
import { ScrollUp } from '@/components/ui/ScrollUp'
import { GridStats } from '@/components/GridStats'
import { WorldMap } from '@/components/WorldMap'
export default function Home() {
return (
@@ -18,23 +19,17 @@ export default function Home() {
<section id="home-hero">
<HomeHero />
</section>
<section id="home-about">
<HomeAbout />
</section>
<section id="grid-stats">
<GridStats />
</section>
<section id="companies">
<Companies />
</section>
<section id="stack-section">
<StackSectionPreview />
</section>
<section id="steps">
<Steps />
</section>
<section id="clickable-gallery">
<ClickableGallery />
<section id="world-map">
<WorldMap />
</section>
<section id="grid-stats">
<GridStats />
</section>
<section id="use-cases">
<UseCases />
@@ -42,9 +37,6 @@ export default function Home() {
<section id="call-to-action">
<CallTo />
</section>
<section id="faqs">
<Faqs />
</section>
<ScrollDown />
<ScrollUp />
</>

View File

@@ -25,8 +25,8 @@ export default function RootLayout({
children: React.ReactNode
}) {
return (
<html lang="en" className={clsx('bg-white antialiased', mulish.variable)}>
<body>{children}</body>
<html lang="en" className={clsx('antialiased', mulish.variable)}>
<body className="bg-black text-white">{children}</body>
</html>
)
}

View File

@@ -0,0 +1,92 @@
"use client";
import React from "react";
import { motion } from "framer-motion";
import { H2, P } from '@/components/Texts';
import Ai21 from '@/components/logos/Ai21';
import Claude from '@/components/logos/Claude';
import BaiduCloud from '@/components/logos/BaiduCloud';
import ByteDance from '@/components/logos/ByteDance';
import DeepSeek from '@/components/logos/DeepSeek';
import DeepMind from '@/components/logos/DeepMind';
import Minimax from '@/components/logos/Minimax';
import Mistral from '@/components/logos/Mistral';
import Moonshot from '@/components/logos/Moonshot';
import AlibabaCloud from '@/components/logos/AlibabaCloud';
import TencentCloud from '@/components/logos/TencentCloud';
import OpenAI from '@/components/logos/OpenAI';
import XAI from '@/components/logos/XAI';
const row1 = [Ai21, Claude, BaiduCloud, ByteDance];
const row2 = [DeepSeek, DeepMind, Minimax, Mistral];
const row3 = [Moonshot, AlibabaCloud];
const row4 = [TencentCloud, OpenAI, XAI];
export function Companies() {
return (
<div id="companies" className="relative flex h-screen w-full overflow-hidden rounded-md bg-transparent antialiased md:items-center md:justify-center">
<div className="relative z-10 mx-auto w-full max-w-6xl p-4 py-12">
{/* Heading */}
<motion.div
className="flex flex-col justify-center max-w-4xl items-center mb-6 mx-auto"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 1 }}
>
<H2 className="text-center pb-6">
Deploy the Worlds Leading AI Models
</H2>
<P className="pb-8 text-center" color="custom">
Deploy and scale AI from top global providers on a decentralized, privacy-first infrastructure.
</P>
</motion.div>
{/* Animated Line */}
<motion.div
className="h-[2px] bg-neutral-400 rounded-full mx-auto mb-12"
initial={{ width: 0 }}
animate={{ width: "100%" }}
transition={{ duration: 2, delay: 1 }}
/>
{/* Logos grid */}
<div className="flex flex-col items-center gap-y-10">
{[row1, row2, row3, row4].map((row, rowIndex) => (
<motion.div
key={rowIndex}
className="flex flex-wrap justify-center items-center gap-x-8 sm:gap-x-10"
initial="hidden"
animate="visible"
variants={{
visible: {
transition: {
staggerChildren: 0.15,
delayChildren: 2.8 + rowIndex * 0.5, // Stagger rows
},
},
}}
>
{row.map((Logo, i) => (
<motion.div
key={i}
className="flex justify-center"
variants={{
hidden: { opacity: 0, y: 30 },
visible: { opacity: 1, y: 0 },
}}
transition={{ duration: 0.6, ease: "easeOut" }}
>
<div className="text-[#2F3178]"><Logo /></div>
</motion.div>
))}
</motion.div>
))}
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,117 @@
"use client";
import CountUp from "react-countup";
import React from "react";
import { Button } from "@/components/Button";
export function GridStats() {
return (
<div id="grid-stats" className="py-24 bg-transparent relative">
<div className="mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-8">
<div className="grid grid-cols-1 gap-8 lg:grid-cols-3">
{/* Column 1: Title & NODES */}
<div className="flex flex-col space-y-10">
{/* Title + Description */}
<div>
<h2 className="text-2xl font-semibold tracking-tight leading-tight text-black lg:text-4xl">
Powered by a Global Community
</h2>
<p className="mt-4 sm:mt-6 text-sm font-light text-pretty text-black lg:text-base">
ThreeFolds groundbreaking technology enables anyone individuals, organizations, and communities to deploy their own Internet infrastructure.
</p>
<Button className="mt-8" variant="outline" href="https://threefold.io/build" >Explore TFGrid </Button>
</div>
</div>
{/* Column 2: CORES (staggered) + SSD */}
<div className="flex flex-col space-y-10">
<StatCard
label="CORES"
description="A globally distributed mesh of CPU cores powering decentralized applications, AI workloads, and edge computing — without central bottlenecks."
value={<CountUp end={54_958} duration={2.5} separator="," />}
note="Total Central Processing Unit Cores available on the grid."
/>
<StatCard
label="SSD CAPACITY"
description="A distributed network of storage capacity — ready to support Web3, AI, and edge computing workloads around the world."
value={<CountUp end={7_364_506} duration={2.5} separator="," />}
unit="GB"
note="The total amount of storage (SSD, HDD, & RAM) on the grid."
/>
</div>
{/* Column 3: nodes countries */}
<div className="flex flex-col space-y-10 justify-start">
<StatCard
label="NODES"
description="A computer server 100% dedicated to the network. It is a building block of the ThreeFold Grid, providing compute, storage, and network resources."
value={<CountUp end={1778} duration={2.5} separator="," />}
note="The total number of nodes on the grid."
/>
<StatCard
label="COUNTRIES"
description="The number of countries where at least one node is connected and operational on the grid."
value={<CountUp end={51} duration={2.5} separator="," />}
note="The total number of countries with active nodes."
/>
</div>
</div>
</div>
</div>
);
}
// 🧱 Stat Card Component
function StatCard({
label,
description,
value,
unit,
note,
className = "",
}: {
label: string;
description: string;
value: React.ReactNode;
unit?: string;
note: string;
className?: string;
}) {
return (
<div
className={`relative flex flex-col overflow-hidden rounded-3xl bg-white shadow-md shadow-gray-900/5 p-8 transition-all duration-300 ease-out hover:scale-105 ${className}`}
style={{
filter: 'brightness(1)',
}}
onMouseEnter={(e) => {
e.currentTarget.style.filter = 'brightness(0.8)';
}}
onMouseLeave={(e) => {
e.currentTarget.style.filter = 'brightness(1)';
}}
>
<h3 className="text-lg font-semibold text-gradient-neutral-vertical" style={{ textShadow: '0 0 12px rgba(255, 255, 255, 0.4), 0 0 24px rgba(255, 255, 255, 0.2)' }}>{label}</h3>
<p className="mt-2 text-sm font-light text-pretty text-black lg:text-base">
{description}
</p>
<div className="mt-8 flex items-center space-x-3">
<span className="text-gradient-neutral-vertical text-3xl"></span>
<div className="text-5xl font-semibold tracking-tight text-black tabular-nums">
{value}
{unit && (
<span className="ml-2 text-lg font-normal text-gray-800">{unit}</span>
)}
</div>
</div>
<p className="mt-2 text-sm text-gray-800 uppercase tracking-wider">
{note}
</p>
</div>
);
}

View File

@@ -0,0 +1,90 @@
'use client'
import { useState } from 'react'
import { motion } from 'framer-motion'
import { TypeAnimation } from 'react-type-animation'
import { Dialog, DialogPanel } from '@headlessui/react'
import { Bars3Icon, XMarkIcon, ChevronDoubleDownIcon } from '@heroicons/react/24/outline'
import { H1, PL } from '@/components/Texts'
const navigation = [
{ name: 'Product', href: '#' },
{ name: 'Features', href: '#' },
{ name: 'Marketplace', href: '#' },
{ name: 'Company', href: '#' },
]
export function HomeHero() {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
return (
<div className="relative h-screen -top-15">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 2 }}
className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[700px] h-[700px] -z-10 rounded-full overflow-hidden"
>
<video
autoPlay
loop
muted
playsInline
className="h-full w-full object-cover"
>
<source src="/videos/mycelium.mp4" type="video/mp4" />
</video>
</motion.div>
<div className="relative isolate px-6 lg:px-8">
<div
aria-hidden="true"
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl lg:-top-80"
>
<div
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
className="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#a4caf6] to-[#aaa4fa] opacity-15 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
/>
</div>
<div
aria-hidden="true"
className="absolute inset-x-0 bottom-10 -z-10 transform-gpu overflow-hidden blur-3xl lg:bottom-40"
>
<div
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
className="relative bottom-[calc(50%+3rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#93c5fd] to-[#9089fc] opacity-15 sm:left-[calc(50%+30rem)] sm:w-[72.1875rem]"
/>
</div>
<div className="relative -top-15 mx-auto max-w-8xl h-screen flex items-center justify-center">
<div className="text-center max-w-5xl">
<H1>
<TypeAnimation
sequence={[
'Decentralized Autonomous Agentic Cloud.',
1000,
]}
wrapper="span"
speed={50}
repeat={0}
/>
</H1>
</div>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 1, delay: 1 }}
>
<PL className="absolute bottom-0 left-0 max-w-xl text-left" color="custom">
Mycelium's advancements in Agentic infrastructure supports private, secure and autonomous Agents that connect, learn and grow with you.
</PL>
</motion.div>
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,71 @@
'use client'
import React, { useRef } from 'react'
import { motion, useInView } from 'framer-motion'
import { H2, P, CT, CP } from '@/components/Texts'
import { TbCircleNumber1Filled, TbCircleNumber2Filled, TbCircleNumber3Filled } from 'react-icons/tb'
const features = [
{
name: 'Choose Your Intelligence',
description: 'Explore a library of leading LLMs and agentic functions. Pick the ones that fit your use case, from general assistants to specialized reasoning models.',
icon: TbCircleNumber1Filled,
},
{
name: 'Add Your Knowledge',
description:
'Connect your data or knowledge base to enable personalized, context-aware results while keeping your information private.',
icon: TbCircleNumber2Filled,
},
{
name: 'Define Your Network',
description:
'Set up and manage your nodes with ease. Scale compute and storage as you grow, while staying fully sovereign and decentralized.',
icon: TbCircleNumber3Filled,
},
]
export function Steps() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
return (
<section id="benefits" ref={ref} className="bg-white pt-0 pb-24 dark:bg-gray-900">
<div className="mx-auto max-w-7xl px-6 lg:px-0">
<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 lg:mx-0"
>
<H2 className="text-3xl font-medium tracking-tight">
Deploy Scalable LLMs and AI Agents in Seconds
</H2>
<P className="mt-6 text-lg" color="custom">
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>
</motion.div>
<motion.ul
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
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"
>
{features.map((feature, index) => (
<motion.li
key={feature.name}
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
transition={{ duration: 0.5, delay: 0.3 + index * 0.2 }}
className="rounded-2xl border border-gray-200 p-8 dark:border-gray-700"
>
<feature.icon className="h-8 w-8 mb-4 text-[#2F3178]" />
<CT as="span" className="font-semibold">{feature.name}</CT>
<CP className="mt-2 text-sm" color="custom">{feature.description}</CP>
</motion.li>
))}
</motion.ul>
</div>
</section>
)
}

View File

@@ -0,0 +1,263 @@
'use client'
import React, { useEffect, useMemo, useRef, useState } from 'react'
import clsx from 'clsx'
import {
ArchiveBoxIcon,
CodeBracketIcon,
CpuChipIcon,
GlobeAltIcon,
MagnifyingGlassIcon,
ShareIcon,
UserGroupIcon,
CheckBadgeIcon,
} from '@heroicons/react/24/solid'
import { Container } from '@/components/Container'
import { H2, P, CT, CP } from '@/components/Texts'
import { motion, useInView } from 'framer-motion'
interface Review {
title: string
body: string
}
const reviews: Array<Review> = [
{
title: 'FungiStor: Long-Term AI Memory',
body: 'Quantum-safe permanent storage preserving AI knowledge forever. Zero-knowledge architecture with mathematical dispersal ensures immortality.',
},
{
title: 'HeroDB: Active AI Memory',
body: 'High-performance datastore for AI working memory. Multi-modal indexing enables vector search with global accessibility.',
},
{
title: 'MOS Sandboxes: Secure Agent Workspaces',
body: 'Lightweight isolated environments deploying globally in five seconds. Hardware-level isolation ensures maximum security for agents.',
},
{
title: 'Mycelium Mesh: Secure Communication Network',
body: 'Peer-to-peer overlay network with end-to-end encryption. Self-healing shortest-path routing creates resilient agentic communication.',
},
{
title: 'Deterministic Deployment: Verifiable Code Execution',
body: 'Cryptographic guarantee system ensuring deployed code matches specifications. Prevents supply-chain attacks with immutable trails.',
},
{
title: 'Agent Coordination: Sovereign Workflow Management',
body: 'User-centric orchestration where HERO agents coordinate worker fleets. Planetary-scale coordination with instant spawning.',
},
{
title: 'Universal Interface Layer: AI Service Gateway',
body: 'Unified broker connecting agents to LLMs, APIs, and services. Integrated micropayments simplify development.',
},
{
title: 'Semantic Index & Search: Navigable Knowledge Fabric',
body: 'Transforms data chaos into unified knowledge graphs. Goes beyond keywords to understand meaning and context.',
},
]
function getReviewIcon(title: string) {
if (title.startsWith('FungiStor')) return ArchiveBoxIcon;
if (title.startsWith('HeroDB')) return CpuChipIcon;
if (title.startsWith('MOS Sandboxes')) return CodeBracketIcon;
if (title.startsWith('Mycelium Mesh')) return ShareIcon;
if (title.startsWith('Deterministic Deployment')) return CheckBadgeIcon;
if (title.startsWith('Agent Coordination')) return UserGroupIcon;
if (title.startsWith('Universal Interface Layer')) return GlobeAltIcon;
if (title.startsWith('Semantic Index & Search')) return MagnifyingGlassIcon;
return GlobeAltIcon; // default
}
function Review({
title,
body,
className,
...props
}: Omit<React.ComponentPropsWithoutRef<'figure'>, keyof Review> & Review) {
let animationDelay = useMemo(() => {
let possibleAnimationDelays = ['0s', '0.1s', '0.2s', '0.3s', '0.4s', '0.5s']
return possibleAnimationDelays[
Math.floor(Math.random() * possibleAnimationDelays.length)
]
}, [])
return (
<figure
className={clsx(
'animate-fade-in rounded-3xl bg-white p-6 opacity-0 shadow-md shadow-gray-900/5',
className,
)}
style={{ animationDelay }}
{...props}
>
<blockquote className="text-gray-900">
{React.createElement(getReviewIcon(title), { className: "h-6 w-6 text-[#2F3178] mb-2" })}
<CT color="primary" className="mt-4 text-lg/6 font-semibold">
{title}
</CT>
<CP color="custom" className="mt-3 text-sm">{body}</CP>
</blockquote>
</figure>
)
}
function splitArray<T>(array: Array<T>, numParts: number) {
let result: Array<Array<T>> = []
for (let i = 0; i < array.length; i++) {
let index = i % numParts
if (!result[index]) {
result[index] = []
}
result[index].push(array[i])
}
return result
}
function ReviewColumn({
reviews,
className,
reviewClassName,
msPerPixel = 0,
}: {
reviews: Array<Review>
className?: string
reviewClassName?: (reviewIndex: number) => string
msPerPixel?: number
}) {
let columnRef = useRef<React.ElementRef<'div'>>(null)
let [columnHeight, setColumnHeight] = useState(0)
let duration = `${columnHeight * msPerPixel}ms`
useEffect(() => {
if (!columnRef.current) {
return
}
let resizeObserver = new window.ResizeObserver(() => {
setColumnHeight(columnRef.current?.offsetHeight ?? 0)
})
resizeObserver.observe(columnRef.current)
return () => {
resizeObserver.disconnect()
}
}, [])
return (
<div
ref={columnRef}
className={clsx('animate-marquee space-y-8 py-4', className)}
style={{ '--marquee-duration': duration } as React.CSSProperties}
>
{reviews.concat(reviews).map((review, reviewIndex) => (
<Review
key={reviewIndex}
aria-hidden={reviewIndex >= reviews.length}
className={reviewClassName?.(reviewIndex % reviews.length)}
{...review}
/>
))}
</div>
)
}
function ReviewGrid() {
let containerRef = useRef<React.ElementRef<'div'>>(null)
let isInView = useInView(containerRef, { once: true, amount: 0.4 })
let columns = splitArray(reviews, 3)
let column1 = columns[0]
let column2 = columns[1]
let column3 = splitArray(columns[2], 2)
return (
<div
ref={containerRef}
className="relative -mx-4 mt-0 grid h-196 max-h-[150vh] grid-cols-1 items-start gap-8 overflow-hidden px-4 sm:mt-20 md:grid-cols-2 lg:grid-cols-3"
>
{isInView && (
<>
<ReviewColumn
reviews={[...column1, ...column3.flat(), ...column2]}
reviewClassName={(reviewIndex) =>
clsx(
reviewIndex >= column1.length + column3[0].length &&
'md:hidden',
reviewIndex >= column1.length && 'lg:hidden',
)
}
msPerPixel={10}
/>
<ReviewColumn
reviews={[...column2, ...column3[1]]}
className="hidden md:block"
reviewClassName={(reviewIndex) =>
reviewIndex >= column2.length ? 'lg:hidden' : ''
}
msPerPixel={15}
/>
<ReviewColumn
reviews={column3.flat()}
className="hidden lg:block"
msPerPixel={10}
/>
</>
)}
<div className="pointer-events-none absolute inset-x-0 top-0 h-32 bg-linear-to-b from-white" />
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-32 bg-linear-to-t from-white" />
</div>
)
}
export function UseCases() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
return (
<section
id="usecases"
ref={ref}
aria-labelledby="usecases-title"
className="py-12"
>
<Container className=''>
<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-2xl lg:max-w-5xl"
>
<H2
id="usecases-title"
color="primary"
className="text-center"
>
Coming Soon: The Future of Mycelium
</H2>
<P className="mt-6 text-center" color="custom">
Mycelium Cloud is evolving to bring even more powerful decentralized features, designed to enhance your experience and expand possibilities. Be the first to explore what's coming next by staying connected with our latest updates.
</P>
</motion.div>
<motion.div
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 1, delay: 0.2 }}
aria-hidden="true"
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
>
<div
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
className="relative left-[calc(50%-30rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#93c5fd] to-[#9089fc] opacity-30 sm:left-[calc(50%-36rem)] sm:w-[72.1875rem]"
/>
</motion.div>
<ReviewGrid />
</Container>
</section>
)
}

View File

@@ -10,13 +10,13 @@ const baseStyles = {
const variantStyles = {
solid: {
cyan: 'relative overflow-hidden bg-[#2F3178] text-white before:absolute before:inset-0 active:before:bg-transparent hover:before:bg-white/10 active:bg-[#2F3178] active:text-white/80 before:transition-colors',
cyan: 'relative overflow-hidden bg-[#005eff] text-white before:absolute before:inset-0 active:before:bg-transparent hover:before:bg-white/10 active:bg-[#005eff] active:text-white/80 before:transition-colors',
white:
'bg-white text-cyan-900 hover:bg-white/90 active:bg-white/90 active:text-cyan-900/70',
gray: 'bg-gray-800 text-white hover:bg-gray-900 active:bg-gray-800 active:text-white/80',
},
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-200 hover:border-gray-400 active:bg-gray-100 active:text-gray-700/80',
},
}

View File

@@ -3,6 +3,7 @@
import React from "react";
import { motion } from "framer-motion";
import { H2, P } from '@/components/Texts';
import { InfiniteMovingCards } from "@/components/magicui/infinite-moving-cards";
@@ -15,76 +16,58 @@ import DeepMind from '@/components/logos/DeepMind';
import Minimax from '@/components/logos/Minimax';
import Mistral from '@/components/logos/Mistral';
import Moonshot from '@/components/logos/Moonshot';
import AlibabaCloud from '@/components/logos/AlibabaCloud';
import TencentCloud from '@/components/logos/TencentCloud';
import OpenAI from '@/components/logos/OpenAI';
import XAI from '@/components/logos/XAI';
const row1 = [Ai21, Claude, BaiduCloud, ByteDance];
const row2 = [DeepSeek, DeepMind, Minimax, Mistral];
const row3 = [Moonshot, AlibabaCloud];
const row4 = [TencentCloud, OpenAI, XAI];
const logos = [
<Ai21 key="ai21" />,
<Claude key="claude" />,
<BaiduCloud key="baidu" />,
<ByteDance key="bytedance" />,
<DeepSeek key="deepseek" />,
<DeepMind key="deepmind" />,
<Minimax key="minimax" />,
<Mistral key="mistral" />,
<Moonshot key="moonshot" />,
<TencentCloud key="tencent" />,
<OpenAI key="openai" />,
<XAI key="xai" />,
];
const row1 = logos.slice(0, 6);
const row2 = logos.slice(6);
export function Companies() {
return (
<div id="companies" className="relative flex h-screen w-full overflow-hidden rounded-md bg-transparent antialiased md:items-center md:justify-center">
<div className="relative z-10 mx-auto w-full max-w-6xl p-4 py-12">
<div id="companies" className="relative bg-black flex flex-col items-center justify-center w-full overflow-hidden antialiased py-12 -top-20">
<div className="relative z-10 mx-auto w-full max-w-6xl p-4">
{/* Heading */}
<motion.div
className="flex flex-col justify-center max-w-4xl items-center mb-6 mx-auto"
className="flex flex-col justify-center max-w-4xl items-center mb-8 mx-auto"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 1 }}
>
<H2 className="text-center pb-6">
Deploy the Worlds Leading AI Models
</H2>
<P className="pb-8 text-center" color="custom">
Deploy and scale AI from top global providers on a decentralized, privacy-first infrastructure. Mycelium Cloud lets you integrate state-of-the-art intelligence into your workflows with full control, sovereignty, and cost efficiency.
<P className="text-gray-100 text-center">
Mycelium Cloud allows you to deploy and scale AI agents from top global providers on a decentralized, privacy-first infrastructure.
</P>
</motion.div>
{/* Animated Line */}
<motion.div
className="h-[2px] bg-neutral-400 rounded-full mx-auto mb-12"
initial={{ width: 0 }}
animate={{ width: "100%" }}
transition={{ duration: 2, delay: 1 }}
/>
{/* Logos grid */}
<div className="flex flex-col items-center gap-y-10">
{[row1, row2, row3, row4].map((row, rowIndex) => (
<motion.div
key={rowIndex}
className="flex flex-wrap justify-center items-center gap-x-8 sm:gap-x-10"
initial="hidden"
animate="visible"
variants={{
visible: {
transition: {
staggerChildren: 0.15,
delayChildren: 2.8 + rowIndex * 0.5, // Stagger rows
},
},
}}
>
{row.map((Logo, i) => (
<motion.div
key={i}
className="flex justify-center"
variants={{
hidden: { opacity: 0, y: 30 },
visible: { opacity: 1, y: 0 },
}}
transition={{ duration: 0.6, ease: "easeOut" }}
>
<div className="text-[#2F3178]"><Logo /></div>
</motion.div>
))}
</motion.div>
))}
<div className="flex flex-col items-center gap-y-6 text-white">
<InfiniteMovingCards
items={row1}
direction="right"
speed="slow"
/>
<InfiniteMovingCards
className=""
items={row2}
direction="left"
speed="slow"
/>
</div>
</div>
</div>

View File

@@ -1,14 +1,21 @@
import { useId } from 'react'
import clsx from 'clsx'
const formClasses =
'block w-full appearance-none rounded-lg border border-gray-200 bg-white py-[calc(--spacing(2)-1px)] px-[calc(--spacing(3)-1px)] text-gray-900 placeholder:text-gray-400 focus:border-cyan-500 focus:outline-hidden focus:ring-cyan-500 sm:text-sm'
const formClasses = {
light:
'block w-full appearance-none rounded-lg border border-gray-200 bg-white py-[calc(--spacing(2)-1px)] px-[calc(--spacing(3)-1px)] text-gray-900 placeholder:text-gray-400 focus:border-cyan-500 focus:outline-none focus:ring-cyan-500 sm:text-sm',
dark:
'block w-full appearance-none rounded-lg border border-gray-600 bg-transparent py-[calc(--spacing(2)-1px)] px-[calc(--spacing(3)-1px)] text-white placeholder:text-gray-400 focus:border-cyan-500 focus:outline-none focus:ring-cyan-500 sm:text-sm',
}
function Label({ id, children }: { id: string; children: React.ReactNode }) {
function Label({ id, children, variant = 'light' }: { id: string; children: React.ReactNode, variant?: 'light' | 'dark' }) {
return (
<label
htmlFor={id}
className="mb-2 block text-sm font-semibold text-gray-900"
className={clsx(
'mb-2 block text-sm font-semibold',
variant === 'light' ? 'text-gray-900' : 'text-white',
)}
>
{children}
</label>
@@ -19,14 +26,15 @@ export function TextField({
label,
type = 'text',
className,
variant = 'light',
...props
}: Omit<React.ComponentPropsWithoutRef<'input'>, 'id'> & { label?: string }) {
}: Omit<React.ComponentPropsWithoutRef<'input'>, 'id'> & { label?: string; variant?: 'light' | 'dark' }) {
let id = useId()
return (
<div className={className}>
{label && <Label id={id}>{label}</Label>}
<input id={id} type={type} {...props} className={formClasses} />
{label && <Label id={id} variant={variant}>{label}</Label>}
<input id={id} type={type} {...props} className={formClasses[variant]} />
</div>
)
}

View File

@@ -22,11 +22,11 @@ function QrCodeBorder(props: React.ComponentPropsWithoutRef<'svg'>) {
export function Footer() {
return (
<footer id="footer" className="border-t border-gray-200">
<footer id="footer" className="border-t border-gray-800">
<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>
<div className="flex items-center text-gray-900">
<div className="flex items-center text-white">
<Logomark className="h-10 w-10 flex-none fill-cyan-500" />
<div className="ml-4">
<p className="text-base font-semibold">Project Mycelium</p>
@@ -37,25 +37,25 @@ export function Footer() {
<NavLinks />
</nav>
</div>
<div className="group relative -mx-4 flex items-center self-stretch p-4 transition-colors hover:bg-gray-100 sm:self-auto sm:rounded-2xl lg:mx-0 lg:self-auto lg:p-6">
<div className="group relative -mx-4 flex items-center self-stretch p-4 transition-colors hover:bg-gray-800/50 sm:self-auto sm:rounded-2xl lg:mx-0 lg:self-auto lg:p-6">
<div className="relative flex h-24 w-24 flex-none items-center justify-center">
<QrCodeBorder className="absolute inset-0 h-full w-full stroke-gray-300 transition-colors group-hover:stroke-cyan-500" />
<QrCodeBorder className="absolute inset-0 h-full w-full stroke-gray-700 transition-colors group-hover:stroke-cyan-500" />
<Image src={qrCode} alt="" unoptimized />
</div>
<div className="ml-8 lg:w-64">
<p className="text-base font-semibold text-gray-900">
<p className="text-base font-semibold text-white">
<Link href="#">
<span className="absolute inset-0 sm:rounded-2xl" />
Download the app
</Link>
</p>
<p className="mt-1 text-sm text-gray-700">
<p className="mt-1 text-sm text-gray-400">
Scan the QR code to download the app from the App Store.
</p>
</div>
</div>
</div>
<div className="flex flex-col items-center border-t border-gray-200 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">
<TextField
type="email"
@@ -63,6 +63,7 @@ export function Footer() {
placeholder="Email address"
autoComplete="email"
required
variant="dark"
className="w-60 min-w-0 shrink"
/>
<Button type="submit" color="cyan" className="ml-4 flex-none">
@@ -70,7 +71,7 @@ export function Footer() {
<span className="lg:hidden">Join newsletter</span>
</Button>
</form>
<p className="mt-6 text-sm text-gray-500 md:mt-0">
<p className="mt-6 text-sm text-gray-400 md:mt-0">
&copy; Copyright ThreeFold {new Date().getFullYear()}. All rights reserved.
</p>
</div>

View File

@@ -2,63 +2,55 @@
import CountUp from "react-countup";
import React from "react";
import { Button } from "./Button";
import { Button } from "@/components/Button";
export function GridStats() {
return (
<div id="grid-stats" className="py-24 bg-transparent relative">
<div className="mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-8">
<div className="grid grid-cols-1 gap-8 lg:grid-cols-3">
{/* Column 1: Title & NODES */}
<div
id="grid-stats"
className="py-24 relative -top-20 "
style={{
backgroundImage: "url(/images/benefits.webp)",
backgroundSize: "cover",
backgroundPosition: "center",
}}
>
<div className="mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-4">
<div className="grid grid-cols-1 gap-12 lg:grid-cols-3">
{/* Column 1: Title & Description */}
<div className="flex flex-col space-y-10">
{/* Title + Description */}
<div>
<h2 className="text-2xl font-semibold tracking-tight leading-tight text-black lg:text-4xl">
Powered by a Global Community
<h2 className="text-2xl font-semibold tracking-tight leading-tight text-white lg:text-4xl">
Robust Infrastructure for your Intellegence Needs
</h2>
<p className="mt-4 sm:mt-6 text-sm font-light text-pretty text-black lg:text-base">
ThreeFolds groundbreaking technology enables anyone individuals, organizations, and communities to deploy their own Internet infrastructure.
<p className="mt-4 sm:mt-6 text-sm font-light text-pretty text-white lg:text-base">
Mycelium's groundbreaking technology provides dedicated, performance-validated GPUs for your AI workloads.
</p>
<Button className="mt-8" variant="outline" href="https://threefold.io/build" >Explore TFGrid →</Button>
</div>
</div>
{/* Column 2: CORES (staggered) + SSD */}
{/* Column 2: StatCards */}
<div className="flex flex-col space-y-10">
<StatCard
label="CORES"
description="A globally distributed mesh of CPU cores powering decentralized applications, AI workloads, and edge computing — without central bottlenecks."
value={<CountUp end={54_958} duration={2.5} separator="," />}
note="Total Central Processing Unit Cores available on the grid."
label="Dedicated Hosting"
description="Run LLMs, VLMs, and diffusion models on single-tenant GPUs with private endpoints. Bring your own weights or deploy from a curated library of open models. Enjoy full control with flexible hourly pricing. Perfect for always-on inference or workloads exceeding 100K tokens per minute."
/>
<StatCard
label="SSD CAPACITY"
description="A distributed network of storage capacity — ready to support Web3, AI, and edge computing workloads around the world."
value={<CountUp end={7_364_506} duration={2.5} separator="," />}
unit="GB"
note="The total amount of storage (SSD, HDD, & RAM) on the grid."
label="Data Sovereignty"
description="Keep your sensitive data fully under your control. Mycelium nodes run on trusted infrastructure you own or choose, ensuring that no third party can access, train on, or monetize your data. This makes Mycelium ideal for enterprises in regulated industries that demand compliance and privacy."
/>
</div>
{/* Column 3: nodes countries */}
{/* Column 3: StatCards */}
<div className="flex flex-col space-y-10 justify-start">
<StatCard
label="NODES"
description="A computer server 100% dedicated to the network. It is a building block of the ThreeFold Grid, providing compute, storage, and network resources."
value={<CountUp end={1778} duration={2.5} separator="," />}
note="The total number of nodes on the grid."
label="Seamless Scalability"
description="Scale from a single agent to hundreds without re-architecting. Myceliums decentralized infrastructure dynamically allocates compute, storage, and bandwidth across the network, so your AI workloads remain fast and resilient even under heavy demand."
/>
<StatCard
label="COUNTRIES"
description="The number of countries where at least one node is connected and operational on the grid."
value={<CountUp end={51} duration={2.5} separator="," />}
note="The total number of countries with active nodes."
label="Composable Agent Ecosystem"
description="Mix and match agents for every part of your workflow: data ingestion, cleaning, orchestration, analysis, and reporting. Build an intelligent automation stack that evolves with your business needs, integrating easily with existing tools and APIs."
/>
</div>
</div>
@@ -71,21 +63,15 @@ export function GridStats() {
function StatCard({
label,
description,
value,
unit,
note,
className = "",
}: {
label: string;
description: string;
value: React.ReactNode;
unit?: string;
note: string;
className?: string;
}) {
return (
<div
className={`relative flex flex-col overflow-hidden rounded-3xl bg-white shadow-md shadow-gray-900/5 p-8 transition-all duration-300 ease-out hover:scale-105 ${className}`}
className={`relative flex flex-col overflow-hidden rounded-3xl bg-gray-900/75 shadow-md shadow-gray-900/5 p-8 transition-all duration-300 ease-out hover:scale-105 ${className}`}
style={{
filter: 'brightness(1)',
}}
@@ -96,22 +82,10 @@ function StatCard({
e.currentTarget.style.filter = 'brightness(1)';
}}
>
<h3 className="text-lg font-semibold text-gradient-neutral-vertical" style={{ textShadow: '0 0 12px rgba(255, 255, 255, 0.4), 0 0 24px rgba(255, 255, 255, 0.2)' }}>{label}</h3>
<p className="mt-2 text-sm font-light text-pretty text-black lg:text-base">
<h3 className="text-lg font-semibold text-white" style={{ textShadow: '0 0 12px rgba(255, 255, 255, 0.4), 0 0 24px rgba(255, 255, 255, 0.2)' }}>{label}</h3>
<p className="mt-2 text-sm font-light text-pretty text-white lg:text-base">
{description}
</p>
<div className="mt-8 flex items-center space-x-3">
<span className="text-gradient-neutral-vertical text-3xl"></span>
<div className="text-5xl font-semibold tracking-tight text-black tabular-nums">
{value}
{unit && (
<span className="ml-2 text-lg font-normal text-gray-800">{unit}</span>
)}
</div>
</div>
<p className="mt-2 text-sm text-gray-800 uppercase tracking-wider">
{note}
</p>
</div>
);
}

View File

@@ -18,51 +18,23 @@ export function HomeHero() {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
return (
<div className="relative h-screen -top-15">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 2 }}
className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[700px] h-[700px] -z-10 rounded-full overflow-hidden"
>
<div className="relative h-screen -top-20">
<div className="absolute inset-0 -z-10">
<video
autoPlay
loop
muted
playsInline
className="h-full w-full object-cover"
className="absolute inset-0 w-full h-full object-cover"
>
<source src="/videos/mycelium.mp4" type="video/mp4" />
</video>
</motion.div>
<div className="relative isolate px-6 lg:px-8">
<div
aria-hidden="true"
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl lg:-top-80"
>
<div
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
className="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#a4caf6] to-[#aaa4fa] opacity-15 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
/>
</div>
<div
aria-hidden="true"
className="absolute inset-x-0 bottom-10 -z-10 transform-gpu overflow-hidden blur-3xl lg:bottom-40"
>
<div
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
className="relative bottom-[calc(50%+3rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#93c5fd] to-[#9089fc] opacity-15 sm:left-[calc(50%+30rem)] sm:w-[72.1875rem]"
/>
</div>
<div className="absolute inset-0 bg-black/60" />
</div>
<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="text-center max-w-5xl">
<H1>
<H1 color="light">
<TypeAnimation
sequence={[
'Decentralized Autonomous Agentic Cloud.',
@@ -79,7 +51,7 @@ export function HomeHero() {
animate={{ opacity: 1 }}
transition={{ duration: 1, delay: 1 }}
>
<PL className="absolute bottom-0 left-0 max-w-xl text-left" color="custom">
<PL className="absolute bottom-0 left-0 max-w-xl text-left 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>

File diff suppressed because one or more lines are too long

View File

@@ -21,7 +21,7 @@ export function NavLinks() {
<Link
key={label}
href={href}
className="relative -mx-3 -my-2 rounded-lg px-3 py-2 text-sm text-[#2F3178] transition-colors delay-150 hover:text-[#2F3178] hover:delay-0"
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"
onMouseEnter={() => {
if (timeoutRef.current) {
window.clearTimeout(timeoutRef.current)
@@ -37,7 +37,7 @@ export function NavLinks() {
<AnimatePresence>
{hoveredIndex === index && (
<motion.span
className="absolute inset-0 rounded-lg bg-gray-100"
className="absolute inset-0 rounded-lg bg-white/10"
layoutId="hoverBackground"
initial={{ opacity: 0 }}
animate={{ opacity: 1, transition: { duration: 0.15 } }}

View File

@@ -30,18 +30,19 @@ export function Steps() {
const isInView = useInView(ref, { once: true });
return (
<section id="benefits" ref={ref} className="bg-white pt-0 pb-24 dark:bg-gray-900">
<div className="mx-auto max-w-7xl px-6 lg:px-0">
<section id="benefits" ref={ref} className="relative bg-cover bg-center py-32 -top-20 text-white" style={{ backgroundImage: "url('/images/deployment.webp')" }}>
<div className="absolute inset-0 bg-black/70" />
<div className="relative px-6 lg:px-6">
<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 lg:mx-0"
>
<H2 className="text-3xl font-medium tracking-tight">
<H2 className="text-3xl font-medium tracking-tight" color="light">
Deploy Scalable LLMs and AI Agents in Seconds
</H2>
<P className="mt-6 text-lg" color="custom">
<P className="mt-6 text-lg" 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.
</P>
</motion.div>
@@ -57,11 +58,11 @@ export function Steps() {
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
transition={{ duration: 0.5, delay: 0.3 + index * 0.2 }}
className="rounded-2xl border border-gray-200 p-8 dark:border-gray-700"
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"
>
<feature.icon className="h-8 w-8 mb-4 text-[#2F3178]" />
<CT as="span" className="font-semibold">{feature.name}</CT>
<CP className="mt-2 text-sm" color="custom">{feature.description}</CP>
<feature.icon className="h-8 w-8 mb-4 text-white" />
<CT as="span" className="font-semibold" color="light">{feature.name}</CT>
<CP className="mt-2 text-sm" color="light">{feature.description}</CP>
</motion.li>
))}
</motion.ul>

View File

@@ -7,6 +7,7 @@ const colorVariants = {
primary: 'text-[#2F3178]',
secondary: 'text-gray-600',
custom: 'text-[#1c1c49]',
light: 'text-white',
} as const
type TextOwnProps = {
@@ -51,10 +52,10 @@ const createTextComponent = <DefaultElement extends React.ElementType>(
// Exports
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 H2 = createTextComponent('h2', 'text-4xl font-medium text-pretty lg:text-5xl')
export const P = createTextComponent('p', 'text-xl font-normal text-pretty lg:text-2xl')
export const H3 = createTextComponent('h3', 'text-3xl lg:text-4xl font-medium')
export const H4 = createTextComponent('h4', 'text-2xl lg:text-3xl font-semibold leading-tight')
export const CT = createTextComponent('span', 'text-base lg:text-xl font-semibold text-center')
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 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 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 NL = createTextComponent('span', 'text-lg font-semibold leading-6')

View File

@@ -86,18 +86,18 @@ function Review({
return (
<figure
className={clsx(
'animate-fade-in rounded-3xl bg-white p-6 opacity-0 shadow-md shadow-gray-900/5',
'animate-fade-in rounded-3xl bg-gray-900/50 p-6 opacity-0 shadow-md shadow-gray-900/5',
className,
)}
style={{ animationDelay }}
{...props}
>
<blockquote className="text-gray-900">
<blockquote className="text-white">
{React.createElement(getReviewIcon(title), { className: "h-6 w-6 text-[#2F3178] mb-2" })}
<CT color="primary" className="mt-4 text-lg/6 font-semibold">
<CT color="light" className="mt-4 text-lg/6 font-semibold">
{title}
</CT>
<CP color="custom" className="mt-3 text-sm">{body}</CP>
<CP color="light" className="mt-3 text-sm">{body}</CP>
</blockquote>
</figure>
@@ -176,7 +176,7 @@ function ReviewGrid() {
return (
<div
ref={containerRef}
className="relative -mx-4 mt-0 grid h-196 max-h-[150vh] grid-cols-1 items-start gap-8 overflow-hidden px-4 sm:mt-20 md:grid-cols-2 lg:grid-cols-3"
className="relative -mx-4 mt-0 grid h-196 max-h-[150vh] grid-cols-1 items-start gap-8 overflow-hidden px-4 md:grid-cols-2 lg:grid-cols-3"
>
{isInView && (
<>
@@ -206,8 +206,8 @@ function ReviewGrid() {
/>
</>
)}
<div className="pointer-events-none absolute inset-x-0 top-0 h-32 bg-linear-to-b from-white" />
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-32 bg-linear-to-t from-white" />
<div className="pointer-events-none absolute inset-x-0 top-0 h-32 bg-linear-to-b from-black" />
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-32 bg-linear-to-t from-black" />
</div>
)
}
@@ -221,7 +221,7 @@ export function UseCases() {
id="usecases"
ref={ref}
aria-labelledby="usecases-title"
className="py-12"
className="bg-black py-12"
>
<Container className=''>
<motion.div
@@ -232,12 +232,12 @@ export function UseCases() {
>
<H2
id="usecases-title"
color="primary"
color="light"
className="text-center"
>
Coming Soon: The Future of Mycelium
</H2>
<P className="mt-6 text-center" color="custom">
<P className="mt-6 text-center" color="light">
Mycelium Cloud is evolving to bring even more powerful decentralized features, designed to enhance your experience and expand possibilities. Be the first to explore what's coming next by staying connected with our latest updates.
</P>
</motion.div>

View File

@@ -0,0 +1,23 @@
import { Globe } from "@/components/ui/globe"
import { motion } from "framer-motion"
import { H2, H3, H4, P } from "./Texts"
export function WorldMap() {
return (
<div className="relative h-screen max-w-full overflow-hidden bg-black -top-20">
<div className="absolute top-0 left-0 px-6 py-24 z-10 max-w-lg">
<H4 className="" color="light">
Mycelium Network is Live.
</H4>
<P className="mt-6 text-base text-pretty leading-relaxed font-light" color="light">
Mycelium Cloud's advancement technology enables anyone to deploy their own Internet infrastructure, anywhere.
</P>
</div>
<div className="absolute inset-0 flex items-center justify-center">
<Globe className="top-28" />
</div>
<div className="pointer-events-none absolute inset-0 h-full bg-[radial-gradient(circle_at_50%_200%,rgba(0,0,0,0.2),rgba(255,255,255,0))]" />
</div>
);
}

View File

@@ -1,3 +1,3 @@
import { Ai21 } from '@lobehub/icons';
export default () => <Ai21.Brand size={40} />;
export default () => <Ai21.Brand size={30} />;

View File

@@ -1,3 +1,3 @@
import { AlibabaCloud } from '@lobehub/icons';
export default () => <AlibabaCloud.Text size={40} />;
export default () => <AlibabaCloud.Text size={30} />;

View File

@@ -1,3 +1,3 @@
import { BaiduCloud } from '@lobehub/icons';
export default () => <BaiduCloud.Combine size={40} />;
export default () => <BaiduCloud.Combine size={30} />;

View File

@@ -1,3 +1,3 @@
import { ByteDance } from '@lobehub/icons';
export default () => <ByteDance.Text size={40} />;
export default () => <ByteDance.Text size={30} />;

View File

@@ -1,3 +1,3 @@
import { Claude } from '@lobehub/icons';
export default () => <Claude.Combine size={40} />;
export default () => <Claude.Combine size={30} />;

View File

@@ -1,3 +1,3 @@
import { DeepMind } from '@lobehub/icons';
export default () => <DeepMind.Combine size={40} />;
export default () => <DeepMind.Combine size={30} />;

View File

@@ -1,3 +1,3 @@
import { DeepSeek } from '@lobehub/icons';
export default () => <DeepSeek.Combine size={40} />;
export default () => <DeepSeek.Combine size={30} />;

View File

@@ -1,3 +1,3 @@
import { Minimax } from '@lobehub/icons';
export default () => <Minimax.Combine size={40} />;
export default () => <Minimax.Combine size={30} />;

View File

@@ -1,3 +1,3 @@
import { Mistral } from '@lobehub/icons';
export default () => <Mistral.Combine size={40} />;
export default () => <Mistral.Combine size={30} />;

View File

@@ -1,3 +1,3 @@
import { Moonshot } from '@lobehub/icons';
export default () => <Moonshot.Combine size={40} />;
export default () => <Moonshot.Combine size={30} />;

View File

@@ -1,3 +1,3 @@
import { OpenAI } from '@lobehub/icons';
export default () => <OpenAI.Combine size={40} />;
export default () => <OpenAI.Combine size={30} />;

View File

@@ -1,3 +1,3 @@
import { TencentCloud } from '@lobehub/icons';
export default () => <TencentCloud.Combine size={40} />;
export default () => <TencentCloud.Combine size={30} />;

View File

@@ -1,3 +1,3 @@
import { XAI } from '@lobehub/icons';
export default () => <XAI.Text size={40} />;
export default () => <XAI.Text size={30} />;

View File

@@ -0,0 +1,96 @@
"use client";
import { cn } from "@/lib/utils";
import React, { useEffect, useState } from "react";
export const InfiniteMovingCards = ({
items,
direction = "left",
speed = "fast",
pauseOnHover = true,
className,
}: {
items: React.ReactNode[];
direction?: "left" | "right";
speed?: "fast" | "normal" | "slow";
pauseOnHover?: boolean;
className?: string;
}) => {
const containerRef = React.useRef<HTMLDivElement>(null);
const scrollerRef = React.useRef<HTMLUListElement>(null);
useEffect(() => {
addAnimation();
}, []);
const [start, setStart] = useState(false);
function addAnimation() {
if (containerRef.current && scrollerRef.current) {
const scrollerContent = Array.from(scrollerRef.current.children);
scrollerContent.forEach((item) => {
const duplicatedItem = item.cloneNode(true);
if (scrollerRef.current) {
scrollerRef.current.appendChild(duplicatedItem);
}
});
getDirection();
getSpeed();
setStart(true);
}
}
const getDirection = () => {
if (containerRef.current) {
if (direction === "left") {
containerRef.current.style.setProperty(
"--animation-direction",
"forwards"
);
} else {
containerRef.current.style.setProperty(
"--animation-direction",
"reverse"
);
}
}
};
const getSpeed = () => {
if (containerRef.current) {
if (speed === "fast") {
containerRef.current.style.setProperty("--animation-duration", "20s");
} else if (speed === "normal") {
containerRef.current.style.setProperty("--animation-duration", "40s");
} else {
containerRef.current.style.setProperty("--animation-duration", "80s");
}
}
};
return (
<div
ref={containerRef}
className={cn(
"scroller relative z-20 max-w-7xl overflow-hidden [mask-image:linear-gradient(to_right,transparent,white_20%,white_80%,transparent)]",
className
)}
>
<ul
ref={scrollerRef}
className={cn(
" flex min-w-full shrink-0 gap-4 py-0 w-max flex-nowrap",
start && "animate-scroll ",
pauseOnHover && "hover:[animation-play-state:paused]"
)}
>
{items.map((item, idx) => (
<li
className="w-[160px] max-w-full relative flex-shrink-0 flex items-center justify-center px-8 py-0 md:w-[180px]"
key={idx}
>
{item}
</li>
))}
</ul>
</div>
);
};

View File

@@ -10,12 +10,12 @@ const baseStyles = {
const variantStyles = {
solid: {
primary: 'bg-[#2F3178] text-white hover:bg-[#2F3178]/90 active:bg-[#2F3178]/80',
primary: 'bg-[#005eff] text-white hover:bg-[#005eff]/90 active:bg-[#005eff]/80',
white: 'bg-white text-black hover:bg-white/90 active:bg-white/90 active:text-gray-400',
gray: 'bg-gray-800 text-white hover:bg-gray-900 active:bg-gray-800 active:text-white/80',
},
outline: {
primary: 'border-[#2F3178] text-[#2F3178] hover:border-[#2F3178]/80 hover:text-[#2F3178]/80 active:bg-gray-100 active:text-[#2F3178]/70',
primary: 'border-[#005eff] text-[#005eff] hover:border-[#005eff]/80 hover:text-[#005eff]/80 active:bg-gray-100 active:text-[#005eff]/70',
gray: 'border-gray-300 text-gray-700 hover:border-gray-400 active:bg-gray-100 active:text-gray-700/80',
},
}

View File

@@ -13,7 +13,7 @@ export function ScrollDown() {
return (
<button
onClick={scrollToNext}
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 text-2xl font-medium text-white lg:text-3xl animate-blink"
>
<span>scroll</span>
<ChevronDoubleDownIcon className="h-6 w-6" />

128
src/components/ui/globe.tsx Normal file
View File

@@ -0,0 +1,128 @@
"use client";
import createGlobe, { COBEOptions } from "cobe";
import { useMotionValue, useSpring } from "motion/react";
import { useEffect, useRef } from "react";
import { cn } from "@/lib/utils";
const MOVEMENT_DAMPING = 1400;
const GLOBE_CONFIG: COBEOptions = {
width: 800,
height: 800,
onRender: () => {},
devicePixelRatio: 2,
phi: 0,
theta: 0.3,
dark: 0,
diffuse: 0.4,
mapSamples: 16000,
mapBrightness: 1.2,
baseColor: [1, 1, 1],
markerColor: [1 / 255, 94 / 255, 255 / 255],
glowColor: [1, 1, 1],
markers: [
{ location: [14.5995, 120.9842], size: 0.03 },
{ location: [19.076, 72.8777], size: 0.1 },
{ location: [23.8103, 90.4125], size: 0.05 },
{ location: [30.0444, 31.2357], size: 0.07 },
{ location: [39.9042, 116.4074], size: 0.08 },
{ location: [-23.5505, -46.6333], size: 0.1 },
{ location: [19.4326, -99.1332], size: 0.1 },
{ location: [40.7128, -74.006], size: 0.1 },
{ location: [34.6937, 135.5022], size: 0.05 },
{ location: [41.0082, 28.9784], size: 0.06 },
],
};
export function Globe({
className,
config = GLOBE_CONFIG,
}: {
className?: string;
config?: COBEOptions;
}) {
let phi = 0;
let width = 0;
const canvasRef = useRef<HTMLCanvasElement>(null);
const pointerInteracting = useRef<number | null>(null);
const pointerInteractionMovement = useRef(0);
const r = useMotionValue(0);
const rs = useSpring(r, {
mass: 1,
damping: 30,
stiffness: 100,
});
const updatePointerInteraction = (value: number | null) => {
pointerInteracting.current = value;
if (canvasRef.current) {
canvasRef.current.style.cursor = value !== null ? "grabbing" : "grab";
}
};
const updateMovement = (clientX: number) => {
if (pointerInteracting.current !== null) {
const delta = clientX - pointerInteracting.current;
pointerInteractionMovement.current = delta;
r.set(r.get() + delta / MOVEMENT_DAMPING);
}
};
useEffect(() => {
const onResize = () => {
if (canvasRef.current) {
width = canvasRef.current.offsetWidth;
}
};
window.addEventListener("resize", onResize);
onResize();
const globe = createGlobe(canvasRef.current!, {
...config,
width: width * 2,
height: width * 2,
onRender: (state) => {
if (!pointerInteracting.current) phi += 0.005;
state.phi = phi + rs.get();
state.width = width * 2;
state.height = width * 2;
},
});
setTimeout(() => (canvasRef.current!.style.opacity = "1"), 0);
return () => {
globe.destroy();
window.removeEventListener("resize", onResize);
};
}, [rs, config]);
return (
<div
className={cn(
"absolute inset-0 mx-auto aspect-[1/1] w-full max-w-[600px]",
className,
)}
>
<canvas
className={cn(
"size-full opacity-0 transition-opacity duration-500 [contain:layout_paint_size]",
)}
ref={canvasRef}
onPointerDown={(e) => {
pointerInteracting.current = e.clientX;
updatePointerInteraction(e.clientX);
}}
onPointerUp={() => updatePointerInteraction(null)}
onPointerOut={() => updatePointerInteraction(null)}
onMouseMove={(e) => updateMovement(e.clientX)}
onTouchMove={(e) =>
e.touches[0] && updateMovement(e.touches[0].clientX)
}
/>
</div>
);
}

View File

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

View File

@@ -1,8 +1,17 @@
@import 'tailwindcss';
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
@plugin '@tailwindcss/forms';
@theme {
@keyframes scroll {
to {
transform: translate(calc(-50% - 0.5rem));
}
}
--text-*: initial;
--text-xs: 0.75rem;
--text-xs--line-height: 1rem;
@@ -39,7 +48,7 @@
--animate-spin-reverse-slower: spin-reverse 6s linear infinite;
--animate-marquee-vertical: marquee-vertical 40s linear infinite;
--animate-bounce-y: bounce-y 1.5s infinite;
--radius-4xl: 2rem;
--radius-5xl: 2.5rem;
@@ -101,6 +110,10 @@
}
@layer utilities {
.animate-scroll {
animation: scroll var(--animation-duration, 40s) var(--animation-direction, forwards) linear infinite;
}
.animate-blink {
animation: blink 2s infinite;
}
@@ -112,10 +125,132 @@
@theme inline {
--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 {
100% {
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.13 0.028 261.692);
--card: oklch(1 0 0);
--card-foreground: oklch(0.13 0.028 261.692);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.13 0.028 261.692);
--primary: oklch(0.21 0.034 264.665);
--primary-foreground: oklch(0.985 0.002 247.839);
--secondary: oklch(0.967 0.003 264.542);
--secondary-foreground: oklch(0.21 0.034 264.665);
--muted: oklch(0.967 0.003 264.542);
--muted-foreground: oklch(0.551 0.027 264.364);
--accent: oklch(0.967 0.003 264.542);
--accent-foreground: oklch(0.21 0.034 264.665);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.928 0.006 264.531);
--input: oklch(0.928 0.006 264.531);
--ring: oklch(0.707 0.022 261.325);
--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.002 247.839);
--sidebar-foreground: oklch(0.13 0.028 261.692);
--sidebar-primary: oklch(0.21 0.034 264.665);
--sidebar-primary-foreground: oklch(0.985 0.002 247.839);
--sidebar-accent: oklch(0.967 0.003 264.542);
--sidebar-accent-foreground: oklch(0.21 0.034 264.665);
--sidebar-border: oklch(0.928 0.006 264.531);
--sidebar-ring: oklch(0.707 0.022 261.325);
}
.dark {
--background: oklch(0.13 0.028 261.692);
--foreground: oklch(0.985 0.002 247.839);
--card: oklch(0.21 0.034 264.665);
--card-foreground: oklch(0.985 0.002 247.839);
--popover: oklch(0.21 0.034 264.665);
--popover-foreground: oklch(0.985 0.002 247.839);
--primary: oklch(0.928 0.006 264.531);
--primary-foreground: oklch(0.21 0.034 264.665);
--secondary: oklch(0.278 0.033 256.848);
--secondary-foreground: oklch(0.985 0.002 247.839);
--muted: oklch(0.278 0.033 256.848);
--muted-foreground: oklch(0.707 0.022 261.325);
--accent: oklch(0.278 0.033 256.848);
--accent-foreground: oklch(0.985 0.002 247.839);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.551 0.027 264.364);
--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.21 0.034 264.665);
--sidebar-foreground: oklch(0.985 0.002 247.839);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0.002 247.839);
--sidebar-accent: oklch(0.278 0.033 256.848);
--sidebar-accent-foreground: oklch(0.985 0.002 247.839);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.551 0.027 264.364);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}