Skip to content

Commit cd0be11

Browse files
Enhance parallax effect on landing page
Implement more advanced and innovative parallax effects throughout the landing page, including the hero section, to improve user experience and visual appeal.
1 parent 83e63bd commit cd0be11

5 files changed

Lines changed: 401 additions & 126 deletions

File tree

src/components/ApplicationsSection.tsx

Lines changed: 108 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -10,37 +10,58 @@ const ApplicationsSection = () => {
1010
const isMobile = useIsMobile();
1111
const sectionRef = useRef<HTMLElement>(null);
1212
const cardsRef = useRef<HTMLDivElement>(null);
13+
const titleRef = useRef<HTMLHeadingElement>(null);
1314

14-
// Add parallax effect on scroll
15+
// Advanced parallax effect on scroll
1516
useEffect(() => {
1617
const handleScroll = () => {
1718
if (!sectionRef.current || !cardsRef.current) return;
1819

1920
const scrollPosition = window.scrollY;
21+
const viewportHeight = window.innerHeight;
2022
const sectionTop = sectionRef.current.offsetTop;
2123
const sectionHeight = sectionRef.current.offsetHeight;
2224

23-
// Check if section is in viewport
24-
if (scrollPosition > sectionTop - window.innerHeight &&
25-
scrollPosition < sectionTop + sectionHeight) {
26-
25+
// Calculate how far through the section we've scrolled (0 to 1)
26+
const scrollProgress = (scrollPosition - (sectionTop - viewportHeight)) /
27+
(sectionHeight + viewportHeight);
28+
29+
// Check if section is in viewport (with buffer)
30+
if (scrollProgress >= -0.2 && scrollProgress <= 1.2) {
31+
// Card staggered animations
2732
const cards = cardsRef.current.querySelectorAll('.focus-card');
2833

2934
cards.forEach((card, index) => {
3035
const cardElement = card as HTMLElement;
31-
const offset = (scrollPosition - (sectionTop - window.innerHeight * 0.5)) * 0.02;
32-
const delay = index * 0.1;
33-
const translateY = Math.min(30, Math.max(0, offset - delay * 10));
36+
// Create a staggered effect based on index and scroll
37+
const delay = index * 0.15;
38+
const cardScrollProgress = Math.max(0, Math.min(1, (scrollProgress - delay) * 2));
3439

3540
// Only apply effect if not on mobile
3641
if (!isMobile) {
37-
cardElement.style.transform = `translateY(-${translateY}px)`;
38-
cardElement.style.opacity = `${Math.min(1, 0.7 + translateY / 100)}`;
42+
// Initial state is translated down and rotated
43+
const translateY = 100 - (cardScrollProgress * 100);
44+
const opacity = Math.min(1, cardScrollProgress * 2);
45+
const rotateX = 20 - (cardScrollProgress * 20); // Tilt effect
46+
const scale = 0.8 + (cardScrollProgress * 0.2); // Subtle scale
47+
48+
cardElement.style.transform = `perspective(1000px) translateY(${translateY}px) rotateX(${rotateX}deg) scale(${scale})`;
49+
cardElement.style.opacity = `${opacity}`;
3950
} else {
4051
cardElement.style.transform = '';
4152
cardElement.style.opacity = '1';
4253
}
4354
});
55+
56+
// Title parallax effect
57+
if (titleRef.current) {
58+
const titleProgress = Math.max(0, Math.min(1, scrollProgress * 3));
59+
const titleTranslateY = 50 - (titleProgress * 50);
60+
const titleOpacity = Math.min(1, titleProgress * 1.5);
61+
62+
titleRef.current.style.transform = `translateY(${titleTranslateY}px)`;
63+
titleRef.current.style.opacity = `${titleOpacity}`;
64+
}
4465
}
4566
};
4667

@@ -52,74 +73,89 @@ const ApplicationsSection = () => {
5273

5374
return (
5475
<section ref={sectionRef} className="py-20 bg-primary-blue/5 relative overflow-hidden">
55-
{/* Decorative shapes for parallax */}
76+
{/* Decorative shapes with parallax */}
5677
<div className="absolute -z-10 opacity-10 top-0 left-0 w-full h-full overflow-hidden">
5778
<div className="parallax-item absolute top-10 left-10 w-64 h-64 rounded-full bg-bistre/20"></div>
5879
<div className="parallax-item absolute bottom-20 right-20 w-80 h-80 rounded-full bg-primary-blue/20"></div>
80+
<div className="parallax-item absolute top-[60%] left-[30%] w-40 h-40 rounded-full bg-bistre/15"></div>
81+
<div className="parallax-item absolute top-[20%] right-[20%] w-32 h-32 rounded-full bg-primary-blue/15"></div>
5982
</div>
60-
61-
<div className="container mx-auto px-4">
62-
<div className="max-w-6xl mx-auto">
63-
<h2 className="text-3xl md:text-4xl font-bold mb-16 text-center text-primary-blue">
64-
<span className="relative pb-2">
65-
Where We Apply Our Technology
66-
<span className="absolute bottom-0 left-1/2 transform -translate-x-1/2 w-20 h-1 bg-bistre"></span>
67-
</span>
68-
</h2>
69-
70-
<div ref={cardsRef} className={`grid ${isMobile ? 'grid-cols-1' : 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5'} gap-6 max-w-5xl mx-auto`}>
71-
<Card className="focus-card bg-offwhite border-primary-blue/20 hover:border-primary-blue/50 transition-all duration-700">
72-
<CardContent className="p-6 flex flex-col items-center text-center">
73-
<div className="focus-icon bg-primary-blue/5 text-primary-blue">
74-
<Bot size={24} />
75-
</div>
76-
<h3 className="text-lg font-bold text-primary-blue">Robotics</h3>
77-
</CardContent>
78-
</Card>
79-
80-
<Card className="focus-card bg-offwhite border-primary-blue/20 hover:border-primary-blue/50 transition-all duration-700">
81-
<CardContent className="p-6 flex flex-col items-center text-center">
82-
<div className="focus-icon bg-primary-blue/5 text-primary-blue">
83-
<Cpu size={24} />
84-
</div>
85-
<h3 className="text-lg font-bold text-primary-blue">Drones</h3>
86-
</CardContent>
87-
</Card>
88-
89-
<Card className="focus-card bg-offwhite border-primary-blue/20 hover:border-primary-blue/50 transition-all duration-700">
90-
<CardContent className="p-6 flex flex-col items-center text-center">
91-
<div className="focus-icon bg-primary-blue/5 text-primary-blue">
92-
<Database size={24} />
93-
</div>
94-
<h3 className="text-lg font-bold text-primary-blue">Smart Manufacturing</h3>
95-
</CardContent>
96-
</Card>
83+
84+
{/* 3D perspective wrapper for depth */}
85+
<div style={{ perspective: "2000px" }} className="relative z-10">
86+
<div className="container mx-auto px-4">
87+
<div className="max-w-6xl mx-auto">
88+
<h2
89+
ref={titleRef}
90+
className="text-3xl md:text-4xl font-bold mb-16 text-center text-primary-blue"
91+
style={{ willChange: "transform, opacity" }}
92+
>
93+
<span className="relative pb-2">
94+
Where We Apply Our Technology
95+
<span className="absolute bottom-0 left-1/2 transform -translate-x-1/2 w-20 h-1 bg-bistre"></span>
96+
</span>
97+
</h2>
9798

98-
<Card className="focus-card bg-offwhite border-primary-blue/20 hover:border-primary-blue/50 transition-all duration-700">
99-
<CardContent className="p-6 flex flex-col items-center text-center">
100-
<div className="focus-icon bg-primary-blue/5 text-primary-blue">
101-
<Car size={24} />
102-
</div>
103-
<h3 className="text-lg font-bold text-primary-blue">Automotive</h3>
104-
</CardContent>
105-
</Card>
99+
<div
100+
ref={cardsRef}
101+
className={`grid ${isMobile ? 'grid-cols-1' : 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5'} gap-6 max-w-5xl mx-auto`}
102+
>
103+
<Card className="focus-card bg-offwhite border-primary-blue/20 hover:border-primary-blue/50 transition-all duration-700" style={{ willChange: "transform, opacity" }}>
104+
<CardContent className="p-6 flex flex-col items-center text-center">
105+
<div className="focus-icon bg-primary-blue/5 text-primary-blue">
106+
<Bot size={24} />
107+
</div>
108+
<h3 className="text-lg font-bold text-primary-blue">Robotics</h3>
109+
</CardContent>
110+
</Card>
111+
112+
<Card className="focus-card bg-offwhite border-primary-blue/20 hover:border-primary-blue/50 transition-all duration-700" style={{ willChange: "transform, opacity" }}>
113+
<CardContent className="p-6 flex flex-col items-center text-center">
114+
<div className="focus-icon bg-primary-blue/5 text-primary-blue">
115+
<Cpu size={24} />
116+
</div>
117+
<h3 className="text-lg font-bold text-primary-blue">Drones</h3>
118+
</CardContent>
119+
</Card>
120+
121+
<Card className="focus-card bg-offwhite border-primary-blue/20 hover:border-primary-blue/50 transition-all duration-700" style={{ willChange: "transform, opacity" }}>
122+
<CardContent className="p-6 flex flex-col items-center text-center">
123+
<div className="focus-icon bg-primary-blue/5 text-primary-blue">
124+
<Database size={24} />
125+
</div>
126+
<h3 className="text-lg font-bold text-primary-blue">Smart Manufacturing</h3>
127+
</CardContent>
128+
</Card>
129+
130+
<Card className="focus-card bg-offwhite border-primary-blue/20 hover:border-primary-blue/50 transition-all duration-700" style={{ willChange: "transform, opacity" }}>
131+
<CardContent className="p-6 flex flex-col items-center text-center">
132+
<div className="focus-icon bg-primary-blue/5 text-primary-blue">
133+
<Car size={24} />
134+
</div>
135+
<h3 className="text-lg font-bold text-primary-blue">Automotive</h3>
136+
</CardContent>
137+
</Card>
138+
139+
<Card className="focus-card bg-offwhite border-primary-blue/20 hover:border-primary-blue/50 transition-all duration-700" style={{ willChange: "transform, opacity" }}>
140+
<CardContent className="p-6 flex flex-col items-center text-center">
141+
<div className="focus-icon bg-primary-blue/5 text-primary-blue">
142+
<Microscope size={24} />
143+
</div>
144+
<h3 className="text-lg font-bold text-primary-blue">Biomedical</h3>
145+
</CardContent>
146+
</Card>
147+
</div>
106148

107-
<Card className="focus-card bg-offwhite border-primary-blue/20 hover:border-primary-blue/50 transition-all duration-700">
108-
<CardContent className="p-6 flex flex-col items-center text-center">
109-
<div className="focus-icon bg-primary-blue/5 text-primary-blue">
110-
<Microscope size={24} />
111-
</div>
112-
<h3 className="text-lg font-bold text-primary-blue">Biomedical</h3>
113-
</CardContent>
114-
</Card>
115-
</div>
116-
117-
<div className="text-center mt-16">
118-
<Link to="/about">
119-
<Button variant="outline" className="border-2 border-primary-blue text-primary-blue hover:bg-primary-blue/5">
120-
Learn More About Our Work
121-
</Button>
122-
</Link>
149+
<div className="text-center mt-16">
150+
<Link to="/about">
151+
<Button
152+
variant="outline"
153+
className="border-2 border-primary-blue text-primary-blue hover:bg-primary-blue/5"
154+
>
155+
Learn More About Our Work
156+
</Button>
157+
</Link>
158+
</div>
123159
</div>
124160
</div>
125161
</div>

src/components/HeroSection.tsx

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,120 @@
1-
21
import React, { useEffect, useRef } from "react";
32
import { Link } from "react-router-dom";
43
import { Button } from "@/components/ui/button";
54
import CircuitPattern from "@/components/CircuitPattern";
65

76
const HeroSection = () => {
87
const heroRef = useRef<HTMLDivElement>(null);
8+
const heroTextRef = useRef<HTMLDivElement>(null);
9+
const heroImageRef = useRef<HTMLDivElement>(null);
910

10-
// Add parallax effect to hero elements
11+
// Advanced parallax effect on mouse move and scroll
1112
useEffect(() => {
1213
const handleMouseMove = (e: MouseEvent) => {
1314
if (!heroRef.current) return;
1415

15-
const moveX = (e.clientX - window.innerWidth / 2) * 0.01;
16-
const moveY = (e.clientY - window.innerHeight / 2) * 0.01;
16+
const mouseX = e.clientX;
17+
const mouseY = e.clientY;
1718

18-
const decorativeCircles = heroRef.current.querySelectorAll('.hero-circle');
19-
const teamImage = heroRef.current.querySelector('.team-image');
19+
// Calculate distance from center of screen (in percentage)
20+
const centerX = window.innerWidth / 2;
21+
const centerY = window.innerHeight / 2;
22+
const moveX = (mouseX - centerX) / centerX * 100;
23+
const moveY = (mouseY - centerY) / centerY * 100;
2024

25+
// Apply to decorative elements with varying intensity
26+
const decorativeCircles = heroRef.current.querySelectorAll('.hero-circle');
2127
decorativeCircles.forEach((circle, index) => {
22-
const speed = index === 0 ? 0.04 : 0.02;
28+
const speed = index === 0 ? 0.05 : 0.03;
2329
(circle as HTMLElement).style.transform = `translate(${moveX * speed}px, ${moveY * speed}px)`;
2430
});
2531

26-
if (teamImage) {
27-
(teamImage as HTMLElement).style.transform = `translate(${-moveX * 0.02}px, ${-moveY * 0.02}px)`;
32+
// Apply subtle effect to team image
33+
if (heroImageRef.current) {
34+
heroImageRef.current.style.transform = `translate(${-moveX * 0.03}px, ${-moveY * 0.03}px)`;
35+
}
36+
37+
// Apply even more subtle effect to text for better readability
38+
if (heroTextRef.current) {
39+
heroTextRef.current.style.transform = `translate(${moveX * 0.01}px, ${moveY * 0.01}px)`;
40+
}
41+
};
42+
43+
// Add scroll-based parallax
44+
const handleScroll = () => {
45+
if (!heroRef.current) return;
46+
47+
const scrollY = window.scrollY;
48+
const heroHeight = heroRef.current.offsetHeight;
49+
const scrollProgress = Math.min(1, scrollY / heroHeight);
50+
51+
// Transform decorative elements based on scroll
52+
const decorativeCircles = heroRef.current.querySelectorAll('.hero-circle');
53+
decorativeCircles.forEach((circle, index) => {
54+
const direction = index === 0 ? -1 : 1;
55+
const translateY = scrollProgress * 50 * direction;
56+
const scale = 1 + scrollProgress * 0.1;
57+
const currentElement = circle as HTMLElement;
58+
const currentTransform = currentElement.style.transform;
59+
60+
// Update only the Y transform, keep the mousemove X transform
61+
const newTransform = currentTransform.includes('translate')
62+
? currentTransform.replace(/translate\([^)]+\)/, `translate(${parseFloat(currentTransform.split(',')[0].substring(10))}px, ${translateY}px)`)
63+
: `translate(0px, ${translateY}px)`;
64+
65+
currentElement.style.transform = newTransform + ` scale(${scale})`;
66+
currentElement.style.opacity = `${1 - scrollProgress * 0.5}`;
67+
});
68+
69+
// Create depth effect with scroll
70+
if (heroTextRef.current) {
71+
heroTextRef.current.style.transform = `translateY(${scrollProgress * 70}px)`;
72+
heroTextRef.current.style.opacity = `${1 - scrollProgress * 1.2}`;
73+
}
74+
75+
if (heroImageRef.current) {
76+
heroImageRef.current.style.transform = `translateY(${scrollProgress * 30}px)`;
77+
heroImageRef.current.style.opacity = `${1 - scrollProgress * 1.2}`;
78+
}
79+
80+
// Apply parallax to the circuit background
81+
const circuitBg = heroRef.current.querySelector('.circuit-bg');
82+
if (circuitBg) {
83+
(circuitBg as HTMLElement).style.transform = `translateY(${scrollProgress * 150}px)`;
2884
}
2985
};
3086

3187
window.addEventListener('mousemove', handleMouseMove);
88+
window.addEventListener('scroll', handleScroll);
3289

3390
return () => {
3491
window.removeEventListener('mousemove', handleMouseMove);
92+
window.removeEventListener('scroll', handleScroll);
3593
};
3694
}, []);
3795

3896
return (
39-
<section ref={heroRef} className="relative overflow-hidden pt-24 md:pt-32 pb-16 md:pb-24">
40-
{/* Circuit background */}
41-
<div className="absolute inset-0 z-0" style={{
97+
<section ref={heroRef} className="relative overflow-hidden pt-24 md:pt-32 pb-16 md:pb-24" style={{perspective: "1000px"}}>
98+
{/* Circuit background with parallax */}
99+
<div className="circuit-bg absolute inset-0 z-0" style={{
42100
backgroundImage: `url('/lovable-uploads/b1b3ac59-c3b2-4f3e-99d8-f4241b81e61e.png')`,
43101
backgroundSize: 'cover',
44102
backgroundPosition: 'center',
45-
opacity: 0.05
103+
opacity: 0.05,
104+
willChange: 'transform'
46105
}} />
47106

48107
{/* Static circuit pattern overlay */}
49108
<CircuitPattern />
50109

51-
{/* Large decorative circles with parallax effect */}
52-
<div className="hero-circle absolute left-[10%] top-[-10%] w-[500px] h-[500px] bg-bistre opacity-10 hidden md:block transition-transform duration-500 ease-out" />
53-
<div className="hero-circle absolute right-[-10%] bottom-[-30%] w-[600px] h-[600px] bg-primary-blue/10 hidden md:block transition-transform duration-500 ease-out" />
110+
{/* Large decorative circles with enhanced parallax effect */}
111+
<div className="hero-circle absolute left-[10%] top-[-10%] w-[500px] h-[500px] rounded-full bg-bistre opacity-10 hidden md:block transition-all duration-500 ease-out" style={{willChange: 'transform, opacity'}} />
112+
<div className="hero-circle absolute right-[-10%] bottom-[-30%] w-[600px] h-[600px] rounded-full bg-primary-blue/10 hidden md:block transition-all duration-500 ease-out" style={{willChange: 'transform, opacity'}} />
113+
<div className="hero-circle absolute left-[20%] bottom-[-10%] w-[300px] h-[300px] rounded-full bg-night/5 hidden md:block transition-all duration-500 ease-out" style={{willChange: 'transform, opacity'}} />
54114

55115
<div className="container mx-auto px-4 relative z-10">
56116
<div className="flex flex-col lg:flex-row items-center gap-8 lg:gap-12">
57-
<div className="w-full lg:w-1/2">
117+
<div ref={heroTextRef} className="w-full lg:w-1/2" style={{willChange: 'transform, opacity'}}>
58118
<h1 className="font-bold text-6xl md:text-7xl mb-3 text-primary-blue lg:text-[#333351] text-[#333351]">
59119
Open<span className="text-[#AB9A89] text-[#AB9A89]">Hardware</span>
60120
</h1>
@@ -84,8 +144,8 @@ const HeroSection = () => {
84144
</div>
85145
</div>
86146

87-
{/* Team image with rounded corners and parallax effect */}
88-
<div className="w-full lg:w-1/2 flex justify-center lg:justify-end">
147+
{/* Team image with enhanced parallax effect */}
148+
<div ref={heroImageRef} className="w-full lg:w-1/2 flex justify-center lg:justify-end" style={{willChange: 'transform, opacity'}}>
89149
<div className="team-image relative overflow-hidden rounded-2xl shadow-lg border-4 border-offwhite transition-transform duration-500 ease-out">
90150
<img
91151
src="/lovable-uploads/f96871b8-773a-4f10-a7bf-67c1abe3384c.png"

0 commit comments

Comments
 (0)