Organic, mechanical and interface forms drawn with the same 1.7px rounded stroke on a 24px grid. No fills except three signal dots, no text, no assembly — every mark is authored geometry that inherits currentColor and survives a CSS stroke-width.
All eighteen at 24px in one line. If the mechanical icons feel heavier than the wind, or the interface icons drift lighter, the family fails — this is the test the set was drawn against.
Organic first (swell, wind, moon, rain, tide, current), then mechanical (anemometer, buoy, gauge, mooring, compass, temp), then interface (filter, export, alert, history, compare, favourite). Hover to inspect.
#i-swell#i-wind#i-moon#i-rain#i-tide#i-current#i-anemometer#i-buoy#i-tide-gauge#i-mooring#i-compass#i-temp#i-filter#i-export#i-alert#i-history#i-compare#i-favouriteReadable at 16px, composed at 96px. Two masters ship a deliberate small form where curls and ticks would clog: wind and tide-gauge. Everything else holds without simplification.
| Default | Small (16px) | Why |
|---|---|---|
| Curls close up; three bars keep rhythm. | ||
| Four ticks + wave → two ticks + rule. |
Stroke width lives in CSS (--sw), never in the sprite. Drag to prove it:
No inverted duplicates. Every glyph is currentColor strokes (plus three solid signal dots), so the same sprite works on both grounds.
A harbour-master station card. Decorative icons are hidden from assistive technology; the gale-warning icon carries a name.
One grid for all three families. Optical correction beats maths: circles overshoot the live area, waves run edge to edge, dots are drawn 2px and never stroked.
| Rule | Value |
|---|---|
| Grid / live / padding | 24 · 20 × 20 (2–22) · 2px safe |
| Stroke | 1.7px · round caps + joins · set in CSS via --sw, never in sprite |
| Corners / radii | 2px nominal; joins do the rounding — no chamfers |
| Optical correction | Circles r 6.5–7.2 centred 12/12; squares inset extra 0.5px; waves span 3–21 to look full; buoy body narrowed 1px to offset water weight |
| Density | 2–3 strokes per glyph; solid dots only for alert, anemometer hub, thermometer bulb |
| Node budget | Max 8 commands in set (mooring flukes); all ≤ 24 · 2-decimal coords · no transforms · titled symbols |
Copy the sprite once, reference anywhere. Decorative instances are hidden; meaningful ones are named.
<svg class="icon" aria-hidden="true"><use href="#i-wind"/></svg>
<!-- meaningful: name it -->
<svg class="icon" role="img" aria-label="Gale warning">
<use href="#i-alert"/>
</svg>
<style>
.icon{
width:24px; height:24px;
color:#14313d; /* currentColor */
fill:none; stroke:currentColor;
stroke-width:var(--sw,1.7);
stroke-linecap:round; stroke-linejoin:round;
}
.dark .icon{ color:#e8f2f3; }
</style>Left: decorative swell hidden from AT. Right: alert exposed with a name.
Each <symbol> carries a <title> so the source is self-describing; instances decide exposure via aria-hidden or aria-label.