sketchyicons

Adding a hand to Lucide's geometry

Lucide draws arrow-right with the path M5 12h14. Fourteen units of perfectly horizontal line. The generator turns that into a curve, and doing the same thing to the other 7,026 paths in the catalogue is the entire library.

Straight runs bow

A line command becomes a quadratic with one control point, pushed off the chord along its normal. That is the move your eye reads as a hand, and it is the only one that matters at a glance.

arrow-right, the horizontal stroke
lucide    M5 12h14
sketchy   M5 11.99Q12 11.56 18.81 11.93

The control point lands at 12 11.56, four tenths of a unit above a chord that runs at roughly y=11.96. On a 24 unit grid that is small enough to stay a line and large enough to stop being a ruler.

How far it swings is bounded twice. It grows with the run, at 0.35 + min(length * 0.14, 1.5), and then it is capped at half the run's own length. Without that second cap a two unit stroke could bow further than it is long, which reads as a mistake rather than as a hand.

Coordinates drift

Every vertex then moves. The amplitude starts at 0.6 units and scales down with the shorter of the two runs meeting at that point, reaching full amplitude at a run length of 2.4 units.

That ratio exists because a coordinate that wanders further than the run it belongs to is not that run drawn by hand, it is somewhere else. Short segments are exactly where an icon set falls apart, and they are the ones a fixed displacement ruins first.

Some subpaths are held to the ruler

A subpath made only of straight commands gets a fraction of the amplitude, 0.21 of the drift and 0.24 of the bow. Crosses, chevrons and arrows keep their geometry while the rest of the icon wobbles.

circle-plus, 72 px24 px15 px
The circle carries the hand. The plus inside it barely moves, because a cross whose arms are not square stops reading as a plus and starts reading as a rendering bug.

Curves change fullness instead

A path that already curves has nothing to bow. Its control points move along the line that joins them to their anchors, by up to 0.16 of that distance, so the curve comes out slightly fuller or slightly flatter than it went in.

Closing strokes get one more thing. A Z that lands exactly where the subpath began is the one move a hand never makes, so the closing point is allowed to carry past its start by up to 1.25 times the drift.

Everything is clamped to the frame

After all of that, each coordinate is clamped back inside the icon's own bounding box. A glyph that grows by half a unit while its neighbours do not is a glyph that no longer lines up in a toolbar, and lining up is most of what an icon set is for.

16 px24 px48 px96 px

Where the numbers live

None of these constants were picked by eye alone. They are written down in the generator with the reasoning next to them, and an icon a human looked at and rejected goes into an overrides file with a required note saying why. There are only a handful of those.

The other half of this is that running the generator twice produces the same files, which is what the next post is about. Or go and look at the output, which is the only argument that really counts here.

Keep reading