139 lines
3.6 KiB
TypeScript
139 lines
3.6 KiB
TypeScript
/**
|
|
* Parallax and Motion Configuration
|
|
* Defines constraints, performance budgets, and accessibility settings
|
|
* for parallax and split-screen hero sections
|
|
*/
|
|
|
|
export const PARALLAX_CONFIG = {
|
|
// Performance budgets
|
|
performance: {
|
|
maxLayers: 3, // Maximum parallax layers to prevent performance issues
|
|
throttleMs: 16, // ~60fps throttling for scroll events
|
|
maxMainThreadTime: 50, // Maximum main thread time per frame (ms)
|
|
lcpTarget: 2500, // LCP target in milliseconds
|
|
},
|
|
|
|
// Parallax depth settings (multipliers for scroll offset)
|
|
depth: {
|
|
background: 0.14, // Background moves slower (creates depth)
|
|
midground: 0.07, // Midground elements
|
|
foreground: -0.03, // Foreground moves slightly faster
|
|
subtle: 0.05, // Very subtle movement for accessibility
|
|
},
|
|
|
|
// Scroll ranges (viewport heights)
|
|
scrollRange: {
|
|
mobile: 1.5, // 1.5 viewport heights on mobile
|
|
desktop: 2.0, // 2 viewport heights on desktop
|
|
},
|
|
|
|
// Breakpoints
|
|
breakpoints: {
|
|
mobile: 768, // Below this is mobile
|
|
tablet: 1024, // Tablet range
|
|
desktop: 1024, // Desktop and above
|
|
},
|
|
|
|
// Reduced motion settings
|
|
reducedMotion: {
|
|
disableParallax: true, // Completely disable parallax
|
|
useSubtleMotion: false, // Use very subtle motion instead
|
|
fallbackTransition: 'opacity 0.3s ease', // Simple fade transitions
|
|
},
|
|
|
|
// Layer configuration
|
|
layers: {
|
|
hero: {
|
|
background: {
|
|
depth: 0.14,
|
|
zIndex: 1,
|
|
transform: 'translateY(var(--parallax-bg))',
|
|
},
|
|
midground: {
|
|
depth: 0.07,
|
|
zIndex: 2,
|
|
transform: 'translateY(var(--parallax-mid))',
|
|
},
|
|
foreground: {
|
|
depth: -0.03,
|
|
zIndex: 3,
|
|
transform: 'translateY(var(--parallax-fg))',
|
|
},
|
|
},
|
|
splitScreen: {
|
|
leftPanel: {
|
|
depth: 0.04,
|
|
zIndex: 2,
|
|
transform: 'translateY(var(--parallax-left))',
|
|
},
|
|
rightPanel: {
|
|
depth: -0.04,
|
|
zIndex: 2,
|
|
transform: 'translateY(var(--parallax-right))',
|
|
},
|
|
},
|
|
},
|
|
} as const
|
|
|
|
/**
|
|
* CSS Custom Properties for parallax transforms
|
|
* These will be updated via JavaScript for smooth animations
|
|
*/
|
|
export const PARALLAX_CSS_VARS = {
|
|
'--parallax-bg': '0px',
|
|
'--parallax-mid': '0px',
|
|
'--parallax-fg': '0px',
|
|
'--parallax-left': '0px',
|
|
'--parallax-right': '0px',
|
|
} as const
|
|
|
|
/**
|
|
* Media query for reduced motion preference
|
|
*/
|
|
export const REDUCED_MOTION_QUERY = '(prefers-reduced-motion: reduce)'
|
|
|
|
/**
|
|
* Utility to check if reduced motion is preferred
|
|
*/
|
|
export function prefersReducedMotion(): boolean {
|
|
if (typeof window === 'undefined') return false
|
|
return window.matchMedia(REDUCED_MOTION_QUERY).matches
|
|
}
|
|
|
|
/**
|
|
* Utility to get appropriate parallax depth based on motion preference
|
|
*/
|
|
export function getParallaxDepth(baseDepth: number): number {
|
|
if (prefersReducedMotion()) {
|
|
return PARALLAX_CONFIG.reducedMotion.disableParallax ? 0 : baseDepth * 0.1
|
|
}
|
|
return baseDepth
|
|
}
|
|
|
|
/**
|
|
* Utility to check if device is mobile
|
|
*/
|
|
export function isMobile(): boolean {
|
|
if (typeof window === 'undefined') return false
|
|
return window.innerWidth < PARALLAX_CONFIG.breakpoints.mobile
|
|
}
|
|
|
|
/**
|
|
* Performance monitoring utilities
|
|
*/
|
|
export const PerformanceMonitor = {
|
|
startTime: 0,
|
|
|
|
start() {
|
|
this.startTime = performance.now()
|
|
},
|
|
|
|
end(operation: string) {
|
|
const duration = performance.now() - this.startTime
|
|
if (duration > PARALLAX_CONFIG.performance.maxMainThreadTime) {
|
|
console.warn(`Parallax operation "${operation}" took ${duration.toFixed(2)}ms (exceeds ${PARALLAX_CONFIG.performance.maxMainThreadTime}ms budget)`)
|
|
}
|
|
return duration
|
|
},
|
|
}
|