Seção Hero 3D Animada com Vídeo Controlado por Scroll

De Wikiprompt, a enciclopédia livre de prompts

Kashberg
Contribuído porKashbergXFonte

19 de jun. de 2026

Seção Hero 3D Animada com Vídeo Controlado por Scroll Um prompt abrangente para construir uma landing page cinematográfica com vídeo de fundo, scroll-scrubbing, efeitos de desfoque e animações suaves usando React, Tailwind e Framer Motion.

Conteúdo do PromptSalvar

🌐
import { useEffect, useRef, useState } from "react"; import { motion, useScroll, useTransform } from "motion/react"; import Lenis from "lenis"; const VIDEO_URL = "https://t.co/cvkGVS5C0E"; const LiquidVideoCanvas = () => { const videoRef = useRef<HTMLVideoElement>(null); const containerRef = useRef<HTMLDivElement>(null); const [isReady, setIsReady] = useState(false); const isSeeking = useRef(false); const nextSeekTime = useRef<number | null>(null); // Entrance animation state const [entrance, setEntrance] = useState({ scale: 1.12, opacity: 0 }); // Scroll-driven effects const { scrollYProgress } = useScroll(); const blurRef = useRef<HTMLDivElement>(null); // Progressive blur: 0-5px first half, 5-55px second half useEffect(() => { const updateBlur = () => { if (!blurRef.current) return; const progress = scrollYProgress.get(); const blur = progress < 0.5 ? progress * 10 : 5 + (progress - 0.5) * 100; blurRef.current.style.backdropFilter = `blur(${blur}px)`; blurRef.current.style.webkitBackdropFilter = `blur(${blur}px)`; }; const unsubscribe = scrollYProgress.on("change", updateBlur); return () => unsubscribe(); }, [scrollYProgress]); // Video frame seeking with LERP smoothing useEffect(() => { const video = videoRef.current; if (!video) return; let targetTime = 0; let currentTime = 0; let rafId: number; const lerp = (start: number, end: number, factor: number) => { return start + (end - start) * factor; }; const seekToTime = (time: number) => { if (!video) return; const clampedTime = Math.max(0, Math.min(time, video.duration || 0)); if (!isSeeking.current && !video.seeking) { isSeeking.current = true; video.currentTime = clampedTime; } else { nextSeekTime.current = clampedTime; } }; const onSeeked = () => { isSeeking.current = false; if (nextSeekTime.current !== null) { const queuedTime = nextSeekTime.current; nextSeekTime.current = null; seekToTime(queuedTime); } }; const onSeeking = () => { isSeeking.current = true; }; const animate = () => { targetTime = scrollYProgress.get() * (video.duration || 0); currentTime = lerp(currentTime, targetTime, 0.12); if (Math.abs(currentTime - targetTime) > 0.01) { seekToTime(currentTime); } rafId = requestAnimationFrame(animate); }; video.addEventListener("seeked", onSeeked); video.addEventListener("seeking", onSeeking); rafId = requestAnimationFrame(animate); return () => { cancelAnimationFrame(rafId); video.removeEventListener("seeked", onSeeked); video.removeEventListener("seeking", onSeeking); }; }, [scrollYProgress]); // Entrance animation useEffect(() => { const video = videoRef.current; if (!video) return; const checkReady = () => { if (video.readyState >= 3) { setEntrance({ scale: 1, opacity: 1 }); } }; const timeout = setTimeout(() => { setEntrance({ scale: 1, opacity: 1 }); }, 3500); video.addEventListener("loadeddata", checkReady); video.addEventListener("canplay", checkReady); return () => { clearTimeout(timeout); video.removeEventListener("loadeddata", checkReady); video.removeEventListener("canplay", checkReady); }; }, []); return ( <div ref={containerRef} className="fixed inset-0 z-[1] bg-black"> <motion.video ref={videoRef} className="w-full h-full object-cover" loop muted playsInline preload="auto" src={VIDEO_URL} initial={{ scale: 1.12, opacity: 0 }} animate={entrance} transition={{ duration: 1.4, ease: [0.33, 1, 0.68, 1] }} /> </div> ); }; const HeroContent = () => { const { scrollYProgress } = useScroll(); const opacity = useTransform(scrollYProgress, [0, 0.3], [1, 0]); const y = useTransform(scrollYProgress, [0, 0.3], [0, -50]); return ( <motion.div style={{ opacity, y }} className="relative z-10 flex flex-col items-center justify-center min-h-screen text-center px-4" > <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ delay: 0.5, duration: 0.8 }} className="mb-8" > <i className="bi bi-apple text-4xl text-white/80" /> </motion.div> <motion.h1 initial={{ opacity: 0, y: 30 }} animate={{ opacity: 1, y: 0 }} transition={{ delay: 0.7, duration: 0.8 }} className="text-5xl md:text-7xl font-bold tracking-tight mb-6" > SynapseX </motion.h1> <motion.p initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ delay: 0.9, duration: 0.8 }} className="text-lg md:text-xl text-white/70 max-w-2xl mb-12" > Enter the future of neural computing. Where human intuition meets machine intelligence. </motion.p> <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ delay: 1.1, duration: 0.8 }} className="flex gap-4" > <button className="px-8 py-3 bg-white text-black font-bold rounded-full hover:bg-white/90 transition-colors"> Get Started </button> <button className="px-8 py-3 border border-white/30 text-white font-bold rounded-full hover:bg-white/10 transition-colors"> Learn More </button> </motion.div> </motion.div> ); }; const App = () => { const { scrollYProgress } = useScroll(); // Lenis smooth scroll setup useEffect(() => { const lenis = new Lenis({ duration: 1.2, easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), smoothWheel: true, }); const raf = (time: number) => { lenis.raf(time); requestAnimationFrame(raf); }; requestAnimationFrame(raf); return () => { lenis.destroy(); }; }, []); return ( <div className="relative overflow-x-hidden"> <LiquidVideoCanvas /> {/* Progressive blur overlay */} <div ref={useRef<HTMLDivElement>(null)} className="fixed bottom-0 left-0 right-0 h-screen z-30 pointer-events-none" style={{ backdropFilter: "blur(0px)" }} /> {/* Header */} <header className="fixed top-0 left-0 right-0 z-50 flex items-center justify-between px-6 py-4"> <div className="text-xl font-bold">SynapseX</div> <nav className="hidden md:flex gap-8"> <a href="#" className="text-white/70 hover:text-white transition-colors">About</a> <a href="#" className="text-white/70 hover:text-white transition-colors">Technology</a> <a href="#" className="text-white/70 hover:text-white transition-colors">Research</a> <a href="#" className="text-white/70 hover:text-white transition-colors">Contact</a> </nav> </header> <HeroContent /> {/* Scroll indicator */} <motion.div style={{ opacity: useTransform(scrollYProgress, [0, 0.1], [1, 0]) }} className="fixed bottom-8 left-1/2 transform -translate-x-1/2 z-40" > <div className="w-6 h-10 border-2 border-white/30 rounded-full flex justify-center pt-2"> <motion.div animate={{ y: [0, 12, 0] }} transition={{ duration: 1.5, repeat: Infinity }} className="w-1 h-2 bg-white/50 rounded-full" /> </div> </motion.div> </div> ); }; export default App;

Entre para ver o prompt completo

Continuar com:

Ao entrar, você concorda com nossos Termos de uso e Política de privacidade

Uso

Este prompt foi projetado para uso com coding. Copie o conteúdo acima e cole na sua ferramenta de IA preferida.

Para melhores resultados, personalize os marcadores (indicados por colchetes ou maiúsculas) com seus requisitos específicos.

Referências

Categorias:coding| twitter| react| vite

Discussão

0 comentários