mirror of
https://github.com/hanzoai/templates.git
synced 2026-10-30 18:20:05 +00:00
224 lines
8.1 KiB
TypeScript
224 lines
8.1 KiB
TypeScript
import React, { useRef } from 'react'
|
|
import { motion, useScroll, useTransform } from 'framer-motion'
|
|
import { Canvas, useFrame } from '@react-three/fiber'
|
|
import { OrbitControls, Sphere, MeshDistortMaterial, Environment, Float } from '@react-three/drei'
|
|
import { TypeAnimation } from 'react-type-animation'
|
|
import Tilt from 'react-parallax-tilt'
|
|
import { useInView } from 'react-intersection-observer'
|
|
|
|
interface Hero3DProps {
|
|
title: string
|
|
subtitle: string
|
|
description: string
|
|
primaryColor: string
|
|
secondaryColor: string
|
|
features?: string[]
|
|
}
|
|
|
|
function AnimatedSphere({ color }: { color: string }) {
|
|
const meshRef = useRef<any>(null)
|
|
|
|
useFrame((state) => {
|
|
if (meshRef.current) {
|
|
meshRef.current.rotation.x = state.clock.getElapsedTime() * 0.2
|
|
meshRef.current.rotation.y = state.clock.getElapsedTime() * 0.3
|
|
}
|
|
})
|
|
|
|
return (
|
|
<Float speed={2} rotationIntensity={1} floatIntensity={1}>
|
|
<Sphere ref={meshRef} args={[1, 100, 100]} scale={2.5}>
|
|
<MeshDistortMaterial
|
|
color={color}
|
|
attach="material"
|
|
distort={0.3}
|
|
speed={2}
|
|
roughness={0}
|
|
metalness={0.8}
|
|
/>
|
|
</Sphere>
|
|
</Float>
|
|
)
|
|
}
|
|
|
|
export function Hero3D({ title, subtitle, description, primaryColor, secondaryColor, features = [] }: Hero3DProps) {
|
|
const { ref, inView } = useInView({
|
|
threshold: 0.1,
|
|
triggerOnce: true
|
|
})
|
|
|
|
const containerRef = useRef<HTMLDivElement>(null)
|
|
const { scrollYProgress } = useScroll({
|
|
target: containerRef,
|
|
offset: ["start start", "end start"]
|
|
})
|
|
|
|
const y = useTransform(scrollYProgress, [0, 1], [0, -300])
|
|
const opacity = useTransform(scrollYProgress, [0, 0.5], [1, 0])
|
|
|
|
return (
|
|
<section ref={containerRef} className="relative min-h-screen overflow-hidden">
|
|
{/* Animated gradient background */}
|
|
<div
|
|
className="absolute inset-0 opacity-30"
|
|
style={{
|
|
background: `linear-gradient(135deg, ${primaryColor} 0%, ${secondaryColor} 50%, ${primaryColor} 100%)`,
|
|
backgroundSize: '400% 400%',
|
|
animation: 'gradient 15s ease infinite'
|
|
}}
|
|
/>
|
|
|
|
{/* Particle effect background */}
|
|
<div className="absolute inset-0">
|
|
{[...Array(50)].map((_, i) => (
|
|
<motion.div
|
|
key={i}
|
|
className="absolute w-1 h-1 bg-white rounded-full"
|
|
initial={{
|
|
x: Math.random() * window.innerWidth,
|
|
y: Math.random() * window.innerHeight,
|
|
opacity: Math.random()
|
|
}}
|
|
animate={{
|
|
y: [null, Math.random() * -100 - 50],
|
|
opacity: [null, 0, Math.random()]
|
|
}}
|
|
transition={{
|
|
duration: Math.random() * 10 + 10,
|
|
repeat: Infinity,
|
|
ease: "linear"
|
|
}}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
<motion.div style={{ y, opacity }} className="relative z-10">
|
|
<div className="container mx-auto px-4 pt-32 pb-20">
|
|
<div className="grid lg:grid-cols-2 gap-12 items-center">
|
|
{/* Left content */}
|
|
<motion.div
|
|
ref={ref}
|
|
initial={{ opacity: 0, x: -50 }}
|
|
animate={inView ? { opacity: 1, x: 0 } : {}}
|
|
transition={{ duration: 0.8, delay: 0.2 }}
|
|
>
|
|
<motion.div
|
|
initial={{ scale: 0 }}
|
|
animate={inView ? { scale: 1 } : {}}
|
|
transition={{ type: "spring", stiffness: 100, delay: 0.1 }}
|
|
className="inline-block"
|
|
>
|
|
<span className="px-4 py-2 rounded-full text-sm font-semibold text-white bg-gradient-to-r from-purple-600 to-pink-600 mb-6 inline-block">
|
|
✨ Next Generation Platform
|
|
</span>
|
|
</motion.div>
|
|
|
|
<h1 className="text-5xl lg:text-7xl font-bold mb-6">
|
|
<TypeAnimation
|
|
sequence={[
|
|
title,
|
|
2000,
|
|
`${title} 🚀`,
|
|
2000,
|
|
]}
|
|
wrapper="span"
|
|
speed={50}
|
|
className="bg-gradient-to-r from-blue-600 via-purple-600 to-pink-600 bg-clip-text text-transparent"
|
|
repeat={Infinity}
|
|
/>
|
|
</h1>
|
|
|
|
<p className="text-xl lg:text-2xl text-gray-600 dark:text-gray-300 mb-8">
|
|
{subtitle}
|
|
</p>
|
|
|
|
<p className="text-gray-500 dark:text-gray-400 mb-8">
|
|
{description}
|
|
</p>
|
|
|
|
{/* Animated feature list */}
|
|
<div className="space-y-3 mb-8">
|
|
{features.map((feature, index) => (
|
|
<motion.div
|
|
key={feature}
|
|
initial={{ opacity: 0, x: -20 }}
|
|
animate={inView ? { opacity: 1, x: 0 } : {}}
|
|
transition={{ delay: 0.5 + index * 0.1 }}
|
|
className="flex items-center gap-3"
|
|
>
|
|
<motion.div
|
|
whileHover={{ scale: 1.2, rotate: 360 }}
|
|
className="w-6 h-6 rounded-full bg-gradient-to-r from-green-400 to-emerald-400 flex items-center justify-center"
|
|
>
|
|
<span className="text-white text-xs">✓</span>
|
|
</motion.div>
|
|
<span className="text-gray-700 dark:text-gray-300">{feature}</span>
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
|
|
{/* CTA Buttons */}
|
|
<div className="flex flex-wrap gap-4">
|
|
<Tilt tiltMaxAngleX={5} tiltMaxAngleY={5}>
|
|
<motion.button
|
|
whileHover={{ scale: 1.05 }}
|
|
whileTap={{ scale: 0.95 }}
|
|
className="px-8 py-4 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-xl font-semibold shadow-2xl hover:shadow-purple-500/25"
|
|
>
|
|
Get Started Free
|
|
</motion.button>
|
|
</Tilt>
|
|
|
|
<Tilt tiltMaxAngleX={5} tiltMaxAngleY={5}>
|
|
<motion.button
|
|
whileHover={{ scale: 1.05 }}
|
|
whileTap={{ scale: 0.95 }}
|
|
className="px-8 py-4 bg-white dark:bg-gray-800 text-gray-900 dark:text-white rounded-xl font-semibold shadow-xl border border-gray-200 dark:border-gray-700"
|
|
>
|
|
Watch Demo
|
|
</motion.button>
|
|
</Tilt>
|
|
</div>
|
|
</motion.div>
|
|
|
|
{/* Right 3D content */}
|
|
<motion.div
|
|
initial={{ opacity: 0, scale: 0.8 }}
|
|
animate={inView ? { opacity: 1, scale: 1 } : {}}
|
|
transition={{ duration: 1, delay: 0.3 }}
|
|
className="h-[500px] lg:h-[600px]"
|
|
>
|
|
<Canvas camera={{ position: [0, 0, 5] }}>
|
|
<ambientLight intensity={0.5} />
|
|
<directionalLight position={[10, 10, 5]} intensity={1} />
|
|
<AnimatedSphere color={primaryColor} />
|
|
<Environment preset="city" />
|
|
<OrbitControls enableZoom={false} autoRotate />
|
|
</Canvas>
|
|
</motion.div>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
|
|
{/* Scroll indicator */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ delay: 1, repeat: Infinity, duration: 2 }}
|
|
className="absolute bottom-8 left-1/2 -translate-x-1/2"
|
|
>
|
|
<div className="flex flex-col items-center gap-2">
|
|
<span className="text-sm text-gray-500">Scroll to explore</span>
|
|
<motion.div
|
|
animate={{ y: [0, 10, 0] }}
|
|
transition={{ repeat: Infinity, duration: 1.5 }}
|
|
>
|
|
<svg className="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 14l-7 7m0 0l-7-7m7 7V3" />
|
|
</svg>
|
|
</motion.div>
|
|
</div>
|
|
</motion.div>
|
|
</section>
|
|
)
|
|
} |