AI face swapping for GIFs β running 100% locally on your Mac.
No cloud. No uploads. Just memes.
β¬οΈ Download for Mac Β· π Landing page Β· Installation Β· Architecture Β· Contributing
meme-swap wraps the FaceFusion AI engine in a fully typed TypeScript pipeline, and ships it as three apps that share one local engine:
| Surface | Stack | What you get |
|---|---|---|
| π Web app | Next.js 16 | Drag & drop face swap, Giphy search, model settings, live progress |
| π₯οΈ Desktop app | Electron | Native macOS app with guided first-run setup, packaged as a .dmg |
| π€ MCP server | Model Context Protocol | Lets AI assistants (Claude, Cursorβ¦) run face swaps as a tool |
- π Private by design β models, processing and results all live in
~/.meme-swap/on your machine. Your face never leaves your Mac, and swapping works fully offline once installed. - β‘ Apple Silicon fast β inference runs through CoreML (Neural Engine + GPU) via ONNX Runtime, with CPU and CUDA fallbacks.
- π§ A real AI pipeline β not just a swap:
inswapper_128for identity transfer, CodeFormer face restoration, Real-ESRGAN Γ2 frame upscaling, expression restorer and lip syncer, orchestrated per-frame. - ποΈ GIF-native β FFmpeg handles GIF β MP4 both ways with palette-optimized output, so memes stay memes.
- π Giphy, plugged in β search trending memes right inside the app with hashtag shortcuts; pick a GIF and it's fetched and converted automatically (with a curated offline library when no API key is set).
Giphy built in β search, click, swap. No downloads, no tabs. |
Ready to swap β target GIF, source face, quality presets. One button. |
- Architecture
- Project Structure
- Prerequisites
- Installation
- Running the Apps
- Packages
- Environment Variables
- Landing Page & Docs
- Contributing
- Responsible Use
graph TB
subgraph "Applications"
FE["Web Frontend\n(Next.js 16)"]
DE["Desktop App\n(Electron)"]
MCP["MCP Server\n(HTTP/SSE)"]
end
subgraph "Shared Packages"
FC["@meme-swap/faceswap-core\nFaceFusion wrapper"]
VP["@meme-swap/video-processor\nFFmpeg wrapper"]
AC["@meme-swap/api-client\n(Giphy client)"]
I18N["@meme-swap/i18n\nTranslations"]
end
subgraph "Local engine β ~/.meme-swap/"
FF["FaceFusion\n(Python venv + ONNX models)"]
FFMPEG["FFmpeg\n(system)"]
end
FE --> FC
FE --> VP
DE --> FC
DE --> VP
MCP --> FC
MCP --> VP
FC --> FF
VP --> FFMPEG
sequenceDiagram
participant U as User
participant App as App (Web/Desktop/MCP)
participant VP as video-processor
participant FC as faceswap-core
participant FF as FaceFusion
U->>App: Upload face image + target GIF
App->>VP: gifToMp4() if target is GIF
VP-->>App: MP4 video
App->>FC: runFaceSwap(source, target.mp4)
FC->>FF: spawn python3 facefusion.py (headless-run)
FF-->>FC: processed MP4 (+ live progress)
FC-->>App: result path
App->>VP: mp4ToGif() if output should be GIF
VP-->>App: final GIF
App-->>U: Download URL
| Processor | Model | Role |
|---|---|---|
| Face swapper | inswapper_128 / inswapper_128_fp16 |
Identity transfer, frame by frame |
| Face enhancer | codeformer |
Restores and sharpens the swapped face |
| Frame enhancer | real_esrgan_x2 |
Optional Γ2 super-resolution of the whole frame |
| Expression restorer | expression_restorer |
Keeps the original grimaces and blinks |
| Lip syncer | optional | Re-syncs mouth movement to the source audio |
Execution providers: coreml (default on Apple Silicon) β cpu fallback, cuda supported.
meme-swap/
βββ apps/
β βββ frontend/ # Next.js 16 web application
β βββ desktop/ # Electron desktop application
β βββ mcp-server/ # MCP server (HTTP/SSE transport)
β
βββ packages/
β βββ faceswap-core/ # TypeScript wrapper for FaceFusion
β βββ video-processor/ # FFmpeg wrapper (GIF β MP4)
β βββ api-client/ # Giphy API client (search + trending, with localStorage/IPC/env fallback chain)
β βββ i18n/ # Shared translations (EN/FR)
β
βββ website/ # Landing page (GitHub Pages)
β
βββ scripts/
β βββ setup-facefusion.mjs # FaceFusion one-time installer (CLI wrapper around @meme-swap/installer-core)
β
βββ docs/
β βββ architecture.md # Detailed architecture notes
β βββ development.md # Local development guide
β βββ adr/ # Architecture Decision Records
β
βββ .github/workflows/ # CI β auto-deploys website/ to GitHub Pages
βββ turbo.json # Turborepo pipeline
βββ pnpm-workspace.yaml # pnpm workspace config
Note: FaceFusion is installed globally at
~/.meme-swap/facefusion/and is never bundled inside the repo. All apps resolve it from that path at runtime. Deleting~/.meme-swap/removes every model, cache and result.
| Tool | Version | Install |
|---|---|---|
| Node.js | β₯ 18 | nodejs.org |
| pnpm | β₯ 9 | npm i -g pnpm |
| Python | β₯ 3.9 | brew install python |
| FFmpeg | any | brew install ffmpeg |
| Git | β₯ 2 | pre-installed on macOS |
Grab the latest .dmg (Apple Silicon) from the Releases page, open it and drag Meme Swap.app into Applications. The guided first-run setup installs FaceFusion into ~/.meme-swap/ for you.
The build has no Apple Developer ID (that's a paid Apple program), so it is only ad-hoc signed and not notarized. On first launch macOS will block it with a message like "Apple could not verify 'Meme Swap' is free of malware." This is expected β the app is safe, macOS just can't verify an unnotarized developer. To allow it:
- Try to open Meme Swap.app once (double-click) β you'll get the warning. Click Done.
- Open System Settings β Privacy & Security.
- Scroll down to the Security section β you'll see ""Meme Swap" was blocked to protect your Mac."
- Click Open Anyway, then confirm with your password or Touch ID.
macOS remembers this, so subsequent launches open normally.
Prefer the Terminal?
Removing the download quarantine flag has the same effect:
xattr -cr "/Applications/Meme Swap.app"# 1. Clone & install the monorepo
git clone https://github.com/Tlahey/meme-swap.git && cd meme-swap
pnpm install
# 2. One-time: install FaceFusion + Python venv into ~/.meme-swap
pnpm install:facefusion
# 3. Configure environment (optional)
cp .env.example .env.local
# 4. Build all packages
pnpm buildpnpm frontend:dev
# β http://localhost:3010pnpm desktop:devpnpm build # 1. Build all shared packages
pnpm desktop:build # 2. Compile the desktop TypeScript + copy assets
pnpm desktop:package # 3. Package into a .dmg via electron-builderThe .dmg is output to apps/desktop/dist/. Double-click it to install Meme Swap.app into your Applications folder.
Note:
gatekeeperAssessis disabled in the build config, so macOS may show an unverified developer warning. Right-click β Open to bypass it, or sign the app with an Apple Developer certificate.
# Build first
pnpm build --filter=mcp-server
# Start
cd apps/mcp-server && pnpm start
# β http://localhost:3001To use the MCP server with an AI client (e.g. Cursor), add to your MCP config:
{
"mcpServers": {
"meme-swap": {
"command": "node",
"args": ["<absolute-path>/apps/mcp-server/build/index.js"]
}
}
}Available MCP tools:
run_faceswapβ perform a face swap given a source image and target media path
See apps/mcp-server/README.md for the full API reference.
TypeScript wrapper around the FaceFusion Python CLI.
import { runFaceSwap } from '@meme-swap/faceswap-core';
const result = await runFaceSwap({
sourcePath: './face.jpg',
targetPath: './target.mp4',
outputPath: './output.mp4',
executionProviders: ['coreml', 'cpu'], // Apple Silicon
faceSwapperModel: 'inswapper_128_fp16',
faceEnhancerModel: 'codeformer',
threadCount: 4,
logLevel: 'info',
onProgress: ({ step, percent }) => console.log(step, percent),
});
if (result.success) {
console.log('Output:', result.outputPath);
}| Option | Type | Default | Description |
|---|---|---|---|
sourcePath |
string |
β | Source face image |
targetPath |
string |
β | Target video (must be MP4) |
outputPath |
string |
β | Output file path |
executionProviders |
('coreml' | 'cpu' | 'cuda')[] |
['coreml','cpu'] |
Hardware accelerators |
faceSelectorMode |
string |
β | 'many', 'one', 'reference' |
faceSwapperModel |
string |
β | e.g. inswapper_128_fp16 |
faceEnhancerModel |
string |
β | e.g. codeformer |
frameEnhancerModel |
string |
β | e.g. real_esrgan_x2 |
expressionRestorerModel |
string |
β | Restores original expressions |
lipSyncerModel |
string |
β | Re-syncs lips to source audio |
threadCount |
number |
auto | Parallel execution threads |
logLevel |
'debug' | 'info' | 'warning' | 'error' |
'info' |
Log verbosity |
onProgress |
(p) => void |
β | Live progress callback (analysing / extracting / processing / merging) |
FFmpeg wrapper for format conversion.
import { gifToMp4, mp4ToGif } from '@meme-swap/video-processor';
// GIF β MP4 (required before running FaceFusion)
await gifToMp4({ inputPath: './input.gif', outputPath: './input.mp4' });
// MP4 β GIF (for final output)
await mp4ToGif({
inputPath: './output.mp4',
outputPath: './output.gif',
fps: 10,
maxWidth: 480,
});Copy .env.example to .env.local and configure:
# Optional β used by the Giphy API client for GIF search; falls back to a curated GIF list if unset
GIPHY_API_KEY=your_key_here
# FaceFusion execution providers (default: coreml,cpu on Apple Silicon)
FACEFUSION_EXECUTION_PROVIDERS=coreml,cpu
# Thread count for FaceFusion (default: auto-detected)
FACEFUSION_THREAD_COUNT=8
# Port for the web frontend dev server
PORT=3010The project landing page lives in website/ and is deployed automatically to tlahey.github.io/meme-swap by the deploy-pages GitHub Actions workflow on every push to main that touches website/**.
One-time setup: in the repo settings, set Settings β Pages β Source to GitHub Actions.
More docs:
docs/FEATURES.mdβ summary of what the app can dodocs/architecture.mdβ detailed architecture notesdocs/development.mdβ local development guidedocs/adr/β Architecture Decision Records
Meme Swap is free, open-source, and built in my spare time. If it's useful to you, consider sponsoring on GitHub β it helps keep the project maintained and moving forward.
See CONTRIBUTING.md for the full guide.
Quick summary:
- Fork the repo and create a branch:
feature/<name>orfix/<name> - Follow the code style rules β TypeScript strict mode, named exports, async/await
- Open a pull request with a clear description
Meme Swap is built for entertainment and creative use. Always get consent before swapping someone's face, and never use it to deceive, impersonate or harm anyone. You are responsible for the content you create.
MIT Β© Tlahey
- FaceFusion β AI face manipulation platform
- InsightFace β
inswapperface swap model - CodeFormer β face restoration
- Real-ESRGAN β super-resolution
- FFmpeg β media conversion


