yslootahrobotics/src/components/ScrollOverlays.tsx

321 lines
13 KiB
TypeScript

'use client';
import { useScroll, useTransform, motion } from 'framer-motion';
import { ReactNode } from 'react';
import Link from 'next/link';
interface SectionProps {
children: ReactNode;
progress: any;
startAt: number;
peakAt: number;
endAt: number;
align: 'center' | 'left' | 'right';
verticalAlign?: 'top' | 'center' | 'bottom';
offsetY?: number;
className?: string;
}
function OverlaySection({
children,
progress,
startAt,
peakAt,
endAt,
align,
verticalAlign = 'center',
offsetY = 50,
className = '',
}: SectionProps) {
// Define a wide "plateau" zone where the text is fully readable and static.
// We use 30% of the travel distance for fading in, 30% for fading out.
const diffIn = peakAt - startAt;
const diffOut = endAt - peakAt;
const inStart = startAt;
const inEnd = startAt + diffIn * 0.4; // Fades in quickly
const outStart = endAt - diffOut * 0.6; // Holds for a long time
const outEnd = endAt;
// Smooth fade in and out mapping over a lengthy plateau
const opacity = useTransform(
progress,
[inStart, inEnd, outStart, outEnd],
[0, 1, 1, 0]
);
// Translate Y to slide in, pause entirely while reading, slide out
const y = useTransform(
progress,
[inStart, inEnd, outStart, outEnd],
[offsetY, 0, 0, -offsetY]
);
// Scale stays at 1.0 during reading mode
const scale = useTransform(
progress,
[inStart, inEnd, outStart, outEnd],
[0.95, 1, 1, 1.05]
);
const alignStyle: React.CSSProperties =
align === 'left'
? { alignItems: 'flex-start' }
: align === 'right'
? { alignItems: 'flex-end' }
: { left: '50%', transform: 'translateX(-50%)', alignItems: 'center' };
const alignClass =
align === 'left'
? 'overlay-section-left'
: align === 'right'
? 'overlay-section-right'
: 'overlay-section-center';
const verticalStyle: React.CSSProperties =
verticalAlign === 'top'
? { top: '15vh' }
: verticalAlign === 'bottom'
? { bottom: '15vh', top: 'auto' }
: { top: '50%' };
// Glass panel appearance for side text to not clash with the robot
const isCenter = align === 'center';
const panelStyle: React.CSSProperties = isCenter
? { textAlign: 'center' }
: {
background: 'rgba(255, 255, 255, 0.92)',
backdropFilter: 'blur(20px)',
WebkitBackdropFilter: 'blur(20px)',
boxShadow: '0 8px 32px rgba(0, 0, 0, 0.08)',
border: '1px solid rgba(255, 255, 255, 0.6)',
textAlign: align === 'left' ? 'left' : 'right',
};
return (
<motion.div
className={`${alignClass} ${className}`.trim()}
style={{
position: 'absolute',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
opacity,
pointerEvents: 'none',
...verticalStyle,
...alignStyle,
}}
>
<motion.div
style={{
y,
scale,
...panelStyle,
}}
className={`will-change-transform ${isCenter ? '' : 'overlay-panel'}`}
>
{children}
</motion.div>
</motion.div>
);
}
// Section timing definitions to match ScrollScene camera moves
const SECTION_CONFIGS = [
{ id: 'brand', startAt: 0, peakAt: 0.05, endAt: 0.15, align: 'center' as const, verticalAlign: 'top' as const },
{ id: 'hero', startAt: 0.10, peakAt: 0.22, endAt: 0.35, align: 'left' as const, verticalAlign: 'center' as const },
{ id: 'headReveal', startAt: 0.35, peakAt: 0.46, endAt: 0.53, align: 'right' as const, verticalAlign: 'center' as const },
{ id: 'customization', startAt: 0.55, peakAt: 0.66, endAt: 0.77, align: 'left' as const, verticalAlign: 'center' as const },
{ id: 'mobility', startAt: 0.75, peakAt: 0.82, endAt: 0.90, align: 'right' as const, verticalAlign: 'center' as const },
];
export function ScrollOverlays() {
const { scrollYProgress } = useScroll();
return (
<div
style={{
position: 'fixed',
inset: 0,
zIndex: 10,
pointerEvents: 'none',
overflow: 'hidden',
}}
>
{/* 1. Brand Intro */}
<OverlaySection progress={scrollYProgress} {...SECTION_CONFIGS[0]} className="overlay-brand">
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '1rem', marginBottom: '1rem' }}>
<div style={{ width: '30px', height: '1px', background: 'linear-gradient(90deg, transparent, #c4a265)' }} />
<span style={{ fontSize: '0.75rem', fontWeight: 600, color: '#c4a265', letterSpacing: '0.4em', textTransform: 'uppercase' }}>
YS Lootah Robotics
</span>
<div style={{ width: '30px', height: '1px', background: 'linear-gradient(90deg, #c4a265, transparent)' }} />
</div>
<p style={{ fontSize: '0.9rem', color: '#64748b', fontWeight: 400, letterSpacing: '0.15em', margin: 0 }}>
Pioneering Humanoid Robotics in the UAE
</p>
</OverlaySection>
{/* 2. Hero */}
<OverlaySection progress={scrollYProgress} {...SECTION_CONFIGS[1]}>
<motion.h1 className="overlay-hero-heading" style={{ fontWeight: 200, color: '#1a1a2e', lineHeight: 1.0, letterSpacing: '-0.04em', margin: 0 }}>
The Future
</motion.h1>
<motion.h1 className="overlay-hero-heading" style={{ fontWeight: 200, color: '#1a1a2e', lineHeight: 1.0, letterSpacing: '-0.04em', margin: '0.1em 0 0' }}>
of <span style={{ color: '#c4a265', fontWeight: 400 }}>Robotics</span>
</motion.h1>
<p style={{ fontSize: '1rem', color: '#475569', lineHeight: 1.7, margin: '1.5rem 0 0', fontWeight: 300 }}>
Meet the G1 Humanoid Robot. Fully customizable, enterprise-ready, designed for the world of tomorrow.
</p>
</OverlaySection>
{/* 3. Head Reveal */}
<OverlaySection progress={scrollYProgress} {...SECTION_CONFIGS[2]}>
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
<div style={{ width: '50px', height: '2px', background: '#c4a265', marginBottom: '1.5rem' }} />
<div style={{ fontSize: '0.65rem', fontWeight: 600, color: '#c4a265', letterSpacing: '0.3em', textTransform: 'uppercase', marginBottom: '1rem' }}>
Intelligent by Design
</div>
<h2 className="overlay-heading" style={{ fontWeight: 300, color: '#1a1a2e', lineHeight: 1.1, margin: '0 0 1rem', letterSpacing: '-0.03em' }}>
Vision That<br />Understands
</h2>
<p style={{ fontSize: '0.95rem', color: '#475569', lineHeight: 1.6, margin: 0, fontWeight: 300 }}>
Advanced computer vision and neural processing. The G1 sees, interprets, and responds to the world in real-time.
</p>
<div style={{ display: 'flex', gap: '2.5rem', marginTop: '2rem' }}>
<div style={{ textAlign: 'center' }}>
<div className="overlay-stat" style={{ fontWeight: 300, color: '#1a1a2e', fontFamily: 'monospace' }}>360°</div>
<div style={{ fontSize: '0.65rem', color: '#64748b', letterSpacing: '0.15em', textTransform: 'uppercase', marginTop: '0.5rem' }}>Field of View</div>
</div>
<div style={{ textAlign: 'center' }}>
<div className="overlay-stat" style={{ fontWeight: 300, color: '#1a1a2e', fontFamily: 'monospace' }}>{'<'}50ms</div>
<div style={{ fontSize: '0.65rem', color: '#64748b', letterSpacing: '0.15em', textTransform: 'uppercase', marginTop: '0.5rem' }}>Response Time</div>
</div>
</div>
</div>
</OverlaySection>
{/* 4. Customization */}
<OverlaySection progress={scrollYProgress} {...SECTION_CONFIGS[3]}>
<div style={{ width: '50px', height: '2px', background: '#c4a265', marginBottom: '1.5rem' }} />
<div style={{ fontSize: '0.65rem', fontWeight: 600, color: '#c4a265', letterSpacing: '0.3em', textTransform: 'uppercase', marginBottom: '1rem' }}>
Your Identity
</div>
<h2 className="overlay-heading" style={{ fontWeight: 300, color: '#1a1a2e', lineHeight: 1.1, margin: '0 0 1rem', letterSpacing: '-0.03em' }}>
Dress for Any<br />Mission
</h2>
<p style={{ fontSize: '0.95rem', color: '#475569', lineHeight: 1.6, margin: 0, fontWeight: 300 }}>
From traditional Emarati Kandura to industrial safety gear and professional business attire. Configure every detail to match your brand.
</p>
<div style={{ display: 'flex', gap: '1rem', marginTop: '2rem' }}>
{['Kandura', 'Vest', 'Suit'].map((label) => (
<div
key={label}
style={{
padding: '0.5rem 1rem',
borderRadius: '2rem',
background: 'rgba(196, 162, 101, 0.1)',
border: '1px solid rgba(196, 162, 101, 0.3)',
fontSize: '0.75rem',
color: '#c4a265',
letterSpacing: '0.1em',
fontWeight: 500
}}
>
{label}
</div>
))}
</div>
</OverlaySection>
{/* 5. Mobility */}
<OverlaySection progress={scrollYProgress} {...SECTION_CONFIGS[4]}>
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
<div style={{ width: '50px', height: '2px', background: '#c4a265', marginBottom: '1.5rem' }} />
<div style={{ fontSize: '0.65rem', fontWeight: 600, color: '#c4a265', letterSpacing: '0.3em', textTransform: 'uppercase', marginBottom: '1rem' }}>
Advanced Mobility
</div>
<h2 className="overlay-heading" style={{ fontWeight: 300, color: '#1a1a2e', lineHeight: 1.1, margin: '0 0 1rem', letterSpacing: '-0.03em' }}>
23 Degrees of<br />Freedom
</h2>
<p style={{ fontSize: '0.95rem', color: '#475569', lineHeight: 1.6, margin: 0, fontWeight: 300 }}>
State-of-the-art locomotion enabling natural human-like movement, balance, and agility across any terrain.
</p>
<div style={{ display: 'flex', gap: '2.5rem', marginTop: '2rem' }}>
<div style={{ textAlign: 'center' }}>
<div className="overlay-stat" style={{ fontWeight: 300, color: '#1a1a2e', fontFamily: 'monospace' }}>2m/s</div>
<div style={{ fontSize: '0.65rem', color: '#64748b', letterSpacing: '0.15em', textTransform: 'uppercase', marginTop: '0.5rem' }}>Max Speed</div>
</div>
<div style={{ textAlign: 'center' }}>
<div className="overlay-stat" style={{ fontWeight: 300, color: '#1a1a2e', fontFamily: 'monospace' }}>127kg</div>
<div style={{ fontSize: '0.65rem', color: '#64748b', letterSpacing: '0.15em', textTransform: 'uppercase', marginTop: '0.5rem' }}>Payload</div>
</div>
</div>
</div>
</OverlaySection>
{/* Configure CTA — appears at the very end of scroll */}
<OverlaySection
progress={scrollYProgress}
startAt={0.90}
peakAt={0.95}
endAt={1.0}
align="center"
verticalAlign="center"
className="overlay-cta-section"
>
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '0.75rem', pointerEvents: 'auto' }}>
<Link
href="/configure/"
className="overlay-cta-btn"
style={{
display: 'inline-flex',
alignItems: 'center',
gap: '0.75rem',
padding: '1rem 2.5rem',
borderRadius: '3rem',
background: 'linear-gradient(135deg, #c4a265, #d4b47a)',
color: '#ffffff',
fontSize: '0.95rem',
fontWeight: 600,
letterSpacing: '0.1em',
textTransform: 'uppercase',
textDecoration: 'none',
boxShadow: '0 8px 32px rgba(196, 162, 101, 0.3)',
transition: 'all 0.3s ease',
}}
>
Configure Your G1
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="5" y1="12" x2="19" y2="12" /><polyline points="12 5 19 12 12 19" />
</svg>
</Link>
<span style={{ fontSize: '0.7rem', color: '#94a3b8', letterSpacing: '0.15em', textTransform: 'uppercase' }}>
Build &amp; Order Your Robot
</span>
</div>
</OverlaySection>
{/* Scroll indicator mapped to vanish rapidly when scrolled */}
<motion.div
className="overlay-scroll-hint"
style={{
position: 'absolute',
bottom: '2.5rem',
left: '50%',
x: '-50%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
opacity: useTransform(scrollYProgress, [0, 0.05], [1, 0]),
}}
>
<span style={{ fontSize: '0.65rem', fontWeight: 500, color: '#64748b', letterSpacing: '0.3em', textTransform: 'uppercase', marginBottom: '1rem' }}>
Scroll to Explore
</span>
<div className="scroll-indicator" />
</motion.div>
</div>
);
}