Stunning SVGs.

Kurviq gives coding agents the tools to trace, compose, animate and verify SVG, so what they ship actually works.

Animated, interactive and traced. Browse the examples, or view the source.

A pixelated ink shape resolving into a bird built from smooth curves and control handles
One command
npx kurviq --input in.png --output out.svg --auto
Runtime deps
0
Engine
Wasm
Node.js
18+

Turn pixels into curves right here.

Drop in a PNG or JPEG, choose a recipe, and Kurviq returns an SVG without uploading your image anywhere.

Drop an image here

PNG or JPEG, up to 8 MB

Choose one PNG or JPEG no larger than 8 megabytes.

No image selected

Tracing recipe

SVG outputYour traced result will appear here.

Select an image to begin.

Images never leave your browser.

Built for the agents you already use

  • Claude Code Claude Code
  • Cursor Cursor
  • OpenCode OpenCode
  • Codex Codex

Each mark above is the official logo, traced by Kurviq and checked against the original: mean error under 2 of 255, with fewer than 1.6% of pixels differing by a noticeable amount. Logos are the property of their respective owners.

Built for pipelines, not dialogs.

Repeatable, scriptable, cacheable. The same bytes on every run, and a way to prove it rather than hope.

01

Byte-stable

Repeated runs are byte-identical when the input bytes, options, Kurviq version, and platform are unchanged. Cache and review generated assets with confidence.

02

Self-contained Wasm

The vector engine ships with the package. There is no separate native executable to install and no runtime dependency tree to pull into production.

03

CLI and Node API

Use the command line in asset scripts, or call the synchronous CommonJS API with a Buffer or Uint8Array. The same options apply in both surfaces.

Recipes for difficult pixels. Primitives for everything else.

Start with defaults and add one deliberate correction for the source you have, or skip tracing entirely and compose the SVG yourself.

kurviq/author

Author, do not just trace

Build gradients, patterns, real strokes and markers, clips, masks, filters, interaction states and animation deterministically, then verify each one by rendering it. Zero dependencies.

--auto --explain

Let it pick the recipe

--auto traces once, classifies the source, and re-traces with a matching recipe. --explain prints the decision and the exact flags, and those flags reproduce the run byte for byte, so you can pin them and drop --auto.

--consolidate · --snap

Output you can edit

A default trace of a detailed source can carry tens of thousands of near-identical colors. --consolidate merges them perceptually; --snap emits real circles and rects; --structure adds stable ids and classes.

--theme css-vars

Theme it after the fact

The recovered palette becomes CSS custom properties, so one traced asset serves light and dark. The rules sit behind an opt-in class, so renderers without custom-property support are unaffected.

--animate reveal

Draw itself on arrival

A CSS-only entrance animation, staggered per group, that respects prefers-reduced-motion and always renders the correct static frame in tools that do not animate.

invisible text layer

Keep the text selectable

Text lines are located from the traced geometry, then an invisible text layer is laid over the artwork for selection, search and screen readers. The visible art never changes, so a bad reading cannot corrupt the image. Recognition is a network call, not part of the core.

--upscale · --max-size

Right-size before tracing

--upscale 2 gives small labels and fine edges more working pixels; --max-size 720 caps oversized renders before they bloat the SVG. Both preserve the display size.

--remove-background auto

Remove real backgrounds

Border-connected removal handles uniform cells and attached neutral shadows, with channel protection for narrow gaps and near-white artwork.

--alpha-mode auto

Handle soft alpha

Auto mode detects meaningful partial transparency, resizes alpha-aware, and thresholds the result without letting hidden RGB bleed into the trace.

--sharpen

Sharpen flat artwork

Recover a compact palette from blurry icons before vectorization. The bare flag uses at most 12 colors and stays deterministic.

--mode spline

Fit smooth splines

A tested spline recipe keeps rounded icon contours smooth without over-segmenting every anti-aliased edge.

--gradient_step 8

Preserve gradients

Smaller gradient steps and full color precision retain soft shading when visual fidelity matters more than the smallest possible SVG.

Why not potrace, vtracer, or Image Trace?

All three are reasonable choices. Here is where each one wins, and where Kurviq does.

potrace

Different job.

potrace traces one colour, and it is very good at that. Reach for it on black-and-white line art. Kurviq is built for colour raster art, where the work is clustering and curve fitting, not thresholding.

vtracer

Kurviq is a patched vtracer.

Same lineage, compiled to Wasm so there is no binary to install. Against upstream 0.6.12 on our 10-image corpus: 2.15x faster, DSSIM halved, and 61% smaller output.

Illustrator Image Trace

A dialog, not a step.

Hard to beat with a human in the loop and an eye on the preview. It cannot run in CI, and it does not promise you the same bytes twice.

What that looks like on a real library

A tester traced 72 production assets and kept a trace only where it scored ≥ 0.94 with no size increase. 27 of 72 qualified, replacing 507 KB of WebP with 403 KB of SVG. Flat illustration scored 0.98 to 0.99 and came out around a third of the WebP size. Photographs, pixel art and dense diagrams were rejected.

So more than half of a mixed library should not be traced, and the only way to know which half is to render and compare. That is what the toolbelt is for.

What it will not do

  • Text becomes curves by default. The selectable text layer calls a vision model over the network, so it sits outside the deterministic core, and no mode recovers the original font.
  • Photographs score 0.857 and pixel art 0.767. Continuous tone fragments into thousands of fills. Flat, low-colour art is the target.
  • Dense diagrams come out bigger: 663 KB of SVG against 459 KB of WebP on one real page. Size is a tradeoff you choose, not a score.
  • Determinism is per version and platform. Same input, same options, same Kurviq, same bytes.

Drag across raster and SVG.

Real Kurviq traces, from a small outline icon to a full diagram. File sizes are the source files shown. The examples page also has pieces built with no raster at all.

Illustrations traced by Kurviq itself.

See all 20 examples →
Agent Loop Diagram, raster input Agent Loop Diagram, traced SVG output PNG SVG
PNG: 651.1 KB SVG: 172.1 KB

Agent Loop Diagram

A dark neon diagram: --upscale 2 keeps the dashed radar rings and tick marks that a plain trace loses, then --consolidate 48 holds the file to 156 KB.

Robot Fox Sticker, raster input Robot Fox Sticker, traced SVG output PNG SVG
PNG: 405.6 KB SVG: 219.8 KB

Robot Fox Sticker

A die-cut mascot lifted from a magenta chroma card: bold outlines, small details, and the white keyline survive.

Accessibility, outline icon, raster input Accessibility, outline icon, traced SVG output PNG SVG
PNG: 161.2 KB SVG: 8.1 KB

Accessibility, outline icon

Thin strokes and enclosed shapes after background removal.

One package to make it. One to prove it.

kurviq traces and authors with zero runtime dependencies. @tecsteps/kurviq-toolbelt adds the renderer, so verification never becomes a dependency of conversion.

CLI

Terminal
npm i kurviq
npx kurviq --input in.png --output out.svg --auto

# verification, kept in a separate package on purpose
npm i @tecsteps/kurviq-toolbelt

Node API

JavaScript
const fs = require('node:fs');
const { convert } = require('kurviq');
const { createScene, shapes } = require('kurviq/author');
const { evaluate } = require('@tecsteps/kurviq-toolbelt');

// trace
const traced = convert(fs.readFileSync('in.png'), { upscale: 2 });

// or author, with no raster at all
const scene = createScene({ width: 320, height: 180 });
scene.add(shapes.circle(160, 90, 64, { fill: '#22d3ee' }));

// then prove it: render, compare, check the target
const { report } = evaluate({ svg: scene.serialize(), width: 320 });

Hand it to your coding agent

Installs both packages, checks the install actually worked, and writes a local skill with the rules that are not guessable from the API.

Paste into your coding agent
Set Kurviq up in this workspace as a reusable skill.

1. INSTALL
   npm i kurviq
   npm i -D @tecsteps/kurviq-toolbelt        # rendering + verification; dev-only on purpose

2. VERIFY THE INSTALL - do not skip this, and do not proceed if it fails.
   node -e "
     const {convert} = require('kurviq');
     const a = require('kurviq/author');
     const v = require('kurviq/package.json').version;
     if (typeof convert !== 'function') throw new Error('kurviq root API missing');
     if (!a.createScene) throw new Error('kurviq/author missing - need >= 1.3.0, got ' + v);
     console.log('kurviq', v, 'ok');
   "
   If kurviq/author is missing, STOP and tell me the installed version.

3. WRITE A SKILL to .claude/skills/kurviq/SKILL.md covering:
   - tracing: convert() and npx kurviq --auto --explain, and that the printed
     flags reproduce the run byte-for-byte
   - authoring: kurviq/author, -paint, -stroke, -mask, -filter, -interactive,
     -animate
   - the rules that are NOT guessable from the API:
     * paint-server and mask units are mandatory; the SVG default differs per
       element and silently changes the result
     * filter regions are mandatory; the default clips blurs and shadows
     * an <img>-embedded SVG gets NO pointer events, so :hover is dead markup
       there - assertEmbedding() and inline the SVG instead
     * animate with the initial state only in the keyframes, fill-mode
       backwards, or a non-animating renderer paints a blank image
     * never score a background-removed SVG against its source raster
   - verification: evaluate({svg, referencePng?, states?}) and
     validateTarget(svg, profile)
   - measured resvg limits: custom properties render black, animation never
     executes, pathLength is ignored, mask-type:alpha falls back to luminance

4. CONFIRM by listing the file and printing the version you installed.

Without it, agents default paint-server units, omit filter regions, and put hover states in an <img> where they can never fire. Ships as docs/AGENT-SKILL.md.