Inkvec Trace (raster to SVG)
Turning a generated logo into an SVG file you can actually ship
- image
- mask
- svg
- preview
- mask
"Flux is terrific for quickly generating logos" is a true sentence right up until somebody asks for the file. On the thread where that was posted, the comment that stuck was a guy who'd generated a logo he wanted to use for his company, then realised it needed to be a vector - "then it was on to illustrator." That's the gap Inkvec Trace closes: Recraft is the one commercial generator that emits SVG natively, so everywhere else, ComfyUI included, you generate a raster and convert afterwards.
What it actually is
Inkvec Trace is a thin ComfyUI wrapper around Inkvec, LogoLabs' raster-to-SVG tracer. Not a diffusion model doing something that looks like tracing - a purpose-built vectoriser for flat artwork: logos, icons, diagrams, stickers, UI graphics. Photographs are outside its design scope, and one test run shows you why: banding, hundreds of near-identical paths, a file bigger than the PNG.
Under the hood it shells out to the native inkvec Rust binary, so the tracer's behaviour is the binary's behaviour.
How it works
The tracer reduces your image to a palette of at most colors inks, merging any two colours closer than merge in OKLab - the "these are the same colour" knob, and why a JPEG-ish gradient collapses into a handful of flat fills instead of a mess. Then it fits geometry to each ink region.
precision is where the real dial is. It sets the MDL cost of a coordinate, lambda = ln(extent / precision): smaller keeps more detail with more points. Despite the name it does not control output decimals - coordinates are always written with two. min_area throws away specks below that many square pixels, your despeckle for noisy input.
Defaults are the CLI's own, and the node passes every numeric widget explicitly, so what you see is what runs.
Inputs that matter
image- the raster. Anything overmax_dim(2048) on its long side is traced at 2048 while the SVG is still written at the original size. Nice default, but a 6K scan is then fitted from a downscaled view; raisemax_dimif hairlines vanish.mask- transparency, LoadImage's convention (1 = transparent). Connect LoadImage'sMASKand holes survive into the SVG. A segmentation mask is the other way round: run Invert Mask first.lossy- noise-aware intake for compressed input. The trap: the CLI'sautosniffs the file type, but ComfyUI hands the node decoded pixels, written as PNG, soautobehaves like a PNG here. Set itonfor JPEG/WebP sources and anything from Inkvec Denoise.
native_alpha (on, inkvec 0.1.4+) traces transparency properly - inks carry opacity, holes stay holes, so white artwork on transparency survives. Leave it on. no_background drops the face covering the whole canvas, which is how you get artwork on transparency. content_units is the one to watch: it scales fit tolerances to the raster, which is great for parameter count and will absolutely turn a small square into a circle. timeout_sec (300) is the node's own; extra_args appends raw CLI flags last, overriding the widgets.
Outputs
svg is a STRING and a list - one string per image in the batch, so downstream nodes run once per image. Wire it straight into Inkvec Save SVG.
preview is the traced SVG rendered back to pixels and mask is that render's transparency (1 = transparent), so preview + mask through Join Image with Alpha gives you RGBA. Both need resvg-py or cairosvg; with no renderer installed the node passes the input image through and logs a note instead of failing.
Install
ComfyUI Manager: search "Inkvec" (publisher logolabs-org) and install, then restart. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/logolabs/inkvec-comfyui.git
pip install -r inkvec-comfyui/requirements.txt
On the Windows portable build, use python_embeded\python.exe -m pip install -r inkvec-comfyui\requirements.txt. The requirements are resvg-py, onnxruntime, huggingface_hub and einops; torch, numpy and Pillow already ship with ComfyUI.
The first trace downloads the inkvec binary for your platform from the project's GitHub releases (about 2 MB), verifies it against the release SHA256SUMS, health-checks it with inkvec --version, and caches it in ComfyUI/models/inkvec/<version>/. It is not updated automatically - delete that folder to pull a newer release. Offline, grab the archive yourself and point INKVEC_BIN at the executable.
Where people get burned
A big image times out and looks like a hang. Trace cost grows with pixel count. The node errors after timeout_sec, and the fix menu is in that message: raise timeout_sec, lower max_dim, or set time_budget - a budget expiry still gives a correct, slightly rougher trace rather than nothing.
A proxy or antivirus eats the binary. Downloading and running an executable on first use is the one part of this pack that security software objects to. If it fails, the error tells you to fetch the file by hand and point INKVEC_BIN at it.
The widgets and the binary disagree. native_alpha and content_units need inkvec 0.1.4; flip one on an older cached release and the CLI reports an unknown option. Re-download the binary (INKVEC_VERSION=0.1.4 pins it if you want it locked).
Text is traced as outlines, never as <text> - fine for a logo, surprising if you wanted selectable type. And if the source is a photograph, stop: vectorisation wants flat art, and no amount of dial-turning changes that.
Inputs (19)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| precision | FLOAT | 0.100.01–10 | Sets the MDL cost of a coordinate: lambda = ln(extent / precision). Smaller keeps more detail with more points. It does not set the digits the emitter writes; output coordinates are fixed at 2 decimals. CLI --precision. |
| min_area | FLOAT | 2.00–10000 | Discard features below this area, in px^2. CLI --min-area. |
| colors | INT | 641–4096 | Maximum palette size. CLI --colors. |
| merge | FLOAT | 0.0350–0.5 | OKLab distance below which two colours are one ink. CLI --merge. |
| max_dim | INT | 20480–16384 | Inputs larger than this on their longer side are traced at this size and the SVG is written at the original size. Trace time grows with the pixel count. 0 means no cap. CLI --max-dim. |
| time_budget | FLOAT | 0.00–3600 | Advisory wall-clock budget in seconds. When it runs out the output is still a correct trace, with more fills or a less polished outline. 0 means no budget. CLI --time-budget. |
| margin | FLOAT | 0.000–0.5 | Transparent margin around the output, as a fraction of the larger side; the viewBox grows, the geometry does not move. CLI --margin. |
| cutout | COMBO | auto | Carry the input's transparency into the SVG: transparent areas stay holes, a shape drawn at one opacity keeps fill-opacity, and white artwork on a transparent ground survives. auto = on when the image or the mask input has any transparency, off for opaque images. Inkvec 0.1.4 traces transparency natively (native_alpha), which already carries it out, so there this only matters with native_alpha off; on 0.1.3 and older it is what keeps the holes, which is why auto passes it for any transparent image. CLI --cutout. |
| no_background | BOOLEAN | false | Knock the background out: the face that covers the whole canvas is not painted, so the artwork sits on transparency. CLI --no-background. |
| minify | BOOLEAN | false | No ids or groups, no trailing zeros. Same geometry, typically about a tenth smaller. CLI --minify. |
| lossy | COMBO | auto | Noise-aware intake for compressed input. The CLI's auto reads the file type, but ComfyUI hands the node decoded pixels (written as PNG), so auto behaves like a PNG here. Set on for JPEG/WebP sources and for images from Inkvec Denoise (inkvec --restore does the same). CLI --lossy. |
| harmonize | BOOLEAN | true | Shape harmonization (the CLI default: on). Marks that repeat across the drawing are matched by outline similarity and redrawn from one consensus geometry per cluster, which saves parameters on repetitive art. A mark takes the consensus only where that stays within 0.1 px of the boundary traced for it and costs fewer parameters; a face another face is drawn against, and a fitted circle or rounded rectangle, is never moved. Turn it off to skip the pass. CLI --harmonize. |
| harmonize_threshold | FLOAT | 0.920–1 | Shape-equivalence IoU threshold for harmonization. CLI --harmonize-threshold. |
| native_alpha | BOOLEAN | true | Trace transparency natively: each ink carries an opacity and the transparent ground is an ink of its own -- holes stay holes, glows and shadows stay translucent, and white artwork on a transparent ground traces. An opaque image traces the same either way, so leave it on. Off composites onto a matte first, as inkvec releases up to 0.1.3 did. Needs inkvec 0.1.4; an older binary reports --no-native-alpha as an unknown option. CLI --native-alpha. |
| content_units | BOOLEAN | false | Scale the fit tolerances with the raster, so a large, simple drawing gets the parameter count of a small one. Trades fidelity for parsimony: small squares can come back as circles and thin rings broken. Needs inkvec 0.1.4. CLI --content-units. |
| timeout_sec | INT | 3005–7200 | The node stops the tracer after this many seconds and reports an error. |
| maskopt | MASK | Transparency, as LoadImage outputs it (1 = transparent). A mask where 1 marks the subject must be inverted first (InvertMask). | |
| extra_argsopt | STRING | Further inkvec flags, appended last so they override the widgets, e.g. --strokes or --layers. A flag the installed binary does not know is reported as an error. -o/--output/--help/--version are not allowed. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| svg | STRING | The SVG source, one string per image in the batch. |
| preview | IMAGE | The SVG rendered back to pixels (needs resvg-py or cairosvg; otherwise the input image). |
| mask | MASK | Transparency of the rendered SVG, 1 = transparent (LoadImage's convention). |