Skip to content

Replace webfont stroke-to-outline pipeline with unstroke - #1602

Merged
codecalm merged 1 commit into
mainfrom
unstroke
Sep 18, 2026
Merged

codecalm merged 1 commit into
mainfrom
unstroke

Conversation

@codecalm

Copy link
Copy Markdown
Member

Summary

  • The webfont build now converts stroked icons into filled outlines with unstroke (outlineSvg) instead of svg-path-outline + paper.js + the custom splitPaths / reorientPath / mergePaths helpers.
  • Every glyph is a single unioned path with no self-overlaps, which makes TTF files ~36% smaller and fixes glyphs that lost their filled areas (e.g. the whole percentage-* family rendered as an empty circle).
  • Dropped dependencies: svg-path-outline, paper-jsdom, canvas, @napi-rs/canvas, svg-path-commander. The root onlyBuiltDependencies: ["canvas"] entry is gone too, so install no longer builds native canvas.
  • icons-outlined cache and the filled font are unchanged.

Benchmark (build time, sizes, pixel diff against the source SVGs) is in the comment below.

Test plan

  • pnpm --filter @tabler/icons-webfont run build:webfont with a cold cache
  • Rasterized all 5130 glyphs of the 400 and 200 fonts and compared them with the original stroked SVGs

Use the unstroke package to convert stroked icons into filled outlines
for the webfont build instead of svg-path-outline + paper.js. The output
is a single unioned path per glyph, so TTF files are ~36% smaller and the
build no longer needs canvas, paper-jsdom or svg-path-commander.
@vercel

vercel Bot commented Sep 16, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
tabler-icons Ready Ready Preview Sep 16, 2026 11:48pm UTC

Request Review

@codecalm

Copy link
Copy Markdown
Member Author

Benchmark: before (main, c6d8a78) vs after (this branch)

Full build:webfont with a cold icons-outlined cache, 3 stroke weights × 5130 outline icons, Node 24, Apple Silicon.

Build time

before after
stroke → outline conversion, per weight 12.4 s 4.7–6.4 s
whole build:webfont (conversion + font generation) 62.5 s 38.9 s

Output size

before after
icons-outlined/400 25.3 MB 20.1 MB
tabler-icons.svg (font) 33.5 MB 15.6 MB
tabler-icons.ttf 2772 KB 1764 KB
tabler-icons.woff 776 KB 752 KB
tabler-icons.woff2 452 KB 492 KB
tabler-icons-300.ttf / .woff2 2820 KB / 444 KB 1780 KB / 496 KB
tabler-icons-200.ttf / .woff2 2788 KB / 440 KB 1780 KB / 504 KB

Note on woff2: it is ~9% larger despite the much smaller TTF. The old glyphs were built from many overlapping rectangles and arcs that Brotli compressed very well; a single unioned, curve-fitted path is less repetitive. If woff2 size matters more than TTF size, precision / cornerAngle options in unstroke are worth tuning.

Accuracy: font glyphs rasterized at 96 px vs the original stroked SVGs

before after
mean mismatched pixels, weight 400 0.143 % 0.003 %
mean mismatched pixels, weight 200 0.153 % 0.001 %
icons off by > 1 % (400) 125 1
icons off by > 0.5 % (400) 178 4
worst icon (400) percentage-100: 35 % brand-parsinta: 4.3 %

The old pipeline dropped filled areas: every percentage-* glyph rendered as an empty circle instead of a filled sector, and mood-tongue-wink* / mickey had wrong overlaps. The new output reproduces them. The only remaining outlier is brand-parsinta, whose arc has opacity=".5"; a font cannot express that and the old pipeline had the same 4.3 % there.

@github-actions

Copy link
Copy Markdown
Contributor

✅ All icons are valid!

@codecalm
codecalm merged commit f738085 into main Sep 18, 2026
5 checks passed
@codecalm
codecalm deleted the unstroke branch September 18, 2026 19:28

This branch was successfully deployed

1 active deployment
Preview — ea0e7f2d Deployed Sep 16, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant