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

# Implementar beleza

> Integre o Facebetter Web SDK 2.0

<Note>
  SDK **2.0.0**. Autenticação: [Autenticação e licença](/pt-BR/intro/license). Valores de enum: [Enums de parâmetros](/pt-BR/intro/makeup).
</Note>

## Instalar

```bash theme={null}
npm install facebetter
```

```javascript theme={null}
import {
  BeautyEffectEngine,
  EngineConfig,
  FrameType,
  MirrorMode,
  Reshape,
  SmoothingStyle,
  WhiteningStyle,
  LipstickColor,
  ChromaKeyColor,
  EngineEventCode,
  FacebetterError,
} from 'facebetter';
```

## Criar o mecanismo

`EngineConfig` na Web tem **somente** estes campos. Não há `appId` / `appKey` no objeto de config.

| Campo          | Finalidade                                                                                  |
| -------------- | ------------------------------------------------------------------------------------------- |
| `licenseToken` | String do token de licença, ou JSON `{token}`. **Obrigatório.** Busque-o antes de `init()`. |

O SDK carrega os arquivos de runtime durante `init()`. Você não hospeda um `resource.fbd` na raiz do site para o mecanismo. Progresso de download opcional: `init({ onProgress })`. O mecanismo não busca tokens. A Web **não** suporta `.lic` offline.

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

await engine.setLogConfig({
  consoleEnabled: true,
  fileEnabled: false,
  level: 2, // TRACE=0 … CRITICAL=5
});

await engine.init();
```

<Warning>
  Chame `setLogConfig` antes de `init()` se quiser ver logs de load / autenticação. Logging em arquivo não é suportado no navegador (`fileEnabled` é ignorado).
</Warning>

```javascript theme={null}
try {
  await engine.init();
} catch (error) {
  if (error instanceof FacebetterError) {
    console.error(error.code, error.message);
  }
  throw error;
}
```

## Beleza da pele

Faixa de intensidade **`[0.0, 1.0]`**. `0` desliga o efeito.

```javascript theme={null}
engine.setSmoothing(0.8);
engine.setSmoothingStyle(SmoothingStyle.Natural);
engine.setWhitening(0.5);
engine.setWhiteningStyle(WhiteningStyle.ColdWhite);
engine.setSharpening(0.3);
engine.setRosiness(0.2);
engine.setBeautySkinOnly(true);
```

<Tip>
  `setBeautySkinOnly(true)` limita suavização / clareamento / nitidez / tom rosado à pele detectada. Roupas e fundo permanecem inalterados.
</Tip>

Enums de estilo: [Enums de parâmetros](/pt-BR/intro/makeup).

## Remodelagem facial

```javascript theme={null}
engine.setReshape(Reshape.FaceThin, 0.3);
engine.setReshape(Reshape.EyeSize, 0.2);
```

A faixa é **`[-1.0, 1.0]`**. `0` desliga. Positivo e negativo são direções opostas (por exemplo `FaceThin`: afinar / bochechas mais cheias). Lista completa: [Enums de parâmetros](/pt-BR/intro/makeup).

## Remodelagem corporal

```javascript theme={null}
const bodyPack = new Uint8Array(
  await (await fetch('/resource_body.fbd')).arrayBuffer()
);
engine.addResourcePack(bodyPack);
engine.setBodyReshape(BodyReshape.WaistSlim, 0.4);
engine.setBodyReshape(BodyReshape.LegStretch, 0.3);
engine.setBodyReshape(BodyReshape.TorsoLong, 0.3);
```

A faixa é **`[0.0, 1.0]`**. `0` desliga. Busque `resource_body.fbd` e chame `addResourcePack` após `init()`. Lista: [Enums de parâmetros](/pt-BR/intro/makeup). Pacotes: [Pacotes de recursos opcionais](/pt-BR/intro/resource-packs).

## Maquiagem

Intensidade, formato e cor são setters separados. A intensidade é `[0.0, 1.0]`. Predefinições: [Enums de parâmetros](/pt-BR/intro/makeup).

```javascript theme={null}
engine.setLipstick(0.4);
engine.setLipstickColor(LipstickColor.Rouge);

engine.setBlush(0.3);
engine.setBlushStyle(/* BlushStyle.SunKissed */);
engine.setBlushColor(/* BlushColor.CoralPink */);

engine.setContour(0.4);
engine.setContourStyle(/* ContourStyle.Natural */);

engine.setEyeShadow(0.35);
engine.setEyeShadowStyle(/* EyeShadowStyle.Soft */);
engine.setEyeShadowColor(/* EyeShadowColor.Plum */);

engine.setEyeLiner(0.3);
engine.setEyeLinerStyle(/* ... */);
engine.setEyeLinerColor(/* ... */);

engine.setEyebrow(0.3);
engine.setEyebrowStyle(/* ... */);
engine.setEyebrowColor(/* ... */);

engine.setEyelash(0.3);
engine.setEyelashStyle(/* ... */);
engine.setEyelashColor(/* ... */);

engine.setPupil(0.4);
engine.setPupilColor(/* PupilColor.Hazel */);
```

## Filtros e adesivos

Passe uma URL `.fbd` ou um `Uint8Array` em memória diretamente para o setter.

```javascript theme={null}
engine.setFilter('/assets/filters/portrait/natural/natural.fbd');
engine.setFilterIntensity(0.8);
engine.clearFilter();

engine.setSticker('/stickers/face/fox.fbd');
engine.clearSticker();
```

Adesivos 3D precisam do pacote opcional `resource_3d.fbd` (não está no SDK Web). Veja [Pacotes de recursos opcionais](/pt-BR/intro/resource-packs). Busque os bytes e registre-os após `init()`:

```javascript theme={null}
const pack = new Uint8Array(
  await (await fetch('/resource_3d.fbd')).arrayBuffer()
);
engine.addResourcePack(pack);
engine.set3DSticker('/stickers/3d/oculos.fbd');
engine.clear3DSticker();
```

```javascript theme={null}
const bytes = new Uint8Array(await (await fetch('/filters/chuxin.fbd')).arrayBuffer());
engine.setFilter(bytes);
```

## Fundo virtual e chroma key

```javascript theme={null}
engine.setVirtualBackgroundBlur(0.6);          // [0, 1]; 0 clears blur
engine.setVirtualBackground('/background.jpg'); // path or Uint8Array (png/jpg)
engine.clearVirtualBackground();

engine.setChromaKey(ChromaKeyColor.Green);
engine.setChromaKeySimilarity(0.4);
engine.setChromaKeySmoothness(0.2);
engine.setChromaKeyDesaturation(0.3);
engine.clearChromaKey();
```

<Tip>
  O chroma key só substitui a **máscara**. O preenchimento continua sendo `setVirtualBackgroundBlur` ou `setVirtualBackground`. Desfoque e substituição por imagem são mutuamente exclusivos.
</Tip>

## Callbacks

```javascript theme={null}
engine.setCallbacks({
  onEngineEvent: (code, message) => {
    if (code === EngineEventCode.LicenseValidationSuccess) {
      console.log('license ok');
    } else if (code === EngineEventCode.LicenseValidationFailed) {
      console.error('license failed', message);
    } else if (code === EngineEventCode.InitializationComplete) {
      console.log('engine ready');
    } else if (code === EngineEventCode.InitializationFailed) {
      console.error('init failed', message);
    }
  },
  onFaceLandmarks: (faces) => {
    // faces[].rect, key_points, visibility, face_id, score, pitch, roll, yaw
  },
  maxFaces: 10,
});
```

| Código | Nome                                       |
| ------ | ------------------------------------------ |
| `0`    | `EngineEventCode.LicenseValidationSuccess` |
| `1`    | `EngineEventCode.LicenseValidationFailed`  |
| `100`  | `EngineEventCode.InitializationComplete`   |
| `101`  | `EngineEventCode.InitializationFailed`     |

Omita `onFaceLandmarks` a menos que você precise dos landmarks. Ativá-lo executa detecção facial a cada quadro.

## Processar quadros

Prefira `processImage`. Ele retorna `ImageData` de forma síncrona.

```javascript theme={null}
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const video = document.querySelector('video');

function loop() {
  if (engine.initialized && video.readyState >= 2) {
    const result = engine.processImage(
      video,
      video.videoWidth,
      video.videoHeight,
      FrameType.Video,
      MirrorMode.Horizontal, // front camera
    );
    if (result) {
      if (canvas.width !== result.width) canvas.width = result.width;
      if (canvas.height !== result.height) canvas.height = result.height;
      ctx.putImageData(result, 0, 0);
    }
  }
  requestAnimationFrame(loop);
}
loop();
```

`input` pode ser `ImageData`, `HTMLImageElement`, `HTMLCanvasElement`, `HTMLVideoElement` ou `Uint8ClampedArray` (então `width` / `height` são obrigatórios).

* `FrameType.Video` — câmera ao vivo / streaming (suavização temporal)
* `FrameType.Image` — fotos estáticas

`processTexture(textureHandle, width, height, stride, frameType, mirrorMode)` é para entrada de textura GPU personalizada. **O espelhamento não é aplicado neste caminho.** Apps web típicos devem usar `processImage`.

## Estatísticas

```javascript theme={null}
const { fps, avgProcessTimeMs, sessionTimeS } = engine.getStats();
```

## Destroy

```javascript theme={null}
engine.destroy();
```

Chame isto no unload da página ou quando um componente React/Vue desmontar.

Para TRTC / Agora / LiveKit: [Integração com terceiros](/pt-BR/web/third-party-integration).

## Relacionado

* [Integração com terceiros](/pt-BR/web/third-party-integration)
* [Tratamento de erros](/pt-BR/web/error-handling)
* [Práticas recomendadas](/pt-BR/web/best-practices)
* [Referência da API](/pt-BR/web/api-reference)
* [Perguntas frequentes](/pt-BR/web/faq)
