Velocity UI
Loading…
Menu

Installation

Add this component to your project using the CLI:

terminal
npx vui-registry-cli-v1 add premium-carousel

Source Code

premium-carousel.tsx
'use client'

import React, { useEffect, useState, useCallback, useRef } from 'react'
import { motion, useMotionValue, useSpring, useTransform, MotionValue } from 'framer-motion'
import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselNext,
  CarouselPrevious,
  type CarouselApi,
} from '@/components/ui/carousel'
import { cn } from '@/lib/utils'
import { Shield, Zap, Cpu, Network, Activity, ChevronRight } from 'lucide-react'

const ITEMS = [
  { title: 'Neural Engine', badge: 'v4.0', icon: Cpu, description: 'Real-time inference architecture with zero-latency response protocols.' },
  { title: 'Vector Mesh', badge: 'Global', icon: Network, description: 'Distributed retrieval layers across 42 global edge nodes.' },
  { title: 'Ghost Protocol', badge: 'Secure', icon: Shield, description: 'Next-gen encryption using post-quantum cryptographic standards.' },
  { title: 'Sync Node', badge: 'Active', icon: Activity, description: 'Deterministic state machine for multi-region consistency.' },
]

/**
 * IMPROVED MESH: Reactive to Hover
 */
const HighFreqCyanMesh = ({ active, mouseX, mouseY }: { active: boolean, mouseX: MotionValue<number>, mouseY: MotionValue<number> }) => {
  const [hoveredIdx, setHoveredIdx] = useState<number | null>(null)
  const containerRef = useRef<HTMLDivElement>(null)

  const handleMouseMove = (e: React.MouseEvent) => {
    if (!active || !containerRef.current) return
    const rect = containerRef.current.getBoundingClientRect()
    const x = e.clientX - rect.left
    const y = e.clientY - rect.top
    const col = Math.floor((x / rect.width) * 10)
    const row = Math.floor((y / rect.height) * 8)
    setHoveredIdx(row * 10 + col)
  }

  return (
    <div 
      ref={containerRef}
      onMouseMove={handleMouseMove}
      onMouseLeave={() => setHoveredIdx(null)}
      className="absolute inset-0 h-full w-full pointer-events-auto [mask-image:radial-gradient(circle_at_center,white_40%,transparent_95%)]"
    >
      <div className="grid grid-cols-10 grid-rows-8 h-full w-full p-6 gap-0.5 pointer-events-none">
        {Array.from({ length: 80 }).map((_, i) => {
          // Dots light up if they are the one hovered or direct neighbors
          const isBlinking = hoveredIdx !== null && (
            i === hoveredIdx || 
            i === hoveredIdx + 1 || i === hoveredIdx - 1 || 
            i === hoveredIdx + 10 || i === hoveredIdx - 10
          )
          
          return (
            <div key={i} className="flex items-center justify-center">
              <motion.div
                animate={{
                  opacity: isBlinking ? 1 : 0.08,
                  backgroundColor: isBlinking ? "#22d3ee" : "#52525b",
                  scale: isBlinking ? 2.5 : 1,
                  boxShadow: isBlinking ? "0 0 8px rgba(34,211,238,0.8)" : "none"
                }}
                transition={{ duration: 0.15 }}
                className="w-[1px] h-[1px] rounded-full"
              />
            </div>
          )
        })}
      </div>
    </div>
  )
}

/**
 * Isolated Card Component to fix Hook Order errors
 */
const CarouselCard = ({ item, index, isActive, isLeft, isRight, isVisible, rotateX, rotateY, borderX, borderY, handleMouseMove, resetMouse }: any) => {
  const Icon = item.icon
  
  // useTransform called safely inside the component scope
  const glowBg = useTransform(
    [borderX, borderY],
    ([x, y]) => `radial-gradient(circle at ${x} ${y}, rgba(34,211,238,0.2) 0%, transparent 40%)`
  )

  return (
    <motion.div
      onMouseMove={isActive ? handleMouseMove : undefined}
      onMouseLeave={resetMouse}
      animate={{
        rotateY: isActive ? 0 : isLeft ? 25 : isRight ? -25 : 0,
        scale: isActive ? 1 : 0.85,
        z: isActive ? 0 : -150,
        opacity: isActive ? 1 : isVisible ? 0.4 : 0,
        filter: isActive ? 'blur(0px)' : 'blur(2px)',
      }}
      style={{
        rotateX: isActive ? rotateX : 0,
        rotateY: isActive ? rotateY : (isLeft ? 25 : isRight ? -25 : 0),
        transformStyle: 'preserve-3d',
      }}
      transition={{ type: 'spring', stiffness: 300, damping: 30 }}
      className={cn(
        'relative h-[420px] w-full rounded-3xl p-8 flex flex-col group cursor-crosshair overflow-hidden transition-all duration-500',
        'bg-card border border-border/70',
        isActive ? 'border-primary/40 shadow-xl shadow-primary/5' : 'border-border/40'
      )}
    >
      {isActive && (
        <motion.div 
          className="absolute inset-0 rounded-[24px] pointer-events-none opacity-0 group-hover:opacity-100 transition-opacity"
          style={{
            padding: '1px',
            background: glowBg,
            WebkitMask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)',
            WebkitMaskComposite: 'xor',
            maskComposite: 'exclude',
          }}
        />
      )}

      <HighFreqCyanMesh active={isActive} mouseX={borderX} mouseY={borderY} />

      <div className="relative z-20 h-full flex flex-col pointer-events-none" style={{ transform: "translateZ(50px)" }}>
        <div className="mb-12 flex justify-between items-start">
          <div className={cn(
            "p-3 rounded-2xl border transition-all duration-700",
            isActive ? "border-primary/30 bg-foreground/10 text-primary shadow-[0_0_20px_var(--primary)]" : "border-border text-muted-foreground"
          )}>
            <Icon size={20} strokeWidth={1} />
          </div>
          <span className="text-[9px] font-mono text-muted-foreground tracking-widest">{item.badge}</span>
        </div>

        <h4 className={cn("text-2xl font-light tracking-tight mb-5 transition-colors duration-500", isActive ? "text-foreground" : "text-muted-foreground")}>
          {item.title}
        </h4>
        
        <p className="text-[13px] leading-relaxed text-muted-foreground font-light max-w-[240px]">
          {item.description}
        </p>

        <div className="mt-auto flex items-center justify-between border-t border-zinc-900/50 pt-8">
           <div className="space-y-1">
              <p className="text-[7px] font-mono uppercase tracking-widest text-muted-foreground">Telemetry</p>
              <p className="text-[10px] font-mono text-muted-foreground">{isActive ? 'BUFFER_STREAMING' : 'IDLE_WAIT'}</p>
           </div>
           <div className="flex items-center gap-1 text-muted-foreground">
              <span className="text-[10px] font-mono">0{index + 1}</span>
              <ChevronRight size={12} className={cn(isActive ? "text-primary/50" : "text-muted-foreground")} />
           </div>
        </div>
      </div>
    </motion.div>
  )
}

export default function PremiumRoundedCyanCarousel() {
  const [api, setApi] = useState<CarouselApi>()
  const [current, setCurrent] = useState(0)

  const mouseX = useMotionValue(0)
  const mouseY = useMotionValue(0)

  const springX = useSpring(mouseX, { stiffness: 400, damping: 28 })
  const springY = useSpring(mouseY, { stiffness: 400, damping: 28 })

  const rotateX = useTransform(springY, [-0.5, 0.5], ['10deg', '-10deg'])
  const rotateY = useTransform(springX, [-0.5, 0.5], ['-10deg', '10deg'])

  const borderX = useTransform(mouseX, [-0.5, 0.5], ['0%', '100%'])
  const borderY = useTransform(mouseY, [-0.5, 0.5], ['0%', '100%'])

  const onSelect = useCallback(() => {
    if (!api) return
    setCurrent(api.selectedScrollSnap())
  }, [api])

  useEffect(() => {
    if (!api) return
    onSelect()
    api.on('select', onSelect)
  }, [api, onSelect])

  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
    const rect = e.currentTarget.getBoundingClientRect()
    mouseX.set((e.clientX - rect.left) / rect.width - 0.5)
    mouseY.set((e.clientY - rect.top) / rect.height - 0.5)
  }

  return (
    <div className="w-full min-h-[640px] flex flex-col items-center justify-center bg-background py-10 overflow-hidden">
      <Carousel setApi={setApi} opts={{ align: 'center', loop: true }} className="w-full max-w-6xl overflow-visible">
        <div className="flex items-center justify-between px-6 md:px-10 lg:px-20 mb-10 relative z-50">
          <div className="flex flex-col gap-1">
            <div className="flex items-center gap-2">
              <div className="w-1.5 h-1.5 rounded-full bg-cyan-500 animate-pulse shadow-[0_0_8px_#22d3ee]" />
              <span className="text-muted-foreground text-[10px] font-mono tracking-widest uppercase italic">Node Status: Active</span>
            </div>
            <h2 className="text-foreground text-2xl md:text-3xl font-extralight tracking-tighter">System Infrastructure</h2>
          </div>
          <div className="flex gap-3">
            <CarouselPrevious className="static translate-y-0 h-10 w-10 rounded-full border-border bg-card text-muted-foreground hover:text-primary hover:border-primary/60 transition-all duration-300" />
            <CarouselNext className="static translate-y-0 h-10 w-10 rounded-full border-border bg-card text-muted-foreground hover:text-primary hover:border-primary/60 transition-all duration-300" />
          </div>
        </div>

        <CarouselContent className="ml-0 overflow-visible py-10">
          {ITEMS.map((item, index) => (
            <CarouselItem 
              key={index} 
              className="pl-0 basis-full md:basis-[360px] overflow-visible flex justify-center px-4"
              style={{ perspective: '1200px' }}
              onClick={() => api?.scrollTo(index)}
            >
              <CarouselCard 
                item={item}
                index={index}
                isActive={current === index}
                isLeft={index === (current - 1 + ITEMS.length) % ITEMS.length}
                isRight={index === (current + 1) % ITEMS.length}
                isVisible={(current === index) || (index === (current - 1 + ITEMS.length) % ITEMS.length) || (index === (current + 1) % ITEMS.length)}
                rotateX={rotateX}
                rotateY={rotateY}
                borderX={borderX}
                borderY={borderY}
                handleMouseMove={handleMouseMove}
                resetMouse={() => { mouseX.set(0); mouseY.set(0); }}
              />
            </CarouselItem>
          ))}
        </CarouselContent>
      </Carousel>
    </div>
  )
}