LP Hero Video Skill
Guia para incorporar efetivamente vídeos de demonstração de produtos em landing pages e sites.
Padrões Suportados
- Hero Background Video — Vídeo de fundo em tela cheia no topo da página
- Product Demo Section — Vídeo inline em seção de apresentação do produto
- Floating Device Mockup — Vídeo exibido dentro de uma moldura de dispositivo
- Lightbox / Modal Video — Reprodução ampliada ao clicar
Etapa 0: Checklist de Verificação Prévia
Antes de incorporar o vídeo, verifique o seguinte:
Verificação do Material de Vídeo
- O arquivo de vídeo está pronto? (Se não, crie primeiro um placeholder de UI)
- Formato: idealmente dois formatos
.mp4(H.264) +.webm(VP9) - Resolução: recomendado 1920x1080 para Hero, 1280x720 para cards
- Tamanho do arquivo: 5-15MB para Hero, 2-5MB para cards
- Duração: loop de 10 a 30 segundos é ideal para reprodução automática
Como Criar Material de Vídeo (com Screen Studio ou similar)
- Grave o fluxo de operação mais impressionante do produto em 15 a 30 segundos
- Grave com resolução mínima de 1920x1080
- Na exportação, configure:
- MP4 (H.264): Qualidade Médio-Alta, bitrate 4-8 Mbps
- WebM (VP9): Exportação adicional com qualidade equivalente (se a ferramenta suportar)
- Comando de conversão com ffmpeg:
# Otimização MP4 (para web, com faststart)
ffmpeg -i input.mov -c:v libx264 -crf 23 -preset slow \
-movflags +faststart -an -vf scale=1920:-2 output.mp4
# Conversão para WebM
ffmpeg -i input.mov -c:v libvpx-vp9 -crf 30 -b:v 0 \
-an -vf scale=1920:-2 output.webm
# Para card (menor)
ffmpeg -i input.mov -c:v libx264 -crf 26 -preset slow \
-movflags +faststart -an -vf scale=1280:-2 output-card.mp4
Hospedagem
- Local (
/public/videos/): Para sites pequenos, deploys Vercel / Netlify - CDN / Object Storage: Para sites grandes com múltiplos vídeos (Cloudflare R2, AWS S3 + CloudFront)
- YouTube / Vimeo embed: Para SEO e compartilhamento externo
Padrão 1: Hero Background Video
Exibe o vídeo de demonstração do produto em tela cheia no topo da página, com sobreposição de texto.
Componente React
interface HeroVideoProps {
/** Caminho do vídeo MP4 */
videoSrc: string;
/** Caminho do vídeo WebM (opcional) */
videoSrcWebm?: string;
/** Imagem de poster exibida antes do carregamento do vídeo */
posterSrc?: string;
/** Elementos filhos da sobreposição (ex.: título) */
children?: React.ReactNode;
/** Opacidade da sobreposição (0-1, padrão 0.4) */
overlayOpacity?: number;
}
function HeroVideo({
videoSrc,
videoSrcWebm,
posterSrc,
children,
overlayOpacity = 0.4,
}: HeroVideoProps) {
const videoRef = useRef<HTMLVideoElement>(null);
return (
<div className="relative h-screen w-full overflow-hidden bg-black">
{/* Vídeo de Fundo */}
<video
ref={videoRef}
autoPlay
muted
loop
playsInline
poster={posterSrc}
className="absolute inset-0 w-full h-full object-cover"
>
{videoSrcWebm && <source src={videoSrcWebm} type="video/webm" />}
<source src={videoSrc} type="video/mp4" />
</video>
{/* Sobreposição Escura */}
<div
className="absolute inset-0"
style={{ backgroundColor: `rgba(0, 0, 0, ${overlayOpacity})` }}
/>
{/* Gradiente para o fundo da página */}
<div className="absolute inset-x-0 bottom-0 h-32 bg-gradient-to-t from-background to-transparent" />
{/* Conteúdo */}
{children && (
<div className="absolute inset-0 z-10 flex items-end">
<div className="container pb-16 md:pb-24">{children}</div>
</div>
)}
</div>
);
}
Exemplo de Uso
<HeroVideo
videoSrc="/videos/product-demo.mp4"
videoSrcWebm="/videos/product-demo.webm"
posterSrc="/images/hero-poster.jpg"
overlayOpacity={0.35}
>
<h1 className="text-4xl md:text-6xl font-normal text-white tracking-tight">
Reinventando a conversa com tecnologia.
</h1>
</HeroVideo>
Pontos de Aplicação no LP Plural Reality
Substituindo ou coexistindo com o componente LifeGameHero atual:
// Home.tsx - Padrão de substituição
// Opção A: Substituição completa
<HeroVideo videoSrc="/videos/hero-demo.mp4" posterSrc="/images/IMG_5298.jpeg">
<h1 ...>{h.heroTitle}</h1>
</HeroVideo>
// Opção B: Manter LifeGameHero e adicionar seção de vídeo abaixo
<LifeGameHero>...</LifeGameHero>
<Section className="py-0">
<HeroVideo videoSrc="/videos/product-overview.mp4" overlayOpacity={0.2}>
<h2>Apresentação do Produto</h2>
</HeroVideo>
</Section>
Padrão 2: Product Card Video
Em cada card da lista de produtos, reproduz um vídeo de demonstração ao passar o mouse, substituindo a imagem estática.
Componente React
interface ProductCardVideoProps {
videoSrc: string;
posterSrc: string;
alt: string;
className?: string;
}
function ProductCardVideo({
videoSrc,
posterSrc,
alt,
className,
}: ProductCardVideoProps) {
const videoRef = useRef<HTMLVideoElement>(null);
const handleMouseEnter = () => {
videoRef.current?.play();
};
const handleMouseLeave = () => {
const video = videoRef.current;
if (video) {
video.pause();
video.currentTime = 0;
}
};
return (
<div
className={cn("relative aspect-video bg-muted overflow-hidden", className)}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<video
ref={videoRef}
muted
loop
playsInline
poster={posterSrc}
preload="metadata"
className="w-full h-full object-cover"
>
<source src={videoSrc} type="video/mp4" />
</video>
</div>
);
}
Exemplo de Uso (substituir imagem em cards existentes)
// Antes:
<ParallaxImage src="/images/kouchoai.png" alt={t.products.kouchouAI} />
// Depois:
<ProductCardVideo
videoSrc="/videos/kouchou-ai-demo.mp4"
posterSrc="/images/kouchoai.png"
alt={t.products.kouchouAI}
/>
Padrão 3: Device Mockup Video
Exibe o vídeo de demonstração dentro de uma moldura de navegador ou smartphone (aumenta a confiança).
function BrowserMockupVideo({
videoSrc,
posterSrc,
title,
}: {
videoSrc: string;
posterSrc?: string;
title?: string;
}) {
return (
<div className="border border-border bg-background overflow-hidden">
{/* Chrome do navegador */}
<div className="flex items-center gap-2 px-4 py-3 bg-secondary/30 border-b border-border">
<div className="flex gap-1.5">
<div className="w-3 h-3 rounded-full bg-muted-foreground/20" />
<div className="w-3 h-3 rounded-full bg-muted-foreground/20" />
<div className="w-3 h-3 rounded-full bg-muted-foreground/20" />
</div>
{title && (
<div className="flex-1 text-center">
<span className="text-xs text-muted-foreground font-mono">{title}</span>
</div>
)}
</div>
{/* Conteúdo do vídeo */}
<div className="aspect-video">
<video
autoPlay
muted
loop
playsInline
poster={posterSrc}
className="w-full h-full object-cover"
>
<source src={videoSrc} type="video/mp4" />
</video>
</div>
</div>
);
}
Padrão 4: Lightbox Modal Video
Exibe o vídeo em um modal ao clicar na thumbnail. Também suporta incorporação do YouTube.
function VideoLightbox({
thumbnailSrc,
videoSrc,
youtubeId,
alt,
}: {
thumbnailSrc: string;
videoSrc?: string;
youtubeId?: string;
alt: string;
}) {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<button
onClick={() => setIsOpen(true)}
className="relative group cursor-pointer aspect-video w-full overflow-hidden"
>
<img src={thumbnailSrc} alt={alt} className="w-full h-full object-cover" />
{/* Sobreposição do botão de play */}
<div className="absolute inset-0 flex items-center justify-center bg-black/20 group-hover:bg-black/30 transition-colors">
<div className="w-16 h-16 flex items-center justify-center bg-white/90 group-hover:bg-white transition-colors">
<svg className="w-6 h-6 text-foreground ml-1" fill="currentColor" viewBox="0 0 24 24">
<path d="M8 5v14l11-7z" />
</svg>
</div>
</div>
</button>
{/* Modal */}
{isOpen && (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/80"
onClick={() => setIsOpen(false)}
>
<div className="w-full max-w-5xl aspect-video" onClick={(e) => e.stopPropagation()}>
{youtubeId ? (
<iframe
src={`https://www.youtube.com/embed/${youtubeId}?autoplay=1`}
className="w-full h-full"
allow="autoplay; encrypted-media"
allowFullScreen
/>
) : (
<video
src={videoSrc}
autoPlay
controls
className="w-full h-full object-contain bg-black"
/>
)}
</div>
</div>
)}
</>
);
}
Checklist de Implementação
Ao adicionar um vídeo, verifique o seguinte:
Desempenho
- Configurar os 4 atributos
autoPlay muted loop playsInline(obrigatório para compatibilidade com iOS) - Especificar a imagem de poster com o atributo
poster(melhora a experiência durante o carregamento) - Usar
preload="metadata"para reduzir o carregamento inicial de vídeos em cards - Aplicar
-movflags +faststartao arquivo de vídeo (reprodução progressiva) - Fornecer os dois formatos MP4 + WebM com a tag
<source>(compatibilidade entre navegadores)
Responsividade
- Usar
object-coverouobject-containpara ajuste adequado - Considerar exibir uma imagem estática em vez do vídeo em dispositivos móveis
const isMobile = window.innerWidth < 768; // Em mobile, exibir apenas a imagem de poster, não carregar o vídeo
Acessibilidade
- Vídeos com reprodução automática devem sempre ter o atributo
muted(a reprodução de áudio sem interação do usuário é bloqueada) - Respeitar
prefers-reduced-motione, com animações desabilitadas, exibir uma imagem estática como fallback@media (prefers-reduced-motion: reduce) { video { display: none; } .video-poster-fallback { display: block; } }
Design (Conforme Plural Reality)
- Sem bordas arredondadas (
border-radius: 0px) - Borda:
1px solid var(--border) - Sobreposição com gradiente preto (manter monocromático)
- Ícone do botão de play usando
Playdo Lucide React
Convenção de Organização de Arquivos
client/
public/
videos/
hero-demo.mp4 # Vídeo hero (MP4)
hero-demo.webm # Vídeo hero (WebM)
hero-poster.jpg # Imagem de poster do vídeo hero
kouchou-ai-demo.mp4 # Vídeo de demonstração do Kouchou AI
baisoku-survey-demo.mp4 # Vídeo de demonstração do Baisoku Survey
baisoku-kaigi-demo.mp4 # Vídeo de demonstração do Baisoku Kaigi
src/
components/
HeroVideo.tsx # Componente de vídeo hero em tela cheia
ProductCardVideo.tsx # Componente de vídeo em card com reprodução ao passar o mouse
BrowserMockupVideo.tsx # Componente de vídeo com moldura de navegador
VideoLightbox.tsx # Componente de vídeo em modal
Exemplos de Estrutura Comum
LP de SaaS / Produto (Estrutura Recomendada)
Vídeo hero em tela cheia (loop de 15 a 30 segundos, reprodução automática, sem áudio)
↓
Seção de texto (Missão e Valores)
↓
Vídeo em moldura de navegador (demonstração do produto principal)
↓
Cards de produto (reprodução individual de vídeo de demonstração ao passar o mouse)
↓
Estudo de caso / Cases de sucesso
↓
CTA
Site Corporativo (Estrutura Discreta)
Imagem hero + botão de play (abre vídeo em Lightbox ao clicar)
↓
Seção de texto
↓
Cards de produto (imagem estática, vídeo na página de detalhes)
Padrão 5: Mockup de UI de Produto com Animação CSS (Recomendado)
Renderiza a sensação de interação do produto diretamente com animações CSS / SVG / Canvas, sem necessidade de arquivos de vídeo. É a abordagem adotada por Stripe, Linear e Vercel.
Benefícios
- Sem necessidade de arquivos de vídeo (zero bytes adicionais)
- Totalmente responsivo (não quebra em nenhum tamanho de tela)
- Renderização nativa e nítida (sem artefatos de compressão)
- Possibilidade de interatividade (mudanças ao passar o mouse, clicar)
- Suporte automático a modo escuro / modo claro
Pré-requisito: Ativos de Animação Existentes
O LP Plural Reality já possui animações de alta qualidade implementadas em SolutionAnimations.tsx:
| Componente | Descrição | Tecnologia |
|---|---|---|
NetworkOntologyAnimation | Ontologia de 3 camadas (DATA→ONTOLOGY→APPLICATION) | SVG + framer-motion |
DataFlowAnimation | Pipeline de coletar→organizar→conectar | SVG + framer-motion |
ClusterAnimation | Visualização de agrupamento de opiniões | SVG + framer-motion |
ConversationBranchAnimation | Árvore de ramificação de entrevista aprofundada | SVG + framer-motion |
FeedbackLoopAnimation | Ciclo de conversa contínua | SVG + framer-motion |
IntegrationMeshAnimation | Diagrama de integração de plataforma | SVG + framer-motion |
ParticleFieldAnimation | Rede de partículas | Canvas |
IsometricLayersAnimation | Estrutura de camadas em projeção isométrica | SVG + framer-motion |
Além disso, LifeGameHero.tsx possui uma animação em Canvas do globo terrestre → Japão.
Princípios de Design Comuns
- Fundo: preto (#000000), elementos desenhados em branco
- Monocromático (sem cores, ou apenas Brand Teal como destaque)
- Fonte: var(--font-mono) para rótulos técnicos, var(--font-sans) para elementos de UI
- Sem bordas arredondadas: rx={0} / border-radius: 0px
- Animação: framer-motion com useInView + motion.* para acionamento por scroll
- Fundo de grade: padrão de grade de linhas brancas finas (utilitário GridBg)
- Brilho: feDropShadow para brilho sutil (utilitário GlowDef)
Padrão 5A: Moldura de Navegador + UI Animada
Exibe uma UI mock animada dentro de uma moldura de navegador (barra de título + pontos).
function ProductDemoMock({
title,
children,
className,
}: {
title: string;
children: React.ReactNode;
className?: string;
}) {
return (
<div className={cn("border border-border bg-black overflow-hidden", className)}>
{/* Chrome do navegador */}
<div className="flex items-center gap-2 px-4 py-3 bg-[#1c1c1e] border-b border-border">
<div className="flex gap-1.5">
<div className="w-2.5 h-2.5 rounded-full bg-white/10" />
<div className="w-2.5 h-2.5 rounded-full bg-white/10" />
<div className="w-2.5 h-2.5 rounded-full bg-white/10" />
</div>
<div className="flex-1 text-center">
<span className="text-[10px] text-white/40 font-mono">{title}</span>
</div>
</div>
{/* Conteúdo animado */}
<div className="aspect-video relative overflow-hidden">
{children}
</div>
</div>
);
}
Padrão 5B: Animação de Demonstração do Kouchou AI
Fluxo onde dados de texto são inseridos → IA realiza agrupamento → resultado é exibido.
// Design conceitual (para implementação, consultar ClusterAnimation em SolutionAnimations)
function KouchouAIDemoAnimation() {
const [phase, setPhase] = useState<"input" | "processing" | "result">("input");
useEffect(() => {
const timers = [
setTimeout(() => setPhase("processing"), 2000),
setTimeout(() => setPhase("result"), 4000),
];
const loop = setInterval(() => {
setPhase("input");
timers.push(setTimeout(() => setPhase("processing"), 2000));
timers.push(setTimeout(() => setPhase("result"), 4000));
}, 8000);
return () => { timers.forEach(clearTimeout); clearInterval(loop); };
}, []);
return (
<ProductDemoMock title="kouchou-ai.plural-reality.com">
<svg viewBox="0 0 800 450" className="w-full h-full">
{/* Fase 1: Linhas de texto deslizam da esquerda */}
{phase === "input" && (
<g>
{["O transporte é inconveniente e estou enfrentando dificuldades", "Gostaria que o apoio à criação dos filhos fosse ampliado", "Estou preocupado com as medidas de prevenção de desastres"].map((text, i) => (
<motion.g
key={text}
initial={{ opacity: 0, x: -40 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: i * 0.4 }}
>
<rect x={40} y={60 + i * 50} width={350} height={36} fill="white" fillOpacity={0.05} stroke="white" strokeWidth={0.5} />
<text x={56} y={82 + i * 50} fill="white" fontSize={11} fontFamily="var(--font-sans)" opacity={0.8}>
{text}
</text>
</motion.g>
))}
</g>
)}
{/* Fase 2: Partículas se reúnem no centro */}
{phase === "processing" && (
<motion.text x={400} y={225} textAnchor="middle" fill="white" fontSize={12} fontFamily="var(--font-mono)"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
>
Processando...
</motion.text>
)}
{/* Fase 3: Exibição dos resultados do agrupamento */}
{phase === "result" && (
<g>
{["Transporte", "Educação", "Segurança"].map((label, i) => (
<motion.g
key={label}
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{ delay: i * 0.3 }}
>
<circle cx={200 + i * 200} cy={225} r={60} fill="none" stroke="white" strokeWidth={1} strokeDasharray="4 2" />
<text x={200 + i * 200} y={225} textAnchor="middle" fill="white" fontSize={14} fontFamily="var(--font-mono)">
{label}
</text>
</motion.g>
))}
</g>
)}
</svg>
</ProductDemoMock>
);
}
Padrão 6: Animação de Fundo em Grid (Recomendado para Seções de Destaque)
Usar o componente GridBg para criar um fundo animado com grade, que se move sutilmente ao passar o mouse ou em loop, adicionando profundidade sem distrair.
Implementação
// Utilitário GridBg (já existente na base de código)
function GridBg({ className }: { className?: string }) {
return (
<div className={cn("absolute inset-0 overflow-hidden opacity-[0.03]", className)}>
<svg className="w-full h-full" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="white" strokeWidth="0.5" />
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid)" />
</svg>
</div>
);
}
Uso com Padrão 5A
<ProductDemoMock title="painel.plural-reality.com/dashboard">
<GridBg />
<div className="relative z-10 flex items-center justify-center h-full">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8 }}
>
{/* Conteúdo do dashboard */}
</motion.div>
</div>
</ProductDemoMock>
Boas Práticas
Para Vídeos Reais
- Sempre fornecer fallback em texto/imagem: Caso o vídeo não carregue, o usuário ainda deve entender o conteúdo.
- Usar formatos modernos: MP4 (H.264) é obrigatório para compatibilidade máxima; WebM (VP9) oferece melhor compressão.
- Otimizar para mobile: Considere não carregar vídeos automáticos em dispositivos móveis para economizar dados.
- Testar em múltiplos navegadores: Especialmente Safari (iOS) e Chrome.
Para Animações CSS/SVG
- Manter desempenho: Animações complexas podem causar queda de FPS em dispositivos mais lentos. Use
will-changecom moderação. - Garantir acessibilidade: Respeitar
prefers-reduced-motione oferecer alternativa estática. - Reutilizar componentes: Os componentes de animação em
SolutionAnimations.tsxsão modulares e podem ser combinados.
Conclusão
Este skill fornece uma abordagem flexível para incorporar demonstrações de produtos em landing pages, desde vídeos reais até animações CSS/SVG. A escolha entre vídeos e animações depende do contexto:
- Vídeos reais: Melhor para demonstrações complexas ou que exigem movimento contínuo (ex.: uso do software em tempo real).
- Animações CSS/SVG: Ideais para mostrar fluxos de trabalho conceituais, estrutura de dados ou interações simples, com zero custo de largura de banda e total responsividade.
Recomenda-se começar com animações CSS/SVG (Padrão 5) para a maioria dos casos, complementando com vídeos reais quando a demonstração exigir movimento orgânico ou gravação de tela. Ambos os métodos suportam os princípios de design da Plural Reality (monocromático, sem bordas arredondadas, ângulo reto, tipografia mono).