Changelog

One entry per engine release, newest first. What changed for your file, in plain words — and, where the committed benchmark measured that release, the figures it published.

Releases
18
Latest
0.3.17
Released
2026-08-28
Figures
3

Releases

01

A ramp’s own pair outranks a shade of it

0.3.17 · 2026-08-28

On JPEG artwork a pixel on a blurred ramp between two colours now goes to the pair that explains both its flanks, not to a nearby shade — the Swiss cross keeps its edge and the Japanese disc loses its ghosts.

A chroma-subsampled JPEG bows a colour ramp off the straight segment between its two ends, and where a third palette entry sat close to that bow the snap used to hand the ramp’s pixels to it — a paper-coloured rim along the Swiss flag’s white cross, a ring of codec ghosts around the Japanese flag’s disc. The pair whose segment explains both flanks of the pixel now outranks a shade of it, and the rule fires only where the raster’s ramps actually bow and only where the raster does not hold the chosen entry’s own bytes within the flank walk’s reach, so every PNG in every corpus is byte-identical.

The cost is small and named: one blurred low-contrast polygon at the smallest size draws its corners a fraction of a pixel rounder, and one emoji gains a second path of its paper colour that the eye does not find. The hairline reading stays held for a third round with its five candidates saved, and the large corpus’s worst cases turned out to be a share floor measured against the canvas rather than the ink, which is next.

Link to this release → #v0-3-17
Published figures
boundary error, p95
0.09 px
region-count error
0.000
node-count ratio
1.00×
Corpus
smoke (30 fixtures)
Checked
2026-08-28
Engine
0.3.17
Methodology and every figure/benchmarks
02

Closed paths stop drawing their closing line twice

0.3.16 · 2026-08-28

A closed shape no longer ends with a second line back to its start, so the file carries exactly the nodes the artwork has and an editor shows no duplicate anchor.

Every closed path the engine wrote ended with an explicit line back to its first point, and then closed — the same edge twice, which is the duplicate anchor point an editor shows at the start of a traced shape and one extra node on every rectangle, polygon and star. A measurement of where the surplus nodes on the benchmark sets came from found that this convention was all of it on the synthetic set, with every junction already arriving as a single vertex, so the closing line is now implicit. Nothing in the geometry moved; every render is byte-identical.

A second, much larger synthetic corpus is now committed and measured, with more shape kinds, palettes, hairlines and a larger canvas, and its first run names the engine’s weakest cases in order. The converter’s job ticket also reads the visitor’s plan, so a Pro customer no longer sees a free-preview stamp beside their queue.

Link to this release → #v0-3-16
03

Hairlines come back as strokes

0.3.15 · 2026-08-28

A thin line is read by its own width and ramp, so a script wordmark or a fine outline traces as one stroke instead of a row of dashes.

A hairline’s colour does not run the way a fill’s does — its coverage wobbles along the stroke with the pixel grid — and the ridge reader had been refusing it wherever the colour test failed, so a script wordmark came back in pieces and a blurred letter dissolved into the paper. Where the first reading refuses, the engine now asks a second in the ridge’s own terms: the pixel must be the deepest of its own cross-section, the run continues along the ridge’s ramp, and the width a couple of pixels along must match — a stroke has a width, a wedge has a rate. A crest that continues across a gap no longer than its own width is one crest, so corners and crossings no longer break a stroke, and a stroke that grows out of a fill of its own ink is one shape with it.

On JPEG input a fill cut into pieces by seams — a football’s body, a flag’s cross — is read as one fill before the palette decides whether it is real, so the body keeps its colour instead of merging into the paper. Pro accounts gained the batch queue in the converter, the site gained this changelog, and the preset table is now checked against the engine’s by a committed golden file.

Link to this release → #v0-3-15
04

Nothing in the file is drawn twice

0.3.14 · 2026-08-28

A shape painted the colour it already sits in is no longer written into the file as an invisible duplicate.

Layered output used to nest a same-coloured face inside the shape around it and write it out as a path of its own — invisible on screen, but a region in the file, with nodes of its own, that an editor finds the moment the shape above it is moved. Those faces are now left out, and so is a face whose fitted outline encloses nothing at all. Icons and logos with large flat fills come back leaner, with every visible shape still described exactly once.

Pro accounts also gained API keys with usage metering on the account page, and the palette editor in the converter.

Link to this release → #v0-3-14
05

The same artwork gives the same document

0.3.13 · 2026-08-28

A logo uploaded small, uploaded large or saved as a JPEG now traces to the same paths, the same nodes and the same colours.

A boundary that runs between two crossings of one circle is now drawn as that circle’s arc, exactly, instead of as a run of short curves hugging the pixels — so the size you upload at no longer decides the shape of the result. On JPEG input, a shade in the middle of a colour ramp is read as the ramp rather than as a third ink, which removes the spurious colours a chroma-subsampled file used to add along its strong edges. PNG uploads also trace faster, because a measurement introduced for JPEG artefacts is now skipped whenever no two colours are close enough for it to matter.

Link to this release → #v0-3-13
06

JPEG edges stop growing bands

0.3.12 · 2026-08-28

The overshoot a JPEG paints beside a strong edge is folded back into the fill it rang off.

Where two colours sit close together, JPEG compression rings on either side of the edge between them, and the tracer used to paint those rings as thin bands of the neighbouring colour. The engine now measures how far a raster’s edges overshoot their own flanks — nothing at all on a PNG — and dissolves the bands the codec left behind, so a smiley’s teeth or a football’s panels come back as the regions they are. Where the raster held nothing to measure at a junction, the curve leaving it is redrawn from the crossing’s own geometry, so the tip of a lens on a JPEG leaves cleanly instead of with a hook.

Link to this release → #v0-3-12
07

Phone photos trace upright

0.3.11 · 2026-08-28

The engine reads the EXIF orientation tag itself, so a rotated photo comes out the right way up wherever you trace it.

A phone stores a photo the way its sensor saw it and records the rotation in an EXIF tag, and the engine had been ignoring that tag while browsers honoured it — so the same file could trace upright on the site and sideways through the API or the command line. The tag is now read out of both JPEG and PNG containers and applied before the first pixel is examined, with every transform checked against what Chromium, Firefox and WebKit return for the same files. A file with no tag decodes exactly as it did before, so nothing else in the output moved.

Link to this release → #v0-3-11
08

The converter traces the file you gave it

0.3.10 · 2026-08-28

The browser had been colour-managing and clipping wide-gamut PNGs before the engine saw them; it now hands over the stored pixels exactly.

A PNG carrying a wide-gamut colour profile was being converted to sRGB and clipped by the browser’s decoder, which shifted a logo’s reds and oranges and — because every boundary is measured off the anti-aliasing ramp — cost geometry as well as colour. The converter now decodes with colour management and premultiplication off and reads the bitmap back exactly, so the site traces the same bytes the command line and the API do.

On JPEG input, the engine can now tell a codec’s duplicate of an ink — scattered in blocks across one fill — from a genuine second colour with a shape of its own, so the flat regions of a compressed logo come back as single fills again.

Link to this release → #v0-3-10
09

A JPEG’s block levels are one ink

0.3.9 · 2026-08-28

A JPEG stores one flat colour as a few nearly identical levels; the palette now reads them as the single ink they are.

Compression quantises each block of a JPEG on its own, so a flat fill arrives as a patchwork of levels a few units apart, and the tracer had been giving each level regions of its own. The engine now measures the lattice a raster holds its colours on — none on a PNG — and merges levels that sit one step apart, so a compressed logo comes back with the inks it was drawn in instead of a duplicate of each.

In cutout output, a hairline stroke is now cut out of the shape it lies on rather than painted over it, so the cutting and embroidery presets no longer produce double-painted areas or gaps along a thin line.

Link to this release → #v0-3-9
10

Corners land on the crossing of their sides

0.3.8 · 2026-08-28

A corner is placed where its two sides actually meet, a thin stroke comes back as a stroke, and JPEG input got a benchmark set of its own.

A raster bevels every sharp corner, so the samples along a star’s point stop short of the tip. Each side of a detected corner is now fitted to its own samples and the vertex placed on their crossing, checked against the depth the raster left out — so a star’s points and a triangle’s apex sit where the artwork put them. A stroke about a pixel wide is traced as a centreline with a width rather than as two ragged edges, wherever that reads better.

The engine also stopped assuming every upload is a clean PNG: it measures the raster’s own noise once and states every threshold in it. That changed nothing on PNG and is what made the JPEG work in the releases that followed possible.

Link to this release → #v0-3-8
11

Counters become holes

0.3.7 · 2026-08-27

The hole in an O is now part of the O — a second contour wound the other way — instead of a paper-coloured patch painted on top.

A tracer that stacks its output paints a counter as a background-coloured shape over the letter, which is what a designer finds on moving the letter aside in Illustrator. Each counter is now cut as a hole of the shape that has it, in every export format, so a letter can be moved, recoloured or cut as one object.

Corners at small sizes are found on the samples and put back on the crossing of their sides, and a colour the raster holds exactly over a flat area is treated as an ink however close it sits to the blend between two others — so a chequered flag keeps its greys and a football keeps its seams.

Link to this release → #v0-3-7
12

Lines and arcs by decomposition

0.3.6 · 2026-08-27

A boundary is broken into the straight lines and circular arcs it is made of, each one exact and tangent to the next at the join.

A rounded rectangle now comes back as four lines and four quarter-circle arcs rather than as a run of curves that only approximates them, and a D-shape’s long arc as one exact piece — geometry a cutter follows without stuttering and an editor can adjust by its radius. Low-contrast edges are now read against the raster’s own noise rather than against the pair of colours either side, so a hairline at any angle is traced as one stroke rather than as a row of dashes. Together, those two changes are what make a traced icon open in an editor as a handful of recognisable shapes rather than as a cloud of points.

Link to this release → #v0-3-6
13

Ridges and ramps in the palette

0.3.5 · 2026-08-27

A hairline earns its own colour, and a pixel in the middle of a blend can no longer claim a third one that is not there.

The palette stage now reads a short profile across each feature once and answers three questions with it: a stroke one pixel wide is a ridge and keeps its colour, a pixel whose profile runs between two colours is not confident about a third, and the coverage across a ridge is handed back to its crest. That is what stopped a blurred wordmark from vanishing and a chequered flag from gaining stripes of a grey it never had.

Every closed boundary is also cut clear of its corners before fitting, so a rectangle keeps all four corners instead of losing one to the point where the tracer happened to start walking.

Link to this release → #v0-3-5
14

Boundaries measured off the anti-aliasing ramp

0.3.4 · 2026-08-27

Every boundary sample is placed from the source’s own anti-aliasing to a fraction of a pixel, and every junction on the crossing of its curves.

The tracer stopped reading edges off the pixel grid: for every boundary it walks the source pixels across the anti-aliasing ramp and places the sample where the coverage says the edge is, which is exact at any sub-pixel position for a clean edge and still exact under blur or enlargement. Where three regions meet, the junction is now solved as the crossing of the arcs and lines that arrive there, so the tip of a lens is the intersection of its two circles rather than a blunt stub a pixel short of it. Discs come back at the radius the artwork drew them.

Link to this release → #v0-3-4
15

Exact circles, arcs and straight lines

0.3.3 · 2026-08-27

A boundary that is an arc of a circle comes out as that circle, and a straight run comes out as one line.

The fitter now recognises primitives: a run whose samples stay within tolerance of their chord is one straight segment, and a run a circle explains at least as well as its curves is written as exact arcs of that circle — so a whole circle costs the same few curves whatever size it was uploaded at, and a lens between two discs shares one coincident arc. A sliver pass dissolves the thin strips of a third colour that a two-colour snap leaves where two edges cross, which is what JPEG ringing had been turning into teeth at a lens tip. Junctions that arrive as a cluster of points are merged into one.

Link to this release → #v0-3-3
16

A ramp-aware palette and the optimal polygon

0.3.2 · 2026-08-27

The palette no longer invents a colour along an anti-aliased edge, and every boundary is fitted as the fewest straight pieces first and the fewest curves second.

Snapping every pixel to its nearest palette colour used to send the white-to-red edge of a logo to an orange that happened to lie between them, painting a ring around the disc that is not in the artwork. A pixel is now snapped only to a colour that borders it, and two near-identical colours merge on the evidence of their own pixels rather than on distance alone, so a pale field beside white paper survives. Boundaries are then fitted as the optimal polygon before the curves, and runs of smooth curves merge back into one wherever the result still describes the samples, so files come back with fewer nodes and cleaner edges.

Link to this release → #v0-3-2
17

Shared boundaries, EPS and DXF

0.3.1 · 2026-08-27

Two regions that touch now share one fitted boundary, so stacked layers coincide instead of leaving a rim or a hairline gap — and EPS and DXF export shipped.

Each region’s outline used to be fitted on its own, so two regions that touch were fitted twice from two polygons that disagreed by up to a pixel, and the layer under a disc showed as a rim around it, or as a white gap in cutout mode. Every boundary two regions share is now fitted once and handed to both, reversed where the second runs the other way, so the rim and the gap are gone in every export.

EPS for print workflows and DXF for cutters, plotters and engravers joined SVG and PDF as export formats, and a second benchmark corpus of real icons and emoji was added to keep the engine honest on artwork rather than on synthetic scenes.

Link to this release → #v0-3-1
18

Real curves instead of polylines

0.3.0 · 2026-08-27

The engine fits genuine cubic Bezier curves to every boundary, replacing the chain of short straight pieces that read as a polygon at any zoom.

The week-one tracer’s output was a chain of short straight segments with collinear handles, which looks like a polygon the moment you zoom in and carries several times the nodes an editor wants to see. The new fitter finds the corners, fits least-squares cubics between them and splits at the worst error, with smooth joins everywhere that is not a corner and a tolerance of a quarter of a source pixel. A traced logo now has a fraction of the nodes it had, and its curves are curves.

Link to this release → #v0-3-0