Seção Hero 3D Animada com Vídeo Controlado por Scroll
De Wikiprompt, a enciclopédia livre de prompts
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
- Categoria: Prompts de coding
- Fonte: https://x.com/Kashberg_0/status/2067978971741147543
Discussão
0 comentários