Touch-up
Skin smoothing, the beauty-filter effect every conferencing app ships. Off by default.
new EffectsPipeline(stream, { touchup: true })
That’s the whole thing if you don’t care how it works. Everything below is for when you do.
It runs in parallel with backgrounds
Touch-up and the background are not alternatives — they compose:
new EffectsPipeline(stream, {
background: 'blur',
touchup: { strength: 0.4 },
})
Both ride the same encoder pass. The face keypoints come from a second head on the network that’s already running for the matte, so enabling touch-up doesn’t add an inference — it adds the landmark model and the smoothing passes. Nothing about the background changes.
Options
new EffectsPipeline(stream, {
touchup: {
strength: 0.6,
amount: 8,
detail: 0.35,
style: 'freq-sep',
},
})
How much of the smoothed result is blended over the original, 0–1. 0 is a no-op; 1 is the full effect. This is the knob to put in front of users — it’s the only one most people want.
Smoothing radius, in atlas pixels. Higher removes more; too high and skin goes plastic.
How much high-frequency texture — pores, stubble — survives the smoothing, 0–1. This is what keeps a face looking like skin rather than a mannequin. Only applies to 'freq-sep'; ignored by 'bilateral'.
Which filter does the smoothing.
'freq-sep' — frequency separation. Splits the face into a low-frequency band (blurred) and a high-frequency band (texture), smooths the first, and adds the second back scaled by detail. Softens tone and blotchiness while keeping pores. The default, and the better choice for most video.
'bilateral' — a single edge-preserving pass. Stronger on blemishes and hard edges, at the cost of a more processed look. detail does nothing here.
Both cost about the same. It’s a look preference, not a performance trade — which is why it’s yours to expose rather than ours to pick.
Runtime control
await pipeline.setTouchup({ strength: 0.8 }) // enable, or update params live
await pipeline.setTouchup(null) // disable
The first call fetches the landmark assets (see below); later calls reuse them, so parameter changes are instant. Safe to wire straight to a slider.
Multiple faces
Everyone in frame gets smoothed — up to four faces, on the medium, large and xl presets. small and xs decode keypoints on a coarser grid that can’t reliably separate a second face, so they smooth one.
You don’t configure this and there’s no per-face API. The cost is near-flat in the number of faces: they share a single atlas, so the smoothing passes run once regardless.
Extra assets
Touch-up needs three files beyond the model weights, fetched from weightsBaseUrl on first enable:
| File | What it is |
|---|---|
model_landmark_mesh.bin | the 478-point face landmark model (.f16.bin used when available) |
face_topology.json | the canonical face mesh |
weight_mask.png | which regions get smoothed, and how much |
If you’re self-hosting weights, these need to sit alongside model_*.bin or touch-up will fail to enable. On the default CDN they’re already there.
Performance
The landmark model runs once per face, every frame. On a single face that’s the common case and it’s modest; four faces cost four runs. The smoothing itself is a fixed cost.
If you’re tight on budget, strength is free to lower but the model still runs — to actually reclaim the time, call setTouchup(null).
Requirements
Touch-up needs face-capable model weights. Every current preset has them, so this only bites if you’re self-hosting an older weight set — in which case the SDK logs a warning and leaves the effect off rather than failing your pipeline.