Drive this engine live: open the Hybrid seat on the Test Bench →

Hybrid

hybrid Medium — a normal phone is fine

A real photograph wearing a living face — eyes, lashes and mouth are drawn on top every frame and are never baked into the picture.

A photo <img> under a transparent 2D canvas. The photo supplies the person; the canvas supplies the life.

What it can express

Moods: 25 protocol moods, each with its own channel recipe — the richest mood support of the five 2D engines — plus nine timed gesture actions. One mood is held at a time; a one-shot gesture never clears it.

What it costs a device

measured on this box375×6671440×900
cold mount → first frame636 ms394 ms
rAF fps — idle5957
rAF fps — speaking5956
CPU cores busy — idle0.380.75
CPU cores busy — speaking0.400.77
worst frame gap (p95)16.8 ms16.8 ms
over the wire1.85 MB1.85 MB
JS heap10 MB10 MB

Compute sits between Sketch and SVG (0.38 / 0.75 cores against a 0.08 / 0.10 empty page), but the bandwidth is the real story: 1.85 MB, because a photo base must ship. The measured base here was 1.66 MB on its own.

Why medium: The compute sits mid-pack; the photograph is the real cost. On a phone this engine is expensive in bandwidth and memory before it is expensive in CPU.

Dials it really exposes today

149 numeric feature keysthe geometry and gauge rack — brow thickness, lash fan, lip volume, teeth, wrinkles, accessory placementeach range-clamped individually; 134 carry explicit ranges
12 style dialsversioned looks for each feature familymoStyle · lashStyle · lipStyle · lipVer · mouthVer · browVer · noseVer · eyeShape · earStyle · hatStyle · glassStyle · neckStyle
11 on/off toggleswhole features switched in or outmo · lash · exl · ear · blush2 · flower · hat · glasses · neck · liveBoost · wrinkles
32 palette rolesindependent colour for each part — lashes, teeth, gums, liner, sclera, lens, blush#rgb or #rrggbb only; anything else is dropped
sanitizeTune gatethe geometry, style and palette dials arrive through one whitelist — unknown keys dropped whole, numbers clamped, enums checked, colours regex-tested. The four painter-lane booleans and the style switch are checked separately, not through this gateown-property whitelist; untrusted payloads are safe
lashes / nose / lips2 / photoSkinpainter-lane booleans on the base swapbooleans only
replacePaltreat an incoming palette as complete truth so no defaults bleed throughtrue = replace; otherwise merge

Try it

Hybrid Overlay Lab — swap bases and feature stylesopen/avatar-lab/hybrid/ Universal Stage — Hybrid beside the other fouropen/alive-site/universal-stage.html

Honest limits

Numbers are software-renderer numbers. Measured 2026-08-04 on the estate box (18 vCPU, load 2.8–5.3 during the run) under chromium_headless_shell-1232 + SwiftShader, 3 runs per cell, median reported. SwiftShader rasterizes on the CPU, so a real phone GPU changes the picture — most of all for 3D. Read the ordering between engines, not the absolute figures. Evidence for every claim: CARD-FACTS.md. Harness: work/measure-engines.mjs.