> ## 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.

# Performance de vídeo

> LCP, CLS, lazy loading e Web Vitals em sections React com vídeo — Corvex.

Regras para sections com vídeo rápidas no mobile e desktop. Foco no que **o autor do tema controla** em React.

***

## Princípios

1. **Poster primeiro** — LCP deve ser imagem estática (`poster` / `image`), não o stream.
2. **Nunca carregar todos os vídeos** — grids e carrosséis iniciam reprodução sob demanda.
3. **Um stream ativo** — em carrosséis, reels e grids, só um vídeo tocando por vez.
4. **Reservar espaço** — `aspect-ratio` ou dimensões explícitas (evita CLS).
5. **Destruir ao desmontar** — cleanup no `useEffect` (pause, remover `src`, `load()`).

***

## LCP (Largest Contentful Paint)

| Contexto | Faça |
| - | - |
| Hero com vídeo | `poster` obrigatório + `fetchPriority="high"` na imagem de fallback |
| Hero só vídeo | Poster antes do stream; autoplay `muted` após poster visível |
| Abaixo da dobra | Sem autoplay; poster com `loading="lazy"` |

❌ Hero autoplay sem poster\
❌ Vídeo acima da dobra sem altura reservada

***

## CLS (Cumulative Layout Shift)

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
<section
  className="hero"
  style={{
    aspectRatio: '16 / 9',
    minHeight: 320,
    position: 'relative',
    overflow: 'hidden',
  }}
>
  <CorvexVideo className="hero__video" /* … */ />
</section>
```

* Portrait (Reels): `aspectRatio: '9 / 16'`.
* `objectFit: 'cover'` no vídeo dentro do container com ratio fixo.

***

## Preload

| Cenário | `preload` |
| - | - |
| Grid com 12 cards | `none` — `src` só após clique |
| Hero único | `metadata` |
| Card único PDP | `metadata` ou `none` até play |
| Lista com 20+ itens | **nunca** `auto` em todos |

***

## Lazy loading em React

### Poster

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
<img
  src={poster}
  alt=""
  loading="lazy"
  decoding="async"
  width={400}
  height={711}
/>
```

### Vídeo — play no clique

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
const [src, setSrc] = useState(null);

<button type="button" onClick={() => setSrc(playbackUrl)}>
  Play
</button>
{src ? <video src={src} playsInline muted /> : null}
```

### IntersectionObserver

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
useEffect(() => {
  const el = containerRef.current;
  if (!el) return undefined;

  const observer = new IntersectionObserver(
    ([entry]) => {
      if (!entry.isIntersecting) {
        videoRef.current?.pause();
        return;
      }
      // Opcional: pré-carregar metadata quando visível
    },
    { rootMargin: '100px', threshold: 0.25 }
  );

  observer.observe(el);
  return () => observer.disconnect();
}, []);
```

***

## Carrossel e slider

* Slide ativo: pode reproduzir (muted, loop).
* Slides ocultos: `pause()`, `preload="none"`.
* Na troca: pausar anterior antes de iniciar o próximo.
* **Nunca** autoplay em todos os slides.

### Carrossel com vídeo (HLS)

Sections com **vários** `<video>` da biblioteca (Reels, marquee) exigem regras extras:

1. **Separe** efeito de setup do HLS (`[src]`) do efeito de play/pause (`[shouldPlay]`). Recriar Hls.js a cada mudança de visibilidade causa loop de requisições `seg_*.mp4`.
2. **Marquee com autoplay:** use `playWhenVisible={false}` — a animação CSS torna o `IntersectionObserver` instável.
3. **Um snippet `CorvexVideo`** com `useCorvexVideoPlayback` — não duplique fetch de `/playback` em cada block.
4. Teste na loja publicada, não só no canvas do editor.

Guia completo: [Carrossel de vídeos (Reels)](https://docs-loja.usecorvex.com.br/guides/video-carousel.md).

***

## Autoplay

| Permitido | Evitar |
| - | - |
| Hero above-the-fold, **muted**, **playsInline**, com poster | Autoplay com som |
| Background decorativo muted + loop | Autoplay below-the-fold |
| | Autoplay em cada card de grid |

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
useEffect(() => {
  if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
    videoRef.current?.removeAttribute('autoplay');
    videoRef.current?.pause();
  }
}, []);
```

***

## Mobile

* `playsInline` em todo `<video>`.
* Botões play/mute ≥ 44×44 px.
* Portrait: testar `9:16` e `env(safe-area-inset-bottom)`.
* Conexão lenta: poster primeiro; stream só após gesto.

***

## Checklist performance

* [ ] Poster no hero (LCP)
* [ ] `aspect-ratio` em todo container de vídeo
* [ ] Máximo um vídeo reproduzindo em listas/carrosséis
* [ ] `preload="none"` em grids
* [ ] Stream iniciado no clique ou quando visível
* [ ] Cleanup no `useEffect` return
* [ ] `prefers-reduced-motion` desliga autoplay
* [ ] Testar URL **publicada**, não só preview do editor
* [ ] Carrossel com vídeo: sem loop HLS — [guia](https://docs-loja.usecorvex.com.br/guides/video-carousel.md)

***

## Leitura relacionada

* [Conceitos](https://docs-loja.usecorvex.com.br/guides/video-concepts.md)
* [Padrões](https://docs-loja.usecorvex.com.br/guides/video-patterns.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.