Snap.svg Logo Draw Reveal — Animated Hero Monogram Snippet
Snap.svg Logo Draw Reveal · Animations · Plain HTML, CSS & JS · Live preview
Copy & paste
Source Code
<section class="sld-hero">
<div class="sld-glow"></div>
<div class="sld-inner">
<svg id="sldSvg" viewBox="0 0 220 220" width="180" height="180"></svg>
<h1 class="sld-word">NOVARA</h1>
<p class="sld-sub">A geometric monogram, drawn stroke by stroke, then filled.</p>
<button class="sld-replay" id="sldReplay">Replay intro</button>
</div>
</section>*{box-sizing:border-box;margin:0;padding:0}
body{font-family:system-ui,-apple-system,sans-serif;background:#080a14;color:#fff;min-height:100vh;display:flex;align-items:center;justify-content:center}
.sld-hero{position:relative;width:100%;min-height:100vh;display:flex;align-items:center;justify-content:center;overflow:hidden;background:radial-gradient(120% 100% at 50% 0%,#161d38,#080a14)}
.sld-glow{position:absolute;width:520px;height:520px;border-radius:50%;background:radial-gradient(circle,rgba(129,140,248,.22),transparent 70%);filter:blur(10px);pointer-events:none}
.sld-inner{position:relative;display:flex;flex-direction:column;align-items:center;gap:10px;padding:40px 24px;text-align:center}
.sld-word{font-size:clamp(28px,6vw,42px);font-weight:800;letter-spacing:.12em;margin-top:6px;opacity:0;transform:translateY(8px);transition:opacity .6s ease,transform .6s ease}
.sld-word.is-in{opacity:1;transform:translateY(0)}
.sld-sub{font-size:13.5px;color:#8e97b8;max-width:340px}
.sld-replay{margin-top:10px;padding:9px 18px;border-radius:99px;border:1px solid rgba(255,255,255,.14);background:rgba(255,255,255,.04);color:#c3cbe8;font:600 12.5px system-ui;cursor:pointer;transition:background .18s,border-color .18s,color .18s}
.sld-replay:hover{background:rgba(255,255,255,.09);color:#fff;border-color:#818cf8}var s = Snap('#sldSvg');
// A simple geometric monogram: a diamond outline with a crossbar, built
// entirely from straight-line path commands so getTotalLength() and the
// dash-offset reveal behave predictably.
var MONOGRAM_PATH = 'M110,20 L200,110 L110,200 L20,110 Z M60,110 L160,110';
function draw() {
s.clear();
var word = document.querySelector('.sld-word');
if (word) word.classList.remove('is-in');
var outline = s.path(MONOGRAM_PATH).attr({
stroke: '#a5b4fc',
strokeWidth: 4,
fill: 'none',
strokeLinecap: 'round',
strokeLinejoin: 'round'
});
var len = outline.node.getTotalLength();
outline.attr({ strokeDasharray: len, strokeDashoffset: len });
// Stage 1: the outline draws itself in via the dash-offset technique.
outline.animate({ strokeDashoffset: 0 }, 1400, mina.easeinout, function () {
// Stage 2: once the stroke completes, a fill fades in underneath it
// by animating the SVG fill-opacity attribute from 0 to a solid value \u2014
// a plain numeric attribute, so Snap.svg's tween machinery covers it
// the same way it covers stroke-dashoffset.
outline.attr({ fill: '#818cf8', fillOpacity: 0 });
outline.animate({ fillOpacity: 0.85 }, 700, mina.easeout);
if (word) {
setTimeout(function () { word.classList.add('is-in'); }, 200);
}
});
}
document.getElementById('sldReplay').addEventListener('click', draw);
draw();Extend with AI
Take This Snippet Further With AI
The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.
What's included
Features
About this UI Snippet
Snap.svg Logo Draw Reveal — Outline First, Fill Second

A logo reveal reads as premium when it happens in the right order: the *shape* establishes itself first, stroke by stroke, and only once it's recognizable does *substance* — solid color — fill it in. This snippet builds that two-stage reveal with Snap.svg, reusing the same dash-offset draw technique as an animated line chart, but finishing with a second animation stage the chart doesn't need.
Building a monogram from straight lines only
MONOGRAM_PATH = 'M110,20 L200,110 L110,200 L20,110 Z M60,110 L160,110' describes a diamond (four L commands closed with Z) plus a horizontal crossbar (a second M/L pair). Every command here is a straight line — no curves — which matters for this technique specifically: getTotalLength() and the dash-offset reveal work on *any* path, curved or straight, but a path made purely of lines has a length that's simple to reason about and reveals with a perfectly even, constant-feeling draw speed, since every point along it represents an equal fraction of straight-line distance.
Stage 1 — the outline draws itself
Identical mechanism to a self-drawing chart: strokeDasharray and strokeDashoffset are both set to the path's getTotalLength(), making the stroke start fully invisible, then strokeDashoffset animates down to 0 over 1.4 seconds so the outline appears to trace itself from the top point around to the crossbar.
Stage 2 — the fill fades in, gated by the outline's completion
The interesting new piece is what happens in the .animate() call's completion callback, which only fires after stage 1 finishes:
outline.attr({ fill: '#818cf8', fillOpacity: 0 });
outline.animate({ fillOpacity: 0.85 }, 700, mina.easeout);
fill-opacity is a distinct SVG attribute from the shape's overall opacity — it controls only the interior fill's transparency while leaving the stroke fully opaque. Setting the fill color and fillOpacity: 0 in the same attr() call primes the shape with a color that's present but invisible, so the subsequent animate({ fillOpacity: 0.85 }) has something to fade *to* without a flash of full-opacity color appearing instantly. Because this second animation is triggered from the first one's callback rather than started in parallel, the fill can never begin fading in before the outline has visually finished — which is what makes the sequence read as "outline, then substance" instead of everything happening at once.
Gating the wordmark text on the same sequence
The <h1> wordmark next to the SVG is a plain CSS opacity/transform transition, toggled by adding an .is-in class — but that class is added inside the *same* completion callback, delayed by a further setTimeout. This keeps the DOM-based text animation synchronized with the SVG-based logo animation even though they're driven by two completely different animation systems (Snap.svg tweens vs. CSS transitions).
Replay resets cleanly
draw() calls s.clear() first and removes the .is-in class from the wordmark, so clicking "Replay intro" tears down the previous SVG state and CSS state together before rebuilding both from scratch.
Step by step
How to Use
- 1Add the Snap.svg CDNInclude snap.svg-min.js from the CDN panel — it attaches a global Snap function.
- 2Paste HTML, CSS, and JSThe hero plays its logo reveal automatically on load.
- 3Watch the outline drawstroke-dashoffset eases the diamond-and-crossbar path in over 1.4s.
- 4Watch the fill fade infill-opacity animates in only after the outline finishes tracing.
- 5Watch the wordmark arriveA CSS transition brings in the text, synced via the same callback chain.
- 6Replace the monogramSwap MONOGRAM_PATH for your own straight-line SVG path data.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
The dash-offset draw technique works on curves too, but a path made purely of M/L/Z commands has a length that is simple straight-line distance, so the reveal traces at an even, predictable speed across the whole shape rather than seeming to speed up or slow down through curved sections.
fill-opacity controls only the transparency of the shape\u2019s interior fill, leaving its stroke fully opaque. The overall opacity attribute would fade the stroke and fill together. Using fillOpacity lets the outline stay crisp while only the interior fades in.
Snap.svg\u2019s .animate() accepts a completion callback as its fourth argument, which only fires once that animation finishes. Starting the fill fade there guarantees the fill never begins appearing until the outline has visually finished tracing, preserving the "shape first, then substance" sequence.
The wordmark\u2019s .is-in class (which triggers its CSS opacity/transform transition) is added inside the same JavaScript callback that starts the fill animation, with an additional short setTimeout delay \u2014 so a Snap.svg tween and a CSS transition, two unrelated animation systems, are chained through one shared callback.
draw() is reused as the replay handler. Clearing the SVG and resetting the wordmark\u2019s class ensures each replay starts from the same blank state as the initial page load, rather than animating on top of an already-revealed logo.
Split MONOGRAM_PATH into two separate Snap.svg path elements (one for the diamond, one for the crossbar), give each its own getTotalLength()/dashoffset setup, and chain the crossbar\u2019s animation to start in the diamond\u2019s completion callback for a deliberate two-part outline sequence.