diff --git a/public/videos/cloud.mp4 b/public/videos/cloud.mp4 new file mode 100644 index 0000000..dddb48e Binary files /dev/null and b/public/videos/cloud.mp4 differ diff --git a/public/videos/cloud2.mp4 b/public/videos/cloud2.mp4 new file mode 100644 index 0000000..378537b Binary files /dev/null and b/public/videos/cloud2.mp4 differ diff --git a/src/app/(main)/page.tsx b/src/app/(main)/page.tsx index 1baa1b2..e270b61 100644 --- a/src/app/(main)/page.tsx +++ b/src/app/(main)/page.tsx @@ -6,7 +6,7 @@ import { HomeHero } from '@/components/HomeHero' import { HomeHeroLight } from '@/components/HomeHeroLight' import { HomeHeroLight2 } from '@/components/HomeHeroLight2' import { HomeAbout } from '@/components/HomeAbout' -import { ClickableGallery } from '@/components/ClickableGallery' +import { ClickableGalleryLight } from '@/components/ClickableGalleryLight' import { StackSectionLight } from '@/components/StackSectionLight' import { Companies } from '@/components/Companies' import { CallToAction } from '@/components/CallToAction' @@ -36,7 +36,7 @@ export default function Home() {
diff --git a/src/components/ClickableGalleryLight.tsx b/src/components/ClickableGalleryLight.tsx new file mode 100644 index 0000000..f9bcb6e --- /dev/null +++ b/src/components/ClickableGalleryLight.tsx @@ -0,0 +1,179 @@ +'use client' + +import { useEffect, useMemo, useState } from 'react' +import { useResponsiveCarousel } from '@/hooks/useResponsiveCarousel'; +import Image from 'next/image' +import { motion, AnimatePresence } from 'framer-motion' +import { wrap } from 'popmotion' +import { Button } from '@/components/Button'; +import { H2, P, CT } from '@/components/Texts'; +import { TypeAnimation } from 'react-type-animation' +import { FadeIn } from './FadeIn'; + +const galleryItems = [ + { 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/gallery/docs.jpg', width: 448, height: 277 }, + { text: 'Execute multi-step workflows autonomously', image: '/images/gallery/flow.jpg', width: 448, height: 277 }, + { 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/gallery/data.jpg', width: 448, height: 277 }, + { text: 'Identify patterns in complex datasets', image: '/images/gallery/datasets.jpg', width: 448, height: 277 }, + { 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/gallery/code.jpg', width: 448, height: 277 }, + { text: 'Create consistent branded content', image: '/images/gallery/branding.jpg', width: 448, height: 277 }, + { text: 'Translate and localize materials', image: '/images/gallery/translate.jpg', width: 448, height: 277 }, + { text: 'Transform and migrate data structures', image: '/images/gallery/structure.jpg', width: 448, height: 277 }, +] + +// đź”§ Carousel Config +const VISIBLE = 4; +const AUTOPLAY_MS = 3200; + +export function ClickableGalleryLight() { + const [active, setActive] = useState(0); + const [hovering, setHovering] = useState(false); + const { GAP, ROT_Y, DEPTH, SCALE_DROP } = useResponsiveCarousel(); + + // autoplay + useEffect(() => { + if (hovering) return + const id = setInterval(() => setActive((i) => wrap(0, galleryItems.length, i + 1)), AUTOPLAY_MS) + return () => clearInterval(id) + }, [hovering]) + + const indices = useMemo( + () => [...Array(VISIBLE * 2 + 1)].map((_, i) => wrap(0, galleryItems.length, active + i - VISIBLE)), + [active] + ) + + const next = () => setActive((i) => wrap(0, galleryItems.length, i + 1)) + const prev = () => setActive((i) => wrap(0, galleryItems.length, i - 1)) + + return ( +
+
+ +
+

Agents with Endless Possibilities.

+
+
+ +
+

+ Your private agent coordinates a team of specialists that spin up on demand, collaborate across your world, and deliver end-to-end results. + Many agents, one intelligence—yours. +

+
+
+
+ +
setHovering(true)} + onMouseLeave={() => setHovering(false)} + > +
+
+ + {indices.map((idx, i) => { + const distance = i - VISIBLE; + const item = galleryItems[idx]; + + const x = distance * GAP; + const z = -Math.abs(distance) * DEPTH; + const r = distance * ROT_Y; + const s = 1 - Math.abs(distance) * SCALE_DROP; + const o = distance === 0 ? 1 : 0.80; + const zIndex = 100 - Math.abs(distance); + + return ( + setActive(idx)} + > +
+ {item.text} +
+
+ ); + })} +
+
+
+ + {/* Arrows */} +
+ +
+
+ +
+ + {/* Foreground pill (Desktop) */} +
+
+ + + + +
+
+
+ + {/* Text box (Mobile) */} +
+
+ + + + +
+
+
+
+ ); +} diff --git a/src/components/HeaderLight.tsx b/src/components/HeaderLight.tsx index 4bf5299..bf38bcf 100644 --- a/src/components/HeaderLight.tsx +++ b/src/components/HeaderLight.tsx @@ -1,6 +1,6 @@ 'use client' -import { useRef, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import Link from 'next/link' import { AnimatePresence, motion } from 'framer-motion' import clsx from 'clsx' @@ -60,11 +60,39 @@ function NavLinks() { } export function HeaderLight() { + const [isVisible, setIsVisible] = useState(true); + const [lastScrollY, setLastScrollY] = useState(0); + + const controlHeader = () => { + if (typeof window !== 'undefined') { + if (window.scrollY > lastScrollY && window.scrollY > 100) { // Hides when scrolling down past 100px + setIsVisible(false); + } else { // Shows when scrolling up + setIsVisible(true); + } + setLastScrollY(window.scrollY); + } + }; + + useEffect(() => { + if (typeof window !== 'undefined') { + window.addEventListener('scroll', controlHeader); + return () => { + window.removeEventListener('scroll', controlHeader); + }; + } + }, [lastScrollY]); + return ( -
+
-
+ ) } diff --git a/src/components/HomeHeroLight2.tsx b/src/components/HomeHeroLight2.tsx index 0d9b09d..c7d5480 100644 --- a/src/components/HomeHeroLight2.tsx +++ b/src/components/HomeHeroLight2.tsx @@ -1,77 +1,58 @@ '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, H2, PL } from '@/components/Texts' -import { ChevronRightIcon } from '@heroicons/react/20/solid' - +import { useRef, useEffect } from 'react' export function HomeHeroLight2() { + const videoRef = useRef(null) + + useEffect(() => { + if (videoRef.current) videoRef.current.playbackRate = 0.4 + }, []) + return ( -
+
+ {/* Background video */} +
) -} \ No newline at end of file +} diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index 72ac8e0..7d17a1a 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -5,6 +5,7 @@ export function Layout({ children }: { children: React.ReactNode }) { return ( <> + {children}
{children}