Create, preview, and QA animated SVGs with CSS animation-aware screenshots. The open-source animated SVG creator tool that captures what users actually see — not a blank screen at t=0.
Every SVG screenshot tool renders at t=0 — the instant the page loads. CSS animations that start with opacity: 0 are invisible in the screenshot, even though users see them animate in within milliseconds.
Your animated SVGs look empty in previews, CI screenshots, and AI-assisted design workflows.
SVGShot fixes this with animation-aware capture modes that screenshot your SVGs the way users actually experience them.
- 🎬 Animation-Aware SVG Screenshots — Capture animated SVGs mid-animation, at their final state, or frame-by-frame
- 🎞️ Filmstrip Mode — Generate multi-frame strips showing the full SVG animation progression at configurable intervals
- 🔍 Visual Diff — Pixel-level comparison between two versions of your SVG or HTML
- 🤖 MCP Server — Drop-in tool for Claude Code, Cursor, and any MCP-compatible AI agent
- 🌐 REST API — Simple HTTP endpoints for any SVG creator workflow or CI pipeline
- ⚡ Fast — Shared Playwright browser instance, 2-second renders, no cold starts after first request
- 🎨 SVG + HTML + React — Auto-detects input format, wraps SVG/snippets in proper boilerplate with Tailwind CDN
git clone https://github.com/BusyBee3333/svgshot.git
cd svgshot
npm install
npx playwright install chromium
npm start
# Server running at http://localhost:3700The core innovation — four ways to capture animated SVG content:
| Mode | What It Does | Best For |
|---|---|---|
natural |
Waits configurable delay (default 800ms) then screenshots | Animated SVGs — captures mid-animation state like users see |
freeze-end |
Injects CSS to force all SVG animations to their final state | Static previews of fully-settled designs |
filmstrip |
Captures N frames at intervals, composites into one image | SVG animation QA — verify timing, opacity ramps, transitions frame by frame |
instant |
Screenshots immediately at page load (t=0) | Static SVGs or comparing with the t=0 bug behavior |
Injects this CSS before capture to jump every CSS animation to its end state:
*, *::before, *::after {
animation-delay: -9999s !important;
animation-duration: 0.001s !important;
animation-fill-mode: both !important;
transition-duration: 0s !important;
transition-delay: 0s !important;
}Capture 8 frames over 2 seconds to verify your animated SVG output:
curl -X POST http://localhost:3700/filmstrip \
-H 'Content-Type: application/json' \
-d '{
"code": "<svg>...</svg>",
"frames": 8,
"duration": 2000,
"layout": "horizontal",
"showTimestamps": true
}' --output filmstrip.jpgReturns a single composite image with all frames side by side, each labeled with its timestamp. Perfect for verifying CSS animation timing in your SVG creator workflow.
curl -X POST http://localhost:3700/render \
-H 'Content-Type: application/json' \
-d '{
"code": "<svg viewBox=\"0 0 200 200\"><style>@keyframes fadeIn{from{opacity:0}to{opacity:1}} circle{animation:fadeIn 1s forwards}</style><circle cx=\"100\" cy=\"100\" r=\"80\" fill=\"coral\" opacity=\"0\"/></svg>",
"viewport": { "width": 400, "height": 400 },
"quality": 90,
"animationMode": "natural",
"screenshotDelay": 1000
}' --output screenshot.jpgParameters:
| Param | Type | Default | Description |
|---|---|---|---|
code |
string | required | SVG, HTML, or React code to render |
viewport |
object | {width:1280, height:800} |
Viewport dimensions |
quality |
number | 85 |
JPEG quality (1-100) |
fullPage |
boolean | false |
Capture full scrollable page |
animationMode |
string | "natural" |
natural, freeze-end, or instant |
screenshotDelay |
number | 800 |
Milliseconds to wait before capture (natural mode) |
Response: JPEG image buffer with headers:
X-Console-Errors— JSON array of JS console errors during renderX-Render-Meta— JSON object with render metadata
curl -X POST http://localhost:3700/filmstrip \
-H 'Content-Type: application/json' \
-d '{
"code": "<svg>...</svg>",
"frames": 6,
"duration": 2000,
"layout": "grid",
"showTimestamps": true
}' --output filmstrip.jpgParameters:
| Param | Type | Default | Description |
|---|---|---|---|
code |
string | required | SVG or HTML to capture |
viewport |
object | {width:800, height:600} |
Per-frame viewport |
quality |
number | 85 |
JPEG quality |
frames |
number | 6 |
Number of frames to capture |
duration |
number | 2000 |
Total duration to capture (ms) |
layout |
string | "horizontal" |
horizontal, vertical, or grid |
showTimestamps |
boolean | true |
Show timestamp labels on each frame |
curl -X POST http://localhost:3700/diff \
-H 'Content-Type: application/json' \
-d '{
"before": "<svg><circle cx=\"50\" cy=\"50\" r=\"40\" fill=\"red\"/></svg>",
"after": "<svg><circle cx=\"50\" cy=\"50\" r=\"40\" fill=\"blue\"/></svg>"
}'Response:
{
"diffPercent": 2.45,
"totalPixels": 1024000,
"changedPixels": 25088,
"dimensions": { "width": 1280, "height": 800 }
}{ "status": "ok", "service": "svgshot", "version": "1.0.0" }Use SVGShot as an MCP tool in Claude Code, Cursor, Windsurf, or any MCP-compatible AI coding agent. The AI can create animated SVGs, render them, see the output, and iterate — all in one conversation.
claude mcp add svgshot -- node /path/to/svgshot/src/mcp.js{
"mcpServers": {
"svgshot": {
"command": "node",
"args": ["/path/to/svgshot/src/mcp.js"]
}
}
}| Tool | Description |
|---|---|
render |
Full SVG/HTML render with all options — returns base64 JPEG + metadata |
render_svg |
SVG convenience wrapper — auto-sets natural mode + 1000ms delay |
filmstrip |
Capture SVG animation as multi-frame composite strip |
diff |
Visual diff between two SVG/HTML versions — returns diff image + percentage |
- Create your SVG with CSS
@keyframesanimations - Render with
naturalmode to see what users actually experience - Use
filmstripto verify animation timing frame by frame - Iterate until perfect, then ship
# Render all SVGs and check for console errors
for svg in assets/*.svg; do
curl -s -X POST http://localhost:3700/render \
-H 'Content-Type: application/json' \
-d "{\"code\": $(jq -Rs . < "$svg")}" \
-D - -o /dev/null | grep X-Console-Errors
done# Diff before and after an SVG change
curl -X POST http://localhost:3700/diff \
-H 'Content-Type: application/json' \
-d "{\"before\": $(cat before.svg | jq -Rs .), \"after\": $(cat after.svg | jq -Rs .)}"With the MCP server, your AI coding agent can:
- Create animated SVGs from text descriptions
- Render them immediately to verify the visual output
- See what's wrong and fix it in the same conversation
- Use filmstrip to verify SVG animation timing
- Iterate until the animation is perfect — no more blind SVG coding
svgshot/
src/
server.js — Express REST server (port 3700)
mcp.js — MCP stdio server (4 tools)
renderer.js — Core Playwright engine + filmstrip
differ.js — Pixel diff (pixelmatch)
package.json
start.sh — Start REST server
mcp.sh — Start MCP server
LICENSE — Apache 2.0
- Shared browser instance — Playwright Chromium reused across requests
- 2x device scale — Retina-quality SVG screenshots by default
- Auto-detect format — SVG, HTML snippets, and full HTML documents handled automatically
- Tailwind CDN — Included by default for HTML snippet rendering
- Graceful shutdown — Clean browser teardown on SIGTERM/SIGINT
- Node.js 18+
- Playwright Chromium (
npx playwright install chromium)
Apache License 2.0 — see LICENSE for details.
Built for the animated SVG creator community — because animated SVGs deserve screenshots that actually show the animations.