We see clean, straight lines everywhere in modern web design. Everything is perfectly aligned, sharp, and sterile. But sometimes, you want a design to feel alive, raw, and organic.
I recently experimented with creating hand-drawn, boiling vector illustrations and wobbly icons.
The secret? A combination of SVG filters and a simple CSS stepped animation.
The Secret Sauce: SVG Filters
You don't need to manually draw multiple frames of an icon to make it shake. Instead, we can warp any existing SVG using two SVG filter primitives: <feTurbulence> and <feDisplacementMap>.
Here is the basic filter structure:
1<svg class="hidden-filter-defs">
2 <defs>
3 <filter id="wobble-filter-1">
4 <feTurbulence
5 type="fractalNoise"
6 baseFrequency="0.05"
7 numOctaves="1"
8 result="noise"
9 seed="1"
10 />
11 <feDisplacementMap
12 in="SourceGraphic"
13 in2="noise"
14 scale="4"
15 xChannelSelector="R"
16 yChannelSelector="G"
17 />
18 </filter>
19 </defs>
20</svg>Let's break down how this works:
- feTurbulence: This component generates mathematical Perlin noise. The
baseFrequencycontrols how detailed or wavy the noise is, whileseeddetermines the starting pattern of the noise. - feDisplacementMap: This takes the original graphic (
SourceGraphic) and shifts its pixels based on the red (R) and green (G) color values of the noise generated in the previous step. Thescaleattribute controls how dramatic the displacement (wobble) is.
Creating the "Boiling" Effect
If we just apply this filter, our SVG lines will look slightly warped, but they will be static.
To make it look like a hand-drawn animation, we need the wobble to change rapidly, mimicking the jitter of hand-drawn frames. We do this by defining multiple filters with different seed values.
Since each seed produces a completely different noise pattern, toggling between them creates a classic "boiling line" animation.
Let's define three distinct filters with seeds 1, 2, and 3:
1<svg class="hidden-filter-defs">
2 <defs>
3 <!-- Filter 1 -->
4 <filter id="wobble-1">
5 <feTurbulence type="fractalNoise" baseFrequency="0.06" numOctaves="1" result="noise" seed="1" />
6 <feDisplacementMap in="SourceGraphic" in2="noise" scale="3" xChannelSelector="R" yChannelSelector="G" />
7 </filter>
8
9 <!-- Filter 2 -->
10 <filter id="wobble-2">
11 <feTurbulence type="fractalNoise" baseFrequency="0.06" numOctaves="1" result="noise" seed="2" />
12 <feDisplacementMap in="SourceGraphic" in2="noise" scale="3.5" xChannelSelector="R" yChannelSelector="G" />
13 </filter>
14
15 <!-- Filter 3 -->
16 <filter id="wobble-3">
17 <feTurbulence type="fractalNoise" baseFrequency="0.06" numOctaves="1" result="noise" seed="3" />
18 <feDisplacementMap in="SourceGraphic" in2="noise" scale="3" xChannelSelector="R" yChannelSelector="G" />
19 </filter>
20 </defs>
21</svg>Animating it with CSS
Now that we have three filters, we can cycle through them using CSS.
Normally, CSS transitions are smooth. But for a hand-drawn look, we want sudden jumps between our frames. This is where animation-timing-function: steps() comes in.
Here is the CSS class to trigger the wobble:
1.wobble-hover:hover {
2 animation: wobble-cycle 0.3s steps(1) infinite;
3}
4
5@keyframes wobble-cycle {
6 0% {
7 filter: url(#wobble-1);
8 }
9 33% {
10 filter: url(#wobble-2);
11 }
12 66% {
13 filter: url(#wobble-3);
14 }
15}By using steps(1) in the animation, the browser instantly snaps between filter states rather than smoothly morphing them. This produces the charming, low-framerate boiling line look typical of traditional cell animations.
Why This Matters
In a web filled with identical-looking component libraries, custom micro-interactions stand out.
Adding a wobbly hand-drawn effect to button hovers or decorative icons gives your site personality. It makes the page feel crafted, human, and interactive.
Best of all, since it is powered entirely by SVG filters, it works on any vector icon or text element without needing heavy video files or massive Lottie runtimes.
Quick Mental Model
- feTurbulence: Generates random organic noise vectors.
- feDisplacementMap: Warps the SVG paths using that noise.
- CSS Animation: Cycles the noise seed using stepped transitions to create motion.
Written by
Abhinav Yadav