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

# Práticas recomendadas

> Desempenho e segurança do Facebetter Web SDK 2.0

<Note>
  SDK **2.0.0**. Autenticação: [Autenticação e licença](/pt-BR/intro/license).
</Note>

## Autenticação em produção

Mantenha `app_id` / `app_key` no servidor. Busque um `licenseToken` de curta duração **no seu** backend e, em seguida, passe-o para o mecanismo.

```javascript theme={null}
const licenseToken = await fetch('/api/facebetter/auth', { method: 'POST' }).then((r) => r.text());
const engine = new BeautyEffectEngine(new EngineConfig({ licenseToken }));
```

<Warning>
  Nunca coloque `appKey` em um bundle de frontend.
</Warning>

Vincule o domínio exato de produção no Console. A Web não pode usar `.lic` offline.

## Um mecanismo por página

Crie **um** `BeautyEffectEngine`, chame `init()` uma vez e reutilize-o durante a sessão. Não construa um mecanismo novo a cada quadro.

```javascript theme={null}
useEffect(() => {
  let engine;
  (async () => {
    engine = new BeautyEffectEngine(new EngineConfig({ licenseToken }));
    await engine.init();
    engineRef.current = engine;
  })();
  return () => {
    engineRef.current?.destroy();
    engineRef.current = null;
  };
}, []);
```

## Loop de quadros

* Dirija o vídeo com `requestAnimationFrame`, não um `while` sem limite.
* Use `FrameType.Video` para a câmera; `FrameType.Image` para stills.
* Combine o tamanho do canvas com o `ImageData` processado para evitar scaling extra.
* Pule quadros até `video.readyState >= 2` e `videoWidth > 0`.
* Prefira `processImage` para câmera e canvas. `processTexture` não aplica espelhamento.

```javascript theme={null}
const result = engine.processImage(
  video,
  video.videoWidth,
  video.videoHeight,
  FrameType.Video,
  MirrorMode.Horizontal,
);
ctx.putImageData(result, 0, 0);
```

<h2 id="large-stills">
  Stills grandes (prévia e exportação)
</h2>

Em galeria ou retoque, não envie pixels em resolução total para `processImage` a cada movimento do slider. Ao abrir o arquivo, mantenha dois buffers:

1. **Quadro de prévia** — um `ImageData` reduzido (lado longo cerca de 1280–1440, ou o tamanho CSS do canvas × `devicePixelRatio`, o que for menor). Use este enquanto o usuário ajusta os efeitos.
2. **Original** — o `HTMLImageElement` (ou um bitmap sem reduzir). Chame `processImage` **uma vez**, na exportação.

Use `FrameType.Image` nos dois. Mesmo mecanismo, mesmos setters. O tamanho da saída acompanha a entrada: a prévia é pequena; a exportação é em resolução total. Não amplie o resultado da prévia para fingir uma exportação.

Não passe um `<img>` sem reduzir no loop de prévia — `processImage` lê `naturalWidth` / `naturalHeight`.

```javascript theme={null}
function rasterize(source, maxEdge) {
  const sw = source.naturalWidth || source.width;
  const sh = source.naturalHeight || source.height;
  const scale = Math.min(1, maxEdge / Math.max(sw, sh));
  const w = Math.max(1, Math.round(sw * scale));
  const h = Math.max(1, Math.round(sh * scale));
  const canvas = document.createElement('canvas');
  canvas.width = w;
  canvas.height = h;
  const ctx = canvas.getContext('2d');
  ctx.drawImage(source, 0, 0, w, h);
  return ctx.getImageData(0, 0, w, h);
}

const preview = rasterize(image, 1440); // once, when the file opens
// Keep `image` for export

const previewOut = engine.processImage(
  preview,
  preview.width,
  preview.height,
  FrameType.Image,
);
previewCtx.putImageData(previewOut, 0, 0);

// Export — full resolution, once
const exportOut = engine.processImage(
  image,
  image.naturalWidth,
  image.naturalHeight,
  FrameType.Image,
);
```

A prévia da câmera é outro caminho: resolução de captura + `FrameType.Video`. Faça debounce das chamadas de `processImage` do slider. Mostre um estado de ocupado antes de exportar; o processamento em resolução total é síncrono e pode travar a página.

## Parâmetros

Comece baixo na prévia em tempo real (`smoothing` \~ `0.2`–`0.5`). A remodelagem é `[-1, 1]`; valores pequenos ficam mais naturais na câmera.

Não registre `onFaceLandmarks` a menos que a UI precise deles — isso força detecção por quadro.

`setBeautySkinOnly(true)` evita borrar fundos quando a suavização está alta.

## Recursos

* Hospede `.fbd` de filtro / adesivo e jpg/png de fundo como arquivos estáticos; passe a URL para `setFilter` / `setSticker` / `setVirtualBackground`.
* Os recursos de runtime são carregados pelo SDK durante `init()`. Não coloque um `resource.fbd` na raiz do site para o mecanismo.
* Troque filtro / adesivo na entrada do usuário, não a cada quadro.

## Memória

* Chame `destroy()` no unmount / `beforeunload`.
* Reutilize o canvas de exibição; não aloque um canvas novo a cada quadro.

## HTTPS e CORS

O acesso à câmera precisa de HTTPS ou localhost. Se os assets de filtro / adesivo estiverem em outra origem, envie headers CORS.

## Relacionado

* [Tratamento de erros](/pt-BR/web/error-handling)
* [Perguntas frequentes](/pt-BR/web/faq)
* [Referência da API](/pt-BR/web/api-reference)
