Skip to content

Commit 78970c1

Browse files
committed
feat: enhance hero section with modern TV background, auto-sliding videos, and futuristic UI elements
1 parent 9fc9b00 commit 78970c1

2 files changed

Lines changed: 267 additions & 42 deletions

File tree

src/components/HeroSection.tsx

Lines changed: 130 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from "react";
22
import { motion, useScroll, useTransform } from "motion/react";
33
import { useRef } from "react";
4-
import { ImageWithFallback } from "./figma/ImageWithFallback";
4+
import { TVBackground } from "./TVBackground";
55

66
export function HeroSection() {
77
const ref = useRef(null);
@@ -19,19 +19,14 @@ export function HeroSection() {
1919
data-scroll-section
2020
className="relative h-screen flex items-center justify-center overflow-hidden bg-black"
2121
>
22-
{/* Parallax Background */}
22+
{/* TV Background */}
2323
<motion.div
2424
data-scroll
2525
data-scroll-speed="-2"
2626
style={{ y }}
2727
className="absolute inset-0 w-full h-[120%] -z-10"
2828
>
29-
<ImageWithFallback
30-
src="https://images.unsplash.com/photo-1688550181338-e013f4b72aba?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxESiUyMGJvb3RoJTIwbmVvbiUyMGxpZ2h0c3xlbnwxfHx8fDE3NTY1ODYyNTB8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
31-
alt="DJ booth with neon lights"
32-
className="w-full h-full object-cover opacity-40"
33-
/>
34-
<div className="absolute inset-0 bg-gradient-to-b from-black/50 via-black/30 to-black/80" />
29+
<TVBackground />
3530
</motion.div>
3631

3732
{/* Hero Content */}
@@ -58,9 +53,9 @@ export function HeroSection() {
5853
initial={{ opacity: 0, y: 20 }}
5954
animate={{ opacity: 1, y: 0 }}
6055
transition={{ duration: 0.8, delay: 3.2 }}
61-
className="mb-6"
56+
className="mb-8"
6257
>
63-
<motion.p
58+
<motion.div
6459
animate={{
6560
opacity: [0.6, 1, 0.6],
6661
scale: [0.98, 1, 0.98]
@@ -70,37 +65,103 @@ export function HeroSection() {
7065
repeat: Infinity,
7166
ease: "easeInOut"
7267
}}
73-
className="text-sm sm:text-base lg:text-lg font-light text-white/70 tracking-wider uppercase"
74-
style={{ fontFamily: "'Inter', sans-serif" }}
68+
className="relative"
7569
>
76-
Experience the future of sound
77-
</motion.p>
70+
<motion.p
71+
className="text-sm sm:text-base lg:text-lg font-light text-white/70 tracking-wider uppercase mb-2"
72+
style={{ fontFamily: "'Inter', sans-serif" }}
73+
>
74+
Experience the future of sound
75+
</motion.p>
76+
77+
{/* Futuristic line */}
78+
<motion.div
79+
animate={{ width: [0, 100, 0] }}
80+
transition={{
81+
duration: 4,
82+
repeat: Infinity,
83+
ease: "easeInOut"
84+
}}
85+
className="h-px bg-gradient-to-r from-transparent via-[#00FF85] to-transparent mx-auto"
86+
/>
87+
</motion.div>
7888
</motion.div>
7989

80-
{/* Decorative Image Below Title */}
90+
{/* Futuristic DJ Interface */}
8191
<motion.div
8292
initial={{ opacity: 0, scale: 0.8 }}
8393
animate={{ opacity: 1, scale: 1 }}
8494
transition={{ duration: 1, delay: 2.8 }}
8595
className="mb-8 relative"
8696
>
87-
<div className="w-32 h-32 sm:w-40 sm:h-40 mx-auto relative overflow-hidden rounded-full border-2 border-[#00FF85]/30 backdrop-blur-sm">
88-
<ImageWithFallback
89-
src="https://images.unsplash.com/photo-1572327918400-f1932eded229?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxESiUyMGhhbmRzJTIwdHVybnRhYmxlcyUyMG1peGluZ3xlbnwxfHx8fDE3NTY1ODczMzV8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
90-
alt="DJ hands on turntables"
91-
className="w-full h-full object-cover opacity-70"
97+
<div className="w-48 h-48 sm:w-56 sm:h-56 mx-auto relative">
98+
{/* Main Interface Circle */}
99+
<div className="w-full h-full relative">
100+
{/* Outer Ring */}
101+
<motion.div
102+
animate={{ rotate: 360 }}
103+
transition={{ duration: 30, repeat: Infinity, ease: "linear" }}
104+
className="absolute inset-0 border-2 border-[#00FF85]/40 rounded-full"
105+
/>
106+
107+
{/* Middle Ring */}
108+
<motion.div
109+
animate={{ rotate: -360 }}
110+
transition={{ duration: 20, repeat: Infinity, ease: "linear" }}
111+
className="absolute inset-4 border border-[#00FF85]/30 rounded-full"
112+
/>
113+
114+
{/* Inner Ring */}
115+
<motion.div
116+
animate={{ rotate: 360 }}
117+
transition={{ duration: 15, repeat: Infinity, ease: "linear" }}
118+
className="absolute inset-8 border border-[#00FF85]/20 rounded-full"
119+
/>
120+
121+
{/* Center Element */}
122+
<div className="absolute inset-12 bg-gradient-to-br from-[#00FF85]/20 to-black/80 rounded-full flex items-center justify-center backdrop-blur-sm">
123+
<motion.div
124+
animate={{
125+
scale: [1, 1.1, 1],
126+
opacity: [0.8, 1, 0.8]
127+
}}
128+
transition={{
129+
duration: 2,
130+
repeat: Infinity,
131+
ease: "easeInOut"
132+
}}
133+
className="w-8 h-8 bg-[#00FF85] rounded-full"
134+
/>
135+
</div>
136+
</div>
137+
138+
{/* Floating Elements */}
139+
<motion.div
140+
animate={{
141+
y: [0, -20, 0],
142+
rotate: [0, 180, 360]
143+
}}
144+
transition={{
145+
duration: 8,
146+
repeat: Infinity,
147+
ease: "easeInOut"
148+
}}
149+
className="absolute -top-4 -right-4 w-6 h-6 border border-[#00FF85]/60 rounded-full"
150+
/>
151+
152+
<motion.div
153+
animate={{
154+
y: [0, 20, 0],
155+
rotate: [360, 180, 0]
156+
}}
157+
transition={{
158+
duration: 6,
159+
repeat: Infinity,
160+
ease: "easeInOut"
161+
}}
162+
className="absolute -bottom-4 -left-4 w-4 h-4 bg-[#00FF85]/40 rounded-full"
92163
/>
93-
<div className="absolute inset-0 bg-gradient-to-b from-[#00FF85]/20 to-black/40" />
94164
</div>
95-
{/* Rotating ring around image */}
96-
<motion.div
97-
animate={{ rotate: 360 }}
98-
transition={{ duration: 20, repeat: Infinity, ease: "linear" }}
99-
className="absolute inset-0 w-32 h-32 sm:w-40 sm:h-40 mx-auto border border-[#00FF85]/50 rounded-full"
100-
style={{
101-
background: "conic-gradient(from 0deg, transparent, #00FF85, transparent)"
102-
}}
103-
/>
104165
</motion.div>
105166

106167
<motion.p
@@ -113,7 +174,7 @@ export function HeroSection() {
113174
</motion.p>
114175
</motion.div>
115176

116-
{/* Enhanced Scroll Indicator */}
177+
{/* Futuristic Scroll Indicator */}
117178
<motion.div
118179
initial={{ opacity: 0 }}
119180
animate={{ opacity: 1 }}
@@ -123,24 +184,51 @@ export function HeroSection() {
123184
<motion.div
124185
animate={{ y: [0, 10, 0] }}
125186
transition={{ duration: 2, repeat: Infinity }}
126-
className="flex flex-col items-center space-y-2"
187+
className="flex flex-col items-center space-y-3"
127188
>
189+
{/* Main Scroll Bar */}
190+
<div className="relative">
191+
<motion.div
192+
animate={{ height: [20, 40, 20] }}
193+
transition={{ duration: 2, repeat: Infinity }}
194+
className="w-1 bg-gradient-to-b from-[#00FF85] to-transparent rounded-full"
195+
/>
196+
<motion.div
197+
animate={{
198+
y: [0, 20, 0],
199+
opacity: [0.8, 1, 0.8]
200+
}}
201+
transition={{ duration: 2, repeat: Infinity }}
202+
className="absolute top-0 w-3 h-3 bg-[#00FF85] rounded-full -left-1"
203+
/>
204+
</div>
205+
206+
{/* SCROLL Text */}
128207
<motion.div
129-
animate={{ y: [0, 12, 0] }}
130-
transition={{ duration: 2, repeat: Infinity }}
131-
className="w-1 h-3 bg-[#00FF85] rounded-full"
132-
/>
133-
<motion.p
134208
animate={{ opacity: [0.6, 1, 0.6] }}
135209
transition={{ duration: 2, repeat: Infinity }}
136-
className="text-xs text-white/60 font-medium tracking-wider"
210+
className="text-center"
137211
>
138-
SCROLL
139-
</motion.p>
212+
<motion.p
213+
className="text-xs text-white/60 font-medium tracking-widest uppercase"
214+
>
215+
SCROLL
216+
</motion.p>
217+
<motion.div
218+
animate={{ width: [0, 20, 0] }}
219+
transition={{ duration: 2, repeat: Infinity }}
220+
className="h-px bg-[#00FF85] mx-auto mt-1"
221+
/>
222+
</motion.div>
223+
224+
{/* Bottom Indicator */}
140225
<motion.div
141-
animate={{ y: [0, 8, 0] }}
226+
animate={{
227+
y: [0, 8, 0],
228+
scale: [1, 1.2, 1]
229+
}}
142230
transition={{ duration: 2, repeat: Infinity, delay: 0.5 }}
143-
className="w-1 h-2 bg-white/40 rounded-full"
231+
className="w-2 h-2 bg-white/40 rounded-full"
144232
/>
145233
</motion.div>
146234
</motion.div>

src/components/TVBackground.tsx

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import React, { useState, useEffect } from "react";
2+
import { motion, AnimatePresence } from "motion/react";
3+
4+
interface VideoSlide {
5+
id: number;
6+
src: string;
7+
poster: string;
8+
alt: string;
9+
}
10+
11+
const videoSlides: VideoSlide[] = [
12+
{
13+
id: 1,
14+
src: "https://player.vimeo.com/external/434045526.sd.mp4?s=c27eecc69a27dbc4ff2b87d38afc35f1a9e7c02d&profile_id=164&oauth2_token_id=57447761",
15+
poster: "https://images.unsplash.com/photo-1688550181338-e013f4b72aba?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxESiUyMGJvb3RoJTIwbmVvbiUyMGxpZ2h0c3xlbnwxfHx8fDE3NTY1ODYyNTB8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
16+
alt: "DJ booth with neon lights"
17+
},
18+
{
19+
id: 2,
20+
src: "https://player.vimeo.com/external/434045526.sd.mp4?s=c27eecc69a27dbc4ff2b87d38afc35f1a9e7c02d&profile_id=164&oauth2_token_id=57447761",
21+
poster: "https://images.unsplash.com/photo-1558258021-971dd2148be5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxjb25jZXJ0JTIwY3Jvd2QlMjBlbmVyZ3l8ZW58MXx8fHwxNzU2NTg2MjUxfDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
22+
alt: "Concert crowd energy"
23+
},
24+
{
25+
id: 3,
26+
src: "https://player.vimeo.com/external/434045526.sd.mp4?s=c27eecc69a27dbc4ff2b87d38afc35f1a9e7c02d&profile_id=164&oauth2_token_id=57447761",
27+
poster: "https://images.unsplash.com/photo-1604025707953-41752f5793ab?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxmdXR1cmlzdGljJTIwcHVycGxlJTIwbGlnaHRzfGVufDF8fHx8MTc1NjU4NjI1MXww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
28+
alt: "Futuristic purple lights"
29+
}
30+
];
31+
32+
export function TVBackground() {
33+
const [currentVideoIndex, setCurrentVideoIndex] = useState(0);
34+
const [isTransitioning, setIsTransitioning] = useState(false);
35+
36+
useEffect(() => {
37+
const interval = setInterval(() => {
38+
setIsTransitioning(true);
39+
setTimeout(() => {
40+
setCurrentVideoIndex((prev) => (prev + 1) % videoSlides.length);
41+
setIsTransitioning(false);
42+
}, 500);
43+
}, 5000);
44+
45+
return () => clearInterval(interval);
46+
}, []);
47+
48+
return (
49+
<div className="absolute inset-0 w-full h-full -z-10">
50+
{/* TV Frame */}
51+
<div className="relative w-full h-full">
52+
{/* TV Bezel */}
53+
<div className="absolute inset-0 border-8 border-gray-800 rounded-3xl shadow-2xl">
54+
{/* TV Screen */}
55+
<div className="absolute inset-2 bg-black rounded-2xl overflow-hidden">
56+
{/* Video Content */}
57+
<AnimatePresence mode="wait">
58+
<motion.div
59+
key={currentVideoIndex}
60+
initial={{ opacity: 0, scale: 1.1 }}
61+
animate={{ opacity: 1, scale: 1 }}
62+
exit={{ opacity: 0, scale: 0.9 }}
63+
transition={{ duration: 0.5 }}
64+
className="w-full h-full relative"
65+
>
66+
<video
67+
key={videoSlides[currentVideoIndex].id}
68+
autoPlay
69+
muted
70+
loop
71+
poster={videoSlides[currentVideoIndex].poster}
72+
className="w-full h-full object-cover"
73+
>
74+
<source src={videoSlides[currentVideoIndex].src} type="video/mp4" />
75+
</video>
76+
77+
{/* Video Overlay */}
78+
<div className="absolute inset-0 bg-gradient-to-b from-black/60 via-black/30 to-black/80" />
79+
</motion.div>
80+
</AnimatePresence>
81+
82+
{/* TV Scan Lines Effect */}
83+
<div className="absolute inset-0 pointer-events-none">
84+
<div className="w-full h-full bg-gradient-to-b from-transparent via-white/5 to-transparent opacity-30 animate-pulse" />
85+
</div>
86+
</div>
87+
88+
{/* TV Stand */}
89+
<div className="absolute -bottom-4 left-1/2 transform -translate-x-1/2 w-32 h-4 bg-gradient-to-b from-gray-700 to-gray-900 rounded-b-lg" />
90+
</div>
91+
92+
{/* Floating UI Elements */}
93+
<motion.div
94+
animate={{
95+
y: [0, -10, 0],
96+
opacity: [0.7, 1, 0.7]
97+
}}
98+
transition={{
99+
duration: 4,
100+
repeat: Infinity,
101+
ease: "easeInOut"
102+
}}
103+
className="absolute top-8 right-8 w-16 h-16"
104+
>
105+
<svg viewBox="0 0 64 64" fill="none" className="w-full h-full">
106+
<circle cx="32" cy="32" r="30" stroke="#00FF85" strokeWidth="2" fill="none" opacity="0.6" />
107+
<circle cx="32" cy="32" r="20" stroke="#00FF85" strokeWidth="1" fill="none" opacity="0.4" />
108+
<circle cx="32" cy="32" r="8" fill="#00FF85" opacity="0.8" />
109+
</svg>
110+
</motion.div>
111+
112+
{/* Video Progress Indicator */}
113+
<div className="absolute bottom-8 left-1/2 transform -translate-x-1/2 flex space-x-2">
114+
{videoSlides.map((_, index) => (
115+
<motion.div
116+
key={index}
117+
animate={{
118+
scale: currentVideoIndex === index ? 1.2 : 1,
119+
opacity: currentVideoIndex === index ? 1 : 0.4
120+
}}
121+
transition={{ duration: 0.3 }}
122+
className={`w-2 h-2 rounded-full ${
123+
currentVideoIndex === index ? 'bg-[#00FF85]' : 'bg-white/40'
124+
}`}
125+
/>
126+
))}
127+
</div>
128+
129+
{/* Corner Accents */}
130+
<div className="absolute top-4 left-4 w-8 h-8 border-l-2 border-t-2 border-[#00FF85] rounded-tl-lg" />
131+
<div className="absolute top-4 right-4 w-8 h-8 border-r-2 border-t-2 border-[#00FF85] rounded-tr-lg" />
132+
<div className="absolute bottom-4 left-4 w-8 h-8 border-l-2 border-b-2 border-[#00FF85] rounded-bl-lg" />
133+
<div className="absolute bottom-4 right-4 w-8 h-8 border-r-2 border-b-2 border-[#00FF85] rounded-br-lg" />
134+
</div>
135+
</div>
136+
);
137+
}

0 commit comments

Comments
 (0)