'use client' import { useEffect, useRef, useState } from 'react' import { useTranslations } from 'next-intl' const TOTAL_FRAMES = 298 const FRAME_PATH = (n: number) => `/frames/ezgif-frame-${String(n).padStart(3, '0')}.jpg` export default function CloudRevealSection() { const t = useTranslations('hero') const sectionRef = useRef(null) const canvasRef = useRef(null) const textRef = useRef(null) const framesRef = useRef([]) const currentFrameRef = useRef(0) const rafRef = useRef(null) const [loaded, setLoaded] = useState(false) const [loadProgress, setLoadProgress] = useState(0) // Frame'leri sıralı preload et useEffect(() => { const images: HTMLImageElement[] = new Array(TOTAL_FRAMES) let loadedCount = 0 for (let i = 0; i < TOTAL_FRAMES; i++) { const img = new Image() img.src = FRAME_PATH(i + 1) img.onload = () => { loadedCount++ setLoadProgress(Math.round((loadedCount / TOTAL_FRAMES) * 100)) if (loadedCount === TOTAL_FRAMES) { framesRef.current = images setLoaded(true) // İlk frame'i hemen çiz drawFrame(0, images) } } images[i] = img } }, []) function drawFrame(index: number, images?: HTMLImageElement[]) { const canvas = canvasRef.current if (!canvas) return const ctx = canvas.getContext('2d') if (!ctx) return const imgs = images || framesRef.current const img = imgs[index] if (!img || !img.complete || img.naturalWidth === 0) return ctx.drawImage(img, 0, 0, canvas.width, canvas.height) } // Scroll handler useEffect(() => { if (!loaded) return const section = sectionRef.current const text = textRef.current if (!section || !text) return const handleScroll = () => { const rect = section.getBoundingClientRect() const sectionHeight = section.offsetHeight const windowH = window.innerHeight const scrolled = -rect.top const total = sectionHeight - windowH const progress = Math.min(Math.max(scrolled / total, 0), 1) // Hangi frame'i göstereceğimizi hesapla const frameIndex = Math.min( Math.floor(progress * (TOTAL_FRAMES - 1)), TOTAL_FRAMES - 1 ) // Sadece frame değiştiyse çiz (RAF ile) if (frameIndex !== currentFrameRef.current) { currentFrameRef.current = frameIndex if (rafRef.current) cancelAnimationFrame(rafRef.current) rafRef.current = requestAnimationFrame(() => drawFrame(frameIndex)) } // Tagline: ilk %15'te görünür, sonra solar if (progress < 0.15) { const opacity = 1 - progress / 0.15 text.style.opacity = String(opacity) text.style.transform = `translateY(${progress * 40}px)` } else { text.style.opacity = '0' } } window.addEventListener('scroll', handleScroll, { passive: true }) return () => { window.removeEventListener('scroll', handleScroll) if (rafRef.current) cancelAnimationFrame(rafRef.current) } }, [loaded]) // Canvas boyutunu ekrana sığdır useEffect(() => { const canvas = canvasRef.current if (!canvas) return const resize = () => { canvas.width = window.innerWidth canvas.height = window.innerHeight // Resize sonrası mevcut frame'i yeniden çiz drawFrame(currentFrameRef.current) } resize() window.addEventListener('resize', resize) return () => window.removeEventListener('resize', resize) }, [loaded]) return (
{/* Canvas — frame'ler buraya çizilir */} {/* Loading ekranı */} {!loaded && (

{loadProgress}%

)} {/* Tagline */}

Vesta Muğla

{t('tagline')}

{t('subtitle')}

{/* Scroll indicator */} {loaded && (
{t('scroll')}
)}
) }