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

# Carrossel de vídeos (Reels)

> Como implementar sections com vários vídeos da biblioteca — Embla, marquee, CorvexVideo e HLS sem loop de requisições.

Guia normativo para sections com **vários cards de vídeo** (formato Reels 9:16), blocks `video-reel`, carrossel Embla e faixa **marquee** com autoplay.

Use este documento quando for criar ou revisar uma section como `video-carousel`. Ele evita os problemas mais comuns que **não aparecem no editor** ou só estouram na **vitrine publicada**.

> [!WARNING]
>
> Carrossel de vídeo ≠ slideshow de imagens. Cada card pode abrir um stream HLS da biblioteca de vídeos da loja. Trate **playback**, **concorrência** e **ciclo de vida do player** como requisitos de arquitetura — não como detalhe de CSS.

***

## Arquitetura recomendada

```
sections/video-carousel/
  section.jsx      ← layout, Embla/marquee, SectionBlockCanvas no editor
  schema.json
  blocks.json
  styles.css

blocks/video-reel/
  block.jsx        ← um card; classe __slide no wrapper do block
  schema.json      ← campo type: "video" (videoId)

snippets/corvex-video/
  snippet.jsx      ← único lugar que resolve UUID + HLS

lib/
  videoCarouselPlaybackContext.js   ← opcional; ver marquee abaixo
```

| Peça | Responsabilidade |
| - | - |
| **Block** | Um card (poster, legenda, `CorvexVideo`) |
| **Section** | Track, Embla, marquee, contagem de slides |
| **Snippet `CorvexVideo`** | Classificar valor, resolver playback, HLS, play/pause |
| **Theme SDK** | `useCorvexVideoPlayback`, `classifyVideoValue` |

**Nunca** resolva UUID ou monte HLS dentro da section ou do block — centralize no snippet.

### Integração `@corvex/runtime`

**Padrão B** — sections que montam cards a partir de `settings` **sem** `{children}` no track (marquee de vídeos). Se cada block é um card React visível, use **Padrão A** (`{children}` no editor).

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

const { liveItems } = useSectionLiveBlocks();
```

* **`useSectionLiveBlocks()`** — [Padrão B](https://docs-loja.usecorvex.com.br/reference/runtime-api.md#padrão-b-—-blocks-lidos-sem-children-marquee-/-faixa) — ordem ao vivo + settings mesclados.
* Grid com `block.jsx` por depoimento/slide → **`{children}`** no canvas — [Padrão A](https://docs-loja.usecorvex.com.br/reference/runtime-api.md#grid-de-depoimentos-canônico).

Boas práticas: [Runtime API](https://docs-loja.usecorvex.com.br/reference/runtime-api.md).

***

## 1. Resolver playback (biblioteca)

### Use o Theme SDK

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

const kind = classifyVideoValue(videoId);
const { playbackUrl, thumbnail, loading } = useCorvexVideoPlayback(videoId);
const src = kind === 'url' ? videoId : kind === 'library' ? playbackUrl : null;
```

O hook resolve o UUID. Se a resposta de playback vier sem URL e com miniatura da biblioteca de vídeos da loja, o SDK monta o manifesto HLS a partir dessa miniatura.

### ❌ Errado

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
// UUID não é URL — o browser não reproduz
<video src={settings.videoId} autoPlay muted />

// Ler só manifest da API e ignorar resposta parcial
const url = response.video.manifest; // null em prod → hero vazio
```

### ✅ Correto

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
<CorvexVideo
  value={settings.videoId}
  poster={settings.poster}
  autoplay
  muted
  loop
  controls={false}
/>
```

Até `playbackUrl` existir, mostre **poster** (`thumbnail` do hook ou `image` do block). Nunca deixe o card vazio.

***

## 2. Ciclo de vida do HLS — evite loop de requisições

O bug mais grave em carrosséis: **destruir e recriar o HLS** sempre que `shouldPlay` ou visibilidade mudam. Isso gera centenas de requisições pendentes (`init.mp4`, `seg_2.mp4`, …) no Network.

### Regra de ouro

| Efeito React | Dependências | O que faz |
| - | - | - |
| **Setup do stream** | `[src]` (e `kind` se precisar) | `hls.loadSource(src)` **uma vez** por URL |
| **Play / pause** | `[shouldPlay, muted]` | `video.play()` / `video.pause()` — **sem** `hls.destroy()` |
| **Visibilidade** | Observer com **debounce** | Só altera play/pause, não o source |

### ❌ Errado — um único `useEffect` com `shouldPlay` no array

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
useEffect(() => {
  cleanupHls();
  if (!src) return;
  const hls = new Hls();
  hls.loadSource(src);
  // ...
}, [src, shouldPlay]); // ← shouldPlay recria HLS a cada frame do marquee
```

### ✅ Correto — efeitos separados

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
// 1) Anexar source — só quando a URL muda
useEffect(() => {
  let hls;
  if (!src) {
    video.pause();
    video.removeAttribute('src');
    return () => hls?.destroy();
  }
  if (isHlsUrl(src) && Hls.isSupported()) {
    hls = new Hls({ maxBufferLength: 12 });
    hls.attachMedia(video);
    hls.on(Hls.Events.MEDIA_ATTACHED, () => hls.loadSource(src));
    return () => hls.destroy();
  }
  video.src = src;
  return () => { video.removeAttribute('src'); };
}, [src]);

// 2) Play/pause — sem tocar no HLS
useEffect(() => {
  if (shouldPlay) void video.play().catch(() => {});
  else video.pause();
}, [shouldPlay, muted]);
```

### Outras regras do snippet

* **Não** use `video.src = manifest.m3u8` como fallback após erro fatal do HLS (Chrome não reproduz HLS nativo assim — só gera mais falhas).
* Prefira `hls.recoverMediaError()` uma vez em erros de mídia.
* `preload="metadata"` em listas; evite `preload="auto"` em todos os cards.
* Debounce do `IntersectionObserver` (\~150–200 ms) se usar `playWhenVisible`.

***

## 3. Marquee + vários cards clonados

Faixas marquee **duplicam** os mesmos cards para preencher o trilho (`expandReelsForMarquee`). Um carrossel com 2 vídeos únicos pode virar **8+ instâncias** de `<video>` + HLS.

### Problemas típicos

| Sintoma | Causa |
| - | - |
| 500–1000+ requests `seg_*.mp4` pendentes | HLS recriado a cada toggle de visibilidade |
| Vídeo pisca na vitrine | `playWhenVisible` + animação CSS do marquee |
| Editor OK, loja quebrada | Tema publicado sem `corvex build` + sync; vitrine em deploy separado do editor |
| Playback sem URL e com thumbnail | Use `useCorvexVideoPlayback`. Não leia só `manifest` |

### Marquee: desligue `playWhenVisible`

Com autoplay na faixa, **não** use `IntersectionObserver` — os cards estão sempre em movimento e o observer fica instável.

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
// section.jsx — modo marquee
<VideoReelCard playWhenVisible={false} /* … */ />

// Ou contexto para blocks da section:
<VideoCarouselPlaybackContext.Provider value={{ playWhenVisible: false }}>
  <section className="dm-video-carousel dm-video-carousel--marquee">…</section>
</VideoCarouselPlaybackContext.Provider>
```

No block:

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
const { playWhenVisible: fromSection } = useVideoCarouselPlayback();
const resolved = playWhenVisible && fromSection;
```

### Limite de streams simultâneos

* **Marquee com autoplay:** aceite que vários vídeos tocam muted ao mesmo tempo — mantenha **buffer baixo** no Hls.js e **não** recrie players.
* **Carrossel Embla (um slide visível):** pause slides inativos; só o ativo reproduz.
* **Grid / muitos cards:** play no clique — um stream ativo por vez.

***

## 4. Section + blocks

Siga [Runtime API — Padrão B](https://docs-loja.usecorvex.com.br/reference/runtime-api.md#padrão-b-—-blocks-lidos-sem-children-marquee-/-faixa) quando o JSX monta cards a partir de `useSectionLiveBlocks()` — **não** quando cada block é um componente visual (nesse caso use Padrão A + `{children}` no editor).

1. **Vitrine:** monte cards a partir de `liveItems` / `block_order`.
2. **Classe de slide** no block (`dm-video-carousel__slide`).
3. **`useSectionBlockCount()`** se usar `{children}` — não `Children.count(children)`.
4. **`useSectionLiveBlocks()`** — ordem ao vivo alinhada ao painel Itens (marquee/faixa).

CSS:

```css theme={"theme":{"light":"github-light","dark":"github-dark"}}
.dm-video-carousel__track { display: flex; gap: var(--vc-card-gap); }
.dm-video-carousel__track > .cx-block,
.dm-video-carousel__slide { flex: 0 0 auto; width: var(--vc-card-width-mobile); }
```

***

## 5. Editor vs vitrine publicada

| Ambiente | Onde roda | Implicação |
| - | - | - |
| Editor | Canvas do tema | O preview não substitui a loja publicada |
| Loja publicada | Depois de **Publicar** no editor | `corvex sync` atualiza o código do tema; a vitrine usa a revisão publicada |
| Playback | Hook do Theme SDK | Não chame a rota de playback no block |

Checklist de deploy:

1. `corvex build` no tema
2. `corvex sync` (código do tema na loja)
3. **Publicar** no editor
4. Hard refresh na loja publicada

Teste sempre na **URL publicada**, não só no preview do editor.

***

## 6. Checklist — carrossel de vídeos

### Snippet `CorvexVideo`

* [ ] Usa `useCorvexVideoPlayback` (ou `resolveStoreVideoPlayback`) para UUID
* [ ] Poster enquanto `playbackUrl` é `null` ou `loading`
* [ ] HLS: setup em efeito **só com `[src]`**
* [ ] Play/pause em efeito **separado** (`shouldPlay`)
* [ ] `playsInline`, `muted` para autoplay
* [ ] Cleanup: `hls.destroy()`, `pause()`, `removeAttribute('src')` no unmount
* [ ] `prefers-reduced-motion` desliga autoplay

### Section `video-carousel`

* [ ] Blocks com `type: "video"` no schema
* [ ] `children` montados **uma vez** no track (sem duplicar marquee + canvas)
* [ ] Marquee: `playWhenVisible={false}` nos cards
* [ ] Embla: pause em slides inativos
* [ ] `corvex validate` + `corvex build` antes do sync

### Vitrine

* [ ] Publicou após sync do tema
* [ ] Uma resolução por UUID (o SDK guarda o resultado em cache)
* [ ] Network: **não** centenas de `seg_*.mp4` pendentes
* [ ] Funciona em mobile (playsInline)

***

## Leitura relacionada

* [Biblioteca de vídeos](https://docs-loja.usecorvex.com.br/guides/video-library.md)
* [Padrões — CorvexVideo](https://docs-loja.usecorvex.com.br/guides/video-patterns.md)
* [Performance de vídeo](https://docs-loja.usecorvex.com.br/guides/video-performance.md)
* [Libs de terceiros — carrossel](https://docs-loja.usecorvex.com.br/guides/third-party-libraries.md)
* [Pitfalls — vídeo](https://docs-loja.usecorvex.com.br/data/pitfalls.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.