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
- Paste the snippet just before
</head>. - Add
data-line-drawto an<svg>whose shapes have astroke(and usuallyfill="none").
Options
Add any of these attributes to the same element.
data-loop | Draw in, hold, erase and repeat. |
data-duration | Time to draw each stroke. Default 1400 ms. |
data-stagger | Gap between strokes. Default 180 ms. |
data-hold | How long the finished drawing stays, when looping. Default 1400 ms. |
<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><svg data-line-draw viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 12l6 6L21 6"/>
</svg>