voxa_beauty 0.2.2
voxa_beauty: ^0.2.2 copied to clipboard
Real-time beauty filters for VoxaRTC — skin smoothing, tone and warmth on the camera capture path, entirely on the GPU. No licence, no subscription.
voxa_beauty #
Real-time beauty filtering for voxa_rtc_engine —
skin smoothing, tone and warmth on the camera capture path.
No licence, no subscription, no account, no model files. The entire effect is a shader.
Setup #
dependencies:
voxa_beauty: ^0.1.0
That is the whole integration. No gradle edit, no MainActivity change, no
ProGuard rule, no native code — the filter registers itself.
final beauty = VoxaBeauty(engine);
await beauty.enable(); // sensible defaults
await beauty.setSmoothing(0.7); // or drive it from a slider
await beauty.disable();
Gate your control on beauty.isSupported rather than assuming — it is false on
platforms this package does not cover yet, so you show no toggle instead of one
that does nothing.
Settings #
All are 0..1 and take effect on the next frame, so they are cheap to drive from a slider.
| Default | Notes | |
|---|---|---|
setSmoothing |
0.55 | Around 0.5 reads as a good camera. Past ~0.8 skin starts to look plastic, which is rarely what people want even when they ask for it. |
setBrightness |
0.12 | Lifts shadows rather than the whole curve, so highlights don't wash out. |
setWarmth |
0.10 | Nudges towards warmer tones. |
setSaturation |
0.10 | Extra colour. |
Why it's effectively free #
The filter runs in the graphics context the capturer and the hardware encoder already share. A frame arrives as a GPU texture, goes through one shader pass, and leaves as a GPU texture — no readback, no CPU copy, no pixel ever touching system memory, and nothing crossing into Dart.
Measured on a Pixel 6 at 1024×576: 24 fps with beauty on, which is the camera's own capture rate — the same as with no filter at all.
There is no per-frame millisecond figure here on purpose. GL commands are queued rather than executed, so timing the draw call measures how long it took to submit work, not what the GPU spent on it. Sustained capture rate is the honest number.
Makeup #
Lipstick tracks the mouth using MediaPipe face landmarks — on-device, Apache 2.0, no account and no per-user fee.
await beauty.setLipColour(const Color(0xFFC7385A));
await beauty.setLipstick(0.7);
await beauty.setLipstick(0); // off, and tracking stops
It multiplies rather than paints, so the lip keeps its own highlights and creases instead of looking like a sticker.
Makeup is the one thing here that is not free. Any strength above zero starts face tracking, which reads back a small copy of each frame and runs a model on it. Detection runs off the capture thread against a downscaled, upright copy and the shader always uses the newest result rather than waiting, so measured frame rate is unchanged at 24 fps — but it is real work, and it stays off until a user chooses a colour.
Landmarks are smoothed over time before use. Raw ones wobble even on a still face, and lipstick drawn straight onto them swims on the mouth.
What it does, and what it doesn't #
Smoothing is an edge-preserving blur — a sparse bilateral approximation — gated by a skin-tone mask in YCbCr. The mask is what makes it look deliberate: blur the whole frame and the room goes soft and it reads as a cheap filter, but restrict it to skin and eyes, hair and background stay sharp.
Beyond lipstick there is no blush, eyeshadow, mask or prop support yet, and no background replacement. The tracking those need is now in place — what is missing is the rendering and, more to the point, a filter format and the artwork to fill it. See below.
Downloadable filters #
There is no filter file format here yet. Effects are code, not data, so adding one means changing this package rather than dropping in a download. A format (a manifest plus textures painted to MediaPipe's canonical face UV layout) is the natural next step, and the tracking it would sit on is already working.
For prop and elaborate makeup effects today, see
voxa_deepar — the two register under
different names and can both be installed.
Platforms #
| Platform | Status |
|---|---|
| Android | Supported |
| iOS | Not yet — isSupported returns false rather than failing at runtime |
Notes #
Frames that arrive on the CPU rather than as a texture pass through untouched: uploading, filtering and reading back would cost more than the effect is worth. In practice camera frames are textures.