Skip to main content

Generate lip sync mouth shape sprites from any face image using AI

Project description

Blabberer

AI-powered lip sync sprite generator

Turn any face photo into 9 production-ready mouth shape sprites — and animate them in real time.

License: MIT Python 3.10+ TypeScript Claude Code Plugin PRs Welcome


https://github.com/user-attachments/assets/af47b852-281a-47c5-84c8-afd69edd79e9


Highlights

  • One command, nine sprites — feed in a portrait, get back 9 mouth shapes based on the Preston Blair phoneme system
  • Auto face detection — MediaPipe finds the face automatically; no manual cropping needed
  • AI-generated — Gemini (via OpenRouter) generates each mouth shape from reference artwork
  • Production-ready output — transparent backgrounds, soft-edge feathering, WebP format
  • Real-time lip sync engine — vanilla TypeScript engine syncs audio energy + text phonemes to shapes at 60fps
  • Claude Code plugin — install the skill and let Claude run the full pipeline for you
  • Zero frameworks — Python stdlib for HTTP, vanilla TS for the demo — minimal dependencies

How It Works

Portrait → Face Detection → Gemini AI → 9 Mouth Shapes → Post-Processing → Sprites
 (photo)    (MediaPipe)     (OpenRouter)  (Preston Blair)   (rembg + soft edges)   (WebP)

The 9 Shapes

Shape Phonemes Visual
A M, B, P Lips pressed together
B S, T, D, K, N Teeth visible, slightly open
C A, I Open mouth (speaking vowels)
D E Wide horizontal stretch
E O Rounded mouth
F U, W, Q Puckered lips
G F, V Upper teeth on lower lip
H L, T, D Barely parted lips
X (idle) Resting / closed mouth

Quick Start

Install

# Clone
git clone https://github.com/historacle-ai/blabberer.git
cd blabberer

# Install (pick one)
uv pip install -e .
# or: pip install -e .

Generate sprites

export OPENROUTER_API_KEY=sk-or-...   # https://openrouter.ai/keys

blabberer generate photo.jpg --output-dir ./sprites --verbose

Output:

sprites/
├── soft/              # Production-ready (transparent bg + soft edges)
│   ├── shape_A.webp
│   ├── shape_B.webp
│   ├── ...
│   └── shape_X.webp
├── shape_A.webp       # Transparent background (no soft edges)
├── ...
└── shape_X.webp

CLI Reference

blabberer generate <image> [options]

Options:
  --api-key KEY          OpenRouter API key (or set OPENROUTER_API_KEY env var)
  --output-dir, -o DIR   Output directory (default: ./sprites)
  --crop-box L,T,R,B     Manual face crop box (auto-detects if omitted)
  --model MODEL          Gemini model (default: google/gemini-3.1-flash-image-preview)
  --workers N            Concurrent API calls (default: 3)
  --skip-postprocess     Skip background removal and soft edges
  --verbose, -v          Detailed output

Python API

from blabberer import generate_sprites, full_postprocess

# Generate sprites
results = generate_sprites(
    image_path="photo.jpg",
    output_dir="./sprites",
    api_key="sk-or-...",
)

# Post-process (background removal + soft edges)
final = full_postprocess("./sprites")

Face Detection

from blabberer import detect_face_crop
from PIL import Image

image = Image.open("photo.jpg")
crop_box = detect_face_crop(image)  # → (left, top, right, bottom)

# Custom expansion ratios
crop_box = detect_face_crop(
    image,
    expand_top=0.3,      # 30% above face
    expand_bottom=0.5,   # 50% below face
    expand_sides=0.25,   # 25% each side
)

Interactive Demo

A browser demo lets you see lip sync in action — audio analysis drives mouth shapes in real time.

cd demo && npm install && npm run dev
# → http://localhost:5173

Two modes:

Mode Entry What it does
Canvas (default) simple.html Draws shapes on a <canvas> overlay — no sprites needed
Sprite index.html Dual-layer crossfade with generated sprite images

Lip Sync Algorithm

The LipSyncEngine uses a 3-tier energy model with text-informed shape selection:

  1. Audio analysis — Web Audio AnalyserNode extracts frequency data (first 30 bins)
  2. Energy smoothing — exponential moving average (rise=0.28, decay=0.18)
  3. Hysteresis state machine — LOW / MID / HIGH with asymmetric thresholds to prevent flicker
  4. Text-to-shape mapping — 28 letter + 12 digraph preferences per energy level
  5. Min hold time — 100ms per shape prevents "chewing" artifacts
  6. Crossfade rendering — two stacked <img> elements with 60ms CSS transitions

Use the Engine in Your Project

The demo's src/ files are standalone vanilla TypeScript — zero framework dependencies. Copy them into any project:

import { AudioAnalyser } from './audioAnalyser';
import { LipSyncEngine } from './lipSync';

const audio = document.querySelector('audio')!;
const analyser = new AudioAnalyser();
const node = analyser.connect(audio);
const engine = new LipSyncEngine(node!);

engine.loadText('Hello world');
audio.play();

function animate() {
  requestAnimationFrame(animate);
  const shape = engine.update(performance.now());
  // shape: 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'X'
}
requestAnimationFrame(animate);

Claude Code Plugin

Blabberer ships as a Claude Code plugin with a /lip-sync-pipeline skill that automates the entire workflow.

Install

/plugin install historacle-ai/blabberer

Run

/blabberer:lip-sync-pipeline photo.jpg

Claude handles face detection, sprite generation, post-processing, demo setup, and troubleshooting — end to end.


Requirements

Component Requirement
Python >= 3.10
API key OpenRouter with Gemini model access
Disk ~170 MB for rembg U2Net model (downloaded on first run)
Node.js >= 18 (demo only)

Project Structure

blabberer/
├── blabberer/                # Python package
│   ├── cli.py                # CLI entry point
│   ├── generator.py          # Face detect → Gemini → sprites
│   ├── face_detect.py        # MediaPipe face detection
│   ├── shapes.py             # 9 Preston Blair shape definitions
│   ├── postprocess.py        # Background removal + soft edges
│   └── reference/            # 12 bundled reference images
├── demo/                     # Browser lip sync demo
│   ├── simple.html           # Canvas mode (default)
│   ├── index.html            # Sprite mode
│   └── src/                  # Vanilla TypeScript
│       ├── lipSync.ts        # Audio + text → shape engine
│       ├── audioAnalyser.ts  # Web Audio API bridge
│       ├── mouthRenderer.ts  # Dual-layer crossfade
│       ├── simple.ts         # Canvas demo
│       └── main.ts           # Sprite demo
├── skills/                   # Claude Code plugin
│   └── lip-sync-pipeline/
├── .claude-plugin/           # Plugin manifest
└── pyproject.toml

Contributing

Contributions are welcome! Feel free to open an issue or submit a pull request.

  1. Fork the repo
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

About HistOracle

HistOracle

Blabberer was extracted from the production lip sync pipeline at HistOracle — an AI platform that brings historical figures to life through interactive conversations. HistOracle uses AI-generated visemes, real-time audio analysis, and natural language understanding to create lifelike talking portraits of figures from history.

We open-sourced the lip sync sprite generation and animation engine so developers, educators, and creators can build their own talking-face experiences.

License

MIT License — see LICENSE.

Copyright (c) 2026 Editlingo Solutions LLC

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

blabberer-0.1.0.tar.gz (323.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

blabberer-0.1.0-py3-none-any.whl (326.4 kB view details)

Uploaded Python 3

File details

Details for the file blabberer-0.1.0.tar.gz.

File metadata

  • Download URL: blabberer-0.1.0.tar.gz
  • Upload date:
  • Size: 323.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.0

File hashes

Hashes for blabberer-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ea7abd1ea42d6f067adc94c7e2829034b9bc24cceb411ef5d3f606e2bdb4f1d4
MD5 6eb6ae00d480ebfc5e6124d5b3e32c11
BLAKE2b-256 dfd04066e110303c60ff3c581037fc65f62aa2db8f5edc293af93c7a8a3bcf46

See more details on using hashes here.

File details

Details for the file blabberer-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: blabberer-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 326.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.0

File hashes

Hashes for blabberer-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 51dce4de1f6f4a04c9e9c0f775c5e32b8300e6b0a4002046a8c929748ddfb5d4
MD5 0e2a74d751513cf6f64a5473418a18a1
BLAKE2b-256 af3cb9a8f1e09efda0e50714e256eafd23a56baa178e7907f86c51a0bb6bfcb5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page