How to Create a Sketchy/Hand‑Drawn Primitive Using an SVG Turbulence Filter

A sketchy primitive in Diagram Design is built by combining feTurbulence for fractal noise generation with feDisplacementMap to distort the original graphic, producing organic, hand‑drawn edges.

The Diagram Design repository implements this effect as a reusable SVG filter that adds subtle noise to any shape group. According to the source code in cathrynlavery/diagram-design, the filter is defined once in primitive-sketchy.md and applied selectively to non‑text elements, preserving readability while giving illustrations a rough, editorial character.


SVG Filter Architecture

The sketchy effect relies on two chained filter primitives working in sequence.

feTurbulence: Generating the Noise

The <feTurbulence> element creates fractal noise that serves as the displacement map:

  • type="fractalNoise" produces smooth, organic noise rather than blocky turbulence
  • baseFrequency controls the spatial frequency of the noise
  • numOctaves adds layers of detail
  • seed provides deterministic randomness

feDisplacementMap: Distorting the Graphic

The <feDisplacementMap> uses the turbulence output to shift pixels in the source graphic:

  • in="SourceGraphic" specifies what to distort
  • scale determines displacement magnitude in pixels

Complete Filter Definition

The standard filter definition from skills/diagram-design/references/primitive-sketchy.md:

<defs>
  <filter id="sketchy" x="-2%" y="-2%" width="104%" height="104%">
    <feTurbulence type="fractalNoise"
                  baseFrequency="0.02"
                  numOctaves="2"
                  seed="4"/>
    <feDisplacementMap in="SourceGraphic" scale="1.5"/>
  </filter>
</defs>

The expanded filter region (x="-2%" y="-2%" width="104%" height="104%") prevents edge clipping when displacement pushes pixels outward.


Applying the Sketchy Primitive to SVG Elements

The filter is attached to a <g> element that wraps only non‑text shapes. Text elements must remain unfiltered to maintain legibility.

<!-- Shapes receive the hand‑drawn effect -->
<g filter="url(#sketchy)">
  <rect x="10" y="10" width="80" height="40" />
  <circle cx="50" cy="70" r="20" />
</g>

<!-- Labels stay crisp and readable -->
<text x="15" y="35" font-family="sans-serif">Label</text>

This separation is critical—the displacement that creates the sketchy aesthetic would render body text illegible if applied uniformly.


Tuning Parameters for Different Visual Styles

Parameter Typical Range Visual Effect
baseFrequency 0.01–0.04 Lower values produce lazy, flowing waviness; higher values create jitterier, more nervous lines
numOctaves 1–3 Additional octaves add finer noise detail and complexity
scale 1–6 Controls displacement strength: 1 for subtle texture, 4+ for exaggerated cartoon effects
seed Any integer Changes the noise pattern while keeping all other parameters constant

The tuning table in primitive-sketchy.md provides these guidelines for adapting the filter to specific creative contexts.


Complete Working Example

A self‑contained SVG demonstrating the sketchy primitive implementation:

<svg width="120" height="100" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <filter id="sketchy" x="-2%" y="-2%" width="104%" height="104%">
      <feTurbulence type="fractalNoise" baseFrequency="0.02" numOctaves="2" seed="4"/>
      <feDisplacementMap in="SourceGraphic" scale="1.5"/>
    </filter>
  </defs>

  <g filter="url(#sketchy)">
    <rect x="10" y="10" width="80" height="40" fill="#4caf50"/>
    <circle cx="60" cy="70" r="15" fill="#ff9800"/>
  </g>

  <text x="15" y="35" font-size="12" fill="#000">Sketchy Box</text>
</svg>

More Jittery Variant

For a rougher, more energetic appearance, increase frequency and scale:

<feTurbulence baseFrequency="0.035" numOctaves="3" seed="7"/>
<feDisplacementMap in="SourceGraphic" scale="3"/>


Where to Use the Sketchy Filter

According to the repository's README (approximately line 568), the sketchy primitive excels in:

  • Essays and blog posts — adds personality and human warmth
  • Newsletters — distinguishes editorial content from sterile graphics
  • Work‑in‑progress diagrams — signals draft status visually

Avoid the filter in:

  • Dense technical documentation where precision matters
  • Dark backgrounds where noise patterns become distracting
  • Any context requiring exact measurement or alignment

The SKILL.md file under skills/diagram-design/ lists the "Sketchy variant" as an optional primitive with a link to the full reference implementation.


Summary

  • The sketchy primitive combines feTurbulence and feDisplacementMap in a single SVG filter definition
  • primitive-sketchy.md contains the canonical filter code and tuning guidance
  • Apply filter="url(#sketchy)" only to shape groups, keeping text elements separate
  • Tune baseFrequency, numOctaves, scale, and seed to match your desired aesthetic intensity
  • Use for editorial and informal diagrams; avoid for precise technical documentation

Frequently Asked Questions

What makes the sketchy filter different from simple CSS filters?

CSS filters like blur or contrast operate uniformly across pixels, whereas the SVG turbulence filter generates spatially varying displacement that follows organic noise patterns. This creates the irregular, hand‑drawn line quality impossible to achieve with CSS alone. The feDisplacementMap component is what enables this pixel‑by‑pixel distortion based on the turbulence texture.

Why must text stay outside the filtered group in the sketchy primitive implementation?

Displacement would distort glyph shapes and degrade readability. The filter intentionally separates <g filter="url(#sketchy)"> for shapes from unwrapped <text> elements. This architectural choice in Diagram Design preserves sharp, vector‑precise typography while surrounding elements carry the rough aesthetic.

How do I make the sketchy effect more or less pronounced?

Adjust the scale attribute on feDisplacementMap and the baseFrequency on feTurbulence. Increasing scale from 1.5 to 4–6 amplifies the wobble dramatically. Raising baseFrequency from 0.02 toward 0.04 introduces finer, more frequent noise. The primitive-sketchy.md tuning table documents these relationships with specific value ranges.

Can the sketchy filter be animated or changed dynamically?

Yes, by modifying filter attributes via JavaScript or SMIL animation. Changing the seed attribute generates new random patterns, while animating baseFrequency or scale produces evolving distortion effects. The deterministic nature of seed ensures reproducible results when static, or controlled variation when animated.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →