1500+ icons that look
hand drawn.
Nobody drew them. A generator takes Lucide's geometry and bends every line, seeded per icon so your build and mine produce it byte for byte. Same names, same props, so switching over is one import line.
- d1 M14.38 18.27C13.6 18.29 13.13 19.03 12.69 18.91Q8.84 19.41 4.85 18.61Q6.37 15.16 5.01 11.32C5.42 10.72 5.68 10.6 5.62 10.06Q10.21 8.38 12.33 3.61C13.33 2.16 15.87 1.07 17.74 2.33C19.62 2.22 21.49 3.75 21.84 6.19C21.96 7.94 21.64 11.44 19.94 12.27Q15.94 14.1 14.55 18.41
- d2 M15.98 7.97Q8.98 14.98 1.81 22.11
- d3 M17.46 14.92Q13.24 15.58 9.13 14.93
How the hand gets added
Two passes over the path data. Nothing is redrawn; the coordinates move. Below is feather, upstream on the left and published on the right, at the same size and the same stroke.
Where it starts
Exact coordinates on a 24 unit grid. Straight runs stay straight, which is what makes a generated set look generated.
Where it lands
Every straight run becomes a quadratic whose control point sits off the midpoint by a fraction of the run's own length. Then every coordinate moves. Both are seeded from the icon name, so the result is identical on every machine.
Chrome is quiet, content has a hand
A coordinate cannot wander further than the run it belongs to and still be that run, so tight shapes barely move. That is the point rather than a limitation: everybody knows exactly what a chevron looks like, so a shaky one reads as broken, while a feather can wander and still look deliberate.
Both of these are shipped geometry with the upstream original underneath. Nothing was tuned for this page.
- chevron-right
- barely moves
- feather
- wanders
It has to hold at 15 pixels
That is the size an interface actually uses inside a control, and it is where a wobbly stroke turns to mud. An icon that only reads at 24 is not finished.
rendered at 15, 20, 24, 40 px
| glyph | 15 px | 20 px | 24 px | 40 px |
|---|---|---|---|---|
| leaf | ||||
| compass | ||||
| flask-conical | ||||
| trophy |
1500+ icons, drawn
Search by name. Point at one and the plotter goes over it again.
93 shown, type to search all of them
- feather
- compass
- flame
- anvil
- leaf
- bird
- heart
- star
- trophy
- crown
- sparkles
- flask-conical
- book-open
- bookmark
- quote
- pen-line
- pencil-ruler
- ruler
- camera
- music
- coffee
- umbrella
- ticket
- fish
- globe
- map-pin
- rocket
- anchor
- moon
- sun
- cloud
- zap
- lightbulb
- magnet
- paperclip
- scissors
- package
- folder
- git-branch
- terminal
- key
- lock
- send
- message-circle
- bell
- calendar
- user
- telescope
- hammer
- shovel
- axe
- wrench
- drill
- tent
- mountain
- waves-horizontal
- snowflake
- sprout
- trees
- guitar
- drum
- piano
- mic-vocal
- radio
- headphones
- croissant
- ice-cream-cone
- pizza
- cake-slice
- wine
- beer
- shirt
- glasses
- watch
- footprints
- gem
- cat
- dog
- rabbit
- squirrel
- snail
- shell
- origami
- swords
- dices
- puzzle
- palette
- brush
- microscope
- atom
- dna
- orbit
Each glyph is its own file. Importing one icon pulls in one icon, and size-limit proves that in CI rather than assuming it.
The original underneath, in blue
The source geometry is the blue line, the drawn one sits on top of it. Every departure you can see is a coordinate that moved, and none of it is a redraw. How far it moves is the hand setting, noted under each one.
- leaf
- compass
- flask-conical
- trophy
The props you already pass
If Lucide is already in the project, the change is the import line. Nothing else about the call site moves.
import { Feather, Compass } from "@sketchyicons/react";
// same call site as before
<Feather size={20} strokeWidth={1.75} />- size
- number Width and height in pixels. Defaults to 24.
- color
- string Stroke color. Defaults to currentColor.
- strokeWidth
- number Defaults to 2. Thinner reads better above 32.
- fill
- string Read only by the glyphs that have a solid state.
One package per framework
Each target carries its own peer dependencies, so a Vue project never sees React in its tree. All of them are generated from the same geometry, so a glyph is identical whichever package you install it from.
- @sketchyicons/datapublished
The drawn geometry as JSON. No framework, no dependency, and the source every other package is generated from.
- @sketchyicons/staticpublished
One SVG file per icon, plus a sprite. This is the one you reach for from Flutter, SwiftUI, Figma or plain HTML.
- @sketchyicons/reactpublished
One component per icon, tree shakeable, with no runtime dependency.
- @sketchyicons/react-nativepublished
The same components on react-native-svg, which is the only peer dependency.
- vue, svelte, angular, solidnot yet
Additional generation templates over the same data. Not published yet.
- Zero runtime dependencies
- One peer dependency per target: react for the web package, react-native-svg for the native one. Nothing else.
- Byte identical rebuilds
- Two generator runs produce the same files. A test asserts it, so an upstream bump shows up as a reviewable diff instead of noise.
- One file per icon
- A barrel of 1500+ exports would undo your bundler's work. Tree shaking is measured in CI, not assumed.
- Lucide's own props
- size, color, strokeWidth and fill, forwarded to the SVG the same way. Migrating is one import line.
Your product does not have to look like everyone else's.
Most interfaces reach for the same set, and it shows. This one keeps the shapes people already recognise and changes the only thing that carries any warmth, which is the line itself. One import, and every screen you ship reads as drawn by somebody.