Communitygithub.com

LP Hero Video

Habilita a incorporação de vídeos de demonstração de produtos em landing pages, com animações CSS, vídeos hero, vídeos em cards e modais.

O que é LP Hero Video?

Este skill fornece um guia completo para desenvolvedores implementarem vídeos de demonstração de produtos em landing pages e sites, com suporte para React e Next.js. Ele cobre cinco padrões principais: Hero Background Video (vídeo em tela cheia), Product Card Video (reprodução ao passar o mouse), Device Mockup Video (vídeo dentro de moldura de dispositivo), Lightbox Modal Video (vídeo em modal ao clicar) e CSS Animation Mockups (animações sem arquivos de vídeo). O skill é útil para criar experiências imersivas e profissionais, melhorando a conversão e o engajamento do usuário. Ele inclui componentes React prontos para uso, diretrizes de desempenho (como formatos MP4/WebM, compressão com ffmpeg, atributos essenciais como autoPlay, muted, loop, playsInline), práticas de acessibilidade (como prefers-reduced-motion) e uma convenção de organização de arquivos. Além disso, oferece alternativas sem vídeo usando CSS, SVG e framer-motion, inspiradas em empresas como Stripe e Linear, e inclui um checklist de implementação para garantir desempenho, responsividade e acessibilidade.

Funciona com~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/yuidvg/skills/tree/HEAD/skills/lp-hero-video

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

LP Hero Video Skill

Guia para incorporar efetivamente vídeos de demonstração de produtos em landing pages e sites.

Padrões Suportados

  1. Hero Background Video — Vídeo de fundo em tela cheia no topo da página
  2. Product Demo Section — Vídeo inline em seção de apresentação do produto
  3. Floating Device Mockup — Vídeo exibido dentro de uma moldura de dispositivo
  4. 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)

  1. Grave o fluxo de operação mais impressionante do produto em 15 a 30 segundos
  2. Grave com resolução mínima de 1920x1080
  3. 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)
  4. 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 +faststart ao arquivo de vídeo (reprodução progressiva)
  • Fornecer os dois formatos MP4 + WebM com a tag <source> (compatibilidade entre navegadores)

Responsividade

  • Usar object-cover ou object-contain para 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-motion e, 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 Play do 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:

ComponenteDescriçãoTecnologia
NetworkOntologyAnimationOntologia de 3 camadas (DATA→ONTOLOGY→APPLICATION)SVG + framer-motion
DataFlowAnimationPipeline de coletar→organizar→conectarSVG + framer-motion
ClusterAnimationVisualização de agrupamento de opiniõesSVG + framer-motion
ConversationBranchAnimationÁrvore de ramificação de entrevista aprofundadaSVG + framer-motion
FeedbackLoopAnimationCiclo de conversa contínuaSVG + framer-motion
IntegrationMeshAnimationDiagrama de integração de plataformaSVG + framer-motion
ParticleFieldAnimationRede de partículasCanvas
IsometricLayersAnimationEstrutura de camadas em projeção isométricaSVG + 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

  1. Sempre fornecer fallback em texto/imagem: Caso o vídeo não carregue, o usuário ainda deve entender o conteúdo.
  2. Usar formatos modernos: MP4 (H.264) é obrigatório para compatibilidade máxima; WebM (VP9) oferece melhor compressão.
  3. Otimizar para mobile: Considere não carregar vídeos automáticos em dispositivos móveis para economizar dados.
  4. Testar em múltiplos navegadores: Especialmente Safari (iOS) e Chrome.

Para Animações CSS/SVG

  1. Manter desempenho: Animações complexas podem causar queda de FPS em dispositivos mais lentos. Use will-change com moderação.
  2. Garantir acessibilidade: Respeitar prefers-reduced-motion e oferecer alternativa estática.
  3. Reutilizar componentes: Os componentes de animação em SolutionAnimations.tsx sã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).

Habilidades Relacionadas