Convert animated GIFs to animated SVGs.
framesvg is a web app, command-line tool, and Python library that converts animated GIFs into animated SVGs. It leverages the power of VTracer for raster-to-vector conversion, producing smooth, scalable, and true vector animations.
This is a significant improvement over embedding raster images (like GIFs) directly within SVGs, as framesvg generates genuine vector output that plays automatically and scales beautifully. Ideal for readmes, documentation, and web graphics.
- Features
- Examples
- Installation
- Usage
- Configuration & Options
- API Reference
- Optimization Guide
- Development
- True Vector Output: Creates scalable vector graphics, not embedded rasters.
- Automatic Playback: Generated SVGs play automatically in browsers and image viewers.
- Network Efficiency: SVGs are text-based. When served with Gzip or Brotli compression, they can load significantly faster than GIFs.
- Flexible Tooling: Available as a Web App, CLI tool, and Python library.
- Highly Configurable: Fine-tune the vectorization process (speckle filtering, smoothing, color precision) to balance quality vs. file size.
- Variable Frame Rate Support: Preserves the specific duration of each frame from the original GIF.
Note: You can view a live comparison gallery on the Examples Page.
| Original GIF | Converted SVG |
|---|---|
![]() |
|
![]() |
|
![]() |
|
![]() |
| Original GIF | Converted SVG |
|---|---|
![]() |
|
![]() |
These examples use the binary color mode. All bright colors turn transparent. (If they appear dark here, it is due to the transparency on a dark background; they look correct on light backgrounds).
| Original GIF | Converted SVG |
|---|---|
![]() |
|
![]() |
pip install framesvgOption 2: Using pipx (Recommended for CLI use)
If you only need the command-line tool, pipx installs it in an isolated environment.
pipx install framesvgBasic conversion:
framesvg input.gifSpecify output filename and force 24 FPS:
framesvg input.gif output.svg --fps 24Optimize for file size (High filtering, low precision):
framesvg input.gif --filter-speckle 10 --color-precision 4 --mode polygonfrom framesvg import gif_to_animated_svg_write, gif_to_animated_svg
# 1. Convert and save directly to a file
gif_to_animated_svg_write("input.gif", "output.svg", fps=30)
# 2. Get SVG content as a string (useful for web apps)
svg_content = gif_to_animated_svg("input.gif")
print(f"Generated SVG size: {len(svg_content)} bytes")
# 3. Advanced: Custom VTracer options
options = {
"mode": "spline", # Smoother curves
"filter_speckle": 2, # Keep more detail
"colormode": "binary" # Black and white
}
gif_to_animated_svg_write("input.gif", "artistic.svg", vtracer_options=options)These options control the VTracer engine. Tweak these to balance Visual Fidelity vs. File Size.
| Flag | Option | Default | Description |
|---|---|---|---|
-f |
--fps |
None | Animation speed. Defaults to GIF frame delays; falls back to 10. |
-c |
--colormode |
color |
color (standard) or binary (threshold-based transparency). |
-m |
--mode |
polygon |
polygon (smaller files), spline (smoother curves), or none. |
-s |
--filter-speckle |
4 |
Crucial. Cleans up noise. Higher = smaller file, less detail. |
-p |
--color-precision |
8 |
Bit-depth of colors. Lower = fewer colors, smaller file. |
-d |
--layer-difference |
16 |
Gradient threshold. Higher = fewer layers, smaller file. |
-i |
--hierarchical |
stacked |
stacked (shapes on top of others) or cutout. |
--corner-threshold |
60 |
Minimum angle to be considered a corner. | |
--length-threshold |
4.0 |
Minimum path length to render. | |
--splice-threshold |
45 |
Angle threshold for splitting splines. |
def gif_to_animated_svg(
gif_path: str,
vtracer_options: dict | None = None,
fps: float | None = None
) -> strReads a GIF file and returns the animated SVG content as a string.
gif_path: Path to the source GIF.vtracer_options: A dictionary of VTracer parameters. Keys correspond to the CLI flags above, but use underscores instead of hyphens (e.g.,filter_speckle,color_precision).fps: Force a specific frame rate. IfNone, uses the GIF's original frame delays.
def gif_to_animated_svg_write(
gif_path: str,
output_svg_path: str,
vtracer_options: dict | None = None,
fps: float | None = None
) -> NoneReads a GIF file, converts it, and saves the result directly to output_svg_path.
Vectorizing complex raster images can result in large files. Here is how to keep file size under control:
- Increase Speckle Filter (
-s): This is the most effective setting. Try increasing it to10or higher to remove small "dust" artifacts. - Use Polygon Mode (
-m polygon): Splines look smoother but require more data. Polygons are often sufficient for animation and significantly smaller. - Reduce Color Precision (
-p): Dropping this to6or4reduces the palette size, merging similar colors. - Simplify the Source: If possible, reduce the noise or dither in the source GIF before converting.
Tip: Use the VTracer Online Demo to visualize how these parameters affect a single frame before converting the whole animation.
We use Hatch for dependency management.
# Install Hatch
pip install hatch
# Run tests
hatch test
# Format and Lint
hatch fmtThe web interface is built with vanilla HTML/JS and Python serverless functions (Vercel).
- Install Vercel CLI:
npm install -g vercel - Run Locally:
Note: Set the root directory to
vercel dev
./webwhen prompted.
Contributions are welcome! Please submit pull requests or open issues on the GitHub repository.
MIT License Β© 2025 Romelium







