← SVG & icons

Line Draw

The strokes of any SVG draw themselves in, one after another, as if sketched by hand. Works on outline icons, illustrations and signatures.

How to use it

  1. Paste the snippet just before </head>.
  2. Add data-line-draw to an <svg> whose shapes have a stroke (and usually fill="none").

Options

Add any of these attributes to the same element.

data-loopDraw in, hold, erase and repeat.
data-durationTime to draw each stroke. Default 1400 ms.
data-staggerGap between strokes. Default 180 ms.
data-holdHow long the finished drawing stays, when looping. Default 1400 ms.
1 · Snippet
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/bundles/anime.umd.min.js"></script>
<script>
  (function () {
    // Line Draw: the strokes of any SVG draw themselves in, one after another, as
    // if sketched by hand. Works on outline icons, illustrations and signatures.
    // Usage: <svg data-line-draw viewBox="…">…paths with a stroke…</svg>
    // Optional: data-duration (ms per stroke), data-stagger (ms between strokes),
    // data-loop (draw in, hold, draw out, repeat), data-hold (ms).
    var DEFAULTS = { duration: 1400, stagger: 180, hold: 1400 };

    function run(svg) {
      var d = svg.dataset;
      var shapes = svg.querySelectorAll('path, line, polyline, polygon, circle, ellipse, rect');
      if (!shapes.length) return;
      var lines = anime.svg.createDrawable(shapes);
      var loop = d.loop !== undefined && d.loop !== 'false';
      var duration = +d.duration || DEFAULTS.duration;
      var stagger = +d.stagger || DEFAULTS.stagger;
      var tl = anime.createTimeline({ loop: loop });
      tl.add(lines, { draw: ['0 0', '0 1'], duration: duration, ease: 'inOut(3)', delay: anime.stagger(stagger) });
      if (loop) {
        // Erase in the same direction it was drawn, so it feels like one stroke.
        tl.add(lines, { draw: ['0 1', '1 1'], duration: duration * 0.7, ease: 'inOut(3)', delay: anime.stagger(stagger * 0.5) },
          '+=' + (+d.hold || DEFAULTS.hold));
      }
    }

    function init() {
      var reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
      var io = new IntersectionObserver(function (entries) {
        entries.forEach(function (e) {
          if (!e.isIntersecting) return;
          io.unobserve(e.target);
          run(e.target);
        });
      }, { threshold: 0.3 });
      document.querySelectorAll('[data-line-draw]').forEach(function (svg) {
        if (svg._ld || reduced) return;
        svg._ld = true;
        // Hide the strokes until they are drawn.
        anime.utils.set(anime.svg.createDrawable(svg.querySelectorAll('path, line, polyline, polygon, circle, ellipse, rect')), { draw: '0 0' });
        io.observe(svg);
      });
    }

    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
    else init();
  })();
</script>
2 · Your HTML
<svg data-line-draw viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
  <path d="M3 12l6 6L21 6"/>
</svg>