Captures animations from any website via headless browser, extracts frame-level telemetry, and reconstructs them as production-ready CSS / GSAP / Framer Motion code using a multimodal AI pipeline.
URL
│
▼
core/capture.py ← Playwright + CDP injection (MutationObserver, Web Animations API, PerformanceObserver)
│
▼
core/extract.py ← Video → keyframes (cv2 adaptive scene-change detection)
│
▼
core/align.py ← Cross-correlate frame timestamps with CDP telemetry → AlignedTimeline JSON
│
▼
ai/generator.py ← Load prompt template → call AI backend (litellm) → refine via sandbox loop
│ ai/prompts/{css,gsap,framer}.md
▼
core/validate.py ← Playwright sandbox render → SSIM + pixel diff comparison → pass/fail + delta
│
▼
cli.py ← typer CLI: capture | generate | validate | export
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
playwright install chromium --with-depsdocker compose build| Variable | Default | Description |
|---|---|---|
AI_PROVIDER |
openai |
Provider: openai, anthropic, qwen, groq, ollama, together, deepseek, gemini |
AI_MODEL |
gpt-4o |
Model identifier (provider-specific) |
AI_API_KEY |
— | API key for the selected provider |
AI_BASE_URL |
— | Custom base URL (Ollama, proxy, etc.) |
AI_MAX_RETRIES |
3 |
Max retry attempts on AI failures |
AI_RETRY_DELAY |
1.5 |
Initial retry delay in seconds (exponential backoff) |
AI_TEMPERATURE |
0.2 |
Generation temperature |
AI_MAX_TOKENS |
8192 |
Max tokens per AI response |
CAPTURE_TIMEOUT |
30000 |
Navigation timeout in milliseconds |
CAPTURE_VIEWPORT_WIDTH |
1280 |
Browser viewport width |
CAPTURE_VIEWPORT_HEIGHT |
720 |
Browser viewport height |
CAPTURE_WAIT_FOR |
networkidle |
Playwright wait strategy |
CAPTURE_MAX_DURATION_MS |
10000 |
Max animation capture window |
EXTRACT_FPS_TARGET |
60 |
Frame sampling target |
EXTRACT_KEYFRAME_THRESHOLD |
0.02 |
Scene-change sensitivity (0–1) |
EXTRACT_MAX_FRAMES |
600 |
Hard cap on extracted frames |
VALIDATE_SSIM_THRESHOLD |
0.92 |
Min SSIM score to pass (0–1) |
VALIDATE_PIXEL_THRESHOLD |
0.02 |
Max pixel diff ratio to pass (0–1) |
VALIDATE_MAX_ITERATIONS |
3 |
Refinement loop iterations |
OUTPUT_DIR |
./output |
Root directory for all session artifacts |
LOG_LEVEL |
INFO |
DEBUG / INFO / WARNING / ERROR |
LOG_JSON |
false |
Emit structured JSON logs |
Create a .env file in the project root to set these.
Record a page and extract telemetry without generating code.
python cli.py capture https://stripe.com --output ./output --max-duration 8000Returns a session ID used by subsequent commands.
Generate animation code from a session (or trigger a fresh capture inline).
# From existing session
python cli.py generate --session <SESSION_ID> --framework gsap --provider openai
# Fresh capture + generate in one step
python cli.py generate --url https://stripe.com --framework css --provider anthropicOptions:
| Flag | Description |
|---|---|
--framework |
css (default), gsap, framer |
--provider |
Override AI_PROVIDER |
--model |
Override AI_MODEL |
--max-iter |
Refinement iterations (default: 3) |
--skip-validation |
Skip sandbox comparison |
Re-run validation against an existing session.
python cli.py validate <SESSION_ID> --framework gsapCopy the generated code to a destination path.
python cli.py export <SESSION_ID> --framework gsap --dest ./my-animation.js# Set your API key
export AI_API_KEY=sk-...
# One-shot capture + generate
docker compose run --rm motion-replica \
generate --url https://framer.com --framework framer --provider openai
# Interactive shell
docker compose run --rm --entrypoint bash motion-replicaOutput artifacts land in ./output/ on the host.
Each run creates output/<session-id>/:
output/<session-id>/
├── video/ ← raw .webm recording
├── cdp_log.json ← raw CDP telemetry (mutations, animations, perf)
├── timeline.json ← aligned timeline (segments, events, keyframe refs)
├── animation.css ← generated CSS (or .js / .tsx)
└── generation_meta.json ← tokens, model, validation scores
- Add a new entry to
_PROVIDER_MODEL_MAPinai/backend.py. - If authentication differs, add a branch in
_build_kwargs. - Pass
--provider <name>via CLI.
All providers are routed through litellm, which supports 100+ model endpoints transparently.
- Add
ai/prompts/<framework>.mdwith system prompt instructions. - Add the framework key to
SUPPORTED_FRAMEWORKSinai/generator.py. - Add the file extension mapping in
cli.py::_file_ext. - Implement sandbox rendering in
core/validate.py::_render_sandboxif needed.
The validator renders the generated code in a headless Playwright sandbox and compares frame-by-frame against the original capture:
- SSIM (Structural Similarity Index) — perceptual quality, target ≥ 0.92
- Pixel diff ratio — fraction of changed pixels, target ≤ 0.02
- pixelmatch (Node.js) — used when
nodeis available; falls back to pure NumPy
If validation fails, the delta is fed back into the next AI generation iteration (max 3 by default).