🎨 CSS

SVG Stroke to Fill Converter

Paste an SVG path's d attribute, set the stroke width, and get a filled-shape version of the same path.

STROKE (INPUT)
FILL (OUTPUT)

How This Works

It walks 200 points along your path, offsets each one perpendicular to the direction of travel, and stitches the two resulting edges into a closed outline. That approximation holds up well for smooth, simple paths like icons, logos, or blob outlines, though very sharp corners can come out slightly rounded instead of mitered.

It borrows the browser's own geometry engine instead of reimplementing curve math

Converting a stroked path into a filled outline requires knowing exactly where every point along that path sits, including on curved bezier and arc segments, which is genuinely nontrivial math to reimplement from scratch. Rather than parsing and solving that curve geometry itself, this tool creates a temporary, invisible <svg> and <path> element (positioned absolutely, zero opacity, appended to the page only briefly), sets your path data on it, and then calls the browser's own native getTotalLength() and getPointAtLength() methods, standard SVG DOM APIs every browser already implements to answer exactly this question. It's effectively using the browser as the path-math engine, then discarding the temporary element once it has the measurements it needs.

The step-by-step offset algorithm

At each of 200 evenly-spaced points along the path's total length, the tool estimates the local direction of travel by sampling two nearby points slightly before and after it and finding the vector between them, a standard finite-difference approximation of the curve's tangent at that spot. That tangent is normalized to a unit vector, then rotated 90 degrees to get the perpendicular "normal" direction (swapping the x and y components and negating one, (-dy, dx), is the standard shortcut for rotating a 2D vector a quarter turn). Each sample point is then offset by half the stroke width along that normal in both directions, building two parallel lists of points, one for the outer edge of the stroke, one for the inner edge.

Why the inner points get stitched in reverse order

The final path walks through every outer-edge point in order, then walks through every inner-edge point in reverse order, before closing back to the start. That specific direction flip is what keeps the resulting shape a clean, non-self-intersecting ribbon rather than a bowtie or figure-eight, if both edges were stitched in the same direction, the closing segment would have to cross back across the entire shape to connect them, creating a self-intersecting path that would fill incorrectly.

Why very sharp corners round off slightly

This whole technique is a point-sampling approximation of a true mathematical offset curve, and offset curves of bezier curves are a genuinely hard problem in computational geometry, the offset of a bezier curve isn't itself a bezier curve in general, which is exactly why real vector design software also relies on numerical approximation rather than an exact closed-form solution. At a sharp corner, the path's direction changes abruptly, but since this tool measures the tangent using nearby points at a fixed small distance, it smooths across that abrupt direction change rather than detecting a true discontinuity, producing a gently rounded corner in the output similar to how stroke-linejoin: round looks, rather than a crisp mitered point. For most icon and logo work with mostly-smooth curves, this is imperceptible, but a path with genuinely sharp 90-degree corners will show visibly rounded corners in the filled result.

Two things to check before using the copied path

First, the sample count is fixed at 200 points and isn't user-adjustable, this is a deliberate balance between accurately following curve detail and keeping the output path's data string from becoming excessively long and complex, higher sample counts add more anchor points to the path without meaningfully improving the visible result for typical icon-scale artwork. Second, the copied output always sets fill="#000000" regardless of what stroke color you were previewing, that's just a placeholder value, remember to change it to whatever fill color you actually intend to use in your project.

Frequently Asked Questions

How does this tool measure points along curved bezier paths without reimplementing curve math?

It creates a temporary, invisible SVG path element with your path data and calls the browser's own native getTotalLength() and getPointAtLength() methods, standard SVG DOM APIs that every browser already implements, then removes the temporary element once it has the measurements it needs.

Why does the output sometimes round off sharp corners instead of keeping them crisp?

The tool estimates direction by sampling nearby points at a small fixed distance, which smooths across abrupt direction changes at sharp corners rather than detecting a true discontinuity. This produces a gently rounded corner similar to stroke-linejoin: round rather than a mitered point.

Why are the inner-edge points stitched in reverse order in the final path?

Walking the outer points forward and the inner points in reverse is what keeps the resulting shape a clean, non-self-intersecting ribbon. Stitching both edges in the same direction would force the closing segment to cross the entire shape, creating a self-intersecting, incorrectly-filling path.

Can I change how many sample points the conversion uses?

No, it's fixed at 200 points. This is a deliberate balance between accurately following curve detail and keeping the output path's data string reasonably sized, since more points add complexity without meaningfully improving results for typical icon-scale artwork.

Why does the copied path always use fill="#000000"?

That's a placeholder value, not a reflection of your original stroke color. Since a filled path doesn't have a stroke color the way the preview does, you'll need to manually change the fill attribute to whatever color you actually intend to use.

Does this tool work on any SVG path, including ones with curves and arcs?

Yes, because it relies on the browser's native path length and point APIs rather than parsing path commands itself, it works on lines, bezier curves, and arcs alike, anything a valid SVG path d attribute can describe.