-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathHero.jsx
More file actions
157 lines (143 loc) · 4.77 KB
/
Copy pathHero.jsx
File metadata and controls
157 lines (143 loc) · 4.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import React, { useState, useRef, useEffect } from 'react';
import { TiLocationArrow } from 'react-icons/ti';
import { ArrowDown } from './icons';
import Button from './Button';
import { useGSAP } from '@gsap/react';
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/all';
gsap.registerPlugin(ScrollTrigger);
const Hero = () => {
const [currentIndex, setCurrentIndex] = useState(1);
const [hasClick, setHasClick] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [loadedVideos, setLoadedVideos] = useState(0);
const totalVideos = 4;
const nextVideoRef = useRef(null);
const handleVideoLoad = () => {
setLoadedVideos((prev) => prev + 1);
};
const upComingVideoIndex = (currentIndex % totalVideos) + 1;
const handleMiniVidClick = () => {
setHasClick(true);
setCurrentIndex(upComingVideoIndex);
};
useEffect(() => {
if (loadedVideos === totalVideos - 1) {
setIsLoading(false);
}
}, [loadedVideos]);
useGSAP(
() => {
if (hasClick) {
gsap.set('#next-video', { visibility: 'visible' });
gsap.to('#next-video', {
transformOrigin: 'center',
scale: 1,
width: '100%',
height: '100%',
duration: 1,
ease: 'power1.inOut',
onStart: () => nextVideoRef.current.play(),
});
gsap.from('#current-video', {
transformOrigin: 'center center',
scale: 0,
duration: 1.5,
ease: 'power1.inOut',
});
}
},
{ dependencies: [currentIndex], revertOnUpdate: true }
);
useGSAP(() => {
gsap.set('#video-frame', {
clipPath: 'polygon(14% 0%, 72% 0%, 90% 90%, 0% 100%)',
borderRadius: '0 0 40% 10%',
});
gsap.from('#video-frame', {
clipPath: 'polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)',
borderRadius: '0 0 0 0',
ease: 'power1.inOut',
scrollTrigger: {
trigger: '#video-frame',
start: 'center center',
end: 'bottom center',
scrub: 1,
},
});
});
const getVideoSrc = (index) => `videos/hero-${index}.mp4`;
return (
<div className="relative h-dvh w-screen overflow-x-hidden">
{isLoading && (
<div className="flex-center absolute z-[100] h-dvh w-screen overflow-hidden bg-violet-50">
<div className="three-body">
<div className="three-body__dot" />
<div className="three-body__dot" />
<div className="three-body__dot" />
</div>
</div>
)}
<div
id="video-frame"
className="relative z-10 h-dvh w-screen overflow-hidden rounded-lg bg-blue-75"
>
<div>
<div className="mask-clip-path absolute-center absolute z-50 size-64 cursor-pointer overflow-hidden rounded-lg">
<div
onClick={handleMiniVidClick}
className="origin-center scale-50 opacity-0 transition-all duration-500 ease-in hover:scale-100 hover:opacity-100"
>
<video
ref={nextVideoRef}
src={getVideoSrc(upComingVideoIndex)}
loop
muted
id="current-video"
className="size-64 origin-center scale-150 object-cover object-center"
onLoadedData={handleVideoLoad}
/>
</div>
</div>
<video
ref={nextVideoRef}
src={getVideoSrc(currentIndex)}
loop
muted
id="next-video"
className="absolute-center invisible absolute z-20 size-64 object-cover object-center"
onLoadedData={handleVideoLoad}
/>
<video
src={getVideoSrc(1)}
autoPlay
loop
muted
className="absolute left-0 top-0 size-full object-cover object-center"
onLoadedData={handleVideoLoad}
/>
</div>
<h1 className="special-font hero-heading absolute bottom-5 right-5 z-40 text-blue-75">
G<b>a</b>ming
</h1>
<div className="absolute left-0 top-0 z-40 size-full">
<div className="mt-24 px-5 sm:px-10">
<h1 className="special-font hero-heading text-blue-100">
redefi<b>n</b>e
</h1>
<p className="mb-5 max-w-72 lg:max-w-96 font-robert-regular text-sm md:text-base lg:text-lg text-blue-100">
Enter the Metagame Layer.
<br />
The substrate where life, data, and AI form a perpetual
engine, compounding intelligence, capability, and value.
</p>
</div>
</div>
</div>
<h1 className="special-font hero-heading absolute bottom-5 right-5 text-black">
G<b>a</b>ming
</h1>
</div>
);
};
export default Hero;