00How it works
A recipe in,
a pencil drawing out.
Matita doesn't store drawings. It stores recipes: a few lines of text like "a rectangle here, a line there". When you use an icon, a small program follows the recipe and draws it the way a pencil would, with a little wobble. The wobble comes from the icon's name, so the same icon always comes out the same.
01The recipe
Every icon is a recipe
A glyph is a short list of drafting shapes on a 24 by 24 grid, the kind of thing you would plot with a ruler and compass. There are nine kinds of shape, and most icons use two to five of them.
| Code | Shape | Numbers it takes |
|---|---|---|
L | Line | x1 y1 x2 y2 |
P | Polyline | x y x y … |
Z | Closed shape | x y x y … |
R | Rectangle | x y w h |
C | Circle | cx cy r |
E | Ellipse | cx cy rx ry |
A | Arc | cx cy r a0 a1 |
Q | Curve | x1 y1 cx cy x2 y2 |
O | Dot | cx cy |
R 4 5.5 16 15;
L 4 10 20 10;
L 8.5 3.5 8.5 7;
L 15.5 3.5 15.5 7
Plotted is the recipe drawn with a ruler: perfectly straight, perfectly closed. Drawn is what Matita gives you.
02The pencil
The habits of a pencil
The program gives every shape a few small habits. Each one is something a hand really does with a ruler, and each one has a limit so the icon still reads when it is small. Numbers are grid units; at 24 px one unit is one pixel.
- Lines overshoot
- Both ends of a line are pushed out along its direction by 0.2 to 0.5, and each endpoint moves by up to 0.2. The line is drawn as a gentle curve whose middle is pulled sideways by at most 0.7, or 4.5 % of its length, whichever is smaller. A ruled pencil line is never perfectly straight and rarely stops exactly where you aimed.
- Boxes cross at the corners
- A rectangle is not a closed path. It is four separate lines with a bigger overshoot (0.5 to 1.5), so every corner is a small cross, like a box drawn edge by edge.
- Circles overlap where the pen closes
- A circle starts at a random angle and sweeps 388° to 418°, so the pen runs 28° to 58° past where it started. Over the sweep the radius drifts outward by 0.55 to 1, so the closing pass sits just outside the opening one. Each point gets ±2.8 % radius noise, and the whole ring is squashed by up to 4.5 %.
- Joints stay sharp
- Every corner of a polyline moves by up to 0.2 and every segment bows on its own, but the joints stay sharp: a check mark still has a point at the bottom. Closed shapes run past their starting point along the first edge, the way you would close a shape without lifting the pencil.
- Arcs and curves overshoot too
- Arcs run 4° to 9° past each end, and curves overshoot their ends by 0.15 to 0.45.
- Pressure varies per stroke
- Every stroke gets its own width, between 0.86 and 1.14 times the base 1.6.
- Dots are taps
- A dot is a near-zero-length stroke with a round cap, so it reads as a single tap of the pen.
03Repeatable
Same name, same drawing
The wobble is not rolled fresh each time. The icon's name is turned into a number, that number starts a tiny random number generator, and every "random" choice for that icon comes from it, in a fixed order.
// the name becomes a number...
const hash = s => { let h = 2166136261; for (const c of s) { h ^= c.charCodeAt(0); h = Math.imul(h, 16777619); } return h >>> 0; };
hash('calendar') // 2759920927
// ...which starts the generator (add a seed for another take)
const random = prng(hash(name) + seed * 7919);So calendar is drawn the same way on every machine, in every build, unless its recipe changes. That matters more than it sounds:
- No hydration mismatch. The server-rendered SVG and the client-rendered SVG are byte-identical.
- No flicker. Nothing re-rolls when a component re-renders.
- Snapshot tests stay green. The same input always gives the same output.
- No drawing at runtime. The whole set is drawn once at build time and the package ships the finished path data. The engine only runs if you ask for another seed or draw your own icon.
Don't like a particular drawing? Pass a seed. Seed 0 is the default; the others are other takes of the same recipe.
04Small sizes
Built for small sizes
A hand-drawn look is easy at 96 px and hard at 16 px: too much wobble and a small icon turns to mush. The caps above are what keep it usable. At 24 px a line bows by less than a pixel and an endpoint moves by a fifth of one, and no stroke is thinner than about 1.4.
The same icon at true pixel sizes. At UI sizes the set reads like a regular line icon set; the pencil character shows from about 32 px up.
05Try it
Write a recipe, watch it draw
Search the set and pick an icon to see its recipe, then change the numbers. The icon's name decides the wobble, and a seed gives you another take of the same recipe.
173 icons
No icon matches “”.
calendar as a number: 2759920927
Shapes: L P Z R C E A Q O. Separate shapes with ;. For example, C 12 12 8; L 12 6 12 12 is a circle with a hand pointing up.
06Your own
Draw your own
The engine is part of the package, so you can draw your own icons in the same hand and use them like any other icon.
npm i @matita/iconsimport { drawIcon } from '@matita/icons/engine';
import { createSketchIcon } from '@matita/icons/react';
const Kite = createSketchIcon(drawIcon('kite', {
defs: { kite: 'Z 12 3 18 10 12 21 6 10; L 6 10 18 10; L 12 3 12 21' },
}));
<Kite size={32} />07Questions
Good questions
The ones people ask most. Something missing? Open an issue and it can be added here.
Are the icons hand-drawn?
No. Nobody drew these strokes. Each icon is a short recipe, written by hand, and a small program draws it in a pencil style. The wobble is on purpose; the hand is code.
Is AI involved?
No. It is a plain algorithm: about 90 lines of code and a tiny random number generator. There is no model and no training, and nothing is drawn differently from one run to the next.
Why not just draw them by hand?
Consistency and speed. Every icon follows the same rules, so the set feels like one hand drew it, and adding an icon is one line of text instead of an afternoon at the drawing board.
What does "the same every time" mean?
That the drawing is repeatable. The wobble is not rolled fresh on every render: it comes from the icon's name, so the server and the browser, or two different builds, draw exactly the same strokes. If you want another take, ask for a different seed.
How big are the icons?
About 0.8 KB each as a raw SVG (about 0.45 KB gzipped), and around 1.5 KB for the pencil version. In a bundle, one React icon adds about 1 KB gzipped with the renderer included, and ten add about 4 KB. The whole set is drawn once at build time and ships as finished path data.
Does it still read at 16 px?
Yes. Every habit of the pencil has a cap. At 24 px a line bows by less than a pixel and an endpoint moves by about a fifth of one, and no stroke is thinner than about 1.4. The pencil character shows from about 32 px up.
Can I turn any SVG into this style?
No. The engine only understands its nine shapes (below). You describe an icon with those shapes instead, and the engine draws it in the same hand as the rest of the set.
Is it free to use?
Yes. Matita is MIT licensed, free for personal and commercial projects.