forked from hazem/yslootahrobotics
feat: add responsive overlay styles and enhance ScrollOverlays component
This commit is contained in:
parent
83d0d9ab00
commit
a955da7ec8
@ -363,3 +363,144 @@ html {
|
|||||||
max-height: 100dvh !important;
|
max-height: 100dvh !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===== Scroll Overlay Responsive ===== */
|
||||||
|
|
||||||
|
/* Overlay glass panels (side sections) */
|
||||||
|
.overlay-panel {
|
||||||
|
max-width: 450px;
|
||||||
|
padding: 2.5rem;
|
||||||
|
border-radius: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Overlay section positioning */
|
||||||
|
.overlay-section-left {
|
||||||
|
left: clamp(2rem, 6vw, 6rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-section-right {
|
||||||
|
right: clamp(2rem, 6vw, 6rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-heading {
|
||||||
|
font-size: clamp(2rem, 3.5vw, 3rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-hero-heading {
|
||||||
|
font-size: clamp(2.5rem, 5vw, 4.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-stat {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tablet */
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.overlay-panel {
|
||||||
|
max-width: 380px;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.overlay-section-left,
|
||||||
|
.overlay-section-right {
|
||||||
|
left: 50% !important;
|
||||||
|
right: auto !important;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 90vw;
|
||||||
|
max-width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-section-left {
|
||||||
|
top: auto !important;
|
||||||
|
bottom: 6vh !important;
|
||||||
|
align-items: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-section-right {
|
||||||
|
top: auto !important;
|
||||||
|
bottom: 6vh !important;
|
||||||
|
align-items: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-panel {
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 1.5rem;
|
||||||
|
border-radius: 1.25rem;
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-panel > div {
|
||||||
|
align-items: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-hero-heading {
|
||||||
|
font-size: clamp(1.8rem, 8vw, 2.8rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-heading {
|
||||||
|
font-size: clamp(1.5rem, 6vw, 2rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-stat {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-brand {
|
||||||
|
top: 8vh !important;
|
||||||
|
bottom: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-brand .overlay-panel,
|
||||||
|
.overlay-brand span,
|
||||||
|
.overlay-brand p {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-scroll-hint {
|
||||||
|
bottom: 1.5rem !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small phones */
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.overlay-section-left,
|
||||||
|
.overlay-section-right {
|
||||||
|
width: 92vw;
|
||||||
|
bottom: 4vh !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-panel {
|
||||||
|
padding: 1.25rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-hero-heading {
|
||||||
|
font-size: clamp(1.5rem, 7vw, 2.2rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-heading {
|
||||||
|
font-size: clamp(1.3rem, 5.5vw, 1.8rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-stat {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Very small phones */
|
||||||
|
@media (max-width: 375px) {
|
||||||
|
.overlay-panel {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-hero-heading {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-heading {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ interface SectionProps {
|
|||||||
align: 'center' | 'left' | 'right';
|
align: 'center' | 'left' | 'right';
|
||||||
verticalAlign?: 'top' | 'center' | 'bottom';
|
verticalAlign?: 'top' | 'center' | 'bottom';
|
||||||
offsetY?: number;
|
offsetY?: number;
|
||||||
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function OverlaySection({
|
function OverlaySection({
|
||||||
@ -23,6 +24,7 @@ function OverlaySection({
|
|||||||
align,
|
align,
|
||||||
verticalAlign = 'center',
|
verticalAlign = 'center',
|
||||||
offsetY = 50,
|
offsetY = 50,
|
||||||
|
className = '',
|
||||||
}: SectionProps) {
|
}: SectionProps) {
|
||||||
// Define a wide "plateau" zone where the text is fully readable and static.
|
// 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.
|
// We use 30% of the travel distance for fading in, 30% for fading out.
|
||||||
@ -57,17 +59,24 @@ function OverlaySection({
|
|||||||
|
|
||||||
const alignStyle: React.CSSProperties =
|
const alignStyle: React.CSSProperties =
|
||||||
align === 'left'
|
align === 'left'
|
||||||
? { left: 'clamp(2rem, 6vw, 6rem)', alignItems: 'flex-start' }
|
? { alignItems: 'flex-start' }
|
||||||
: align === 'right'
|
: align === 'right'
|
||||||
? { right: 'clamp(2rem, 6vw, 6rem)', alignItems: 'flex-end' }
|
? { alignItems: 'flex-end' }
|
||||||
: { left: '50%', x: '-50%', alignItems: 'center' };
|
: { left: '50%', alignItems: 'center' };
|
||||||
|
|
||||||
|
const alignClass =
|
||||||
|
align === 'left'
|
||||||
|
? 'overlay-section-left'
|
||||||
|
: align === 'right'
|
||||||
|
? 'overlay-section-right'
|
||||||
|
: '';
|
||||||
|
|
||||||
const verticalStyle: React.CSSProperties =
|
const verticalStyle: React.CSSProperties =
|
||||||
verticalAlign === 'top'
|
verticalAlign === 'top'
|
||||||
? { top: '15vh' }
|
? { top: '15vh' }
|
||||||
: verticalAlign === 'bottom'
|
: verticalAlign === 'bottom'
|
||||||
? { bottom: '15vh', top: 'auto' }
|
? { bottom: '15vh', top: 'auto' }
|
||||||
: { top: '50%', y: '-50%' };
|
: { top: '50%' };
|
||||||
|
|
||||||
// Glass panel appearance for side text to not clash with the robot
|
// Glass panel appearance for side text to not clash with the robot
|
||||||
const isCenter = align === 'center';
|
const isCenter = align === 'center';
|
||||||
@ -77,16 +86,14 @@ function OverlaySection({
|
|||||||
background: 'rgba(255, 255, 255, 0.92)',
|
background: 'rgba(255, 255, 255, 0.92)',
|
||||||
backdropFilter: 'blur(20px)',
|
backdropFilter: 'blur(20px)',
|
||||||
WebkitBackdropFilter: 'blur(20px)',
|
WebkitBackdropFilter: 'blur(20px)',
|
||||||
padding: '2.5rem',
|
|
||||||
borderRadius: '1.5rem',
|
|
||||||
boxShadow: '0 8px 32px rgba(0, 0, 0, 0.08)',
|
boxShadow: '0 8px 32px rgba(0, 0, 0, 0.08)',
|
||||||
border: '1px solid rgba(255, 255, 255, 0.6)',
|
border: '1px solid rgba(255, 255, 255, 0.6)',
|
||||||
textAlign: align === 'left' ? 'left' : 'right',
|
textAlign: align === 'left' ? 'left' : 'right',
|
||||||
maxWidth: '450px',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
|
className={`${alignClass} ${className}`.trim()}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -104,7 +111,7 @@ function OverlaySection({
|
|||||||
scale,
|
scale,
|
||||||
...panelStyle,
|
...panelStyle,
|
||||||
}}
|
}}
|
||||||
className="will-change-transform"
|
className={`will-change-transform ${isCenter ? '' : 'overlay-panel'}`}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</motion.div>
|
</motion.div>
|
||||||
@ -135,7 +142,7 @@ export function ScrollOverlays() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* 1. Brand Intro */}
|
{/* 1. Brand Intro */}
|
||||||
<OverlaySection progress={scrollYProgress} {...SECTION_CONFIGS[0]}>
|
<OverlaySection progress={scrollYProgress} {...SECTION_CONFIGS[0]} className="overlay-brand">
|
||||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '1rem', marginBottom: '1rem' }}>
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '1rem', marginBottom: '1rem' }}>
|
||||||
<div style={{ width: '30px', height: '1px', background: 'linear-gradient(90deg, transparent, #c4a265)' }} />
|
<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' }}>
|
<span style={{ fontSize: '0.75rem', fontWeight: 600, color: '#c4a265', letterSpacing: '0.4em', textTransform: 'uppercase' }}>
|
||||||
@ -150,10 +157,10 @@ export function ScrollOverlays() {
|
|||||||
|
|
||||||
{/* 2. Hero */}
|
{/* 2. Hero */}
|
||||||
<OverlaySection progress={scrollYProgress} {...SECTION_CONFIGS[1]}>
|
<OverlaySection progress={scrollYProgress} {...SECTION_CONFIGS[1]}>
|
||||||
<motion.h1 style={{ fontSize: 'clamp(2.5rem, 5vw, 4.5rem)', fontWeight: 200, color: '#1a1a2e', lineHeight: 1.0, letterSpacing: '-0.04em', margin: 0 }}>
|
<motion.h1 className="overlay-hero-heading" style={{ fontWeight: 200, color: '#1a1a2e', lineHeight: 1.0, letterSpacing: '-0.04em', margin: 0 }}>
|
||||||
The Future
|
The Future
|
||||||
</motion.h1>
|
</motion.h1>
|
||||||
<motion.h1 style={{ fontSize: 'clamp(2.5rem, 5vw, 4.5rem)', fontWeight: 200, color: '#1a1a2e', lineHeight: 1.0, letterSpacing: '-0.04em', margin: '0.1em 0 0' }}>
|
<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>
|
of <span style={{ color: '#c4a265', fontWeight: 400 }}>Robotics</span>
|
||||||
</motion.h1>
|
</motion.h1>
|
||||||
<p style={{ fontSize: '1rem', color: '#475569', lineHeight: 1.7, margin: '1.5rem 0 0', fontWeight: 300 }}>
|
<p style={{ fontSize: '1rem', color: '#475569', lineHeight: 1.7, margin: '1.5rem 0 0', fontWeight: 300 }}>
|
||||||
@ -168,7 +175,7 @@ export function ScrollOverlays() {
|
|||||||
<div style={{ fontSize: '0.65rem', fontWeight: 600, color: '#c4a265', letterSpacing: '0.3em', textTransform: 'uppercase', marginBottom: '1rem' }}>
|
<div style={{ fontSize: '0.65rem', fontWeight: 600, color: '#c4a265', letterSpacing: '0.3em', textTransform: 'uppercase', marginBottom: '1rem' }}>
|
||||||
Intelligent by Design
|
Intelligent by Design
|
||||||
</div>
|
</div>
|
||||||
<h2 style={{ fontSize: 'clamp(2rem, 3.5vw, 3rem)', fontWeight: 300, color: '#1a1a2e', lineHeight: 1.1, margin: '0 0 1rem', letterSpacing: '-0.03em' }}>
|
<h2 className="overlay-heading" style={{ fontWeight: 300, color: '#1a1a2e', lineHeight: 1.1, margin: '0 0 1rem', letterSpacing: '-0.03em' }}>
|
||||||
Vision That<br />Understands
|
Vision That<br />Understands
|
||||||
</h2>
|
</h2>
|
||||||
<p style={{ fontSize: '0.95rem', color: '#475569', lineHeight: 1.6, margin: 0, fontWeight: 300 }}>
|
<p style={{ fontSize: '0.95rem', color: '#475569', lineHeight: 1.6, margin: 0, fontWeight: 300 }}>
|
||||||
@ -176,11 +183,11 @@ export function ScrollOverlays() {
|
|||||||
</p>
|
</p>
|
||||||
<div style={{ display: 'flex', gap: '2.5rem', marginTop: '2rem' }}>
|
<div style={{ display: 'flex', gap: '2.5rem', marginTop: '2rem' }}>
|
||||||
<div style={{ textAlign: 'center' }}>
|
<div style={{ textAlign: 'center' }}>
|
||||||
<div style={{ fontSize: '1.8rem', fontWeight: 300, color: '#1a1a2e', fontFamily: 'monospace' }}>360°</div>
|
<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 style={{ fontSize: '0.65rem', color: '#64748b', letterSpacing: '0.15em', textTransform: 'uppercase', marginTop: '0.5rem' }}>Field of View</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ textAlign: 'center' }}>
|
<div style={{ textAlign: 'center' }}>
|
||||||
<div style={{ fontSize: '1.8rem', fontWeight: 300, color: '#1a1a2e', fontFamily: 'monospace' }}>{'<'}50ms</div>
|
<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 style={{ fontSize: '0.65rem', color: '#64748b', letterSpacing: '0.15em', textTransform: 'uppercase', marginTop: '0.5rem' }}>Response Time</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -193,7 +200,7 @@ export function ScrollOverlays() {
|
|||||||
<div style={{ fontSize: '0.65rem', fontWeight: 600, color: '#c4a265', letterSpacing: '0.3em', textTransform: 'uppercase', marginBottom: '1rem' }}>
|
<div style={{ fontSize: '0.65rem', fontWeight: 600, color: '#c4a265', letterSpacing: '0.3em', textTransform: 'uppercase', marginBottom: '1rem' }}>
|
||||||
Your Identity
|
Your Identity
|
||||||
</div>
|
</div>
|
||||||
<h2 style={{ fontSize: 'clamp(2rem, 3.5vw, 3rem)', fontWeight: 300, color: '#1a1a2e', lineHeight: 1.1, margin: '0 0 1rem', letterSpacing: '-0.03em' }}>
|
<h2 className="overlay-heading" style={{ fontWeight: 300, color: '#1a1a2e', lineHeight: 1.1, margin: '0 0 1rem', letterSpacing: '-0.03em' }}>
|
||||||
Dress for Any<br />Mission
|
Dress for Any<br />Mission
|
||||||
</h2>
|
</h2>
|
||||||
<p style={{ fontSize: '0.95rem', color: '#475569', lineHeight: 1.6, margin: 0, fontWeight: 300 }}>
|
<p style={{ fontSize: '0.95rem', color: '#475569', lineHeight: 1.6, margin: 0, fontWeight: 300 }}>
|
||||||
@ -227,7 +234,7 @@ export function ScrollOverlays() {
|
|||||||
<div style={{ fontSize: '0.65rem', fontWeight: 600, color: '#c4a265', letterSpacing: '0.3em', textTransform: 'uppercase', marginBottom: '1rem' }}>
|
<div style={{ fontSize: '0.65rem', fontWeight: 600, color: '#c4a265', letterSpacing: '0.3em', textTransform: 'uppercase', marginBottom: '1rem' }}>
|
||||||
Advanced Mobility
|
Advanced Mobility
|
||||||
</div>
|
</div>
|
||||||
<h2 style={{ fontSize: 'clamp(2rem, 3.5vw, 3rem)', fontWeight: 300, color: '#1a1a2e', lineHeight: 1.1, margin: '0 0 1rem', letterSpacing: '-0.03em' }}>
|
<h2 className="overlay-heading" style={{ fontWeight: 300, color: '#1a1a2e', lineHeight: 1.1, margin: '0 0 1rem', letterSpacing: '-0.03em' }}>
|
||||||
23 Degrees of<br />Freedom
|
23 Degrees of<br />Freedom
|
||||||
</h2>
|
</h2>
|
||||||
<p style={{ fontSize: '0.95rem', color: '#475569', lineHeight: 1.6, margin: 0, fontWeight: 300 }}>
|
<p style={{ fontSize: '0.95rem', color: '#475569', lineHeight: 1.6, margin: 0, fontWeight: 300 }}>
|
||||||
@ -235,11 +242,11 @@ export function ScrollOverlays() {
|
|||||||
</p>
|
</p>
|
||||||
<div style={{ display: 'flex', gap: '2.5rem', marginTop: '2rem' }}>
|
<div style={{ display: 'flex', gap: '2.5rem', marginTop: '2rem' }}>
|
||||||
<div style={{ textAlign: 'center' }}>
|
<div style={{ textAlign: 'center' }}>
|
||||||
<div style={{ fontSize: '1.8rem', fontWeight: 300, color: '#1a1a2e', fontFamily: 'monospace' }}>2m/s</div>
|
<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 style={{ fontSize: '0.65rem', color: '#64748b', letterSpacing: '0.15em', textTransform: 'uppercase', marginTop: '0.5rem' }}>Max Speed</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ textAlign: 'center' }}>
|
<div style={{ textAlign: 'center' }}>
|
||||||
<div style={{ fontSize: '1.8rem', fontWeight: 300, color: '#1a1a2e', fontFamily: 'monospace' }}>127kg</div>
|
<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 style={{ fontSize: '0.65rem', color: '#64748b', letterSpacing: '0.15em', textTransform: 'uppercase', marginTop: '0.5rem' }}>Payload</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -248,6 +255,7 @@ export function ScrollOverlays() {
|
|||||||
|
|
||||||
{/* Scroll indicator mapped to vanish rapidly when scrolled */}
|
{/* Scroll indicator mapped to vanish rapidly when scrolled */}
|
||||||
<motion.div
|
<motion.div
|
||||||
|
className="overlay-scroll-hint"
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
bottom: '2.5rem',
|
bottom: '2.5rem',
|
||||||
|
|||||||
@ -60,8 +60,9 @@ function lerpScalar(a: number, b: number, t: number): number {
|
|||||||
const scrollState = { progress: 0, inScrollZone: true };
|
const scrollState = { progress: 0, inScrollZone: true };
|
||||||
|
|
||||||
function ScrollCamera() {
|
function ScrollCamera() {
|
||||||
const { camera } = useThree();
|
const { camera, size } = useThree();
|
||||||
const lookAtTarget = useRef(new THREE.Vector3(0, 0.5, 0));
|
const lookAtTarget = useRef(new THREE.Vector3(0, 0.5, 0));
|
||||||
|
const isMobile = size.width < 768;
|
||||||
|
|
||||||
useFrame(({ clock }) => {
|
useFrame(({ clock }) => {
|
||||||
if (!scrollState.inScrollZone) return;
|
if (!scrollState.inScrollZone) return;
|
||||||
@ -70,6 +71,10 @@ function ScrollCamera() {
|
|||||||
const pos = interpolateKeyframes(CAMERA_KEYFRAMES, p);
|
const pos = interpolateKeyframes(CAMERA_KEYFRAMES, p);
|
||||||
const lookAt = interpolateKeyframes(LOOKAT_KEYFRAMES, p);
|
const lookAt = interpolateKeyframes(LOOKAT_KEYFRAMES, p);
|
||||||
|
|
||||||
|
// On mobile, pull camera back and center it more so robot doesn't overlap text
|
||||||
|
const mobileZOffset = isMobile ? 2.5 : 0;
|
||||||
|
const mobileCenterX = isMobile ? pos.x * 0.3 : 0;
|
||||||
|
|
||||||
// Dynamic camera oscillation based on scroll position
|
// Dynamic camera oscillation based on scroll position
|
||||||
const oscillationX = Math.sin(p * Math.PI * 4) * 0.05;
|
const oscillationX = Math.sin(p * Math.PI * 4) * 0.05;
|
||||||
const oscillationY = Math.cos(p * Math.PI * 3) * 0.025;
|
const oscillationY = Math.cos(p * Math.PI * 3) * 0.025;
|
||||||
@ -80,9 +85,9 @@ function ScrollCamera() {
|
|||||||
|
|
||||||
// Apply oscillations to position
|
// Apply oscillations to position
|
||||||
const adjustedPos = new THREE.Vector3(
|
const adjustedPos = new THREE.Vector3(
|
||||||
pos.x + oscillationX + driftZone,
|
pos.x - mobileCenterX + oscillationX + driftZone,
|
||||||
pos.y + oscillationY + verticalDrift,
|
pos.y + oscillationY + verticalDrift,
|
||||||
pos.z
|
pos.z + mobileZOffset
|
||||||
);
|
);
|
||||||
|
|
||||||
// Adaptive lerp for smooth camera transitions
|
// Adaptive lerp for smooth camera transitions
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user