Tacet

Tacet

454 icons whose contour cut is data rather than something carved into the geometry. Hence the draw-in animation, four cut densities and a solid mode — out of one source, with no second set of files.

npm i tacet-react

how it works

A cut is data

Every stroke gets pathLength=100, and the breaks are described as start-and-width pairs in percent of the contour length. Moving a cut or removing it is editing one number, not redrawing the path. The animation comes out of the same record: it draws the contour while the cuts hold their place.

"bell": [
  p("M6 8a6 6 0 1 1 12 0c0 4 1.5 5 2 6H4c.5-1 2-2 2-6Z",
    [[14,10],[60,10]]),
  p("M10 19a2 2 0 0 0 4 0", null, { accent: true }),
]

any stack

React is one of four ways

The engine has no idea React exists: it turns a glyph name into SVG attributes and animates a plain DOM element. React is a thin wrapper over it — and so are the custom element, which needs no framework at all, and the React Native one, which draws the same glyphs on a phone.

Custom element

Works anywhere HTML does: Vue, Svelte, Astro, a plain page, a template rendered on the server.

npm i tacet-element
<script type="module">
  import "tacet-element";
</script>

<tacet-icon name="rocket" size="24"></tacet-icon>
<tacet-icon name="bell" animate></tacet-icon>

React Native

The same set on a phone, drawn with react-native-svg. There is no cascade there, so the colour is passed in, and cuts are measured into real units — pathLength does not exist in React Native. Of the animation modes only the draw-in is there so far, played on demand.

npm i tacet-native react-native-svg
import { Icon } from "tacet-native";

<Icon name="rocket" size={24} color="#18181b" />
<Icon name="bell" replayKey={taps} color="#18181b" />

Engine on its own

For your own wrapper, a generator or a build step. No dependencies at all, not even a peer one.

npm i tacet-core
import { renderSpec } from "tacet-core";

const spec = renderSpec("rocket", { size: 24 });
// spec.parts → [{ tag: "path", attrs: {…} }]

Static files

No runtime at all. Cuts are baked into the files; only the animation is lost. Every glyph is also served here as a single SVG.

<img src="bell.svg" width="24" alt="">
<svg width="24" height="24">
  <use href="sprite.svg#tacet-bell"></use>
</svg>

four densities

One glyph, four characters

The same data reads four ways: with and without the accent, with one cut and with all of them. Plus a solid mode — for places where breaks get in the way, small status marks for instance.

A one cut
B all cuts
C one and accent
D all and accent
solid unbroken

digits

Ten digits that draw themselves

Each digit is one stroke, laid down the way a hand writes it. When a number changes, only the digits that changed move: they flow into the new shape, hand over to it, or erase and write it again. The accent is data too — a stretch of the contour, stored the way a cut is.

clock
counter
Inbox
verification code
quantity
<Digits value={unread} size={16} />
<Digits value="12:30" transition="relay" />
<DigitsField defaultValue="1" inputMode="numeric" />
<tacet-digits value="1248" size="40"></tacet-digits>
<tacet-digits-field name="qty" inputmode="numeric"></tacet-digits-field>

letters

Capitals that write themselves

Latin and Cyrillic capitals, digits and punctuation, set in lines with kerning measured from the outlines. Every letter is written stroke by stroke, in the order a hand writes it. When the text changes, what stays stays put; what changed erases back along its strokes, and the new part writes itself in.

text field
a line that changes
<Text value="Сохранено" size={24} />
<TextField defaultValue="Привет" placeholder="Name" />
<tacet-text value="10:30 — «TACET»" size="32"></tacet-text>
<tacet-text-field name="title" placeholder="Title"></tacet-text-field>

stroke

A large icon does not get fat

Stroke follows size by a power law rather than proportionally: an icon enlarged fourfold does not turn into a heavy blueprint. Need an even hairline at any size — there is absoluteStroke.

24px · 1.50
48px · 2.05
96px · 2.83
128px · 3.19

what others do not have

64 instruments in one style

Duduk, handpan, bayan, jaw harp, gusli, didgeridoo — drawn with the same stroke and the same cuts as the arrows and folders. Plus roles: producer, sound engineer, conductor, beatmaker.

saxophone
balalaika
handpan
duduk
bayan
harp
djembe
sitar
gusli
kalimba
didgeridoo
jaw-harp
accordion
banjo
cello
timpani

for agents

It is written down when to use which icon

Interfaces are increasingly written by an AI agent that picks an icon by name — which is how trash ends up where archive was meant. Each of the 454 glyphs carries what it is for, what it gets confused with and what to take instead. Search tags exist in every set; a guide to choosing exists in none.

trash
Permanent deletion, the item is gone.
If the item is only moved out of sight and can come back, that is archive. If access is being denied rather than data removed, use ban.
archive
Moving out of the active list while keeping the data.
Do not use for deletion — that is trash.
check
A bare checkmark inside another control: a checkbox, a menu item, a chip.
For the result of an operation — «done, succeeded» — use check-circle: it reads as a status, not as a mark.
check-circle
Successful outcome of an operation or a completed state.
Inside a checkbox this is too loud — there use check.

Shipped as llms.txt and icons.json, and in code as the META export from tacet-core.