> ## Documentation Index
> Fetch the complete documentation index at: https://docs-loja.usecorvex.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Padrões de vídeo

> Exemplos React — hero, Reels, grid, carrossel, background e snippet CorvexVideo reutilizável.

Catálogo de implementações para temas Corvex React. Todos usam `type: "video"` + classificação do valor. Ver [Schema](https://docs-loja.usecorvex.com.br/guides/video-schema.md).

***

## Snippet reutilizável — `CorvexVideo`

> [!NOTE]
>
> Use o **Theme SDK**: `useCorvexVideoPlayback` e `classifyVideoValue` de `@corvex/theme-sdk`. Não implemente fetch manual de playback no block. Centralize no snippet.
>
> Sections com **vários vídeos** (carrossel Reels, marquee): leia [Carrossel de vídeos](https://docs-loja.usecorvex.com.br/guides/video-carousel.md) antes de implementar — erros de ciclo de vida do HLS só aparecem na vitrine publicada.

Crie `snippets/corvex-video/snippet.jsx` no seu tema:

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { useEffect, useRef } from 'react';
import { useCorvexVideoPlayback } from '@corvex/theme-sdk';

function toEmbedSrc(url) {
  const yt = url.match(/(?:youtu\.be\/|youtube\.com\/(?:watch\?v=|embed\/))([\w-]+)/i);
  if (yt) return `https://www.youtube.com/embed/${yt[1]}?playsinline=1`;
  const vimeo = url.match(/vimeo\.com\/(\d+)/i);
  if (vimeo) return `https://player.vimeo.com/video/${vimeo[1]}`;
  return null;
}

export default function CorvexVideo({
  value,
  poster,
  autoplay = false,
  muted = true,
  loop = false,
  controls = true,
  preload = 'metadata',
  className = '',
  ariaLabel,
}) {
  const videoRef = useRef(null);
  const { kind, playbackUrl, thumbnail } = useCorvexVideoPlayback(value);
  const posterUrl = poster || thumbnail || undefined;

  useEffect(() => {
    const video = videoRef.current;
    if (!video) return undefined;

    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
      video.removeAttribute('autoplay');
      video.pause();
    }

    return () => {
      video.pause();
      video.removeAttribute('src');
      video.load();
    };
  }, []);

  if (kind === 'empty') return null;

  if (kind === 'embed') {
    const embedSrc = toEmbedSrc(value);
    if (!embedSrc) return posterUrl ? <img src={posterUrl} alt="" className={className} /> : null;
    return (
      <iframe
        src={embedSrc}
        className={className}
        title={ariaLabel || 'Vídeo'}
        allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
        allowFullScreen
        style={{ border: 0, width: '100%', height: '100%' }}
      />
    );
  }

  const src =
    kind === 'url' ? value : kind === 'library' ? playbackUrl : null;

  if (!src) {
    return posterUrl ? (
      <img
        src={posterUrl}
        alt={ariaLabel || ''}
        className={className}
        style={{ width: '100%', height: '100%', objectFit: 'cover' }}
      />
    ) : null;
  }

  return (
    <video
      ref={videoRef}
      className={className}
      src={src}
      poster={posterUrl}
      autoPlay={autoplay}
      muted={muted}
      loop={loop}
      controls={controls}
      playsInline
      preload={preload}
      aria-label={ariaLabel || undefined}
      style={{ width: '100%', height: '100%', objectFit: 'cover' }}
    />
  );
}
```

Importe no tema:

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import CorvexVideo from '@corvex/snippets/corvex-video';
```

***

## Hero Video

**`sections/hero-video/schema.json`** (trecho):

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "name": "Hero com vídeo",
  "category": "Banner",
  "settings": [
    {
      "id": "mediaMode",
      "type": "select",
      "label": "Tipo de mídia",
      "options": [
        { "value": "image", "label": "Imagem" },
        { "value": "video", "label": "Vídeo" }
      ],
      "default": "image"
    },
    { "id": "heroImage", "type": "image", "label": "Imagem" },
    { "id": "heroPoster", "type": "image", "label": "Poster do vídeo" },
    { "id": "heroVideo", "type": "video", "label": "Vídeo" },
    { "id": "videoAutoplay", "type": "checkbox", "label": "Autoplay", "default": true },
    { "id": "videoLoop", "type": "checkbox", "label": "Loop", "default": true },
    { "id": "showOverlay", "type": "checkbox", "label": "Overlay escuro", "default": true },
    { "id": "title", "type": "text", "label": "Título", "default": "Bem-vindo" },
    { "id": "buttonLabel", "type": "text", "label": "Botão", "default": "Comprar agora" },
    { "id": "buttonUrl", "type": "url", "label": "Link do botão" }
  ]
}
```

**`section.jsx`** (trecho):

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import CorvexVideo from '@corvex/snippets/corvex-video';

export default function HeroVideoSection({ settings = {} }) {
  const showVideo = settings.mediaMode === 'video' && settings.heroVideo;

  return (
    <section
      className={`hero-video${settings.showOverlay ? ' hero-video--overlay' : ''}`}
      style={{ position: 'relative', minHeight: 560, aspectRatio: '16 / 9' }}
    >
      <div className="hero-video__media" style={{ position: 'absolute', inset: 0 }}>
        {showVideo ? (
          <CorvexVideo
            value={settings.heroVideo}
            poster={settings.heroPoster || settings.heroImage}
            autoplay={settings.videoAutoplay}
            muted
            loop={settings.videoLoop}
            controls={false}
            ariaLabel={settings.title}
          />
        ) : settings.heroImage ? (
          <img
            src={settings.heroImage}
            alt={settings.title ?? ''}
            fetchPriority="high"
            style={{ width: '100%', height: '100%', objectFit: 'cover' }}
          />
        ) : null}
      </div>

      <div className="hero-video__content" style={{ position: 'relative', zIndex: 1 }}>
        <h1>{settings.title}</h1>
        {settings.buttonLabel ? (
          <a href={settings.buttonUrl || '#'}>{settings.buttonLabel}</a>
        ) : null}
      </div>
    </section>
  );
}
```

***

## Background Video

Vídeo decorativo — sem controles, sempre muted.

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
<CorvexVideo
  value={settings.bgVideo}
  poster={settings.bgPoster}
  autoplay
  muted
  loop
  controls={false}
  preload="metadata"
  className="bg-video__layer"
/>
```

***

## Video Card Reels (9:16)

**Block `reel`** — play no clique, um vídeo ativo por vez:

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import CorvexVideo from '@corvex/snippets/corvex-video';

export default function ReelBlock({ settings = {} }) {
  return (
    <article className="reel-card" style={{ aspectRatio: '9 / 16' }}>
      <CorvexVideo
        value={settings.videoId}
        poster={settings.poster}
        autoplay={false}
        muted
        loop
        controls
        preload="none"
      />
      {settings.caption ? <p>{settings.caption}</p> : null}
    </article>
  );
}
```

Na section pai, pause outros cards ao iniciar um (estado local ou context).

***

## Carrossel com vídeo

Pausar vídeos em slides inativos:

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
useEffect(() => {
  slides.forEach((slide, index) => {
    const video = slide.querySelector('video');
    if (!video) return;
    if (index === activeIndex) {
      if (!video.src && video.dataset.src) video.src = video.dataset.src;
      video.muted = true;
      video.play().catch(() => {});
    } else {
      video.pause();
    }
  });
}, [activeIndex, slides]);
```

Use `preload="none"` e `data-src` em vez de `src` até o slide ficar ativo.

***

## Carrossel de vídeos (Reels / marquee)

Vários cards com `type: "video"` + autoplay exigem o guia dedicado:

* [Carrossel de vídeos (Reels)](https://docs-loja.usecorvex.com.br/guides/video-carousel.md) — arquitetura, HLS, marquee, checklist de deploy

Resumo:

1. Snippet `CorvexVideo` com `useCorvexVideoPlayback`
2. HLS: efeito separado para `src` vs `shouldPlay`
3. Marquee: `playWhenVisible={false}`
4. `corvex build`, depois `corvex sync`, depois **Publicar** no editor

***

## Índice rápido

| Padrão | Uso | Autoplay |
| - | - | - |
| Hero | Home, landing | Sim (muted) |
| [Background](#background-video) | Decorativo | Sim (muted) |
| [Reels](#video-card-reels-9:16) | Stories, social | No clique |
| Carrossel | Slideshow | Só slide ativo |
| Reels / marquee | Vários vídeos da biblioteca | Ver o guia de carrossel |

***

## Leitura relacionada

* [Schema](https://docs-loja.usecorvex.com.br/guides/video-schema.md)
* [Performance](https://docs-loja.usecorvex.com.br/guides/video-performance.md)
* [Carrossel de vídeos](https://docs-loja.usecorvex.com.br/guides/video-carousel.md)
* [Cookbook — Hero](https://docs-loja.usecorvex.com.br/cookbook/video-hero.md)
* [FAQ](https://docs-loja.usecorvex.com.br/guides/video-faq.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.